Files
centvrion/tests/12_test_failures.py
2026-04-24 19:13:48 +02:00

149 lines
13 KiB
Python

from tests._helpers import (
unittest, parameterized, Fraction, time,
run_test, run_compiler_error_test,
ArrayIndex, ArraySlice, Bool, BinOp, BuiltIn, DataArray, DataDict, DataRangeArray,
Defini, Continva, Designa, DesignaDestructure, DesignaIndex, DumStatement,
Erumpe, ExpressionStatement, Fvnctio, ID, InterpolatedString, Invoca,
ModuleCall, Nullus, Numeral, PerStatement, Program, Redi, SiStatement,
String, TemptaStatement, UnaryMinus, UnaryNot, Fractio, frac_to_fraction,
fraction_to_frac, num_to_int, int_to_num, make_string,
ValInt, ValStr, ValBool, ValList, ValDict, ValNul, ValFunc, ValFrac,
CentvrionError, _RUNTIME_C, _cent_rng,
Lexer, Parser, compile_program,
os, subprocess, tempfile, StringIO, patch,
)
# --- Errors ---
error_tests = [
("x", CentvrionError), # undefined variable
("INVOCA f ()", CentvrionError), # undefined function
("DESIGNA VT III", SyntaxError), # parse error: missing id after DESIGNA
("DESIGNA x III", SyntaxError), # parse error: missing VT
("DEFINI f () VT { REDI(I) }\nf()", SyntaxError), # function call without INVOCA (no args)
("DEFINI f (x) VT { REDI(x) }\nf(I)", SyntaxError), # function call without INVOCA (with args)
("DIC(M + M + M + M)", CentvrionError), # output > 3999 without MAGNVM
("IIII", CentvrionError), # invalid Roman numeral in source
("FORTVITVS_NVMERVS(I, X)", CentvrionError), # requires FORS module
('NVMERVS(I)', CentvrionError), # NVMERVS expects a string, not int
('NVMERVS("ABC")', CentvrionError), # invalid Roman numeral string
('NVMERVS("XIV", "IX")', CentvrionError), # too many args
("DEFINI f (x) VT { REDI(x) }\nINVOCA f (I, II)", CentvrionError), # too many args
("DEFINI f (x, y) VT { REDI(x) }\nINVOCA f (I)", CentvrionError), # too few args
("DEFINI f () VT { REDI(I) }\nINVOCA f (I)", CentvrionError), # args to zero-param function
("SI NVLLVS TVNC { DESIGNA r VT I }", CentvrionError), # NVLLVS cannot be used as boolean
("NVLLVS AVT VERITAS", CentvrionError), # NVLLVS cannot be used as boolean in AVT
("FALSITAS AVT NVLLVS", CentvrionError), # no short-circuit: right side evaluated, NVLLVS not boolean
("VERITAS ET NVLLVS", CentvrionError), # no short-circuit: right side evaluated, NVLLVS not boolean
("NVLLVS ET VERITAS", CentvrionError), # NVLLVS cannot be used as boolean in ET
('I @ [II]', CentvrionError), # @ requires two arrays (int @ array)
('[I] @ "hello"', CentvrionError), # @ requires two arrays (array @ string)
('"a" @ "b"', CentvrionError), # @ requires two arrays (string @ string)
('"hello" + " world"', CentvrionError), # use & for string concatenation, not +
("[I, II][III]", CentvrionError), # index too high
("CVM SVBNVLLA\n[I, II][-I]", CentvrionError), # negative index
("[I, II][-I]", CentvrionError), # negative value
("I / NVLLVS", CentvrionError), # division by zero (NVLLVS coerces to 0)
("V RELIQVVM NVLLVS", CentvrionError), # modulo by zero (NVLLVS coerces to 0)
("NVLLVS RELIQVVM NVLLVS", CentvrionError), # modulo by zero (both NVLLVS)
("I / [I, II]", CentvrionError), # division with array operand
("I - \"hello\"", CentvrionError), # subtraction with string
("I * \"hello\"", CentvrionError), # multiplication with string
("\"hello\" MINVS \"world\"", CentvrionError), # comparison with strings
('"a" HAVD_PLVS "b"', CentvrionError), # HAVD_PLVS on strings
('[I] HAVD_MINVS [II]', CentvrionError), # HAVD_MINVS on arrays
("I[I]", CentvrionError), # indexing a non-array
('"SALVTE"[VII]', CentvrionError), # string index out of range
('"SALVTE"[NVLLVS]', CentvrionError), # string index with non-integer
('"SALVTE"[II VSQVE VII]', CentvrionError), # string slice out of range
('"SALVTE"[III VSQVE II]', CentvrionError), # string slice from > to
("DESIGNA x VT I\nDESIGNA x[I] VT II", CentvrionError), # index-assign to non-array
("SEMEN(I)", CentvrionError), # requires FORS module
('CVM FORS\nSEMEN("abc")', CentvrionError), # SEMEN requires integer seed
("FORTVITA_ELECTIO([])", CentvrionError), # FORS required for FORTVITA_ELECTIO
("CVM FORS\nFORTVITA_ELECTIO([])", CentvrionError), # FORTVITA_ELECTIO on empty array
("CVM FORS\nFORTVITVS_NVMERVS(X, I)", CentvrionError), # FORTVITVS_NVMERVS a > b
("PER i IN I FAC { DIC(i) }", CentvrionError), # PER over non-array
("DECIMATIO([I, II, III])", CentvrionError), # FORS required for DECIMATIO
("CVM FORS\nDECIMATIO(I)", CentvrionError), # DECIMATIO requires an array
("LONGITVDO(I)", CentvrionError), # LONGITVDO on non-array
("ORDINA(I)", CentvrionError), # ORDINA on non-array
('ORDINA([I, "a"])', CentvrionError), # ORDINA mixed types
("DESIGNA x VT I\nORDINA(x)", CentvrionError), # ORDINA on id (non-array)
("SENATVS(I)", CentvrionError), # SENATVS requires booleans
("SENATVS(VERITAS, I)", CentvrionError), # SENATVS mixed types
("SENATVS([I, II, III])", CentvrionError), # SENATVS array of non-bools
('LEGE("x.txt")', CentvrionError), # SCRIPTA required for LEGE
('SCRIBE("x.txt", "hi")', CentvrionError), # SCRIPTA required for SCRIBE
('ADIVNGE("x.txt", "hi")', CentvrionError), # SCRIPTA required for ADIVNGE
("DESIGNA x VT I\nINVOCA x ()", CentvrionError), # invoking a non-function
("SI I TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: int
("IIIS", CentvrionError), # fraction without FRACTIO module
("CVM FRACTIO\n[I, II, III][IIIS]", CentvrionError), # fractional index (IIIS = 7/2)
("CVM FRACTIO\n[I, II, III][I / II]", CentvrionError), # fractional index from division (1/2)
("DESIGNA z VT I - I\nSI z TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: zero int
("SI [I] TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: non-empty list
("SI [] TVNC { DESIGNA r VT I }", CentvrionError), # non-bool SI condition: empty list
("DESIGNA x VT I\nDVM x FAC {\nDESIGNA x VT x + I\n}", CentvrionError), # non-bool DVM condition: int
("NON I", CentvrionError), # NON on integer
("DESIGNA z VT I - I\nNON z", CentvrionError), # NON on zero integer
('NON "hello"', CentvrionError), # NON on string
("DESIGNA a, b VT III", CentvrionError), # destructure non-array
("DESIGNA a, b VT [I]", CentvrionError), # destructure length mismatch: too many targets
("DESIGNA a, b VT [I, II, III]", CentvrionError), # destructure length mismatch: too few targets
("PER a, b IN [I, II, III] FAC { DIC(a) }", CentvrionError), # PER destructure: element is not an array
("PER a, b IN [[I], [II]] FAC { DIC(a) }", CentvrionError), # PER destructure: wrong number of elements
("[I, II, III][II VSQVE IV]", CentvrionError), # slice upper bound out of range
("[I, II, III][NVLLVS VSQVE II]", CentvrionError), # slice with non-integer bound
("I[I VSQVE II]", CentvrionError), # slice on non-array
("[I, II, III][III VSQVE I]", CentvrionError), # slice from > to
("CVM SVBNVLLA\n[I, II, III][-I VSQVE II]", CentvrionError), # slice with negative lower bound
("CVM SVBNVLLA\n[I, II, III][I VSQVE -I]", CentvrionError), # slice with negative upper bound
("CVM FRACTIO\n[I, II, III][IIIS VSQVE III]", CentvrionError), # slice with fractional lower bound
("CVM FRACTIO\n[I, II, III][I VSQVE IIIS]", CentvrionError), # slice with fractional upper bound
("CVM FRACTIO\n[I, II, III][I / II VSQVE III]", CentvrionError), # slice with division-fraction lower bound
("TEMPTA {\nDESIGNA x VT I / NVLLVS\n} CAPE e {\nDESIGNA y VT I / NVLLVS\n}", CentvrionError), # uncaught error in catch block propagates
('QVAERE(I, "abc")', CentvrionError), # QVAERE requires strings, not int
('QVAERE("abc", I)', CentvrionError), # QVAERE requires strings, not int
('QVAERE("[", "abc")', CentvrionError), # QVAERE invalid regex
('SVBSTITVE(I, "b", "c")', CentvrionError), # SVBSTITVE requires strings, not int pattern
('SVBSTITVE("a", I, "c")', CentvrionError), # SVBSTITVE requires strings, not int replacement
('SVBSTITVE("a", "b", I)', CentvrionError), # SVBSTITVE requires strings, not int text
('SVBSTITVE("[", "b", "c")', CentvrionError), # SVBSTITVE invalid regex
("SVBSTITVE('(a)', '\\1', 'a')", CentvrionError), # Arabic backref in replacement
("QVAERE('(.)\\1', 'aa')", CentvrionError), # Arabic backref in pattern
("QVAERE('a{3}', 'aaa')", CentvrionError), # Arabic quantifier in pattern
('SCINDE(I, ",")', CentvrionError), # SCINDE requires strings, not int
('SCINDE("a", I)', CentvrionError), # SCINDE requires strings, not int delimiter
('MAIVSCVLA(I)', CentvrionError), # MAIVSCVLA requires a string, not int
('MAIVSCVLA()', CentvrionError), # MAIVSCVLA requires exactly 1 arg
('MAIVSCVLA("a", "b")', CentvrionError), # MAIVSCVLA too many args
('MINVSCVLA(I)', CentvrionError), # MINVSCVLA requires a string, not int
('MINVSCVLA()', CentvrionError), # MINVSCVLA requires exactly 1 arg
('MINVSCVLA("a", "b")', CentvrionError), # MINVSCVLA too many args
('PETE("http://example.com")', CentvrionError), # RETE required for PETE
('CVM RETE\nPETE(I)', CentvrionError), # PETE requires a string URL
('PETITVR("/", FVNCTIO (r) VT {\nREDI("hi")\n})', CentvrionError), # RETE required for PETITVR
('CVM RETE\nPETITVR(I, FVNCTIO (r) VT {\nREDI("hi")\n})', CentvrionError), # PETITVR path must be string
('CVM RETE\nPETITVR("/", "not a func")', CentvrionError), # PETITVR handler must be function
('CVM RETE\nAVSCVLTA(LXXX)', CentvrionError), # AVSCVLTA: no routes registered
('AVSCVLTA(LXXX)', CentvrionError), # RETE required for AVSCVLTA
('CVM RETE\nPETITVR("/", FVNCTIO (r) VT {\nREDI("hi")\n})\nAVSCVLTA("text")', CentvrionError), # AVSCVLTA port must be integer
("DONICVM i VT I VSQVE X GRADV I - I FAC { DIC(i) }", CentvrionError), # GRADV zero step
('DONICVM i VT I VSQVE X GRADV "foo" FAC { DIC(i) }', CentvrionError), # GRADV non-integer step
]
class TestErrors(unittest.TestCase):
@parameterized.expand(error_tests)
def test_errors(self, source, error_type):
with self.assertRaises(error_type):
run_test(self, source, None, None)
compiler_error_tests = [(s, e) for s, e in error_tests if e == CentvrionError]
class TestCompilerErrors(unittest.TestCase):
@parameterized.expand(compiler_error_tests)
def test_compiler_errors(self, source, error_type):
run_compiler_error_test(self, source)