diff --git a/tests/integration/constants.py b/tests/integration/constants.py new file mode 100644 index 0000000..07dacbe --- /dev/null +++ b/tests/integration/constants.py @@ -0,0 +1,16 @@ +""" +Constants for use in the tests +""" + +ALL_INT_TYPES = ['u8', 'u32', 'u64', 'i32', 'i64'] +COMPLETE_INT_TYPES = ['u32', 'u64', 'i32', 'i64'] + +ALL_FLOAT_TYPES = ['f32', 'f64'] +COMPLETE_FLOAT_TYPES = ALL_FLOAT_TYPES + +TYPE_MAP = { + **{x: int for x in ALL_INT_TYPES}, + **{x: float for x in ALL_FLOAT_TYPES}, +} + +COMPLETE_PRIMITIVE_TYPES = COMPLETE_INT_TYPES + COMPLETE_FLOAT_TYPES diff --git a/tests/integration/test_examples/__init__.py b/tests/integration/test_examples/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/integration/test_examples.py b/tests/integration/test_examples/test_crc32.py similarity index 93% rename from tests/integration/test_examples.py rename to tests/integration/test_examples/test_crc32.py index b3b278d..d9f74bf 100644 --- a/tests/integration/test_examples.py +++ b/tests/integration/test_examples/test_crc32.py @@ -3,9 +3,9 @@ import struct import pytest -from .helpers import Suite +from ..helpers import Suite -@pytest.mark.integration_test +@pytest.mark.slow_integration_test def test_crc32(): # FIXME: Stub # crc = 0xFFFFFFFF diff --git a/tests/integration/test_fib.py b/tests/integration/test_examples/test_fib.py similarity index 94% rename from tests/integration/test_fib.py rename to tests/integration/test_examples/test_fib.py index 20e7e63..3f99a46 100644 --- a/tests/integration/test_fib.py +++ b/tests/integration/test_examples/test_fib.py @@ -1,6 +1,6 @@ import pytest -from .helpers import Suite +from ..helpers import Suite @pytest.mark.slow_integration_test def test_fib(): diff --git a/tests/integration/test_helper.py b/tests/integration/test_helper.py deleted file mode 100644 index cb44021..0000000 --- a/tests/integration/test_helper.py +++ /dev/null @@ -1,70 +0,0 @@ -import io - -import pytest - -from pywasm import binary -from pywasm import Runtime - -from wasmer import wat2wasm - -def run(code_wat): - code_wasm = wat2wasm(code_wat) - module = binary.Module.from_reader(io.BytesIO(code_wasm)) - - runtime = Runtime(module, {}, {}) - - out_put = runtime.exec('testEntry', []) - return (runtime, out_put) - -@pytest.mark.parametrize('size,offset,exp_out_put', [ - ('32', 0, 0x3020100), - ('32', 1, 0x4030201), - ('64', 0, 0x706050403020100), - ('64', 2, 0x908070605040302), -]) -def test_i32_64_load(size, offset, exp_out_put): - code_wat = f""" - (module - (memory 1) - (data (memory 0) (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\10") - - (func (export "testEntry") (result i{size}) - i32.const {offset} - i{size}.load - return )) -""" - - (_, out_put) = run(code_wat) - assert exp_out_put == out_put - -def test_load_then_store(): - code_wat = """ - (module - (memory 1) - (data (memory 0) (i32.const 0) "\\04\\00\\00\\00") - - (func (export "testEntry") (result i32) (local $my_memory_value i32) - ;; Load i32 from address 0 - i32.const 0 - i32.load - - ;; Add 8 to the loaded value - i32.const 8 - i32.add - - local.set $my_memory_value - - ;; Store back to the memory - i32.const 0 - local.get $my_memory_value - i32.store - - ;; Return something - i32.const 9 - return )) -""" - (runtime, out_put) = run(code_wat) - - assert 9 == out_put - - assert (b'\x0c'+ b'\00' * 23) == runtime.store.mems[0].data[:24] diff --git a/tests/integration/test_lang/__init__.py b/tests/integration/test_lang/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/integration/test_builtins.py b/tests/integration/test_lang/test_builtins.py similarity index 95% rename from tests/integration/test_builtins.py rename to tests/integration/test_lang/test_builtins.py index 4b84197..2b06afd 100644 --- a/tests/integration/test_builtins.py +++ b/tests/integration/test_lang/test_builtins.py @@ -2,8 +2,8 @@ import sys import pytest -from .helpers import Suite, write_header -from .runners import RunnerPywasm +from ..helpers import Suite, write_header +from ..runners import RunnerPywasm def setup_interpreter(phash_code: str) -> RunnerPywasm: runner = RunnerPywasm(phash_code) diff --git a/tests/integration/test_lang/test_bytes.py b/tests/integration/test_lang/test_bytes.py new file mode 100644 index 0000000..45fc2a1 --- /dev/null +++ b/tests/integration/test_lang/test_bytes.py @@ -0,0 +1,53 @@ +import pytest + +from ..helpers import Suite + +@pytest.mark.integration_test +def test_bytes_address(): + code_py = """ +@exported +def testEntry(f: bytes) -> bytes: + return f +""" + + result = Suite(code_py).run_code(b'This is a test') + + # THIS DEPENDS ON THE ALLOCATOR + # A different allocator will return a different value + assert 20 == result.returned_value + +@pytest.mark.integration_test +def test_bytes_length(): + code_py = """ +@exported +def testEntry(f: bytes) -> i32: + return len(f) +""" + + result = Suite(code_py).run_code(b'This is another test') + + assert 20 == result.returned_value + +@pytest.mark.integration_test +def test_bytes_index(): + code_py = """ +@exported +def testEntry(f: bytes) -> u8: + return f[8] +""" + + result = Suite(code_py).run_code(b'This is another test') + + assert 0x61 == result.returned_value + +@pytest.mark.integration_test +def test_bytes_index_out_of_bounds(): + code_py = """ +@exported +def testEntry(f: bytes) -> u8: + return f[50] +""" + + result = Suite(code_py).run_code(b'Short', b'Long' * 100) + + assert 0 == result.returned_value diff --git a/tests/integration/test_lang/test_if.py b/tests/integration/test_lang/test_if.py new file mode 100644 index 0000000..5d77eb9 --- /dev/null +++ b/tests/integration/test_lang/test_if.py @@ -0,0 +1,71 @@ +import pytest + +from ..helpers import Suite + +@pytest.mark.integration_test +@pytest.mark.parametrize('inp', [9, 10, 11, 12]) +def test_if_simple(inp): + code_py = """ +@exported +def testEntry(a: i32) -> i32: + if a > 10: + return 15 + + return 3 +""" + exp_result = 15 if inp > 10 else 3 + + suite = Suite(code_py) + + result = suite.run_code(inp) + assert exp_result == result.returned_value + +@pytest.mark.integration_test +@pytest.mark.skip('Such a return is not how things should be') +def test_if_complex(): + code_py = """ +@exported +def testEntry(a: i32) -> i32: + if a > 10: + return 10 + elif a > 0: + return a + else: + return 0 + + return -1 # Required due to function type +""" + + suite = Suite(code_py) + + assert 10 == suite.run_code(20).returned_value + assert 10 == suite.run_code(10).returned_value + + assert 8 == suite.run_code(8).returned_value + + assert 0 == suite.run_code(0).returned_value + assert 0 == suite.run_code(-1).returned_value + +@pytest.mark.integration_test +def test_if_nested(): + code_py = """ +@exported +def testEntry(a: i32, b: i32) -> i32: + if a > 11: + if b > 11: + return 3 + + return 2 + + if b > 11: + return 1 + + return 0 +""" + + suite = Suite(code_py) + + assert 3 == suite.run_code(20, 20).returned_value + assert 2 == suite.run_code(20, 10).returned_value + assert 1 == suite.run_code(10, 20).returned_value + assert 0 == suite.run_code(10, 10).returned_value diff --git a/tests/integration/test_lang/test_interface.py b/tests/integration/test_lang/test_interface.py new file mode 100644 index 0000000..cbacd73 --- /dev/null +++ b/tests/integration/test_lang/test_interface.py @@ -0,0 +1,27 @@ +import pytest + +from ..helpers import Suite + +@pytest.mark.integration_test +def test_imported(): + code_py = """ +@imported +def helper(mul: i32) -> i32: + pass + +@exported +def testEntry() -> i32: + return helper(2) +""" + + def helper(mul: int) -> int: + return 4238 * mul + + result = Suite(code_py).run_code( + runtime='wasmer', + imports={ + 'helper': helper, + } + ) + + assert 8476 == result.returned_value diff --git a/tests/integration/test_lang/test_primitives.py b/tests/integration/test_lang/test_primitives.py new file mode 100644 index 0000000..d0eeb8f --- /dev/null +++ b/tests/integration/test_lang/test_primitives.py @@ -0,0 +1,324 @@ +import pytest + +from ..helpers import Suite +from ..constants import ALL_INT_TYPES, ALL_FLOAT_TYPES, COMPLETE_INT_TYPES, TYPE_MAP + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ALL_INT_TYPES) +def test_expr_constant_int(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 13 +""" + + result = Suite(code_py).run_code() + + assert 13 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES) +def test_expr_constant_float(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 32.125 +""" + + result = Suite(code_py).run_code() + + assert 32.125 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ALL_INT_TYPES) +def test_module_constant_int(type_): + code_py = f""" +CONSTANT: {type_} = 13 + +@exported +def testEntry() -> {type_}: + return CONSTANT +""" + + result = Suite(code_py).run_code() + + assert 13 == result.returned_value + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES) +def test_module_constant_float(type_): + code_py = f""" +CONSTANT: {type_} = 32.125 + +@exported +def testEntry() -> {type_}: + return CONSTANT +""" + + result = Suite(code_py).run_code() + + assert 32.125 == result.returned_value + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ['u32', 'u64']) # FIXME: Support u8, requires an extra AND operation +def test_logical_left_shift(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 10 << 3 +""" + + result = Suite(code_py).run_code() + + assert 80 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64']) +def test_logical_right_shift(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 10 >> 3 +""" + + result = Suite(code_py).run_code() + + assert 1 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64']) +def test_bitwise_or(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 10 | 3 +""" + + result = Suite(code_py).run_code() + + assert 11 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64']) +def test_bitwise_xor(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 10 ^ 3 +""" + + result = Suite(code_py).run_code() + + assert 9 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64']) +def test_bitwise_and(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 10 & 3 +""" + + result = Suite(code_py).run_code() + + assert 2 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', COMPLETE_INT_TYPES) +def test_addition_int(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 10 + 3 +""" + + result = Suite(code_py).run_code() + + assert 13 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES) +def test_addition_float(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 32.0 + 0.125 +""" + + result = Suite(code_py).run_code() + + assert 32.125 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', COMPLETE_INT_TYPES) +def test_subtraction_int(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 10 - 3 +""" + + result = Suite(code_py).run_code() + + assert 7 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES) +def test_subtraction_float(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 100.0 - 67.875 +""" + + result = Suite(code_py).run_code() + + assert 32.125 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +# TODO: Multiplication +# TODO: Division + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ['f32', 'f64']) +def test_buildins_sqrt(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return sqrt(25.0) +""" + + result = Suite(code_py).run_code() + + assert 5 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', TYPE_MAP.keys()) +def test_function_argument(type_): + code_py = f""" +@exported +def testEntry(a: {type_}) -> {type_}: + return a +""" + + result = Suite(code_py).run_code(125) + + assert 125 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.skip('TODO') +def test_explicit_positive_number(): + code_py = """ +@exported +def testEntry() -> i32: + return +523 +""" + + result = Suite(code_py).run_code() + + assert 523 == result.returned_value + +@pytest.mark.integration_test +@pytest.mark.skip('TODO') +def test_explicit_negative_number(): + code_py = """ +@exported +def testEntry() -> i32: + return -19 +""" + + result = Suite(code_py).run_code() + + assert -19 == result.returned_value + +@pytest.mark.integration_test +def test_call_no_args(): + code_py = """ +def helper() -> i32: + return 19 + +@exported +def testEntry() -> i32: + return helper() +""" + + result = Suite(code_py).run_code() + + assert 19 == result.returned_value + +@pytest.mark.integration_test +def test_call_pre_defined(): + code_py = """ +def helper(left: i32, right: i32) -> i32: + return left + right + +@exported +def testEntry() -> i32: + return helper(10, 3) +""" + + result = Suite(code_py).run_code() + + assert 13 == result.returned_value + +@pytest.mark.integration_test +def test_call_post_defined(): + code_py = """ +@exported +def testEntry() -> i32: + return helper(10, 3) + +def helper(left: i32, right: i32) -> i32: + return left - right +""" + + result = Suite(code_py).run_code() + + assert 7 == result.returned_value + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', COMPLETE_INT_TYPES) +def test_call_with_expression_int(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return helper(10 + 20, 3 + 5) + +def helper(left: {type_}, right: {type_}) -> {type_}: + return left - right +""" + + result = Suite(code_py).run_code() + + assert 22 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES) +def test_call_with_expression_float(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return helper(10.078125 + 90.046875, 63.0 + 5.0) + +def helper(left: {type_}, right: {type_}) -> {type_}: + return left - right +""" + + result = Suite(code_py).run_code() + + assert 32.125 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) diff --git a/tests/integration/test_lang/test_static_array.py b/tests/integration/test_lang/test_static_array.py new file mode 100644 index 0000000..ced9277 --- /dev/null +++ b/tests/integration/test_lang/test_static_array.py @@ -0,0 +1,87 @@ +import pytest + +from phasm.exceptions import StaticError + +from ..constants import COMPLETE_PRIMITIVE_TYPES, TYPE_MAP +from ..helpers import Suite + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', COMPLETE_PRIMITIVE_TYPES) +def test_static_array_module_constant(type_): + code_py = f""" +CONSTANT: {type_}[3] = (24, 57, 80, ) + +@exported +def testEntry() -> {type_}: + return helper(CONSTANT) + +def helper(array: {type_}[3]) -> {type_}: + return array[0] + array[1] + array[2] +""" + + result = Suite(code_py).run_code() + + assert 161 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', COMPLETE_PRIMITIVE_TYPES) +def test_static_array_indexed(type_): + code_py = f""" +CONSTANT: {type_}[3] = (24, 57, 80, ) + +@exported +def testEntry() -> {type_}: + return helper(CONSTANT, 0, 1, 2) + +def helper(array: {type_}[3], i0: u32, i1: u32, i2: u32) -> {type_}: + return array[i0] + array[i1] + array[i2] +""" + + result = Suite(code_py).run_code() + + assert 161 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) + +@pytest.mark.integration_test +def test_static_array_constant_too_few_values(): + code_py = """ +CONSTANT: u8[3] = (24, 57, ) +""" + + with pytest.raises(StaticError, match='Static error on line 2: Invalid number of static array values'): + phasm_parse(code_py) + +@pytest.mark.integration_test +def test_static_array_constant_too_many_values(): + code_py = """ +CONSTANT: u8[3] = (24, 57, 1, 1, ) +""" + + with pytest.raises(StaticError, match='Static error on line 2: Invalid number of static array values'): + phasm_parse(code_py) + +@pytest.mark.integration_test +def test_static_array_constant_type_mismatch(): + code_py = """ +CONSTANT: u8[3] = (24, 4000, 1, ) +""" + + with pytest.raises(StaticError, match='Static error on line 2: Integer value out of range; expected 0..255, actual 4000'): + phasm_parse(code_py) + +@pytest.mark.integration_test +def test_static_array_index_out_of_bounds(): + code_py = """ +CONSTANT0: u32[3] = (24, 57, 80, ) + +CONSTANT1: u32[16] = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ) + +@exported +def testEntry() -> u32: + return CONSTANT0[16] +""" + + result = Suite(code_py).run_code() + + assert 0 == result.returned_value diff --git a/tests/integration/test_static_checking.py b/tests/integration/test_lang/test_struct.py similarity index 54% rename from tests/integration/test_static_checking.py rename to tests/integration/test_lang/test_struct.py index 1544537..04846e7 100644 --- a/tests/integration/test_static_checking.py +++ b/tests/integration/test_lang/test_struct.py @@ -1,18 +1,65 @@ import pytest -from phasm.parser import phasm_parse -from phasm.exceptions import StaticError +from ..helpers import Suite @pytest.mark.integration_test -@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64']) -def test_type_mismatch_function_argument(type_): +@pytest.mark.parametrize('type_', ('i32', 'f64', )) +def test_struct_0(type_): code_py = f""" -def helper(a: {type_}) -> (i32, i32, ): - return a +class CheckedValue: + value: {type_} + +@exported +def testEntry() -> {type_}: + return helper(CheckedValue(23)) + +def helper(cv: CheckedValue) -> {type_}: + return cv.value """ - with pytest.raises(StaticError, match=f'Static error on line 3: Expected \\(i32, i32, \\), a is actually {type_}'): - phasm_parse(code_py) + 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 @pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64']) @@ -39,21 +86,6 @@ def testEntry(arg: ({type_}, )) -> (i32, i32, ): with pytest.raises(StaticError, match=f'Static error on line 3: Expected \\(i32, i32, \\), arg\\[0\\] is actually {type_}'): phasm_parse(code_py) -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64']) -def test_type_mismatch_function_result(type_): - code_py = f""" -def helper() -> {type_}: - return 1 - -@exported -def testEntry() -> (i32, i32, ): - return helper() -""" - - with pytest.raises(StaticError, match=f'Static error on line 7: Expected \\(i32, i32, \\), helper actually returns {type_}'): - phasm_parse(code_py) - @pytest.mark.integration_test def test_tuple_constant_too_few_values(): code_py = """ @@ -80,30 +112,3 @@ CONSTANT: (u32, u8, u8, ) = (24, 4000, 1, ) with pytest.raises(StaticError, match='Static error on line 2: Integer value out of range; expected 0..255, actual 4000'): phasm_parse(code_py) - -@pytest.mark.integration_test -def test_static_array_constant_too_few_values(): - code_py = """ -CONSTANT: u8[3] = (24, 57, ) -""" - - with pytest.raises(StaticError, match='Static error on line 2: Invalid number of static array values'): - phasm_parse(code_py) - -@pytest.mark.integration_test -def test_static_array_constant_too_many_values(): - code_py = """ -CONSTANT: u8[3] = (24, 57, 1, 1, ) -""" - - with pytest.raises(StaticError, match='Static error on line 2: Invalid number of static array values'): - phasm_parse(code_py) - -@pytest.mark.integration_test -def test_static_array_constant_type_mismatch(): - code_py = """ -CONSTANT: u8[3] = (24, 4000, 1, ) -""" - - with pytest.raises(StaticError, match='Static error on line 2: Integer value out of range; expected 0..255, actual 4000'): - phasm_parse(code_py) diff --git a/tests/integration/test_constants.py b/tests/integration/test_lang/test_tuple.py similarity index 56% rename from tests/integration/test_constants.py rename to tests/integration/test_lang/test_tuple.py index accf9e2..5c5321e 100644 --- a/tests/integration/test_constants.py +++ b/tests/integration/test_lang/test_tuple.py @@ -1,34 +1,7 @@ import pytest -from .helpers import Suite - -@pytest.mark.integration_test -def test_i32_asis(): - code_py = """ -CONSTANT: i32 = 13 - -@exported -def testEntry() -> i32: - return CONSTANT -""" - - result = Suite(code_py).run_code() - - assert 13 == result.returned_value - -@pytest.mark.integration_test -def test_i32_binop(): - code_py = """ -CONSTANT: i32 = 13 - -@exported -def testEntry() -> i32: - return CONSTANT * 5 -""" - - result = Suite(code_py).run_code() - - assert 65 == result.returned_value +from ..constants import COMPLETE_PRIMITIVE_TYPES, TYPE_MAP +from ..helpers import Suite @pytest.mark.integration_test @pytest.mark.parametrize('type_', ['u8', 'u32', 'u64', ]) @@ -66,36 +39,46 @@ def helper(vector: (u8, u8, u32, u32, u64, u64, )) -> u32: assert 3333 == result.returned_value @pytest.mark.integration_test -@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64', ]) -def test_static_array_1(type_): +@pytest.mark.parametrize('type_', COMPLETE_PRIMITIVE_TYPES) +def test_tuple_simple_constructor(type_): code_py = f""" -CONSTANT: {type_}[1] = (65, ) - @exported def testEntry() -> {type_}: - return helper(CONSTANT) + return helper((24, 57, 80, )) -def helper(vector: {type_}[1]) -> {type_}: - return vector[0] +def helper(vector: ({type_}, {type_}, {type_}, )) -> {type_}: + return vector[0] + vector[1] + vector[2] """ result = Suite(code_py).run_code() - assert 65 == result.returned_value + assert 161 == result.returned_value + assert TYPE_MAP[type_] == type(result.returned_value) @pytest.mark.integration_test -def test_static_array_6(): +def test_tuple_float(): code_py = """ -CONSTANT: u32[6] = (11, 22, 3333, 4444, 555555, 666666, ) - @exported -def testEntry() -> u32: - return helper(CONSTANT) +def testEntry() -> f32: + return helper((1.0, 2.0, 3.0, )) -def helper(vector: u32[6]) -> u32: - return vector[2] +def helper(v: (f32, f32, f32, )) -> f32: + return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]) """ result = Suite(code_py).run_code() - assert 3333 == result.returned_value + assert 3.74 < result.returned_value < 3.75 + +@pytest.mark.integration_test +@pytest.mark.skip('SIMD support is but a dream') +def test_tuple_i32x4(): + code_py = """ +@exported +def testEntry() -> i32x4: + return (51, 153, 204, 0, ) +""" + + result = Suite(code_py).run_code() + + assert (1, 2, 3, 0) == result.returned_value diff --git a/tests/integration/test_type_checks.py b/tests/integration/test_lang/test_type_checks.py similarity index 100% rename from tests/integration/test_type_checks.py rename to tests/integration/test_lang/test_type_checks.py diff --git a/tests/integration/test_runtime_checks.py b/tests/integration/test_runtime_checks.py deleted file mode 100644 index 97d6542..0000000 --- a/tests/integration/test_runtime_checks.py +++ /dev/null @@ -1,31 +0,0 @@ -import pytest - -from .helpers import Suite - -@pytest.mark.integration_test -def test_bytes_index_out_of_bounds(): - code_py = """ -@exported -def testEntry(f: bytes) -> u8: - return f[50] -""" - - result = Suite(code_py).run_code(b'Short', b'Long' * 100) - - assert 0 == result.returned_value - -@pytest.mark.integration_test -def test_static_array_index_out_of_bounds(): - code_py = """ -CONSTANT0: u32[3] = (24, 57, 80, ) - -CONSTANT1: u32[16] = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ) - -@exported -def testEntry() -> u32: - return CONSTANT0[16] -""" - - result = Suite(code_py).run_code() - - assert 0 == result.returned_value diff --git a/tests/integration/test_simple.py b/tests/integration/test_simple.py deleted file mode 100644 index fdad1e4..0000000 --- a/tests/integration/test_simple.py +++ /dev/null @@ -1,644 +0,0 @@ -import pytest - -from .helpers import Suite - -ALL_INT_TYPES = ['u8', 'u32', 'u64', 'i32', 'i64'] -COMLETE_INT_TYPES = ['u32', 'u64', 'i32', 'i64'] -ALL_FLOAT_TYPES = ['f32', 'f64'] - -TYPE_MAP = { - **{x: int for x in ALL_INT_TYPES}, - **{x: float for x in ALL_FLOAT_TYPES}, -} - -COMPLETE_SIMPLE_TYPES = [ - 'u32', 'u64', - 'i32', 'i64', - 'f32', 'f64', -] - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', ALL_INT_TYPES) -def test_return_int(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return 13 -""" - - result = Suite(code_py).run_code() - - assert 13 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES) -def test_return_float(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return 32.125 -""" - - result = Suite(code_py).run_code() - - assert 32.125 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', COMLETE_INT_TYPES) -def test_addition_int(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return 10 + 3 -""" - - result = Suite(code_py).run_code() - - assert 13 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES) -def test_addition_float(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return 32.0 + 0.125 -""" - - result = Suite(code_py).run_code() - - assert 32.125 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', COMLETE_INT_TYPES) -def test_subtraction_int(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return 10 - 3 -""" - - result = Suite(code_py).run_code() - - assert 7 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES) -def test_subtraction(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return 100.0 - 67.875 -""" - - result = Suite(code_py).run_code() - - assert 32.125 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', ['u32', 'u64']) # FIXME: Support u8, requires an extra AND operation -def test_logical_left_shift(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return 10 << 3 -""" - - result = Suite(code_py).run_code() - - assert 80 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64']) -def test_logical_right_shift(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return 10 >> 3 -""" - - result = Suite(code_py).run_code() - - assert 1 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64']) -def test_bitwise_or(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return 10 | 3 -""" - - result = Suite(code_py).run_code() - - assert 11 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64']) -def test_bitwise_xor(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return 10 ^ 3 -""" - - result = Suite(code_py).run_code() - - assert 9 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64']) -def test_bitwise_and(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return 10 & 3 -""" - - result = Suite(code_py).run_code() - - assert 2 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', ['f32', 'f64']) -def test_buildins_sqrt(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return sqrt(25.0) -""" - - result = Suite(code_py).run_code() - - assert 5 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', TYPE_MAP.keys()) -def test_arg(type_): - code_py = f""" -@exported -def testEntry(a: {type_}) -> {type_}: - return a -""" - - result = Suite(code_py).run_code(125) - - assert 125 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.skip('Do we want it to work like this?') -def test_i32_to_i64(): - code_py = """ -@exported -def testEntry(a: i32) -> i64: - return a -""" - - result = Suite(code_py).run_code(125) - - assert 125 == result.returned_value - -@pytest.mark.integration_test -@pytest.mark.skip('Do we want it to work like this?') -def test_i32_plus_i64(): - code_py = """ -@exported -def testEntry(a: i32, b: i64) -> i64: - return a + b -""" - - result = Suite(code_py).run_code(125, 100) - - assert 225 == result.returned_value - -@pytest.mark.integration_test -@pytest.mark.skip('Do we want it to work like this?') -def test_f32_to_f64(): - code_py = """ -@exported -def testEntry(a: f32) -> f64: - return a -""" - - result = Suite(code_py).run_code(125.5) - - assert 125.5 == result.returned_value - -@pytest.mark.integration_test -@pytest.mark.skip('Do we want it to work like this?') -def test_f32_plus_f64(): - code_py = """ -@exported -def testEntry(a: f32, b: f64) -> f64: - return a + b -""" - - result = Suite(code_py).run_code(125.5, 100.25) - - assert 225.75 == result.returned_value - -@pytest.mark.integration_test -@pytest.mark.skip('TODO') -def test_uadd(): - code_py = """ -@exported -def testEntry() -> i32: - return +523 -""" - - result = Suite(code_py).run_code() - - assert 523 == result.returned_value - -@pytest.mark.integration_test -@pytest.mark.skip('TODO') -def test_usub(): - code_py = """ -@exported -def testEntry() -> i32: - return -19 -""" - - result = Suite(code_py).run_code() - - assert -19 == result.returned_value - -@pytest.mark.integration_test -@pytest.mark.parametrize('inp', [9, 10, 11, 12]) -def test_if_simple(inp): - code_py = """ -@exported -def testEntry(a: i32) -> i32: - if a > 10: - return 15 - - return 3 -""" - exp_result = 15 if inp > 10 else 3 - - suite = Suite(code_py) - - result = suite.run_code(inp) - assert exp_result == result.returned_value - -@pytest.mark.integration_test -@pytest.mark.skip('Such a return is not how things should be') -def test_if_complex(): - code_py = """ -@exported -def testEntry(a: i32) -> i32: - if a > 10: - return 10 - elif a > 0: - return a - else: - return 0 - - return -1 # Required due to function type -""" - - suite = Suite(code_py) - - assert 10 == suite.run_code(20).returned_value - assert 10 == suite.run_code(10).returned_value - - assert 8 == suite.run_code(8).returned_value - - assert 0 == suite.run_code(0).returned_value - assert 0 == suite.run_code(-1).returned_value - -@pytest.mark.integration_test -def test_if_nested(): - code_py = """ -@exported -def testEntry(a: i32, b: i32) -> i32: - if a > 11: - if b > 11: - return 3 - - return 2 - - if b > 11: - return 1 - - return 0 -""" - - suite = Suite(code_py) - - assert 3 == suite.run_code(20, 20).returned_value - assert 2 == suite.run_code(20, 10).returned_value - assert 1 == suite.run_code(10, 20).returned_value - assert 0 == suite.run_code(10, 10).returned_value - -@pytest.mark.integration_test -def test_call_no_args(): - code_py = """ -def helper() -> i32: - return 19 - -@exported -def testEntry() -> i32: - return helper() -""" - - result = Suite(code_py).run_code() - - assert 19 == result.returned_value - -@pytest.mark.integration_test -def test_call_pre_defined(): - code_py = """ -def helper(left: i32, right: i32) -> i32: - return left + right - -@exported -def testEntry() -> i32: - return helper(10, 3) -""" - - result = Suite(code_py).run_code() - - assert 13 == result.returned_value - -@pytest.mark.integration_test -def test_call_post_defined(): - code_py = """ -@exported -def testEntry() -> i32: - return helper(10, 3) - -def helper(left: i32, right: i32) -> i32: - return left - right -""" - - result = Suite(code_py).run_code() - - assert 7 == result.returned_value - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', COMLETE_INT_TYPES) -def test_call_with_expression_int(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return helper(10 + 20, 3 + 5) - -def helper(left: {type_}, right: {type_}) -> {type_}: - return left - right -""" - - result = Suite(code_py).run_code() - - assert 22 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES) -def test_call_with_expression_float(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return helper(10.078125 + 90.046875, 63.0 + 5.0) - -def helper(left: {type_}, right: {type_}) -> {type_}: - return left - right -""" - - result = Suite(code_py).run_code() - - assert 32.125 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.skip('Not yet implemented') -def test_assign(): - code_py = """ - -@exported -def testEntry() -> i32: - a: i32 = 8947 - return a -""" - - result = Suite(code_py).run_code() - - assert 8947 == result.returned_value - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', TYPE_MAP.keys()) -def test_struct_0(type_): - code_py = f""" -class CheckedValue: - value: {type_} - -@exported -def testEntry() -> {type_}: - return helper(CheckedValue(23)) - -def helper(cv: CheckedValue) -> {type_}: - 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 -@pytest.mark.parametrize('type_', COMPLETE_SIMPLE_TYPES) -def test_tuple_simple_constructor(type_): - code_py = f""" -@exported -def testEntry() -> {type_}: - return helper((24, 57, 80, )) - -def helper(vector: ({type_}, {type_}, {type_}, )) -> {type_}: - return vector[0] + vector[1] + vector[2] -""" - - result = Suite(code_py).run_code() - - assert 161 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -def test_tuple_float(): - code_py = """ -@exported -def testEntry() -> f32: - return helper((1.0, 2.0, 3.0, )) - -def helper(v: (f32, f32, f32, )) -> f32: - return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]) -""" - - result = Suite(code_py).run_code() - - assert 3.74 < result.returned_value < 3.75 - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', COMPLETE_SIMPLE_TYPES) -def test_static_array_module_constant(type_): - code_py = f""" -CONSTANT: {type_}[3] = (24, 57, 80, ) - -@exported -def testEntry() -> {type_}: - return helper(CONSTANT) - -def helper(array: {type_}[3]) -> {type_}: - return array[0] + array[1] + array[2] -""" - - result = Suite(code_py).run_code() - - assert 161 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -@pytest.mark.parametrize('type_', COMPLETE_SIMPLE_TYPES) -def test_static_array_indexed(type_): - code_py = f""" -CONSTANT: {type_}[3] = (24, 57, 80, ) - -@exported -def testEntry() -> {type_}: - return helper(CONSTANT, 0, 1, 2) - -def helper(array: {type_}[3], i0: u32, i1: u32, i2: u32) -> {type_}: - return array[i0] + array[i1] + array[i2] -""" - - result = Suite(code_py).run_code() - - assert 161 == result.returned_value - assert TYPE_MAP[type_] == type(result.returned_value) - -@pytest.mark.integration_test -def test_bytes_address(): - code_py = """ -@exported -def testEntry(f: bytes) -> bytes: - return f -""" - - result = Suite(code_py).run_code(b'This is a test') - - # THIS DEPENDS ON THE ALLOCATOR - # A different allocator will return a different value - assert 20 == result.returned_value - -@pytest.mark.integration_test -def test_bytes_length(): - code_py = """ -@exported -def testEntry(f: bytes) -> i32: - return len(f) -""" - - result = Suite(code_py).run_code(b'This is another test') - - assert 20 == result.returned_value - -@pytest.mark.integration_test -def test_bytes_index(): - code_py = """ -@exported -def testEntry(f: bytes) -> u8: - return f[8] -""" - - result = Suite(code_py).run_code(b'This is another test') - - assert 0x61 == result.returned_value - -@pytest.mark.integration_test -@pytest.mark.skip('SIMD support is but a dream') -def test_tuple_i32x4(): - code_py = """ -@exported -def testEntry() -> i32x4: - return (51, 153, 204, 0, ) -""" - - result = Suite(code_py).run_code() - - assert (1, 2, 3, 0) == result.returned_value - -@pytest.mark.integration_test -def test_imported(): - code_py = """ -@imported -def helper(mul: i32) -> i32: - pass - -@exported -def testEntry() -> i32: - return helper(2) -""" - - def helper(mul: int) -> int: - return 4238 * mul - - result = Suite(code_py).run_code( - runtime='wasmer', - imports={ - 'helper': helper, - } - ) - - assert 8476 == result.returned_value diff --git a/tests/integration/test_stdlib/__init__.py b/tests/integration/test_stdlib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/integration/test_stdlib_alloc.py b/tests/integration/test_stdlib/test_alloc.py similarity index 95% rename from tests/integration/test_stdlib_alloc.py rename to tests/integration/test_stdlib/test_alloc.py index da8ccea..96d1fd6 100644 --- a/tests/integration/test_stdlib_alloc.py +++ b/tests/integration/test_stdlib/test_alloc.py @@ -2,8 +2,8 @@ import sys import pytest -from .helpers import write_header -from .runners import RunnerPywasm3 as Runner +from ..helpers import write_header +from ..runners import RunnerPywasm3 as Runner def setup_interpreter(phash_code: str) -> Runner: runner = Runner(phash_code)