phasm/tests/integration/test_lang/test_subscriptable.py
Johan B.W. de Vries f8d107f4fa Replaces did_construct with a proper router
By annotating types with the constructor application
that was used to create them.

Later on we can use the router to replace compiler's
INSTANCES or for user defined types.
2025-05-10 16:49:10 +02:00

134 lines
3.3 KiB
Python

import pytest
import wasmtime
from phasm.type3.entry import Type3Exception
from ..helpers import Suite
@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_0(type_, in_put, exp_result):
code_py = f"""
@exported
def testEntry(f: {type_}) -> u8:
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), 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(Type3Exception, match='u32 must be u8 instead'):
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(Type3Exception, match='Must index with 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(Type3Exception, 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), ),
# bytes 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(Type3Exception, 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(Type3Exception, 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(Type3Exception, match='u8 cannot be subscripted'):
Suite(code_py).run_code()