From 942ee9400d378e763402bb5723368e5493e66e0d Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Fri, 18 May 2018 20:15:35 -0700 Subject: [PATCH 1/4] Updates for Julia 0.7 This raises the minimum required Julia version to 0.6 release, which is required for any new tags in METADATA, and adds a dependency on Compat to support Julia 0.7. It also fixes all deprecation warnings emitted on Julia 0.7 and adds 0.7 testing to CI. --- .travis.yml | 1 + REQUIRE | 3 +- src/DeepDiffs.jl | 15 +++++-- src/arrays.jl | 19 +++------ src/dicts.jl | 19 +++------ src/strings.jl | 22 ++++------ test/REQUIRE | 1 - test/display.jl | 102 ++++++++++++++--------------------------------- test/runtests.jl | 12 ++++-- 9 files changed, 72 insertions(+), 122 deletions(-) delete mode 100644 test/REQUIRE diff --git a/.travis.yml b/.travis.yml index 1e73104..03c88c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ os: - osx julia: - 0.6 + - nightly notifications: email: false # uncomment the following lines to override the default test script diff --git a/REQUIRE b/REQUIRE index f194848..913499f 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1 +1,2 @@ -julia 0.6.0-pre +julia 0.6 +Compat 0.62.0 diff --git a/src/DeepDiffs.jl b/src/DeepDiffs.jl index 8bf1884..f28b047 100644 --- a/src/DeepDiffs.jl +++ b/src/DeepDiffs.jl @@ -1,8 +1,18 @@ module DeepDiffs +using Compat + export deepdiff, added, removed, changed, before, after export SimpleDiff, VectorDiff, StringDiff, DictDiff +# Helper function for comparing two instances of a type for equality by field +function fieldequal(x::T, y::T) where T + for f in fieldnames(T) + getfield(x, f) == getfield(y, f) || return false + end + true +end + """ diff = deepdiff(obj1, obj2) @@ -16,13 +26,12 @@ function deepdiff end abstract type DeepDiff end # fallback diff that just stores two values -type SimpleDiff{T1, T2} <: DeepDiff +struct SimpleDiff{T1, T2} <: DeepDiff before::T1 after::T2 end -import Base: == -==(lhs::SimpleDiff, rhs::SimpleDiff) = lhs.before == rhs.before && lhs.after == rhs.after +Base.:(==)(lhs::SimpleDiff, rhs::SimpleDiff) = fieldequal(lhs, rhs) before(d::SimpleDiff) = d.before after(d::SimpleDiff) = d.after diff --git a/src/arrays.jl b/src/arrays.jl index f2a2b63..6473ac6 100644 --- a/src/arrays.jl +++ b/src/arrays.jl @@ -1,4 +1,4 @@ -type VectorDiff{T1, T2} <: DeepDiff +struct VectorDiff{T1, T2} <: DeepDiff before::T1 after::T2 removed::Vector{Int} @@ -11,14 +11,7 @@ removed(diff::VectorDiff) = diff.removed added(diff::VectorDiff) = diff.added changed(diff::VectorDiff) = Int[] -function ==(d1::VectorDiff, d2::VectorDiff) - d1.before == d2.before || return false - d1.after == d2.after || return false - d1.removed == d2.removed || return false - d1.added == d2.added || return false - - true -end +Base.:(==)(d1::VectorDiff, d2::VectorDiff) = fieldequal(d1, d2) # diffing an array is an application of the Longest Common Subsequence problem: # https://en.wikipedia.org/wiki/Longest_common_subsequence_problem @@ -103,10 +96,10 @@ function Base.show(io::IO, diff::VectorDiff) visitall(diff) do idx, state, last if state == :removed printitem(io, from[idx], :red, "(-)") - last || print_with_color(:red, io, ", ") + last || printstyled(io, ", ", color=:red) elseif state == :added printitem(io, to[idx], :green, "(+)") - last || print_with_color(:green, io, ", ") + last || printstyled(io, ", ", color=:green) else printitem(io, from[idx]) last || print(io, ", ") @@ -117,8 +110,8 @@ end # prefix is printed if we're not using color function printitem(io, v, color=:normal, prefix="") - if(Base.have_color) - print_with_color(color, io, string(v)) + if Base.have_color + printstyled(io, v, color=color) else print(io, prefix, v) end diff --git a/src/dicts.jl b/src/dicts.jl index d5331d0..b0574ed 100644 --- a/src/dicts.jl +++ b/src/dicts.jl @@ -1,4 +1,4 @@ -type DictDiff{T1, KT1, T2, KT2} <: DeepDiff +struct DictDiff{T1, KT1, T2, KT2} <: DeepDiff before::T1 after::T2 removed::Set{KT1} @@ -13,18 +13,9 @@ removed(diff::DictDiff) = diff.removed added(diff::DictDiff) = diff.added changed(diff::DictDiff) = diff.changed -function ==(lhs::DictDiff, rhs::DictDiff) - lhs.before == rhs.before || return false - lhs.after == rhs.after || return false - lhs.removed == rhs.removed || return false - lhs.added == rhs.added || return false - lhs.changed == rhs.changed || return false - lhs.unchanged == rhs.unchanged || return false +Base.:(==)(lhs::DictDiff, rhs::DictDiff) = fieldequal(lhs, rhs) - true -end - -function deepdiff(X::Associative, Y::Associative) +function deepdiff(X::AbstractDict, Y::AbstractDict) xkeys = Set(keys(X)) ykeys = Set(keys(Y)) bothkeys = intersect(xkeys, ykeys) @@ -101,7 +92,7 @@ function diffprint(io, d::DictDiff, indent=0) print(io, inspace ^ indent, ")") end -function prettyprint(io, d::Associative, linemarker, indent) +function prettyprint(io, d::AbstractDict, linemarker, indent) println(io, "Dict(") for p in d print(io, linemarker, inspace ^ (indent+1)) @@ -117,7 +108,7 @@ function prettyprint(io, p::Pair, linemarker, indent) prettyprint(io, p[2], linemarker, indent) end -function prettyprint{T1, T2<:DictDiff}(io, p::Pair{T1, T2}, linemarker, indent) +function prettyprint(io, p::Pair{<:Any, <:DictDiff}, linemarker, indent) prettyprint(io, p[1], linemarker, indent) print(io, " => ") diffprint(io, p[2], indent) diff --git a/src/strings.jl b/src/strings.jl index c303e33..b232c5e 100644 --- a/src/strings.jl +++ b/src/strings.jl @@ -1,19 +1,19 @@ # used for single-line strings -type StringDiff{T1, T2} <: DeepDiff +struct StringDiff{T1, T2} <: DeepDiff before::T1 after::T2 diff::VectorDiff end # used for multi-line strings -type StringLineDiff{T1, T2} <: DeepDiff +struct StringLineDiff{T1, T2} <: DeepDiff before::T1 after::T2 diff::VectorDiff end function deepdiff(X::AbstractString, Y::AbstractString) - if contains(X, "\n") || contains(Y, "\n") + if occursin("\n", X) || occursin("\n", Y) # we'll compare hashes of each line rather than the text itself, because # these comparisons are done many times xhashes = map(hash, split(X, '\n')) @@ -33,13 +33,7 @@ added(diff::AllStringDiffs) = added(diff.diff) removed(diff::AllStringDiffs) = removed(diff.diff) changed(diff::AllStringDiffs) = [] -function =={T<:AllStringDiffs}(d1::T, d2::T) - d1.before == d2.before || return false - d1.after == d2.after || return false - d1.diff == d2.diff || return false - - true -end +Base.:(==)(d1::T, d2::T) where {T<:AllStringDiffs} = fieldequal(d1, d2) function Base.show(io::IO, diff::StringLineDiff) xlines = split(diff.before, '\n') @@ -47,9 +41,9 @@ function Base.show(io::IO, diff::StringLineDiff) println(io, "\"\"\"") visitall(diff.diff) do idx, state, last if state == :removed - print_with_color(:red, io, "- ", escape_string(xlines[idx])) + printstyled(io, "- ", escape_string(xlines[idx]), color=:red) elseif state == :added - print_with_color(:green, io, "+ ", escape_string(ylines[idx])) + printstyled(io, "+ ", escape_string(ylines[idx]), color=:green) else print(io, " ", escape_string(xlines[idx])) end @@ -83,9 +77,9 @@ function Base.show(io::IO, diff::StringDiff) end end if state == :removed - print_with_color(:red, io, string(xchars[idx])) + printstyled(io, string(xchars[idx]), color=:red) elseif state == :added - print_with_color(:green, io, string(ychars[idx])) + printstyled(io, string(ychars[idx]), color=:green) else print(io, xchars[idx]) end diff --git a/test/REQUIRE b/test/REQUIRE deleted file mode 100644 index 557b023..0000000 --- a/test/REQUIRE +++ /dev/null @@ -1 +0,0 @@ -TestSetExtensions diff --git a/test/display.jl b/test/display.jl index fde0d6b..24f2014 100644 --- a/test/display.jl +++ b/test/display.jl @@ -17,16 +17,9 @@ buf = IOBuffer() eval(Base, :(have_color=true)) - # in 0.6 colored output is no longer bold as of PR #18628 - if VERSION < v"0.6.0-dev.1574" - expected1 = """ - [2, 3, 4, 1, 2, 7, 3, 5]""" - expected2 = """[1, 2]""" - else - expected1 = """ - [2, 3, 4, 1, 2, 7, 3, 5]""" - expected2 = """[1, 2]""" - end + expected1 = """ + [2, 3, 4, 1, 2, 7, 3, 5]""" + expected2 = """[1, 2]""" @testset "Color Diffs" begin display(TextDisplay(buf), d1) @test String(take!(buf)) == expected1 @@ -86,48 +79,25 @@ eval(Base, :(have_color=true)) buf = IOBuffer() display(TextDisplay(buf), d) - # in 0.6 colored output is no longer bold as of PR #18628 - if VERSION < v"0.6.0-dev.1574" - expected = """ - Dict( - :a => "a", - :dict1 => Dict( - :c => 3, - :a => 1, - :b => 2, - ), - - :c => "c", -  :list => [1, 2, 4, 3], - :b => "bd", - :dict2 => Dict( - :a => 1, - - :b => 2, - - :c => 3, - + :c => 4, -  ), - + :e => "e", - )""" - else - expected = """ - Dict( - :a => "a", - :dict1 => Dict( - :c => 3, - :a => 1, - :b => 2, - ), - - :c => "c", -  :list => [1, 2, 4, 3], - :b => "bd", - :dict2 => Dict( - :a => 1, - - :b => 2, - - :c => 3, - + :c => 4, -  ), - + :e => "e", - )""" - end + expected = """ + Dict( + :a => "a", + :dict1 => Dict( + :c => 3, + :a => 1, + :b => 2, + ), + - :c => "c", +  :list => [1, 2, 4, 3], + :b => "bd", + :dict2 => Dict( + :a => 1, + - :b => 2, + - :c => 3, + + :c => 4, +  ), + + :e => "e", + )""" # This test is broken because the specifics of how the ANSI color # codes are printed change based on the order, which changes with # different julia versions. @@ -187,26 +157,14 @@ buf = IOBuffer() @testset "Color Display" begin eval(Base, :(have_color=true)) - # in 0.6 colored output is no longer bold as of PR #18628 - if VERSION < v"0.6.0-dev.1574" - expected = """ - \"\"\" - differences can - - be hard to find - - in - + be hurd to find - multiline - output\"\"\"""" - else - expected = """ - \"\"\" - differences can - - be hard to find - - in - + be hurd to find - multiline - output\"\"\"""" - end + expected = """ + \"\"\" + differences can + - be hard to find + - in + + be hurd to find + multiline + output\"\"\"""" display(TextDisplay(buf), diff) @test String(take!(buf)) == expected end diff --git a/test/runtests.jl b/test/runtests.jl index 51d2ab0..99d72ab 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,7 +1,11 @@ using DeepDiffs -using Base.Test -using TestSetExtensions +using Compat +using Compat.Test -@testset DottedTestSet "DeepDiff Tests" begin - @includetests ARGS +@testset "DeepDiff Tests" begin + include("arrays.jl") + include("dicts.jl") + include("display.jl") + include("simplediff.jl") + include("strings.jl") end From d75d12b039b60b9053bc74ba9cac8388bf6b4d68 Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Fri, 18 May 2018 20:19:48 -0700 Subject: [PATCH 2/4] Modernize the AppVeyor setup --- appveyor.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index e374f40..90029fa 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,14 @@ environment: matrix: + - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe" - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe" + - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe" + - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe" + +branches: + only: + - master + - /release-.*/ notifications: - provider: Email @@ -10,6 +18,11 @@ notifications: install: - ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12" +# if there's a newer build queued for the same PR, cancel this one + - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod ` + https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | ` + Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { ` + throw "There are newer queued builds for this pull request, failing early." } # Download most recent Julia Windows binary - ps: (new-object net.webclient).DownloadFile( $env:JULIA_URL, @@ -24,4 +37,4 @@ build_script: Pkg.clone(pwd(), \"DeepDiffs\"); Pkg.build(\"DeepDiffs\")" test_script: - - C:\projects\julia\bin\julia -e "Pkg.test(\"DeepDiffs\")" + - C:\projects\julia\bin\julia --check-bounds=yes -e "Pkg.test(\"DeepDiffs\")" From d02740f4c5afbeeb7a76d42d8c247fdb89f69cbd Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Sat, 19 May 2018 11:28:01 -0700 Subject: [PATCH 3/4] Use IOContexts instead of Base.have_color on 0.7 In Julia 0.7, whether an IO object supports color is a property of its context; Base.have_color refers only to whether Julia was launched with --color=yes. In 0.6, controlling color requires manipulating that global flag. Thus we'll hack around the difference with version checking. --- src/DeepDiffs.jl | 7 ++++++ src/arrays.jl | 2 +- src/strings.jl | 4 +-- test/display.jl | 65 +++++++++++++++++++++++++++++------------------- test/runtests.jl | 3 +++ 5 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/DeepDiffs.jl b/src/DeepDiffs.jl index f28b047..f534f7d 100644 --- a/src/DeepDiffs.jl +++ b/src/DeepDiffs.jl @@ -13,6 +13,13 @@ function fieldequal(x::T, y::T) where T true end +# Determine whether color is supported by the given stream +@static if VERSION >= v"0.7.0-DEV.3077" + hascolor(io::IO) = get(IOContext(io), :color, false) +else + hascolor(io::IO) = Base.have_color +end + """ diff = deepdiff(obj1, obj2) diff --git a/src/arrays.jl b/src/arrays.jl index 6473ac6..4f182e6 100644 --- a/src/arrays.jl +++ b/src/arrays.jl @@ -110,7 +110,7 @@ end # prefix is printed if we're not using color function printitem(io, v, color=:normal, prefix="") - if Base.have_color + if hascolor(io) printstyled(io, v, color=color) else print(io, prefix, v) diff --git a/src/strings.jl b/src/strings.jl index b232c5e..a92d7af 100644 --- a/src/strings.jl +++ b/src/strings.jl @@ -62,7 +62,7 @@ function Base.show(io::IO, diff::StringDiff) print(io, "\"") visitall(diff.diff) do idx, state, last - if !Base.have_color + if !hascolor(io) # check to see if we need to close a block if laststate == :removed && state != :removed print(io, "-}") @@ -85,7 +85,7 @@ function Base.show(io::IO, diff::StringDiff) end laststate = state end - if !Base.have_color + if !hascolor(io) if laststate == :removed print(io, "-}") elseif laststate == :added diff --git a/test/display.jl b/test/display.jl index 24f2014..3c34ae7 100644 --- a/test/display.jl +++ b/test/display.jl @@ -1,4 +1,21 @@ @testset "Display tests" begin + # Return a stream with color set as specified. On 0.6 this requires setting + # a global flag, and the :color property in the IOContext has no effect. + function setcolor(yn::Bool) + if VERSION < v"0.7.0-DEV.3077" + eval(Base, :(have_color = $yn)) + end + IOContext(IOBuffer(), :color=>yn) + end + + function resetcolor() + global orig_color + if VERSION < v"0.7.0-DEV.3077" + eval(Base, :(have_color = $orig_color)) + end + nothing + end + # check dictionary print output. This is a little complicated because # the ordering isn't specified. To work around this we just split # up both into lines and make sure they have the same lines in some ordering. @@ -10,34 +27,33 @@ explines = sort(split(expected, "\n")) @test outlines == explines end - orig_color = Base.have_color + @testset "Array diffs print correctly" begin d1 = deepdiff([1, 2, 7, 3], [2, 3, 4, 1, 2, 3, 5]) d2 = deepdiff([1], [2]) - buf = IOBuffer() - eval(Base, :(have_color=true)) + buf = setcolor(true) expected1 = """ [2, 3, 4, 1, 2, 7, 3, 5]""" expected2 = """[1, 2]""" @testset "Color Diffs" begin display(TextDisplay(buf), d1) - @test String(take!(buf)) == expected1 + @test String(take!(buf.io)) == expected1 display(TextDisplay(buf), d2) - @test String(take!(buf)) == expected2 + @test String(take!(buf.io)) == expected2 end - eval(Base, :(have_color=false)) + buf = setcolor(false) @testset "No-Color Diffs" begin display(TextDisplay(buf), d1) - @test String(take!(buf)) == """ + @test String(take!(buf.io)) == """ [(+)2, (+)3, (+)4, 1, 2, (-)7, 3, (+)5]""" display(TextDisplay(buf), d2) - @test String(take!(buf)) == """ + @test String(take!(buf.io)) == """ [(-)1, (+)2]""" end - eval(Base, :(have_color=$orig_color)) + resetcolor() end @testset "Dict diffs print correctly" begin @@ -76,8 +92,7 @@ ) @testset "Color Diffs" begin - eval(Base, :(have_color=true)) - buf = IOBuffer() + buf = setcolor(true) display(TextDisplay(buf), d) expected = """ Dict( @@ -101,11 +116,10 @@ # This test is broken because the specifics of how the ANSI color # codes are printed change based on the order, which changes with # different julia versions. - @test_skip String(take!(buf)) == expected + @test_skip String(take!(buf.io)) == expected end @testset "No-Color Diffs" begin - eval(Base, :(have_color=false)) - buf = IOBuffer() + buf = setcolor(false) display(TextDisplay(buf), d) expected = """ Dict( @@ -126,19 +140,19 @@ ), + :e => "e", )""" - checkdictprint(String(take!(buf)), expected) + checkdictprint(String(take!(buf.io)), expected) end - eval(Base, :(have_color=$orig_color)) + + resetcolor() end @testset "single-line strings display correctly" begin # this test is just to handle some cases that don't get exercised elsewhere diff = deepdiff("abc", "adb") - buf = IOBuffer() - eval(Base, :(have_color=false)) + buf = setcolor(false) display(TextDisplay(buf), diff) - @test String(take!(buf)) == "\"a{+d+}b{-c-}\"" - eval(Base, :(have_color=true)) + @test String(take!(buf.io)) == "\"a{+d+}b{-c-}\"" + resetcolor() end @testset "Multi-line strings display correctly" begin @@ -154,9 +168,8 @@ multiline output""" diff = deepdiff(s1, s2) - buf = IOBuffer() @testset "Color Display" begin - eval(Base, :(have_color=true)) + buf = setcolor(true) expected = """ \"\"\" differences can @@ -166,12 +179,12 @@ multiline output\"\"\"""" display(TextDisplay(buf), diff) - @test String(take!(buf)) == expected + @test String(take!(buf.io)) == expected end @testset "No-Color Display" begin - eval(Base, :(have_color=false)) + buf = setcolor(false) display(TextDisplay(buf), diff) - @test String(take!(buf)) == """ + @test String(take!(buf.io)) == """ \"\"\" differences can - be hard to find @@ -180,6 +193,6 @@ multiline output\"\"\"""" end - eval(Base, :(have_color=$orig_color)) + resetcolor() end end diff --git a/test/runtests.jl b/test/runtests.jl index 99d72ab..b7c2f13 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,6 +2,9 @@ using DeepDiffs using Compat using Compat.Test +# Capture the original state of the global flag +orig_color = Base.have_color + @testset "DeepDiff Tests" begin include("arrays.jl") include("dicts.jl") From caa0a75b7fe8e91613684e508674177d9cf588ea Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Fri, 25 May 2018 19:28:17 -0700 Subject: [PATCH 4/4] Only assign to Base.have_color if it exists --- test/runtests.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index b7c2f13..d5d08fc 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,8 +2,10 @@ using DeepDiffs using Compat using Compat.Test -# Capture the original state of the global flag -orig_color = Base.have_color +if isdefined(Base, :have_color) + # Capture the original state of the global flag + orig_color = Base.have_color +end @testset "DeepDiff Tests" begin include("arrays.jl")