text:
using Cryptography
using Test

tests =
[
  "Hashers/md5_hasher",
  "Padders/ansix923_padder",
  "Padders/pkcs7_padder",
  "Ciphers/null_block_cipher",
  "Ciphers/des_cipher",
  "Ciphers/triple_des_cipher",
  "Ciphers/blowfish_cipher",
  "Ciphers/rc4_cipher",
  "Ciphers/cbc_mode_cipher"
]

for t in tests
  try
    include("$(t).jl")
  catch e
  end
end


text:
using GaussianProcesses: Mean, Kernel, GPE

GPE(rd::RegionData, args...) = GPE(rd.x, rd.y, args...)

function MultiGPCovars(rdict::Dict{KEY,RegionData}, groupKeys::AbstractVector{KEY}, spkern::Kernel, βkern::Kernel, logNoise::Real, mean::Mean=MeanZero()) where {KEY}
    Dlist = Matrix{Float64}[]
    gpList = GPE[]
    for key in groupKeys
        rd = rdict[key]
        D = rd.D
        y = rd.y
        gp = GPE(rd.x, rd.y, mean, spkern, logNoise)
        push!(gpList, gp)
        push!(Dlist, D)
    end
    return MultiGPCovars(Dlist, gpList, groupKeys, βkern)
end
function MultiGPCovars(rdict::Dict{KEY,RegionData}, spkern::Kernel, args...) where {KEY}
    groupKeys = collect(keys(rdict))
    return MultiGPCovars(rdict, groupKeys, spkern, args...)
end

function GPRealisations(rdict::Dict{KEY,RegionData}, groupKeys::AbstractVector{KEY}, spkern::Kernel, logNoise::Real, mean::Mean=MeanZero()) where {KEY}
    gpList = GPE[]
    for key in groupKeys
        rd = rdict[key]
        y = rd.y
        gp = GPE(rd.x, rd.y, mean, spkern, logNoise)
        push!(gpList, gp)
    end
    return GPRealisations(gpList, groupKeys)
end

function GPRealisations(rdict::Dict{KEY,RegionData}, spkern::Kernel, args...) where {KEY}
    groupKeys = collect(keys(rdict))
    return GPRealisations(rdict, groupKeys, spkern, args...)
end

ext: jl


text:
### A symmetric tridiagonal matrix that supports appending onto the bottom
### right corner of the matrix and keeping track of eigenvalues of the matrix.
### * Support dynamic LU decomposition in real time, without pivoting.
### * Fast characteristic polynomial computations for shifted system of this
###   matrix.

mutable struct DynamicSymTridiagonal{T<:AbstractFloat}
    # Parameters groupd 1
    alphas::Vector{T}       # Diaognal
    betas::Vector{T}        # Lower & upper Diaognal
    L::Vector{T}            # The lower diagonal of the unit-bidiagonal matrix L
    U::Vector{T}            # Lower diagonal of the upper bi-diagonal matrix U
    k::Int64                # Size of the matrix.

    # Parameters group 2
    last_update::Int64          # last iteration where eigenvalues are updated for this matrix.
    thetas::Vector{T}           # Ritz values.
    converged::Vector{Bool}     # Indicates convergence for matching index ritz value from last iteration.
    converged_this_step::Vector{T}
    velocity::Vector{T}
    velocity_tol::Float64

    function DynamicSymTridiagonal{T}(
        alpha::T;
        velocity_tol::S=1e-10
    ) where {T<:AbstractFloat, S<:AbstractFloat}
        this = new{T}()
        this.alphas = Vector{T}()
        push!(this.alphas, alpha)
        this.betas = Vector{T}()
        this.L = Vector{T}()
        this.U = Vector{T}()
        push!(this.U, alpha)
        this.k = 1
        this.last_update = 1
        this.thetas = Vector{T}(); push!(this.thetas, alpha)
        this.converged = Vector{T}(); push!(this.converged, false)
        this.velocity = Vector{T}();push!(this.velocity, Inf)
        this.velocity_tol = velocity_tol # <- Default value.
        this.converged_this_step = Vector{T}()

    return this end

    function DynamicSymTridiagonal(alpha::Number)
        return DynamicSymTridiagonal{Float64}(convert(Float64, alpha))
    end
end

"""
    Opverting the opertor (alpha,beta) to append new element to the matrix.
    append an alpha and a beta (diagonal and sub & super diagonal) elemnt to
    the current sym diagonal matrix.
"""
function (this::DynamicSymTridiagonal{T})(alpha::T, beta::T) where {T<:AbstractFloat}
    push!(this.alphas, alpha)
    push!(this.betas, beta)
    push!(this.U, alpha - beta^2/this.U[end])
    push!(this.L, beta/this.U[end - 1])
    this.k += 1
return this end

"""
    Evaluate for an instance of the symmetric tridiagonal symmetric matrix for
    a given shift value of x, which evalutes: det(A - xI) for the instance matrix.

    * It will return Nan if the polynomial exploded.
"""
function CharPolyShifted(this::DynamicSymTridiagonal{T}, x::Number=0.0) where {T<:AbstractFloat}
    pPrevious = 1
    pNow = this.alphas[1] - x
    for j in 2:this.k
        pNew = (this.alphas[j] - x)*pNow - (this.betas[j - 1]^2)*pPrevious
        pPrevious = pNow
        pNow = pNew
    end
return pNow end

"""
    Evalute the derivetive of the characteristic polynoial for a shifted quantity x.
    det(T - xI)
"""
function CharacteristicPolyDerivative(
    this::DynamicSymTridiagonal{T},
    x::Number
) where {T<:AbstractFloat}
    error("I haven't implement it yet. ")
return end

"""
    Locate the eigenvalue given only the left bound on the eigenvalue.
    * Eigenvalue CANNOT be on the boundary that passed in, they might cause
    sign problem violating the bisection pre-conditions.
"""
function EigenValueLocate(
    this::DynamicSymTridiagonal{T},
    left_bound::T,
    right_bound::T
) where {T<:AbstractFloat}
    @assert !(isnan(left_bound) || isnan(right_bound)) "Any of the bound for "*
    "the eigenvalue for dynamic tridiagonal symmetric matrix cannot be nan. "
    @assert !(isinf(left_bound) && isinf(right_bound)) "Both left and "*
    "right_bound cannot be inf. "
    @assert left_bound < right_bound "The left boundary should be less than the"*
    "right boundary, this is by the definition of interval. "

    # perform search when one of the bound is infinity.
    P(x) = CharPolyShifted(this, x)
    if isinf(left_bound) || isinf(right_bound)
        stepSize = isinf(left_bound) ? -1e-8 : 1e-8
        if stepSize > 0
            while sign(P(left_bound + stepSize)) == sign(P(left_bound))
                    stepSize += 2*stepSize
            end
        else
            while sign(P(right_bound + stepSize)) == sign(P(right_bound))
                stepSize += 2*stepSize
            end
        end
        if isinf(left_bound)
            left_bound = right_bound + stepSize
        else
            right_bound = left_bound + stepSize
        end
    end

    # test preconditions for bisection
    pL = P(left_bound); pR = P(right_bound)
    @assert sign(pL) != sign(pR) "Bisection search error;"*
    "the left and right bondary turns out to have the same sign, please check the "*
    "caller routine which is responsible. the left and right bounds are"*
    ": $(left_bound), $(right_bound), function values is: $(pL), $(pR); "*
    "please consider adjusing the velocity tolerance."
    @assert !isnan(pL) && !isnan(pR) "Polynomial exploded with Nan on one of "*
    "the boundaries OR both boundaries after expontneial probing "*
    "(or without the probing). Please refine search interval. "

    # perform bisection search to locate a root.
    midX = (left_bound + right_bound)/2
    midP = P(midX)
    itrLimit = 100
    while midP != 0 &&
        itrLimit > 0 &&
        right_bound != midX &&
        left_bound != midX

        if sign(midP) == sign(P(left_bound))
            left_bound = midX
        else
            right_bound = midX
        end
        itrLimit -= 1
        midX = (left_bound + right_bound)/2
        if right_bound - left_bound < this.velocity_tol
            break
        end
        midP = P(midX)
        # println("Bisection: [$left_bound, $right_bound]")
    end

return midX end

"""
    Update the eigenvalues based on all the eigenvalues
    from the previous sub-matrix.
        * If current eigenvalues are not from the previous iterations, this
        will give an error, it can only compute eigenvalues for this iteration
        based on the eigenvalues from the previous iterations.
"""
function EigenvaluesUpdate(this::DynamicSymTridiagonal{T}) where {T <: AbstractFloat}
    if this.k == 1  # current matrix is 1 x 1.
        EstablishEigenSystem(this)
        this.last_update = this.k
        return
    end

    if this.k == this.last_update  # eigen system already updated.
        return
    elseif this.k - this.last_update == 1
        # update the eigensystem using the interlace properties and search routine.
        if all(this.converged)
            # method will re-establish eigen system.
            EstablishEigenSystem(this)
            return
        end
        v = this.thetas
        c = this.converged
        k = length(v) + 1
        δ = 0
        push!(v, convert(T, Inf64))
        pushfirst!(v, convert(T, -Inf64))
        newThetas = Array{T}(undef, k)
        newConverged = Array{Bool}(undef, k)
        Δ = Array{T}(undef, k)
        empty!(this.converged_this_step)
        for II in 1: k
            if II < min(ceil(k/2), floor(k/2) + 1)
                if c[II]
                    newThetas[II] = v[II + 1]
                    newConverged[II] = true
                else
                    newThetas[II] = EigenValueLocate(this, v[II] + δ, v[II + 1] - δ)
                    newConverged[II] = abs(newThetas[II] - v[II + 1]) <= this.velocity_tol
                    if II != 1 && II != k
                        newConverged[II] = newConverged[II] && c[II - 1]
                    end
                    if newConverged[II]
                        push!(this.converged_this_step, newThetas[II])
                    end
                end
            elseif II > max(ceil(k/2), floor(k/2) + 1)
                if c[II - 1]
                    newThetas[II] = v[II]
                    newConverged[II] = true
                else
                    newThetas[II] = EigenValueLocate(this, v[II] + δ, v[II + 1] - δ)
                    newConverged[II] = abs(newThetas[II] - v[II]) <= this.velocity_tol
                    if II != 1 && II != k
                        newConverged[II] = newConverged[II] && c[II]
                    end
                    if newConverged[II]
                        push!(this.converged_this_step, newThetas[II])
                    end
                end
            else
                newThetas[II] = EigenValueLocate(this, v[II] + δ, v[II + 1] - δ)
                newConverged[II] = false
            end

        end
        # Velocity update
        for II in 1:k
            if II < min(ceil(k/2), floor(k/2) + 1)
                Δ[II] = newThetas[II] - v[II + 1]
            elseif II > max(ceil(k/2), floor(k/2) + 1)
                Δ[II] = newThetas[II] - v[II]
            else
                Δ[II] = Inf
            end
        end

        this.thetas = newThetas
        this.converged = newConverged
        this.velocity = Δ
        this.last_update = this.k
        return
    else
        # Maybeshould consdier re-establishing the system.
        # error("Must updated after each iterations, or else we lost track of the eigenvalues. ")
        EstablishEigenSystem(this)
    end

return end

"""
    Function establish the eigensystem of the current Tridiagonal Matrix using Lapack
    Routine, and erase all running parameters about the eigensystem.

    * Compute all the eigenvalues of the tridiagonal system and mark all as
    convernged.
"""
function EstablishEigenSystem(this::DynamicSymTridiagonal{T}) where {T<:AbstractFloat}
    TMatrix = GetT(this)
    eigenvalues = eigvals(TMatrix)
    sort!(eigenvalues)
    this.thetas = eigenValues
    this.betas = fill(true, length(eigenValues))
return end

"""
    Get the L matrix for this instance.
"""
function GetL(this::DynamicSymTridiagonal)
    return Bidiagonal(fill(1, this.k), convert(Vector{Float64}, this.L), :L)
end

"""
    Get the U matrix for this instance.
"""
function GetU(this::DynamicSymTridiagonal)
    return Bidiagonal(convert(Vector{Float64}, this.U), this.betas, :U)
end

"""
    Get the Tridiagonal Matrix
"""
function GetT(this::DynamicSymTridiagonal)
    return SymTridiagonal(this.alphas, this.betas)
end

function CountConverged(this::DynamicSymTridiagonal)
    return convert(Vector{Int64}, this.converged) |> sum
end

function GetConverged(this::DynamicSymTridiagonal) return this.thetas[this.converged] end

function ChangeVelocityTol!(
    this::DynamicSymTridiagonal,
    velocity_tol::T
) where {T<:AbstractFloat}
    this.velocity_tol = velocity_tol
end


text:
using Gridap
using Gridap.Io
using GridapGmsh

model = GmshDiscreteModel("model.msh")

writevtk(model,"model")

fn = "model.json"
to_json_file(model,fn)


text:
# This file is a part of Julia. License is MIT: https://julialang.org/license

using Test, Distributed, Random, Serialization, Sockets
import Distributed: launch, manage

@test cluster_cookie() isa String

