phasm/tests/integration/test_lang/test_second_order_functions.py
Johan B.W. de Vries 5e068d691d Notes
2025-07-27 14:51:51 +02:00

223 lines
5.5 KiB
Python

import pytest
from phasm.type5.solver import Type5SolverException
from ..helpers import Suite
@pytest.mark.integration_test
def test_sof_in_code_0_arg():
code_py = """
def thirteen() -> i32:
return 13
def action(applicable: Callable[i32]) -> i32:
return applicable()
@exported
def testEntry() -> i32:
return action(thirteen)
"""
result = Suite(code_py).run_code()
assert 13 == result.returned_value
@pytest.mark.integration_test
def test_sof_in_code_1_arg():
code_py = """
def double(left: i32) -> i32:
return left * 2
def action(applicable: Callable[i32, i32], left: i32) -> i32:
return applicable(left)
@exported
def testEntry() -> i32:
return action(double, 13)
"""
result = Suite(code_py).run_code()
assert 26 == result.returned_value
@pytest.mark.integration_test
def test_sof_in_code_2_arg():
code_py = """
def add(left: i32, right: i32) -> i32:
return left + right
def action(applicable: Callable[i32, i32, i32], left: i32, right: i32) -> i32:
return applicable(left, right)
@exported
def testEntry() -> i32:
return action(add, 13, 14)
"""
result = Suite(code_py).run_code()
assert 27 == result.returned_value
@pytest.mark.integration_test
def test_sof_in_code_3_arg():
code_py = """
def add(left: i32, mid: i32, right: i32) -> i32:
return left + mid + right
def action(applicable: Callable[i32, i32, i32, i32], left: i32, mid: i32, right: i32) -> i32:
return applicable(left, mid, right)
@exported
def testEntry() -> i32:
return action(add, 13, 14, 15)
"""
result = Suite(code_py).run_code()
assert 42 == result.returned_value
@pytest.mark.integration_test
def test_sof_function_with_wrong_argument_type_use():
code_py = """
def double(left: i32) -> i32:
return left * 2
def action(applicable: Callable[i32, i32], left: f32) -> i32:
return applicable(left)
@exported
def testEntry() -> i32:
return action(double, 13.0)
"""
match = r'Callable\[i32, i32\] ~ Callable\[f32, i32\]'
with pytest.raises(Type5SolverException, match=match):
Suite(code_py).run_code()
@pytest.mark.integration_test
def test_sof_function_with_wrong_argument_type_pass():
code_py = """
def double(left: f32) -> i32:
return truncate(left) * 2
def action(applicable: Callable[i32, i32], left: i32) -> i32:
return applicable(left)
@exported
def testEntry() -> i32:
return action(double, 13)
"""
match = r'Callable\[Callable\[i32, i32\], i32, i32\] ~ Callable\[Callable\[f32, i32\], p_[0-9]+, i32\]'
with pytest.raises(Type5SolverException, match=match):
Suite(code_py).run_code()
@pytest.mark.integration_test
def test_sof_function_with_wrong_return_type_use():
code_py = """
def double(left: i32) -> i32:
return left * 2
def action(applicable: Callable[i32, i32], left: i32) -> f32:
return applicable(left)
@exported
def testEntry() -> f32:
return action(double, 13)
"""
match = r'Callable\[i32, i32\] ~ Callable\[i32, f32\]'
with pytest.raises(Type5SolverException, match=match):
Suite(code_py).run_code()
@pytest.mark.integration_test
def test_sof_function_with_wrong_return_type_pass():
code_py = """
def double(left: i32) -> f32:
return convert(left) * 2
def action(applicable: Callable[i32, i32], left: i32) -> i32:
return applicable(left)
@exported
def testEntry() -> i32:
return action(double, 13)
"""
match = r'Callable\[Callable\[i32, i32\], i32, i32\] ~ Callable\[Callable\[i32, f32\], p_[0-9]+, i32\]'
with pytest.raises(Type5SolverException, match=match):
Suite(code_py).run_code()
@pytest.mark.integration_test
def test_sof_not_enough_args_use():
code_py = """
def add(left: i32, right: i32) -> i32:
return left + right
def action(applicable: Callable[i32, i32, i32], left: i32) -> i32:
return applicable(left)
@exported
def testEntry() -> i32:
return action(add, 13)
"""
match = r'Callable\[i32, i32, i32\] ~ Callable\[i32, i32\]'
with pytest.raises(Type5SolverException, match=match):
Suite(code_py).run_code()
@pytest.mark.integration_test
def test_sof_not_enough_args_pass():
code_py = """
def double(left: i32) -> i32:
return left * 2
def action(applicable: Callable[i32, i32, i32], left: i32, right: i32) -> i32:
return applicable(left, right)
@exported
def testEntry() -> i32:
return action(double, 13, 14)
"""
match = r'Callable\[Callable\[i32, i32, i32\], i32, i32, i32\] ~ Callable\[Callable\[i32, i32\], p_[0-9]+, p_[0-9]+, i32\]'
with pytest.raises(Type5SolverException, match=match):
Suite(code_py).run_code()
@pytest.mark.integration_test
def test_sof_too_many_args_use():
code_py = """
def thirteen() -> i32:
return 13
def action(applicable: Callable[i32], left: i32) -> i32:
return applicable(left)
@exported
def testEntry() -> i32:
return action(thirteen, 13)
"""
match = r'Callable\[i32\] ~ Callable\[i32, i32\]'
with pytest.raises(Type5SolverException, match=match):
Suite(code_py).run_code(verbose=True)
@pytest.mark.integration_test
def test_sof_too_many_args_pass():
code_py = """
def double(left: i32) -> i32:
return left * 2
def action(applicable: Callable[i32], left: i32, right: i32) -> i32:
return applicable()
@exported
def testEntry() -> i32:
return action(double, 13, 14)
"""
match = r'Callable\[Callable\[i32\], i32, i32, i32\] ~ Callable\[Callable\[i32, i32\], p_[0-9]+, p_[0-9]+, i32\]'
with pytest.raises(Type5SolverException, match=match):
Suite(code_py).run_code()