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