blob: 10a23d310e6c39a7a782faf33009a4a85e66a743 [file] [log] [blame]
Ben Olmsteadc0d77842019-07-31 17:34:05 -07001# Copyright 2019 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Tests for front_end.synthetics."""
16
17import unittest
18from front_end import glue
19from front_end import synthetics
20from front_end import test_util
21from public import ir_pb2
22
23
24class SyntheticsTest(unittest.TestCase):
25
26 def _find_attribute(self, field, name):
27 result = None
28 for attribute in field.attribute:
29 if attribute.name.text == name:
30 self.assertIsNone(result)
31 result = attribute
32 self.assertIsNotNone(result)
33 return result
34
35 def _make_ir(self, emb_text):
36 ir, unused_debug_info, errors = glue.parse_emboss_file(
37 "m.emb",
38 test_util.dict_file_reader({"m.emb": emb_text}),
39 stop_before_step="synthesize_fields")
40 assert not errors, errors
41 return ir
42
43 def test_nothing_to_do(self):
44 ir = self._make_ir("struct Foo:\n"
45 " 0 [+1] UInt x\n"
46 " 1 [+1] UInt:8[] y\n")
47 self.assertEqual([], synthetics.synthesize_fields(ir))
48
49 def test_adds_anonymous_bits_fields(self):
50 ir = self._make_ir("struct Foo:\n"
51 " 0 [+1] bits:\n"
52 " 0 [+4] Bar bar\n"
53 " 4 [+4] UInt uint\n"
54 " 1 [+1] bits:\n"
55 " 0 [+4] Bits nested_bits\n"
56 "enum Bar:\n"
57 " BAR = 0\n"
58 "bits Bits:\n"
59 " 0 [+4] UInt uint\n")
60 self.assertEqual([], synthetics.synthesize_fields(ir))
61 structure = ir.module[0].type[0].structure
62 # The first field should be the anonymous bits structure.
63 self.assertTrue(structure.field[0].HasField("location"))
64 # Then the aliases generated for those structures.
65 self.assertEqual("bar", structure.field[1].name.name.text)
66 self.assertEqual("uint", structure.field[2].name.name.text)
67 # Then the second anonymous bits.
68 self.assertTrue(structure.field[3].HasField("location"))
69 # Then the alias from the second anonymous bits.
70 self.assertEqual("nested_bits", structure.field[4].name.name.text)
71
72 def test_adds_correct_existence_condition(self):
73 ir = self._make_ir("struct Foo:\n"
74 " 0 [+1] bits:\n"
75 " 0 [+4] UInt bar\n")
76 self.assertEqual([], synthetics.synthesize_fields(ir))
77 bits_field = ir.module[0].type[0].structure.field[0]
78 alias_field = ir.module[0].type[0].structure.field[1]
79 self.assertEqual("bar", alias_field.name.name.text)
80 self.assertEqual(bits_field.name.name.text,
81 alias_field.existence_condition.function.args[0].function.
82 args[0].field_reference.path[0].source_name[-1].text)
83 self.assertEqual(bits_field.name.name.text,
84 alias_field.existence_condition.function.args[1].function.
85 args[0].field_reference.path[0].source_name[-1].text)
86 self.assertEqual("bar",
87 alias_field.existence_condition.function.args[1].function.
88 args[0].field_reference.path[1].source_name[-1].text)
89 self.assertEqual(
90 ir_pb2.Function.PRESENCE,
91 alias_field.existence_condition.function.args[0].function.function)
92 self.assertEqual(
93 ir_pb2.Function.PRESENCE,
94 alias_field.existence_condition.function.args[1].function.function)
95 self.assertEqual(ir_pb2.Function.AND,
96 alias_field.existence_condition.function.function)
97
98 def test_adds_correct_read_transform(self):
99 ir = self._make_ir("struct Foo:\n"
100 " 0 [+1] bits:\n"
101 " 0 [+4] UInt bar\n")
102 self.assertEqual([], synthetics.synthesize_fields(ir))
103 bits_field = ir.module[0].type[0].structure.field[0]
104 alias_field = ir.module[0].type[0].structure.field[1]
105 self.assertEqual("bar", alias_field.name.name.text)
106 self.assertEqual(
107 bits_field.name.name.text,
108 alias_field.read_transform.field_reference.path[0].source_name[-1].text)
109 self.assertEqual(
110 "bar",
111 alias_field.read_transform.field_reference.path[1].source_name[-1].text)
112
113 def test_adds_correct_abbreviation(self):
114 ir = self._make_ir("struct Foo:\n"
115 " 0 [+1] bits:\n"
116 " 0 [+4] UInt bar\n"
117 " 4 [+4] UInt baz (qux)\n")
118 self.assertEqual([], synthetics.synthesize_fields(ir))
119 bar_alias = ir.module[0].type[0].structure.field[1]
120 baz_alias = ir.module[0].type[0].structure.field[2]
121 self.assertFalse(bar_alias.HasField("abbreviation"))
122 self.assertEqual("qux", baz_alias.abbreviation.text)
123
124 def test_anonymous_bits_sets_correct_is_synthetic(self):
125 ir = self._make_ir("struct Foo:\n"
126 " 0 [+1] bits:\n"
127 " 0 [+4] UInt bar (b)\n")
128 self.assertEqual([], synthetics.synthesize_fields(ir))
129 bits_field = ir.module[0].type[0].subtype[0].structure.field[0]
130 alias_field = ir.module[0].type[0].structure.field[1]
131 self.assertFalse(alias_field.name.source_location.is_synthetic)
132 self.assertTrue(alias_field.HasField("abbreviation"))
133 self.assertFalse(alias_field.abbreviation.source_location.is_synthetic)
134 self.assertTrue(alias_field.HasField("read_transform"))
135 read_alias = alias_field.read_transform
136 self.assertTrue(read_alias.source_location.is_synthetic)
137 self.assertTrue(
138 read_alias.field_reference.path[0].source_location.is_synthetic)
139 alias_condition = alias_field.existence_condition
140 self.assertTrue(alias_condition.source_location.is_synthetic)
141 self.assertTrue(
142 alias_condition.function.args[0].source_location.is_synthetic)
143 self.assertTrue(bits_field.name.source_location.is_synthetic)
144 self.assertTrue(bits_field.name.name.source_location.is_synthetic)
145 self.assertTrue(bits_field.abbreviation.source_location.is_synthetic)
146
147 def test_adds_text_output_skip_attribute_to_anonymous_bits(self):
148 ir = self._make_ir("struct Foo:\n"
149 " 0 [+1] bits:\n"
150 " 0 [+4] UInt bar (b)\n")
151 self.assertEqual([], synthetics.synthesize_fields(ir))
152 bits_field = ir.module[0].type[0].structure.field[0]
153 text_output_attribute = self._find_attribute(bits_field, "text_output")
154 self.assertEqual("Skip", text_output_attribute.value.string_constant.text)
155
156 def test_skip_attribute_is_marked_as_synthetic(self):
157 ir = self._make_ir("struct Foo:\n"
158 " 0 [+1] bits:\n"
159 " 0 [+4] UInt bar\n")
160 self.assertEqual([], synthetics.synthesize_fields(ir))
161 bits_field = ir.module[0].type[0].structure.field[0]
162 attribute = self._find_attribute(bits_field, "text_output")
163 self.assertTrue(attribute.source_location.is_synthetic)
164 self.assertTrue(attribute.name.source_location.is_synthetic)
165 self.assertTrue(attribute.value.source_location.is_synthetic)
166 self.assertTrue(
167 attribute.value.string_constant.source_location.is_synthetic)
168
169 def test_adds_size_in_bytes(self):
170 ir = self._make_ir("struct Foo:\n"
171 " 1 [+l] UInt:8[] bytes\n"
172 " 0 [+1] UInt length (l)\n")
173 self.assertEqual([], synthetics.synthesize_fields(ir))
174 structure = ir.module[0].type[0].structure
175 size_in_bytes_field = structure.field[2]
176 max_size_in_bytes_field = structure.field[3]
177 min_size_in_bytes_field = structure.field[4]
178 self.assertEqual("$size_in_bytes", size_in_bytes_field.name.name.text)
179 self.assertEqual(ir_pb2.Function.MAXIMUM,
180 size_in_bytes_field.read_transform.function.function)
181 self.assertEqual("$max_size_in_bytes",
182 max_size_in_bytes_field.name.name.text)
183 self.assertEqual(ir_pb2.Function.UPPER_BOUND,
184 max_size_in_bytes_field.read_transform.function.function)
185 self.assertEqual("$min_size_in_bytes",
186 min_size_in_bytes_field.name.name.text)
187 self.assertEqual(ir_pb2.Function.LOWER_BOUND,
188 min_size_in_bytes_field.read_transform.function.function)
189 # The correctness of $size_in_bytes et al are tested much further down
190 # stream, in tests of the generated C++ code.
191
192 def test_adds_size_in_bits(self):
193 ir = self._make_ir("bits Foo:\n"
194 " 1 [+9] UInt hi\n"
195 " 0 [+1] Flag lo\n")
196 self.assertEqual([], synthetics.synthesize_fields(ir))
197 structure = ir.module[0].type[0].structure
198 size_in_bits_field = structure.field[2]
199 max_size_in_bits_field = structure.field[3]
200 min_size_in_bits_field = structure.field[4]
201 self.assertEqual("$size_in_bits", size_in_bits_field.name.name.text)
202 self.assertEqual(ir_pb2.Function.MAXIMUM,
203 size_in_bits_field.read_transform.function.function)
204 self.assertEqual("$max_size_in_bits",
205 max_size_in_bits_field.name.name.text)
206 self.assertEqual(ir_pb2.Function.UPPER_BOUND,
207 max_size_in_bits_field.read_transform.function.function)
208 self.assertEqual("$min_size_in_bits",
209 min_size_in_bits_field.name.name.text)
210 self.assertEqual(ir_pb2.Function.LOWER_BOUND,
211 min_size_in_bits_field.read_transform.function.function)
212 # The correctness of $size_in_bits et al are tested much further down
213 # stream, in tests of the generated C++ code.
214
215 def test_adds_text_output_skip_attribute_to_size_in_bytes(self):
216 ir = self._make_ir("struct Foo:\n"
217 " 1 [+l] UInt:8[] bytes\n"
218 " 0 [+1] UInt length (l)\n")
219 self.assertEqual([], synthetics.synthesize_fields(ir))
220 size_in_bytes_field = ir.module[0].type[0].structure.field[2]
221 self.assertEqual("$size_in_bytes", size_in_bytes_field.name.name.text)
222 text_output_attribute = self._find_attribute(size_in_bytes_field,
223 "text_output")
224 self.assertEqual("Skip", text_output_attribute.value.string_constant.text)
225
226
227if __name__ == "__main__":
228 unittest.main()