1import os
2from clang.cindex import Config
3if 'CLANG_LIBRARY_PATH' in os.environ:
4    Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
5
6from clang.cindex import Cursor
7from clang.cindex import File
8from clang.cindex import SourceLocation
9from clang.cindex import SourceRange
10from .util import get_cursor
11from .util import get_tu
12
13import unittest
14
15
16baseInput="int one;\nint two;\n"
17
18
19class TestLocation(unittest.TestCase):
20    def assert_location(self, loc, line, column, offset):
21        self.assertEqual(loc.line, line)
22        self.assertEqual(loc.column, column)
23        self.assertEqual(loc.offset, offset)
24
25    def test_location(self):
26        tu = get_tu(baseInput)
27        one = get_cursor(tu, 'one')
28        two = get_cursor(tu, 'two')
29
30        self.assertIsNotNone(one)
31        self.assertIsNotNone(two)
32
33        self.assert_location(one.location,line=1,column=5,offset=4)
34        self.assert_location(two.location,line=2,column=5,offset=13)
35
36        # adding a linebreak at top should keep columns same
37        tu = get_tu('\n' + baseInput)
38        one = get_cursor(tu, 'one')
39        two = get_cursor(tu, 'two')
40
41        self.assertIsNotNone(one)
42        self.assertIsNotNone(two)
43
44        self.assert_location(one.location,line=2,column=5,offset=5)
45        self.assert_location(two.location,line=3,column=5,offset=14)
46
47        # adding a space should affect column on first line only
48        tu = get_tu(' ' + baseInput)
49        one = get_cursor(tu, 'one')
50        two = get_cursor(tu, 'two')
51
52        self.assert_location(one.location,line=1,column=6,offset=5)
53        self.assert_location(two.location,line=2,column=5,offset=14)
54
55        # define the expected location ourselves and see if it matches
56        # the returned location
57        tu = get_tu(baseInput)
58
59        file = File.from_name(tu, 't.c')
60        location = SourceLocation.from_position(tu, file, 1, 5)
61        cursor = Cursor.from_location(tu, location)
62
63        one = get_cursor(tu, 'one')
64        self.assertIsNotNone(one)
65        self.assertEqual(one, cursor)
66
67        # Ensure locations referring to the same entity are equivalent.
68        location2 = SourceLocation.from_position(tu, file, 1, 5)
69        self.assertEqual(location, location2)
70        location3 = SourceLocation.from_position(tu, file, 1, 4)
71        self.assertNotEqual(location2, location3)
72
73        offset_location = SourceLocation.from_offset(tu, file, 5)
74        cursor = Cursor.from_location(tu, offset_location)
75        verified = False
76        for n in [n for n in tu.cursor.get_children() if n.spelling == 'one']:
77            self.assertEqual(n, cursor)
78            verified = True
79
80        self.assertTrue(verified)
81
82    def test_extent(self):
83        tu = get_tu(baseInput)
84        one = get_cursor(tu, 'one')
85        two = get_cursor(tu, 'two')
86
87        self.assert_location(one.extent.start,line=1,column=1,offset=0)
88        self.assert_location(one.extent.end,line=1,column=8,offset=7)
89        self.assertEqual(baseInput[one.extent.start.offset:one.extent.end.offset], "int one")
90
91        self.assert_location(two.extent.start,line=2,column=1,offset=9)
92        self.assert_location(two.extent.end,line=2,column=8,offset=16)
93        self.assertEqual(baseInput[two.extent.start.offset:two.extent.end.offset], "int two")
94
95        file = File.from_name(tu, 't.c')
96        location1 = SourceLocation.from_position(tu, file, 1, 1)
97        location2 = SourceLocation.from_position(tu, file, 1, 8)
98
99        range1 = SourceRange.from_locations(location1, location2)
100        range2 = SourceRange.from_locations(location1, location2)
101        self.assertEqual(range1, range2)
102
103        location3 = SourceLocation.from_position(tu, file, 1, 6)
104        range3 = SourceRange.from_locations(location1, location3)
105        self.assertNotEqual(range1, range3)
106