include(joinpath(Sys.BINDIR, "..", "share", "julia", "test", "testenv.jl"))

@test Distributed.extract_imports(:(begin; import Foo, Bar; let; using Baz; end; end)) ==
      Any[:(import Foo, Bar), :(using Baz)]

# Test a few "remote" invocations when no workers are present
@test remote(myid)() == 1
@test pmap(identity, 1:100) == [1:100...]
@test 100 == @distributed (+) for i in 1:100
        1
    end

addprocs_with_testenv(4)
@test nprocs() == 5

# distributed loading of packages

# setup
@everywhere begin
    old_act_proj = Base.ACTIVE_PROJECT[]
    pushfirst!(Base.LOAD_PATH, "@")
    Base.ACTIVE_PROJECT[] = joinpath(Sys.BINDIR, "..", "share", "julia", "test", "TestPkg")
end

# cause precompilation of TestPkg to avoid race condition
Base.compilecache(Base.identify_package("TestPkg"))

@everywhere using TestPkg
@everywhere using TestPkg

@everywhere begin
    Base.ACTIVE_PROJECT[] = old_act_proj
    popfirst!(Base.LOAD_PATH)
end

@everywhere using Test, Random, LinearAlgebra

id_me = myid()
id_other = filter(x -> x != id_me, procs())[rand(1:(nprocs()-1))]

# Test role
@everywhere using Distributed
@test Distributed.myrole() === :master
for wid = workers()
    wrole = remotecall_fetch(wid) do
        Distributed.myrole()
    end
    @test wrole === :worker
end

# Test remote()
let
    pool = default_worker_pool()

    count = 0
    count_condition = Condition()

    function remote_wait(c)
        @async begin
            count += 1
            remote(take!)(c)
            count -= 1
            notify(count_condition)
        end
        yield()
    end

    testchannels = [RemoteChannel() for i in 1:nworkers()]
    testcount = 0
    @test isready(pool) == true
    for c in testchannels
        @test count == testcount
        remote_wait(c)
        testcount += 1
    end
    @test count == testcount
    @test isready(pool) == false

    for c in testchannels
        @test count == testcount
        put!(c, "foo")
        testcount -= 1
        wait(count_condition)
        @test count == testcount
        @test isready(pool) == true
    end

    @test count == 0

    for c in testchannels
        @test count == testcount
        remote_wait(c)
        testcount += 1
    end
    @test count == testcount
    @test isready(pool) == false

    for c in reverse(testchannels)
        @test count == testcount
        put!(c, "foo")
        testcount -= 1
        wait(count_condition)
        @test count == testcount
        @test isready(pool) == true
    end

    @test count == 0
end

# Test Futures
function testf(id)
    f=Future(id)
    @test isready(f) == false
    @test f.v === nothing
    put!(f, :OK)
    @test isready(f) == true
    @test f.v !== nothing

    @test_throws ErrorException put!(f, :OK) # Cannot put! to a already set future
    @test_throws MethodError take!(f) # take! is unsupported on a Future

    @test fetch(f) == :OK
end

testf(id_me)
testf(id_other)

# Distributed GC tests for Futures
function test_futures_dgc(id)
    f = remotecall(myid, id)
    fid = remoteref_id(f)

    # remote value should be deleted after a fetch
    @test remotecall_fetch(k->(yield();haskey(Distributed.PGRP.refs, k)), id, fid) == true
    @test f.v === nothing
    @test fetch(f) == id
    @test f.v !== nothing
    yield(); # flush gc msgs
    @test remotecall_fetch(k->(yield();haskey(Distributed.PGRP.refs, k)), id, fid) == false

    # if unfetched, it should be deleted after a finalize
    f = remotecall(myid, id)
    fid = remoteref_id(f)
    @test remotecall_fetch(k->(yield();haskey(Distributed.PGRP.refs, k)), id, fid) == true
    @test f.v === nothing
    finalize(f)
    yield(); # flush gc msgs
    @test remotecall_fetch(k->(yield();haskey(Distributed.PGRP.refs, k)), id, fid) == false
end

test_futures_dgc(id_me)
test_futures_dgc(id_other)

# if sent to another worker, it should not be deleted till all references are fetched.
wid1 = workers()[1]
wid2 = workers()[2]
f = remotecall(myid, wid1)
fid = remoteref_id(f)

fstore = RemoteChannel(wid2)
put!(fstore, f)

@test fetch(f) == wid1
@test remotecall_fetch(k->haskey(Distributed.PGRP.refs, k), wid1, fid) == true
remotecall_fetch(r->(fetch(fetch(r)); yield()), wid2, fstore)
sleep(0.5) # to ensure that wid2 gc messages have been executed on wid1
@test remotecall_fetch(k->haskey(Distributed.PGRP.refs, k), wid1, fid) == false

# put! should release remote reference since it would have been cached locally
f = Future(wid1)
fid = remoteref_id(f)

# should not be created remotely till accessed
@test remotecall_fetch(k->haskey(Distributed.PGRP.refs, k), wid1, fid) == false
# create it remotely
isready(f)

@test remotecall_fetch(k->haskey(Distributed.PGRP.refs, k), wid1, fid) == true
put!(f, :OK)
@test remotecall_fetch(k->haskey(Distributed.PGRP.refs, k), wid1, fid) == false
@test fetch(f) == :OK

# RemoteException should be thrown on a put! when another process has set the value
f = Future(wid1)
fid = remoteref_id(f)

fstore = RemoteChannel(wid2)
put!(fstore, f) # send f to wid2
put!(f, :OK) # set value from master

@test remotecall_fetch(k->haskey(Distributed.PGRP.refs, k), wid1, fid) == true

testval = remotecall_fetch(wid2, fstore) do x
    try
        put!(fetch(x), :OK)
        return 0
    catch e
        if isa(e, RemoteException)
            return 1
        else
            return 2
        end
    end
end
@test testval == 1

# Issue number #25847
@everywhere function f25847(ref)
    fetch(ref)
    return true
end

f = remotecall_wait(identity, id_other, ones(10))
rrid = Distributed.RRID(f.whence, f.id)
remotecall_fetch(f25847, id_other, f)
@test BitSet([id_me]) == remotecall_fetch(()->Distributed.PGRP.refs[rrid].clientset, id_other)

remotecall_fetch(f25847, id_other, f)
@test BitSet([id_me]) == remotecall_fetch(()->Distributed.PGRP.refs[rrid].clientset, id_other)

finalize(f)
yield() # flush gc msgs
@test false == remotecall_fetch(chk_rrid->(yield(); haskey(Distributed.PGRP.refs, chk_rrid)), id_other, rrid)

# Distributed GC tests for RemoteChannels
function test_remoteref_dgc(id)
    rr = RemoteChannel(id)
    put!(rr, :OK)
    rrid = remoteref_id(rr)

    # remote value should be deleted after finalizing the ref
    @test remotecall_fetch(k->(yield();haskey(Distributed.PGRP.refs, k)), id, rrid) == true
    @test fetch(rr) == :OK
    @test remotecall_fetch(k->(yield();haskey(Distributed.PGRP.refs, k)), id, rrid) == true
    finalize(rr)
    yield(); # flush gc msgs
    @test remotecall_fetch(k->(yield();haskey(Distributed.PGRP.refs, k)), id, rrid) == false
end
test_remoteref_dgc(id_me)
test_remoteref_dgc(id_other)

# if sent to another worker, it should not be deleted till the other worker has also finalized.
let wid1 = workers()[1],
    wid2 = workers()[2],
    rr = RemoteChannel(wid1),
    rrid = remoteref_id(rr),
    fstore = RemoteChannel(wid2)

    put!(fstore, rr)
    @test remotecall_fetch(k -> haskey(Distributed.PGRP.refs, k), wid1, rrid) == true
    finalize(rr) # finalize locally
    yield() # flush gc msgs
    @test remotecall_fetch(k -> haskey(Distributed.PGRP.refs, k), wid1, rrid) == true
    remotecall_fetch(r -> (finalize(take!(r)); yield(); nothing), wid2, fstore) # finalize remotely
    sleep(0.5) # to ensure that wid2 messages have been executed on wid1
    @test remotecall_fetch(k -> haskey(Distributed.PGRP.refs, k), wid1, rrid) == false
end

# Tests for issue #23109 - should not hang.
f = @spawnat :any rand(1, 1)
@sync begin
    for _ in 1:10
        @async fetch(f)
    end
end

wid1, wid2 = workers()[1:2]
f = @spawnat wid1 rand(1,1)
@sync begin
    @async fetch(f)
    @async remotecall_fetch(()->fetch(f), wid2)
end

@test fetch(@spawnat id_other myid()) == id_other
@test (@fetchfrom id_other myid()) == id_other

pids=[]
for i in 1:nworkers()
    push!(pids, @fetch myid())
end
@test sort(pids) == sort(workers())

# test getindex on Futures and RemoteChannels
function test_indexing(rr)
    a = rand(5,5)
    put!(rr, a)
    @test rr[2,3] == a[2,3]
    @test rr[] == a
end

test_indexing(Future())
test_indexing(Future(id_other))
test_indexing(RemoteChannel())
test_indexing(RemoteChannel(id_other))

# Test ser/deser to non-ClusterSerializer objects.
function test_regular_io_ser(ref::Distributed.AbstractRemoteRef)
    io = IOBuffer()
    serialize(io, ref)
    seekstart(io)
    ref2 = deserialize(io)
    for fld in fieldnames(typeof(ref))
        v = getfield(ref2, fld)
        if isa(v, Number)
            @test v === zero(typeof(v))
        elseif v !== nothing
            error(string("Add test for field ", fld))
        end
    end
end

test_regular_io_ser(Future())
test_regular_io_ser(RemoteChannel())

# Test @distributed load balancing - all processors should get either M or M+1
# iterations out of the loop range for some M.
ids = @distributed((a,b)->[a;b], for i=1:7; myid(); end)
workloads = Int[sum(ids .== i) for i in 2:nprocs()]
@test maximum(workloads) - minimum(workloads) <= 1

# @distributed reduction should work even with very short ranges
@test @distributed(+, for i=1:2; i; end) == 3

@test_throws ArgumentError sleep(-1)
@test_throws ArgumentError timedwait(()->false, 0.1, pollint=-0.5)

# specify pids for pmap
@test sort(workers()[1:2]) == sort(unique(pmap(x->(sleep(0.1);myid()), WorkerPool(workers()[1:2]), 1:10)))

# Testing buffered  and unbuffered reads
# This large array should write directly to the socket
a = fill(1, 10^6)
@test a == remotecall_fetch((x)->x, id_other, a)

# Not a bitstype, should be buffered
s = [randstring() for x in 1:10^5]
@test s == remotecall_fetch((x)->x, id_other, s)

#large number of small requests
num_small_requests = 10000
@test fill(id_other, num_small_requests) == [remotecall_fetch(myid, id_other) for i in 1:num_small_requests]

# test parallel sends of large arrays from multiple tasks to the same remote worker
ntasks = 10
rr_list = [Channel(1) for x in 1:ntasks]

for rr in rr_list
    local rr
    let rr = rr
        @async try
            for i in 1:10
                a = rand(2*10^5)
                @test a == remotecall_fetch(x->x, id_other, a)
                yield()
            end
            put!(rr, :OK)
        catch
            put!(rr, :ERROR)
        end
    end
end

@test [fetch(rr) for rr in rr_list] == [:OK for x in 1:ntasks]

function test_channel(c)
    @test isopen(c) == true
    put!(c, 1)
    put!(c, "Hello")
    put!(c, 5.0)

    @test isready(c) == true
    @test isopen(c) == true
    @test fetch(c) == 1
    @test fetch(c) == 1   # Should not have been popped previously
    @test take!(c) == 1
    @test take!(c) == "Hello"
    @test fetch(c) == 5.0
    @test take!(c) == 5.0
    @test isready(c) == false
    @test isopen(c) == true
    close(c)
    @test isopen(c) == false
end

test_channel(Channel(10))
test_channel(RemoteChannel(()->Channel(10)))

c=Channel{Int}(1)
@test_throws MethodError put!(c, "Hello")

# test channel iterations
function test_iteration(in_c, out_c)
    t=@async for v in in_c
        put!(out_c, v)
    end

    @test isopen(in_c) == true
    put!(in_c, 1)
    @test take!(out_c) == 1
    put!(in_c, "Hello")
    close(in_c)
    @test take!(out_c) == "Hello"
    @test isopen(in_c) == false
    @test_throws InvalidStateException put!(in_c, :foo)
    yield()
    @test istaskdone(t) == true
end

test_iteration(Channel(10), Channel(10))
# make sure exceptions propagate when waiting on Tasks
@test_throws CompositeException (@sync (@async error("oops")))
try
    @sync begin
        for i in 1:5
            @async error(i)
        end
    end
    error("unexpected")
catch ex
    @test typeof(ex) == CompositeException
    @test length(ex) == 5
    @test typeof(ex.exceptions[1]) == TaskFailedException
    @test typeof(ex.exceptions[1].task.exception) == ErrorException
    # test start, next, and done
    for (i, i_ex) in enumerate(ex)
        @test i == parse(Int, i_ex.task.exception.msg)
    end
    # test showerror
    err_str = sprint(showerror, ex)
    err_one_str = sprint(showerror, ex.exceptions[1])
    @test err_str == err_one_str * "\n\n...and 4 more exceptions.\n"
