phasm/tests/integration/test_simple.py
Johan B.W. de Vries 4b46483895 Worked on floats
2022-09-17 19:21:56 +02:00

627 lines
14 KiB
Python

import pytest
from .helpers import Suite
ALL_INT_TYPES = ['u8', '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_', ALL_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_', ALL_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_', COMPLETE_SIMPLE_TYPES)
def test_call_with_expression(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.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