149 lines
13 KiB
Python
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)
|