874b6f20c2
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
105 lines
5.4 KiB
Python
105 lines
5.4 KiB
Python
import json
|
||
from pathlib import Path
|
||
import tempfile
|
||
import unittest
|
||
from unittest import mock
|
||
|
||
from tools import test_rust_parity as parity
|
||
|
||
|
||
class ParityRunnerTests(unittest.TestCase):
|
||
def test_report_rejects_sources_changed_during_a_run(self):
|
||
with tempfile.TemporaryDirectory() as temp:
|
||
# Resolved, as source_hashes resolves the sources: macOS's temp folder is a symlink
|
||
# (/var -> /private/var).
|
||
root = Path(temp).resolve()
|
||
source = root / "source.rs"
|
||
source.write_text("before")
|
||
with mock.patch.object(parity.lab, "ROOT", root):
|
||
before = parity.source_hashes([source])
|
||
parity.ensure_sources_unchanged([source], before)
|
||
source.write_text("after")
|
||
with self.assertRaisesRegex(RuntimeError, "source.rs"):
|
||
parity.ensure_sources_unchanged([source], before)
|
||
def test_comparison_rejects_changed_missing_extra_and_empty_results(self):
|
||
for reference, candidate in [("rng 0 1\n", "rng 0 2\n"),
|
||
("rng 0 1\n", ""),
|
||
("rng 0 1\n", "rng 0 1\nrng 1 2\n"), ("", "")]:
|
||
with self.subTest(reference=reference, candidate=candidate), tempfile.TemporaryDirectory() as temp:
|
||
left, right = Path(temp) / "reference", Path(temp) / "candidate"
|
||
left.write_text(reference)
|
||
right.write_text(candidate)
|
||
with self.assertRaises(AssertionError):
|
||
parity.compare(left, right)
|
||
|
||
def test_comparison_counts_matching_lines(self):
|
||
with tempfile.TemporaryDirectory() as temp:
|
||
left, right = Path(temp) / "reference", Path(temp) / "candidate"
|
||
left.write_text("rng 0 1\nrng 1 -1\n")
|
||
right.write_text(left.read_text())
|
||
self.assertEqual(parity.compare(left, right), 2)
|
||
|
||
def test_chunk_comparison_preserves_newlines_unicode_and_unterminated_lines(self):
|
||
cases = [
|
||
("one", "one", 1),
|
||
("\n\n", "\n\n", 2),
|
||
("one\r\ntwo\r", "one\ntwo\n", 2),
|
||
("α" * (1024 * 1024 + 1) + "\r\nlast", "α" * (1024 * 1024 + 1) + "\nlast", 2),
|
||
("same\n" * 220000 + "tail", "same\n" * 220000 + "tail", 220001),
|
||
]
|
||
with tempfile.TemporaryDirectory() as temp:
|
||
left, right = Path(temp) / "reference", Path(temp) / "candidate"
|
||
for reference, candidate, count in cases:
|
||
left.write_bytes(reference.encode("utf-8"))
|
||
right.write_bytes(candidate.encode("utf-8"))
|
||
self.assertEqual(parity.compare(left, right), count)
|
||
|
||
def test_chunk_mismatch_retains_exact_first_line_diagnostic(self):
|
||
prefix = "same\n" * 220000
|
||
cases = [("expected\n", "actual\n", "'expected\\n'", "'actual\\n'"),
|
||
("tail", "tail\n", "'tail'", "'tail\\n'"),
|
||
("extra\n", "", "'extra\\n'", "None")]
|
||
with tempfile.TemporaryDirectory() as temp:
|
||
left, right = Path(temp) / "reference", Path(temp) / "candidate"
|
||
for reference, candidate, expected, actual in cases:
|
||
left.write_text(prefix + reference)
|
||
right.write_text(prefix + candidate)
|
||
with self.assertRaises(AssertionError) as caught:
|
||
parity.compare(left, right)
|
||
self.assertEqual(str(caught.exception),
|
||
f"Parity mismatch at output line 220001: vanilla={expected}, Rust={actual}")
|
||
|
||
def test_failed_artifact_verification_removes_previous_success(self):
|
||
with tempfile.TemporaryDirectory() as temp:
|
||
local = Path(temp)
|
||
report = local / "rust-parity/report.json"
|
||
report.parent.mkdir()
|
||
report.write_text(json.dumps({"previous_success": True}))
|
||
with mock.patch.object(parity.lab, "LOCAL", local), mock.patch("sys.argv", ["parity"]), \
|
||
mock.patch.object(parity, "verify_artifacts", side_effect=ValueError("corrupt artifact")):
|
||
with self.assertRaisesRegex(ValueError, "corrupt artifact"):
|
||
parity.main()
|
||
self.assertFalse(report.exists())
|
||
|
||
def test_corpus_is_repeatable_and_contains_rejection_and_word_boundaries(self):
|
||
commands = list(parity.corpus())
|
||
self.assertEqual(commands, list(parity.corpus()))
|
||
self.assertIn("xoroshiro_state 0 0 2200", commands)
|
||
self.assertIn("legacy -9223372036854775808 2200", commands)
|
||
factories = [line.split() for line in commands if line.startswith("factory ")]
|
||
self.assertEqual(len(factories), 4400)
|
||
self.assertTrue({"-", "d800", "dc00", "d83dde00", "d8000061dc00"} <= {line[9] for line in factories})
|
||
helpers = [line.split() for line in commands if line.startswith("helpers ")]
|
||
self.assertEqual(len(helpers), 5000)
|
||
for stream in ["legacy", "xoroshiro"]:
|
||
bounds = {(int(line[3]), int(line[4])) for line in helpers if line[1] == stream}
|
||
self.assertTrue({(-2147483648, 2147483647), (2147483647, -2147483648), (0, 0), (0, 1073741825)} <= bounds)
|
||
for bits in range(1, 33):
|
||
lengths = {int(line.split()[2]) for line in commands if line.startswith(f"storage {bits} ")}
|
||
per_word = 64 // bits
|
||
self.assertTrue({0, 1, per_word - 1, per_word, per_word + 1, 4096} <= lengths)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|