diff --git a/test/async.jl b/test/async.jl new file mode 100644 index 0000000..74831c8 --- /dev/null +++ b/test/async.jl @@ -0,0 +1,107 @@ +finished_async_tests = RemoteChannel() + +@async begin + s = listen(7777) + s = accept(s) + + Base.start_reading(s) + + @test JSON.parse(s) != nothing # a + @test JSON.parse(s) != nothing # b + validate_c(s) # c + @test JSON.parse(s) != nothing # d + validate_svg_tviewer_menu(s) # svg_tviewer_menu + @test JSON.parse(s) != nothing # gmaps + @test JSON.parse(s) != nothing # colors1 + @test JSON.parse(s) != nothing # colors2 + @test JSON.parse(s) != nothing # colors3 + @test JSON.parse(s) != nothing # twitter + @test JSON.parse(s) != nothing # facebook + validate_flickr(s) # flickr + @test JSON.parse(s) != nothing # youtube + @test JSON.parse(s) != nothing # iphone + @test JSON.parse(s) != nothing # customer + @test JSON.parse(s) != nothing # product + @test JSON.parse(s) != nothing # interop + validate_unicode(s) # unicode + @test JSON.parse(s) != nothing # issue5 + @test JSON.parse(s) != nothing # dollars + @test JSON.parse(s) != nothing # brackets + + put!(finished_async_tests, nothing) +end + +w = connect("localhost", 7777) + +@test JSON.parse(a) != nothing +write(w, a) + +@test JSON.parse(b) != nothing +write(w, b) + +validate_c(c) +write(w, c) + +@test JSON.parse(d) != nothing +write(w, d) + +validate_svg_tviewer_menu(svg_tviewer_menu) +write(w, svg_tviewer_menu) + +@test JSON.parse(gmaps) != nothing +write(w, gmaps) + +@test JSON.parse(colors1) != nothing +write(w, colors1) + +@test JSON.parse(colors2) != nothing +write(w, colors2) + +@test JSON.parse(colors3) != nothing +write(w, colors3) + +@test JSON.parse(twitter) != nothing +write(w, twitter) + +@test JSON.parse(facebook) != nothing +write(w, facebook) + +validate_flickr(flickr) +write(w, flickr) + +@test JSON.parse(youtube) != nothing +write(w, youtube) + +@test JSON.parse(iphone) != nothing +write(w, iphone) + +@test JSON.parse(customer) != nothing +write(w, customer) + +@test JSON.parse(product) != nothing +write(w, product) + +@test JSON.parse(interop) != nothing +write(w, interop) + +validate_unicode(unicode) +write(w, unicode) + +# issue #5 +issue5 = "[\"A\",\"B\",\"C\\n\"]" +JSON.parse(issue5) +write(w, issue5) + +# $ escaping issue +dollars = ["all of the \$s", "µniçø∂\$"] +json_dollars = json(dollars) +@test JSON.parse(json_dollars) != nothing +write(w, json_dollars) + +# unmatched brackets +brackets = Dict("foo"=>"ba}r", "be}e]p"=>"boo{p") +json_brackets = json(brackets) +@test JSON.parse(json_brackets) != nothing +write(w, json_dollars) + +fetch(finished_async_tests) diff --git a/test/enum.jl b/test/enum.jl new file mode 100644 index 0000000..ead3d99 --- /dev/null +++ b/test/enum.jl @@ -0,0 +1,4 @@ +@enum Animal zebra aardvark horse +@test json(zebra) == "\"zebra\"" +@test json([aardvark, horse, Dict("z" => zebra)]) == + "[\"aardvark\",\"horse\",{\"z\":\"zebra\"}]" diff --git a/test/indentation.jl b/test/indentation.jl new file mode 100644 index 0000000..98fa5f0 --- /dev/null +++ b/test/indentation.jl @@ -0,0 +1,10 @@ +# check indented json has same final value as non indented +fb = JSON.parse(facebook) +fbjson1 = json(fb, 2) +fbjson2 = json(fb) +@test JSON.parse(fbjson1) == JSON.parse(fbjson2) + +ev = JSON.parse(svg_tviewer_menu) +ejson1 = json(ev, 2) +ejson2 = json(ev) +@test JSON.parse(ejson1) == JSON.parse(ejson2) diff --git a/test/json-samples.jl b/test/json-samples.jl index 8e2b791..5750da7 100644 --- a/test/json-samples.jl +++ b/test/json-samples.jl @@ -37,32 +37,41 @@ b="{ } " -c="{\"widget\": { - \"debug\": \"on\", - \"window\": { - \"title\": \"Sample Konfabulator Widget\", - \"name\": \"main_window\", - \"width\": 500, - \"height\": 500 +const c = """ +{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 }, - \"image\": { - \"src\": \"Images/Sun.png\", - \"name\": \"sun1\", - \"hOffset\": 250, - \"vOffset\": 250, - \"alignment\": \"center\" + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" }, - \"text\": { - \"data\": \"Click Here\", - \"size\": 36.5, - \"style\": \"bold\", - \"name\": \"text1\", - \"hOffset\": 250, - \"vOffset\": 100, - \"alignment\": \"center\", - \"onMouseUp\": \"sun1.opacity = (sun1.opacity / 100) * 90;\" + "text": { + "data": "Click Here", + "size": 36.5, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" } -}}" +}}""" +function validate_c(c) + j = JSON.parse(c) + @test j != nothing + @test typeof(j["widget"]["image"]["hOffset"]) == Int64 + @test j["widget"]["image"]["hOffset"] == 250 + @test typeof(j["widget"]["text"]["size"]) == Float64 + @test j["widget"]["text"]["size"] == 36.5 +end d = "{\"web-app\": { \"servlet\": [ @@ -153,33 +162,48 @@ d = "{\"web-app\": { \"taglib-uri\": \"cofax.tld\", \"taglib-location\": \"/WEB-INF/tlds/cofax.tld\"}}}" -e="{\"menu\": { - \"header\": \"SVG\\tViewer\\u03b1\", - \"items\": [ - {\"id\": \"Open\"}, - {\"id\": \"OpenNew\", \"label\": \"Open New\"}, +const svg_tviewer_menu = """ +{"menu": { + "header": "SVG\\tViewer\\u03b1", + "items": [ + {"id": "Open"}, + {"id": "OpenNew", "label": "Open New"}, null, - {\"id\": \"ZoomIn\", \"label\": \"Zoom In\"}, - {\"id\": \"ZoomOut\", \"label\": \"Zoom Out\"}, - {\"id\": \"OriginalView\", \"label\": \"Original View\"}, + {"id": "ZoomIn", "label": "Zoom In"}, + {"id": "ZoomOut", "label": "Zoom Out"}, + {"id": "OriginalView", "label": "Original View"}, null, - {\"id\": \"Quality\"}, - {\"id\": \"Pause\"}, - {\"id\": \"Mute\"}, + {"id": "Quality"}, + {"id": "Pause"}, + {"id": "Mute"}, null, - {\"id\": \"Find\", \"label\": \"Find...\"}, - {\"id\": \"FindAgain\", \"label\": \"Find Again\"}, - {\"id\": \"Copy\"}, - {\"id\": \"CopyAgain\", \"label\": \"Copy Again\"}, - {\"id\": \"CopySVG\", \"label\": \"Copy SVG\"}, - {\"id\": \"ViewSVG\", \"label\": \"View SVG\"}, - {\"id\": \"ViewSource\", \"label\": \"View Source\"}, - {\"id\": \"SaveAs\", \"label\": \"Save As\"}, + {"id": "Find", "label": "Find..."}, + {"id": "FindAgain", "label": "Find Again"}, + {"id": "Copy"}, + {"id": "CopyAgain", "label": "Copy Again"}, + {"id": "CopySVG", "label": "Copy SVG"}, + {"id": "ViewSVG", "label": "View SVG"}, + {"id": "ViewSource", "label": "View Source"}, + {"id": "SaveAs", "label": "Save As"}, null, - {\"id\": \"Help\"}, - {\"id\": \"About\", \"label\": \"About Adobe SVG Viewer...\"} + {"id": "Help"}, + {"id": "About", "label": "About Adobe SVG Viewer..."} ] -}}" +}}""" +function validate_svg_tviewer_menu(str) + j = JSON.parse(str) + @test j != nothing + @test typeof(j) == Dict{String, Any} + @test length(j) == 1 + @test typeof(j["menu"]) == Dict{String, Any} + @test length(j["menu"]) == 2 + @test j["menu"]["header"] == "SVG\tViewerα" + @test isa(j["menu"]["items"], Vector{Any}) + @test length(j["menu"]["items"]) == 22 + @test j["menu"]["items"][3] == nothing + @test j["menu"]["items"][2]["id"] == "OpenNew" + @test j["menu"]["items"][2]["label"] == "Open New" +end #Example JSON strings from http://www.jquery4u.com/json/10-example-json-files/ @@ -343,27 +367,33 @@ facebook= "{ ] }" -flickr = "{ - \"title\": \"Talk On Travel Pool\", - \"link\": \"http://www.flickr.com/groups/talkontravel/pool/\", - \"description\": \"Travel and vacation photos from around the world.\", - \"modified\": \"2009-02-02T11:10:27Z\", - \"generator\": \"http://www.flickr.com/\", - \"totalItems\":222, - \"items\": [ +const flickr = """{ + "title": "Talk On Travel Pool", + "link": "http://www.flickr.com/groups/talkontravel/pool/", + "description": "Travel and vacation photos from around the world.", + "modified": "2009-02-02T11:10:27Z", + "generator": "http://www.flickr.com/", + "totalItems":222, + "items": [ { - \"title\": \"View from the hotel\", - \"link\": \"http://www.flickr.com/photos/33112458@N08/3081564649/in/pool-998875@N22\", - \"media\": {\"m\":\"http://farm4.static.flickr.com/3037/3081564649_4a6569750c_m.jpg\"}, - \"date_taken\": \"2008-12-04T04:43:03-08:00\", - \"description\": \"