end
@test sprint(showerror, CompositeException()) == "CompositeException()\n"

function test_remoteexception_thrown(expr)
    try
        expr()
        error("unexpected")
    catch ex
        @test typeof(ex) == RemoteException
        @test typeof(ex.captured) == CapturedException
        @test typeof(ex.captured.ex) == ErrorException
        @test ex.captured.ex.msg == "foobar"
    end
end

for id in [id_other, id_me]
    local id
    test_remoteexception_thrown() do
        remotecall_fetch(id) do
            throw(ErrorException("foobar"))
        end
    end
    test_remoteexception_thrown() do
        remotecall_wait(id) do
            throw(ErrorException("foobar"))
        end
    end
    test_remoteexception_thrown() do
        wait(remotecall(id) do
            throw(ErrorException("foobar"))
        end)
    end
end

# make sure the stackframe from the remote error can be serialized
let ex
    try
        remotecall_fetch(id_other) do
            @eval module AModuleLocalToOther
                foo() = throw(ErrorException("A.error"))
                foo()
            end
        end
    catch ex
    end
    @test (ex::RemoteException).pid == id_other
    @test ((ex.captured::CapturedException).ex::ErrorException).msg == "A.error"
    bt = ex.captured.processed_bt::Array{Any,1}
    @test length(bt) > 1
    frame, repeated = bt[1]::Tuple{Base.StackTraces.StackFrame, Int}
    @test frame.func == :foo
    @test frame.linfo === nothing
    @test repeated == 1
end

# pmap tests. Needs at least 4 processors dedicated to the below tests. Which we currently have
# since the distributed tests are now spawned as a separate set.

# Test all combinations of pmap keyword args.
pmap_args = [
                (:distributed, [:default, false]),
                (:batch_size, [:default,2]),
                (:on_error, [:default, e -> (e.msg == "foobar" ? true : rethrow())]),
                (:retry_delays, [:default, fill(0.001, 1000)]),
                (:retry_check, [:default, (s,e) -> (s,endswith(e.msg,"foobar"))]),
            ]

kwdict = Dict()
function walk_args(i)
    if i > length(pmap_args)
        kwargs = []
        for (k,v) in kwdict
            if v !== :default
                push!(kwargs, (k,v))
            end
        end

        data = 1:100

        testw = kwdict[:distributed] === false ? [1] : workers()

        if kwdict[:retry_delays] !== :default
            mapf = x -> iseven(myid()) ? error("notfoobar") : (x*2, myid())
            results_test = pmap_res -> begin
                results = [x[1] for x in pmap_res]
                pids = [x[2] for x in pmap_res]
                @test results == [2:2:200...]
                for p in testw
                    if isodd(p)
                        @test p in pids
                    else
                        @test !(p in pids)
                    end
                end
            end
        elseif kwdict[:on_error] === :default
            mapf = x -> (x*2, myid())
            results_test = pmap_res -> begin
                results = [x[1] for x in pmap_res]
                pids = [x[2] for x in pmap_res]
                @test results == [2:2:200...]
                for p in testw
                    @test p in pids
                end
            end
        else
            mapf = x -> iseven(x) ? error("foobar") : (x*2, myid())
            results_test = pmap_res -> begin
                w = testw
                for (idx,x) in enumerate(data)
                    if iseven(x)
                        @test pmap_res[idx] == true
                    else
                        @test pmap_res[idx][1] == x*2
                        @test pmap_res[idx][2] in w
                    end
                end
            end
        end

        try
            results_test(pmap(mapf, data; kwargs...))
        catch
            println("pmap executing with args : ", kwargs)
            rethrow()
        end

        return
    end

    kwdict[pmap_args[i][1]] = pmap_args[i][2][1]
    walk_args(i+1)

    kwdict[pmap_args[i][1]] = pmap_args[i][2][2]
    walk_args(i+1)
end

# Start test for various kw arg combinations
walk_args(1)

include(joinpath(Sys.BINDIR, "..", "share", "julia", "test", "generic_map_tests.jl"))
empty_pool = WorkerPool([myid()])
pmap_fallback = (f, c...) -> pmap(f, empty_pool, c...)
generic_map_tests(pmap_fallback)

# pmap with various types. Test for equivalence with map
run_map_equivalence_tests(pmap)
@test pmap(uppercase, "Hello World!") == map(uppercase, "Hello World!")

# Simple test for pmap throws error
let error_thrown = false
    try
        pmap(x -> x == 50 ? error("foobar") : x, 1:100)
    catch e
        @test e.captured.ex.msg == "foobar"
        error_thrown = true
    end
    @test error_thrown
end

# Test pmap with a generator type iterator
@test [1:100...] == pmap(x->x, Base.Generator(x->(sleep(0.0001); x), 1:100))

# Test pgenerate
n = 10
as = [rand(4,4) for i in 1:n]
bs = deepcopy(as)
cs = collect(Distributed.pgenerate(x->(sleep(rand()*0.1); svd(x)), bs))
svdas = map(svd, as)
for i in 1:n
    @test cs[i].U ≈ svdas[i].U
    @test cs[i].S ≈ svdas[i].S
    @test cs[i].V ≈ svdas[i].V
end

# Test that the default worker pool cycles through all workers
pmap(_->myid(), 1:nworkers())  # priming run
@test nworkers() == length(unique(pmap(_->myid(), 1:100)))

# Test same behaviour when executed on a worker
@test nworkers() == length(unique(remotecall_fetch(()->pmap(_->myid(), 1:100), id_other)))

# Same tests with custom worker pools.
wp = WorkerPool(workers())
@test nworkers() == length(unique(pmap(_->myid(), wp, 1:100)))
@test nworkers() == length(unique(remotecall_fetch(wp->pmap(_->myid(), wp, 1:100), id_other, wp)))

# CachingPool tests
wp = CachingPool(workers())
@test [1:100...] == pmap(x->x, wp, 1:100)

clear!(wp)
@test length(wp.map_obj2ref) == 0

# The below block of tests are usually run only on local development systems, since:
# - tests which print errors
# - addprocs tests are memory intensive
# - ssh addprocs requires sshd to be running locally with passwordless login enabled.
# The test block is enabled by defining env JULIA_TESTFULL=1

DoFullTest = Bool(parse(Int,(get(ENV, "JULIA_TESTFULL", "0"))))

if DoFullTest
    println("Testing exception printing on remote worker from a `remote_do` call")
    println("Please ensure the remote error and backtrace is displayed on screen")

    remote_do(id_other) do
        throw(ErrorException("TESTING EXCEPTION ON REMOTE DO. PLEASE IGNORE"))
    end
    sleep(0.5)  # Give some time for the above error to be printed

    println("\n\nThe following 'invalid connection credentials' error messages are to be ignored.")
    all_w = workers()
    # Test sending fake data to workers. The worker processes will print an
    # error message but should not terminate.
    for w in Distributed.PGRP.workers
        if isa(w, Distributed.Worker)
            local s = connect(w.config.host, w.config.port)
            write(s, randstring(32))
        end
    end
    @test workers() == all_w
    @test all([p == remotecall_fetch(myid, p) for p in all_w])

if Sys.isunix() # aka have ssh
    function test_n_remove_pids(new_pids)
        for p in new_pids
            w_in_remote = sort(remotecall_fetch(workers, p))
            try
                @test intersect(new_pids, w_in_remote) == new_pids
            catch
                print("p       :     $p\n")
                print("newpids :     $new_pids\n")
                print("w_in_remote : $w_in_remote\n")
                print("intersect   : $(intersect(new_pids, w_in_remote))\n\n\n")
                rethrow()
            end
        end

        remotecall_fetch(rmprocs, 1, new_pids)
    end

    print("\n\nTesting SSHManager. A minimum of 4GB of RAM is recommended.\n")
    print("Please ensure: \n")
    print("1) sshd is running locally with passwordless login enabled.\n")
    print("2) Env variable USER is defined and is the ssh user.\n")
    print("3) Port 9300 is not in use.\n")

    sshflags = `-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=ERROR `
    #Issue #9951
    hosts=[]
    localhost_aliases = ["localhost", string(getipaddr()), "127.0.0.1"]
    num_workers = parse(Int,(get(ENV, "JULIA_ADDPROCS_NUM", "9")))

    for i in 1:(num_workers/length(localhost_aliases))
        append!(hosts, localhost_aliases)
    end

    print("\nTesting SSH addprocs with $(length(hosts)) workers...\n")
    new_pids = addprocs_with_testenv(hosts; sshflags=sshflags)
    @test length(new_pids) == length(hosts)
    test_n_remove_pids(new_pids)

    print("\nMixed ssh addprocs with :auto\n")
    new_pids = addprocs_with_testenv(["localhost", ("127.0.0.1", :auto), "localhost"]; sshflags=sshflags)
    @test length(new_pids) == (2 + Sys.CPU_THREADS)
    test_n_remove_pids(new_pids)

    print("\nMixed ssh addprocs with numeric counts\n")
    new_pids = addprocs_with_testenv([("localhost", 2), ("127.0.0.1", 2), "localhost"]; sshflags=sshflags)
    @test length(new_pids) == 5
    test_n_remove_pids(new_pids)

    print("\nssh addprocs with tunnel\n")
    new_pids = addprocs_with_testenv([("localhost", num_workers)]; tunnel=true, sshflags=sshflags)
    @test length(new_pids) == num_workers
    test_n_remove_pids(new_pids)

    print("\nssh addprocs with tunnel (SSH multiplexing)\n")
    new_pids = addprocs_with_testenv([("localhost", num_workers)]; tunnel=true, multiplex=true, sshflags=sshflags)
    @test length(new_pids) == num_workers
    controlpath = joinpath(homedir(), ".ssh", "julia-$(ENV["USER"])@localhost:22")
    @test issocket(controlpath)
    test_n_remove_pids(new_pids)
    @test :ok == timedwait(()->!issocket(controlpath), 10.0; pollint=0.5)

    print("\nAll supported formats for hostname\n")
    h1 = "localhost"
    user = ENV["USER"]
    h2 = "$user@$h1"
    h3 = "$h2:22"
    h4 = "$h3 $(string(getipaddr()))"
    h5 = "$h4:9300"

    new_pids = addprocs_with_testenv([h1, h2, h3, h4, h5]; sshflags=sshflags)
    @test length(new_pids) == 5
    test_n_remove_pids(new_pids)

    print("\nkeyword arg exename\n")
    for exename in [`$(joinpath(Sys.BINDIR, Base.julia_exename()))`, "$(joinpath(Sys.BINDIR, Base.julia_exename()))"]
        for addp_func in [()->addprocs_with_testenv(["localhost"]; exename=exename, exeflags=test_exeflags, sshflags=sshflags),
                          ()->addprocs_with_testenv(1; exename=exename, exeflags=test_exeflags)]

            local new_pids = addp_func()
            @test length(new_pids) == 1
            test_n_remove_pids(new_pids)
        end
    end

end # unix-only
end # full-test

let t = @task 42
    schedule(t, ErrorException(""), error=true)
    @test_throws TaskFailedException(t) Base.wait(t)
end

# issue #8207
let A = Any[]
    @distributed (+) for i in (push!(A,1); 1:2)
        i
    end
    @test length(A) == 1
end

# issue #13168
function f13168(n)
    val = 0
    for i = 1:n
        val += sum(rand(n, n)^2)
    end
    return val
end
let t = schedule(@task f13168(100))
    @test t.state == :runnable
    @test t.queue !== nothing
    @test_throws ErrorException schedule(t)
    yield()
    @test t.state == :done
    @test t.queue === nothing
    @test_throws ErrorException schedule(t)
    @test isa(fetch(t), Float64)
end

# issue #13122
@test remotecall_fetch(identity, workers()[1], C_NULL) === C_NULL

# issue #11062
function t11062()
    @async v11062 = 1
    v11062 = 2
end

@test t11062() == 2

# issue #15406
v15406 = remotecall_wait(() -> 1, id_other)
fetch(v15406)
remotecall_wait(fetch, id_other, v15406)

# Test various forms of remotecall* invocations

@everywhere f_args(v1, v2=0; kw1=0, kw2=0) = v1+v2+kw1+kw2

function test_f_args(result, args...; kwargs...)
    @test fetch(remotecall(args...; kwargs...)) == result
    @test fetch(remotecall_wait(args...; kwargs...)) == result
    @test remotecall_fetch(args...; kwargs...) == result

    # A visual test - remote_do should NOT print any errors
    remote_do(args...; kwargs...)
end

for tid in [id_other, id_me, default_worker_pool()]
    test_f_args(1, f_args, tid, 1)
    test_f_args(3, f_args, tid, 1, 2)
    test_f_args(5, f_args, tid, 1; kw1=4)
    test_f_args(13, f_args, tid, 1; kw1=4, kw2=8)
    test_f_args(15, f_args, tid, 1, 2; kw1=4, kw2=8)
