Skip to content

Commit

Permalink
Rework @composed
Browse files Browse the repository at this point in the history
This reworks `@composed`, allowing the function to be called
like any other function, similar to how `@check` allows it.
In addition, this fixes the `Data.postype` bug of `@composed` when
used in a local scope.

Fixes #13
  • Loading branch information
Seelengrab committed Mar 2, 2024
1 parent 68adf62 commit fc21191
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 18 deletions.
35 changes: 23 additions & 12 deletions src/api.jl
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,23 @@ function kw_to_let(tc, kwargs)
return head
end

"""
Composed{S,T} <: Possibility{T}
A `Possibility` composed from multiple different `Possibility` through
`@composed`. A tiny bit more fancy/convenient compared to `map` if multiple
`Possibility` are required to be mapped over at the same time.
Should not be instantiated manually; keep the object returned by `@composed`
around instead.
"""
struct Composed{S,T} <: Data.Possibility{T}
function Composed{S}() where S
prodtype = Base.promote_op(Data.produce, Composed{S}, TestCase)
new{S, prodtype}()
end
end

"""
@composed
Expand Down Expand Up @@ -367,29 +384,23 @@ macro composed(e::Expr)
tc = gensym()
strategy_let = kw_to_let(tc, kwargs)

structproduce = Symbol(name, "__produce")
prodname = QuoteNode(name)

structfunc = Expr(:function)
funchead = copy(last(strategy_let.args))
funchead.head = :call
pushfirst!(funchead.args, structproduce)
pushfirst!(funchead.args, name)
push!(structfunc.args, funchead)
push!(structfunc.args, body)

return esc(quote
struct $name{T} <: $Data.Possibility{T}
function $name()
new{$Base.promote_op($Data.produce, $name, $TestCase)}()
end
end
$structfunc

function $Data.produce(::$name, $tc::$TestCase)
$structproduce($strategy_let...)
function $Data.produce(::$Composed{$prodname}, $tc::$TestCase)
$name($strategy_let...)
end

$structfunc

$name()
$Composed{$prodname}()
end)
end

Expand Down
1 change: 1 addition & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[deps]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
RequiredInterfaces = "97f35ef4-7bc5-4ec1-a41a-dcc69c7308c6"
Expand Down
43 changes: 37 additions & 6 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ using Aqua
using Random
using Logging
using Statistics: mean
using InteractiveUtils: subtypes
using .Threads: @spawn
import RequiredInterfaces
const RI = RequiredInterfaces
Expand All @@ -27,7 +28,8 @@ const verb = VERSION.major == 1 && VERSION.minor < 11
Aqua.test_stale_deps(Supposition; ignore)
end
@testset "Interfaces" begin
@testset "Possibility" RI.check_implementations(Supposition.Data.Possibility)
possibility_subtypes = filter(!=(Supposition.Composed), subtypes(Data.Possibility))
@testset "Possibility" RI.check_implementations(Supposition.Data.Possibility, possibility_subtypes)
@testset "ExampleDB" RI.check_implementations(Supposition.ExampleDB)
end
# Write your tests here.
Expand Down Expand Up @@ -435,7 +437,7 @@ const verb = VERSION.major == 1 && VERSION.minor < 11
end
end

@testset "@check verbose=verb API" begin
@testset "@check API" begin
@testset "regular use" begin
Supposition.@check verbose=verb function singlearg(i=Data.Integers(0x0, 0xff))
i isa Integer
Expand Down Expand Up @@ -539,10 +541,39 @@ const verb = VERSION.major == 1 && VERSION.minor < 11
(a,b)
end

@test isstructtype(uint8tup)
# FIXME: This is just the closure bug in disguise
@test_broken Data.postype(gen) === Tuple{UInt8, UInt8}
@test example(gen) isa Tuple{UInt8, UInt8}
@testset "Expected return types" begin
@test gen isa Supposition.Composed{:uint8tup, Tuple{UInt8,UInt8}}
@test Data.postype(gen) === Tuple{UInt8, UInt8}
@test example(gen) isa Tuple{UInt8, UInt8}
end

@testset "Can call defined function" begin
@test uint8tup(1,2) === (1,2)
end
end

@testset "Using external generators" begin
text = Data.Text(Data.AsciiCharacters(); max_len=10)
g2 = Supposition.@composed function stringcat(
t=text,
b=Data.Integers{UInt8}())
string(t, b)
end

@testset "Expected return types" begin
@test g2 isa Supposition.Composed{:stringcat, String}
@test Data.postype(g2) === String
@test example(g2) isa String
end

@check function stringcatcorrect(s=g2)
# The range-syntax in the regex captures all ASCII
contains(s, r"[\0-\x7f]*-?\d+")
end

@testset "Can call defined function" begin
@test stringcat("foo", "1") === "foo1"
end
end

@testset "Calling function defined outside Supposition" begin
Expand Down

0 comments on commit fc21191

Please sign in to comment.