blob: 45f99200d0aa9c78f7680a4fa56d79c8ebf4a131 [file] [log] [blame]
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for util.error."""
import unittest
from compiler.util import error
from compiler.util import parser_types
class MessageTest(unittest.TestCase):
"""Tests for _Message, as returned by error, warn, and note."""
def test_error(self):
error_message = error.error(
"foo.emb", parser_types.make_location((3, 4), (3, 6)), "Bad thing"
)
self.assertEqual("foo.emb", error_message.source_file)
self.assertEqual(error.ERROR, error_message.severity)
self.assertEqual(
parser_types.make_location((3, 4), (3, 6)), error_message.location
)
self.assertEqual("Bad thing", error_message.message)
sourceless_format = error_message.format({})
sourced_format = error_message.format({"foo.emb": "\n\nabcdefghijklm"})
self.assertEqual(
"foo.emb:3:4: error: Bad thing", "".join([x[1] for x in sourceless_format])
)
self.assertEqual(
[
(error.BOLD, "foo.emb:3:4: "), # Location
(error.BRIGHT_RED, "error: "), # Severity
(error.BOLD, "Bad thing"), # Message
],
sourceless_format,
)
self.assertEqual(
"foo.emb:3:4: error: Bad thing\n" "abcdefghijklm\n" " ^^",
"".join([x[1] for x in sourced_format]),
)
self.assertEqual(
[
(error.BOLD, "foo.emb:3:4: "), # Location
(error.BRIGHT_RED, "error: "), # Severity
(error.BOLD, "Bad thing\n"), # Message
(error.WHITE, "abcdefghijklm\n"), # Source snippet
(error.BRIGHT_GREEN, " ^^"), # Error column indicator
],
sourced_format,
)
def test_synthetic_error(self):
error_message = error.error(
"foo.emb", parser_types.make_location((3, 4), (3, 6), True), "Bad thing"
)
sourceless_format = error_message.format({})
sourced_format = error_message.format({"foo.emb": "\n\nabcdefghijklm"})
self.assertEqual(
"foo.emb:[compiler bug]: error: Bad thing",
"".join([x[1] for x in sourceless_format]),
)
self.assertEqual(
[
(error.BOLD, "foo.emb:[compiler bug]: "), # Location
(error.BRIGHT_RED, "error: "), # Severity
(error.BOLD, "Bad thing"), # Message
],
sourceless_format,
)
self.assertEqual(
"foo.emb:[compiler bug]: error: Bad thing",
"".join([x[1] for x in sourced_format]),
)
self.assertEqual(
[
(error.BOLD, "foo.emb:[compiler bug]: "), # Location
(error.BRIGHT_RED, "error: "), # Severity
(error.BOLD, "Bad thing"), # Message
],
sourced_format,
)
def test_prelude_as_file_name(self):
error_message = error.error(
"", parser_types.make_location((3, 4), (3, 6)), "Bad thing"
)
self.assertEqual("", error_message.source_file)
self.assertEqual(error.ERROR, error_message.severity)
self.assertEqual(
parser_types.make_location((3, 4), (3, 6)), error_message.location
)
self.assertEqual("Bad thing", error_message.message)
sourceless_format = error_message.format({})
sourced_format = error_message.format({"": "\n\nabcdefghijklm"})
self.assertEqual(
"[prelude]:3:4: error: Bad thing",
"".join([x[1] for x in sourceless_format]),
)
self.assertEqual(
[
(error.BOLD, "[prelude]:3:4: "), # Location
(error.BRIGHT_RED, "error: "), # Severity
(error.BOLD, "Bad thing"), # Message
],
sourceless_format,
)
self.assertEqual(
"[prelude]:3:4: error: Bad thing\n" "abcdefghijklm\n" " ^^",
"".join([x[1] for x in sourced_format]),
)
self.assertEqual(
[
(error.BOLD, "[prelude]:3:4: "), # Location
(error.BRIGHT_RED, "error: "), # Severity
(error.BOLD, "Bad thing\n"), # Message
(error.WHITE, "abcdefghijklm\n"), # Source snippet
(error.BRIGHT_GREEN, " ^^"), # Error column indicator
],
sourced_format,
)
def test_multiline_error_source(self):
error_message = error.error(
"foo.emb", parser_types.make_location((3, 4), (4, 6)), "Bad thing"
)
self.assertEqual("foo.emb", error_message.source_file)
self.assertEqual(error.ERROR, error_message.severity)
self.assertEqual(
parser_types.make_location((3, 4), (4, 6)), error_message.location
)
self.assertEqual("Bad thing", error_message.message)
sourceless_format = error_message.format({})
sourced_format = error_message.format(
{"foo.emb": "\n\nabcdefghijklm\nnopqrstuv"}
)
self.assertEqual(
"foo.emb:3:4: error: Bad thing", "".join([x[1] for x in sourceless_format])
)
self.assertEqual(
[
(error.BOLD, "foo.emb:3:4: "), # Location
(error.BRIGHT_RED, "error: "), # Severity
(error.BOLD, "Bad thing"), # Message
],
sourceless_format,
)
self.assertEqual(
"foo.emb:3:4: error: Bad thing\n" "abcdefghijklm\n" " ^",
"".join([x[1] for x in sourced_format]),
)
self.assertEqual(
[
(error.BOLD, "foo.emb:3:4: "), # Location
(error.BRIGHT_RED, "error: "), # Severity
(error.BOLD, "Bad thing\n"), # Message
(error.WHITE, "abcdefghijklm\n"), # Source snippet
(error.BRIGHT_GREEN, " ^"), # Error column indicator
],
sourced_format,
)
def test_multiline_error(self):
error_message = error.error(
"foo.emb",
parser_types.make_location((3, 4), (3, 6)),
"Bad thing\nSome explanation\nMore explanation",
)
self.assertEqual("foo.emb", error_message.source_file)
self.assertEqual(error.ERROR, error_message.severity)
self.assertEqual(
parser_types.make_location((3, 4), (3, 6)), error_message.location
)
self.assertEqual(
"Bad thing\nSome explanation\nMore explanation", error_message.message
)
sourceless_format = error_message.format({})
sourced_format = error_message.format(
{"foo.emb": "\n\nabcdefghijklm\nnopqrstuv"}
)
self.assertEqual(
"foo.emb:3:4: error: Bad thing\n"
"foo.emb:3:4: note: Some explanation\n"
"foo.emb:3:4: note: More explanation",
"".join([x[1] for x in sourceless_format]),
)
self.assertEqual(
[
(error.BOLD, "foo.emb:3:4: "), # Location
(error.BRIGHT_RED, "error: "), # Severity
(error.BOLD, "Bad thing\n"), # Message
(error.BOLD, "foo.emb:3:4: "), # Location, line 2
(error.WHITE, "note: "), # "Note" severity, line 2
(error.WHITE, "Some explanation\n"), # Message, line 2
(error.BOLD, "foo.emb:3:4: "), # Location, line 3
(error.WHITE, "note: "), # "Note" severity, line 3
(error.WHITE, "More explanation"), # Message, line 3
],
sourceless_format,
)
self.assertEqual(
"foo.emb:3:4: error: Bad thing\n"
"foo.emb:3:4: note: Some explanation\n"
"foo.emb:3:4: note: More explanation\n"
"abcdefghijklm\n"
" ^^",
"".join([x[1] for x in sourced_format]),
)
self.assertEqual(
[
(error.BOLD, "foo.emb:3:4: "), # Location
(error.BRIGHT_RED, "error: "), # Severity
(error.BOLD, "Bad thing\n"), # Message
(error.BOLD, "foo.emb:3:4: "), # Location, line 2
(error.WHITE, "note: "), # "Note" severity, line 2
(error.WHITE, "Some explanation\n"), # Message, line 2
(error.BOLD, "foo.emb:3:4: "), # Location, line 3
(error.WHITE, "note: "), # "Note" severity, line 3
(error.WHITE, "More explanation\n"), # Message, line 3
(error.WHITE, "abcdefghijklm\n"), # Source snippet
(error.BRIGHT_GREEN, " ^^"), # Column indicator
],
sourced_format,
)
def test_warn(self):
warning_message = error.warn(
"foo.emb", parser_types.make_location((3, 4), (3, 6)), "Not good thing"
)
self.assertEqual("foo.emb", warning_message.source_file)
self.assertEqual(error.WARNING, warning_message.severity)
self.assertEqual(
parser_types.make_location((3, 4), (3, 6)), warning_message.location
)
self.assertEqual("Not good thing", warning_message.message)
sourced_format = warning_message.format({"foo.emb": "\n\nabcdefghijklm"})
self.assertEqual(
"foo.emb:3:4: warning: Not good thing\n" "abcdefghijklm\n" " ^^",
"".join([x[1] for x in sourced_format]),
)
self.assertEqual(
[
(error.BOLD, "foo.emb:3:4: "), # Location
(error.BRIGHT_YELLOW, "warning: "), # Severity
(error.BOLD, "Not good thing\n"), # Message
(error.WHITE, "abcdefghijklm\n"), # Source snippet
(error.BRIGHT_GREEN, " ^^"), # Column indicator
],
sourced_format,
)
def test_note(self):
note_message = error.note(
"foo.emb", parser_types.make_location((3, 4), (3, 6)), "OK thing"
)
self.assertEqual("foo.emb", note_message.source_file)
self.assertEqual(error.NOTE, note_message.severity)
self.assertEqual(
parser_types.make_location((3, 4), (3, 6)), note_message.location
)
self.assertEqual("OK thing", note_message.message)
sourced_format = note_message.format({"foo.emb": "\n\nabcdefghijklm"})
self.assertEqual(
"foo.emb:3:4: note: OK thing\n" "abcdefghijklm\n" " ^^",
"".join([x[1] for x in sourced_format]),
)
self.assertEqual(
[
(error.BOLD, "foo.emb:3:4: "), # Location
(error.WHITE, "note: "), # Severity
(error.WHITE, "OK thing\n"), # Message
(error.WHITE, "abcdefghijklm\n"), # Source snippet
(error.BRIGHT_GREEN, " ^^"), # Column indicator
],
sourced_format,
)
def test_equality(self):
note_message = error.note(
"foo.emb", parser_types.make_location((3, 4), (3, 6)), "thing"
)
self.assertEqual(
note_message,
error.note("foo.emb", parser_types.make_location((3, 4), (3, 6)), "thing"),
)
self.assertNotEqual(
note_message,
error.warn("foo.emb", parser_types.make_location((3, 4), (3, 6)), "thing"),
)
self.assertNotEqual(
note_message,
error.note("foo2.emb", parser_types.make_location((3, 4), (3, 6)), "thing"),
)
self.assertNotEqual(
note_message,
error.note("foo.emb", parser_types.make_location((2, 4), (3, 6)), "thing"),
)
self.assertNotEqual(
note_message,
error.note("foo.emb", parser_types.make_location((3, 4), (3, 6)), "thing2"),
)
class StringTest(unittest.TestCase):
"""Tests for strings."""
# These strings are a fixed part of the API.
def test_color_strings(self):
self.assertEqual("\033[0;30m", error.BLACK)
self.assertEqual("\033[0;31m", error.RED)
self.assertEqual("\033[0;32m", error.GREEN)
self.assertEqual("\033[0;33m", error.YELLOW)
self.assertEqual("\033[0;34m", error.BLUE)
self.assertEqual("\033[0;35m", error.MAGENTA)
self.assertEqual("\033[0;36m", error.CYAN)
self.assertEqual("\033[0;37m", error.WHITE)
self.assertEqual("\033[0;1;30m", error.BRIGHT_BLACK)
self.assertEqual("\033[0;1;31m", error.BRIGHT_RED)
self.assertEqual("\033[0;1;32m", error.BRIGHT_GREEN)
self.assertEqual("\033[0;1;33m", error.BRIGHT_YELLOW)
self.assertEqual("\033[0;1;34m", error.BRIGHT_BLUE)
self.assertEqual("\033[0;1;35m", error.BRIGHT_MAGENTA)
self.assertEqual("\033[0;1;36m", error.BRIGHT_CYAN)
self.assertEqual("\033[0;1;37m", error.BRIGHT_WHITE)
self.assertEqual("\033[0;1m", error.BOLD)
self.assertEqual("\033[0m", error.RESET)
def test_error_strings(self):
self.assertEqual("error", error.ERROR)
self.assertEqual("warning", error.WARNING)
self.assertEqual("note", error.NOTE)
class SplitErrorsTest(unittest.TestCase):
def test_split_errors(self):
user_error = [
error.error(
"foo.emb", parser_types.make_location((1, 2), (3, 4)), "Bad thing"
),
error.note(
"foo.emb",
parser_types.make_location((3, 4), (5, 6)),
"Note: bad thing referrent",
),
]
user_error_2 = [
error.error(
"foo.emb", parser_types.make_location((8, 9), (10, 11)), "Bad thing"
),
error.note(
"foo.emb",
parser_types.make_location((10, 11), (12, 13)),
"Note: bad thing referrent",
),
]
synthetic_error = [
error.error(
"foo.emb", parser_types.make_location((1, 2), (3, 4)), "Bad thing"
),
error.note(
"foo.emb",
parser_types.make_location((3, 4), (5, 6), True),
"Note: bad thing referrent",
),
]
synthetic_error_2 = [
error.error(
"foo.emb",
parser_types.make_location((8, 9), (10, 11), True),
"Bad thing",
),
error.note(
"foo.emb",
parser_types.make_location((10, 11), (12, 13)),
"Note: bad thing referrent",
),
]
user_errors, synthetic_errors = error.split_errors(
[user_error, synthetic_error]
)
self.assertEqual([user_error], user_errors)
self.assertEqual([synthetic_error], synthetic_errors)
user_errors, synthetic_errors = error.split_errors(
[synthetic_error, user_error]
)
self.assertEqual([user_error], user_errors)
self.assertEqual([synthetic_error], synthetic_errors)
user_errors, synthetic_errors = error.split_errors(
[synthetic_error, user_error, synthetic_error_2, user_error_2]
)
self.assertEqual([user_error, user_error_2], user_errors)
self.assertEqual([synthetic_error, synthetic_error_2], synthetic_errors)
def test_filter_errors(self):
user_error = [
error.error(
"foo.emb", parser_types.make_location((1, 2), (3, 4)), "Bad thing"
),
error.note(
"foo.emb",
parser_types.make_location((3, 4), (5, 6)),
"Note: bad thing referrent",
),
]
synthetic_error = [
error.error(
"foo.emb", parser_types.make_location((1, 2), (3, 4)), "Bad thing"
),
error.note(
"foo.emb",
parser_types.make_location((3, 4), (5, 6), True),
"Note: bad thing referrent",
),
]
synthetic_error_2 = [
error.error(
"foo.emb",
parser_types.make_location((8, 9), (10, 11), True),
"Bad thing",
),
error.note(
"foo.emb",
parser_types.make_location((10, 11), (12, 13)),
"Note: bad thing referrent",
),
]
self.assertEqual(
[user_error],
error.filter_errors([synthetic_error, user_error, synthetic_error_2]),
)
class FormatErrorsTest(unittest.TestCase):
def test_format_errors(self):
errors = [
[error.note("foo.emb", parser_types.make_location((3, 4), (3, 6)), "note")]
]
sources = {"foo.emb": "x\ny\nz bcd\nq\n"}
self.assertEqual(
"foo.emb:3:4: note: note\n" "z bcd\n" " ^^",
error.format_errors(errors, sources),
)
bold = error.BOLD
reset = error.RESET
white = error.WHITE
bright_green = error.BRIGHT_GREEN
self.assertEqual(
bold
+ "foo.emb:3:4: "
+ reset
+ white
+ "note: "
+ reset
+ white
+ "note\n"
+ reset
+ white
+ "z bcd\n"
+ reset
+ bright_green
+ " ^^"
+ reset,
error.format_errors(errors, sources, use_color=True),
)
if __name__ == "__main__":
unittest.main()