from tests._helpers import ( unittest, parameterized, Fraction, run_test, Bool, BuiltIn, DataArray, DataDict, Designa, ExpressionStatement, ID, ModuleCall, Nullus, Numeral, Program, String, ValInt, ValStr, ValBool, ValList, ValDict, ValNul, ValFrac, ) def _scribe(arg, modules=("IASON",)): return Program( [ModuleCall(m) for m in modules], [ExpressionStatement(BuiltIn("IASON_SCRIBE", [arg]))], ) def _lege(arg, modules=("IASON",)): return Program( [ModuleCall(m) for m in modules], [ExpressionStatement(BuiltIn("IASON_LEGE", [String(arg)]))], ) def _src_lege(arg, extra_modules=()): modules = ("IASON",) + tuple(extra_modules) prefix = "\n".join(f"CVM {m}" for m in modules) + "\n" return prefix + f"IASON_LEGE('{arg}')" def _src_scribe(arg_text, extra_modules=()): modules = ("IASON",) + tuple(extra_modules) prefix = "\n".join(f"CVM {m}" for m in modules) + "\n" return prefix + f"IASON_SCRIBE({arg_text})" iason_tests = [ # ---- Parse: scalars ---- (_src_lege("null"), _lege("null"), ValNul()), (_src_lege("true"), _lege("true"), ValBool(True)), (_src_lege("false"), _lege("false"), ValBool(False)), (_src_lege("42"), _lege("42"), ValInt(42)), (_src_lege('"hello"'), _lege('"hello"'), ValStr("hello")), # ---- Parse: empty containers ---- (_src_lege("[]"), _lege("[]"), ValList([])), (_src_lege("{}"), _lege("{}"), ValDict({})), # ---- Parse: array of mixed types ---- (_src_lege('[1, true, null, "x"]'), _lege('[1, true, null, "x"]'), ValList([ValInt(1), ValBool(True), ValNul(), ValStr("x")])), # ---- Parse: nested ---- (_src_lege('{"a": [1, 2], "b": {"c": 3}}'), _lege('{"a": [1, 2], "b": {"c": 3}}'), ValDict({ "a": ValList([ValInt(1), ValInt(2)]), "b": ValDict({"c": ValInt(3)}), })), # ---- Parse: numbers ---- (_src_lege("-7"), _lege("-7"), ValInt(-7)), (_src_lege("0"), _lege("0"), ValInt(0)), # ---- Parse: string escapes ---- # NB: single-quoted CENTVRION strings unescape \n / \" / \\ before the # JSON parser sees them, so direct parse tests for those escapes would # have ambiguous semantics. Serialize tests below cover the inverse, and # this \u test exercises the JSON parser's escape path. (_src_lege('"\\u00e9"'), _lege('"\\u00e9"'), ValStr("é")), # ---- Parse: float without FRACTIO floors ---- (_src_lege("3.7"), _lege("3.7"), ValInt(3)), (_src_lege("-2.5"), _lege("-2.5"), ValInt(-3)), (_src_lege("1e2"), _lege("1e2"), ValInt(100)), # ---- Parse: float with FRACTIO is exact ---- (_src_lege("0.5", extra_modules=("FRACTIO",)), _lege("0.5", modules=("IASON", "FRACTIO")), ValFrac(Fraction(1, 2))), (_src_lege("0.1", extra_modules=("FRACTIO",)), _lege("0.1", modules=("IASON", "FRACTIO")), ValFrac(Fraction(1, 10))), (_src_lege("-0.25", extra_modules=("FRACTIO",)), _lege("-0.25", modules=("IASON", "FRACTIO")), ValFrac(Fraction(-1, 4))), (_src_lege("5", extra_modules=("FRACTIO",)), _lege("5", modules=("IASON", "FRACTIO")), ValInt(5)), (_src_lege("3.0", extra_modules=("FRACTIO",)), _lege("3.0", modules=("IASON", "FRACTIO")), ValInt(3)), # ---- Serialize: scalars ---- (_src_scribe("NVLLVS"), _scribe(Nullus()), ValStr("null")), (_src_scribe("VERITAS"), _scribe(Bool(True)), ValStr("true")), (_src_scribe("FALSITAS"), _scribe(Bool(False)), ValStr("false")), (_src_scribe("XLII"), _scribe(Numeral("XLII")), ValStr("42")), (_src_scribe('"hello"'), _scribe(String("hello")), ValStr('"hello"')), (_src_scribe("[]"), _scribe(DataArray([])), ValStr("[]")), (_src_scribe("TABVLA {}"), _scribe(DataDict([])), ValStr("{}")), # ---- Serialize: nested ---- (_src_scribe("[I, II, III]"), _scribe(DataArray([Numeral("I"), Numeral("II"), Numeral("III")])), ValStr("[1, 2, 3]")), (_src_scribe('TABVLA {"a" VT I, "b" VT VERITAS}'), _scribe(DataDict([(String("a"), Numeral("I")), (String("b"), Bool(True))])), ValStr('{"a": 1, "b": true}')), # ---- Serialize: special chars ---- (_src_scribe('"a\\nb"'), _scribe(String("a\nb")), ValStr('"a\\nb"')), (_src_scribe('"a\\"b"'), _scribe(String('a"b')), ValStr('"a\\"b"')), (_src_scribe('"a\\\\b"'), _scribe(String("a\\b")), ValStr('"a\\\\b"')), # ---- Round-trip ---- ("CVM IASON\nDIC(IASON_LEGE('[1, 2, 3]'))", Program([ModuleCall("IASON")], [ExpressionStatement(BuiltIn("DIC", [BuiltIn("IASON_LEGE", [String("[1, 2, 3]")])]))]), ValStr("[I II III]"), "[I II III]\n"), ("CVM IASON\nDIC(IASON_SCRIBE(IASON_LEGE('{\"a\": [1, true, null]}')))", Program([ModuleCall("IASON")], [ExpressionStatement(BuiltIn("DIC", [BuiltIn("IASON_SCRIBE", [BuiltIn("IASON_LEGE", [String('{"a": [1, true, null]}')])])]))]), ValStr('{"a": [1, true, null]}'), '{"a": [1, true, null]}\n'), ("CVM IASON\nCVM FRACTIO\nDIC(IASON_SCRIBE(IASON_LEGE('0.5')))", Program([ModuleCall("IASON"), ModuleCall("FRACTIO")], [ExpressionStatement(BuiltIn("DIC", [BuiltIn("IASON_SCRIBE", [BuiltIn("IASON_LEGE", [String("0.5")])])]))]), ValStr("0.5"), "0.5\n"), ("CVM IASON\nCVM FRACTIO\nDIC(IASON_SCRIBE(IASON_LEGE('0.1')))", Program([ModuleCall("IASON"), ModuleCall("FRACTIO")], [ExpressionStatement(BuiltIn("DIC", [BuiltIn("IASON_SCRIBE", [BuiltIn("IASON_LEGE", [String("0.1")])])]))]), ValStr("0.1"), "0.1\n"), # ---- Serialize: insertion order preserved ---- (_src_scribe('TABVLA {"b" VT II, "a" VT I, "c" VT III}'), _scribe(DataDict([ (String("b"), Numeral("II")), (String("a"), Numeral("I")), (String("c"), Numeral("III")), ])), ValStr('{"b": 2, "a": 1, "c": 3}')), # ---- Whitespace-tolerant parse ---- (_src_lege(" [ 1 , 2 ] "), _lege(" [ 1 , 2 ] "), ValList([ValInt(1), ValInt(2)])), # ---- Unicode passes through serialize (ensure_ascii=False) ---- ('CVM IASON\nDIC(IASON_SCRIBE("café"))', Program([ModuleCall("IASON")], [ExpressionStatement(BuiltIn("DIC", [BuiltIn("IASON_SCRIBE", [String("café")])]))]), ValStr('"café"'), '"café"\n'), ] class TestIason(unittest.TestCase): @parameterized.expand(iason_tests) def test_iason(self, source, nodes, value, output="", input_lines=[]): run_test(self, source, nodes, value, output, input_lines)