end

# Test remote_do
f=Future(id_me)
remote_do(fut->put!(fut, myid()), id_me, f)
@test fetch(f) == id_me

f=Future(id_other)
remote_do(fut->put!(fut, myid()), id_other, f)
@test fetch(f) == id_other

# Github issue #29932
rc_unbuffered = RemoteChannel(()->Channel{Vector{Float64}}(0))
@test eltype(rc_unbuffered) == Vector{Float64}

@async begin
    # Trigger direct write (no buffering) of largish array
    array_sz = Int(Base.SZ_UNBUFFERED_IO/8) + 1
    largev = zeros(array_sz)
    for i in 1:10
        largev[1] = float(i)
        put!(rc_unbuffered, largev)
    end
end

@test remotecall_fetch(rc -> begin
        for i in 1:10
            take!(rc)[1] != float(i) && error("Failed")
        end
        return :OK
    end, id_other, rc_unbuffered) == :OK

# github PR #14456
n = DoFullTest ? 6 : 5
for i = 1:10^n
    fetch(@spawnat myid() myid())
end

# issue #15451
@test remotecall_fetch(x->(y->2y)(x)+1, workers()[1], 3) == 7

# issue #16091
mutable struct T16091 end
wid = workers()[1]
@test try
    remotecall_fetch(()->T16091, wid)
    false
catch ex
    ((ex::RemoteException).captured::CapturedException).ex === UndefVarError(:T16091)
end
@test try
    remotecall_fetch(identity, wid, T16091)
    false
catch ex
    ((ex::RemoteException).captured::CapturedException).ex === UndefVarError(:T16091)
end

f16091a() = 1
remotecall_fetch(()->eval(:(f16091a() = 2)), wid)
@test remotecall_fetch(f16091a, wid) === 2
@test remotecall_fetch((myid)->remotecall_fetch(f16091a, myid), wid, myid()) === 1

# these will only heisen-fail, since it depends on the gensym counter collisions:
f16091b = () -> 1
remotecall_fetch(()->eval(:(f16091b = () -> 2)), wid)
@test remotecall_fetch(f16091b, 2) === 1
# Global anonymous functions are over-written...
@test remotecall_fetch((myid)->remotecall_fetch(f16091b, myid), wid, myid()) === 1

# ...while local anonymous functions are by definition, local.
let
    f16091c = () -> 1
    @test remotecall_fetch(f16091c, 2) === 1
    @test remotecall_fetch(
        myid -> begin
            let
                f16091c = () -> 2
                remotecall_fetch(f16091c, myid)
            end
        end, wid, myid()) === 2
end

# issue #16451
rng=RandomDevice()
retval = @distributed (+) for _ in 1:10
    rand(rng)
end
@test retval > 0.0 && retval < 10.0

rand(rng)
retval = @distributed (+) for _ in 1:10
    rand(rng)
end
@test retval > 0.0 && retval < 10.0

# serialization tests
wrkr1 = workers()[1]
wrkr2 = workers()[end]

@test remotecall_fetch(p->remotecall_fetch(myid, p), wrkr1, wrkr2) == wrkr2

# Send f to wrkr1 and wrkr2. Then try calling f on wrkr2 from wrkr1
f_myid = ()->myid()
@test wrkr1 == remotecall_fetch(f_myid, wrkr1)
@test wrkr2 == remotecall_fetch(f_myid, wrkr2)
@test wrkr2 == remotecall_fetch((f, p)->remotecall_fetch(f, p), wrkr1, f_myid, wrkr2)

# Deserialization error recovery test
# locally defined module, but unavailable on workers
module LocalFoo
    global foo=1
end

let
    @test_throws RemoteException remotecall_fetch(()->LocalFoo.foo, 2)

    bad_thunk = ()->NonexistantModule.f()
    @test_throws RemoteException remotecall_fetch(bad_thunk, 2)

    # Test that the stream is still usable
    @test remotecall_fetch(()->:test,2) == :test
    ref = remotecall(bad_thunk, 2)
    @test_throws RemoteException fetch(ref)
end

# Test calling @everywhere from a module not defined on the workers
module LocalBar
    using Distributed
    bar() = @everywhere new_bar()=myid()
end
LocalBar.bar()
for p in procs()
    @test p == remotecall_fetch(new_bar, p)
end

# @everywhere (remotecall_eval) behaviors (#22589)
let (p, p2) = filter!(p -> p != myid(), procs())
    @test (myid() + 1) == @everywhere myid() (myid() + 1)
    @test (p * 2) == @everywhere p (myid() * 2)
    @test 1 == @everywhere p defined_on_p = 1
    @test !@isdefined defined_on_p
    @test !isdefined(Main, :defined_on_p)
    @test remotecall_fetch(isdefined, p, Main, :defined_on_p)
    @test !remotecall_fetch(isdefined, p2, Main, :defined_on_p)
    @test nothing === @everywhere [p, p] defined_on_p += 1
    @test 3 === @everywhere p defined_on_p
    let ref = Ref(0)
        @test nothing ===
            @everywhere [myid(), p, myid(), myid(), p] begin
                Test.@test Main === @__MODULE__
                $ref[] += 1
            end
        @test ref[] == 3
    end
    function test_throw_on(procs, msg)
        try
            @everywhere procs error($msg)
            error("test failed to throw")
        catch excpt
            if procs isa Int
                ex = Any[excpt]
            else
                ex = (excpt::CompositeException).exceptions
            end
            for (p, ex) in zip(procs, ex)
                local p
                if procs isa Int || p != myid()
                    @test (ex::RemoteException).pid == p
                    ex = ((ex::RemoteException).captured::CapturedException).ex
                else
                    ex = (ex::TaskFailedException).task.exception
                end
                @test (ex::ErrorException).msg == msg
            end
        end
    end
    test_throw_on(p, "everywhere on p")
    test_throw_on(myid(), "everywhere on myid")
    test_throw_on([p, myid()], "everywhere on myid and p")
    test_throw_on([p2, p], "everywhere on p and p2")
end

# Test addprocs enable_threaded_blas parameter

const get_num_threads = function() # anonymous so it will be serialized when called
    blas = LinearAlgebra.BLAS.vendor()
    # Wrap in a try to catch unsupported blas versions
    try
        if blas == :openblas
            return ccall((:openblas_get_num_threads, Base.libblas_name), Cint, ())
        elseif blas == :openblas64
            return ccall((:openblas_get_num_threads64_, Base.libblas_name), Cint, ())
        elseif blas == :mkl
            return ccall((:MKL_Get_Max_Num_Threads, Base.libblas_name), Cint, ())
        end

        # OSX BLAS looks at an environment variable
        if Sys.isapple()
            return tryparse(Cint, get(ENV, "VECLIB_MAXIMUM_THREADS", "1"))
        end
    catch
    end

    return nothing
end

function get_remote_num_threads(processes_added)
    return [remotecall_fetch(get_num_threads, proc_id) for proc_id in processes_added]
end

function test_blas_config(pid, expected)
    for worker in Distributed.PGRP.workers
        if worker.id == pid
            @test worker.config.enable_threaded_blas == expected
            return
        end
    end
end

function test_add_procs_threaded_blas()
    master_blas_thread_count = get_num_threads()
    if master_blas_thread_count === nothing
        @warn "Skipping blas num threads tests due to unsupported blas version"
        return
    end
    @test master_blas_thread_count <= 8 # check that Base set the environment variable in __init__ before LinearAlgebra dlopen'd it

    # Test with default enable_threaded_blas false
    processes_added = addprocs_with_testenv(2)
    for proc_id in processes_added
        test_blas_config(proc_id, false)
    end

    # Master thread should not have changed
    @test get_num_threads() == master_blas_thread_count

    # Threading disabled in children by default
    thread_counts_by_process = get_remote_num_threads(processes_added)
    for thread_count in thread_counts_by_process
        @test thread_count == 1
    end
    rmprocs(processes_added)

    processes_added = addprocs_with_testenv(2, enable_threaded_blas=true)
    for proc_id in processes_added
        test_blas_config(proc_id, true)
    end

    @test get_num_threads() == master_blas_thread_count

    # BLAS.set_num_threads(`num`) doesn't  cause get_num_threads to return `num`
    # depending on the machine, the BLAS version, and BLAS configuration, so
    # we need a very lenient test.
    thread_counts_by_process = get_remote_num_threads(processes_added)
    for thread_count in thread_counts_by_process
        @test thread_count >= 1
    end
    rmprocs(processes_added)
end
test_add_procs_threaded_blas()

#19687
if false ### TODO: The logic that is supposed to implement this is racy - Disabled for now
# ensure no race conditions between rmprocs and addprocs
for i in 1:5
    p = addprocs_with_testenv(1)[1]
    @spawnat p sleep(5)
    rmprocs(p; waitfor=0)
end

# Test if a wait has been called on rmprocs(...;waitfor=0), further remotecalls
# don't throw errors.
for i in 1:5
    p = addprocs_with_testenv(1)[1]
    np = nprocs()
    @spawnat p sleep(5)
    Base.wait(rmprocs(p; waitfor=0))
    for pid in procs()
        @test pid == remotecall_fetch(myid, pid)
    end
    @test nprocs() == np - 1
end

# Test that an exception is thrown if workers are unable to be removed within requested time.
if DoFullTest
    pids=addprocs_with_testenv(4);
    @test_throws ErrorException rmprocs(pids; waitfor=0.001);
    # wait for workers to be removed
    while any(in(procs()), pids)
        sleep(0.1)
    end
end
end

# Test addprocs/rmprocs from master node only
for f in [ ()->addprocs(1; exeflags=test_exeflags), ()->rmprocs(workers()) ]
    local f
    try
        remotecall_fetch(f, id_other)
        error("Unexpected")
    catch ex
        @test isa(ex, RemoteException)
        @test ex.captured.ex.msg == "Only process 1 can add and remove workers"
    end
end

# Test the following addprocs error conditions
# - invalid host name - github issue #20372
# - julia exe exiting with an error
# - timeout reading host:port from worker stdout
# - host:port not found in worker stdout in the first 1000 lines

struct ErrorSimulator <: ClusterManager
    mode
end

function launch(manager::ErrorSimulator, params::Dict, launched::Array, c::Condition)
    exename = params[:exename]
    dir = params[:dir]

    cmd = `$(Base.julia_cmd(exename)) --startup-file=no`
    if manager.mode == :timeout
        cmd = `$cmd -e "sleep(10)"`
    elseif manager.mode == :ntries
        cmd = `$cmd -e "[println(x) for x in 1:1001]"`
    elseif manager.mode == :exit
        cmd = `$cmd -e "exit(-1)"`
    else
        error("Unknown mode")
    end
    io = open(detach(setenv(cmd, dir=dir)))

    wconfig = WorkerConfig()
    wconfig.process = io
    wconfig.io = io.out
    push!(launched, wconfig)
    notify(c)
end

testruns = Any[]

if DoFullTest
    append!(testruns, [(()->addprocs_with_testenv(["errorhost20372"]), "Unable to read host:port string from worker. Launch command exited with error?", ())])
end

append!(testruns, [
    (()->addprocs_with_testenv(ErrorSimulator(:exit)), "Unable to read host:port string from worker. Launch command exited with error?", ()),
    (()->addprocs_with_testenv(ErrorSimulator(:ntries)), "Unexpected output from worker launch command. Host:port string not found.", ()),
    (()->addprocs_with_testenv(ErrorSimulator(:timeout)), "Timed out waiting to read host:port string from worker.", ("JULIA_WORKER_TIMEOUT"=>"1",))
])

for (addp_testf, expected_errstr, env) in testruns
    old_stdout = stdout
    stdout_out, stdout_in = redirect_stdout()
    stdout_txt = @async filter!(readlines(stdout_out)) do s
            return !startswith(s, "\tFrom worker startup:\t")
        end
    try
        withenv(env...) do
            addp_testf()
        end
        error("Unexpected")
    catch ex
        redirect_stdout(old_stdout)
        close(stdout_in)
        @test isempty(fetch(stdout_txt))
        @test isa(ex, CompositeException)
        @test ex.exceptions[1].task.exception.msg == expected_errstr
    end
end

# Auto serialization of globals from Main.
# bitstypes
global v1 = 1
@test remotecall_fetch(()->v1, id_other) == v1
@test remotecall_fetch(()->isdefined(Main, :v1), id_other)
for i in 2:5
    global v1 = i
    @test remotecall_fetch(()->v1, id_other) == i
end

# non-bitstypes
global v2 = zeros(10)
for i in 1:5
    v2[i] = i
    @test remotecall_fetch(()->v2, id_other) == v2
end

# Different global bindings to the same object
global v3 = fill(1., 10)
global v4 = v3
@test remotecall_fetch(()->v3, id_other) == remotecall_fetch(()->v4, id_other)
@test remotecall_fetch(()->isdefined(Main, :v3), id_other)
@test remotecall_fetch(()->isdefined(Main, :v4), id_other)

# Global references to Types and Modules should work if they are locally defined
global v5 = Int
global v6 = Distributed
@test remotecall_fetch(()->v5, id_other) === Int
@test remotecall_fetch(()->v6, id_other) === Distributed

