phasm/tests/integration/test_lang/test_struct.py
Johan B.W. de Vries ac4b46bbe7 Fix: You could assign structs to each other
As long as the arguments matched at least.
2025-05-12 20:00:56 +02:00

177 lines
3.8 KiB
Python

import pytest
from phasm.exceptions import StaticError
from phasm.type3.entry import Type3Exception
from ..helpers import Suite
@pytest.mark.integration_test
def test_struct_0():
code_py = """
class CheckedValue:
value: i32
@exported
def testEntry() -> i32:
return helper(CheckedValue(23))
def helper(cv: CheckedValue) -> i32:
return cv.value
"""
result = Suite(code_py).run_code()
assert 23 == result.returned_value
@pytest.mark.integration_test
def test_struct_1():
code_py = """
class Rectangle:
height: i32
width: i32
border: i32
@exported
def testEntry() -> i32:
return helper(Rectangle(100, 150, 2))
def helper(shape: Rectangle) -> i32:
return shape.height + shape.width + shape.border
"""
result = Suite(code_py).run_code()
assert 252 == result.returned_value
@pytest.mark.integration_test
def test_struct_2():
code_py = """
class Rectangle:
height: i32
width: i32
border: i32
@exported
def testEntry() -> i32:
return helper(Rectangle(100, 150, 2), Rectangle(200, 90, 3))
def helper(shape1: Rectangle, shape2: Rectangle) -> i32:
return shape1.height + shape1.width + shape1.border + shape2.height + shape2.width + shape2.border
"""
result = Suite(code_py).run_code()
assert 545 == result.returned_value
@pytest.mark.integration_test
def test_type_mismatch_struct_call_root():
code_py = """
class CheckedValueBlue:
value: i32
class CheckedValueRed:
value: i32
CONST: CheckedValueBlue = CheckedValueRed(1)
"""
with pytest.raises(Type3Exception, match='CheckedValueBlue must be CheckedValueRed instead'):
Suite(code_py).run_code()
@pytest.mark.integration_test
def test_type_mismatch_struct_call_nested():
code_py = """
class CheckedValueBlue:
value: i32
class CheckedValueRed:
value: i32
CONST: (CheckedValueBlue, u32, ) = (CheckedValueRed(1), 16, )
"""
with pytest.raises(Type3Exception, match='CheckedValueBlue must be CheckedValueRed instead'):
Suite(code_py).run_code()
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64'])
def test_type_mismatch_struct_member(type_):
code_py = f"""
class Struct:
param: {type_}
def testEntry(arg: Struct) -> (i32, i32, ):
return arg.param
"""
with pytest.raises(Type3Exception, match=type_ + r' must be \(i32, i32, \) instead'):
Suite(code_py).run_code()
@pytest.mark.integration_test
def test_name_already_use_struct():
code_py = """
class Struct:
param: i32
class Struct:
param: i64
"""
with pytest.raises(StaticError, match='Struct already defined as type'):
Suite(code_py).run_code()
@pytest.mark.integration_test
def test_name_already_use_type():
code_py = """
class f32:
param: i32
"""
with pytest.raises(StaticError, match='f32 already defined as type'):
Suite(code_py).run_code()
@pytest.mark.integration_test
@pytest.mark.skip(reason='FIXME: See constraintgenerator.py for AccessStructMember')
def test_struct_not_accessible():
code_py = """
@exported
def testEntry(x: u8) -> u8:
return x.y
"""
with pytest.raises(Type3Exception, match='u8 is not struct'):
Suite(code_py).run_code()
@pytest.mark.integration_test
def test_struct_export_constant():
code_py = """
class CheckedValue:
value: i32
CONSTANT: CheckedValue = CheckedValue(32)
@exported
def testEntry() -> CheckedValue:
return CONSTANT
"""
result = Suite(code_py).run_code()
assert {"value": 32} == result.returned_value
@pytest.mark.integration_test
def test_struct_export_instantiation():
code_py = """
class CheckedValue:
value: i32
@exported
def testEntry() -> CheckedValue:
return CheckedValue(32)
"""
result = Suite(code_py).run_code()
assert {"value": 32} == result.returned_value