1#!/usr/bin/env python
2#
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import math
19import os
20import struct
21import unittest
22
23from vts.utils.python.coverage import arc_summary
24from vts.utils.python.coverage import block_summary
25from vts.utils.python.coverage import function_summary
26from vts.utils.python.coverage import gcno_parser
27from vts.utils.python.coverage.parser_test import MockStream
28
29
30class GCNOParserTest(unittest.TestCase):
31    """Tests for GCNO parser of vts.utils.python.coverage.
32
33    Ensures error handling, byte order detection, and correct
34    parsing of functions, blocks, arcs, and lines.
35    """
36
37    GOLDEN_GCNO_PATH = 'testdata/sample.gcno'
38
39    def setUp(self):
40        """Creates a stream for each test.
41        """
42        self.stream = MockStream()
43
44    def testReadFunction(self):
45        """Asserts that the function is read correctly.
46
47        Verifies that ident, name, source file name,
48        and first line number are all read correctly.
49        """
50        ident = 102010
51        self.stream = MockStream.concat_int(self.stream, ident)
52        self.stream = MockStream.concat_int(self.stream, 0)
53        self.stream = MockStream.concat_int(self.stream, 0)
54        name = "TestFunction"
55        src_file_name = "TestSouceFile.c"
56        first_line_number = 102
57        self.stream = MockStream.concat_string(self.stream, name)
58        self.stream = MockStream.concat_string(self.stream, src_file_name)
59        self.stream = MockStream.concat_int(self.stream, first_line_number)
60        parser = gcno_parser.GCNOParser(self.stream)
61        summary = parser.ReadFunction()
62        self.assertEqual(name, summary.name)
63        self.assertEqual(ident, summary.ident)
64        self.assertEqual(src_file_name, summary.src_file_name)
65        self.assertEqual(first_line_number, summary.first_line_number)
66
67    def testReadBlocks(self):
68        """Asserts that blocks are correctly read from the stream.
69
70        Tests correct values for flag and index.
71        """
72        n_blocks = 10
73        func = function_summary.FunctionSummary(0, "func", "src.c", 1)
74        for i in range(n_blocks):
75            self.stream = MockStream.concat_int(self.stream, 3 * i)
76        parser = gcno_parser.GCNOParser(self.stream)
77        parser.ReadBlocks(n_blocks, func)
78        self.assertEqual(len(func.blocks), n_blocks)
79        for i in range(n_blocks):
80            self.assertEqual(func.blocks[i].flag, 3 * i)
81            self.assertEqual(func.blocks[i].index, i)
82
83    def testReadArcsNormal(self):
84        """Asserts that arcs are correctly read from the stream.
85
86        Does not test the use of flags. Validates that arcs are
87        created in both blocks and the source/destination are
88        correct for each.
89        """
90        n_blocks = 50
91        func = function_summary.FunctionSummary(0, "func", "src.c", 1)
92        func.blocks = [block_summary.BlockSummary(i, 3 * i)
93                       for i in range(n_blocks)]
94        src_block_index = 0
95        skip = 2
96        self.stream = MockStream.concat_int(self.stream, src_block_index)
97        for i in range(src_block_index + 1, n_blocks, skip):
98            self.stream = MockStream.concat_int(self.stream, i)
99            self.stream = MockStream.concat_int(
100                self.stream, 0)  #  no flag applied to the arc
101        parser = gcno_parser.GCNOParser(self.stream)
102        n_arcs = len(range(src_block_index + 1, n_blocks, skip))
103        parser.ReadArcs(n_arcs * 2 + 1, func)
104        j = 0
105        for i in range(src_block_index + 1, n_blocks, skip):
106            self.assertEqual(
107                func.blocks[src_block_index].exit_arcs[j].src_block.index,
108                src_block_index)
109            self.assertEqual(
110                func.blocks[src_block_index].exit_arcs[j].dst_block.index, i)
111            self.assertEqual(func.blocks[i].entry_arcs[0].src_block.index,
112                             src_block_index)
113            self.assertEqual(func.blocks[i].entry_arcs[0].dst_block.index, i)
114            j += 1
115
116    def testReadArcFlags(self):
117        """Asserts that arc flags are correctly interpreted.
118        """
119        n_blocks = 5
120        func = function_summary.FunctionSummary(0, "func", "src.c", 1)
121        func.blocks = [block_summary.BlockSummary(i, 3 * i)
122                       for i in range(n_blocks)]
123        self.stream = MockStream.concat_int(self.stream,
124                                            0)  #  source block index
125
126        self.stream = MockStream.concat_int(self.stream, 1)  #  normal arc
127        self.stream = MockStream.concat_int(self.stream, 0)
128
129        self.stream = MockStream.concat_int(self.stream, 2)  #  on-tree arc
130        self.stream = MockStream.concat_int(
131            self.stream, arc_summary.ArcSummary.GCOV_ARC_ON_TREE)
132
133        self.stream = MockStream.concat_int(self.stream, 3)  #  fake arc
134        self.stream = MockStream.concat_int(
135            self.stream, arc_summary.ArcSummary.GCOV_ARC_FAKE)
136
137        self.stream = MockStream.concat_int(self.stream, 4)  #  fallthrough arc
138        self.stream = MockStream.concat_int(
139            self.stream, arc_summary.ArcSummary.GCOV_ARC_FALLTHROUGH)
140
141        parser = gcno_parser.GCNOParser(self.stream)
142        parser.ReadArcs(4 * 2 + 1, func)
143
144        self.assertFalse(func.blocks[0].exit_arcs[0].on_tree)
145        self.assertFalse(func.blocks[0].exit_arcs[0].fake)
146        self.assertFalse(func.blocks[0].exit_arcs[0].fallthrough)
147
148        self.assertTrue(func.blocks[0].exit_arcs[1].on_tree)
149        self.assertFalse(func.blocks[0].exit_arcs[1].fake)
150        self.assertFalse(func.blocks[0].exit_arcs[1].fallthrough)
151
152        self.assertFalse(func.blocks[0].exit_arcs[2].on_tree)
153        self.assertTrue(func.blocks[0].exit_arcs[2].fake)
154        self.assertFalse(func.blocks[0].exit_arcs[2].fallthrough)
155
156        self.assertFalse(func.blocks[0].exit_arcs[3].on_tree)
157        self.assertFalse(func.blocks[0].exit_arcs[3].fake)
158        self.assertTrue(func.blocks[0].exit_arcs[3].fallthrough)
159
160    def testReadLines(self):
161        """Asserts that lines are read correctly.
162
163        Blocks must have correct references to the lines contained
164        in the block.
165        """
166        self.stream = MockStream.concat_int(self.stream, 2)  #  block number
167        self.stream = MockStream.concat_int(self.stream, 0)  #  dummy
168        name = "src.c"
169        name_length = int(
170            math.ceil(1.0 * len(name) / MockStream.BYTES_PER_WORD)) + 1
171        self.stream = MockStream.concat_string(self.stream, name)
172        n_arcs = 5
173        for i in range(1, n_arcs + 1):
174            self.stream = MockStream.concat_int(self.stream, i)
175
176        n_blocks = 5
177        func = function_summary.FunctionSummary(0, "func", name, 1)
178        func.blocks = [block_summary.BlockSummary(i, 3 * i)
179                       for i in range(n_blocks)]
180        parser = gcno_parser.GCNOParser(self.stream)
181        parser.ReadLines(n_arcs + name_length + 3, func)
182        self.assertEqual(len(func.blocks[2].lines), 5)
183        self.assertEqual(func.blocks[2].lines, range(1, 6))
184
185    def testSampleFile(self):
186        """Asserts correct parsing of sample GCNO file.
187
188        Verifies the blocks and lines for each function in
189        the file.
190        """
191        dir_path = os.path.dirname(os.path.realpath(__file__))
192        file_path = os.path.join(dir_path, self.GOLDEN_GCNO_PATH)
193        summary = gcno_parser.ParseGcnoFile(file_path)
194        self.assertEqual(len(summary.functions), 2)
195
196        # Check function: testFunctionName
197        func = summary.functions[4]
198        self.assertEqual(func.name, 'testFunctionName')
199        self.assertEqual(func.src_file_name, 'sample.c')
200        self.assertEqual(func.first_line_number, 35)
201        self.assertEqual(len(func.blocks), 5)
202        expected_list = [[], [], [35, 40, 41], [42], []]
203        for index, expected in zip(range(5), expected_list):
204            self.assertEqual(func.blocks[index].lines, expected)
205
206        # Check function: main
207        func = summary.functions[3]
208        self.assertEqual(func.name, 'main')
209        self.assertEqual(func.first_line_number, 5)
210        self.assertEqual(len(func.blocks), 12)
211        self.assertEqual(func.blocks[0].lines, [])
212        expected_list = [[], [], [5, 11, 12, 13], [15], [17], [18], [20],
213                         [23, 24, 25], [26, 25], [], [29], [31]]
214        for index, expected in zip(range(12), expected_list):
215            self.assertEqual(func.blocks[index].lines, expected)
216
217
218if __name__ == "__main__":
219    unittest.main()
220