mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2026-10-05 16:46:35 -05:00
Add English fallbacks for 12 missing keys in 41 language files. Report all missing keys and XML errors before failing validation. Run four regression tests in CI. All tests and 43 XML files pass.
117 lines
4.8 KiB
Python
117 lines
4.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Exercise the XML validator with valid and invalid language packs.
|
|
|
|
Run with python3 Tests/test_xmlvalidate.py. Requires Bash, GNU grep and fxparser
|
|
on PATH (npm install fast-xml-parser@4.5.2 -g, as in the Validate XML workflow).
|
|
"""
|
|
|
|
from pathlib import Path
|
|
import shutil
|
|
import subprocess
|
|
import tempfile
|
|
import unittest
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
VALIDATOR = ROOT / ".github/workflows/xmlvalidate.sh"
|
|
KEYS = ("FIRST", "SECOND", "THIRD")
|
|
|
|
|
|
class XmlValidatorTests(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
if shutil.which("fxparser") is None:
|
|
raise RuntimeError("Install fast-xml-parser@4.5.2 and put fxparser on PATH")
|
|
|
|
def setUp(self):
|
|
temporary = tempfile.TemporaryDirectory(prefix="vc-xml-validation-")
|
|
self.addCleanup(temporary.cleanup)
|
|
self.root = Path(temporary.name) / "VeraCrypt test"
|
|
self.common = self.write_language("src/Common/Language.xml")
|
|
|
|
def write_language(self, relative_path, keys=KEYS, lang="en", text=r"First\nSecond & third"):
|
|
path = self.root / relative_path
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
entries = "".join(
|
|
f' <entry lang="{lang}" key="{key}">{text}</entry>\n'
|
|
for key in keys
|
|
)
|
|
path.write_text(
|
|
'<?xml version="1.0" encoding="UTF-8"?>\n'
|
|
'<VeraCrypt>\n <localization prog-version="DEBUG">\n'
|
|
+ entries + ' </localization>\n</VeraCrypt>\n',
|
|
encoding="utf-8",
|
|
)
|
|
return path
|
|
|
|
def run_validator(self):
|
|
return subprocess.run(
|
|
["bash", str(VALIDATOR), str(self.root)],
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
text=True,
|
|
timeout=30,
|
|
)
|
|
|
|
def assert_overall_failure(self, result):
|
|
self.assertEqual(result.returncode, 1, result.stdout)
|
|
self.assertIn("Overall Result: One or more files failed validation.", result.stdout)
|
|
|
|
def test_complete_translations_and_english_fallbacks_pass(self):
|
|
fallback = self.write_language("Translations/Language.ar.xml")
|
|
translated = self.write_language("Translations/Language.nl.xml", lang="nl")
|
|
|
|
result = self.run_validator()
|
|
|
|
self.assertEqual(result.returncode, 0, result.stdout)
|
|
for path in (self.common, fallback, translated):
|
|
self.assertIn(f"{path} PASSED all checks.", result.stdout)
|
|
self.assertIn("Overall Result: All processed files passed all checks successfully.", result.stdout)
|
|
|
|
def test_reports_every_missing_key_and_continues_to_later_files(self):
|
|
arabic = self.write_language("Translations/Language.ar.xml", keys=("FIRST",))
|
|
french = self.write_language("Translations/Language.fr.xml", keys=("FIRST", "SECOND"))
|
|
dutch = self.write_language("Translations/Language.nl.xml", lang="nl")
|
|
|
|
result = self.run_validator()
|
|
|
|
self.assert_overall_failure(result)
|
|
for path, key in ((arabic, "SECOND"), (arabic, "THIRD"), (french, "THIRD")):
|
|
self.assertIn(f"Key '{key}' (from {self.common}) not found in {path}", result.stdout)
|
|
self.assertIn("2 key(s) missing.", result.stdout)
|
|
self.assertIn("1 key(s) missing.", result.stdout)
|
|
for path in (arabic, french):
|
|
self.assertIn(f"{path} FAILED one or more checks.", result.stdout)
|
|
self.assertIn(f"{dutch} PASSED all checks.", result.stdout)
|
|
|
|
def test_malformed_xml_reports_parser_error_and_continues(self):
|
|
arabic = self.write_language("Translations/Language.ar.xml")
|
|
arabic.write_text(
|
|
arabic.read_text(encoding="utf-8").replace("</VeraCrypt>", "</Broken>"),
|
|
encoding="utf-8",
|
|
)
|
|
dutch = self.write_language("Translations/Language.nl.xml", lang="nl")
|
|
|
|
result = self.run_validator()
|
|
|
|
self.assert_overall_failure(result)
|
|
self.assertIn(f"XML Validation Failed for {arabic} (fxparser exit code: 1)", result.stdout)
|
|
self.assertIn("InvalidTag", result.stdout)
|
|
self.assertIn(f"{arabic} FAILED one or more checks.", result.stdout)
|
|
self.assertIn(f"{dutch} PASSED all checks.", result.stdout)
|
|
|
|
def test_invalid_escape_reports_error_and_continues(self):
|
|
arabic = self.write_language("Translations/Language.ar.xml", text=r"Invalid\q")
|
|
dutch = self.write_language("Translations/Language.nl.xml", lang="nl")
|
|
|
|
result = self.run_validator()
|
|
|
|
self.assert_overall_failure(result)
|
|
self.assertIn(f"File '{arabic}' contains potentially invalid backslash escape sequences.", result.stdout)
|
|
self.assertIn(f"{arabic} FAILED one or more checks.", result.stdout)
|
|
self.assertIn(f"{dutch} PASSED all checks.", result.stdout)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|