diff --git a/src/code-util.jl b/src/code-util.jl index 8449f2e..b6fac21 100644 --- a/src/code-util.jl +++ b/src/code-util.jl @@ -123,25 +123,39 @@ function is_special_symbol(symbol::Symbol)::Bool return symbol == :abort || symbol == :output || symbol == :rel end -# Generate a string representing the Rel type for the input -# Expected inputs are a vector of types, a tuple of types, or a type -function type_string(input::Vector) - if isempty(input) - return "" - end - return type_string(input[1]) -end +# Values can be a single value, a single tuple, a Vector of values, or a typed but empty +# Vector. Types are extracted directly from single values and recursively from Tuples and +# Vectors. -function type_string(input::Tuple) +# :a => [3, 4, 5] +type_string(::Vector{T}) where T = type_string(T) + +# :a => [(1, 2)] +# :a => (1, 2) +function type_string(::Union{T, Vector{T}}) where { T <: Tuple } result = "" - for t in input - result *= type_string(t) + for e_type in fieldtypes(T) + result *= type_string(e_type) end + return result end -function type_string(input) - return "/" * string(typeof(input)) +# [] +type_string(::Type{Any}) = "" + +# Generate a string representing the Rel type for single values +# :a => 1 +type_string(::Union{T, Type{T}}) where T = "/" * string(T) + +# The value tuple contains an inner tuple. Recurse into it. +function type_string(::Type{T}) where { T <: Tuple } + result = "/(" + for e_type in fieldtypes(T) + result *= type_string(e_type) + end + result *= ")" + return result end function key_to_array(input::Tuple) diff --git a/test/expect_result.jl b/test/expect_result.jl index c125e1b..dd278d4 100644 --- a/test/expect_result.jl +++ b/test/expect_result.jl @@ -63,9 +63,29 @@ end actual = generate_arrow(Dict(:a => [])) @test !RAITest.test_expected(expected, actual, "!match empty a") + expected = Dict("/:output/:a/Int64" => [()]) + actual = generate_arrow(Dict(:a => [1, 2, 3])) + @test RAITest.test_expected(expected, actual, "match existence e") + + expected = Dict("/:output/:a/Int64" => []) + actual = generate_arrow(Dict(:a => ["1", "2", "3"])) + @test RAITest.test_expected(expected, actual, "match non-existence e") + + expected = Dict(:a => Int64[]) + actual = generate_arrow(Dict(:a => [Int32(1), Int32(2), Int32(3)])) + @test RAITest.test_expected(expected, actual, "match non-existence e 32bit") + + expected = Dict(:a => Int64[]) + actual = generate_arrow(Dict(:a => ["1", "2", "3"])) + @test RAITest.test_expected(expected, actual, "match non-existence e String") + expected = Dict(:a => []) + actual = generate_arrow(Dict(:a => [()])) + @test !RAITest.test_expected(expected, actual, "!match non-existence e true") + + expected = Dict("/:output/:a/Int64" => []) actual = generate_arrow(Dict(:a => [1, 2, 3])) - @test RAITest.test_expected(expected, actual, "!match existence e") + @test !RAITest.test_expected(expected, actual, "!match non-existence e") expected = Dict(:a => [1, 2, 3]) actual = generate_arrow(Dict(:a => [1, 2, 3], :b => []))