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

224 lines
14 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,
)
# --- Comparison operators ---
comparison_tests = [
# EST on strings
('\"hello\" EST \"hello\"', Program([], [ExpressionStatement(BinOp(String("hello"), String("hello"), "KEYWORD_EST"))]), ValBool(True)),
('\"hello\" EST \"world\"', Program([], [ExpressionStatement(BinOp(String("hello"), String("world"), "KEYWORD_EST"))]), ValBool(False)),
# chain comparisons as conditions
("SI III PLVS II TVNC { DESIGNA r VT I }\nr",
Program([], [SiStatement(BinOp(Numeral("III"), Numeral("II"), "KEYWORD_PLVS"), [Designa(ID("r"), Numeral("I"))], None), ExpressionStatement(ID("r"))]),
ValInt(1)),
("SI II PLVS III TVNC { DESIGNA r VT I } ALIVD { DESIGNA r VT II }\nr",
Program([], [SiStatement(BinOp(Numeral("II"), Numeral("III"), "KEYWORD_PLVS"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
ValInt(2)),
# result of comparison is ValBool
("I EST I", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("I"), "KEYWORD_EST"))]), ValBool(True)),
("I EST II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_EST"))]), ValBool(False)),
("I MINVS II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_MINVS"))]), ValBool(True)),
("II MINVS I", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("I"), "KEYWORD_MINVS"))]), ValBool(False)),
("II PLVS I", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("I"), "KEYWORD_PLVS"))]), ValBool(True)),
("I PLVS II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_PLVS"))]), ValBool(False)),
# NVLLVS coerces to 0 in comparisons
("V PLVS NVLLVS", Program([], [ExpressionStatement(BinOp(Numeral("V"), Nullus(), "KEYWORD_PLVS"))]), ValBool(True)),
("NVLLVS MINVS V", Program([], [ExpressionStatement(BinOp(Nullus(), Numeral("V"), "KEYWORD_MINVS"))]), ValBool(True)),
# DISPAR (not-equal): mirrors EST semantics, negated
("I DISPAR II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_DISPAR"))]), ValBool(True)),
("I DISPAR I", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("I"), "KEYWORD_DISPAR"))]), ValBool(False)),
('"hello" DISPAR "hello"', Program([], [ExpressionStatement(BinOp(String("hello"), String("hello"), "KEYWORD_DISPAR"))]), ValBool(False)),
('"hello" DISPAR "world"', Program([], [ExpressionStatement(BinOp(String("hello"), String("world"), "KEYWORD_DISPAR"))]), ValBool(True)),
("VERITAS DISPAR FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(False), "KEYWORD_DISPAR"))]), ValBool(True)),
("NVLLVS DISPAR NVLLVS", Program([], [ExpressionStatement(BinOp(Nullus(), Nullus(), "KEYWORD_DISPAR"))]), ValBool(False)),
# cross-type: an int and a string are never equal
('I DISPAR "I"', Program([], [ExpressionStatement(BinOp(Numeral("I"), String("I"), "KEYWORD_DISPAR"))]), ValBool(True)),
# integer 0 equals NVLLVS
("(I - I) EST NVLLVS", Program([], [ExpressionStatement(BinOp(BinOp(Numeral("I"), Numeral("I"), "SYMBOL_MINUS"), Nullus(), "KEYWORD_EST"))]), ValBool(True)),
("NVLLVS EST (I - I)", Program([], [ExpressionStatement(BinOp(Nullus(), BinOp(Numeral("I"), Numeral("I"), "SYMBOL_MINUS"), "KEYWORD_EST"))]), ValBool(True)),
("(I - I) DISPAR NVLLVS", Program([], [ExpressionStatement(BinOp(BinOp(Numeral("I"), Numeral("I"), "SYMBOL_MINUS"), Nullus(), "KEYWORD_DISPAR"))]), ValBool(False)),
("NVLLVS DISPAR (I - I)", Program([], [ExpressionStatement(BinOp(Nullus(), BinOp(Numeral("I"), Numeral("I"), "SYMBOL_MINUS"), "KEYWORD_DISPAR"))]), ValBool(False)),
# non-zero integer does not equal NVLLVS
("I EST NVLLVS", Program([], [ExpressionStatement(BinOp(Numeral("I"), Nullus(), "KEYWORD_EST"))]), ValBool(False)),
("NVLLVS DISPAR I", Program([], [ExpressionStatement(BinOp(Nullus(), Numeral("I"), "KEYWORD_DISPAR"))]), ValBool(True)),
# EST / DISPAR on arrays
("[I, II] EST [I, II]", Program([], [ExpressionStatement(BinOp(DataArray([Numeral("I"), Numeral("II")]), DataArray([Numeral("I"), Numeral("II")]), "KEYWORD_EST"))]), ValBool(True)),
("[I, II] EST [I, III]", Program([], [ExpressionStatement(BinOp(DataArray([Numeral("I"), Numeral("II")]), DataArray([Numeral("I"), Numeral("III")]), "KEYWORD_EST"))]), ValBool(False)),
("[I, II] EST [I, II, III]", Program([], [ExpressionStatement(BinOp(DataArray([Numeral("I"), Numeral("II")]), DataArray([Numeral("I"), Numeral("II"), Numeral("III")]), "KEYWORD_EST"))]), ValBool(False)),
("[] EST []", Program([], [ExpressionStatement(BinOp(DataArray([]), DataArray([]), "KEYWORD_EST"))]), ValBool(True)),
("[I, II] DISPAR [I, III]", Program([], [ExpressionStatement(BinOp(DataArray([Numeral("I"), Numeral("II")]), DataArray([Numeral("I"), Numeral("III")]), "KEYWORD_DISPAR"))]), ValBool(True)),
("[I, II] DISPAR [I, II]", Program([], [ExpressionStatement(BinOp(DataArray([Numeral("I"), Numeral("II")]), DataArray([Numeral("I"), Numeral("II")]), "KEYWORD_DISPAR"))]), ValBool(False)),
# HAVD_PLVS (<=) and HAVD_MINVS (>=)
("I HAVD_PLVS II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_HAVD_PLVS"))]), ValBool(True)),
("II HAVD_PLVS I", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("I"), "KEYWORD_HAVD_PLVS"))]), ValBool(False)),
# equality boundary — the only case that distinguishes <= from <
("II HAVD_PLVS II", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("II"), "KEYWORD_HAVD_PLVS"))]), ValBool(True)),
("II HAVD_MINVS I", Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("I"), "KEYWORD_HAVD_MINVS"))]), ValBool(True)),
("I HAVD_MINVS II", Program([], [ExpressionStatement(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_HAVD_MINVS"))]), ValBool(False)),
# equality boundary — the only case that distinguishes >= from >
("II HAVD_MINVS II",Program([], [ExpressionStatement(BinOp(Numeral("II"), Numeral("II"), "KEYWORD_HAVD_MINVS"))]), ValBool(True)),
# NVLLVS coerces to 0
("V HAVD_MINVS NVLLVS", Program([], [ExpressionStatement(BinOp(Numeral("V"), Nullus(), "KEYWORD_HAVD_MINVS"))]), ValBool(True)),
("NVLLVS HAVD_PLVS V", Program([], [ExpressionStatement(BinOp(Nullus(), Numeral("V"), "KEYWORD_HAVD_PLVS"))]), ValBool(True)),
("NVLLVS HAVD_PLVS NVLLVS", Program([], [ExpressionStatement(BinOp(Nullus(), Nullus(), "KEYWORD_HAVD_PLVS"))]), ValBool(True)),
# precedence: * binds tighter, so II*III HAVD_PLVS VI parses as (II*III) HAVD_PLVS VI = 6 <= 6 = True
("II * III HAVD_PLVS VI",
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("II"), Numeral("III"), "SYMBOL_TIMES"), Numeral("VI"), "KEYWORD_HAVD_PLVS"))]),
ValBool(True)),
# control flow: SI ... HAVD_MINVS
("SI II HAVD_MINVS II TVNC { DESIGNA r VT I } ALIVD { DESIGNA r VT II }\nr",
Program([], [SiStatement(BinOp(Numeral("II"), Numeral("II"), "KEYWORD_HAVD_MINVS"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
ValInt(1)),
]
class TestComparisons(unittest.TestCase):
@parameterized.expand(comparison_tests)
def test_comparisons(self, source, nodes, value):
run_test(self, source, nodes, value)
# --- ET and AVT (boolean and/or) ---
et_avt_tests = [
("VERITAS ET VERITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(True), "KEYWORD_ET"))]), ValBool(True)),
("VERITAS ET FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(False), "KEYWORD_ET"))]), ValBool(False)),
("FALSITAS ET VERITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(True), "KEYWORD_ET"))]), ValBool(False)),
("FALSITAS ET FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(False), "KEYWORD_ET"))]), ValBool(False)),
("VERITAS AVT VERITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(True), "KEYWORD_AVT"))]), ValBool(True)),
("VERITAS AVT FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(True), Bool(False), "KEYWORD_AVT"))]), ValBool(True)),
("FALSITAS AVT VERITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(True), "KEYWORD_AVT"))]), ValBool(True)),
("FALSITAS AVT FALSITAS", Program([], [ExpressionStatement(BinOp(Bool(False), Bool(False), "KEYWORD_AVT"))]), ValBool(False)),
# short-circuit behavior: combined with comparisons
("(I EST I) ET (II EST II)",
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("I"), Numeral("I"), "KEYWORD_EST"), BinOp(Numeral("II"), Numeral("II"), "KEYWORD_EST"), "KEYWORD_ET"))]),
ValBool(True)),
("(I EST II) AVT (II EST II)",
Program([], [ExpressionStatement(BinOp(BinOp(Numeral("I"), Numeral("II"), "KEYWORD_EST"), BinOp(Numeral("II"), Numeral("II"), "KEYWORD_EST"), "KEYWORD_AVT"))]),
ValBool(True)),
# used as SI condition
("SI VERITAS ET VERITAS TVNC { DESIGNA r VT I } ALIVD { DESIGNA r VT II }\nr",
Program([], [SiStatement(BinOp(Bool(True), Bool(True), "KEYWORD_ET"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
ValInt(1)),
("SI FALSITAS AVT FALSITAS TVNC { DESIGNA r VT I } ALIVD { DESIGNA r VT II }\nr",
Program([], [SiStatement(BinOp(Bool(False), Bool(False), "KEYWORD_AVT"), [Designa(ID("r"), Numeral("I"))], [Designa(ID("r"), Numeral("II"))]), ExpressionStatement(ID("r"))]),
ValInt(2)),
# short-circuit: right side not evaluated when result is determined
("VERITAS AVT NVLLVS",
Program([], [ExpressionStatement(BinOp(Bool(True), Nullus(), "KEYWORD_AVT"))]),
ValBool(True)),
("FALSITAS ET NVLLVS",
Program([], [ExpressionStatement(BinOp(Bool(False), Nullus(), "KEYWORD_ET"))]),
ValBool(False)),
# short-circuit with side-effect-prone expressions
("DESIGNA x VT NVLLVS\nSI x EST NVLLVS AVT [I, II][x] EST I TVNC { DESIGNA r VT I } ALIVD { DESIGNA r VT II }\nr",
Program([], [
Designa(ID("x"), Nullus()),
SiStatement(
BinOp(BinOp(ID("x"), Nullus(), "KEYWORD_EST"), BinOp(ArrayIndex(DataArray([Numeral("I"), Numeral("II")]), ID("x")), Numeral("I"), "KEYWORD_EST"), "KEYWORD_AVT"),
[Designa(ID("r"), Numeral("I"))],
[Designa(ID("r"), Numeral("II"))]),
ExpressionStatement(ID("r"))]),
ValInt(1)),
("DESIGNA x VT NVLLVS\nSI x DISPAR NVLLVS ET [I, II][x] EST I TVNC { DESIGNA r VT I } ALIVD { DESIGNA r VT II }\nr",
Program([], [
Designa(ID("x"), Nullus()),
SiStatement(
BinOp(BinOp(ID("x"), Nullus(), "KEYWORD_DISPAR"), BinOp(ArrayIndex(DataArray([Numeral("I"), Numeral("II")]), ID("x")), Numeral("I"), "KEYWORD_EST"), "KEYWORD_ET"),
[Designa(ID("r"), Numeral("I"))],
[Designa(ID("r"), Numeral("II"))]),
ExpressionStatement(ID("r"))]),
ValInt(2)),
]
class TestEtAvt(unittest.TestCase):
@parameterized.expand(et_avt_tests)
def test_et_avt(self, source, nodes, value):
run_test(self, source, nodes, value)
# --- NON (boolean not) ---
non_tests = [
("NON VERITAS",
Program([], [ExpressionStatement(UnaryNot(Bool(True)))]),
ValBool(False)),
("NON FALSITAS",
Program([], [ExpressionStatement(UnaryNot(Bool(False)))]),
ValBool(True)),
("NON NON VERITAS",
Program([], [ExpressionStatement(UnaryNot(UnaryNot(Bool(True))))]),
ValBool(True)),
("DESIGNA b VT I EST II\nNON b",
Program([], [Designa(ID("b"), BinOp(Numeral("I"), Numeral("II"), "KEYWORD_EST")), ExpressionStatement(UnaryNot(ID("b")))]),
ValBool(True)),
("DESIGNA z VT I EST I\nNON z",
Program([], [Designa(ID("z"), BinOp(Numeral("I"), Numeral("I"), "KEYWORD_EST")), ExpressionStatement(UnaryNot(ID("z")))]),
ValBool(False)),
("NON VERITAS AVT FALSITAS",
Program([], [ExpressionStatement(BinOp(UnaryNot(Bool(True)), Bool(False), "KEYWORD_AVT"))]),
ValBool(False)),
("NON VERITAS EST FALSITAS",
Program([], [ExpressionStatement(BinOp(UnaryNot(Bool(True)), Bool(False), "KEYWORD_EST"))]),
ValBool(True)),
]
class TestNon(unittest.TestCase):
@parameterized.expand(non_tests)
def test_non(self, source, nodes, value):
run_test(self, source, nodes, value)
# --- Values: equality and truthiness ---
class TestValues(unittest.TestCase):
def test_valint_equality(self):
self.assertEqual(ValInt(3), ValInt(3))
self.assertNotEqual(ValInt(3), ValInt(4))
def test_valstr_equality(self):
self.assertEqual(ValStr("hi"), ValStr("hi"))
self.assertNotEqual(ValStr("hi"), ValStr("bye"))
def test_valbool_equality(self):
self.assertEqual(ValBool(True), ValBool(True))
self.assertNotEqual(ValBool(True), ValBool(False))
def test_valnul_equality(self):
self.assertEqual(ValNul(), ValNul())
def test_vallist_equality(self):
self.assertEqual(ValList([ValInt(1)]), ValList([ValInt(1)]))
self.assertNotEqual(ValList([ValInt(1)]), ValList([ValInt(2)]))
self.assertNotEqual(ValList([ValInt(1)]), ValList([]))
def test_valint_truthiness(self):
self.assertTrue(bool(ValInt(1)))
self.assertTrue(bool(ValInt(-1)))
self.assertFalse(bool(ValInt(0)))
def test_valstr_truthiness(self):
self.assertTrue(bool(ValStr("x")))
self.assertFalse(bool(ValStr("")))
def test_valbool_truthiness(self):
self.assertTrue(bool(ValBool(True)))
self.assertFalse(bool(ValBool(False)))
def test_vallist_truthiness(self):
self.assertTrue(bool(ValList([ValInt(1)])))
self.assertFalse(bool(ValList([])))
def test_cross_type_inequality(self):
self.assertNotEqual(ValInt(1), ValBool(True))
self.assertNotEqual(ValInt(0), ValNul())
self.assertNotEqual(ValStr(""), ValNul())