struct FooStructLocal end
module FooModLocal end
v5 = FooStructLocal
v6 = FooModLocal
@test_throws RemoteException remotecall_fetch(()->v5, id_other)
@test_throws RemoteException remotecall_fetch(()->v6, id_other)

@everywhere struct FooStructEverywhere end
@everywhere module FooModEverywhere end
v5 = FooStructEverywhere
v6 = FooModEverywhere
@test remotecall_fetch(()->v5, id_other) === FooStructEverywhere
@test remotecall_fetch(()->v6, id_other) === FooModEverywhere

# hash value same but different object instance
v7 = ones(10)
oid1 = objectid(v7)
hval1 = hash(v7)
@test v7 == @fetchfrom id_other v7
remote_oid1 = @fetchfrom id_other objectid(v7)

v7 = ones(10)
@test oid1 != objectid(v7)
@test hval1 == hash(v7)
@test remote_oid1 != @fetchfrom id_other objectid(v7)

# Github issue #31252
v31252 = :a
@test :a == @fetchfrom id_other v31252

v31252 = :b
@test :b == @fetchfrom id_other v31252

v31252 = :a
@test :a == @fetchfrom id_other v31252

# Test that a global is not being repeatedly serialized when
# a) referenced multiple times in the closure
# b) hash value has not changed.

@everywhere begin
    using Serialization
    global testsercnt_d = Dict()
    mutable struct TestSerCnt
        v
    end
    import Base.hash, Base.==
    hash(x::TestSerCnt, h::UInt) = hash(hash(x.v), h)
    ==(x1::TestSerCnt, x2::TestSerCnt) = (x1.v == x2.v)

    function Serialization.serialize(s::AbstractSerializer, t::TestSerCnt)
        Serialization.serialize_type(s, TestSerCnt)
        serialize(s, t.v)
        global testsercnt_d
        cnt = get!(testsercnt_d, objectid(t), 0)
        testsercnt_d[objectid(t)] = cnt+1
    end

    Serialization.deserialize(s::AbstractSerializer, ::Type{TestSerCnt}) = TestSerCnt(deserialize(s))
end

# hash value of tsc is not changed
global tsc = TestSerCnt(zeros(10))
for i in 1:5
    remotecall_fetch(()->tsc, id_other)
end
# should have been serialized only once
@test testsercnt_d[objectid(tsc)] == 1

# hash values are changed
n=5
testsercnt_d[objectid(tsc)] = 0
for i in 1:n
    tsc.v[i] = i
    remotecall_fetch(()->tsc, id_other)
end
# should have been serialized as many times as the loop
@test testsercnt_d[objectid(tsc)] == n

# Multiple references in a closure should be serialized only once.
global mrefs = TestSerCnt(fill(1.,10))
@test remotecall_fetch(()->(mrefs.v, 2*mrefs.v, 3*mrefs.v), id_other) == (fill(1.,10), fill(2.,10), fill(3.,10))
@test testsercnt_d[objectid(mrefs)] == 1

# nested anon functions
global f1 = x->x
global f2 = x->f1(x)
v = rand()
@test remotecall_fetch(f2, id_other, v) == v
@test remotecall_fetch(x->f2(x), id_other, v) == v

# consts
const c1 = fill(1., 10)
@test remotecall_fetch(()->c1, id_other) == c1
@test remotecall_fetch(()->isconst(Main, :c1), id_other)

# Test same calls with local vars
function wrapped_var_ser_tests()
    # bitstypes
    local lv1 = 1
    @test remotecall_fetch(()->lv1, id_other) == lv1
    @test !remotecall_fetch(()->isdefined(Main, :lv1), id_other)
    for i in 2:5
        lv1 = i
        @test remotecall_fetch(()->lv1, id_other) == i
    end

    # non-bitstypes
    local lv2 = zeros(10)
    for i in 1:5
        lv2[i] = i
        @test remotecall_fetch(()->lv2, id_other) == lv2
    end

    # nested anon functions
    local lf1 = x->x
    local lf2 = x->lf1(x)
    v = rand()
    @test remotecall_fetch(lf2, id_other, v) == v
    @test remotecall_fetch(x->lf2(x), id_other, v) == v
end

wrapped_var_ser_tests()

# Test internal data structures being cleaned up upon gc.
global ids_cleanup = fill(1., 6)
global ids_func = ()->ids_cleanup

clust_ser = (Distributed.worker_from_id(id_other)).w_serializer
@test remotecall_fetch(ids_func, id_other) == ids_cleanup

# TODO Add test for cleanup from `clust_ser.glbs_in_tnobj`

# reported github issues - Mostly tests with globals and various distributed macros
#2669, #5390
v2669=10
@test fetch(@spawnat :any (1+v2669)) == 11

#12367
refs = []
if true
    n = 10
    for p in procs()
        push!(refs, @spawnat p begin
            @sync for i in 1:n
                nothing
            end
        end)
    end
end
foreach(wait, refs)

#6760
if true
    a = 2
    x = @distributed (vcat) for k=1:2
        sin(a)
    end
end
@test x == map(_->sin(2), 1:2)

let thrown = false
    try
        remotecall_fetch(sqrt, 2, -1)
    catch e
        thrown = true
        local b = IOBuffer()
        showerror(b, e)
        @test occursin("sqrt will only return", String(take!(b)))
    end
    @test thrown
end

# issue #34333
let
    @test fetch(remotecall(Float64, id_other, 1)) == Float64(1)
    @test fetch(remotecall_wait(Float64, id_other, 1)) == Float64(1)
    @test remotecall_fetch(Float64, id_other, 1) == Float64(1)
end

#19463
function foo19463()
    w1 = workers()[1]
    w2 = workers()[2]
    w3 = workers()[3]

    b1 = () -> 1
    b2 = () -> fetch(@spawnat w1 b1()) + 1
    b3 = () -> fetch(@spawnat w2 b2()) + 1
    b4 = () -> fetch(@spawnat w3 b3()) + 1
    b4()
end
@test foo19463() == 4

# Testing clear!
function setup_syms(n, pids)
    syms = []
    for i in 1:n
        symstr = string("clrtest", randstring())
        sym = Symbol(symstr)
        eval(:(global $sym = rand()))
        for p in pids
            eval(:(@test $sym == remotecall_fetch(()->$sym, $p)))
            eval(:(@test remotecall_fetch(isdefined, $p, Main, Symbol($symstr))))
        end
        push!(syms, sym)
    end
    syms
end

function test_clear(syms, pids)
    for p in pids
        for sym in syms
            remote_val = remotecall_fetch(()->getfield(Main, sym), p)
            @test remote_val === nothing
            @test remote_val != getfield(Main, sym)
        end
    end
end

syms = setup_syms(1, [id_other])
clear!(syms[1], id_other)
test_clear(syms, [id_other])

syms = setup_syms(1, workers())
clear!(syms[1], workers())
test_clear(syms, workers())

syms = setup_syms(3, [id_other])
clear!(syms, id_other)
test_clear(syms, [id_other])

syms = setup_syms(3, workers())
clear!(syms, workers())
test_clear(syms, workers())

# Test partial recovery from a deserialization error in CapturedException
try
    expr = quote
                mutable struct DontExistOn1
                    x
                end
                throw(BoundsError(DontExistOn1(1), 1))
           end

    remotecall_fetch(()->eval(expr), id_other)
    error("unexpected")
catch ex
    @test isa(ex.captured.ex.exceptions[1].ex, ErrorException)
    @test occursin("BoundsError", ex.captured.ex.exceptions[1].ex.msg)
    @test ex.captured.ex.exceptions[2].ex == UndefVarError(:DontExistOn1)
end

let
    # creates a new worker in a different folder and tries to include file
    tmp_dir = mktempdir()
    tmp_dir2 = joinpath(tmp_dir, "2")
    tmp_file = joinpath(tmp_dir2, "testfile")
    tmp_file2 = joinpath(tmp_dir2, "testfile2")
    proc = addprocs_with_testenv(1, dir=tmp_dir)
    try
        mkdir(tmp_dir2)
        write(tmp_file, "23.32 + 32 + myid() + include(\"testfile2\")")
        write(tmp_file2, "myid() * 2")
        function test_include_fails_to_open_file(fname)
            try
                include(fname)
            catch exc
                path = joinpath(@__DIR__, fname)
                @test exc isa SystemError
                @test exc.prefix == "opening file $(repr(path))"
            end
        end
        test_include_fails_to_open_file("testfile")
        test_include_fails_to_open_file("testfile2")
        test_include_fails_to_open_file(joinpath("2", "testfile2"))
        @test include(tmp_file) == 58.32
        @test remotecall_fetch(include, proc[1], joinpath("2", "testfile")) == 55.32 + proc[1] * 3
    finally
        rmprocs(proc)
        rm(tmp_file, force=true)
        rm(tmp_file2, force=true)
        rm(tmp_dir2, force=true)
        #rm(tmp_dir, force=true)
    end
end
# cookie and command line option `--worker` tests. remove workers, set cookie and test
struct WorkerArgTester <: ClusterManager
    worker_opt
    write_cookie
end

function launch(manager::WorkerArgTester, params::Dict, launched::Array, c::Condition)
    dir = params[:dir]
    exename = params[:exename]
    exeflags = params[:exeflags]

    cmd = `$exename $exeflags --bind-to $(Distributed.LPROC.bind_addr) $(manager.worker_opt)`
    cmd = pipeline(detach(setenv(cmd, dir=dir)))
    io = open(cmd, "r+")
    manager.write_cookie && Distributed.write_cookie(io)

    wconfig = WorkerConfig()
    wconfig.process = io
    wconfig.io = io.out
    push!(launched, wconfig)

    notify(c)
end
manage(::WorkerArgTester, ::Integer, ::WorkerConfig, ::Symbol) = nothing

nprocs()>1 && rmprocs(workers())

npids = addprocs_with_testenv(WorkerArgTester(`--worker`, true))
@test remotecall_fetch(myid, npids[1]) == npids[1]
rmprocs(npids)

cluster_cookie("")  # An empty string is a valid cookie
npids = addprocs_with_testenv(WorkerArgTester(`--worker=`, false))
@test remotecall_fetch(myid, npids[1]) == npids[1]
rmprocs(npids)

cluster_cookie("foobar") # custom cookie
npids = addprocs_with_testenv(WorkerArgTester(`--worker=foobar`, false))
@test remotecall_fetch(myid, npids[1]) == npids[1]

# tests for start_worker options to retain stdio (issue #31035)
struct RetainStdioTester <: ClusterManager
    close_stdin::Bool
    stderr_to_stdout::Bool
end

function launch(manager::RetainStdioTester, params::Dict, launched::Array, c::Condition)
    dir = params[:dir]
    exename = params[:exename]
    exeflags = params[:exeflags]

    jlcmd = "using Distributed; start_worker(\"\"; close_stdin=$(manager.close_stdin), stderr_to_stdout=$(manager.stderr_to_stdout));"
    cmd = detach(setenv(`$exename $exeflags --bind-to $(Distributed.LPROC.bind_addr) -e $jlcmd`, dir=dir))
    proc = open(cmd, "r+")

    wconfig = WorkerConfig()
    wconfig.process = proc
    wconfig.io = proc.out
    push!(launched, wconfig)

    notify(c)
end
manage(::RetainStdioTester, ::Integer, ::WorkerConfig, ::Symbol) = nothing

nprocs()>1 && rmprocs(workers())
cluster_cookie("")

for close_stdin in (true, false), stderr_to_stdout in (true, false)
    local npids = addprocs_with_testenv(RetainStdioTester(close_stdin,stderr_to_stdout))
    @test remotecall_fetch(myid, npids[1]) == npids[1]
    @test close_stdin != remotecall_fetch(()->isopen(stdin), npids[1])
    @test stderr_to_stdout == remotecall_fetch(()->(stderr === stdout), npids[1])
    rmprocs(npids)
end

# Issue # 22865
# Must be run on a new cluster, i.e., all workers must be in the same state.
@assert nprocs() == 1
p1,p2 = addprocs_with_testenv(2)
@everywhere f22865(p) = remotecall_fetch(x->x.*2, p, fill(1.,2))
@test fill(2.,2) == remotecall_fetch(f22865, p1, p2)
rmprocs(p1, p2)

function reuseport_tests()
    # Run the test on all processes.
    results = asyncmap(procs()) do p
        remotecall_fetch(p) do
            ports_lower = []        # ports of pids lower than myid()
            ports_higher = []       # ports of pids higher than myid()
            for w in Distributed.PGRP.workers
                w.id == myid() && continue
                port = Sockets._sockname(w.r_stream, true)[2]
                if (w.id == 1)
                    # master connects to workers
                    push!(ports_higher, port)
                elseif w.id < myid()
                    push!(ports_lower, port)
                elseif w.id > myid()
                    push!(ports_higher, port)
                end
            end
            @assert (length(ports_lower) + length(ports_higher)) == nworkers()
            for portset in [ports_lower, ports_higher]
                if (length(portset) > 0) && (length(unique(portset)) != 1)
                    @warn "SO_REUSEPORT TESTS FAILED. UNSUPPORTED/OLDER UNIX VERSION?"
                    return 0
                end
            end
            return myid()
        end
    end

    # Ensure that the code has indeed been successfully executed everywhere
    @test all(in(results), procs())
