Skip to content
Merged
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
100 changes: 100 additions & 0 deletions test/dbi.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
using LMDB
using Test

# Fixtures for the typed-read extension-point tests below. Defined at
# module scope because `const` and `struct` aren't allowed inside a
# `@testset` block.
struct Point2D
x::Float32
y::Float32
end
Base.read(io::IO, ::Type{Point2D}) = read!(io, Ref{Point2D}())[]

struct FramedU64
value::UInt64
end
const FRAME_MAGIC = htol(UInt32(0xCAFEF00D))
function Base.read(io::IO, ::Type{FramedU64})
magic = read(io, UInt32)
magic == FRAME_MAGIC || error("bad magic 0x$(string(magic, base=16))")
pos_before = position(io)
skip(io, 0)
@assert position(io) == pos_before
FramedU64(ltoh(read(io, UInt64)))
end

@testset "DBI" begin

key = 10
Expand Down Expand Up @@ -159,4 +181,82 @@ mktempdir() do dir
end
end

# Round-trip a custom bitstype through put!/tryget/walk using only the
# IO-based extension point (`Base.read(io::IO, ::Type{Point2D})`,
# defined at module scope above).
mktempdir() do dir
environment(dir) do env
start(env) do txn
open(txn) do dbi
LMDB.put!(txn, dbi, "origin", Point2D(0f0, 0f0))
LMDB.put!(txn, dbi, "p1", Point2D(1.5f0, 2.5f0))

@test LMDB.tryget(txn, dbi, "p1", Point2D) == Point2D(1.5f0, 2.5f0)
@test LMDB.tryget(txn, dbi, "origin", Point2D) == Point2D(0f0, 0f0)
@test get(txn, dbi, "p1", Point2D) == Point2D(1.5f0, 2.5f0)

# The Vector{E} overload also works for any bitstype E,
# without the user defining anything extra.
@test LMDB.tryget(txn, dbi, "p1", Vector{Point2D}) ==
[Point2D(1.5f0, 2.5f0)]

# Typed walk decodes both K and V through Base.read.
seen = Pair{String,Point2D}[]
LMDB.open(txn, dbi) do cur
LMDB.walk(cur, String, Point2D) do k, v
push!(seen, k => v)
end
end
@test sort(seen; by = first) ==
["origin" => Point2D(0f0, 0f0),
"p1" => Point2D(1.5f0, 2.5f0)]
end
end
end
end

# Framed values: a custom `Base.read` can use the IO interface
# (`skip`, `position`) to step past a header before decoding the
# payload. Exercises the IO contract from inside user code (see
# `FramedU64` / `FRAME_MAGIC` at module scope).
mktempdir() do dir
environment(dir) do env
start(env) do txn
open(txn) do dbi
LMDB.put_reserved!(txn, dbi, "framed", 12) do buf
unsafe_store!(Ptr{UInt32}(pointer(buf)), FRAME_MAGIC)
unsafe_store!(Ptr{UInt64}(pointer(buf) + 4), htol(UInt64(0x1234_5678)))
end
@test LMDB.tryget(txn, dbi, "framed", FramedU64) ==
FramedU64(0x1234_5678)
end
end
end
end

# Non-Array AbstractArray inputs (e.g. `ReinterpretArray`, contiguous
# `SubArray`) flow through `cconvert(Ptr{MDB_val}, ::AbstractArray)`.
mktempdir() do dir
environment(dir) do env
start(env) do txn
open(txn) do dbi
# ReinterpretArray view onto a backing UInt64 vector.
ra_key = reinterpret(UInt8, UInt64[0xdeadbeefcafef00d])
@test !(ra_key isa Array)
LMDB.put!(txn, dbi, ra_key, "v-reinterpret")
@test LMDB.tryget(txn, dbi, ra_key, String) == "v-reinterpret"
@test LMDB.tryget(txn, dbi, collect(ra_key), String) == "v-reinterpret"

# Contiguous SubArray.
backing = collect(0x01:0x10)
sv_key = view(backing, 4:8)
@test !(sv_key isa Array)
LMDB.put!(txn, dbi, sv_key, "v-subarray")
@test LMDB.tryget(txn, dbi, sv_key, String) == "v-subarray"
@test LMDB.tryget(txn, dbi, collect(sv_key), String) == "v-subarray"
end
end
end
end

end # @testset "DBI"
Loading