Talk On Travel<\/a> has added a photo to the pool:<\/p>

\\\"View<\/a><\/p> \", - \"published\": \"2008-12-04T12:43:03Z\", - \"author\": \"nobody@flickr.com (Talk On Travel)\", - \"author_id\": \"33112458@N08\", - \"tags\": \"spain dolphins tenerife canaries lagomera aqualand playadelasamericas junglepark losgigantos loscristines talkontravel\" + "title": "View from the hotel", + "link": "http://www.flickr.com/photos/33112458@N08/3081564649/in/pool-998875@N22", + "media": {"m":"http://farm4.static.flickr.com/3037/3081564649_4a6569750c_m.jpg"}, + "date_taken": "2008-12-04T04:43:03-08:00", + "description": "

Talk On Travel<\/a> has added a photo to the pool:<\/p>

\\"View<\/a><\/p> ", + "published": "2008-12-04T12:43:03Z", + "author": "nobody@flickr.com (Talk On Travel)", + "author_id": "33112458@N08", + "tags": "spain dolphins tenerife canaries lagomera aqualand playadelasamericas junglepark losgigantos loscristines talkontravel" } ] -}" +}""" +function validate_flickr(str) + k = JSON.parse(str) + @test k != nothing + @test k["totalItems"] == 222 + @test k["items"][1]["description"][12] == '\"' +end youtube = "{\"apiVersion\":\"2.0\", \"data\":{ @@ -596,17 +626,19 @@ interop = "{ } }" -unicode = "{\"অলিম্পিকস\": { - \"অ্যাথলেট\": \"২২টি দেশ থেকে ২,০৩৫ জন প্রতিযোগী\", - \"ইভেন্ট\": \"২২টি ইভেন্টের মধ্যে ছিল দড়ি টানাটানি\", - \"রেকর্ড\": [ - {\"১০০মি. স্প্রিন্ট\": \"রেজি ওয়াকার, দক্ষিণ আফ্রিকা\"}, - {\"Marathon\": \"জনি হেইস\"}, - {\" ফ্রি-স্টাইল সাঁতার\": \"Henry Taylor, Britain\"} - ] - }} - " - - - -test21 = "[\r\n{\r\n\"a\": 1,\r\n\"b\": 2\r\n},\r\n{\r\n\"a\": 3,\r\n\"b\": 4\r\n}\r\n]" +const unicode = """ +{"অলিম্পিকস": { + "অ্যাথলেট": "২২টি দেশ থেকে ২,০৩৫ জন প্রতিযোগী", + "ইভেন্ট": "২২টি ইভেন্টের মধ্যে ছিল দড়ি টানাটানি", + "রেকর্ড": [ + {"১০০মি. স্প্রিন্ট": "রেজি ওয়াকার, দক্ষিণ আফ্রিকা"}, + {"Marathon": "জনি হেইস"}, + {" ফ্রি-স্টাইল সাঁতার": "Henry Taylor, Britain"} + ] +}} +""" +function validate_unicode(str) + u = JSON.parse(str) + @test u != nothing + @test u["অলিম্পিকস"]["রেকর্ড"][2]["Marathon"] == "জনি হেইস" +end diff --git a/test/parser/dicttype.jl b/test/parser/dicttype.jl new file mode 100644 index 0000000..164507c --- /dev/null +++ b/test/parser/dicttype.jl @@ -0,0 +1,11 @@ +@testset for T in [ + DataStructures.OrderedDict, + Dict{Symbol, Int32} +] + val = JSON.parse("{\"x\": 3}", dicttype=T) + @test isa(val, T) + @test length(val) == 1 + key = collect(keys(val))[1] + @test string(key) == "x" + @test val[key] == 3 +end diff --git a/test/parser/invalid-input.jl b/test/parser/invalid-input.jl new file mode 100644 index 0000000..ce9b3c9 --- /dev/null +++ b/test/parser/invalid-input.jl @@ -0,0 +1,29 @@ +const FAILURES = [ + # Unexpected character in array + "[1,2,3/4,5,6,7]", + # Unexpected character in object + "{\"1\":2, \"2\":3 _ \"4\":5}", + # Invalid escaped character + "[\"alpha\\α\"]", + # Invalid 'simple' and 'unknown value' + "[tXXe]", + "[fail]", + "∞", + # Invalid number + "[5,2,-]", + "[5,2,+β]", + # Incomplete escape + "\"\\", + # Control character + "\"\0\"", + # Issue #99 + "[\"🍕\"_\"🍕\"" +] + +@testset for fail in FAILURES + # Test memory parser + @test_throws ErrorException JSON.parse(fail) + + # Test streaming parser + @test_throws ErrorException JSON.parse(IOBuffer(fail)) +end diff --git a/test/parser/parsefile.jl b/test/parser/parsefile.jl new file mode 100644 index 0000000..50292b7 --- /dev/null +++ b/test/parser/parsefile.jl @@ -0,0 +1,10 @@ +tmppath, io = mktemp() +write(io, facebook) +close(io) +if is_windows() + # don't use mmap on Windows, to avoid ERROR: unlink: operation not permitted (EPERM) + @test haskey(JSON.parsefile(tmppath; use_mmap=false), "data") +else + @test haskey(JSON.parsefile(tmppath), "data") +end +rm(tmppath) diff --git a/test/regression/issue021.jl b/test/regression/issue021.jl new file mode 100644 index 0000000..856f820 --- /dev/null +++ b/test/regression/issue021.jl @@ -0,0 +1,4 @@ +test21 = "[\r\n{\r\n\"a\": 1,\r\n\"b\": 2\r\n},\r\n{\r\n\"a\": 3,\r\n\"b\": 4\r\n}\r\n]" +a = JSON.parse(test21) +@test isa(a, Vector{Any}) +@test length(a) == 2 diff --git a/test/regression/issue026.jl b/test/regression/issue026.jl new file mode 100644 index 0000000..ff9ea6d --- /dev/null +++ b/test/regression/issue026.jl @@ -0,0 +1,2 @@ +obj = JSON.parse("{\"a\":2e10}") +@test obj["a"] == 2e10 diff --git a/test/regression/issue057.jl b/test/regression/issue057.jl new file mode 100644 index 0000000..1797a8a --- /dev/null +++ b/test/regression/issue057.jl @@ -0,0 +1,2 @@ +obj = JSON.parse("{\"\U0001d712\":\"\\ud835\\udf12\"}") +@test(obj["𝜒"] == "𝜒") diff --git a/test/regression/issue109.jl b/test/regression/issue109.jl new file mode 100644 index 0000000..d0191fa --- /dev/null +++ b/test/regression/issue109.jl @@ -0,0 +1,8 @@ +type t109 + i::Int +end + +let iob = IOBuffer() + JSON.print(iob, t109(1)) + @test get(JSON.parse(String(take!(iob))), "i", 0) == 1 +end diff --git a/test/regression/issue152.jl b/test/regression/issue152.jl new file mode 100644 index 0000000..5b4a01b --- /dev/null +++ b/test/regression/issue152.jl @@ -0,0 +1,2 @@ +@test json([Int64[] Int64[]]) == "[[],[]]" +@test json([Int64[] Int64[]]') == "[]" diff --git a/test/regression/issue163.jl b/test/regression/issue163.jl new file mode 100644 index 0000000..5ace4fa --- /dev/null +++ b/test/regression/issue163.jl @@ -0,0 +1 @@ +@test Float32(JSON.parse(json(2.1f-8))) == 2.1f-8 diff --git a/test/runtests.jl b/test/runtests.jl index c1f28b0..bdcb58e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,320 +4,72 @@ using Compat import DataStructures -include("json-checker.jl") include("json-samples.jl") -@test JSON.parse("{\"x\": 3}", dicttype=DataStructures.OrderedDict) == DataStructures.OrderedDict{AbstractString,Any}([("x",3)]) -@test JSON.parse("{\"x\": 3}", dicttype=Dict{Symbol,Int32}) == Dict{Symbol,Int32}([(:x,3)]) - -# Test definitions ------- -validate_c(c) = begin - j = JSON.parse(c); - @test j != nothing - @test typeof(j["widget"]["image"]["hOffset"]) == Int64 - @test j["widget"]["image"]["hOffset"] == 250 - @test typeof(j["widget"]["text"]["size"]) == Float64 - @test j["widget"]["text"]["size"] == 36.5 - end - -validate_e(e) = begin - j=JSON.parse(e) - @test j != nothing - @test typeof(j) == Dict{String, Any} - @test length(j) == 1 - @test typeof(j["menu"]) == Dict{String, Any} - @test length(j["menu"]) == 2 - @test j["menu"]["header"] == "SVG\tViewerα" - @test isa(j["menu"]["items"], Vector{Any}) - @test length(j["menu"]["items"]) == 22 - @test j["menu"]["items"][3] == nothing - @test j["menu"]["items"][2]["id"] == "OpenNew" - @test j["menu"]["items"][2]["label"] == "Open New" - end - -validate_flickr(flickr) = begin - k = JSON.parse(flickr) - @test k != nothing - @test k["totalItems"] == 222 - @test k["items"][1]["description"][12] == '\"' - end - -validate_unicode(unicode) = begin - u = JSON.parse(unicode) - @test u != nothing - @test u["অলিম্পিকস"]["রেকর্ড"][2]["Marathon"] == "জনি হেইস" - end -# ------- - -finished_async_tests = RemoteChannel() - -@async begin - s = listen(7777) - s = accept(s) - - Base.start_reading(s) - - @test JSON.parse(s) != nothing # a - @test JSON.parse(s) != nothing # b - validate_c(s) # c - @test JSON.parse(s) != nothing # d - validate_e(s) # e - @test JSON.parse(s) != nothing # gmaps - @test JSON.parse(s) != nothing # colors1 - @test JSON.parse(s) != nothing # colors2 - @test JSON.parse(s) != nothing # colors3 - @test JSON.parse(s) != nothing # twitter - @test JSON.parse(s) != nothing # facebook - validate_flickr(s) # flickr - @test JSON.parse(s) != nothing # youtube - @test JSON.parse(s) != nothing # iphone - @test JSON.parse(s) != nothing # customer - @test JSON.parse(s) != nothing # product - @test JSON.parse(s) != nothing # interop - validate_unicode(s) # unicode - @test JSON.parse(s) != nothing # issue5 - @test JSON.parse(s) != nothing # dollars - @test JSON.parse(s) != nothing # brackets - - put!(finished_async_tests, nothing) +@testset "Parser" begin + @testset "Parser Failures" begin + include("parser/invalid-input.jl") + end + + @testset "parsefile" begin + include("parser/parsefile.jl") + end + + @testset "dicttype" begin + include("parser/dicttype.jl") + end + + @testset "Miscellaneous" begin + # test for single values + @test JSON.parse("true") == true + @test JSON.parse("null") == nothing + @test JSON.parse("\"hello\"") == "hello" + @test JSON.parse("\"a\"") == "a" + @test JSON.parse("1") == 1 + @test JSON.parse("1.5") == 1.5 + @test JSON.parse("[true]") == [true] + end end -w = connect("localhost", 7777) - -@test JSON.parse(a) != nothing -write(w, a) - -@test JSON.parse(b) != nothing -write(w, b) - -validate_c(c) -write(w, c) - -@test JSON.parse(d) != nothing -write(w, d) - -validate_e(e) -write(w, e) - -@test JSON.parse(gmaps) != nothing -write(w, gmaps) - -@test JSON.parse(colors1) != nothing -write(w, colors1) - -@test JSON.parse(colors2) != nothing -write(w, colors2) - -@test JSON.parse(colors3) != nothing -write(w, colors3) - -@test JSON.parse(twitter) != nothing -write(w, twitter) - -@test JSON.parse(facebook) != nothing -write(w, facebook) - -validate_flickr(flickr) -write(w, flickr) - -@test JSON.parse(youtube) != nothing -write(w, youtube) - -@test JSON.parse(iphone) != nothing -write(w, iphone) - -@test JSON.parse(customer) != nothing -write(w, customer) - -@test JSON.parse(product) != nothing -write(w, product) - -@test JSON.parse(interop) != nothing -write(w, interop) - -validate_unicode(unicode) -write(w, unicode) - - -#Issue 5 on Github -issue5 = "[\"A\",\"B\",\"C\\n\"]" -JSON.parse(issue5) -write(w, issue5) +@testset "Serializer" begin + @testset "Standard Serializer" begin + include("standard-serializer.jl") + end -# $ escaping issue -dollars = ["all of the \$s", "µniçø∂\$"] -json_dollars = json(dollars) -@test JSON.parse(json_dollars) != nothing -write(w, json_dollars) + @testset "Lowering" begin + include("lowering.jl") + end -# unmatched brackets -brackets = Dict("foo"=>"ba}r", "be}e]p"=>"boo{p") -json_brackets = json(brackets) -@test JSON.parse(json_brackets) != nothing -write(w, json_dollars) - -fetch(finished_async_tests) - -zeros = Dict("\0" => "\0") -json_zeros = json(zeros) -@test contains(json_zeros,"\\u0000") -@test !contains(json_zeros,"\\0") -@test JSON.parse(json_zeros) == zeros - -#Uncomment while doing timing tests -#@time for i=1:100 ; JSON.parse(d) ; end - - -# Printing an empty array or Dict shouldn't cause a BoundsError -@test json(String[]) == "[]" -@test json(Dict()) == "{}" - -#test for issue 26 -obj = JSON.parse("{\"a\":2e10}") -@test(obj["a"] == 2e10) - -#test for issue 21 -a=JSON.parse(test21) -@test isa(a, Vector{Any}) -@test length(a) == 2 -#Multidimensional arrays -@test json([0 1; 2 0]) == "[[0,2],[1,0]]" - -# issue #152 -@test json([Int64[] Int64[]]) == "[[],[]]" -@test json([Int64[] Int64[]]') == "[]" - -# ::Void values should be encoded as null -testDict = Dict("a" => nothing) -nothingJson = JSON.json(testDict) -nothingDict = JSON.parse(nothingJson) -@test testDict == nothingDict - - -# test for issue #57 -obj = JSON.parse("{\"\U0001d712\":\"\\ud835\\udf12\"}") -@test(obj["𝜒"] == "𝜒") - -# test for single values -@test JSON.parse("true") == true -@test JSON.parse("null") == nothing -@test JSON.parse("\"hello\"") == "hello" -@test JSON.parse("\"a\"") == "a" -@test JSON.parse("1") == 1 -@test JSON.parse("1.5") == 1.5 - -# test parsefile -tmppath, io = mktemp() -write(io, facebook) -close(io) -if is_windows() - # don't use mmap on Windows, to avoid ERROR: unlink: operation not permitted (EPERM) - @test haskey(JSON.parsefile(tmppath; use_mmap=false), "data") -else - @test haskey(JSON.parsefile(tmppath), "data") -end -rm(tmppath) - -# check indented json has same final value as non indented - -fb = JSON.parse(facebook) -fbjson1 = json(fb, 2) -fbjson2 = json(fb) -@test JSON.parse(fbjson1) == JSON.parse(fbjson2) - -ev = JSON.parse(e) -ejson1 = json(ev, 2) -ejson2 = json(ev) -@test JSON.parse(ejson1) == JSON.parse(ejson2) - -# test symbols are treated as strings -symtest = Dict(:symbolarray => [:apple, :pear], :symbolsingleton => :hello) -@test (JSON.json(symtest) == "{\"symbolarray\":[\"apple\",\"pear\"],\"symbolsingleton\":\"hello\"}" - || JSON.json(symtest) == "{\"symbolsingleton\":\"hello\",\"symbolarray\":[\"apple\",\"pear\"]}") - -# test for issue #109 -type t109 - i::Int -end -let iob = IOBuffer() - JSON.print(iob, t109(1)) - @test get(JSON.parse(String(take!(iob))), "i", 0) == 1 + @testset "Custom Serializer" begin + include("serializer.jl") + end end -# Check NaNs are printed correctly -@test sprint(JSON.print, [NaN]) == "[null]" -@test sprint(JSON.print, [Inf]) == "[null]" - -# check Nullables are printed correctly -@test sprint(JSON.print, [Nullable()]) == "[null]" -@test sprint(JSON.print, [Nullable{Int64}()]) == "[null]" -@test sprint(JSON.print, [Nullable{Int64}(Int64(1))]) == "[1]" +@testset "Integration" begin + # ::Void values should be encoded as null + testDict = Dict("a" => nothing) + nothingJson = JSON.json(testDict) + nothingDict = JSON.parse(nothingJson) + @test testDict == nothingDict -# check Chars -@test json('a') == "\"a\"" -@test json('\\') == "\"\\\\\"" -@test json('\n') == "\"\\n\"" -@test json('🍩') =="\"🍩\"" + @testset "async" begin + include("async.jl") + end -# check enums -@enum Animal zebra aardvark horse -@test json(zebra) == "\"zebra\"" -@test json([aardvark, horse, Dict("z" => zebra)]) == - "[\"aardvark\",\"horse\",{\"z\":\"zebra\"}]" + @testset "indentation" begin + include("indentation.jl") + end -# check for issue #163 -@test Float32(JSON.parse(json(2.1f-8))) == 2.1f-8 - -# Check printing of more exotic objects -@test sprint(JSON.print, Float64) == string("\"Float64\"") -@test_throws ArgumentError sprint(JSON.print, JSON) - -# test for issue #90 - Date/DateTime -if isdefined(Base, :Dates) -@test json(Date("2016-04-13")) == "\"2016-04-13\"" -@test json([Date("2016-04-13"), Date("2016-04-12")]) == "[\"2016-04-13\",\"2016-04-12\"]" -@test json(DateTime("2016-04-13T00:00:00")) == "\"2016-04-13T00:00:00\"" -@test json([DateTime("2016-04-13T00:00:00"), DateTime("2016-04-12T00:00:00")]) == "[\"2016-04-13T00:00:00\",\"2016-04-12T00:00:00\"]" + @testset "JSON Checker" begin + include("json-checker.jl") + end end -@test JSON.parse("[true]") == [true] - -# Test parser failures -const FAILURES = [ - # Unexpected character in array - "[1,2,3/4,5,6,7]", - # Unexpected character in object - "{\"1\":2, \"2\":3 _ \"4\":5}", - # Invalid escaped character - "[\"alpha\\α\"]", - # Invalid 'simple' and 'unknown value' - "[tXXe]", - "[fail]", - "∞", - # Invalid number - "[5,2,-]", - "[5,2,+β]", - # Incomplete escape - "\"\\", - # Control character - "\"\0\"", - # Issue #99 - "[\"🍕\"_\"🍕\"" -] - -for fail in FAILURES - # Test memory parser - @test_throws ErrorException JSON.parse(fail) - - # Test streaming parser - @test_throws ErrorException JSON.parse(IOBuffer(fail)) +@testset "Regression" begin + @testset "for issue #$i" for i in [21, 26, 57, 109, 152, 163] + include("regression/issue$(lpad(i, 3, '0')).jl") + end end -# Lowering tests -include("lowering.jl") - -# Custom serializing tests -include("serializer.jl") - # Check that printing to the default STDOUT doesn't fail -JSON.print(["JSON.jl tests pass!"],1) +JSON.print(["JSON.jl tests pass!"], 1) diff --git a/test/standard-serializer.jl b/test/standard-serializer.jl new file mode 100644 index 0000000..c63eb8f --- /dev/null +++ b/test/standard-serializer.jl @@ -0,0 +1,59 @@ +@testset "Symbol" begin + symtest = Dict(:symbolarray => [:apple, :pear], :symbolsingleton => :hello) + @test (JSON.json(symtest) == "{\"symbolarray\":[\"apple\",\"pear\"],\"symbolsingleton\":\"hello\"}" + || JSON.json(symtest) == "{\"symbolsingleton\":\"hello\",\"symbolarray\":[\"apple\",\"pear\"]}") +end + +@testset "Floats" begin + @test sprint(JSON.print, [NaN]) == "[null]" + @test sprint(JSON.print, [Inf]) == "[null]" +end + +@testset "Nullable" begin + @test sprint(JSON.print, [Nullable()]) == "[null]" + @test sprint(JSON.print, [Nullable{Int64}()]) == "[null]" + @test sprint(JSON.print, [Nullable{Int64}(Int64(1))]) == "[1]" +end + +@testset "Char" begin + @test json('a') == "\"a\"" + @test json('\\') == "\"\\\\\"" + @test json('\n') == "\"\\n\"" + @test json('🍩') =="\"🍩\"" +end + +@testset "Enum" begin + include("enum.jl") +end + +@testset "Type" begin + @test sprint(JSON.print, Float64) == string("\"Float64\"") +end + +@testset "Module" begin + @test_throws ArgumentError sprint(JSON.print, JSON) +end + +@testset "Dates" begin + @test json(Date("2016-04-13")) == "\"2016-04-13\"" + @test json([Date("2016-04-13"), Date("2016-04-12")]) == "[\"2016-04-13\",\"2016-04-12\"]" + @test json(DateTime("2016-04-13T00:00:00")) == "\"2016-04-13T00:00:00\"" + @test json([DateTime("2016-04-13T00:00:00"), DateTime("2016-04-12T00:00:00")]) == "[\"2016-04-13T00:00:00\",\"2016-04-12T00:00:00\"]" +end + +@testset "Null bytes" begin + zeros = Dict("\0" => "\0") + json_zeros = json(zeros) + @test contains(json_zeros,"\\u0000") + @test !contains(json_zeros,"\\0") + @test JSON.parse(json_zeros) == zeros +end + +@testset "Arrays" begin + # Printing an empty array or Dict shouldn't cause a BoundsError + @test json(String[]) == "[]" + @test json(Dict()) == "{}" + + #Multidimensional arrays + @test json([0 1; 2 0]) == "[[0,2],[1,0]]" +end