|
17 | 17 | import os
|
18 | 18 | import re
|
19 | 19 | import sys
|
| 20 | +import unittest |
20 | 21 | from typing import Any, cast
|
21 | 22 |
|
22 | 23 | import pytest
|
|
30 | 31 | from mypy.modulefinder import BuildSource
|
31 | 32 | from mypy.options import Options
|
32 | 33 | from mypy.server.mergecheck import check_consistency
|
| 34 | +from mypy.server.update import sort_messages_preserving_file_order |
33 | 35 | from mypy.test.config import test_temp_dir
|
34 | 36 | from mypy.test.data import DataDrivenTestCase, DataSuite, DeleteFile, UpdateFile
|
35 | 37 | from mypy.test.helpers import (
|
@@ -369,3 +371,70 @@ def get_inspect(self, program_text: str, incremental_step: int) -> list[tuple[st
|
369 | 371 |
|
370 | 372 | def normalize_messages(messages: list[str]) -> list[str]:
|
371 | 373 | return [re.sub("^tmp" + re.escape(os.sep), "", message) for message in messages]
|
| 374 | + |
| 375 | + |
| 376 | +class TestMessageSorting(unittest.TestCase): |
| 377 | + def test_simple_sorting(self) -> None: |
| 378 | + msgs = ['x.py:1: error: "int" not callable', 'foo/y.py:123: note: "X" not defined'] |
| 379 | + old_msgs = ['foo/y.py:12: note: "Y" not defined', 'x.py:8: error: "str" not callable'] |
| 380 | + assert sort_messages_preserving_file_order(msgs, old_msgs) == list(reversed(msgs)) |
| 381 | + assert sort_messages_preserving_file_order(list(reversed(msgs)), old_msgs) == list( |
| 382 | + reversed(msgs) |
| 383 | + ) |
| 384 | + |
| 385 | + def test_long_form_sorting(self) -> None: |
| 386 | + # Multi-line errors should be sorted together and not split. |
| 387 | + msg1 = [ |
| 388 | + 'x.py:1: error: "int" not callable', |
| 389 | + "and message continues (x: y)", |
| 390 | + " 1()", |
| 391 | + " ^~~", |
| 392 | + ] |
| 393 | + msg2 = [ |
| 394 | + 'foo/y.py: In function "f":', |
| 395 | + 'foo/y.py:123: note: "X" not defined', |
| 396 | + "and again message continues", |
| 397 | + ] |
| 398 | + old_msgs = ['foo/y.py:12: note: "Y" not defined', 'x.py:8: error: "str" not callable'] |
| 399 | + assert sort_messages_preserving_file_order(msg1 + msg2, old_msgs) == msg2 + msg1 |
| 400 | + assert sort_messages_preserving_file_order(msg2 + msg1, old_msgs) == msg2 + msg1 |
| 401 | + |
| 402 | + def test_mypy_error_prefix(self) -> None: |
| 403 | + # Some errors don't have a file and start with "mypy: ". These |
| 404 | + # shouldn't be sorted together with file-specific errors. |
| 405 | + msg1 = 'x.py:1: error: "int" not callable' |
| 406 | + msg2 = 'foo/y:123: note: "X" not defined' |
| 407 | + msg3 = "mypy: Error not associated with a file" |
| 408 | + old_msgs = [ |
| 409 | + "mypy: Something wrong", |
| 410 | + 'foo/y:12: note: "Y" not defined', |
| 411 | + 'x.py:8: error: "str" not callable', |
| 412 | + ] |
| 413 | + assert sort_messages_preserving_file_order([msg1, msg2, msg3], old_msgs) == [ |
| 414 | + msg2, |
| 415 | + msg1, |
| 416 | + msg3, |
| 417 | + ] |
| 418 | + assert sort_messages_preserving_file_order([msg3, msg2, msg1], old_msgs) == [ |
| 419 | + msg2, |
| 420 | + msg1, |
| 421 | + msg3, |
| 422 | + ] |
| 423 | + |
| 424 | + def test_new_file_at_the_end(self) -> None: |
| 425 | + msg1 = 'x.py:1: error: "int" not callable' |
| 426 | + msg2 = 'foo/y.py:123: note: "X" not defined' |
| 427 | + new1 = "ab.py:3: error: Problem: error" |
| 428 | + new2 = "aaa:3: error: Bad" |
| 429 | + old_msgs = ['foo/y.py:12: note: "Y" not defined', 'x.py:8: error: "str" not callable'] |
| 430 | + assert sort_messages_preserving_file_order([msg1, msg2, new1], old_msgs) == [ |
| 431 | + msg2, |
| 432 | + msg1, |
| 433 | + new1, |
| 434 | + ] |
| 435 | + assert sort_messages_preserving_file_order([new1, msg1, msg2, new2], old_msgs) == [ |
| 436 | + msg2, |
| 437 | + msg1, |
| 438 | + new1, |
| 439 | + new2, |
| 440 | + ] |
0 commit comments