end

# Test that the client port is reused. SO_REUSEPORT may not be supported on
# all UNIX platforms, Linux kernels prior to 3.9 and older versions of OSX
@assert nprocs() == 1
addprocs_with_testenv(4; lazy=false)
if ccall(:jl_has_so_reuseport, Int32, ()) == 1
    reuseport_tests()
else
    @info "SO_REUSEPORT is unsupported, skipping reuseport tests"
end

# issue #27933
a27933 = :_not_defined_27933
@test remotecall_fetch(()->a27933, first(workers())) === a27933

# PR #28651
for T in (UInt8, Int8, UInt16, Int16, UInt32, Int32, UInt64)
    local n = @distributed (+) for i in Base.OneTo(T(10))
        i
    end
    @test n == 55
end

# issue #28966
let code = """
    import Distributed
    Distributed.addprocs(1)
    Distributed.@everywhere f() = myid()
    for w in Distributed.workers()
        @assert Distributed.remotecall_fetch(f, w) == w
    end
    """
    @test success(`$(Base.julia_cmd()) --startup-file=no -e $code`)
end

# PR 32431: tests for internal Distributed.head_and_tail
let (h, t) = Distributed.head_and_tail(1:10, 3)
    @test h == 1:3
    @test collect(t) == 4:10
end
let (h, t) = Distributed.head_and_tail(1:10, 0)
    @test h == []
    @test collect(t) == 1:10
end
let (h, t) = Distributed.head_and_tail(1:3, 5)
    @test h == 1:3
    @test collect(t) == []
end
let (h, t) = Distributed.head_and_tail(1:3, 3)
    @test h == 1:3
    @test collect(t) == []
end
let (h, t) = Distributed.head_and_tail(Int[], 3)
    @test h == []
    @test collect(t) == []
end
let (h, t) = Distributed.head_and_tail(Int[], 0)
    @test h == []
    @test collect(t) == []
end

# issue #35937
let e = @test_throws RemoteException pmap(1) do _
            wait(@async error(42))
        end
    # check that the inner TaskFailedException is correctly formed & can be printed
    es = sprint(showerror, e.value)
    @test contains(es, ":\nTaskFailedException\nStacktrace:\n")
    @test contains(es, "\n\n    nested task error:")
    @test_broken contains(es, "\n\n    nested task error: 42\n")
end

# issue #27429, propagate relative `include` path to workers
@everywhere include("includefile.jl")
for p in procs()
    @test @fetchfrom(p, i27429) == 27429
end

include("splitrange.jl")

# Run topology tests last after removing all workers, since a given
# cluster at any time only supports a single topology.
rmprocs(workers())
include("threads.jl")
include("topology.jl")

max_stars_repo_name: sudoWin/julia

max_issues_repo_name: PallHaraldsson/julia

max_forks_repo_name: PallHaraldsson/julia


text:
using Quaternions
using LinearAlgebra
using Random
using Test

struct MyReal <: Real
    val::Real
end
Base.:(/)(a::MyReal, b::Real) = a.val / b

