xref: /aosp_15_r20/external/emboss/compiler/util/error_test.py (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
1# 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 util.error."""
16
17import unittest
18
19from compiler.util import error
20from compiler.util import parser_types
21
22
23class MessageTest(unittest.TestCase):
24  """Tests for _Message, as returned by error, warn, and note."""
25
26  def test_error(self):
27    error_message = error.error("foo.emb", parser_types.make_location(
28        (3, 4), (3, 6)), "Bad thing")
29    self.assertEqual("foo.emb", error_message.source_file)
30    self.assertEqual(error.ERROR, error_message.severity)
31    self.assertEqual(parser_types.make_location((3, 4), (3, 6)),
32                     error_message.location)
33    self.assertEqual("Bad thing", error_message.message)
34    sourceless_format = error_message.format({})
35    sourced_format = error_message.format({"foo.emb": "\n\nabcdefghijklm"})
36    self.assertEqual("foo.emb:3:4: error: Bad thing",
37                     "".join([x[1] for x in sourceless_format]))
38    self.assertEqual([(error.BOLD, "foo.emb:3:4: "),  # Location
39                      (error.BRIGHT_RED, "error: "),  # Severity
40                      (error.BOLD, "Bad thing"),  # Message
41                     ], sourceless_format)
42    self.assertEqual("foo.emb:3:4: error: Bad thing\n"
43                     "abcdefghijklm\n"
44                     "   ^^", "".join([x[1] for x in sourced_format]))
45    self.assertEqual([(error.BOLD, "foo.emb:3:4: "),  # Location
46                      (error.BRIGHT_RED, "error: "),  # Severity
47                      (error.BOLD, "Bad thing\n"),  # Message
48                      (error.WHITE, "abcdefghijklm\n"),  # Source snippet
49                      (error.BRIGHT_GREEN, "   ^^"),  # Error column indicator
50                     ], sourced_format)
51
52  def test_synthetic_error(self):
53    error_message = error.error("foo.emb", parser_types.make_location(
54        (3, 4), (3, 6), True), "Bad thing")
55    sourceless_format = error_message.format({})
56    sourced_format = error_message.format({"foo.emb": "\n\nabcdefghijklm"})
57    self.assertEqual("foo.emb:[compiler bug]: error: Bad thing",
58                     "".join([x[1] for x in sourceless_format]))
59    self.assertEqual([
60        (error.BOLD, "foo.emb:[compiler bug]: "),  # Location
61        (error.BRIGHT_RED, "error: "),  # Severity
62        (error.BOLD, "Bad thing"),  # Message
63    ], sourceless_format)
64    self.assertEqual("foo.emb:[compiler bug]: error: Bad thing",
65                     "".join([x[1] for x in sourced_format]))
66    self.assertEqual([
67        (error.BOLD, "foo.emb:[compiler bug]: "),  # Location
68        (error.BRIGHT_RED, "error: "),  # Severity
69        (error.BOLD, "Bad thing"),  # Message
70    ], sourced_format)
71
72  def test_prelude_as_file_name(self):
73    error_message = error.error("", parser_types.make_location(
74        (3, 4), (3, 6)), "Bad thing")
75    self.assertEqual("", error_message.source_file)
76    self.assertEqual(error.ERROR, error_message.severity)
77    self.assertEqual(parser_types.make_location((3, 4), (3, 6)),
78                     error_message.location)
79    self.assertEqual("Bad thing", error_message.message)
80    sourceless_format = error_message.format({})
81    sourced_format = error_message.format({"": "\n\nabcdefghijklm"})
82    self.assertEqual("[prelude]:3:4: error: Bad thing",
83                     "".join([x[1] for x in sourceless_format]))
84    self.assertEqual([(error.BOLD, "[prelude]:3:4: "),  # Location
85                      (error.BRIGHT_RED, "error: "),  # Severity
86                      (error.BOLD, "Bad thing"),  # Message
87                     ], sourceless_format)
88    self.assertEqual("[prelude]:3:4: error: Bad thing\n"
89                     "abcdefghijklm\n"
90                     "   ^^", "".join([x[1] for x in sourced_format]))
91    self.assertEqual([(error.BOLD, "[prelude]:3:4: "),  # Location
92                      (error.BRIGHT_RED, "error: "),  # Severity
93                      (error.BOLD, "Bad thing\n"),  # Message
94                      (error.WHITE, "abcdefghijklm\n"),  # Source snippet
95                      (error.BRIGHT_GREEN, "   ^^"),  # Error column indicator
96                     ], sourced_format)
97
98  def test_multiline_error_source(self):
99    error_message = error.error("foo.emb", parser_types.make_location(
100        (3, 4), (4, 6)), "Bad thing")
101    self.assertEqual("foo.emb", error_message.source_file)
102    self.assertEqual(error.ERROR, error_message.severity)
103    self.assertEqual(parser_types.make_location((3, 4), (4, 6)),
104                     error_message.location)
105    self.assertEqual("Bad thing", error_message.message)
106    sourceless_format = error_message.format({})
107    sourced_format = error_message.format(
108        {"foo.emb": "\n\nabcdefghijklm\nnopqrstuv"})
109    self.assertEqual("foo.emb:3:4: error: Bad thing",
110                     "".join([x[1] for x in sourceless_format]))
111    self.assertEqual([(error.BOLD, "foo.emb:3:4: "),  # Location
112                      (error.BRIGHT_RED, "error: "),  # Severity
113                      (error.BOLD, "Bad thing"),  # Message
114                     ], sourceless_format)
115    self.assertEqual("foo.emb:3:4: error: Bad thing\n"
116                     "abcdefghijklm\n"
117                     "   ^", "".join([x[1] for x in sourced_format]))
118    self.assertEqual([(error.BOLD, "foo.emb:3:4: "),  # Location
119                      (error.BRIGHT_RED, "error: "),  # Severity
120                      (error.BOLD, "Bad thing\n"),  # Message
121                      (error.WHITE, "abcdefghijklm\n"),  # Source snippet
122                      (error.BRIGHT_GREEN, "   ^"),  # Error column indicator
123                     ], sourced_format)
124
125  def test_multiline_error(self):
126    error_message = error.error("foo.emb", parser_types.make_location(
127        (3, 4), (3, 6)), "Bad thing\nSome explanation\nMore explanation")
128    self.assertEqual("foo.emb", error_message.source_file)
129    self.assertEqual(error.ERROR, error_message.severity)
130    self.assertEqual(parser_types.make_location((3, 4), (3, 6)),
131                     error_message.location)
132    self.assertEqual("Bad thing\nSome explanation\nMore explanation",
133                     error_message.message)
134    sourceless_format = error_message.format({})
135    sourced_format = error_message.format(
136        {"foo.emb": "\n\nabcdefghijklm\nnopqrstuv"})
137    self.assertEqual("foo.emb:3:4: error: Bad thing\n"
138                     "foo.emb:3:4: note: Some explanation\n"
139                     "foo.emb:3:4: note: More explanation",
140                     "".join([x[1] for x in sourceless_format]))
141    self.assertEqual([(error.BOLD, "foo.emb:3:4: "),  # Location
142                      (error.BRIGHT_RED, "error: "),  # Severity
143                      (error.BOLD, "Bad thing\n"),  # Message
144                      (error.BOLD, "foo.emb:3:4: "),  # Location, line 2
145                      (error.BRIGHT_BLACK, "note: "),  # "Note" severity, line 2
146                      (error.WHITE, "Some explanation\n"),  # Message, line 2
147                      (error.BOLD, "foo.emb:3:4: "),  # Location, line 3
148                      (error.BRIGHT_BLACK, "note: "),  # "Note" severity, line 3
149                      (error.WHITE, "More explanation"),  # Message, line 3
150                     ], sourceless_format)
151    self.assertEqual("foo.emb:3:4: error: Bad thing\n"
152                     "foo.emb:3:4: note: Some explanation\n"
153                     "foo.emb:3:4: note: More explanation\n"
154                     "abcdefghijklm\n"
155                     "   ^^", "".join([x[1] for x in sourced_format]))
156    self.assertEqual([(error.BOLD, "foo.emb:3:4: "),  # Location
157                      (error.BRIGHT_RED, "error: "),  # Severity
158                      (error.BOLD, "Bad thing\n"),  # Message
159                      (error.BOLD, "foo.emb:3:4: "),  # Location, line 2
160                      (error.BRIGHT_BLACK, "note: "),  # "Note" severity, line 2
161                      (error.WHITE, "Some explanation\n"),  # Message, line 2
162                      (error.BOLD, "foo.emb:3:4: "),  # Location, line 3
163                      (error.BRIGHT_BLACK, "note: "),  # "Note" severity, line 3
164                      (error.WHITE, "More explanation\n"),  # Message, line 3
165                      (error.WHITE, "abcdefghijklm\n"),  # Source snippet
166                      (error.BRIGHT_GREEN, "   ^^"),  # Column indicator
167                     ], sourced_format)
168
169  def test_warn(self):
170    warning_message = error.warn("foo.emb", parser_types.make_location(
171        (3, 4), (3, 6)), "Not good thing")
172    self.assertEqual("foo.emb", warning_message.source_file)
173    self.assertEqual(error.WARNING, warning_message.severity)
174    self.assertEqual(parser_types.make_location((3, 4), (3, 6)),
175                     warning_message.location)
176    self.assertEqual("Not good thing", warning_message.message)
177    sourced_format = warning_message.format({"foo.emb": "\n\nabcdefghijklm"})
178    self.assertEqual("foo.emb:3:4: warning: Not good thing\n"
179                     "abcdefghijklm\n"
180                     "   ^^", "".join([x[1] for x in sourced_format]))
181    self.assertEqual([(error.BOLD, "foo.emb:3:4: "),  # Location
182                      (error.BRIGHT_MAGENTA, "warning: "),  # Severity
183                      (error.BOLD, "Not good thing\n"),  # Message
184                      (error.WHITE, "abcdefghijklm\n"),  # Source snippet
185                      (error.BRIGHT_GREEN, "   ^^"),  # Column indicator
186                     ], sourced_format)
187
188  def test_note(self):
189    note_message = error.note("foo.emb", parser_types.make_location(
190        (3, 4), (3, 6)), "OK thing")
191    self.assertEqual("foo.emb", note_message.source_file)
192    self.assertEqual(error.NOTE, note_message.severity)
193    self.assertEqual(parser_types.make_location((3, 4), (3, 6)),
194                     note_message.location)
195    self.assertEqual("OK thing", note_message.message)
196    sourced_format = note_message.format({"foo.emb": "\n\nabcdefghijklm"})
197    self.assertEqual("foo.emb:3:4: note: OK thing\n"
198                     "abcdefghijklm\n"
199                     "   ^^", "".join([x[1] for x in sourced_format]))
200    self.assertEqual([(error.BOLD, "foo.emb:3:4: "),  # Location
201                      (error.BRIGHT_BLACK, "note: "),  # Severity
202                      (error.WHITE, "OK thing\n"),  # Message
203                      (error.WHITE, "abcdefghijklm\n"),  # Source snippet
204                      (error.BRIGHT_GREEN, "   ^^"),  # Column indicator
205                     ], sourced_format)
206
207  def test_equality(self):
208    note_message = error.note("foo.emb", parser_types.make_location(
209        (3, 4), (3, 6)), "thing")
210    self.assertEqual(note_message,
211                     error.note("foo.emb", parser_types.make_location(
212                         (3, 4), (3, 6)), "thing"))
213    self.assertNotEqual(note_message,
214                        error.warn("foo.emb", parser_types.make_location(
215                            (3, 4), (3, 6)), "thing"))
216    self.assertNotEqual(note_message,
217                        error.note("foo2.emb", parser_types.make_location(
218                            (3, 4), (3, 6)), "thing"))
219    self.assertNotEqual(note_message,
220                        error.note("foo.emb", parser_types.make_location(
221                            (2, 4), (3, 6)), "thing"))
222    self.assertNotEqual(note_message,
223                        error.note("foo.emb", parser_types.make_location(
224                            (3, 4), (3, 6)), "thing2"))
225
226
227class StringTest(unittest.TestCase):
228  """Tests for strings."""
229
230  # These strings are a fixed part of the API.
231
232  def test_color_strings(self):
233    self.assertEqual("\033[0;30m", error.BLACK)
234    self.assertEqual("\033[0;31m", error.RED)
235    self.assertEqual("\033[0;32m", error.GREEN)
236    self.assertEqual("\033[0;33m", error.YELLOW)
237    self.assertEqual("\033[0;34m", error.BLUE)
238    self.assertEqual("\033[0;35m", error.MAGENTA)
239    self.assertEqual("\033[0;36m", error.CYAN)
240    self.assertEqual("\033[0;37m", error.WHITE)
241    self.assertEqual("\033[0;1;30m", error.BRIGHT_BLACK)
242    self.assertEqual("\033[0;1;31m", error.BRIGHT_RED)
243    self.assertEqual("\033[0;1;32m", error.BRIGHT_GREEN)
244    self.assertEqual("\033[0;1;33m", error.BRIGHT_YELLOW)
245    self.assertEqual("\033[0;1;34m", error.BRIGHT_BLUE)
246    self.assertEqual("\033[0;1;35m", error.BRIGHT_MAGENTA)
247    self.assertEqual("\033[0;1;36m", error.BRIGHT_CYAN)
248    self.assertEqual("\033[0;1;37m", error.BRIGHT_WHITE)
249    self.assertEqual("\033[0;1m", error.BOLD)
250    self.assertEqual("\033[0m", error.RESET)
251
252  def test_error_strings(self):
253    self.assertEqual("error", error.ERROR)
254    self.assertEqual("warning", error.WARNING)
255    self.assertEqual("note", error.NOTE)
256
257
258class SplitErrorsTest(unittest.TestCase):
259
260  def test_split_errors(self):
261    user_error = [
262        error.error("foo.emb", parser_types.make_location((1, 2), (3, 4)),
263                    "Bad thing"),
264        error.note("foo.emb", parser_types.make_location((3, 4), (5, 6)),
265                   "Note: bad thing referrent")
266    ]
267    user_error_2 = [
268        error.error("foo.emb", parser_types.make_location((8, 9), (10, 11)),
269                    "Bad thing"),
270        error.note("foo.emb", parser_types.make_location((10, 11), (12, 13)),
271                   "Note: bad thing referrent")
272    ]
273    synthetic_error = [
274        error.error("foo.emb", parser_types.make_location((1, 2), (3, 4)),
275                    "Bad thing"),
276        error.note("foo.emb", parser_types.make_location((3, 4), (5, 6), True),
277                   "Note: bad thing referrent")
278    ]
279    synthetic_error_2 = [
280        error.error("foo.emb",
281                    parser_types.make_location((8, 9), (10, 11), True),
282                    "Bad thing"),
283        error.note("foo.emb", parser_types.make_location((10, 11), (12, 13)),
284                   "Note: bad thing referrent")
285    ]
286    user_errors, synthetic_errors = error.split_errors(
287        [user_error, synthetic_error])
288    self.assertEqual([user_error], user_errors)
289    self.assertEqual([synthetic_error], synthetic_errors)
290    user_errors, synthetic_errors = error.split_errors(
291        [synthetic_error, user_error])
292    self.assertEqual([user_error], user_errors)
293    self.assertEqual([synthetic_error], synthetic_errors)
294    user_errors, synthetic_errors = error.split_errors(
295        [synthetic_error, user_error, synthetic_error_2, user_error_2])
296    self.assertEqual([user_error, user_error_2], user_errors)
297    self.assertEqual([synthetic_error, synthetic_error_2], synthetic_errors)
298
299  def test_filter_errors(self):
300    user_error = [
301        error.error("foo.emb", parser_types.make_location((1, 2), (3, 4)),
302                    "Bad thing"),
303        error.note("foo.emb", parser_types.make_location((3, 4), (5, 6)),
304                   "Note: bad thing referrent")
305    ]
306    synthetic_error = [
307        error.error("foo.emb", parser_types.make_location((1, 2), (3, 4)),
308                    "Bad thing"),
309        error.note("foo.emb", parser_types.make_location((3, 4), (5, 6), True),
310                   "Note: bad thing referrent")
311    ]
312    synthetic_error_2 = [
313        error.error("foo.emb",
314                    parser_types.make_location((8, 9), (10, 11), True),
315                    "Bad thing"),
316        error.note("foo.emb", parser_types.make_location((10, 11), (12, 13)),
317                   "Note: bad thing referrent")
318    ]
319    self.assertEqual(
320        [user_error],
321        error.filter_errors([synthetic_error, user_error, synthetic_error_2]))
322
323
324class FormatErrorsTest(unittest.TestCase):
325
326  def test_format_errors(self):
327    errors = [[error.note("foo.emb", parser_types.make_location((3, 4), (3, 6)),
328                          "note")]]
329    sources = {"foo.emb": "x\ny\nz  bcd\nq\n"}
330    self.assertEqual("foo.emb:3:4: note: note\n"
331                     "z  bcd\n"
332                     "   ^^", error.format_errors(errors, sources))
333    bold = error.BOLD
334    reset = error.RESET
335    white = error.WHITE
336    bright_black = error.BRIGHT_BLACK
337    bright_green = error.BRIGHT_GREEN
338    self.assertEqual(bold + "foo.emb:3:4: " + reset + bright_black + "note: " +
339                     reset + white + "note\n" +
340                     reset + white + "z  bcd\n" +
341                     reset + bright_green + "   ^^" + reset,
342                     error.format_errors(errors, sources, use_color=True))
343
344if __name__ == "__main__":
345  unittest.main()
346