From ab9a7bb34e7e2ad5567b08177e3c05d9ac1ae8a0 Mon Sep 17 00:00:00 2001 From: Elara6331 Date: Tue, 12 Nov 2024 23:39:13 -0800 Subject: [PATCH] Add unit tests --- test/__init__.py | 0 test/test_interp.py | 137 ++++++++++++++++++++++++++++ test/test_lexer.py | 86 ++++++++++++++++++ test/test_parser.py | 217 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 440 insertions(+) create mode 100644 test/__init__.py create mode 100644 test/test_interp.py create mode 100644 test/test_lexer.py create mode 100644 test/test_parser.py diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/test_interp.py b/test/test_interp.py new file mode 100644 index 0000000..4d31135 --- /dev/null +++ b/test/test_interp.py @@ -0,0 +1,137 @@ +from hisscl import interp +import unittest +import io + +class TestBasic(unittest.TestCase): + def test_assignment(self): + cfg = interp.Interp(io.StringIO("x = 26.04"), "TestBasic.test_assignment").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], 26.04) + + def test_block(self): + cfg = interp.Interp(io.StringIO("x { y = 26.04 }"), "TestBasic.test_block").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], [{'y': 26.04}]) + + def test_block_labels(self): + cfg = interp.Interp(io.StringIO("x y { z = 26.04 }"), "TestBasic.test_block_labels").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], [{'z': 26.04}]) + self.assertEqual(cfg['x'][0].labels, ['y']) + +class TestExpressions(unittest.TestCase): + def test_add(self): + cfg = interp.Interp(io.StringIO("x = 123 + 333"), "TestExpressions.test_add").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], 456) + + def test_sub(self): + cfg = interp.Interp(io.StringIO("x = 456 - 333"), "TestExpressions.test_sub").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], 123) + + def test_mul(self): + cfg = interp.Interp(io.StringIO("x = 128 * 2"), "TestExpressions.test_mul").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], 256) + + def test_div(self): + cfg = interp.Interp(io.StringIO("x = 256 / 2"), "TestExpressions.test_div").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], 128) + + def test_mod(self): + cfg = interp.Interp(io.StringIO("x = 256 % 3"), "TestExpressions.test_mod").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], 1) + + def test_eq(self): + cfg = interp.Interp(io.StringIO("x = 123 == 456"), "TestExpressions.test_eq").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], False) + + def test_ne(self): + cfg = interp.Interp(io.StringIO("x = 123 != 456"), "TestExpressions.test_ne").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], True) + + def test_lt(self): + cfg = interp.Interp(io.StringIO("x = 123 < 456"), "TestExpressions.test_lt").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], True) + + def test_gt(self): + cfg = interp.Interp(io.StringIO("x = 123 > 456"), "TestExpressions.test_gt").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], False) + + def test_le(self): + cfg = interp.Interp(io.StringIO("x = 123 <= 123"), "TestExpressions.test_le").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], True) + + def test_ge(self): + cfg = interp.Interp(io.StringIO("x = 1234 >= 123"), "TestExpressions.test_ge").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], True) + + def test_or(self): + cfg = interp.Interp(io.StringIO("x = true || false"), "TestExpressions.test_or").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], True) + + def test_and(self): + cfg = interp.Interp(io.StringIO("x = true && false"), "TestExpressions.test_and").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], False) + + def test_not(self): + cfg = interp.Interp(io.StringIO("x = !true"), "TestExpressions.test_not").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], False) + + def test_neg(self): + cfg = interp.Interp(io.StringIO("x = -1"), "TestExpressions.test_neg").run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], -1) + +class TestRefs(unittest.TestCase): + def test_var(self): + i = interp.Interp(io.StringIO("x = 123 + y"), "TestRefs.test_var") + i['y'] = 333 + cfg = i.run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], 456) + + def test_index(self): + i = interp.Interp(io.StringIO("x = y[1]"), "TestRefs.test_index") + i['y'] = [123, 456, 789] + cfg = i.run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], 456) + + def test_func(self): + def y(a, b): + return a + b + i = interp.Interp(io.StringIO("x = y(123, 333)"), "TestRefs.test_func") + i['y'] = y + cfg = i.run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], 456) + + def test_func_expansion(self): + def y(a, b): + return a + b + i = interp.Interp(io.StringIO("x = y(z...)"), "TestRefs.test_func_expansion") + i['y'] = y + i['z'] = (123, 333) + cfg = i.run() + self.assertIn('x', cfg) + self.assertEqual(cfg['x'], 456) + + def test_call_uncallable(self): + i = interp.Interp(io.StringIO("x = y(123, 333)"), "TestRefs.test_call_uncallable") + i['y'] = 0 + with self.assertRaises(ValueError) as ctx: + cfg = i.run() + self.assertIn('cannot call non-callable object', str(ctx.exception)) diff --git a/test/test_lexer.py b/test/test_lexer.py new file mode 100644 index 0000000..0309851 --- /dev/null +++ b/test/test_lexer.py @@ -0,0 +1,86 @@ +from hisscl import lexer +import unittest +import io + +class TestComments(unittest.TestCase): + def test_double_slash(self): + tok, pos, lit = lexer.Lexer(io.StringIO('// this should be ignored'), 'TestComments.test_double_slash').scan() + self.assertEqual(tok, lexer.Token.EOF) + self.assertEqual(lit, '') + + def test_pound(self): + tok, pos, lit = lexer.Lexer(io.StringIO('# this should be ignored'), 'TestComments.test_pound').scan() + self.assertEqual(tok, lexer.Token.EOF) + self.assertEqual(lit, '') + + def test_multiline(self): + tok, pos, lit = lexer.Lexer(io.StringIO('/* this\nshould\nbe\nignored */'), 'TestComments.test_multiline').scan() + self.assertEqual(tok, lexer.Token.EOF) + self.assertEqual(lit, '') + +class TestOperators(unittest.TestCase): + def test_lt(self): + tok, pos, lit = lexer.Lexer(io.StringIO('<'), 'TestOperators.test_lt').scan() + self.assertEqual(tok, lexer.Token.OPERATOR) + self.assertEqual(lit, '<') + + def test_div(self): + tok, pos, lit = lexer.Lexer(io.StringIO('/'), 'TestOperators.test_div').scan() + self.assertEqual(tok, lexer.Token.OPERATOR) + self.assertEqual(lit, '/') + + def test_multichar(self): + tok, pos, lit = lexer.Lexer(io.StringIO('<='), 'TestOperators.test_multichar').scan() + self.assertEqual(tok, lexer.Token.OPERATOR) + self.assertEqual(lit, '<=') + + def test_ellipsis(self): + tok, pos, lit = lexer.Lexer(io.StringIO('...'), 'TestOperators.test_ellipsis').scan() + self.assertEqual(tok, lexer.Token.ELLIPSIS) + self.assertEqual(lit, '...') + + def test_invalid_ellipsis(self): + with self.assertRaises(lexer.ExpectedError) as ctx: + lexer.Lexer(io.StringIO('..'), 'TestOperators.test_invalid_ellipsis').scan() + self.assertIn("expected .", str(ctx.exception)) + self.assertIn("got EOF", str(ctx.exception)) + +class TestHeredoc(unittest.TestCase): + def test_heredoc(self): + tok, pos, lit = lexer.Lexer(io.StringIO('<