Skip to content

Commit

Permalink
Split up tests, add a few more
Browse files Browse the repository at this point in the history
  • Loading branch information
swernli committed Dec 10, 2024
1 parent f50aa9f commit 91b6c48
Showing 1 changed file with 117 additions and 10 deletions.
127 changes: 117 additions & 10 deletions pip/tests/test_qsharp.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import pytest
import qsharp
import qsharp.env
import qsharp.utils
from contextlib import redirect_stdout
import io
Expand Down Expand Up @@ -380,10 +381,10 @@ def test_target_profile_from_str_match_enum_values() -> None:
def test_callables_exposed_into_env() -> None:
qsharp.init()
qsharp.eval("function Four() : Int { 4 }")
assert qsharp.env.Four() == 4
assert qsharp.env.Four() == 4, "callable should be available"

Check notice

Code scanning / devskim

If untrusted data (data from HTTP requests, user submitted files, etc.) is included in an eval statement it can allow an attacker to inject their own code. Note test

Review eval for untrusted data
qsharp.eval("function Add(a : Int, b : Int) : Int { a + b }")
assert qsharp.env.Four() == 4
assert qsharp.env.Add(2, 3) == 5
assert qsharp.env.Four() == 4, "first callable should still be available"
assert qsharp.env.Add(2, 3) == 5, "second callable should be available"
# After init, the callables should be cleared and no longer available
qsharp.init()
with pytest.raises(AttributeError):
Expand All @@ -394,22 +395,113 @@ def test_callable_exposed_into_env_complex_types() -> None:
qsharp.eval(
"function Complicated(a : Int, b : (Double, BigInt)) : ((Double, BigInt), Int) { (b, a) }"
)
assert qsharp.env.Complicated(2, (3.0, 4000000000000000000)) == (
(3.0, 4000000000000000000),
assert qsharp.env.Complicated(2, (3.0, 4000000000000000000000)) == (
(3.0, 4000000000000000000000),
2,
)
), "callables that take complex types should marshall them correctly"


def test_callable_exposed_into_env_with_array() -> None:
qsharp.init()
qsharp.eval("function Smallest(a : Int[]) : Int { Std.Math.Min(a)}")

Check notice

Code scanning / devskim

If untrusted data (data from HTTP requests, user submitted files, etc.) is included in an eval statement it can allow an attacker to inject their own code. Note test

Review eval for untrusted data
assert qsharp.env.Smallest([1, 2, 3, 0, 4, 5]) == 0
assert (
qsharp.env.Smallest([1, 2, 3, 0, 4, 5]) == 0
), "callable that takes array should work"


def test_callable_exposed_into_env_fails_incorrect_types() -> None:
def test_callable_with_int_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : Int) : Int { a }")
assert qsharp.env.Identity(4) == 4
with pytest.raises(TypeError):
qsharp.env.Identity("4")
with pytest.raises(TypeError):
qsharp.env.Identity(4.0)
with pytest.raises(OverflowError):
qsharp.env.Identity(4000000000000000000000)
with pytest.raises(TypeError):
qsharp.env.Identity([4])


def test_callable_with_double_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : Double) : Double { a }")
assert qsharp.env.Identity(4.0) == 4.0
assert qsharp.env.Identity(4) == 4.0
with pytest.raises(TypeError):
qsharp.env.Identity("4")
with pytest.raises(TypeError):
qsharp.env.Identity([4])


def test_callable_with_bigint_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : BigInt) : BigInt { a }")
assert qsharp.env.Identity(4000000000000000000000) == 4000000000000000000000
with pytest.raises(TypeError):
qsharp.env.Identity("4")
with pytest.raises(TypeError):
qsharp.env.Identity(4.0)


def test_callable_with_string_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : String) : String { a }")
assert qsharp.env.Identity("4") == "4"
with pytest.raises(TypeError):
qsharp.env.Identity(4)
with pytest.raises(TypeError):
qsharp.env.Identity(4.0)
with pytest.raises(TypeError):
qsharp.env.Identity([4])


