import pytest from phasm.type3.entry import Type3Exception from ..helpers import Suite from .test_natnum import FLOAT_TYPES, INT_TYPES @pytest.mark.integration_test @pytest.mark.parametrize('length', [1, 5, 13]) @pytest.mark.parametrize('a_type', INT_TYPES + FLOAT_TYPES) def test_foldable_sum(length, a_type): code_py = f""" @exported def testEntry(x: {a_type}[{length}]) -> {a_type}: return sum(x) """ in_put = tuple(range(length)) result = Suite(code_py).run_code(in_put) assert sum(in_put) == result.returned_value @pytest.mark.integration_test def test_foldable_sum_not_natnum(): code_py = """ class Foo: bar: i32 @exported def testEntry(x: Foo[4]) -> Foo: return sum(x) """ with pytest.raises(Type3Exception, match='Missing type class instantation: NatNum Foo'): Suite(code_py).run_code() @pytest.mark.integration_test def test_foldable_foldl_size(): code_py = """ def u8_or(l: u8, r: u8) -> u8: return l | r @exported def testEntry(b: bytes) -> u8: return foldl(u8_or, 128, b) """ suite = Suite(code_py) result = suite.run_code(b'') assert 128 == result.returned_value result = suite.run_code(b'\x80') assert 128 == result.returned_value result = suite.run_code(b'\x80\x40') assert 192 == result.returned_value result = suite.run_code(b'\x80\x40\x20\x10') assert 240 == result.returned_value result = suite.run_code(b'\x80\x40\x20\x10\x08\x04\x02\x01') assert 255 == result.returned_value @pytest.mark.integration_test @pytest.mark.parametrize('direction, exp_result', [ ('foldl', -55, ), ('foldr', -5, ), ]) def test_foldable_foldl_foldr(direction, exp_result): # See https://stackoverflow.com/a/13280185 code_py = f""" def i32_sub(l: i32, r: i32) -> i32: return l - r @exported def testEntry(b: i32[10]) -> i32: return {direction}(i32_sub, 0, b) """ suite = Suite(code_py) result = suite.run_code(tuple(range(1, 10))) assert exp_result == result.returned_value @pytest.mark.integration_test @pytest.mark.parametrize('in_typ', ['i8', 'i8[3]']) def test_foldable_argument_must_be_a_function(in_typ): code_py = f""" @exported def testEntry(x: {in_typ}, y: i32, z: i64[3]) -> i32: return foldl(x, y, z) """ r_in_typ = in_typ.replace('[', '\\[').replace(']', '\\]') with pytest.raises(Type3Exception, match=f'{r_in_typ} must be a function instead'): Suite(code_py).run_code() @pytest.mark.integration_test def test_foldable_argument_must_be_right_function(): code_py = """ def foo(l: i32, r: i64) -> i64: return extend(l) + r @exported def testEntry(i: i64, l: i64[3]) -> i64: return foldr(foo, i, l) """ with pytest.raises(Type3Exception, match=r'\(i64 -> i64 -> i64\) must be \(i32 -> i64 -> i64\) instead'): Suite(code_py).run_code() @pytest.mark.integration_test def test_foldable_invalid_return_type(): code_py = """ @exported def testEntry(x: i32[5]) -> f64: return sum(x) """ with pytest.raises(Type3Exception, match='i32 must be f64 instead'): Suite(code_py).run_code((4, 5, 6, 7, 8, )) @pytest.mark.integration_test def test_foldable_not_constructed(): code_py = """ @exported def testEntry(x: i32) -> i32: return sum(x) """ with pytest.raises(Type3Exception, match='Missing type class instantation: Foldable i32.*i32 must be a constructed type instead'): Suite(code_py).run_code() @pytest.mark.integration_test def test_foldable_not_foldable(): code_py = """ @exported def testEntry(x: (i32, u32, )) -> i32: return sum(x) """ with pytest.raises(Type3Exception, match='Missing type class instantation: Foldable tuple'): Suite(code_py).run_code()