@testset "Quaternion" begin
    @testset "type aliases" begin
        @test QuaternionF16 === Quaternion{Float16}
        @test QuaternionF32 === Quaternion{Float32}
        @test QuaternionF64 === Quaternion{Float64}
    end

    @testset "Constructors" begin
        @testset "from coefficients" begin
            cs = [(1, 2.0, 3.0f0, 4//1), (1//1, 2.0f0, 3.0f0, 4)]
            @testset for coef in cs, T in (Float32, Float64, Int), norm in (true, false)
                q = @inferred Quaternion{T}(coef..., norm)
                @test q isa Quaternion{T}
                @test q.norm === norm
                @test q === Quaternion{T}(convert.(T, coef)..., norm)
                q2 = @inferred Quaternion(convert.(T, coef)..., norm)
                @test Quaternion(convert.(T, coef)..., norm) === q
                if !norm
                    @test Quaternion(convert.(T, coef)...) === q
                end
            end
        end
        @testset "from real" begin
            @testset for x in (-1//1, 1.0, 2.0), T in (Float32, Float64, Int, Rational{Int})
                coef = T.((x, 0, 0, 0))
                @test @inferred(Quaternion{T}(x)) === Quaternion{T}(coef..., isone(abs(x)))
                @test @inferred(Quaternion(T(x))) === Quaternion{T}(coef..., isone(abs(x)))
            end
        end
        @testset "from complex" begin
            @testset for z in (1 + 0im, -im, 1 + 2im),
                T in (Float32, Float64, Int, Rational{Int})

                coef = T.((reim(z)..., 0, 0))
                z2 = Complex{T}(z)
                norm = isone(abs(z))
                @test Quaternion{T}(z) === Quaternion{T}(coef..., norm)
                @test @inferred(Quaternion(z2)) === Quaternion{T}(coef..., norm)
            end
        end
        @testset "from quaternion" begin
            @testset for q in (Quaternion(1, 2, 3, 4), QuaternionF64(0, 1, 0, 0, true)),
                T in (Float32, Float64)

                coef = T.((q.s, q.v1, q.v2, q.v3))
                @test @inferred(Quaternion{T}(q)) === Quaternion{T}(coef..., q.norm)
                @test @inferred(Quaternion(q)) === q
            end
        end
        @testset "from vector" begin
            s = randn()
            v = randn(3)
            @test @inferred(Quaternion(s, v)) === Quaternion(s, v...)
            @test @inferred(Quaternion(v)) === Quaternion(0, v)
        end
    end

    @testset "==" begin
        @test Quaternion(1, 2, 3, 4) == Quaternion(1.0, 2.0, 3.0, 4.0)
        @test Quaternion(1, 2, 3, 4) != Quaternion(5, 2, 3, 4)
        @test Quaternion(1, 2, 3, 4) != Quaternion(1, 5, 3, 4)
        @test Quaternion(1, 2, 3, 4) != Quaternion(1, 2, 5, 4)
        @test Quaternion(1, 2, 3, 4) != Quaternion(1, 2, 3, 5)
        x = randn(4)
        # test that .norm field does not affect equality
        @test Quaternion(1, 2, 3, 4, false) == Quaternion(1, 2, 3, 4, true)
    end

    @testset "convert" begin
        @test convert(Quaternion{Float64}, 1) === Quaternion(1.0)
        @test convert(Quaternion{Float64}, Complex(1, 2)) === Quaternion(1.0, 2.0, 0.0, 0.0)
        @test convert(Quaternion{Float64}, Quaternion(1, 2, 3, 4)) ===
            Quaternion(1.0, 2.0, 3.0, 4.0)
        @test convert(Quaternion{Float64}, Quaternion(1.0, 2.0, 3.0, 4.0)) ===
            Quaternion(1.0, 2.0, 3.0, 4.0)
        @test convert(Quaternion{Float64}, Quaternion(0, 1, 0, 0, true)) ===
            Quaternion(0.0, 1.0, 0.0, 0.0, true)
    end

    @testset "promote" begin
        @test promote(Quaternion(1.0, 2, 3, 4), 1.0) ===
            (Quaternion(1.0, 2, 3, 4), Quaternion(1.0))
        @test promote(Quaternion(1.0f0, 2, 3, 4), 2.0) ===
            (Quaternion(1.0, 2, 3, 4), Quaternion(2.0))
        @test promote(Quaternion(1.0f0), 2 + 3im) ===
            (Quaternion(1.0f0), Quaternion(2.0f0 + 3.0f0im))
        @test promote(Quaternion(1.0f0), Quaternion(2.0)) ===
            (Quaternion(1.0), Quaternion(2.0))

        @test Quaternion(1) == 1.0
        @test Quaternion(1, 2, 0, 0) == Complex(1.0, 2.0)
    end

    @testset "shorthands" begin
        @test quat(1) === Quaternion(1) # checking the .norm field in particular
        @test quat(1, 0, 0, 0) === Quaternion(1, 0, 0, 0) # checking the .norm field in particular
        @test quat(1, 2, 3, 4) === Quaternion(1, 2, 3, 4)
        @test quat(Quaternion(1, 0, 0, 0)) === Quaternion(1, 0, 0, 0) # checking the .norm field in particular
        @test quat(Quaternion(1, 2, 3, 4)) === Quaternion(1, 2, 3, 4)
        @test quat(1, 0, 0, 0, false).norm == false # respect the .norm input (even if wrong)
        @test quat(1, 2, 3, 4, true).norm == true # respect the .norm input (even if wrong)
        @test quat(1, [2, 3, 4]) === Quaternion(1, 2, 3, 4)
        @test quat([2, 3, 4]) === Quaternion(0, 2, 3, 4)
    end

    @testset "random generation" begin
        @testset "quatrand" begin
            rng = Random.MersenneTwister(42)
            q1 = quatrand(rng)
            @test q1 isa Quaternion
            @test !q1.norm

            q2 = quatrand()
            @test q2 isa Quaternion
            @test !q2.norm
        end

        @testset "nquatrand" begin
            rng = Random.MersenneTwister(42)
            q1 = nquatrand(rng)
            @test q1 isa Quaternion
            @test q1.norm

            q2 = nquatrand()
            @test q2 isa Quaternion
            @test q2.norm
        end

        @testset "rand($H)" for H in (QuaternionF32, QuaternionF64)
            rng = Random.MersenneTwister(42)
            q = rand(rng, H)
            @test q isa H
            @test !q.norm

            qs = rand(rng, H, 1000)
            @test eltype(qs) === H
            @test length(qs) == 1000
            xs = map(qs) do q
                return [real(q); imag_part(q)...]
            end
            xs_mean = sum(xs) / length(xs)
            xs_var = sum(x -> abs2.(x .- xs_mean), xs) / (length(xs) - 1)
            @test all(isapprox.(xs_mean, 0.5; atol=0.1))
            @test all(isapprox.(xs_var, 1 / 12; atol=0.01))
        end

        @testset "randn($H)" for H in (QuaternionF32, QuaternionF64)
            rng = Random.MersenneTwister(42)
            q = randn(rng, H)
            @test q isa H
            @test !q.norm

            qs = randn(rng, H, 10000)
            @test eltype(qs) === H
            @test length(qs) == 10000
            xs = map(qs) do q
                return [real(q); imag_part(q)...]
            end
            xs_mean = sum(xs) / length(xs)
            xs_var = sum(x -> abs2.(x .- xs_mean), xs) / (length(xs) - 1)
            @test all(isapprox.(xs_mean, 0; atol=0.1))
            @test all(isapprox.(xs_var, 1 / 4; atol=0.1))
        end
    end

    @testset "basic" begin
        q = randn(QuaternionF64)
        qnorm = normalize(q)
        @test real(q) === q.s
        @test_throws MethodError imag(q)
        @test @test_deprecated(Quaternions.imag(q)) == [q.v1, q.v2, q.v3]
        @test imag_part(q) === (q.v1, q.v2, q.v3)
        @test conj(q) === Quaternion(q.s, -q.v1, -q.v2, -q.v3, q.norm)
        @test conj(qnorm) === Quaternion(qnorm.s, -qnorm.v1, -qnorm.v2, -qnorm.v3, true)
        @test conj(conj(q)) === q
        @test conj(conj(qnorm)) === qnorm
        @test float(Quaternion(1, 2, 3, 4)) === float(Quaternion(1.0, 2.0, 3.0, 4.0))
        @test Quaternions.abs_imag(q) == abs(Quaternion(0, q.v1, q.v2, q.v3))
    end

    @testset "algebraic properties" begin
        for _ in 1:100, T in (Float32, Float64, Int32, Int64)
            if T <: Integer
                q, q1, q2, q3 = [Quaternion(rand((-T(100)):T(100), 4)...) for _ in 1:4]
                c1, c2 = [complex(rand((-T(100)):T(100), 2)...) for _ in 1:2]
            else
                q, q1, q2, q3 = randn(Quaternion{T}, 4)
                c1, c2 = randn(Complex{T}, 2)
            end

            # skewfield
            test_group(q1, q2, q3, +, zero(q), -)
            test_group(q1, q2, q3, *, one(q), inv)
            test_multiplicative(q1, q2, *, norm)

            # complex embedding
            test_multiplicative(c1, c2, *, Quaternion)
            test_multiplicative(c1, c2, +, Quaternion)
        end
    end

    @testset "isreal" begin
        @test isreal(Quaternion(1, 0, 0, 0))
        @test !isreal(Quaternion(2, 1, 0, 0))
        @test !isreal(Quaternion(2, 0, 1, 0))
        @test !isreal(Quaternion(2, 0, 0, 1))
    end

    @testset "iszero" begin
        @test iszero(Quaternion(0.0, 0.0, 0.0, 0.0))
        @test !iszero(Quaternion(1.0, 0.0, 0.0, 0.0))
        @test !iszero(Quaternion(0.0, 1.0, 0.0, 0.0))
        @test !iszero(Quaternion(0.0, 0.0, 1.0, 0.0))
        @test !iszero(Quaternion(0.0, 0.0, 0.0, 1.0))
        @test !iszero(Quaternion(0.0, 0.0, 0.0, 0.0, true))
    end

    @testset "isone" begin
        @test isone(Quaternion(1))
        @test !isone(Quaternion(-1))
        @test !isone(Quaternion(0, 1, 0, 0))
        @test !isone(Quaternion(1, 1, 0, 0))
        @test !isone(Quaternion(1, 0, 1, 0))
        @test !isone(Quaternion(1, 0, 0, 1))
    end

    @testset "isfinite" begin
        @test isfinite(Quaternion(1.0, 2.0, 3.0, 4.0))
        for value in (Inf, -Inf, NaN)
            @test !isfinite(Quaternion(value, 0.0, 0.0, 0.0))
            @test !isfinite(Quaternion(0.0, value, 0.0, 0.0))
            @test !isfinite(Quaternion(0.0, 0.0, value, 0.0))
            @test !isfinite(Quaternion(0.0, 0.0, 0.0, value))
            @test isfinite(Quaternion(fill(value, 4)..., true))
        end
    end

    @testset "isinf" begin
        @test !isinf(Quaternion(1.0, 2.0, 3.0, 4.0))
        @test !isinf(Quaternion(1.0, 2.0, 3.0, NaN))
        for inf in (Inf, -Inf)
            @test isinf(Quaternion(inf, 0.0, 0.0, 0.0))
            @test isinf(Quaternion(0.0, inf, 0.0, 0.0))
            @test isinf(Quaternion(0.0, 0.0, inf, 0.0))
            @test isinf(Quaternion(0.0, 0.0, 0.0, inf))
            @test !isinf(Quaternion(inf, inf, inf, inf, true))
        end
    end

    @testset "isnan" begin
        @test !isnan(Quaternion(1, 2, 3, 4))
        @test !isnan(Quaternion(1, 2, 3, Inf))
        @test !isnan(Quaternion(1, 2, 3, -Inf))
        @test isnan(Quaternion(NaN, 2, 3, 4))
        @test isnan(Quaternion(1, NaN, 3, 4))
        @test isnan(Quaternion(1, 2, NaN, 4))
        @test isnan(Quaternion(1, 2, 3, NaN))
    end

    @testset "/" begin
        for _ in 1:100
            q, q2 = randn(QuaternionF64, 2)
            x = randn()
            @test q / q ≈ q \ q ≈ one(q)
            @test q / q2 ≈ q * inv(q2)
            @test q2 \ q ≈ inv(q2) * q
            @test q / x ≈ x \ q ≈ inv(x) * q
        end
    end

    @testset "^" begin
        @testset "^(::Quaternion, ::Real)" begin
            for _ in 1:100
                q = randn(QuaternionF64)
                @test q^2.0 ≈ q * q
                @test q^1.0 ≈ q
                @test q^-1.0 ≈ inv(q)
                @test q^1.3 ≈ exp(1.3 * log(q))
                @test q^7.8 ≈ exp(7.8 * log(q))
                @test q^1.3f0 ≈ exp(1.3f0 * log(q))
                @test q^7.8f0 ≈ exp(7.8f0 * log(q))
            end
        end
        @testset "^(::Quaternion, ::Quaternion)" begin
            @test Quaternion(ℯ, 0, 0, 0)^Quaternion(0, 0, π / 2, 0) ≈ Quaternion(0, 0, 1, 0)
            @test Quaternion(3.5, 0, 0, 2.3)^Quaternion(0.2, 0, 0, 1.7) ≈ Quaternion(
                real((3.5 + 2.3im)^(0.2 + 1.7im)), 0, 0, imag((3.5 + 2.3im)^(0.2 + 1.7im))
            )
            for _ in 1:100
                q, p = randn(QuaternionF64, 2)
                @test q^p ≈ exp(p * log(q))
            end
        end
    end

    @testset "non-analytic functions" begin
        q, q2 = randn(Quaternion{Float64}, 2)
        unary_funs = [conj, abs, abs2, norm, sign]
        # since every quaternion is conjugate to a complex number,
        # one can establish correctness as follows:
        @testset for fun in unary_funs
            for _ in 1:100
                c = randn(ComplexF64)
                q = quat(c)
                @test @inferred(fun(q)) ≈ fun(c)
                @test q2 * fun(q) * inv(q2) ≈ fun(q2 * q * inv(q2))
            end
        end
    end

    @testset "extended complex analytic functions" begin
        # all complex analytic functions can be extended to the quaternions
        #! format: off
        unary_funs = [
            sqrt, inv, exp, exp2, exp10, expm1, log, log2, log10, log1p, cis,
            sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh,
            csc, sec, cot, acsc, asec, acot, csch, sech, coth, acsch, asech, acoth,
            sinpi, cospi,
        ]
        #! format: on
        # since every quaternion is conjugate to a complex number,
        # one can establish correctness as follows:
        @testset for fun in unary_funs
            q, q2 = randn(QuaternionF64, 2)
            for _ in 1:100
                c = randn(ComplexF64)
                q = quat(c)
                fun !== cis && @test @inferred(fun(q)) ≈ fun(c)
                @test q2 * fun(q) * inv(q2) ≈ fun(q2 * q * inv(q2))
            end
        end

        @testset "identities" begin
            for _ in 1:100
                q = randn(QuaternionF64)
                @test inv(q) * q ≈ q * inv(q) ≈ one(q)
                @test sqrt(q) * sqrt(q) ≈ q
                @test exp(log(q)) ≈ q
                @test exp(zero(q)) === one(q)
                @test log(one(q)) === zero(q)
                @test exp2(log2(q)) ≈ q
                @test exp10(log10(q)) ≈ q
                @test expm1(log1p(q)) ≈ q
                @test sinpi(q) ≈ sin(π * q)
                @test cospi(q) ≈ cos(π * q)
                @test all(sincos(q) .≈ (sin(q), cos(q)))
                @test all(sincos(zero(q)) .≈ (sin(zero(q)), cos(zero(q))))
                if VERSION ≥ v"1.6"
                    @test all(sincospi(q) .≈ (sinpi(q), cospi(q)))
                    @test all(sincospi(zero(q)) .≈ (sinpi(zero(q)), cospi(zero(q))))
                end
                @test tan(q) ≈ cos(q) \ sin(q) ≈ sin(q) / cos(q)
                @test tanh(q) ≈ cosh(q) \ sinh(q) ≈ sinh(q) / cosh(q)
                @testset for (f, finv) in [
                    (sin, csc),
                    (cos, sec),
                    (tan, cot),
                    (sinh, csch),
                    (cosh, sech),
                    (tanh, coth),
                ]
                    @test f(q) ≈ inv(finv(q))
                end
                @testset for (f, finv) in [
                    (asin, acsc),
                    (acos, asec),
                    (atan, acot),
                    (asinh, acsch),
                    (acosh, asech),
                    (atanh, acoth),
                ]
                    @test f(q) ≈ finv(inv(q))
                end
                @test cis(q) ≈ exp(normalize(q - real(q)) * q)
                VERSION ≥ v"1.6" && @test cispi(q) ≈ cis(π * q)
            end
        end

        @testset "additional properties" begin
            @testset "log" begin
                @test log(zero(QuaternionF64)) === Quaternion(-Inf, 0, 0, 0)
            end

            @testset "exp" begin
                @test exp(Quaternion(0, 0, 0, 0)) === Quaternion(1.0, 0.0, 0.0, 0.0, true)
                @test exp(Quaternion(2, 0, 0, 0)) === Quaternion(exp(2), 0, 0, 0, false)
                @test exp(Quaternion(0, 2, 0, 0)) === Quaternion(cos(2), sin(2), 0, 0, true)
                @test exp(Quaternion(0, 0, 2, 0)) === Quaternion(cos(2), 0, sin(2), 0, true)
                @test exp(Quaternion(0, 0, 0, 2)) === Quaternion(cos(2), 0, 0, sin(2), true)

                @test norm(exp(Quaternion(0, 0, 0, 0))) ≈ 1
                @test norm(exp(Quaternion(2, 0, 0, 0))) ≠ 1
                @test norm(exp(Quaternion(0, 2, 0, 0))) ≈ 1
                @test norm(exp(Quaternion(0, 0, 2, 0))) ≈ 1
                @test norm(exp(Quaternion(0, 0, 0, 2))) ≈ 1

                @test exp(Quaternion(0.0, 0.0, 0.0, 0.0)) ===
                    Quaternion(1.0, 0.0, 0.0, 0.0, true)
                @test exp(Quaternion(2.0, 0.0, 0.0, 0.0)) ===
                    Quaternion(exp(2), 0, 0, 0, false)
                @test exp(Quaternion(0.0, 2.0, 0.0, 0.0)) ===
                    Quaternion(cos(2), sin(2), 0, 0, true)
                @test exp(Quaternion(0.0, 0.0, 2.0, 0.0)) ===
                    Quaternion(cos(2), 0, sin(2), 0, true)
                @test exp(Quaternion(0.0, 0.0, 0.0, 2.0)) ===
                    Quaternion(cos(2), 0, 0, sin(2), true)

                @test norm(exp(Quaternion(0.0, 0.0, 0.0, 0.0))) ≈ 1
                @test norm(exp(Quaternion(2.0, 0.0, 0.0, 0.0))) ≠ 1
                @test norm(exp(Quaternion(0.0, 2.0, 0.0, 0.0))) ≈ 1
                @test norm(exp(Quaternion(0.0, 0.0, 2.0, 0.0))) ≈ 1
                @test norm(exp(Quaternion(0.0, 0.0, 0.0, 2.0))) ≈ 1

                @test exp(Quaternion(0, 0, 0, 0)) isa Quaternion{Float64}
                @test exp(Quaternion(0.0, 0, 0, 0)) isa Quaternion{Float64}
                @test exp(Quaternion(0//1, 0, 0, 0)) isa Quaternion{Float64}
                @test exp(Quaternion(BigFloat(0), 0, 0, 0)) isa Quaternion{BigFloat}

                # https://github.com/JuliaGeometry/Quaternions.jl/issues/39
                @testset "exp(::Quaternion{Int})" begin
                    @test exp(Quaternion(1, 1, 1, 1)) ≈ exp(Quaternion(1.0, 1.0, 1.0, 1.0))
                end
            end
        end
    end

    @testset "normalize" begin
        for _ in 1:100
            q = quatrand()
            qnorm = @inferred normalize(q)
            @test abs(qnorm) ≈ 1
            @test qnorm.norm
            @test q ≈ abs(q) * qnorm
            @test normalize(qnorm) === qnorm
        end
        @test_broken @inferred(normalize(Quaternion(1, 2, 3, 4)))
    end

    @testset "normalizea" begin
        for _ in 1:100
            q = quatrand()
            qnorm, a = @inferred normalizea(q)
            @test abs(qnorm) ≈ 1
            @test qnorm.norm
            @test a isa Real
            @test a ≈ abs(q)
            @test q ≈ a * qnorm
            @test normalizea(qnorm) === (qnorm, one(real(q)))
        end
        @test_broken @inferred(normalizea(Quaternion(1, 2, 3, 4)))
    end

    @testset "Quaternions.normalizeq" begin
        for _ in 1:100
            q = quatrand()
            @test Quaternions.normalizeq(q) === normalize(q)
        end
        @test Quaternions.normalizeq(zero(QuaternionF64)) == im
        @test_broken @inferred(Quaternions.normalizeq(Quaternion(1, 2, 3, 4)))
    end

    @testset "Quaternions.argq" begin
        for _ in 1:100
            q, q2 = randn(QuaternionF64, 2)
            @test q2 * Quaternions.argq(q) * inv(q2) ≈ Quaternions.argq(q2 * q * inv(q2))
            v = Quaternion(0, randn(3)...)
            @test Quaternions.argq(v) * norm(v) ≈ v
        end
    end

    @testset "rotations" begin
        @testset "qrotation" begin
            @test qrotation([0, 0, 0], 1.0) == Quaternion(1.0) # a zero axis should act like zero rotation
            @test qrotation([1, 0, 0], 0.0) == Quaternion(1.0)
            @test qrotation([0, 0, 0]) == Quaternion(1.0)
            qx = qrotation(view([1, 0, 0], :), pi / 4)
            @test qx * qx ≈ qrotation([1, 0, 0], pi / 2)
            @test qx^2 ≈ qrotation([1, 0, 0], pi / 2)

            # Regression test for
            # https://github.com/JuliaGeometry/Quaternions.jl/issues/8#issuecomment-610640094
            # this used to throw an error
            @testset "qrotation can handle arbitrary reals" begin
                @test qrotation([1, 0, 0], MyReal(1.5)) == qrotation([1, 0, 0], 1.5)
            end
        end

        @testset "rotationmatrix" begin
            theta = pi / 8
            qx = qrotation([1, 0, 0], theta)
            c = cos(theta)
            s = sin(theta)
            Rx = [1 0 0; 0 c -s; 0 s c]
            @test rotationmatrix(qx) ≈ Rx
            theta = pi / 6
            qy = qrotation([0, 1, 0], theta)
            c = cos(theta)
            s = sin(theta)
            Ry = [c 0 s; 0 1 0; -s 0 c]
            @test rotationmatrix(qy) ≈ Ry
            theta = 4pi / 3
            qz = qrotation([0, 0, 1], theta)
            c = cos(theta)
            s = sin(theta)
            Rz = [c -s 0; s c 0; 0 0 1]
            @test rotationmatrix(qz) ≈ Rz

            @test rotationmatrix(qx * qy * qz) ≈ Rx * Ry * Rz
            @test rotationmatrix(qy * qx * qz) ≈ Ry * Rx * Rz
            @test rotationmatrix(qz * qx * qy) ≈ Rz * Rx * Ry

            for _ in 1:100
                q1 = nquatrand()
                q2 = qrotation(rotationmatrix(q1), q1)
                @test q1 ≈ q2
            end
        end

        @testset "angle/axis/angleaxis" begin
            @test_throws ErrorException qrotation([0, 1], 0.1)
            @test_throws ErrorException qrotation([0, 1, 0, 0], 0.1)
            @test_throws ErrorException qrotation([0, 1])
            @test_throws ErrorException qrotation([0, 1, 0, 0])
            @test angle(qrotation([1, 0, 0], 0)) ≈ 0
            @test angle(qrotation([0, 1, 0], pi / 4)) ≈ pi / 4
            @test angle(qrotation([0, 0, 1], pi / 2)) ≈ pi / 2

            @testset "numerical stability of angle" begin
                ax = randn(3)
                for θ in [1e-9, π - 1e-9]
                    q = qrotation(ax, θ)
                    @test angle(q) ≈ θ
                end
            end

            @testset "qrotation and angleaxis inverse" begin
                for _ in 1:100
                    ax = randn(3)
                    ax = ax / norm(ax)
                    Θ = π * rand()
                    q = qrotation(ax, Θ)
                    @test angle(q) ≈ Θ
                    @test axis(q) ≈ ax
                    @test angleaxis(q)[1] ≈ Θ
                    @test angleaxis(q)[2] ≈ ax
                end
            end
        end

        @testset "slerp/linpol" begin
            @testset "q1=1" begin
                a = quat(1, 0, 0, 0.0, true)
                b = quat(0, 0, 0, 1.0, true)
                @test slerp(a, b, 0.0) ≈ a
                @test slerp(a, b, 1.0) ≈ b
                @test slerp(a, b, 0.5) ≈ qrotation([0, 0, 1], deg2rad(90))
                for _ in 1:100
                    q1 = quat(1, 0, 0, 0.0)
                    # there are numerical stability issues with slerp atm
                    θ = clamp(rand() * 3.5, deg2rad(5e-1), π)
                    ax = randn(3)
                    q2 = qrotation(ax, θ)
                    qsmall = qrotation(ax, cbrt(eps()))
                    t = rand()
                    slerp(q1, q2, 0.0) ≈ q1
                    @test slerp(q1, q2, 0.0) ≈ q1
                    @test slerp(q1, q2, 1.0) ≈ q2
                    @test slerp(q1, q2, t) ≈ qrotation(ax, t * θ)
                    @test norm(slerp(q1, q2, t)) ≈ 1
                    @test slerp(q1, q2, 0.5) ≈ qrotation(ax, 0.5 * θ)
                    @test slerp(q1, q1, 0.5) ≈ q1
                    @test slerp(q1, qsmall, 0.5) ≈ sign((q1 + qsmall) / 2)
                    @test linpol(q1, q2, 0.5) ≈ qrotation(ax, 0.5 * θ)
                    @test linpol(q1, q1, 0.5) ≈ q1
                    @test linpol(q1, qsmall, 0.5) ≈ sign((q1 + qsmall) / 2)
                end
            end

            @testset "conjugate invariance" begin
                for _ in 1:100
                    q, q1, q2 = randn(QuaternionF64, 3)
                    ⊗(s, t) = s * t * inv(s)
                    t = rand()
                    @test q ⊗ slerp(q1, q2, t) ≈ slerp(q ⊗ q1, q ⊗ q2, t)
                    @test q ⊗ linpol(q1, q2, t) ≈ linpol(q ⊗ q1, q ⊗ q2, t)
                end
            end
        end
    end

    @testset "sylvester/lyap" begin
        Ts = (Float64, QuaternionF64)
        Ttrips = [(Ta, Tb, Tc) for Ta in Ts for Tb in Ts for Tc in Ts]
        Ttrips = filter(x -> any(y -> y <: Quaternion, x), Ttrips)
        @testset "($Ta, $Tb, $Tc)" for (Ta, Tb, Tc) in Ttrips
            for _ in 1:100
                a = randn(Ta)
                b = randn(Tb)
                c = randn(Tc)
                x = @inferred sylvester(a, b, c)
                @test a * x + x * b ≈ -c
                x = @inferred sylvester(b, a, c)
                @test b * x + x * a ≈ -c
                @test iszero(sylvester(a, b, zero(c)))
                @test sylvester(a, zero(b), c) ≈ a \ -c
                @test sylvester(zero(a), b, c) ≈ -c / b
                @test iszero(sylvester(zero(a), b, zero(c)))
                @test iszero(sylvester(a, zero(b), zero(c)))
                @test iszero(sylvester(a, b, zero(c)))
                # @test isnan(sylvester(zero(a), zero(b), c))

                @test @inferred(lyap(a, c)) ≈ sylvester(a, a', c)
                @test @inferred(lyap(b, c)) ≈ sylvester(b, b', c)
                @test iszero(lyap(a, zero(c)))
            end
            @testset "nan/inf return same as for complex" begin
                Tza, Tzb, Tzc = map(
                    T -> T <: Quaternion ? complex(real(T)) : T, (Ta, Tb, Tc)
                )
                a, b = zero(Ta), zero(Tb)
                za, zb = zero(Tza), zero(Tzb)
                @testset for f in (one, zero, randn)
                    x = sylvester(a, b, f(Tc))
                    zx = sylvester(za, zb, f(Tzc))
                    if isinf(zx)
                        @test isinf(x)
                    elseif isnan(zx)
                        @test isnan(x)
                    end
                    if VERSION ≥ v"1.7"
                        x = lyap(a, f(Tc))
                        zx = lyap(za, f(Tzc))
                        if isinf(zx)
                            @test isinf(x)
                        elseif isnan(zx)
                            @test isnan(x)
                        end
                    end
                end
            end
        end
        @testset "rational" begin
            a = Quaternion(1, 2, 3, 4)
            b = Quaternion(1//2, 2//2, 3//2, 4//2)
            c = Quaternion(-1//2, 2//2, -4//2, -3//2)
            @test @inferred(sylvester(a, b, c)) isa Quaternion{Rational{Int}}
            @test @inferred(lyap(a, c)) isa Quaternion{Rational{Int}}
            a = randn(QuaternionF32)
            @test @inferred(sylvester(a, b, c)) isa QuaternionF32
            @test @inferred(lyap(a, c)) isa QuaternionF32
            null = zero(Quaternion{Rational{Int}})
            @test_throws DivideError sylvester(null, null, null)
            @test_throws DivideError lyap(null, null)
        end
    end
end


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

@doc raw"""EndpointAddress is a tuple that describes single IP address.

    IoK8sApiCoreV1EndpointAddress(;
        hostname=nothing,
        ip=nothing,
        nodeName=nothing,
        targetRef=nothing,
    )

    - hostname::String : The Hostname of this endpoint
    - ip::String : The IP of this endpoint. May not be loopback (127.0.0.0/8), link-local (169.254.0.0/16), or link-local multicast ((224.0.0.0/24). IPv6 is also accepted but not fully supported on all platforms. Also, certain kubernetes components, like kube-proxy, are not IPv6 ready.
    - nodeName::String : Optional: Node hosting this endpoint. This can be used to determine endpoints local to a node.
    - targetRef::IoK8sApiCoreV1ObjectReference : Reference to object providing the endpoint.
"""
mutable struct IoK8sApiCoreV1EndpointAddress <: SwaggerModel
    hostname::Any # spec type: Union{ Nothing, String } # spec name: hostname
    ip::Any # spec type: Union{ Nothing, String } # spec name: ip
    nodeName::Any # spec type: Union{ Nothing, String } # spec name: nodeName
    targetRef::Any # spec type: Union{ Nothing, IoK8sApiCoreV1ObjectReference } # spec name: targetRef

    function IoK8sApiCoreV1EndpointAddress(;hostname=nothing, ip=nothing, nodeName=nothing, targetRef=nothing)
        o = new()
        validate_property(IoK8sApiCoreV1EndpointAddress, Symbol("hostname"), hostname)
        setfield!(o, Symbol("hostname"), hostname)
        validate_property(IoK8sApiCoreV1EndpointAddress, Symbol("ip"), ip)
        setfield!(o, Symbol("ip"), ip)
        validate_property(IoK8sApiCoreV1EndpointAddress, Symbol("nodeName"), nodeName)
        setfield!(o, Symbol("nodeName"), nodeName)
        validate_property(IoK8sApiCoreV1EndpointAddress, Symbol("targetRef"), targetRef)
        setfield!(o, Symbol("targetRef"), targetRef)
        o
    end
end # type IoK8sApiCoreV1EndpointAddress

const _property_map_IoK8sApiCoreV1EndpointAddress = Dict{Symbol,Symbol}(Symbol("hostname")=>Symbol("hostname"), Symbol("ip")=>Symbol("ip"), Symbol("nodeName")=>Symbol("nodeName"), Symbol("targetRef")=>Symbol("targetRef"))
const _property_types_IoK8sApiCoreV1EndpointAddress = Dict{Symbol,String}(Symbol("hostname")=>"String", Symbol("ip")=>"String", Symbol("nodeName")=>"String", Symbol("targetRef")=>"IoK8sApiCoreV1ObjectReference")
Base.propertynames(::Type{ IoK8sApiCoreV1EndpointAddress }) = collect(keys(_property_map_IoK8sApiCoreV1EndpointAddress))
Swagger.property_type(::Type{ IoK8sApiCoreV1EndpointAddress }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_IoK8sApiCoreV1EndpointAddress[name]))}
Swagger.field_name(::Type{ IoK8sApiCoreV1EndpointAddress }, property_name::Symbol) =  _property_map_IoK8sApiCoreV1EndpointAddress[property_name]

function check_required(o::IoK8sApiCoreV1EndpointAddress)
    (getproperty(o, Symbol("ip")) === nothing) && (return false)
    true
end

function validate_property(::Type{ IoK8sApiCoreV1EndpointAddress }, name::Symbol, val)
end


text:
@testset "julia2latex" begin
    @test to_latex(to_math(:(2))) == "2"
    @test to_latex(to_math(:(20^30))) == "20^{30}"
    @test to_latex(to_math(:(1+1))) == "(1 + 1)"
    @test to_latex(to_math(:(1 <= 2))) == "(1 \\le 2)"
    @test to_latex(to_math(:(1 ± 4))) == "(1 \\pm 4)"
    @test to_latex(to_math(:(1*1*3))) == "(1 * 1 * 3)"
    @test to_latex(to_math(:(2^(1+1)))) == "2^{(1 + 1)}"
    @test to_latex(to_math(:(1+(2+3)))) == "(1 + (2 + 3))"
    @test to_latex(to_math(:(1/2))) == "\\frac{1}{2}"
    @test to_latex(to_math(:(1/(2+3)))) == "\\frac{1}{(2 + 3)}"
    @test to_latex(to_math(:(f(x)))) == "f(x)"
    @test to_latex(to_math(:(f(x,y)))) == "f(x ,  y)" #Not sure on the spacing here
    @test to_latex(to_math(:(sin(x)))) == "\\mathrm{sin}(x)"

    @test to_latex(to_math(:(a_b))) == "a_{b}"
    @test to_latex(to_math(:(a_bc))) == "a_{bc}"
    @test to_latex(to_math(:(a_b_c))) == "a_{b,c}"

    @test to_latex(to_math(:([1,2,3]))) == "\\left[\\begin{array}{ccc}\n1\\\\2\\\\3\n\\end{array}\\right]"
    @test to_latex(to_math(:([1;2;3]))) == "\\left[\\begin{array}{ccc}\n1\\\\2\\\\3\n\\end{array}\\right]"
    @test to_latex(to_math(:([1 10 100;2 20 200])))  == "\\left[\\begin{array}{cc}\n1 & 10 & 100\\\\2 & 20 & 200\n\\end{array}\\right]"
    #@test to_latex(to_math(:())) == ""

    @test to_latex(to_math(:(exp(a+b)))) == "\\mathrm{exp}(a + b)"

    @test to_latex(to_math(:(-(a+b)))) == "-(a + b)"
end


text:
module GraphQL
  export DEFAULT_QUERY
  export GraphQLServer
  export GraphQLClient, QueryOptions, query
  export Lexer, advanceLexer

  include("./Types.jl")     ;using .Types
  include("./Language.jl")  ;using .Language
  include("./Execute.jl")   ;using .Execute
  include("./Client.jl")    ;using .Client
  include("./Server.jl")    ;using .Server
end