494 lines
11 KiB
Julia
494 lines
11 KiB
Julia
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
|
|
|
using Base.Test
|
|
|
|
# Check that serializer hasn't gone out-of-frame
|
|
@test Serializer.sertag(Symbol) == 1
|
|
@test Serializer.sertag(()) == 55
|
|
@test Serializer.sertag(false) == 63
|
|
|
|
function create_serialization_stream(f::Function)
|
|
s = IOBuffer()
|
|
f(s)
|
|
close(s)
|
|
end
|
|
|
|
# Tags
|
|
create_serialization_stream() do s
|
|
Serializer.writetag(s, Serializer.sertag(Bool))
|
|
@test take!(s)[end] == UInt8(Serializer.sertag(Bool))
|
|
end
|
|
|
|
create_serialization_stream() do s
|
|
Serializer.write_as_tag(s, Serializer.sertag(Bool))
|
|
@test take!(s)[end] == UInt8(Serializer.sertag(Bool))
|
|
end
|
|
|
|
create_serialization_stream() do s
|
|
Serializer.write_as_tag(s, Serializer.sertag(Symbol))
|
|
data = take!(s)
|
|
@test data[end-1] == 0x00
|
|
@test data[end] == UInt8(Serializer.sertag(Symbol))
|
|
end
|
|
|
|
# Boolean & Empty & Nothing
|
|
create_serialization_stream() do s
|
|
serialize(s, true)
|
|
serialize(s, ())
|
|
serialize(s, nothing)
|
|
seek(s, 0)
|
|
@test deserialize(s) === true
|
|
@test deserialize(s) === ()
|
|
@test deserialize(s) === nothing
|
|
end
|
|
|
|
# Ptr
|
|
create_serialization_stream() do s
|
|
serialize(s, C_NULL)
|
|
seekstart(s)
|
|
@test deserialize(s) === C_NULL
|
|
end
|
|
|
|
# Integer
|
|
create_serialization_stream() do s
|
|
serialize(s, 0x1)
|
|
serialize(s, 32)
|
|
serialize(s, 33)
|
|
seek(s,0)
|
|
@test deserialize(s) === 0x01
|
|
@test deserialize(s) === 32
|
|
@test deserialize(s) === 33
|
|
end
|
|
|
|
# Tuple
|
|
create_serialization_stream() do s
|
|
tpl = (0x1,'a')
|
|
serialize(s, tpl)
|
|
|
|
len = 257
|
|
lt = ntuple(i->0x1, len)
|
|
serialize(s, lt)
|
|
|
|
serialize(s, Tuple{})
|
|
|
|
seek(s, 0)
|
|
@test deserialize(s) === tpl
|
|
@test deserialize(s) === lt
|
|
@test deserialize(s) === Tuple{}
|
|
end
|
|
|
|
# Dict
|
|
create_serialization_stream() do s
|
|
dct = Dict("A"=>1, "B"=>2)
|
|
serialize(s, dct)
|
|
seek(s, 0)
|
|
@test deserialize(s) == dct
|
|
end
|
|
|
|
# Symbol
|
|
create_serialization_stream() do s
|
|
gensym(len) = Symbol(repeat("A", len))
|
|
|
|
smbl = gensym(1)
|
|
serialize(s, smbl)
|
|
|
|
smbl2 = gensym(10)
|
|
serialize(s, smbl2)
|
|
|
|
smbl3 = gensym(257)
|
|
serialize(s, smbl3)
|
|
|
|
seek(s, 0)
|
|
@test deserialize(s) === smbl
|
|
@test deserialize(s) === smbl2
|
|
@test deserialize(s) === smbl3
|
|
end
|
|
|
|
# Module
|
|
create_serialization_stream() do s # user-defined module
|
|
mod = b"SomeModule"
|
|
modstring = String(mod)
|
|
eval(parse("module $(modstring); end"))
|
|
modtype = eval(parse("$(modstring)"))
|
|
serialize(s, modtype)
|
|
seek(s, 0)
|
|
@test deserialize(s) === modtype
|
|
end
|
|
|
|
# DataType
|
|
create_serialization_stream() do s # standard types
|
|
typ1 = UInt8
|
|
serialize(s, typ1)
|
|
typ2 = Bool
|
|
serialize(s, typ2)
|
|
|
|
seek(s, 0)
|
|
@test deserialize(s) == typ1
|
|
@test deserialize(s) == typ2
|
|
end
|
|
|
|
create_serialization_stream() do s # user-defined type
|
|
usertype = "SerializeSomeType"
|
|
eval(parse("abstract type $(usertype) end"))
|
|
utype = eval(parse("$(usertype)"))
|
|
serialize(s, utype)
|
|
seek(s, 0)
|
|
@test deserialize(s) === utype
|
|
end
|
|
|
|
create_serialization_stream() do s # user-defined type
|
|
usertype = "SerializeSomeType1"
|
|
eval(parse("mutable struct $(usertype); end"))
|
|
utype = eval(parse("$(usertype)"))
|
|
serialize(s, utype)
|
|
seek(s, 0)
|
|
@test deserialize(s) === utype
|
|
end
|
|
|
|
create_serialization_stream() do s # user-defined type
|
|
usertype = "SerializeSomeType2"
|
|
eval(parse("abstract type $(usertype){T} end"))
|
|
utype = eval(parse("$(usertype)"))
|
|
serialize(s, utype)
|
|
seek(s, 0)
|
|
@test deserialize(s) == utype
|
|
end
|
|
|
|
create_serialization_stream() do s # immutable struct with 1 field
|
|
usertype = "SerializeSomeType3"
|
|
eval(parse("struct $(usertype){T}; a::T; end"))
|
|
utype = eval(parse("$(usertype)"))
|
|
serialize(s, utype)
|
|
seek(s, 0)
|
|
@test deserialize(s) == utype
|
|
end
|
|
|
|
create_serialization_stream() do s # immutable struct with 2 field
|
|
usertype = "SerializeSomeType4"
|
|
eval(parse("struct $(usertype){T}; a::T; b::T; end"))
|
|
utval = eval(parse("$(usertype)(1,2)"))
|
|
serialize(s, utval)
|
|
seek(s, 0)
|
|
@test deserialize(s) === utval
|
|
end
|
|
|
|
create_serialization_stream() do s # immutable struct with 3 field
|
|
usertype = "SerializeSomeType5"
|
|
eval(parse("struct $(usertype){T}; a::T; b::T; c::T; end"))
|
|
utval = eval(parse("$(usertype)(1,2,3)"))
|
|
serialize(s, utval)
|
|
seek(s, 0)
|
|
@test deserialize(s) === utval
|
|
end
|
|
|
|
create_serialization_stream() do s # immutable struct with 4 field
|
|
usertype = "SerializeSomeType6"
|
|
eval(parse("struct $(usertype){T}; a::T; b::T; c::T; d::T; end"))
|
|
utval = eval(parse("$(usertype)(1,2,3,4)"))
|
|
serialize(s, utval)
|
|
seek(s, 0)
|
|
@test deserialize(s) === utval
|
|
end
|
|
|
|
# Expression
|
|
create_serialization_stream() do s
|
|
expr = parse("a = 1")
|
|
serialize(s, expr)
|
|
|
|
expr2 = parse(repeat("a = 1;", 300))
|
|
serialize(s, expr2)
|
|
|
|
seek(s, 0)
|
|
@test deserialize(s) == expr
|
|
@test deserialize(s) == expr2
|
|
end
|
|
|
|
# Array
|
|
mutable struct TA1
|
|
v::UInt8
|
|
end
|
|
create_serialization_stream() do s # small 1d array
|
|
arr1 = fill(0x01, 10) # small 1d array
|
|
serialize(s, arr1)
|
|
arr2 = fill(0x01, 3, 3) # small 2d array
|
|
serialize(s, arr2)
|
|
arr3 = fill(0x0001, 50) # large 1d array
|
|
serialize(s, arr3)
|
|
arr4 = reshape([true, false, false, false, true, false, false, false, true], 3, 3)
|
|
serialize(s, arr4) # boolean array
|
|
|
|
arr5 = Array{TA1}(3)
|
|
arr5[2] = TA1(0x01)
|
|
serialize(s, arr5)
|
|
|
|
seek(s, 0)
|
|
@test deserialize(s) == arr1
|
|
@test deserialize(s) == arr2
|
|
@test deserialize(s) == arr3
|
|
@test deserialize(s) == arr4
|
|
|
|
result = deserialize(s)
|
|
@test !isassigned(result,1)
|
|
@test !isassigned(result,3)
|
|
@test result[2].v == arr5[2].v
|
|
end
|
|
|
|
# SubArray
|
|
create_serialization_stream() do s # slices
|
|
slc1 = view(ones(UInt8, 4), 2:3)
|
|
serialize(s, slc1)
|
|
slc2 = view(ones(UInt8, 4, 4) .+ [0x00, 0x01, 0x02, 0x03], 1, 2:4)
|
|
serialize(s, slc2)
|
|
|
|
seek(s, 0)
|
|
@test deserialize(s) == slc1
|
|
@test deserialize(s) == slc2
|
|
end
|
|
|
|
# Objects that have a SubArray as a type in a type-parameter list
|
|
module ArrayWrappers
|
|
|
|
struct ArrayWrapper{T,N,A<:AbstractArray} <: AbstractArray{T,N}
|
|
data::A
|
|
end
|
|
ArrayWrapper{T,N}(data::AbstractArray{T,N}) = ArrayWrapper{T,N,typeof(data)}(data)
|
|
Base.size(A::ArrayWrapper) = size(A.data)
|
|
Base.size(A::ArrayWrapper, d) = size(A.data, d)
|
|
Base.getindex(A::ArrayWrapper, i::Real...) = getindex(A.data, i...)
|
|
|
|
end
|
|
|
|
let A = rand(3,4)
|
|
for B in (view(A, :, 2:4), view(A, 2, 1:3))
|
|
C = ArrayWrappers.ArrayWrapper(B)
|
|
io = IOBuffer()
|
|
serialize(io, C)
|
|
seek(io, 0)
|
|
Cd = deserialize(io)
|
|
@test size(Cd) == size(C)
|
|
@test Cd == B
|
|
end
|
|
end
|
|
|
|
# Function
|
|
serialize_test_function() = 1
|
|
serialize_test_function2 = ()->1
|
|
create_serialization_stream() do s # Base generic function
|
|
serialize(s, sin)
|
|
serialize(s, typeof)
|
|
serialize(s, serialize_test_function)
|
|
serialize(s, serialize_test_function2)
|
|
|
|
seek(s, 0)
|
|
@test deserialize(s) === sin
|
|
@test deserialize(s) === typeof
|
|
@test deserialize(s)() === 1
|
|
@test deserialize(s)() === 1
|
|
end
|
|
|
|
# Anonymous Functions
|
|
main_ex = quote
|
|
$create_serialization_stream() do s
|
|
local g() = :magic_token_anon_fun_test
|
|
serialize(s, g)
|
|
serialize(s, g)
|
|
|
|
seekstart(s)
|
|
ds = SerializationState(s)
|
|
local g2 = deserialize(ds)
|
|
$Test.@test g2 !== g
|
|
$Test.@test g2() == :magic_token_anon_fun_test
|
|
$Test.@test g2() == :magic_token_anon_fun_test
|
|
$Test.@test deserialize(ds) === g2
|
|
|
|
# issue #21793
|
|
y = x -> (() -> x)
|
|
seekstart(s)
|
|
serialize(s, y)
|
|
seekstart(s)
|
|
y2 = deserialize(s)
|
|
x2 = y2(2)
|
|
$Test.@test x2() == 2
|
|
end
|
|
end
|
|
# This needs to be run on `Main` since the serializer treats it differently.
|
|
eval(Main, main_ex)
|
|
|
|
# Task
|
|
create_serialization_stream() do s # user-defined type array
|
|
f = () -> begin task_local_storage(:v, 2); return 1+1 end
|
|
t = Task(f)
|
|
wait(schedule(t))
|
|
serialize(s, t)
|
|
seek(s, 0)
|
|
r = deserialize(s)
|
|
@test r.storage[:v] == 2
|
|
@test r.state == :done
|
|
@test r.exception === nothing
|
|
end
|
|
|
|
struct MyErrorTypeTest <: Exception end
|
|
create_serialization_stream() do s # user-defined type array
|
|
t = Task(()->throw(MyErrorTypeTest()))
|
|
@test_throws MyErrorTypeTest wait(schedule(t))
|
|
serialize(s, t)
|
|
seek(s, 0)
|
|
r = deserialize(s)
|
|
@test r.state == :failed
|
|
@test isa(t.exception, MyErrorTypeTest)
|
|
end
|
|
|
|
# corner case: undefined inside immutable struct
|
|
create_serialization_stream() do s
|
|
serialize(s, Nullable{Any}())
|
|
seekstart(s)
|
|
n = deserialize(s)
|
|
@test isa(n, Nullable)
|
|
@test !isdefined(n, :value)
|
|
end
|
|
|
|
# cycles
|
|
module CycleFoo
|
|
echo(x)=x
|
|
end
|
|
create_serialization_stream() do s
|
|
echo(x) = x
|
|
afunc = (x)->x
|
|
A = Any[1,2,3,abs,abs,afunc,afunc,echo,echo,CycleFoo.echo,CycleFoo.echo,4,5]
|
|
A[3] = A
|
|
serialize(s, A)
|
|
seekstart(s)
|
|
b = deserialize(s)
|
|
@test b[3] === b
|
|
@test b[1] == 1
|
|
@test b[4] === abs
|
|
@test b[5] === b[4]
|
|
@test b[5](-1) == 1
|
|
|
|
@test b[6] === b[7]
|
|
@test b[6]("Hello") == "Hello"
|
|
|
|
@test b[8] === b[9]
|
|
@test b[8]("World") == "World"
|
|
|
|
@test b[10] === b[11]
|
|
@test b[10]("foobar") == "foobar"
|
|
|
|
@test b[end] == 5
|
|
@test length(b) == length(A)
|
|
@test isa(b,Vector{Any})
|
|
end
|
|
|
|
# shared references
|
|
create_serialization_stream() do s
|
|
A = [1,2]
|
|
B = [A,A]
|
|
serialize(s, B)
|
|
seekstart(s)
|
|
C = deserialize(s)
|
|
@test C == B
|
|
@test C[1] === C[2]
|
|
end
|
|
|
|
# Regex
|
|
create_serialization_stream() do s
|
|
r1 = r"a?b.*"
|
|
serialize(s, r1)
|
|
seekstart(s)
|
|
r2 = deserialize(s)
|
|
@test r1 == r2
|
|
end
|
|
|
|
# issue #13452
|
|
module Test13452
|
|
using Base.Test
|
|
|
|
module Shell
|
|
export foo
|
|
foo(x) = error("Instances must implement foo")
|
|
end
|
|
|
|
module Instance1
|
|
using ..Shell
|
|
Shell.foo(x::Int) = "This is an Int"
|
|
end
|
|
|
|
using .Shell, .Instance1
|
|
io = IOBuffer()
|
|
serialize(io, foo)
|
|
str = String(take!(io))
|
|
@test isempty(search(str, "Instance1"))
|
|
@test !isempty(search(str, "Shell"))
|
|
|
|
end # module Test13452
|
|
|
|
# issue #15163
|
|
mutable struct B15163{T}
|
|
x::Array{T}
|
|
end
|
|
let b = IOBuffer()
|
|
serialize(b,B15163([1]))
|
|
seekstart(b)
|
|
c = deserialize(b)
|
|
@test isa(c,B15163) && c.x == [1]
|
|
end
|
|
# related issue #20066
|
|
let b = IOBuffer()
|
|
serialize(b, Dict{Vector, Vector}())
|
|
seekstart(b)
|
|
c = deserialize(b)
|
|
@test isa(c, Dict{Vector, Vector})
|
|
end
|
|
|
|
# issue #15849
|
|
let b = IOBuffer()
|
|
vt = Tuple[(1,)]
|
|
serialize(b, vt)
|
|
seekstart(b)
|
|
@test deserialize(b) == vt
|
|
end
|
|
|
|
# issue #1770
|
|
let a = ['T', 'e', 's', 't']
|
|
f = IOBuffer()
|
|
serialize(f, a)
|
|
seek(f, 0)
|
|
@test deserialize(f) == a
|
|
f = IOBuffer()
|
|
serialize(f, a)
|
|
seek(f, 0)
|
|
@test deserialize(f) == a
|
|
|
|
# issue #4414
|
|
seek(f,0)
|
|
serialize(f, :β)
|
|
seek(f,0)
|
|
@test deserialize(f) === :β
|
|
end
|
|
|
|
# issue #20324
|
|
struct T20324{T}
|
|
x::T
|
|
end
|
|
let x = T20324[T20324(1) for i = 1:2]
|
|
b = IOBuffer()
|
|
serialize(b, x)
|
|
seekstart(b)
|
|
y = deserialize(b)
|
|
@test isa(y,Vector{T20324})
|
|
@test y == x
|
|
end
|
|
|
|
# issue #26979
|
|
let io = IOBuffer()
|
|
function gen_f(a::T) where T
|
|
f = x -> T(x)
|
|
return f
|
|
end
|
|
f = gen_f(1f0)
|
|
serialize(io, f)
|
|
seekstart(io)
|
|
f2 = deserialize(io)
|
|
@test f2(1) === 1f0
|
|
end
|