Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/restructure tests #141

Merged
merged 2 commits into from
Apr 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 110 additions & 87 deletions opshin/tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import frozendict
from hypothesis import given
from hypothesis import strategies as st
from parameterized import parameterized
from uplc import ast as uplc, eval as uplc_eval

from .. import compiler, prelude
from ..util import CompilerError


def fib(n):
Expand All @@ -31,27 +31,23 @@ def test_assert_sum_contract_succeed(self):
ret = uplc_eval(f)
self.assertEqual(ret, uplc.PlutusConstr(0, []))

@unittest.expectedFailure
def test_assert_sum_contract_fail(self):
input_file = "examples/smart_contracts/assert_sum.py"
with open(input_file) as fp:
source_code = fp.read()
ast = compiler.parse(source_code)
code = compiler.compile(ast)
code = code.compile()
try:
f = code.term
# UPLC lambdas may only take one argument at a time, so we evaluate by repeatedly applying
for d in [
uplc.PlutusInteger(0),
uplc.PlutusInteger(23),
uplc.BuiltinUnit(),
]:
f = uplc.Apply(f, d)
ret = uplc_eval(f)
failed = False
except Exception as e:
failed = True
self.assertTrue(failed, "Machine did validate the content")
f = code.term
# UPLC lambdas may only take one argument at a time, so we evaluate by repeatedly applying
for d in [
uplc.PlutusInteger(0),
uplc.PlutusInteger(23),
uplc.BuiltinUnit(),
]:
f = uplc.Apply(f, d)
ret = uplc_eval(f)

