/
githubmirror
/
julia
Обзор
Документация
Войти
/
githubmirror
/
julia
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
test/strings/stringview.jl
657 строк
24 KB
Steven G. Johnson
make reverse(::StringView) return String (#61579)
20 апр 2026, 20:50
Не верифицирован
20 апр 2026, 20:50
95fb1c5
Код
Авторство
О чём код?
@testset "StringViews" begin @testset "Construction" begin @test StringView([0x61, 0x62, 0x63]) == "abc" @test StringView(UInt8[0x48, 0x65, 0x6c, 0x6c, 0x6f]) == "Hello" @test StringView(codeunits("test")) == "test" @test StringView(b"hello") == "hello" s = StringView(UInt8[]) @test s == "" @test isempty(s) @test StringView(UInt8[0xc3, 0xa5]) == "å" @test StringView(0x42:0x45) == "BCDE" # Non-concrete parameter @test_throws ArgumentError StringView{DenseVector{UInt8}}([0x01]) end @testset "Construction from other types" begin v = UInt8[0x61, 0x62, 0x63] s = StringView(v) @test String(s) === "abc" # Vector{UInt8} now copies s = StringView(UInt8[0x48, 0x69]) arr = Vector{UInt8}(s) @test arr == [0x48, 0x69] @test arr !== codeunits(s) # Constructor copies s = StringView(UInt8[0x78, 0x79, 0x7a]) arr = Array{UInt8}(s) @test arr == [0x78, 0x79, 0x7a] @test arr !== codeunits(s) # Constructor copies # Vector conversion from view-backed StringView b = Vector{UInt8}("foobar") @test Vector{UInt8}(StringView(@view b[1:3])) == b[1:3] s = StringView(b) @test codeunits(String(s)) == s.data abc = StringView(0x61:0x63) @test Vector{UInt8}(abc) == 0x61:0x63 @test Symbol(StringView(UInt8[0x61, 0x62])) === :ab @test Symbol(StringView(b)) == :foobar @test Symbol(abc) == :abc v = UInt8[0xf0, 0x9f, 0x98, 0x80, 0x44] s = StringView(v) @test String(s) == "😀D" @test Symbol(StringView(0x61:0x63)) === :abc end @testset "copy" begin v = UInt8[0x61, 0x62, 0x63] s = StringView(v) s2 = copy(s) @test s2 == s @test s2 !== s @test codeunits(s2) !== codeunits(s) v[1] = 0x78 @test s == "xbc" @test s2 == "abc" # Copy is a StringView c = copy(StringView(Vector{UInt8}("foobar"))) @test c isa StringView @test c == "foobar" end @testset "Mutation tracking" begin # Docstring: "v may be mutated, which will be reflected" v = UInt8[0x61, 0x62, 0x63] s = StringView(v) push!(v, 0x64) @test ncodeunits(s) == 4 @test s == "abcd" end @testset "Basic properties" begin for v in Any[ [0x61, 0x62, 0x63], 0x41:0x48, b"abcdefg", ] s = StringView(v) @test sizeof(s) == sizeof(collect(v)) @test codeunits(s) === v @test ncodeunits(s) == length(v) @test codeunit(s) === UInt8 end s = StringView(UInt8[0xc3, 0xa5, 0x62]) @test sizeof(s) == 3 @test length(s) == 2 @test sizeof(StringView(UInt8[])) == 0 @test ncodeunits(StringView(UInt8[])) == 0 @test length(StringView(UInt8[])) == 0 b = Vector{UInt8}("foobar") s = StringView(b) @test ncodeunits(s) == sizeof(s) == length(b) @test codeunit(s) == UInt8 @test codeunit(s, 3) == b[3] end @testset "Pointers" begin b = Vector{UInt8}("foobar") s = StringView(b) GC.@preserve b s begin @test pointer(s) == pointer(b) == Base.unsafe_convert(Ptr{UInt8}, s) @test Base.unsafe_convert(Ptr{Int8}, s) == Ptr{Int8}(pointer(s)) @test pointer(s, 3) == pointer(b, 3) end # Non-dense arrays don't have pointer method abc = StringView(0x61:0x63) @test_throws MethodError pointer(abc) end @testset "Comparison and equality" begin s1 = StringView(UInt8[0x61, 0x62, 0x63]) s2 = StringView(UInt8[0x61, 0x62, 0x63]) @test s1 == s2 s1 = StringView(UInt8[0x61, 0x62]) @test s1 == "ab" == s1 # test both a == b and b == a @test StringView([0x61, 0x62]) == StringView(b"ab") @test StringView(UInt8[0x61]) != StringView(UInt8[0x62]) s1 = StringView(0x61:0x62) s2 = StringView(UInt8[0x61, 0x62, 0x63]) @test cmp(s1, s2) < 0 @test cmp(s2, s1) > 0 @test s1 != s2 @test cmp(StringView(0x78:0x79), "xy") == 0 @test StringView(UInt8[0xc3, 0xa5]) == "å" @test StringView(0x61:0x63) == "abc" @test StringView(b"test") == "test" b = Vector{UInt8}("foobar") s = StringView(b) @test cmp("foobar", "bar") == cmp(s, "bar") == -cmp("bar", s) == cmp(s, StringView(Vector{UInt8}("bar"))) @test s == StringView(codeunits("foobar")) == "foobar" == s == "foobar" != StringView(Vector{UInt8}("bar")) abc = StringView(0x61:0x63) @test cmp(abc, "bar") == cmp("abc", "bar") end @testset "isascii and isvalid" begin @test isascii(StringView(UInt8[0x61, 0x62, 0x63])) @test !isascii(StringView(UInt8[0xc3, 0xa5])) @test isascii(StringView(UInt8[0x41, 0x42, 0x7f])) @test isascii(StringView(0x41:0x5a)) @test !isascii(StringView(UInt8[0x61, 0xc3, 0xa5])) s = StringView(UInt8[0x61, 0x62, 0x63]) @test isvalid(s, 1) @test isvalid(s, 2) @test !isvalid(s, 0) s = StringView(UInt8[0xc3, 0xa5, 0x62]) @test isvalid(s, 1) @test !isvalid(s, 2) @test isvalid(s, 3) @test isvalid(StringView(0x61:0x63), 2) # Valid indices of invalid UTF8 s = StringView(UInt8[0x8b, 0x52]) @test isvalid(s, 1) @test isvalid(s, 2) @test !isvalid(s, 3) b = Vector{UInt8}("foobar") s = StringView(b) abc = StringView(0x61:0x63) invalid = StringView([0x8b, 0x52, 0x9b, 0x8d]) @test isascii(s) @test !isascii(StringView(codeunits("fööbār"))) @test isvalid(s) @test isvalid(abc) @test !isvalid(invalid) @test !invoke(isvalid, Tuple{StringView}, invalid) end @testset "Indexing" begin s = StringView(UInt8[0x61, 0x62, 0x63]) @test s[1] == 'a' @test s[2] == 'b' @test s[3] == 'c' s = StringView(UInt8[0xc3, 0xa5, 0x62]) @test s[1] == 'å' @test s[3] == 'b' @test_throws StringIndexError s[2] @test_throws BoundsError s[0] @test_throws BoundsError s[4] s = StringView(UInt8[0x61, 0x62, 0x63, 0x64]) @test s[1:2] == StringView(UInt8[0x61, 0x62]) @test s[2:4] == StringView(UInt8[0x62, 0x63, 0x64]) @test typeof(s[1:0]) == typeof(s) @test StringView(UInt8[0x61, 0x62])[1:1] == StringView(UInt8[0x61]) @test StringView(UInt8[0x61, 0x62, 0x63])[2:2] == "b" @test StringView(UInt8[0x61, 0x62, 0x63])[1:0] == StringView(UInt8[]) @test StringView(0x61:0x64)[2:3] == "bc" # Slicing copies and preserves type v = [0x61, 0x62, 0x63] s = StringView(v)[2:3] @test s isa StringView{Vector{UInt8}} @test codeunits(s) !== v @test StringView(0x41:0x44)[2:3] isa StringView{UnitRange{UInt8}} @test_throws StringIndexError StringView(codeunits("fooα"))[1:5] end @testset "Iteration" begin @test collect(StringView(UInt8[0x61, 0x62, 0x63])) == ['a', 'b', 'c'] @test collect(StringView(UInt8[0xc3, 0xa5, 0x62, 0x63])) == ['å', 'b', 'c'] @test collect(StringView(UInt8[])) == [] @test collect(StringView(UInt8[0x9f, 0xf0])) == ['\x9f', '\xf0'] @test collect(StringView(UInt8[0xf0, 0x9f, 0x98, 0x80])) == ['😀'] s = StringView(UInt8[0x61, 0xc3, 0xa5, 0x62]) @test count(Returns(true), s) == 3 @test collect(StringView(0x61:0x63)) == ['a', 'b', 'c'] @test collect(StringView(b"hello")) == collect("hello") b = Vector{UInt8}("foobar") s = StringView(b) ss = SubString(s, 2, 5) # "ooba" abc = StringView(0x61:0x63) invalid = StringView([0x8b, 0x52, 0x9b, 0x8d]) for str in Any[s, ss, abc, invalid] sS = String(str) @test sS == str @test length(sS) == length(str) @test collect(sS) == collect(str) == getindex.(sS, eachindex(sS)) == getindex.(str, eachindex(sS)) @test collect(eachindex(sS)) == collect(eachindex(str)) @test sS[1:end] == str[1:end] @test sS[nextind(sS, 1):prevind(sS, end)] == str[nextind(str, 1):prevind(str, end)] end end @testset "thisind, nextind, prevind" begin # Thisind s = StringView(collect(codeunits("VeÅæy"))) for i in [1, 2, 3, 5, 7] @test thisind(s, i) == i end @test thisind(s, 4) == 3 @test thisind(s, 6) == 5 @test thisind(s, 8) == 8 @test thisind(s, 0) == 0 # Nextind for i in [0, 1, 2, 4, 6, 7] @test nextind(s, i) == i + 1 end @test nextind(s, 3) == 5 @test nextind(s, 5) == 7 # Prevind for i in [1, 2, 3, 4, 6, 8] @test prevind(s, i) == i - 1 end @test prevind(s, 5) == 3 @test prevind(s, 7) == 5 # Make sure it works for non-dense arrays @test nextind(StringView(0x61:0x63), 1) == 2 end @testset "Searching - findnext" begin @test findnext('a', StringView(UInt8[0x61, 0x62, 0x63]), 1) == 1 @test findnext('a', StringView(UInt8[0x61, 0x62, 0x63]), 2) === nothing @test findnext('b', StringView(UInt8[0x61, 0x62, 0x63]), 1) == 2 @test findnext('c', StringView(UInt8[0x61, 0x62, 0x63]), 1) == 3 @test findnext('d', StringView(UInt8[0x61, 0x62, 0x63]), 1) === nothing s = StringView(UInt8[0x61, 0x61, 0x62]) @test findnext('a', s, 1) == 1 @test findnext('a', s, 2) == 2 @test findnext('a', s, 3) === nothing s = StringView(UInt8[0xc3, 0xa5, 0x62, 0xc3, 0xa5]) @test findnext('å', s, 1) == 1 @test findnext('å', s, 3) == 4 @test findnext('b', s, 1) == 3 @test findnext('a', StringView(UInt8[]), 1) === nothing @test findnext('b', StringView(0x61:0x63), 1) == 2 @test findnext('\xc3', StringView(b"æ"), 1) === nothing # Unicode char search @test findfirst(==('ø'), StringView(codeunits("abc"))) === nothing @test findfirst(==('ø'), StringView(codeunits("abæø"))) == 5 end @testset "Searching - findprev" begin @test findprev('c', StringView(UInt8[0x61, 0x62, 0x63]), 3) == 3 @test findprev('b', StringView(UInt8[0x61, 0x62, 0x63]), 3) == 2 @test findprev('a', StringView(UInt8[0x61, 0x62, 0x63]), 3) == 1 @test findprev('d', StringView(UInt8[0x61, 0x62, 0x63]), 3) === nothing s = StringView(UInt8[0x61, 0x62, 0x61]) @test findprev('a', s, 3) == 3 @test findprev('a', s, 2) == 1 @test findprev('a', s, 0) === nothing s = StringView(UInt8[0xc3, 0xa5, 0x62, 0xc3, 0xa5]) @test findprev('å', s, 5) == 4 @test findprev('å', s, 3) == 1 @test findprev('b', s, 5) == 3 @test findprev('b', StringView(0x61:0x63), 3) == 2 @test findlast('\xc3', StringView(b"æ")) === nothing # Unicode char search @test findlast(==('ø'), StringView(codeunits("abc"))) === nothing @test findlast(==('ø'), StringView(codeunits("abæø"))) == 5 end @testset "Searching - findall" begin @test findall('a', StringView(UInt8[0x61, 0x62, 0x61])) == [1, 3] @test findall('a', StringView(UInt8[0x61, 0x61, 0x61])) == [1, 2, 3] @test findall('a', StringView(UInt8[0x62, 0x63, 0x64])) == [] @test findall('å', StringView(UInt8[0xc3, 0xa5, 0x62, 0xc3, 0xa5])) == [1, 4] @test findall('b', StringView(0x61:0x63)) == [2] end @testset "Searching - general" begin b = Vector{UInt8}("foobar") s = StringView(b) ss = SubString(s, 2, 5) # "ooba" abc = StringView(0x61:0x63) for str in Any[s, ss, abc] sS, n = String(str), lastindex(str) @test startswith(str, "foo") == startswith(sS, "foo") @test endswith(str, "bar") == endswith(sS, "bar") @test replace(str, 'o' => "xy") == replace(sS, 'o' => "xy") @test replace(str, ('o', 'a') => 'x') == replace(sS, ('o', 'a') => 'x') @test findnext(==('b'), str, 1) === findnext(==('b'), sS, 1) @test findprev(==('b'), str, n) === findprev(==('b'), sS, n) end end @testset "Regex matching" begin s = StringView(UInt8[0x61, 0x62, 0x63]) m = match(r"abc", s) @test m !== nothing @test m.match == "abc" s = StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f]) m = match(r"l+", s) @test m !== nothing @test m.match == "ll" m = match(r"\d+", StringView(UInt8[0x31, 0x32, 0x33])) @test m !== nothing @test m.match == "123" @test occursin(r"bc", StringView(UInt8[0x61, 0x62, 0x63])) @test !occursin(r"xyz", StringView(UInt8[0x61, 0x62, 0x63])) @test startswith(StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f]), r"he") @test !startswith(StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f]), r"lo") @test endswith(StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f]), r"lo") @test !endswith(StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f]), r"he") s = StringView(UInt8[0x61, 0x62, 0x63, 0x64]) m = match(r"b(c)", s) @test m !== nothing @test m.captures[1] == "c" b = Vector{UInt8}("foobar") s = StringView(b) ss = SubString(s, 2, 5) # "ooba" for str in Any[s, ss] @test [m.match for m in collect(eachmatch(r"[aeiou]+", str))] == ["oo", "a"] @test occursin(r"o+", str) && !occursin(r"z+", str) @test startswith(str, r"o+") == (str[1:2] == "oo") @test startswith(str, r"f+") == (str[1:2] == "fo") @test endswith(str, r"[aeiou]") == (str[end] == 'a') @test endswith(str, r"[q-z]") == (str[end] == 'r') @test findnext(r"o+", str, 4) === nothing end @test findnext(r"[aeiou]+", s, 1) == 2:3 @test findnext(r"[aeiou]+", ss, 1) == 1:2 # findnext(::Regex) returning a match at a non-first position @test findnext(r"bar", StringView(b"foo bar"), 1) == 5:7 @test findnext(r"bar", StringView(b"foo bar"), 5) == 5:7 @test findnext(r"bar", SubString(StringView(b"xxfoo barxx"), 3, 9), 1) == 5:7 sv = StringView(codeunits("foo 1234 bar")) m = match(r"[0-9]+", sv) @test m isa RegexMatch @test m.match == "1234" # Regex match of substring of stringview m = match(r"^([a-z]+)$", SubString(StringView(b"abc"))) @test m !== nothing @test only(m.captures) isa SubString{StringView{typeof(b"abc")}} end @testset "Named subpatterns" begin m = match(r"(?<a>.)(.)(?<b>.)", StringView(codeunits("xyz"))) @test haskey(m, :a) @test haskey(m, 2) @test haskey(m, "b") @test !haskey(m, "foo") @test (m[:a], m[2], m["b"]) == ("x", "y", "z") @test keys(m) == ["a", 2, "b"] end @testset "tryparse_internal with startpos/endpos" begin # tryparse_internal pointer math on StringView and SubString{StringView} sv = StringView(Vector{UInt8}("xx3.14yy")) @test Base.tryparse_internal(Float64, sv, 3, 6) == 3.14 @test Base.tryparse_internal(Float32, sv, 3, 6) == 3.14f0 ssv = SubString(StringView(Vector{UInt8}(" 2.5 ")), 3, 5) @test Base.tryparse_internal(Float64, ssv, 1, 3) == 2.5 end @testset "Parsing floats" begin @test tryparse(Float64, StringView(UInt8[0x31, 0x2e, 0x35])) == 1.5 @test tryparse(Float64, StringView(UInt8[0x2d, 0x33, 0x2e, 0x31, 0x34])) == -3.14 @test tryparse(Float64, StringView(UInt8[0x30, 0x2e, 0x30])) == 0.0 @test tryparse(Float32, StringView(UInt8[0x32, 0x2e, 0x35])) == 2.5f0 @test tryparse(Float64, StringView(UInt8[0x61, 0x62, 0x63])) === nothing s = StringView(UInt8[0x31, 0x65, 0x32]) result = tryparse(Float64, s) @test result !== nothing && result ≈ 100.0 @test tryparse(Float64, StringView(b"3.14")) ≈ 3.14 end @testset "Parsing complex numbers" begin @test tryparse(Complex{Float64}, StringView(UInt8[0x31, 0x2b, 0x32, 0x69, 0x6d])) == 1.0 + 2.0im @test tryparse(Complex{Float64}, StringView(UInt8[0x2d, 0x31, 0x2b, 0x33, 0x69, 0x6d])) == -1.0 + 3.0im @test tryparse(Complex{Float64}, StringView(UInt8[0x32, 0x69, 0x6d])) == 2.0im @test tryparse(Complex{Float64}, StringView(UInt8[0x35])) == 5.0 + 0.0im @test tryparse(Complex{Float64}, StringView(b"2+3im")) == 2.0 + 3.0im end @testset "Parsing integers" begin @test tryparse(Int, StringView(UInt8[0x31, 0x32, 0x33])) == 123 @test tryparse(Int, StringView(UInt8[0x2d, 0x34, 0x35])) == -45 @test tryparse(Int, StringView(UInt8[0x30])) == 0 @test tryparse(Int, StringView(UInt8[0x61, 0x62, 0x63])) === nothing @test tryparse(Int, StringView(UInt8[0x46, 0x46]), base = 16) == 255 @test tryparse(Int, StringView(b"42")) == 42 end @testset "Mixed parsing" begin for val in Any[true, 1234, 1234.5, 1234.5f0, 4.5 + 3.25im] sval = string(val) for str in Any[StringView(codeunits(sval)), SubString("foo" * sval * "bar", 4, 3 + length(sval))] @test parse(typeof(val), str) === val end end end @testset "SubString of StringView" begin s = StringView(UInt8[0x61, 0x62, 0x63, 0x64]) sub = SubString(s, 2, 3) @test sub == "bc" s = StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f]) sub = SubString(s, 1, 2) @test sub == "he" @test typeof(sub) <: SubString @test findnext('b', SubString(StringView(UInt8[0x61, 0x62, 0x63]), 1, 3), 1) == 2 sub = SubString(StringView(0x61:0x64), 2, 3) @test sub == "bc" sub = SubString(StringView(b"hello"), 2, 4) @test sub == "ell" b = Vector{UInt8}("foobar") s = StringView(b) ss = SubString(s, 2, 5) # "ooba" @test Vector{UInt8}(ss) == codeunits(ss) @test codeunits(ss) == b[2:5] @test Symbol(ss) == :ooba @test pointer(ss) == pointer(b) + 1 == Base.unsafe_convert(Ptr{UInt8}, ss) @test ncodeunits(ss) == sizeof(ss) == length(b) - 2 @test codeunit(ss) == UInt8 @test codeunit(ss, 3) == b[4] @test cmp("foobar", "bar") == cmp(ss, "bar") == -cmp("bar", ss) == cmp(ss, StringView(Vector{UInt8}("bar"))) @test ss == StringView(codeunits("ooba")) == "ooba" == ss == "ooba" @test isvalid(ss) end @testset "replace functionality" begin @test replace(StringView(UInt8[0x61, 0x62, 0x63]), "b" => "x") == "axc" @test replace(StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f]), "l" => "L") == "heLLo" @test replace(StringView(UInt8[0x61, 0x61, 0x61]), "a" => "b", count = 2) == "bba" @test replace(StringView(UInt8[0x78, 0x79, 0x7a]), "w" => "v") == "xyz" @test replace(StringView(0x61:0x63), "b" => "x") == "axc" @test replace(StringView(b"test"), "t" => "T") == "TesT" @test replace(StringView(b"abcd"), r"[bc]?" => "^") == "^a^^d^" @test replace(StringView(b"a"), 'a' => typeof) == "Char" @test replace(StringView(b"The foxes."), r"fox(es)?" => s"bus\1") == "The buses." @test replace(StringView(b"foobarbaz"), "oo" => "zz", "ar" => "zz", "z" => "m") == "fzzbzzbam" @test replace(StringView(b"foobar"), 'o' => '0', "" => "") == "f00bar" let v = [0x32, 0x30, 0x32, 0x31, 0x2d, 0x31, 0x31, 0x2d, 0x31, 0x30, 0x20, 0x32, 0x31, 0x3a, 0x34, 0x32, 0x3a, 0x30, 0x35, 0x2e, 0x31, 0x31, 0x35, 0x38, 0x30, 0x37], pat = r"(\.[\d]{3})\d+" => s"\g<1>" @test replace(String(copy(v)), pat) == replace(StringView(v), pat) end end @testset "startswith and endswith" begin @test startswith(StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f]), "he") @test !startswith(StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f]), "lo") @test endswith(StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f]), "lo") @test !endswith(StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f]), "he") s1 = StringView(UInt8[0x61, 0x62, 0x63]) s2 = StringView(UInt8[0x61, 0x62]) @test startswith(s1, s2) s1 = StringView(UInt8[0x78, 0x79, 0x7a]) s2 = StringView(UInt8[0x79, 0x7a]) @test endswith(s1, s2) @test startswith(StringView(0x61:0x63), "ab") @test endswith(StringView(b"hello"), "lo") end @testset "reverse" begin @test reverse(StringView(UInt8[0x61, 0x62, 0x63])) == "cba" @test reverse(StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f])) == "olleh" @test reverse(StringView(UInt8[])) == "" @test reverse(StringView(0x61:0x63)) == "cba" s = "abævø∩\0c" @test reverse(StringView(collect(codeunits(s)))) == reverse(s) @test reverse(StringView(codeunits(s))) isa String # reverse returns same value as String reverse and same type b = Vector{UInt8}("foobar") s = StringView(b) ss = SubString(s, 2, 5) abc = StringView(0x61:0x63) invalid = StringView([0x8b, 0x52, 0x9b, 0x8d]) for str in Any[s, abc, invalid, ss] @test reverse(str) == reverse(String(str)) # Not guaranteed, but let's test it anyway, to reduce breakage @test reverse(str) isa String end end @testset "chomp" begin @test chomp(StringView(UInt8[0x61, 0x62, 0x0a])) == "ab" @test chomp(StringView(UInt8[0x61, 0x62, 0x0d, 0x0a])) == "ab" @test chomp(StringView(UInt8[0x61, 0x62, 0x63])) == "abc" @test chomp(StringView(UInt8[0x0a])) == "" @test chomp(StringView(b"test\n")) == "test" @test chomp(StringView(codeunits("foo\n\n"))) == "foo\n" @test chomp(SubString(StringView(Vector{UInt8}("ab\r\n")))) == "ab" @test chomp(SubString(StringView(Vector{UInt8}("xxab\r\nxx")), 3, 6)) == "ab" end @testset "write and print" begin io = IOBuffer() write(io, StringView(UInt8[0x61, 0x62, 0x63])) @test String(take!(io)) == "abc" io = IOBuffer() print(io, StringView(UInt8[0x68, 0x65, 0x6c, 0x6c, 0x6f])) @test String(take!(io)) == "hello" io = IOBuffer() write(io, StringView(0x61:0x63)) @test String(take!(io)) == "abc" end @testset "typemin and one" begin s = StringView(UInt8[0x61, 0x62]) @test typemin(s) isa StringView{Vector{UInt8}} @test typemin(s) == "" @test one(s) == one(typeof(s)) == typemin(s) == "" @test oneunit(s) == oneunit(typeof(s)) == one(s) == "" b = Vector{UInt8}("foobar") s = StringView(b) @test typemin(s) isa StringView{Vector{UInt8}} @test typemin(s) == "" @test one(s) == one(typeof(s)) == typemin(s) == "" @test oneunit(s) == oneunit(typeof(s)) == one(s) == "" end @testset "hash" begin # Hash matches String hash for various types. # We don't guarantee this, but may as well test it. s1 = StringView(UInt8[0x61, 0x62, 0x63]) s2 = "abc" @test hash(s1) == hash(s2) @test hash(StringView(0x61:0x63)) == hash("abc") b = Vector{UInt8}("foobar") s = StringView(b) ss = SubString(s, 2, 5) abc = StringView(0x61:0x63) invalid = StringView([0x8b, 0x52, 0x9b, 0x8d]) for str in Any[s, abc, invalid, ss] @test hash(str) == hash(String(str)) end end @testset "length with indices" begin sv = StringView(collect(codeunits("αβγ"))) @test length(sv, 1, 6) == 3 @test length(sv, 3, 4) == 1 @test length(sv, 3, 2) == 0 ss = SubString(sv, 1, 3) @test length(ss) == 2 end end # testset "StringViews"