Skip to content

Commit

Permalink
Add some more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobnissen committed Jul 3, 2024
1 parent d968c85 commit 72b1091
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 10 deletions.
14 changes: 13 additions & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ Hence, the value written to an `Auxiliary` may not be the same value when being
- ¶ These are stored as `Int32` and `UInt32` for `Signed` and `Unsigned`, respectively.

### BAM element types
The only different between SAM and BAM types is that the latter format permits different types of integers.
#### BAM integers
The main difference between SAM and BAM types is that the latter format permits different types of integers.
Hence, except the types mentioned below, all the SAM types in the table above are also supported in BAM,
with the same Julia <-> BAM type correspondance.
Further, reading a value of `i` will return an `Int32` instead of an `Int`.
Expand All @@ -190,6 +191,17 @@ Further, reading a value of `i` will return an `Int32` instead of an `Int`.
| `Unsigned` | `I` | `UInt32` |
| `Signed` | `i` | `Int32` |

#### BAM Arrays
Whereas reading a SAM array (type `B`) will result in a `Memory`, BAM arrays only promise
that they return an `AbstractVector` of the correct element type:

```jldoctest
julia> aux = BAM.Auxiliary("ABBs\2\0\0\0\1\2\3\4");
julia> aux["AB"] isa AbstractVector{Int16}
true
```

### The `Hex` type
The SAM/BAM type `H` signifies a hex-encoded byte array.
Byte arrays are stored as the `B:C` type when written, since this type is more legible (in SAM),
Expand Down
9 changes: 2 additions & 7 deletions src/XAMAuxData.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,6 @@ get_type_tag(::Type{<:AbstractString}) = UInt8('Z')
get_type_tag(::Type{<:AbstractVector}) = UInt8('B')
get_type_tag(::Type{<:Hex}) = UInt8('H')

function as_aux_type(T::Type{<:AUX_NUMBER_TYPES})
T != Union{} ? T : error("Cannot convert Union{} to XAM-compatible type")
end

as_aux_type(::Type{<:Real}) = Float32
as_aux_type(::Type{<:Integer}) = Int32

Expand Down Expand Up @@ -170,18 +166,17 @@ function Base.isvalid(aux::AbstractAuxiliary)
all(i -> !isa(i, Error), iter_encodings(aux))
end

function striptype end
function Base.copy(aux::AbstractAuxiliary)
x = aux.x
v = if x isa Vector{UInt8}
x[aux.start:end]
else
copy(MemoryView(aux))
end
typeof(aux)(v, 1)
striptype(typeof(aux))(v, 1)
end

Base.empty(T::Type{<:AbstractAuxiliary{V}}) where V = T(empty(V), 1)

function Base.length(aux::AbstractAuxiliary)::Int
n = 0
for val in iter_encodings(aux)
Expand Down
4 changes: 4 additions & 0 deletions src/bam.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ..AuxTag, ..AbstractAuxiliary, ..Hex
import ..AUX_NUMBER_TYPES, ..try_auxtag, ..Error, ..Errors
import ..is_printable, ..ELTYPE_DICT, ..load_hex, ..iter_encodings, ..AbstractEncodedIterator
import ..is_printable_char, ..as_bam_aux_value, ..get_type_tag, ..hexencode!, ..AuxException
import ..striptype

public Auxiliary, AuxTag, Error, Errors

Expand Down Expand Up @@ -78,6 +79,9 @@ struct Auxiliary{T} <: AbstractAuxiliary{T}
end
end

striptype(::Type{<:Auxiliary}) = Auxiliary
Base.empty(::Type{Auxiliary}) = Auxiliary(UInt8[], 1)

const MutableAuxiliary = Auxiliary{Vector{UInt8}}

MemoryView(x::Auxiliary) = @inbounds MemoryView(x.x)[x.start:end]
Expand Down
5 changes: 4 additions & 1 deletion src/sam.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module SAM
import ..AuxTag, ..AbstractAuxiliary, ..ELTYPE_DICT, ..is_printable_char, ..is_printable, ..Hex, ..setindex_nonexisting!
import ..DelimitedIterator, ..get_type_tag, ..Error, ..Errors, ..load_hex
import ..try_auxtag, ..Unsafe, ..as_sam_aux_value, ..AUX_NUMBER_TYPES, ..hexencode!
import ..iter_encodings, ..AbstractEncodedIterator, ..AuxException
import ..iter_encodings, ..AbstractEncodedIterator, ..AuxException, ..striptype

