Revision a311f4d8327a5051b11a6bcd1c44ed931d4ab261 authored by Jacob Quinn on 20 October 2022, 02:44:43 UTC, committed by GitHub on 20 October 2022, 02:44:43 UTC
As reported [here](https://discourse.julialang.org/t/test-failures-for-sockets-base-runtests-sockets/88898).

My guess on the original issue reported is that, for some reason, the host where the tests are run
is unable to listen on any ports, so we end up cycling through the entire UInt16 range (the test
starts at port 11011), but when we fail on port 65535, we do `addr.port + 1` and instead of wrapping
around as I believe this function intends to happen (as noted by the `addr.port == default_port` check
before we error), it gets promoted to `Int(65536)` which then throws an (unexpected) error in the `InetAddr`
constructor.

I'm not quite sure how to test this exactly though, because we'd need to simulate not being able
to listen on any ports? If anyone has any ideas, I'm all ears.
1 parent 0d52506
Raw File
dict.jl
# This file is a part of Julia. License is MIT: https://julialang.org/license

using Random

@testset "Pair" begin
    p = Pair(10,20)
    @test p == (10=>20)
    @test isequal(p,10=>20)
    @test iterate(p)[1] == 10
    @test iterate(p, iterate(p)[2])[1] == 20
    @test iterate(p, iterate(p, iterate(p)[2])[2]) == nothing
    @test firstindex(p) == 1
    @test lastindex(p) == length(p) == 2
    @test Base.indexed_iterate(p, 1, nothing) == (10,2)
    @test Base.indexed_iterate(p, 2, nothing) == (20,3)
    @test (1=>2) < (2=>3)
    @test (2=>2) < (2=>3)
    @test !((2=>3) < (2=>3))
    @test (2=>3) < (4=>3)
    @test (1=>100) < (4=>1)
    @test p[1] == 10
    @test p[2] == 20
    @test_throws BoundsError p[3]
    @test_throws BoundsError p[false]
    @test p[true] == 10
    @test p[2.0] == 20
    @test p[0x01] == 10
    @test_throws InexactError p[2.3]
    @test first(p) == 10
    @test last(p) == 20
    @test eltype(p) == Int
    @test eltype(4 => 5.6) == Union{Int,Float64}
    @test vcat(1 => 2.0, 1.0 => 2) == [1.0 => 2.0, 1.0 => 2.0]
end

@testset "Dict" begin
    h = Dict()
    for i=1:10000
        h[i] = i+1
    end
    for i=1:10000
        @test (h[i] == i+1)
    end
    for i=1:2:10000
        delete!(h, i)
    end
    for i=1:2:10000
        h[i] = i+1
    end
    for i=1:10000
        @test (h[i] == i+1)
    end
    for i=1:10000
        delete!(h, i)
    end
    @test isempty(h)
    h[77] = 100
    @test h[77] == 100
    for i=1:10000
        h[i] = i+1
    end
    for i=1:2:10000
        delete!(h, i)
    end
    for i=10001:20000
        h[i] = i+1
    end
    for i=2:2:10000
        @test h[i] == i+1
    end
    for i=10000:20000
        @test h[i] == i+1
    end
    h = Dict{Any,Any}("a" => 3)
    @test h["a"] == 3
    h["a","b"] = 4
    @test h["a","b"] == h[("a","b")] == 4
    h["a","b","c"] = 4
    @test h["a","b","c"] == h[("a","b","c")] == 4

    @testset "eltype, keytype and valtype" begin
        @test eltype(h) == Pair{Any,Any}
        @test keytype(h) == Any
        @test valtype(h) == Any

        td = Dict{AbstractString,Float64}()
        @test eltype(td) == Pair{AbstractString,Float64}
        @test keytype(td) == AbstractString
        @test valtype(td) == Float64
        @test keytype(Dict{AbstractString,Float64}) === AbstractString
        @test valtype(Dict{AbstractString,Float64}) === Float64
    end
    # test rethrow of error in ctor
    @test_throws DomainError Dict((sqrt(p[1]), sqrt(p[2])) for p in zip(-1:2, -1:2))
end

let x = Dict(3=>3, 5=>5, 8=>8, 6=>6)
    pop!(x, 5)
    for k in keys(x)
        Dict{Int,Int}(x)
        @test k in [3, 8, 6]
    end
end

let z = Dict()
    get_KeyError = false
    try
        z["a"]
    catch _e123_
        get_KeyError = isa(_e123_,KeyError)
    end
    @test get_KeyError
end

_d = Dict("a"=>0)
@test isa([k for k in filter(x->length(x)==1, collect(keys(_d)))], Vector{String})

@testset "typeof" begin
    d = Dict(((1, 2), (3, 4)))
    @test d[1] === 2
    @test d[3] === 4
    d2 = Dict(1 => 2, 3 => 4)
    d3 = Dict((1 => 2, 3 => 4))
    @test d == d2 == d3
    @test typeof(d) == typeof(d2) == typeof(d3) == Dict{Int,Int}

    d = Dict(((1, 2), (3, "b")))
    @test d[1] === 2
    @test d[3] == "b"
    d2 = Dict(1 => 2, 3 => "b")
    d3 = Dict((1 => 2, 3 => "b"))
    @test d == d2 == d3
    @test typeof(d) == typeof(d2) == typeof(d3) == Dict{Int,Any}

    d = Dict(((1, 2), ("a", 4)))
    @test d[1] === 2
    @test d["a"] === 4
    d2 = Dict(1 => 2, "a" => 4)
    d3 = Dict((1 => 2, "a" => 4))
    @test d == d2 == d3
    @test typeof(d) == typeof(d2) == typeof(d3) == Dict{Any,Int}

    d = Dict(((1, 2), ("a", "b")))
    @test d[1] === 2
    @test d["a"] == "b"
    d2 = Dict(1 => 2, "a" => "b")
    d3 = Dict((1 => 2, "a" => "b"))
    @test d == d2 == d3
    @test typeof(d) == typeof(d2) == typeof(d3) == Dict{Any,Any}
end

@test_throws ArgumentError first(Dict())
@test first(Dict(:f=>2)) == (:f=>2)

@testset "constructing Dicts from iterators" begin
    d = @inferred Dict(i=>i for i=1:3)
    @test isa(d, Dict{Int,Int})
    @test d == Dict(1=>1, 2=>2, 3=>3)
    d = Dict(i==1 ? (1=>2) : (2.0=>3.0) for i=1:2)
    @test isa(d, Dict{Real,Real})
    @test d == Dict{Real,Real}(2.0=>3.0, 1=>2)

    # issue #39117
    @test Dict(t[1]=>t[2] for t in zip((1,"2"), (2,"2"))) == Dict{Any,Any}(1=>2, "2"=>"2")
end

@testset "empty tuple ctor" begin
    h = Dict(())
    @test length(h) == 0
end

@testset "type of Dict constructed from varargs of Pairs" begin
    @test Dict(1=>1, 2=>2.0) isa Dict{Int,Real}
    @test Dict(1=>1, 2.0=>2) isa Dict{Real,Int}
    @test Dict(1=>1.0, 2.0=>2) isa Dict{Real,Real}

    for T in (Nothing, Missing)
        @test Dict(1=>1, 2=>T()) isa Dict{Int,Union{Int,T}}
        @test Dict(1=>T(), 2=>2) isa Dict{Int,Union{Int,T}}
        @test Dict(1=>1, T()=>2) isa Dict{Union{Int,T},Int}
        @test Dict(T()=>1, 2=>2) isa Dict{Union{Int,T},Int}
    end
end

@test_throws KeyError Dict("a"=>2)[Base.secret_table_token]

@testset "issue #1821" begin
    d = Dict{String, Vector{Int}}()
    d["a"] = [1, 2]
    @test_throws MethodError d["b"] = 1
    @test isa(repr(d), AbstractString)  # check that printable without error
end

@testset "issue #2344" begin
    local bar
    bestkey(d, key) = key
    bestkey(d::AbstractDict{K,V}, key) where {K<:AbstractString,V} = string(key)
    bar(x) = bestkey(x, :y)
    @test bar(Dict(:x => [1,2,5])) === :y
    @test bar(Dict("x" => [1,2,5])) == "y"
end

mutable struct I1438T
    id
end
import Base.hash
hash(x::I1438T, h::UInt) = hash(x.id, h)

@testset "issue #1438" begin
    seq = [26, 28, 29, 30, 31, 32, 33, 34, 35, 36, -32, -35, -34, -28, 37, 38, 39, 40, -30,
           -31, 41, 42, 43, 44, -33, -36, 45, 46, 47, 48, -37, -38, 49, 50, 51, 52, -46, -50, 53]
    xs = [ I1438T(id) for id = 1:53 ]
    s = Set()
    for id in seq
        if id > 0
            x = xs[id]
            push!(s, x)
            @test in(x, s)                 # check that x can be found
        else
            delete!(s, xs[-id])
        end
    end
end

@testset "equality" for eq in (isequal, ==)
    @test  eq(Dict(), Dict())
    @test  eq(Dict(1 => 1), Dict(1 => 1))
    @test !eq(Dict(1 => 1), Dict())
    @test !eq(Dict(1 => 1), Dict(1 => 2))
    @test !eq(Dict(1 => 1), Dict(2 => 1))

    # Generate some data to populate dicts to be compared
    data_in = [ (rand(1:1000), randstring(2)) for _ in 1:1001 ]

    # Populate the first dict
    d1 = Dict{Int, AbstractString}()
    for (k, v) in data_in
        d1[k] = v
    end
    data_in = collect(d1)
    # shuffle the data
    for i in 1:length(data_in)
        j = rand(1:length(data_in))
        data_in[i], data_in[j] = data_in[j], data_in[i]
    end
    # Inserting data in different (shuffled) order should result in
    # equivalent dict.
    d2 = Dict{Int, AbstractString}()
    for (k, v) in data_in
        d2[k] = v
    end

    @test eq(d1, d2)
    d3 = copy(d2)
    d4 = copy(d2)
    # Removing an item gives different dict
    delete!(d1, data_in[rand(1:length(data_in))][1])
    @test !eq(d1, d2)
    # Changing a value gives different dict
    d3[data_in[rand(1:length(data_in))][1]] = randstring(3)
    !eq(d1, d3)
    # Adding a pair gives different dict
    d4[1001] = randstring(3)
    @test !eq(d1, d4)

    @test eq(Dict(), sizehint!(Dict(),96))

    # Dictionaries of different types
    @test !eq(Dict(1 => 2), Dict("dog" => "bone"))
    @test eq(Dict{Int,Int}(), Dict{AbstractString,AbstractString}())
end

@testset "equality special cases" begin
    @test Dict(1=>0.0) == Dict(1=>-0.0)
    @test !isequal(Dict(1=>0.0), Dict(1=>-0.0))

    @test Dict(0.0=>1) != Dict(-0.0=>1)
    @test !isequal(Dict(0.0=>1), Dict(-0.0=>1))

    @test Dict(1=>NaN) != Dict(1=>NaN)
    @test isequal(Dict(1=>NaN), Dict(1=>NaN))

    @test Dict(NaN=>1) == Dict(NaN=>1)
    @test isequal(Dict(NaN=>1), Dict(NaN=>1))

    @test ismissing(Dict(1=>missing) == Dict(1=>missing))
    @test isequal(Dict(1=>missing), Dict(1=>missing))
    d = Dict(1=>missing)
    @test ismissing(d == d)
    d = Dict(1=>[missing])
    @test ismissing(d == d)
    d = Dict(1=>NaN)
    @test d != d
    @test isequal(d, d)

    @test Dict(missing=>1) == Dict(missing=>1)
    @test isequal(Dict(missing=>1), Dict(missing=>1))
end

@testset "get!" begin # (get with default values assigned to the given location)
    f(x) = x^2
    d = Dict(8=>19)
    @test get!(d, 8, 5) == 19
    @test get!(d, 19, 2) == 2

    @test get!(d, 42) do  # d is updated with f(2)
        f(2)
    end == 4

    @test get!(d, 42) do  # d is not updated
        f(200)
    end == 4

    @test get(d, 13) do   # d is not updated
        f(4)
    end == 16

    @test d == Dict(8=>19, 19=>2, 42=>4)
end

@testset "getkey" begin
   h = Dict(1=>2, 3 => 6, 5=>10)
   @test getkey(h, 1, 7) == 1
   @test getkey(h, 4, 6) == 6
   @test getkey(h, "1", 8) == 8
end

@testset "show" begin
    for d in (Dict("\n" => "\n", "1" => "\n", "\n" => "2"),
              Dict(string(i) => i for i = 1:30),
              Dict(reshape(1:i^2,i,i) => reshape(1:i^2,i,i) for i = 1:24),
              Dict(String(Char['α':'α'+i;]) => String(Char['α':'α'+i;]) for i = (1:10)*10),
              Dict("key" => zeros(0, 0)))
        for cols in (12, 40, 80), rows in (2, 10, 24)
            # Ensure output is limited as requested
            s = IOBuffer()
            io = Base.IOContext(s, :limit => true, :displaysize => (rows, cols))
            Base.show(io, MIME("text/plain"), d)
            out = split(String(take!(s)),'\n')
            for line in out[2:end]
                @test textwidth(line) <= cols
            end
            @test length(out) <= rows

            for f in (keys, values)
                s = IOBuffer()
                io = Base.IOContext(s, :limit => true, :displaysize => (rows, cols))
                Base.show(io, MIME("text/plain"), f(d))
                out = split(String(take!(s)),'\n')
                for line in out[2:end]
                    @test textwidth(line) <= cols
                end
                @test length(out) <= rows
            end
        end
        # Simply ensure these do not throw errors
        Base.show(IOBuffer(), d)
        @test !isempty(summary(d))
        @test !isempty(summary(keys(d)))
        @test !isempty(summary(values(d)))
    end
    # show on empty Dict
    io = IOBuffer()
    d = Dict{Int, String}()
    show(io, d)
    str = String(take!(io))
    @test str == "Dict{$(Int), String}()"
    close(io)
end


struct RainbowString
    s::String
    bold::Bool
    other::Bool
    valid::Bool
    offset::Int
end
RainbowString(s, bold=false, other=false, valid=true) = RainbowString(s, bold, other, valid, 0)

function Base.show(io::IO, rbs::RainbowString)
    for (i, s) in enumerate(rbs.s)
        if i ≤ rbs.offset
            print(io, s)
            continue
        end
        color = rbs.other ? string("\033[4", rand(1:7), 'm') : Base.text_colors[rand(0:255)]
        if rbs.bold
            printstyled(io, color, s; bold=true)
        else
            print(io, color, s)
        end
        if rbs.valid
            print(io, '\033', '[', rbs.other ? "0" : "39", 'm')  # end of color marker
        end
    end
end

@testset "Display with colors" begin
    d = Dict([randstring(8) => [RainbowString(randstring(8)) for i in 1:10] for j in 1:5]...)
    str = sprint(io -> show(io, MIME("text/plain"), d); context = (:displaysize=>(30,80), :color=>true, :limit=>true))
    lines = split(str, '\n')
    @test all(endswith("\033[0m…"), lines[2:end])
    @test all(x -> length(x) > 100, lines[2:end])

    d2 = Dict(:foo => RainbowString("bar"))
    str2 = sprint(io -> show(io, MIME("text/plain"), d2); context = (:displaysize=>(30,80), :color=>true, :limit=>true))
    @test !occursin('…', str2)
    @test endswith(str2, "\033[0m")

    d3 = Dict(:foo => RainbowString("bar", true))
    str3 = sprint(io -> show(io, MIME("text/plain"), d3); context = (:displaysize=>(30,80), :color=>true, :limit=>true))
    @test !occursin('…', str3)
    @test endswith(str3, "\033[0m")

    d4 = Dict(RainbowString(randstring(8), true) => nothing)
    str4 = sprint(io -> show(io, MIME("text/plain"), d4); context = (:displaysize=>(30,20), :color=>true, :limit=>true))
    @test endswith(str4, "\033[0m… => nothing")

    d5 = Dict(RainbowString(randstring(30), false, true, false) => nothing)
    str5 = sprint(io -> show(io, MIME("text/plain"), d5); context = (:displaysize=>(30,30), :color=>true, :limit=>true))
    @test endswith(str5, "\033[0m… => nothing")

    d6 = Dict(randstring(8) => RainbowString(randstring(30), true, true, false) for _ in 1:3)
    str6 = sprint(io -> show(io, MIME("text/plain"), d6); context = (:displaysize=>(30,30), :color=>true, :limit=>true))
    lines6 = split(str6, '\n')
    @test all(endswith("\033[0m…"), lines6[2:end])
    @test all(x -> length(x) > 100, lines6[2:end])
    str6_long = sprint(io -> show(io, MIME("text/plain"), d6); context = (:displaysize=>(30,80), :color=>true, :limit=>true))
    lines6_long = split(str6_long, '\n')
    @test all(endswith("\033[0m"), lines6_long[2:end])

    d7 = Dict(randstring(8) => RainbowString(randstring(30)))
    str7 = sprint(io -> show(io, MIME("text/plain"), d7); context = (:displaysize=>(30,20), :color=>true, :limit=>true))
    line7 = split(str7, '\n')[2]
    @test endswith(line7, "\033[0m…")
    @test length(line7) > 100

    d8 = Dict(:x => RainbowString(randstring(10), false, false, false, 6))
    str8 = sprint(io -> show(io, MIME("text/plain"), d8); context = (:displaysize=>(30,14), :color=>true, :limit=>true))
    line8 = split(str8, '\n')[2]
    @test !occursin("\033[", line8)
    @test length(line8) == 14
    str8_long = sprint(io -> show(io, MIME("text/plain"), d8); context = (:displaysize=>(30,16), :color=>true, :limit=>true))
    line8_long = split(str8_long, '\n')[2]
    @test endswith(line8_long, "\033[0m…")
    @test length(line8_long) > 20

    d9 = Dict(:x => RainbowString(repeat('苹', 5), false, true, false))
    str9 = sprint(io -> show(io, MIME("text/plain"), d9); context = (:displaysize=>(30,15), :color=>true, :limit=>true))
    @test endswith(str9, "\033[0m…")
    @test count('苹', str9) == 3

    d10 = Dict(:xy => RainbowString(repeat('苹', 5), false, true, false))
    str10 = sprint(io -> show(io, MIME("text/plain"), d10); context = (:displaysize=>(30,15), :color=>true, :limit=>true))
    @test endswith(str10, "\033[0m…")
    @test count('苹', str10) == 2

    d11 = Dict(RainbowString("abcdefgh", false, true, false) => 0, "123456" => 1)
    str11 = sprint(io -> show(io, MIME("text/plain"), d11); context = (:displaysize=>(30,80), :color=>true, :limit=>true))
    _, line11_a, line11_b = split(str11, '\n')
    @test endswith(line11_a, "h\033[0m => 0") || endswith(line11_b, "h\033[0m => 0")
    @test endswith(line11_a, "6\" => 1") || endswith(line11_b, "6\" => 1")

    d12 = Dict(RainbowString(repeat(Char(48+i), 4), (i&1)==1, (i&2)==2, (i&4)==4) => i for i in 1:8)
    str12 = sprint(io -> show(io, MIME("text/plain"), d12); context = (:displaysize=>(30,80), :color=>true, :limit=>true))
    @test !occursin('…', str12)

    d13 = Dict(RainbowString("foo\nbar") => 74)
    str13 = sprint(io -> show(io, MIME("text/plain"), d13); context = (:displaysize=>(30,80), :color=>true, :limit=>true))
    @test count('\n', str13) == 1
    @test occursin('…', str13)
end

@testset "Issue #15739" begin # Compact REPL printouts of an `AbstractDict` use brackets when appropriate
    d = Dict((1=>2) => (3=>45), (3=>10) => (10=>11))
    buf = IOBuffer()
    show(IOContext(buf, :compact => true), d)

    # Check explicitly for the expected strings, since the CPU bitness effects
    # dictionary ordering.
    result = String(take!(buf))
    @test occursin("Dict", result)
    @test occursin("(1=>2)=>(3=>45)", result)
    @test occursin("(3=>10)=>(10=>11)", result)
end

mutable struct Alpha end
Base.show(io::IO, ::Alpha) = print(io,"α")
@testset "issue #9463" begin
    sbuff = IOBuffer()
    io = Base.IOContext(sbuff, :limit => true, :displaysize => (10, 20))

    Base.show(io, MIME("text/plain"), Dict(Alpha()=>1))
    local str = String(take!(sbuff))
    @test !occursin("…", str)
    @test endswith(str, "α => 1")
end

@testset "issue #2540" begin
    d = Dict{Any,Any}(Dict(x => 1 for x in ['a', 'b', 'c']))
    @test d == Dict('a'=>1, 'b'=>1, 'c'=> 1)
end

@testset "issue #2629" begin
    d = Dict{AbstractString,AbstractString}(Dict(a=>"foo" for a in ["a","b","c"]))
    @test d == Dict("a"=>"foo","b"=>"foo","c"=>"foo")
end

@testset "issue #5886" begin
    d5886 = Dict()
    for k5886 in 1:11
       d5886[k5886] = 1
    end
    for k5886 in keys(d5886)
       # undefined ref if not fixed
       d5886[k5886] += 1
    end
end

@testset "issue #8877" begin
    a = Dict("foo" => 0.0, "bar" => 42.0)
    b = Dict("フー" => 17, "バー" => 4711)
    @test typeof(merge(a, b)) === Dict{String,Float64}
end

@testset "issue 9295" begin
    d = Dict()
    @test push!(d, 'a' => 1) === d
    @test d['a'] == 1
    @test push!(d, 'b' => 2, 'c' => 3) === d
    @test d['b'] == 2
    @test d['c'] == 3
    @test push!(d, 'd' => 4, 'e' => 5, 'f' => 6) === d
    @test d['d'] == 4
    @test d['e'] == 5
    @test d['f'] == 6
    @test length(d) == 6
end

mutable struct T10647{T}; x::T; end
@testset "issue #10647" begin
    a = IdDict()
    a[1] = a
    a[a] = 2
    a[3] = T10647(a)
    @test isequal(a, a)
    show(IOBuffer(), a)
    Base.show(Base.IOContext(IOBuffer(), :limit => true), a)
    Base.show(IOBuffer(), a)
    Base.show(Base.IOContext(IOBuffer(), :limit => true), a)
end

@testset "IdDict{Any,Any} and partial inference" begin
    a = IdDict{Any,Any}()
    a[1] = a
    a[a] = 2

    sa = empty(a)
    @test isempty(sa)
    @test isa(sa, IdDict{Any,Any})

    @test length(a) == 2
    @test 1 in keys(a)
    @test a in keys(a)
    @test a[1] === a
    @test a[a] === 2

    ca = copy(a)
    @test length(ca) == length(a)
    @test isequal(ca, a)
    @test ca !== a # make sure they are different objects

    ca = empty!(ca)
    @test length(ca) == 0
    @test length(a) == 2

    d = Dict('a'=>1, 'b'=>1, 'c'=> 3)
    @test a != d
    @test !isequal(a, d)

    @test length(IdDict{Any,Any}(1=>2, 1.0=>3)) == 2
    @test length(Dict(1=>2, 1.0=>3)) == 1

    d = @inferred IdDict{Any,Any}(i=>i for i=1:3)
    @test isa(d, IdDict{Any,Any})
    @test d == IdDict{Any,Any}(1=>1, 2=>2, 3=>3)

    d = @inferred IdDict{Any,Any}(Pair(1,1), Pair(2,2), Pair(3,3))
    @test isa(d, IdDict{Any,Any})
    @test d == IdDict{Any,Any}(1=>1, 2=>2, 3=>3)
    @test eltype(d) == Pair{Any,Any}

    d = IdDict{Any,Int32}(:hi => 7)
    let c = Ref{Any}(1.5)
        f() = c[]
        @test @inferred(get!(f, d, :hi)) === Int32(7)
        @test_throws InexactError(:Int32, Int32, 1.5) get!(f, d, :hello)
    end
end

@testset "IdDict" begin
    a = IdDict()
    a[1] = a
    a[a] = 2

    sa = empty(a)
    @test isempty(sa)
    @test isa(sa, IdDict)

    @test length(a) == 2
    @test 1 in keys(a)
    @test a in keys(a)
    @test a[1] === a
    @test a[a] === 2

    ca = copy(a)
    @test length(ca) == length(a)
    @test isequal(ca, a)
    @test ca !== a # make sure they are different objects

    ca = empty!(ca)
    @test length(ca) == 0
    @test length(a) == 2

    d = Dict('a'=>1, 'b'=>1, 'c'=> 3)
    @test a != d
    @test !isequal(a, d)

    @test length(IdDict(1=>2, 1.0=>3)) == 2
    @test length(Dict(1=>2, 1.0=>3)) == 1

    d = @inferred IdDict(i=>i for i=1:3)
    @test isa(d, IdDict)
    @test d == IdDict(1=>1, 2=>2, 3=>3)

    d = @inferred IdDict(Pair(1,1), Pair(2,2), Pair(3,3))
    @test isa(d, IdDict)
    @test d == IdDict(1=>1, 2=>2, 3=>3)
    @test eltype(d) == Pair{Int,Int}
    @test_throws KeyError d[:a]
    @test_throws ArgumentError d[:a] = 1
    @test_throws MethodError d[1] = :a

    # copy constructor
    d = IdDict(Pair(1,1), Pair(2,2), Pair(3,3))
    @test collect(values(IdDict{Int,Float64}(d))) == collect(values(d))
    @test_throws ArgumentError IdDict{Float64,Int}(d)

    # misc constructors
    @test typeof(IdDict(1=>1, :a=>2)) == IdDict{Any,Int}
    @test typeof(IdDict(1=>1, 1=>:a)) == IdDict{Int,Any}
    @test typeof(IdDict(:a=>1, 1=>:a)) == IdDict{Any,Any}
    @test typeof(IdDict(())) == IdDict{Any,Any}

    # check that returned values are inferred
    d = @inferred IdDict(Pair(1,1), Pair(2,2), Pair(3,3))
    @test 1 == @inferred d[1]
    @inferred setindex!(d, -1, 10)
    @test d[10] == -1
    @test 1 == @inferred d[1]
    @test get(d, -111, nothing) == nothing
    @test 1 == @inferred get(d, 1, 1)
    @test pop!(d, -111, nothing) == nothing
    @test 1 == @inferred pop!(d, 1)

    # get! and delete!
    d = @inferred IdDict(Pair(:a,1), Pair(:b,2), Pair(3,3))
    @test get!(d, "a", -1) == -1
    @test d["a"] == -1
    @test get!(d, "a", "b") == -1
    @test_throws MethodError get!(d, "b", "b")
    @test delete!(d, "a") === d
    @test !haskey(d, "a")
    @test_throws ArgumentError get!(IdDict{Symbol,Any}(), 2, "b")
    @test get!(IdDict{Int,Int}(), 1, 2.0) === 2
    @test get!(()->2.0, IdDict{Int,Int}(), 1) === 2

    # sizehint! & rehash!
    d = IdDict()
    @test sizehint!(d, 10^4) === d
    @test length(d.ht) >= 10^4
    d = IdDict()
    for jj=1:30, i=1:10^4
        d[i] = i
    end
    for i=1:10^4
        @test d[i] == i
    end
    @test length(d.ht) >= 10^4
    @test d === Base.rehash!(d, 123452) # number needs to be even

    # filter!
    d = IdDict(1=>1, 2=>3, 3=>2)
    filter!(x->isodd(x[2]), d)
    @test d[1] == 1
    @test d[2] == 3
    @test !haskey(d, 3)

    # not an iterator of tuples or pairs
    @test_throws ArgumentError IdDict([1, 2, 3, 4])
    # test rethrow of error in ctor
    @test_throws DomainError   IdDict((sqrt(p[1]), sqrt(p[2])) for p in zip(-1:2, -1:2))
end

@testset "issue 30165, get! for IdDict" begin
    f(x) = x^2
    d = IdDict(8=>19)
    @test get!(d, 8, 5) == 19
    @test get!(d, 19, 2) == 2

    @test get!(d, 42) do  # d is updated with f(2)
        f(2)
    end == 4

    @test get!(d, 42) do  # d is not updated
        f(200)
    end == 4

    @test get(d, 13) do   # d is not updated
        f(4)
    end == 16

    @test d == IdDict(8=>19, 19=>2, 42=>4)
end

@testset "issue #26833, deletion from IdDict" begin
    d = IdDict()
    i = 1
    # generate many hash collisions
    while length(d) < 32 # expected to occur at i <≈ 2^16 * 2^5
        if objectid(i) % UInt16 == 0x1111
            push!(d, i => true)
        end
        i += 1
    end
    k = collect(keys(d))
    @test haskey(d, k[1])
    delete!(d, k[1])
    @test length(d) == 31
    @test !haskey(d, k[1])
    @test haskey(d, k[end])
    push!(d, k[end] => false)
    @test length(d) == 31
    @test haskey(d, k[end])
    @test !pop!(d, k[end])
    @test !haskey(d, k[end])
    @test length(d) == 30
end


@testset "Issue #7944" begin
    d = Dict{Int,Int}()
    get!(d, 0) do
        d[0] = 1
    end
    @test length(d) == 1
end

@testset "iteration" begin
    d = Dict('a'=>1, 'b'=>1, 'c'=> 3)
    @test [d[k] for k in keys(d)] == [d[k] for k in eachindex(d)] ==
          [v for (k, v) in d] == [d[x[1]] for (i, x) in enumerate(d)]
end

@testset "generators, similar" begin
    d = Dict(:a=>"a")
    # TODO: restore when 0.7 deprecation is removed
    #@test @inferred(map(identity, d)) == d
end

@testset "Issue 12451" begin
    @test_throws ArgumentError Dict(0)
    @test_throws ArgumentError Dict([1])
    @test_throws ArgumentError Dict([(1,2),0])
end

# test Dict constructor's argument checking (for an iterable of pairs or tuples)
# make sure other errors can propagate when the nature of the iterator is not the problem
@test_throws InexactError Dict(convert(Int,1.5) for i=1:1)
@test_throws InexactError WeakKeyDict(convert(Int,1.5) for i=1:1)

import Base.ImmutableDict
@testset "ImmutableDict" begin
    d = ImmutableDict{String, String}()
    k1 = "key1"
    k2 = "key2"
    v1 = "value1"
    v2 = "value2"
    d1 = ImmutableDict(d, k1 => v1)
    d2 = ImmutableDict(d1, k2 => v2)
    d3 = ImmutableDict(d2, k1 => v2)
    d4 = ImmutableDict(d3, k2 => v1)
    dnan = ImmutableDict{String, Float64}(k2, NaN)
    dnum = ImmutableDict(dnan, k2 => 1)
    f(x) = x^2

    @test isempty(collect(d))
    @test !isempty(collect(d1))
    @test isempty(d)
    @test !isempty(d1)
    @test length(d) == 0
    @test length(d1) == 1
    @test length(d2) == 2
    @test length(d3) == 3
    @test length(d4) == 4
    @test !(k1 in keys(d))
    @test k1 in keys(d1)
    @test k1 in keys(d2)
    @test k1 in keys(d3)
    @test k1 in keys(d4)

    @test !haskey(d, k1)
    @test haskey(d1, k1)
    @test haskey(d2, k1)
    @test haskey(d3, k1)
    @test haskey(d4, k1)
    @test !(k2 in keys(d1))
    @test k2 in keys(d2)
    @test !(k1 in values(d4))
    @test v1 in values(d4)
    @test collect(d1) == [Pair(k1, v1)]
    @test collect(d4) == reverse([Pair(k1, v1), Pair(k2, v2), Pair(k1, v2), Pair(k2, v1)])
    @test d1 == ImmutableDict(d, k1 => v1)
    @test !((k1 => v2) in d2)
    @test (k1 => v2) in d3
    @test (k1 => v1) in d4
    @test (k1 => v2) in d4
    @test in(k2 => "value2", d4, ===)
    @test in(k2 => v2, d4, ===)
    @test in(k2 => NaN, dnan, isequal)
    @test in(k2 => NaN, dnan, ===)
    @test !in(k2 => NaN, dnan, ==)
    @test !in(k2 => 1, dnum, ===)
    @test in(k2 => 1.0, dnum, ===)
    @test !in(k2 => 1, dnum, <)
    @test in(k2 => 0, dnum, <)
    @test get(d1, "key1", :default) === v1
    @test get(d4, "key1", :default) === v2
    @test get(d4, "foo", :default) === :default
    @test get(d, k1, :default) === :default
    @test get(d1, "key1") do
        f(2)
    end === v1
    @test get(d4, "key1") do
        f(4)
    end === v2
    @test get(d4, "foo") do
        f(6)
    end === 36
    @test get(d, k1) do
        f(8)
    end === 64
    @test d1["key1"] === v1
    @test d4["key1"] === v2
    @test empty(d3) === d
    @test empty(d) === d

    @test_throws KeyError d[k1]
    @test_throws KeyError d1["key2"]

    v = [k1 => v1, k2 => v2]
    d5 = ImmutableDict(v...)
    @test d5 == d2
    @test reverse(collect(d5)) == v
    d6 = ImmutableDict(:a => 1, :b => 3, :a => 2)
    @test d6[:a] == 2
    @test d6[:b] == 3

    @test !haskey(ImmutableDict(-0.0=>1), 0.0)
end

@testset "filtering" begin
    d = Dict(zip(1:1000,1:1000))
    f = p -> iseven(p.first)
    @test filter(f, d) == filter!(f, copy(d)) ==
          invoke(filter!, Tuple{Function,AbstractDict}, f, copy(d)) ==
          Dict(zip(2:2:1000, 2:2:1000))
    d = Dict(zip(-1:3,-1:3))
    f = p -> sqrt(p.second) > 2
    # test rethrowing error from f
    @test_throws DomainError filter(f, d)
end

struct MyString <: AbstractString
    str::String
end
struct MyInt <: Integer
    val::UInt
end

import Base.==
const global hashoffset = [UInt(190)]

Base.hash(s::MyString) = hash(s.str) + hashoffset[]
Base.lastindex(s::MyString) = lastindex(s.str)
Base.iterate(s::MyString, v::Int=1) = iterate(s.str, v)
Base.isequal(a::MyString, b::MyString) = isequal(a.str, b.str)
==(a::MyString, b::MyString) = (a.str == b.str)

Base.hash(v::MyInt) = v.val + hashoffset[]
Base.lastindex(v::MyInt) = lastindex(v.val)
Base.iterate(v::MyInt, i...) = iterate(v.val, i...)
Base.isequal(a::MyInt, b::MyInt) = isequal(a.val, b.val)
==(a::MyInt, b::MyInt) = (a.val == b.val)
@testset "issue #15077" begin
    let badKeys = [
        "FINO_emv5.0","FINO_ema0.1","RATE_ema1.0","NIBPM_ema1.0",
        "SAO2_emv5.0","O2FLOW_ema5.0","preop_Neuro/Psych_","gender_",
        "FIO2_ema0.1","PEAK_ema5.0","preop_Reproductive_denies","O2FLOW_ema0.1",
        "preop_Endocrine_denies","preop_Respiratory_",
        "NIBPM_ema0.1","PROPOFOL_MCG/KG/MIN_decay5.0","NIBPD_ema1.0","NIBPS_ema5.0",
        "anesthesiaStartTime","NIBPS_ema1.0","RESPRATE_ema1.0","PEAK_ema0.1",
        "preop_GU_denies","preop_Cardiovascular_","PIP_ema5.0","preop_ENT_denies",
        "preop_Skin_denies","preop_Renal_denies","asaCode_IIIE","N2OFLOW_emv5.0",
        "NIBPD_emv5.0", # <--- here is the key that we later can't find
        "NIBPM_ema5.0","preop_Respiratory_complete","ETCO2_ema5.0",
        "RESPRATE_ema0.1","preop_Functional Status_<2","preop_Renal_symptoms",
        "ECGRATE_ema5.0","FIO2_emv5.0","RESPRATE_emv5.0","7wu3ty0a4fs","BVO",
        "4UrCWXUsaT"
    ]
        local d = Dict{AbstractString,Int}()
        for i = 1:length(badKeys)
            d[badKeys[i]] = i
        end
        # Check all keys for missing values
        for i = 1:length(badKeys)
            @test d[badKeys[i]] == i
        end

        # Walk through all possible hash values (mod size of hash table)
        for offset = 0:1023
            local d2 = Dict{MyString,Int}()
            hashoffset[] = offset
            for i = 1:length(badKeys)
                d2[MyString(badKeys[i])] = i
            end
            # Check all keys for missing values
            for i = 1:length(badKeys)
                @test d2[MyString(badKeys[i])] == i
            end
        end
    end


    let badKeys = UInt16[0xb800,0xa501,0xcdff,0x6303,0xe40a,0xcf0e,0xf3df,0xae99,0x9913,0x741c,
                         0xd01f,0xc822,0x9723,0xb7a0,0xea25,0x7423,0x6029,0x202a,0x822b,0x492c,
                         0xd02c,0x862d,0x8f34,0xe529,0xf938,0x4f39,0xd03a,0x473b,0x1e3b,0x1d3a,
                         0xcc39,0x7339,0xcf40,0x8740,0x813d,0xe640,0xc443,0x6344,0x3744,0x2c3d,
                         0x8c48,0xdf49,0x5743]
        # Walk through all possible hash values (mod size of hash table)
        for offset = 0:1023
            local d2 = Dict{MyInt, Int}()
            hashoffset[] = offset
            for i = 1:length(badKeys)
                d2[MyInt(badKeys[i])] = i
            end
            # Check all keys for missing values
            for i = 1:length(badKeys)
                @test d2[MyInt(badKeys[i])] == i
            end
        end
    end
end

# #18213
Dict(1 => rand(2,3), 'c' => "asdf") # just make sure this does not trigger a deprecation

@testset "WeakKeyDict" begin
    A = [1]
    B = [2]
    C = [3]

    # construction
    wkd = WeakKeyDict()
    wkd[A] = 2
    wkd[B] = 3
    wkd[C] = 4
    dd = convert(Dict{Any,Any},wkd)
    @test WeakKeyDict(dd) == wkd
    @test convert(WeakKeyDict{Any, Any}, dd) == wkd
    @test isa(WeakKeyDict(dd), WeakKeyDict{Any,Any})
    @test WeakKeyDict(A=>2, B=>3, C=>4) == wkd
    @test isa(WeakKeyDict(A=>2, B=>3, C=>4), WeakKeyDict{Array{Int,1},Int})
    @test WeakKeyDict(a=>i+1 for (i,a) in enumerate([A,B,C]) ) == wkd
    @test WeakKeyDict([(A,2), (B,3), (C,4)]) == wkd
    @test WeakKeyDict{typeof(A), Int64}(Pair(A,2), Pair(B,3), Pair(C,4)) == wkd
    @test WeakKeyDict(Pair(A,2), Pair(B,3), Pair(C,4)) == wkd
    D = [[4.0]]
    @test WeakKeyDict(Pair(A,2), Pair(B,3), Pair(D,4.0)) isa WeakKeyDict{Any, Any}
    @test isa(WeakKeyDict(Pair(A,2), Pair(B,3.0), Pair(C,4)), WeakKeyDict{Array{Int,1},Any})
    @test isa(WeakKeyDict(Pair(convert(Vector{Number}, A),2), Pair(B,3), Pair(C,4)), WeakKeyDict{Any,Int})
    @test copy(wkd) == wkd

    @test length(wkd) == 3
    @test !isempty(wkd)
    res = pop!(wkd, C)
    @test res == 4
    @test length(wkd) == 2
    res = pop!(wkd, C, 3)
    @test res == 3
    @test C ∉ keys(wkd)
    @test 4 ∉ values(wkd)
    @test length(wkd) == 2
    @test !isempty(wkd)
    wkd = filter!( p -> p.first != B, wkd)
    @test B ∉ keys(wkd)
    @test 3 ∉ values(wkd)
    @test length(wkd) == 1
    @test WeakKeyDict(Pair(A, 2)) == wkd
    @test !isempty(wkd)

    wkd = empty!(wkd)
    @test wkd == empty(wkd)
    @test typeof(wkd) == typeof(empty(wkd))
    @test length(wkd) == 0
    @test isempty(wkd)
    @test isa(wkd, WeakKeyDict)

    @test_throws ArgumentError WeakKeyDict([1, 2, 3])

    wkd = WeakKeyDict(A=>1)
    @test delete!(wkd, A) == empty(wkd)
    @test delete!(wkd, A) === wkd

    # issue #26939
    d26939 = WeakKeyDict()
    (@noinline d -> d[big"1.0" + 1.1] = 1)(d26939)
    GC.gc() # primarily to make sure this doesn't segfault
    @test count(d26939) == 0
    @test length(d26939.ht) == 1
    @test length(d26939) == 0
    @test isempty(d26939)
    empty!(d26939)
    for i in 1:8
        (@noinline (d, i) -> d[big(i + 12345)] = 1)(d26939, i)
    end
    lock(GC.gc, d26939)
    @test length(d26939.ht) == 8
    @test count(d26939) == 0
    @test !haskey(d26939, nothing)
    @test_throws KeyError(nothing) d26939[nothing]
    @test_throws KeyError(nothing) get(d26939, nothing, 1)
    @test_throws KeyError(nothing) get(() -> 1, d26939, nothing)
    @test_throws KeyError(nothing) pop!(d26939, nothing)
    @test getkey(d26939, nothing, 321) === 321
    @test pop!(d26939, nothing, 321) === 321
    @test delete!(d26939, nothing) === d26939
    @test length(d26939.ht) == 8
    @test_throws ArgumentError d26939[nothing] = 1
    @test_throws ArgumentError get!(d26939, nothing, 1)
    @test_throws ArgumentError get!(() -> 1, d26939, nothing)
    @test isempty(d26939)
    @test length(d26939.ht) == 0
    @test length(d26939) == 0

    # WeakKeyDict does not convert keys on setting
    @test_throws ArgumentError WeakKeyDict{Vector{Int},Any}([5.0]=>1)
    wkd = WeakKeyDict(A=>2)
    @test_throws ArgumentError get!(wkd, [2.0], 2)
    @test get!(wkd, [1.0], 2) === 2

    # WeakKeyDict does convert on getting
    wkd = WeakKeyDict(A=>2)
    @test keytype(wkd)==Vector{Int}
    @test wkd[[1.0]] == 2
    @test haskey(wkd, [1.0])
    @test pop!(wkd, [1.0]) == 2
    @test get(()->3, wkd, [2.0]) == 3

    # map! on values of WKD
    wkd = WeakKeyDict(A=>2, B=>3)
    map!(v -> v-1, values(wkd))
    @test wkd == WeakKeyDict(A=>1, B=>2)

    # get!
    wkd = WeakKeyDict(A=>2)
    @test get!(wkd, B, 3) == 3
    @test wkd == WeakKeyDict(A=>2, B=>3)
    @test get!(()->4, wkd, C) == 4
    @test wkd == WeakKeyDict(A=>2, B=>3, C=>4)
    @test get!(()->5, wkd, [1.0]) == 2

    GC.@preserve A B C D nothing
end

@testset "issue #19995, hash of dicts" begin
    @test hash(Dict(Dict(1=>2) => 3, Dict(4=>5) => 6)) != hash(Dict(Dict(4=>5) => 3, Dict(1=>2) => 6))
    a = Dict(Dict(3 => 4, 2 => 3) => 2, Dict(1 => 2, 5 => 6) => 1)
    b = Dict(Dict(1 => 2, 2 => 3, 5 => 6) => 1, Dict(3 => 4) => 2)
    @test hash(a) != hash(b)
end

mutable struct Foo_15776
    x::Vector{Pair{Tuple{Function, Vararg{Int}}, Int}}
end
@testset "issue #15776, convert for pair" begin
    z = [Pair((+,1,5,7), 3), Pair((-,6,5,3,5,8), 1)]
    f = Foo_15776(z)
    @test f.x[1].first == (+, 1, 5, 7)
    @test f.x[1].second == 3
    @test f.x[2].first == (-, 6, 5, 3, 5, 8)
    @test f.x[2].second == 1
end

@testset "issue #18708 error type for dict constructor" begin
    @test_throws UndefVarError Dict(x => y for x in 1:10)
end

mutable struct Error19179 <: Exception
end

@testset "issue #19179 throwing error in dict constructor" begin
    @test_throws Error19179 Dict(i => throw(Error19179()) for i in 1:10)
end

# issue #18090
let
    d = Dict(i => i^2 for i in 1:10_000)
    z = zip(keys(d), values(d))
    for (pair, tupl) in zip(d, z)
        @test pair[1] == tupl[1] && pair[2] == tupl[2]
    end
end

struct NonFunctionCallable end
(::NonFunctionCallable)(args...) = +(args...)

@testset "Dict merge" begin
    d1 = Dict("A" => 1, "B" => 2)
    d2 = Dict("B" => 3.0, "C" => 4.0)
    @test @inferred merge(d1, d2) == Dict("A" => 1, "B" => 3, "C" => 4)
    # merge with combiner function
    @test @inferred mergewith(+, d1, d2) == Dict("A" => 1, "B" => 5, "C" => 4)
    @test @inferred mergewith(*, d1, d2) == Dict("A" => 1, "B" => 6, "C" => 4)
    @test @inferred mergewith(-, d1, d2) == Dict("A" => 1, "B" => -1, "C" => 4)
    @test @inferred mergewith(NonFunctionCallable(), d1, d2) == Dict("A" => 1, "B" => 5, "C" => 4)
    @test foldl(mergewith(+), [d1, d2]; init=Dict{Union{},Union{}}()) ==
        Dict("A" => 1, "B" => 5, "C" => 4)
    # backward compatibility
    @test @inferred merge(+, d1, d2) == Dict("A" => 1, "B" => 5, "C" => 4)
end

@testset "Dict merge!" begin
    d1 = Dict("A" => 1, "B" => 2)
    d2 = Dict("B" => 3, "C" => 4)
    @inferred merge!(d1, d2)
    @test d1 == Dict("A" => 1, "B" => 3, "C" => 4)
    # merge! with combiner function
    @inferred mergewith!(+, d1, d2)
    @test d1 == Dict("A" => 1, "B" => 6, "C" => 8)
    @inferred mergewith!(*, d1, d2)
    @test d1 == Dict("A" => 1, "B" => 18, "C" => 32)
    @inferred mergewith!(-, d1, d2)
    @test d1 == Dict("A" => 1, "B" => 15, "C" => 28)
    @inferred mergewith!(NonFunctionCallable(), d1, d2)
    @test d1 == Dict("A" => 1, "B" => 18, "C" => 32)
    @test foldl(mergewith!(+), [d1, d2]; init=empty(d1)) ==
        Dict("A" => 1, "B" => 21, "C" => 36)
    # backward compatibility
    merge!(+, d1, d2)
    @test d1 == Dict("A" => 1, "B" => 21, "C" => 36)
end

@testset "Dict reduce merge" begin
    function check_merge(i::Vector{<:Dict}, o)
        r1 = reduce(merge, i)
        r2 = merge(i...)
        t = typeof(o)
        @test r1 == o
        @test r2 == o
        @test typeof(r1) == t
        @test typeof(r2) == t
    end
    check_merge([Dict(1=>2), Dict(1.0=>2.0)], Dict(1.0=>2.0))
    check_merge([Dict(1=>2), Dict(2=>Complex(1.0, 1.0))],
      Dict(2=>Complex(1.0, 1.0), 1=>Complex(2.0, 0.0)))
    check_merge([Dict(1=>2), Dict(3=>4)], Dict(3=>4, 1=>2))
    check_merge([Dict(3=>4), Dict(:a=>5)], Dict(:a => 5, 3 => 4))
end

@testset "AbstractDict mergewith!" begin
# we use IdDict to test the mergewith! implementation for AbstractDict
    d1 = IdDict(1 => 1, 2 => 2)
    d2 = IdDict(2 => 3, 3 => 4)
    d3 = IdDict{Int, Float64}(1 => 5, 3 => 6)
    d = copy(d1)
    @inferred mergewith!(-, d, d2)
    @test d == IdDict(1 => 1, 2 => -1, 3 => 4)
    d = copy(d1)
    @inferred mergewith!(-, d, d3)
    @test d == IdDict(1 => -4, 2 => 2, 3 => 6)
    d = copy(d1)
    @inferred mergewith!(+, d, d2, d3)
    @test d == IdDict(1 => 6, 2 => 5, 3 => 10)
    @inferred mergewith(+, d1, d2, d3)
    d = mergewith(+, d1, d2, d3)
    @test d isa Dict{Int, Float64}
    @test d == Dict(1 => 6, 2 => 5, 3 => 10)
end

@testset "misc error/io" begin
    d = Dict('a'=>1, 'b'=>1, 'c'=> 3)
    @test_throws ErrorException 'a' in d
    key_str = sprint(show, keys(d))
    @test 'a' ∈ key_str
    @test 'b' ∈ key_str
    @test 'c' ∈ key_str
end

@testset "Dict pop!" begin
    d = Dict(1=>2, 3=>4)
    @test pop!(d, 1) == 2
    @test_throws KeyError pop!(d, 1)
    @test pop!(d, 1, 0) == 0
    @test pop!(d) == (3=>4)
    @test_throws ArgumentError pop!(d)
end

@testset "keys as a set" begin
    d = Dict(1=>2, 3=>4)
    @test keys(d) isa AbstractSet
    @test empty(keys(d)) isa AbstractSet
    let i = keys(d) ∩ Set([1,2])
        @test i isa AbstractSet
        @test i == Set([1])
    end
    @test Set(string(k) for k in keys(d)) == Set(["1","3"])
end

@testset "find" begin
    @test findall(isequal(1), Dict(:a=>1, :b=>2)) == [:a]
    @test sort(findall(isequal(1), Dict(:a=>1, :b=>1))) == [:a, :b]
    @test isempty(findall(isequal(1), Dict()))
    @test isempty(findall(isequal(1), Dict(:a=>2, :b=>3)))

    @test findfirst(isequal(1), Dict(:a=>1, :b=>2)) === :a
    @test findfirst(isequal(1), Dict(:a=>1, :b=>1, :c=>3)) in (:a, :b)
    @test findfirst(isequal(1), Dict()) === nothing
    @test findfirst(isequal(1), Dict(:a=>2, :b=>3)) === nothing
end

@testset "Dict printing with limited rows" begin
    local buf
    buf = IOBuffer()
    io = IOContext(buf, :displaysize => (4, 80), :limit => true)
    d = Base.ImmutableDict(1=>2)
    show(io, MIME"text/plain"(), d)
    @test String(take!(buf)) == "Base.ImmutableDict{$Int, $Int} with 1 entry: …"
    show(io, MIME"text/plain"(), keys(d))
    @test String(take!(buf)) ==
        "KeySet for a Base.ImmutableDict{$Int, $Int} with 1 entry. Keys: …"

    io = IOContext(io, :displaysize => (5, 80))
    show(io, MIME"text/plain"(), d)
    @test String(take!(buf)) == "Base.ImmutableDict{$Int, $Int} with 1 entry:\n  1 => 2"
    show(io, MIME"text/plain"(), keys(d))
    @test String(take!(buf)) ==
        "KeySet for a Base.ImmutableDict{$Int, $Int} with 1 entry. Keys:\n  1"
    d = Base.ImmutableDict(d, 3=>4)
    show(io, MIME"text/plain"(), d)
    @test String(take!(buf)) == "Base.ImmutableDict{$Int, $Int} with 2 entries:\n  ⋮ => ⋮"
    show(io, MIME"text/plain"(), keys(d))
    @test String(take!(buf)) ==
        "KeySet for a Base.ImmutableDict{$Int, $Int} with 2 entries. Keys:\n  ⋮"

    io = IOContext(io, :displaysize => (6, 80))
    show(io, MIME"text/plain"(), d)
    @test String(take!(buf)) ==
        "Base.ImmutableDict{$Int, $Int} with 2 entries:\n  3 => 4\n  1 => 2"
    show(io, MIME"text/plain"(), keys(d))
    @test String(take!(buf)) ==
        "KeySet for a Base.ImmutableDict{$Int, $Int} with 2 entries. Keys:\n  3\n  1"
    d = Base.ImmutableDict(d, 5=>6)
    show(io, MIME"text/plain"(), d)
    @test String(take!(buf)) ==
        "Base.ImmutableDict{$Int, $Int} with 3 entries:\n  5 => 6\n  ⋮ => ⋮"
    show(io, MIME"text/plain"(), keys(d))
    @test String(take!(buf)) ==
        "KeySet for a Base.ImmutableDict{$Int, $Int} with 3 entries. Keys:\n  5\n  ⋮"
end

@testset "copy!" begin
    s = Dict(1=>2, 2=>3)
    for a = ([3=>4], [0x3=>0x4], [3=>4, 5=>6, 7=>8], Pair{UInt,UInt}[3=>4, 5=>6, 7=>8])
        @test s === copy!(s, Dict(a)) == Dict(a)
        if length(a) == 1 # current limitation of Base.ImmutableDict
            @test s === copy!(s, Base.ImmutableDict(a[])) == Dict(a[])
        end
    end
    s2 = copy(s)
    @test copy!(s, s) == s2
end

@testset "map!(f, values(dict))" begin
    @testset "AbstractDict & Fallback" begin
        mutable struct TestDict{K, V}  <: AbstractDict{K, V}
            dict::Dict{K, V}
            function TestDict(args...)
                d = Dict(args...)
                new{keytype(d), valtype(d)}(d)
            end
        end
        Base.setindex!(td::TestDict, args...) = setindex!(td.dict, args...)
        Base.getindex(td::TestDict, args...) = getindex(td.dict, args...)
        Base.pairs(D::TestDict) = pairs(D.dict)
        testdict = TestDict(:a=>1, :b=>2)
        map!(v->v-1, values(testdict))
        @test testdict[:a] == 0
        @test testdict[:b] == 1
        @test sizehint!(testdict, 1) === testdict
    end
    @testset "Dict" begin
        testdict = Dict(:a=>1, :b=>2)
        map!(v->v-1, values(testdict))
        @test testdict[:a] == 0
        @test testdict[:b] == 1
    end
end

# WeakKeyDict soundness (#38727)
mutable struct ComparesWithGC38727
    i::Int
end
const armed = Ref{Bool}(true)
@noinline fwdab38727(a, b) = invoke(Base.isequal, Tuple{Any, WeakRef}, a, b)
function Base.isequal(a::ComparesWithGC38727, b::WeakRef)
    # This GC.gc() here simulates a GC during compilation in the original issue
    armed[] && GC.gc()
    armed[] = false
    fwdab38727(a, b)
end
Base.isequal(a::WeakRef, b::ComparesWithGC38727) = isequal(b, a)
Base.:(==)(a::ComparesWithGC38727, b::ComparesWithGC38727) = a.i == b.i
Base.hash(a::ComparesWithGC38727, u::UInt) = Base.hash(a.i, u)
function make_cwgc38727(wkd, i)
    f = ComparesWithGC38727(i)
    function fin(f)
        f.i = -1
    end
    finalizer(fin, f)
    f
end
@noinline mk38727(wkd) = wkd[make_cwgc38727(wkd, 1)] = nothing
function bar()
    wkd = WeakKeyDict{Any, Nothing}()
    mk38727(wkd)
    armed[] = true
    z = getkey(wkd, ComparesWithGC38727(1), missing)
end
# Run this twice, in case compilation the first time around
# masks something.
let c = bar()
    @test c === missing || c == ComparesWithGC38727(1)
end
let c = bar()
    @test c === missing || c == ComparesWithGC38727(1)
end

@testset "shrinking" begin
    d = Dict(i => i for i = 1:1000)
    filter!(x -> x.first < 10, d)
    sizehint!(d, 10)
    @test length(d.slots) < 100
end
back to top