phasm/tests/integration/test_lang/test_subscriptable.py
Johan B.W. de Vries 24ac2d49e4 Notes
2025-08-01 19:01:25 +02:00

152 lines
3.9 KiB
Python

import pytest
import wasmtime
from phasm.type5.solver import Type5SolverException
from ..helpers import Suite
@pytest.mark.integration_test
@pytest.mark.parametrize('in_typ, in_put, out_typ, exp_result', [
('(u8, u8, )', (45, 46), 'u8', 45, ),
('u16[2]', (45, 46), 'u16', 45, ),
('u32[...]', (45, 46), 'u32', 45, ),
('bytes', b'This is a test', 'u8', 84),
])
def test_subscript_0(in_typ, in_put, out_typ, exp_result):
code_py = f"""
@exported
def testEntry(f: {in_typ}) -> {out_typ}:
return f[0]
"""
result = Suite(code_py).run_code(in_put)
assert exp_result == result.returned_value
@pytest.mark.integration_test
@pytest.mark.parametrize('type_, in_put, exp_result', [
('(u8, u8, u8, )', (45, 46, 47), 46, ),
('u8[5]', (45, 46, 47, 48, 49), 46, ),
('bytes', b'This is a test', 104)
])
def test_subscript_1(type_, in_put, exp_result):
code_py = f"""
@exported
def testEntry(f: {type_}) -> u8:
return f[1]
"""
result = Suite(code_py).run_code(in_put)
assert exp_result == result.returned_value
@pytest.mark.integration_test
@pytest.mark.parametrize('type_, in_put, exp_result', [
('(u8, u8, u8, )', (45, 46, 47), 47, ),
('u8[5]', (45, 46, 47, 48, 49), 47, ),
('bytes', b'This is a test', 105)
])
def test_subscript_2(type_, in_put, exp_result):
code_py = f"""
@exported
def testEntry(f: {type_}) -> u8:
return f[2]
"""
result = Suite(code_py).run_code(in_put)
assert exp_result == result.returned_value
@pytest.mark.integration_test
@pytest.mark.parametrize('type_, in_put, exp_result', [
('(u8, u8, )', (45, 46), 45, ),
('u8[2]', (45, 46), 45, ),
('bytes', b'This is a test', 84)
])
def test_subscript_invalid_type(type_, in_put, exp_result):
code_py = f"""
@exported
def testEntry(f: {type_}) -> u32:
return f[0]
"""
with pytest.raises(Type5SolverException, match='Not the same type'):
Suite(code_py).run_code(in_put)
@pytest.mark.integration_test
def test_subscript_tuple_must_be_literal():
code_py = """
@exported
def testEntry(x: (u8, u32, u64), y: u8) -> u64:
return x[y]
"""
with pytest.raises(Type5SolverException, match='Must index with integer literal'):
Suite(code_py).run_code()
@pytest.mark.integration_test
def test_subscript_tuple_must_be_int():
code_py = """
@exported
def testEntry(x: (u8, u32, u64)) -> u64:
return x[0.0]
"""
with pytest.raises(Type5SolverException, match='Must index with integer literal'):
Suite(code_py).run_code()
@pytest.mark.integration_test
@pytest.mark.parametrize('type_, in_put', [
('(u8, u8, )', (45, 46), ),
('u8[2]', (45, 46), ),
# dynamic_array isn't known at runtime so works like normal
])
def test_subscript_oob_constant_low(type_, in_put):
code_py = f"""
@exported
def testEntry(x: {type_}) -> u8:
return x[-1]
"""
with pytest.raises(Type5SolverException, match='Tuple index out of range'):
Suite(code_py).run_code(in_put)
@pytest.mark.integration_test
def test_subscript_oob_constant_high():
code_py = """
@exported
def testEntry(x: (u8, u32, u64)) -> u64:
return x[4]
"""
with pytest.raises(Type5SolverException, match='Tuple index out of range'):
Suite(code_py).run_code()
@pytest.mark.integration_test
@pytest.mark.parametrize('type_, in_put', [
# Cannot Subscript tuple without a constant
('u8[2]', (45, 46), ),
('bytes', b'This is a test', ),
])
def test_subscript_oob_normal(type_, in_put):
code_py = f"""
@exported
def testEntry(x: {type_}, y: u32) -> u8:
return x[y]
"""
with pytest.raises(wasmtime.Trap):
Suite(code_py).run_code(in_put, 255)
@pytest.mark.integration_test
def test_subscript_not_subscriptable():
code_py = """
@exported
def testEntry(x: u8) -> u8:
return x[0]
"""
with pytest.raises(Type5SolverException, match='Missing type class instantation: Subscriptable u8'):
Suite(code_py).run_code()