@given(
a=st.integers(min_value=-10, max_value=10),
Expand Down Expand Up @@ -250,6 +246,7 @@ def test_gift_contract_succeed(self):
ret = uplc_eval(f)
self.assertEqual(ret, uplc.PlutusConstr(0, []))

@unittest.expectedFailure
def test_gift_contract_fail(self):
input_file = "examples/smart_contracts/gift.py"
with open(input_file) as fp:
Expand All @@ -259,34 +256,29 @@ def test_gift_contract_fail(self):
code = code.compile()
f = code.term
# UPLC lambdas may only take one argument at a time, so we evaluate by repeatedly applying
try:
# required sig missing int this script context
for d in [
uplc.PlutusConstr(
0,
[
uplc.PlutusByteString(
bytes.fromhex(
"dc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2"
)
)
],
),
uplc.PlutusConstr(0, []),
uplc.data_from_cbor(
bytes.fromhex(
(
"d8799fd8799f9fd8799fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffd8799fd8799fd87a9f581cdbe769758f26efb21f008dc097bb194cffc622acc37fcefc5372eee3ffd87a80ffa140a1401a00989680d87a9f5820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dffd87a80ffffff809fd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a14000d87980d87a80ffffa140a14000a140a1400080a0d8799fd8799fd87a9f1b000001836ac117d8ffd87a80ffd8799fd87b80d87a80ffff80a1d87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffd87980a15820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd8799f5820797a1e1720b63621c6b185088184cb8e23af6e46b55bd83e7a91024c823a6c2affffd87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffff"
# required sig missing int this script context
for d in [
uplc.PlutusConstr(
0,
[
uplc.PlutusByteString(
bytes.fromhex(
"dc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2"
)
)
),
]:
f = uplc.Apply(f, d)
ret = uplc_eval(f)
failed = False
except Exception as e:
failed = True
self.assertTrue(failed, "Machine did validate the content")
],
),
uplc.PlutusConstr(0, []),
uplc.data_from_cbor(
bytes.fromhex(
(
"d8799fd8799f9fd8799fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffd8799fd8799fd87a9f581cdbe769758f26efb21f008dc097bb194cffc622acc37fcefc5372eee3ffd87a80ffa140a1401a00989680d87a9f5820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dffd87a80ffffff809fd8799fd8799fd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd87a80ffa140a14000d87980d87a80ffffa140a14000a140a1400080a0d8799fd8799fd87a9f1b000001836ac117d8ffd87a80ffd8799fd87b80d87a80ffff80a1d87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffd87980a15820dfab81872ce2bbe6ee5af9bbfee4047f91c1f57db5e30da727d5fef1e7f02f4dd8799f581cdc315c289fee4484eda07038393f21dc4e572aff292d7926018725c2ffd8799f5820797a1e1720b63621c6b185088184cb8e23af6e46b55bd83e7a91024c823a6c2affffd87a9fd8799fd8799f582055d353acacaab6460b37ed0f0e3a1a0aabf056df4a7fa1e265d21149ccacc527ff01ffffff"
)
)
),
]:
f = uplc.Apply(f, d)
ret = uplc_eval(f)

def test_recursion(self):
source_code = """
Expand Down Expand Up @@ -396,6 +388,7 @@ def test_parameterized_compile(self):
code = code.compile()
f = code.term

@unittest.expectedFailure
def test_dict_datum(self):
input_file = "examples/dict_datum.py"
with open(input_file) as fp:
Expand All @@ -405,31 +398,23 @@ def test_dict_datum(self):
code = code.compile()
f = code.term
# UPLC lambdas may only take one argument at a time, so we evaluate by repeatedly applying
try:
# required sig missing int this script context
for d in [
uplc.PlutusConstr(
0,
[
uplc.PlutusMap(
frozendict.frozendict(
{
uplc.PlutusConstr(
0, [uplc.PlutusByteString(b"\x01")]
): 2
}
)
# required sig missing int this script context
for d in [
uplc.PlutusConstr(
0,
[
uplc.PlutusMap(
frozendict.frozendict(
{uplc.PlutusConstr(0, [uplc.PlutusByteString(b"\x01")]): 2}
)
],
),
]:
f = uplc.Apply(f, d)
ret = uplc_eval(f)
failed = False
except Exception as e:
failed = True
self.assertTrue(failed, "Machine did validate the content")
)
],
),
]:
f = uplc.Apply(f, d)
ret = uplc_eval(f)

@unittest.expectedFailure
def test_overopt_removedeadvar(self):
# this tests that errors that are caused by assignments are actually triggered at the time of assigning
source_code = """
Expand All @@ -443,17 +428,13 @@ def validator(x: Token) -> bool:
code = code.compile()
f = code.term
# UPLC lambdas may only take one argument at a time, so we evaluate by repeatedly applying
try:
for d in [
uplc.PlutusConstr(0, []),
]:
f = uplc.Apply(f, d)
ret = uplc_eval(f)
failed = False
except Exception as e:
failed = True
self.assertTrue(failed, "Machine did validate the content")
for d in [
uplc.PlutusConstr(0, []),
]:
f = uplc.Apply(f, d)
ret = uplc_eval(f)

@unittest.expectedFailure
def test_opt_shared_var(self):
# this tests that errors that are caused by assignments are actually triggered at the time of assigning
source_code = """
Expand All @@ -470,16 +451,11 @@ def validator(x: Token) -> bool:
code = code.compile()
f = code.term
# UPLC lambdas may only take one argument at a time, so we evaluate by repeatedly applying
try:
for d in [
uplc.PlutusConstr(0, []),
]:
f = uplc.Apply(f, d)
ret = uplc_eval(f)
failed = False
except Exception as e:
failed = True
self.assertTrue(failed, "Machine did validate the content")
for d in [
uplc.PlutusConstr(0, []),
]:
f = uplc.Apply(f, d)
ret = uplc_eval(f)

def test_list_expr(self):
# this tests that the list expression is evaluated correctly
Expand All @@ -497,7 +473,7 @@ def validator(x: None) -> List[int]:
]:
f = uplc.Apply(f, d)
ret = [x.value for x in uplc_eval(f).value]
self.assertEqual(ret, [1, 2, 3, 4, 5], "Machine did validate the content")
self.assertEqual(ret, [1, 2, 3, 4, 5], "List expression incorrectly compiled")

def test_redefine_constr(self):
# this tests that classes defined by assignment inherit constructors
Expand All @@ -516,7 +492,7 @@ def validator(x: None) -> bytes:
]:
f = uplc.Apply(f, d)
ret = uplc_eval(f).value
self.assertEqual(ret, bytes([2, 3]), "Machine did validate the content")
self.assertEqual(ret, bytes([2, 3]), "Re-assignment of global variable failed")

def test_wrap_into_generic_data(self):
# this tests that errors that are caused by assignments are actually triggered at the time of assigning
Expand All @@ -540,7 +516,7 @@ def validator(_: None) -> SomeOutputDatum:
uplc.data_from_cbor(
prelude.SomeOutputDatum(b"a").to_cbor(encoding="bytes")
),
"Machine did validate the content",
"Wrapping to generic data failed",
)

def test_list_comprehension_even(self):
Expand Down Expand Up @@ -976,3 +952,50 @@ def validator(x: Token) -> bool:
except Exception as e:
failed = True
self.assertTrue(failed, "Machine did validate the content")

@unittest.skip
def test_inner_outer_state_functions(self):
source_code = """
a = 2
def b() -> int:
return a

def validator(_: None) -> int:
a = 3
return b()
"""
ast = compiler.parse(source_code)
code = compiler.compile(ast).compile()
res = uplc_eval(uplc.Apply(code, uplc.PlutusConstr(0, [])))
self.assertEqual(res, uplc.PlutusInteger(2))

def test_outer_state_change_functions(self):
source_code = """
a = 2
def b() -> int:
return a
a = 3

def validator(_: None) -> int:
return b()
"""
ast = compiler.parse(source_code)
code = compiler.compile(ast).compile()
res = uplc_eval(uplc.Apply(code, uplc.PlutusConstr(0, [])))
self.assertEqual(res, uplc.PlutusInteger(3))

@unittest.expectedFailure
def test_f(self):
source_code = """
def c():
a = 2
def b() -> int:
return a
return b

def validator(_: None):
a = 3
return c()
"""
ast = compiler.parse(source_code)
code = compiler.compile(ast).compile()
12 changes: 10 additions & 2 deletions opshin/typed_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,14 @@ def __ge__(self, other):

@dataclass(frozen=True, unsafe_hash=True)
class AnyType(ClassType):
"""The top element in the partial order on types"""
"""The top element in the partial order on types (excluding FunctionTypes, which do not compare to anything)"""

def __ge__(self, other):
return True
return (
isinstance(other, ClassType)
and not isinstance(other, FunctionType)
and not isinstance(other, PolymorphicFunctionType)
)


@dataclass(frozen=True, unsafe_hash=True)
Expand Down Expand Up @@ -1120,6 +1124,10 @@ def transform_output_map(p: Type):
assert isinstance(
p, InstanceType
), "Can only transform instances, not classes as input"
if isinstance(p.typ, FunctionType) or isinstance(p.typ, PolymorphicFunction):
raise NotImplementedError(
"Can not map functions into PlutusData and hence not return them from a function as Anything"
)
if p in TransformOutputMap:
return TransformOutputMap[p]
if isinstance(p.typ, ListType):
Expand Down