public Auxiliary, AuxTag, Hex, Errors, Error

Expand Down Expand Up @@ -115,6 +115,9 @@ struct Auxiliary{T <: AbstractVector{UInt8}} <: AbstractAuxiliary{T}
end
end

striptype(::Type{<:Auxiliary}) = Auxiliary
Base.empty(::Type{Auxiliary}) = Auxiliary(UInt8[], 1)

const MutableAuxiliary = Auxiliary{Vector{UInt8}}

function iter_encodings(aux::Auxiliary)
Expand Down
68 changes: 67 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module XAMAuxDataTests

using XAMAuxData: XAMAuxData, SAM, BAM, AuxTag, Hex, DelimitedIterator, Errors
using XAMAuxData: XAMAuxData, SAM, BAM, AuxTag, Hex, DelimitedIterator, Errors, try_auxtag
using Test
using MemoryViews: MemoryView
using FormatSpecimens
Expand Down Expand Up @@ -33,6 +33,14 @@ end

@testset "AuxTag" begin
@test AuxTag("ac") == AuxTag('a', 'c') == AuxTag(0x61, 0x63)
for good in ["AB", "A1", "a9", "w5"]
@test try_auxtag(good) isa AuxTag
end
for bad in ["", "A", "ABC", "A11", "5A", "", "a!"]
@test try_auxtag(bad) === nothing
end

@test sort!(AuxTag.(["XA", "X1", "ab", "AB"])) == AuxTag.(["AB", "X1", "XA", "ab"])
end

@testset "SAM" begin
Expand Down Expand Up @@ -543,6 +551,24 @@ end # BAM
@test aux["Kk"] == Float32.(mem)
end

@testset "Arrays of non-basic types" begin
for T in [SAM.Auxiliary, BAM.Auxiliary]
aux = T(rand(UInt8, 10), 11)
inp = BigInt[20, -400, 102]
aux["AB"] = inp
outp = aux["AB"]
@test outp isa (T == SAM.Auxiliary ? Memory{Int32} : AbstractVector{Int32})
@test outp == inp

empty!(aux)
inp = [pi, MathConstants.e]
aux["KV"] = inp
outp = aux["KV"]
@test outp isa (T == SAM.Auxiliary ? Memory{Float32} : AbstractVector{Float32})
@test outp inp
end
end

@testset "Bad arrays" begin
for bad_eltype in [
"W,1,2,3",
Expand All @@ -565,6 +591,46 @@ end # BAM
aux = SAM.Auxiliary("AB:B:" * bad_array)
@test aux["AB"] == Errors.InvalidArray
end

for T in [SAM.Auxiliary, BAM.Auxiliary]
aux = T(UInt8[], 1)
@test_throws Exception aux["AB"] = Vector{Union{}}(undef, 3)
end
end
end

@testset "Various operations" begin
for T in [SAM.Auxiliary, BAM.Auxiliary]
aux = T(UInt8[], 1)
@test Dict(empty(T)) == Dict(aux)
@test length(aux) == 0
@test isempty(aux)
aux["k1"] = 1234
@test length(aux) == 1
@test !isempty(aux)
aux["v9"] = 'w'
@test length(aux) == 2
aux["AA"] = Int16[-500, 205, 1]
@test length(aux) == 3

for k in ["k1", "v9", "AA"]
@test haskey(aux, k)
end
@test collect(keys(aux)) == AuxTag.(["k1", "v9", "AA"])
for k in ["k2", "v7", "BB", "c1"]
@test !haskey(aux, k)
end

cp = copy(aux)
d = Dict(aux)
@test d == Dict(cp)
len = 3
for k in ["k1", "v9", "AA"]
delete!(aux, k)
len -= 1
@test length(aux) == len
end
@test Dict(cp) == d
end
end

Expand Down

2 comments on commit 72b1091

@jakobnissen
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request updated: JuliaRegistries/General/110325

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.1.0 -m "<description of version>" 72b1091562d16abb3a2e6241c05b41a291f93b4f
git push origin v0.1.0

Please sign in to comment.