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