def test_callable_with_bool_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : Bool) : Bool { a }")
assert qsharp.env.Identity(True) == True
with pytest.raises(TypeError):
qsharp.env.Identity("4")
with pytest.raises(TypeError):
qsharp.env.Identity(4)
with pytest.raises(TypeError):
qsharp.env.Identity(4.0)
with pytest.raises(TypeError):
qsharp.env.Identity([4])


def test_callable_with_array_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : Int[]) : Int[] { a }")

Check notice

Code scanning / devskim

If untrusted data (data from HTTP requests, user submitted files, etc.) is included in an eval statement it can allow an attacker to inject their own code. Note test

Review eval for untrusted data
assert qsharp.env.Identity([4, 5, 6]) == [4, 5, 6]
assert qsharp.env.Identity([]) == []
assert qsharp.env.Identity((4, 5, 6)) == [4, 5, 6]
with pytest.raises(TypeError):
qsharp.env.Identity(4)
with pytest.raises(TypeError):
qsharp.env.Identity("4")
with pytest.raises(TypeError):
qsharp.env.Identity(4.0)
with pytest.raises(TypeError):
qsharp.env.Identity([1, 2, 3.0])


def test_callable_with_tuple_exposed_into_env_fails_incorrect_types() -> None:
qsharp.init()
qsharp.eval("function Identity(a : (Int, Double)) : (Int, Double) { a }")
assert qsharp.env.Identity((4, 5.0)) == (4, 5.0)
assert qsharp.env.Identity((4, 5)) == (4, 5.0)
assert qsharp.env.Identity([4, 5.0]) == (4, 5.0)
with pytest.raises(qsharp.QSharpError):
qsharp.env.Identity((4, 5, 6))
with pytest.raises(TypeError):
qsharp.env.Identity(4)
with pytest.raises(TypeError):
qsharp.env.Identity("4")
with pytest.raises(TypeError):
qsharp.env.Identity(4.0)
with pytest.raises(TypeError):
qsharp.env.Identity([4.0, 5])


def test_callables_in_namespaces_exposed_into_env_submodules_and_removed_on_reinit() -> (
Expand All @@ -419,8 +511,7 @@ def test_callables_in_namespaces_exposed_into_env_submodules_and_removed_on_rein
# callables should be created with their namespaces
qsharp.eval("namespace Test { function Four() : Int { 4 } }")
qsharp.eval("function Identity(a : Int) : Int { a }")
assert qsharp.env.Test.Four() == 4
# should be able to import callables
# should be able to import callables from env and namespace submodule
from qsharp.env import Identity
from qsharp.env.Test import Four

Expand All @@ -440,17 +531,33 @@ def test_callables_with_unsupported_types_raise_errors_on_call() -> None:
qsharp.eval("function Unsupported(a : Int, q : Qubit) : Unit { }")
with pytest.raises(qsharp.QSharpError, match="unsupported input type: `Qubit`"):
qsharp.env.Unsupported()


def test_callables_with_unsupported_types_in_tuples_raise_errors_on_call() -> None:
qsharp.init()
qsharp.eval("function Unsupported(q : (Int, Qubit)[]) : Unit { }")
with pytest.raises(qsharp.QSharpError, match="unsupported input type: `Qubit`"):
qsharp.env.Unsupported()


def test_callables_with_unsupported_return_types_raise_errors_on_call() -> None:
qsharp.init()
qsharp.eval('function Unsupported() : Qubit { fail "won\'t be called" }')
with pytest.raises(qsharp.QSharpError, match="unsupported output type: `Qubit`"):
qsharp.env.Unsupported()


def test_callables_with_unsupported_udt_types_raise_errors_on_call() -> None:
qsharp.init()
qsharp.eval("function Unsupported(a : Std.Math.Complex) : Unit { }")
with pytest.raises(
qsharp.QSharpError, match='unsupported input type: `UDT<"Complex":'
):
qsharp.env.Unsupported()


def test_callable_with_unsupported_udt_return_types_raise_errors_on_call() -> None:
qsharp.init()
qsharp.eval('function Unsupported() : Std.Math.Complex { fail "won\'t be called" }')
with pytest.raises(
qsharp.QSharpError, match='unsupported output type: `UDT<"Complex":'
Expand Down

0 comments on commit 91b6c48

Please sign in to comment.