Add unit tests
This commit is contained in:
parent
fbd62512d1
commit
ab9a7bb34e
0
test/__init__.py
Normal file
0
test/__init__.py
Normal file
137
test/test_interp.py
Normal file
137
test/test_interp.py
Normal file
@ -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))
|
86
test/test_lexer.py
Normal file
86
test/test_lexer.py
Normal file
@ -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('<<EOT\nthis\nis\na\nmultiline\nstring\nEOT'), 'TestHeredoc.test_heredoc').scan()
|
||||
self.assertEqual(tok, lexer.Token.HEREDOC)
|
||||
self.assertEqual(lit, '\nthis\nis\na\nmultiline\nstring\n')
|
||||
|
||||
class TestNumber(unittest.TestCase):
|
||||
def test_integer(self):
|
||||
tok, pos, lit = lexer.Lexer(io.StringIO('1234'), 'TestNumber.test_integer').scan()
|
||||
self.assertEqual(tok, lexer.Token.INTEGER)
|
||||
self.assertEqual(lit, "1234")
|
||||
|
||||
def test_float(self):
|
||||
tok, pos, lit = lexer.Lexer(io.StringIO('1234.5678'), 'TestNumber.test_float').scan()
|
||||
self.assertEqual(tok, lexer.Token.FLOAT)
|
||||
self.assertEqual(lit, "1234.5678")
|
||||
|
||||
def test_invalid_float(self):
|
||||
with self.assertRaises(lexer.ExpectedError) as ctx:
|
||||
lexer.Lexer(io.StringIO('1.0.0'), 'TestNumber.test_invalid_float').scan()
|
||||
self.assertIn("expected number", str(ctx.exception))
|
||||
self.assertIn("got '.'", str(ctx.exception))
|
||||
|
||||
class TestString(unittest.TestCase):
|
||||
def test_basic(self):
|
||||
tok, pos, lit = lexer.Lexer(io.StringIO('""'), 'TestString.test_basic').scan()
|
||||
self.assertEqual(tok, lexer.Token.STRING)
|
||||
self.assertEqual(lit, '""')
|
||||
|
||||
def test_escape(self):
|
||||
tok, pos, lit = lexer.Lexer(io.StringIO('"\\""'), 'TestString.test_escape').scan()
|
||||
self.assertEqual(tok, lexer.Token.STRING)
|
||||
self.assertEqual(lit, '"\\""')
|
||||
|
||||
def test_newline(self):
|
||||
with self.assertRaises(lexer.ExpectedError) as ctx:
|
||||
lexer.Lexer(io.StringIO('"\n"'), 'TestString.test_newline').scan()
|
||||
self.assertIn("expected '\"'", str(ctx.exception))
|
||||
self.assertIn("got '\\n'", str(ctx.exception))
|
217
test/test_parser.py
Normal file
217
test/test_parser.py
Normal file
@ -0,0 +1,217 @@
|
||||
from hisscl import parser, ast
|
||||
import unittest
|
||||
import io
|
||||
|
||||
class TestLiterals(unittest.TestCase):
|
||||
def test_integer(self):
|
||||
val = parser.Parser(io.StringIO('1234'), 'TestLiterals.test_integer')._parse_value()
|
||||
self.assertIsInstance(val, ast.Integer)
|
||||
assert type(val) is ast.Integer
|
||||
self.assertEqual(val.value, 1234)
|
||||
|
||||
def test_float(self):
|
||||
val = parser.Parser(io.StringIO('1234.5678'), 'TestLiterals.test_float')._parse_value()
|
||||
self.assertIsInstance(val, ast.Float)
|
||||
assert type(val) is ast.Float
|
||||
self.assertEqual(val.value, 1234.5678)
|
||||
|
||||
def test_string(self):
|
||||
val = parser.Parser(io.StringIO('"test \\" \\u26a7"'), 'TestLiterals.test_string')._parse_value()
|
||||
self.assertIsInstance(val, ast.String)
|
||||
assert type(val) is ast.String
|
||||
self.assertEqual(val.value, 'test " \u26a7')
|
||||
|
||||
def test_bool(self):
|
||||
val = parser.Parser(io.StringIO('true'), 'TestLiterals.test_bool')._parse_value()
|
||||
self.assertIsInstance(val, ast.Bool)
|
||||
assert type(val) is ast.Bool
|
||||
self.assertEqual(val.value, True)
|
||||
|
||||
def test_heredoc(self):
|
||||
val = parser.Parser(io.StringIO('<<EOT\nthis\nis\na\nmultiline\nstring\nEOT'), 'TestLiterals.test_heredoc')._parse_value()
|
||||
self.assertIsInstance(val, ast.String)
|
||||
assert type(val) is ast.String
|
||||
self.assertEqual(val.value, '\nthis\nis\na\nmultiline\nstring\n')
|
||||
|
||||
class TestCollections(unittest.TestCase):
|
||||
def test_tuple(self):
|
||||
val = parser.Parser(io.StringIO('[1, 2.0, "3", true]'), 'TestCollections.test_tuple')._parse_value()
|
||||
self.assertIsInstance(val, ast.Tuple)
|
||||
assert type(val) is ast.Tuple
|
||||
self.assertEqual(val.items, [
|
||||
ast.Integer(
|
||||
pos = ast.Position(name="TestCollections.test_tuple", line=1, col=2),
|
||||
value = 1,
|
||||
),
|
||||
ast.Float(
|
||||
pos = ast.Position(name="TestCollections.test_tuple", line=1, col=5),
|
||||
value = 2.0,
|
||||
),
|
||||
ast.String(
|
||||
pos = ast.Position(name="TestCollections.test_tuple", line=1, col=10),
|
||||
value = "3",
|
||||
),
|
||||
ast.Bool(
|
||||
pos = ast.Position(name="TestCollections.test_tuple", line=1, col=15),
|
||||
value = True,
|
||||
),
|
||||
])
|
||||
|
||||
def test_object(self):
|
||||
val = parser.Parser(io.StringIO('{true: 2.0, "3": 4, 5.0: "6"}'), 'TestCollections.test_object')._parse_value()
|
||||
self.assertIsInstance(val, ast.Object)
|
||||
assert type(val) is ast.Object
|
||||
self.assertEqual(val.items, [
|
||||
(
|
||||
ast.Bool(
|
||||
pos = ast.Position(name="TestCollections.test_object", line=1, col=2),
|
||||
value = True,
|
||||
),
|
||||
ast.Float(
|
||||
pos = ast.Position(name="TestCollections.test_object", line=1, col=8),
|
||||
value = 2.0,
|
||||
),
|
||||
),
|
||||
(
|
||||
ast.String(
|
||||
pos = ast.Position(name="TestCollections.test_object", line=1, col=13),
|
||||
value = "3",
|
||||
),
|
||||
ast.Integer(
|
||||
pos = ast.Position(name="TestCollections.test_object", line=1, col=18),
|
||||
value = 4,
|
||||
),
|
||||
),
|
||||
(
|
||||
ast.Float(
|
||||
pos = ast.Position(name="TestCollections.test_object", line=1, col=21),
|
||||
value = 5.0,
|
||||
),
|
||||
ast.String(
|
||||
pos = ast.Position(name="TestCollections.test_object", line=1, col=26),
|
||||
value = "6",
|
||||
),
|
||||
)
|
||||
])
|
||||
|
||||
class TestExpressions(unittest.TestCase):
|
||||
def test_bare_value(self):
|
||||
val = parser.Parser(io.StringIO('1234'), 'TestExpressions.test_bare_value')._parse_expr()
|
||||
self.assertIsInstance(val, ast.Integer)
|
||||
assert type(val) is ast.Integer
|
||||
self.assertEqual(val.value, 1234)
|
||||
|
||||
def test_binary(self):
|
||||
val = parser.Parser(io.StringIO('1234 == 5678'), 'TestExpressions.test_binary')._parse_expr()
|
||||
self.assertEqual(val, ast.BinaryExpression(
|
||||
pos = ast.Position(name='TestExpressions.test_binary', line=1, col=1),
|
||||
left = ast.Integer(
|
||||
pos = ast.Position(name='TestExpressions.test_binary', line=1, col=1),
|
||||
value = 1234,
|
||||
),
|
||||
op = ast.Operator(
|
||||
pos = ast.Position(name='TestExpressions.test_binary', line=1, col=6),
|
||||
value = '==',
|
||||
),
|
||||
right = ast.Integer(
|
||||
pos = ast.Position(name='TestExpressions.test_binary', line=1, col=9),
|
||||
value = 5678
|
||||
),
|
||||
))
|
||||
|
||||
def test_binary_nested(self):
|
||||
val = parser.Parser(io.StringIO('(1234 - 5) == 5678'), 'TestExpressions.test_binary_nested')._parse_expr()
|
||||
self.assertEqual(val, ast.BinaryExpression(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=2),
|
||||
left = ast.BinaryExpression(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=2),
|
||||
left = ast.Integer(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=2),
|
||||
value = 1234,
|
||||
),
|
||||
op = ast.Operator(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=7),
|
||||
value = '-',
|
||||
),
|
||||
right = ast.Integer(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=9),
|
||||
value = 5,
|
||||
),
|
||||
),
|
||||
op = ast.Operator(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=12),
|
||||
value = '==',
|
||||
),
|
||||
right = ast.Integer(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=15),
|
||||
value = 5678
|
||||
),
|
||||
))
|
||||
|
||||
def test_binary_multi(self):
|
||||
val = parser.Parser(io.StringIO('1234 == 5678 - 4444'), 'TestExpressions.test_binary_nested')._parse_expr()
|
||||
self.assertEqual(val, ast.BinaryExpression(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=1),
|
||||
left = ast.Integer(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=1),
|
||||
value = 1234,
|
||||
),
|
||||
op = ast.Operator(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=6),
|
||||
value = '==',
|
||||
),
|
||||
right = ast.BinaryExpression(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=9),
|
||||
left = ast.Integer(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=9),
|
||||
value = 5678
|
||||
),
|
||||
op = ast.Operator(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=14),
|
||||
value = '-',
|
||||
),
|
||||
right = ast.Integer(
|
||||
pos = ast.Position(name='TestExpressions.test_binary_nested', line=1, col=16),
|
||||
value = 4444,
|
||||
),
|
||||
),
|
||||
))
|
||||
|
||||
def test_expansion(self):
|
||||
val = parser.Parser(io.StringIO('x(y...)'), 'TestExpressions.test_expansion')._parse_expr()
|
||||
self.assertEqual(val, ast.FunctionCall(
|
||||
pos = ast.Position(name='TestExpressions.test_expansion', line=1, col=1),
|
||||
name = 'x',
|
||||
args = [
|
||||
ast.Expansion(
|
||||
pos = ast.Position(name='TestExpressions.test_expansion', line=1, col=3),
|
||||
value = ast.VariableRef(
|
||||
pos = ast.Position(name='TestExpressions.test_expansion', line=1, col=3),
|
||||
name = 'y',
|
||||
),
|
||||
),
|
||||
],
|
||||
))
|
||||
|
||||
def test_index(self):
|
||||
val = parser.Parser(io.StringIO('x[0]'), 'TestExpressions.test_index')._parse_expr()
|
||||
self.assertIsInstance(val, ast.Index)
|
||||
assert type(val) is ast.Index
|
||||
self.assertEqual(val.value, ast.VariableRef(
|
||||
pos = ast.Position(name='TestExpressions.test_index', line=1, col=1),
|
||||
name = 'x',
|
||||
))
|
||||
self.assertEqual(val.index, ast.Integer(
|
||||
pos = ast.Position(name='TestExpressions.test_index', line=1, col=3),
|
||||
value = 0,
|
||||
))
|
||||
|
||||
def test_unary(self):
|
||||
val = parser.Parser(io.StringIO('!true'), 'TestExpressions.test_unary')._parse_value()
|
||||
self.assertIsInstance(val, ast.UnaryExpression)
|
||||
assert type(val) is ast.UnaryExpression
|
||||
self.assertEqual(val.op.value, '!')
|
||||
self.assertEqual(val.value, ast.Bool(
|
||||
pos = ast.Position(name="TestExpressions.test_unary", line=1, col=2),
|
||||
value = True,
|
||||
))
|
Loading…
Reference in New Issue
Block a user