From 37a7b035f8feb248d25741b22e22ffb0ec7463d6 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 18 Jan 2012 10:12:50 +0100 Subject: Import json support from playground/qtbinaryjson This imports the JSON support for Qt 5 from playground/qtbinaryjson. It adds a fast, fully compliant json parser, a convenient C++ API, conversion to and from QVariants and a binary format for JSON that is extremely fast to use together with the C++ API. Change-Id: If9e3a21a4241d388d0abaa446b6824f9cc6edb1c Reviewed-by: Thiago Macieira --- tests/auto/corelib/corelib.pro | 1 + tests/auto/corelib/json/json.pro | 6 + tests/auto/corelib/json/test.bjson | Bin 0 -> 60992 bytes tests/auto/corelib/json/test.json | 66 ++ tests/auto/corelib/json/test2.json | 1 + tests/auto/corelib/json/tst_qtjson.cpp | 1535 ++++++++++++++++++++++++++++++++ 6 files changed, 1609 insertions(+) create mode 100644 tests/auto/corelib/json/json.pro create mode 100644 tests/auto/corelib/json/test.bjson create mode 100644 tests/auto/corelib/json/test.json create mode 100644 tests/auto/corelib/json/test2.json create mode 100644 tests/auto/corelib/json/tst_qtjson.cpp (limited to 'tests/auto') diff --git a/tests/auto/corelib/corelib.pro b/tests/auto/corelib/corelib.pro index 84eb3f284c..be12fdab62 100644 --- a/tests/auto/corelib/corelib.pro +++ b/tests/auto/corelib/corelib.pro @@ -6,6 +6,7 @@ SUBDIRS=\ global \ io \ itemmodels \ + json \ kernel \ plugin \ statemachine \ diff --git a/tests/auto/corelib/json/json.pro b/tests/auto/corelib/json/json.pro new file mode 100644 index 0000000000..f7b7a80a2d --- /dev/null +++ b/tests/auto/corelib/json/json.pro @@ -0,0 +1,6 @@ +TARGET = tst_qtjson +QT = core testlib +CONFIG -= app_bundle +CONFIG += testcase + +SOURCES += tst_qtjson.cpp diff --git a/tests/auto/corelib/json/test.bjson b/tests/auto/corelib/json/test.bjson new file mode 100644 index 0000000000..aa412eec67 Binary files /dev/null and b/tests/auto/corelib/json/test.bjson differ diff --git a/tests/auto/corelib/json/test.json b/tests/auto/corelib/json/test.json new file mode 100644 index 0000000000..7c935fffc8 --- /dev/null +++ b/tests/auto/corelib/json/test.json @@ -0,0 +1,66 @@ +[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\"", + "backslash": "\\", + "controls": "\b\f\n\r\t", + "slash": "/ & \/", + "alpha": "abcdefghijklmnopqrstuvwxyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "`1~!@#$%^&*()_+-={\':[,]}|;.?", + "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + "true": true, + "false": false, + "null": null, + "array":[ ], + "object":{ }, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], + "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + "quotes": "" \u0022 %22 0x22 034 "", + "\/\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?" : "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00, +2e+00, +2e-00, +"rosebud", +{"foo": "bar"}, +{"classification":{"relevancyScore":1000,"searchUrl":{"value":"http://www.bizrate.com/iphone-cases/index__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"}},"products":{"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$4,833.99","integral":483399}},"product":[{"type":"PRODUCT","title":"Silicone case for iPhone 3G/ 3GS","description":"Elite Horizontal Leather Pouch for Apple iPhone 3G/3Gs - Premium quality horizontal case for your Apple iPhone 3G/3Gs. This pouch is ideal for the style conscious on the go. This great looking case is made from high-quality leather with classic black...","manufacturer":"Apple","url":{"value":"http://www.bizrate.com/silicone-case-for-iphone-3g-3gs--pid1968262863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1968262863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1968262863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1968262863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1968262863","xsize":400,"ysize":400}]},"relevancy":310711221747712.000000,"priceSet":{"minPrice":{"value":"$1.56","integral":156},"maxPrice":{"value":"$29.99","integral":2999},"stores":14},"id":1968262863,"categoryId":8515},{"type":"PRODUCT","title":"Nonslip Checkered Silicone Skin Soft Case for iPhone 4 4G","description":"Specification:Product Name Silicone Skin Case Model for Apple iPhone 4 Color Black Material Soft Silicone Skin Weight 26g Package 1 x Case for Apple iPhone 4 Description:This is a non-OEM product.Accessory Only, Phone is not included.","manufacturer":"H&B","url":{"value":"http://www.bizrate.com/nonslip-checkered-silicone-skin-soft-case-for-iphone-4-4g--pid2534935499/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2534935499","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2534935499","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2534935499","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2534935499","xsize":400,"ysize":400}]},"relevancy":175580930637824.000000,"priceSet":{"minPrice":{"value":"$0.45","integral":45},"maxPrice":{"value":"$194.95","integral":19495},"stores":34},"id":2534935499,"categoryId":8515},{"type":"PRODUCT","title":"Plastic Case for iPhone 4 - Black","description":"Description:Detachable Windmill Type Matte Hard Plastic Case Cover for iPhone 4 (Black / Magenta)Customised your iPhone with this wonderful Plastic Case which is a accessory for your iPhone 4 which is made of high quality and durable plastic, protect","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/plastic-case-for-iphone-4-black--pid2305624670/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2305624670","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2305624670","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2305624670","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2305624670","xsize":400,"ysize":400}]},"relevancy":132488642953216.000000,"priceSet":{"minPrice":{"value":"$0.99","integral":99},"maxPrice":{"value":"$303.68","integral":30368},"stores":33},"id":2305624670,"categoryId":8515},{"type":"PRODUCT","title":"Protective Silicone Case for iPhone 4","description":"Made of high quality PVC material Protects your iPhone 4 from any scratch and dirt Easy to install and remove, no any tool needed Cut-out design allows user can access all keypad / button and slot without having to remove the case","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/protective-silicone-case-for-iphone-4--pid2120981405/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2120981405","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2120981405","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2120981405","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2120981405","xsize":400,"ysize":400}]},"relevancy":108614681362432.000000,"priceSet":{"minPrice":{"value":"$1.70","integral":170},"maxPrice":{"value":"$99.99","integral":9999},"stores":11},"id":2120981405,"categoryId":8515},{"type":"PRODUCT","title":"Iphone® 4 Aerosport Case","description":"Do more than just protect your iPhone 4 with this case bundle from rooCASE. This 3 in 1 bundle include a snap-on case, screen protector and a Nike+ sensor shoe pouch that can be use on most running shoes. Color: Purple Design: Love Provides protection...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/iphone-4-aerosport-case--pid2203798762/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2203798762","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2203798762","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2203798762","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2203798762","xsize":400,"ysize":400}]},"relevancy":96203484168192.000000,"priceSet":{"minPrice":{"value":"$2.49","integral":249},"maxPrice":{"value":"$79.95","integral":7995},"stores":16},"id":2203798762,"categoryId":8515},{"type":"PRODUCT","title":"Case Reflect For Iphone 3G","description":"NCAA iPhone 3G faceplate features the schools primary logo silk screened on the front of the case.","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/case-reflect-for-iphone-3g--pid1114627445/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1114627445","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1114627445","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1114627445","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1114627445","xsize":400,"ysize":400}]},"relevancy":84727583211520.000000,"priceSet":{"minPrice":{"value":"$0.69","integral":69},"maxPrice":{"value":"$75.52","integral":7552},"stores":59},"id":1114627445,"categoryId":8515},{"type":"PRODUCT","title":"Infuse Protector Case for iPhone 4 Black","description":"Protect and personalize your iPhone 4 with this front and back image design Protector Case. Form-fitting front and back hard plastic covers Protects your cell phone without adding a lot of bulk Smooth glossy finish Snaps on to the front edges, sides...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/infuse-protector-case-for-iphone-4-black--pid2557462717/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2557462717","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2557462717","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2557462717","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2557462717","xsize":400,"ysize":400}]},"relevancy":80831066406912.000000,"priceSet":{"minPrice":{"value":"$0.59","integral":59},"maxPrice":{"value":"$79.00","integral":7900},"stores":24},"id":2557462717,"categoryId":8515},{"type":"PRODUCT","title":"Dragonfly iPhone 4 Kream Case - Black","description":"DF-0030219 - White, Kream Case for iPhone 4 by Dragon-Fly","url":{"value":"http://www.bizrate.com/dragonfly-iphone-4-kream-case-black--pid2442061740/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2442061740","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2442061740","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2442061740","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2442061740","xsize":400,"ysize":400}]},"relevancy":70900229603328.000000,"priceSet":{"minPrice":{"value":"$1.05","integral":105},"maxPrice":{"value":"$94.49","integral":9449},"stores":30},"id":2442061740,"categoryId":8515},{"type":"PRODUCT","title":"Apple iPhone 3G/3GS Silicone Case (Black)","description":"Snap on Apple iPhone 3G 3GS Synthetic Leather Hardshell Case! Premium Qualtiy Synthetic Leather cover provides style, comfort, and protection to your iPhone 3G & 3GS. It also adds a sophisticated elegance and cool to your fashion. The case allows Quick...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/apple-iphone-3g3gs-silicone-case-black--pid2004746863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2004746863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2004746863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2004746863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2004746863","xsize":400,"ysize":400}]},"relevancy":65194915004416.000000,"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$414.99","integral":41499},"stores":39},"id":2004746863,"categoryId":8515},{"type":"PRODUCT","title":"Otterbox iPhone 4 Defender Case - Black","description":"Your iPhone 4 has become a big part of your life. With FaceTime video, retina display, multitasking, HD video recording and more - you've got a lot to lose. You won't find a tougher case than the OtterBox Defender Series for iPhone 4. This three-layer...","manufacturer":"Universal","url":{"value":"http://www.bizrate.com/otterbox-iphone-4-defender-case-black--pid2584611575/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2584611575","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2584611575","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2584611575","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2584611575","xsize":400,"ysize":400}]},"relevancy":61515478597632.000000,"priceSet":{"minPrice":{"value":"$3.28","integral":328},"maxPrice":{"value":"$110.65","integral":11065},"stores":25},"id":2584611575,"categoryId":8515}],"includedResults":10,"totalResults":2000}}, +{"classification":{"relevancyScore":1000,"searchUrl":{"value":"http://www.bizrate.com/iphone-cases/index__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"}},"products":{"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$4,833.99","integral":483399}},"product":[{"type":"PRODUCT","title":"Silicone case for iPhone 3G/ 3GS","description":"Elite Horizontal Leather Pouch for Apple iPhone 3G/3Gs - Premium quality horizontal case for your Apple iPhone 3G/3Gs. This pouch is ideal for the style conscious on the go. This great looking case is made from high-quality leather with classic black...","manufacturer":"Apple","url":{"value":"http://www.bizrate.com/silicone-case-for-iphone-3g-3gs--pid1968262863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1968262863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1968262863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1968262863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1968262863","xsize":400,"ysize":400}]},"relevancy":310711221747712.000000,"priceSet":{"minPrice":{"value":"$1.56","integral":156},"maxPrice":{"value":"$29.99","integral":2999},"stores":14},"id":1968262863,"categoryId":8515},{"type":"PRODUCT","title":"Nonslip Checkered Silicone Skin Soft Case for iPhone 4 4G","description":"Specification:Product Name Silicone Skin Case Model for Apple iPhone 4 Color Black Material Soft Silicone Skin Weight 26g Package 1 x Case for Apple iPhone 4 Description:This is a non-OEM product.Accessory Only, Phone is not included.","manufacturer":"H&B","url":{"value":"http://www.bizrate.com/nonslip-checkered-silicone-skin-soft-case-for-iphone-4-4g--pid2534935499/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2534935499","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2534935499","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2534935499","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2534935499","xsize":400,"ysize":400}]},"relevancy":175580930637824.000000,"priceSet":{"minPrice":{"value":"$0.45","integral":45},"maxPrice":{"value":"$194.95","integral":19495},"stores":34},"id":2534935499,"categoryId":8515},{"type":"PRODUCT","title":"Plastic Case for iPhone 4 - Black","description":"Description:Detachable Windmill Type Matte Hard Plastic Case Cover for iPhone 4 (Black / Magenta)Customised your iPhone with this wonderful Plastic Case which is a accessory for your iPhone 4 which is made of high quality and durable plastic, protect","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/plastic-case-for-iphone-4-black--pid2305624670/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2305624670","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2305624670","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2305624670","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2305624670","xsize":400,"ysize":400}]},"relevancy":132488642953216.000000,"priceSet":{"minPrice":{"value":"$0.99","integral":99},"maxPrice":{"value":"$303.68","integral":30368},"stores":33},"id":2305624670,"categoryId":8515},{"type":"PRODUCT","title":"Protective Silicone Case for iPhone 4","description":"Made of high quality PVC material Protects your iPhone 4 from any scratch and dirt Easy to install and remove, no any tool needed Cut-out design allows user can access all keypad / button and slot without having to remove the case","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/protective-silicone-case-for-iphone-4--pid2120981405/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2120981405","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2120981405","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2120981405","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2120981405","xsize":400,"ysize":400}]},"relevancy":108614681362432.000000,"priceSet":{"minPrice":{"value":"$1.70","integral":170},"maxPrice":{"value":"$99.99","integral":9999},"stores":11},"id":2120981405,"categoryId":8515},{"type":"PRODUCT","title":"Iphone® 4 Aerosport Case","description":"Do more than just protect your iPhone 4 with this case bundle from rooCASE. This 3 in 1 bundle include a snap-on case, screen protector and a Nike+ sensor shoe pouch that can be use on most running shoes. Color: Purple Design: Love Provides protection...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/iphone-4-aerosport-case--pid2203798762/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2203798762","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2203798762","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2203798762","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2203798762","xsize":400,"ysize":400}]},"relevancy":96203484168192.000000,"priceSet":{"minPrice":{"value":"$2.49","integral":249},"maxPrice":{"value":"$79.95","integral":7995},"stores":16},"id":2203798762,"categoryId":8515},{"type":"PRODUCT","title":"Case Reflect For Iphone 3G","description":"NCAA iPhone 3G faceplate features the schools primary logo silk screened on the front of the case.","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/case-reflect-for-iphone-3g--pid1114627445/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1114627445","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1114627445","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1114627445","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1114627445","xsize":400,"ysize":400}]},"relevancy":84727583211520.000000,"priceSet":{"minPrice":{"value":"$0.69","integral":69},"maxPrice":{"value":"$75.52","integral":7552},"stores":59},"id":1114627445,"categoryId":8515},{"type":"PRODUCT","title":"Infuse Protector Case for iPhone 4 Black","description":"Protect and personalize your iPhone 4 with this front and back image design Protector Case. Form-fitting front and back hard plastic covers Protects your cell phone without adding a lot of bulk Smooth glossy finish Snaps on to the front edges, sides...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/infuse-protector-case-for-iphone-4-black--pid2557462717/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2557462717","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2557462717","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2557462717","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2557462717","xsize":400,"ysize":400}]},"relevancy":80831066406912.000000,"priceSet":{"minPrice":{"value":"$0.59","integral":59},"maxPrice":{"value":"$79.00","integral":7900},"stores":24},"id":2557462717,"categoryId":8515},{"type":"PRODUCT","title":"Dragonfly iPhone 4 Kream Case - Black","description":"DF-0030219 - White, Kream Case for iPhone 4 by Dragon-Fly","url":{"value":"http://www.bizrate.com/dragonfly-iphone-4-kream-case-black--pid2442061740/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2442061740","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2442061740","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2442061740","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2442061740","xsize":400,"ysize":400}]},"relevancy":70900229603328.000000,"priceSet":{"minPrice":{"value":"$1.05","integral":105},"maxPrice":{"value":"$94.49","integral":9449},"stores":30},"id":2442061740,"categoryId":8515},{"type":"PRODUCT","title":"Apple iPhone 3G/3GS Silicone Case (Black)","description":"Snap on Apple iPhone 3G 3GS Synthetic Leather Hardshell Case! Premium Qualtiy Synthetic Leather cover provides style, comfort, and protection to your iPhone 3G & 3GS. It also adds a sophisticated elegance and cool to your fashion. The case allows Quick...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/apple-iphone-3g3gs-silicone-case-black--pid2004746863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2004746863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2004746863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2004746863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2004746863","xsize":400,"ysize":400}]},"relevancy":65194915004416.000000,"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$414.99","integral":41499},"stores":39},"id":2004746863,"categoryId":8515},{"type":"PRODUCT","title":"Otterbox iPhone 4 Defender Case - Black","description":"Your iPhone 4 has become a big part of your life. With FaceTime video, retina display, multitasking, HD video recording and more - you've got a lot to lose. You won't find a tougher case than the OtterBox Defender Series for iPhone 4. This three-layer...","manufacturer":"Universal","url":{"value":"http://www.bizrate.com/otterbox-iphone-4-defender-case-black--pid2584611575/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2584611575","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2584611575","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2584611575","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2584611575","xsize":400,"ysize":400}]},"relevancy":61515478597632.000000,"priceSet":{"minPrice":{"value":"$3.28","integral":328},"maxPrice":{"value":"$110.65","integral":11065},"stores":25},"id":2584611575,"categoryId":8515}],"includedResults":10,"totalResults":2000}}, +{"classification":{"relevancyScore":1000,"searchUrl":{"value":"http://www.bizrate.com/iphone-cases/index__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"}},"products":{"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$4,833.99","integral":483399}},"product":[{"type":"PRODUCT","title":"Silicone case for iPhone 3G/ 3GS","description":"Elite Horizontal Leather Pouch for Apple iPhone 3G/3Gs - Premium quality horizontal case for your Apple iPhone 3G/3Gs. This pouch is ideal for the style conscious on the go. This great looking case is made from high-quality leather with classic black...","manufacturer":"Apple","url":{"value":"http://www.bizrate.com/silicone-case-for-iphone-3g-3gs--pid1968262863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1968262863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1968262863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1968262863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1968262863","xsize":400,"ysize":400}]},"relevancy":310711221747712.000000,"priceSet":{"minPrice":{"value":"$1.56","integral":156},"maxPrice":{"value":"$29.99","integral":2999},"stores":14},"id":1968262863,"categoryId":8515},{"type":"PRODUCT","title":"Nonslip Checkered Silicone Skin Soft Case for iPhone 4 4G","description":"Specification:Product Name Silicone Skin Case Model for Apple iPhone 4 Color Black Material Soft Silicone Skin Weight 26g Package 1 x Case for Apple iPhone 4 Description:This is a non-OEM product.Accessory Only, Phone is not included.","manufacturer":"H&B","url":{"value":"http://www.bizrate.com/nonslip-checkered-silicone-skin-soft-case-for-iphone-4-4g--pid2534935499/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2534935499","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2534935499","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2534935499","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2534935499","xsize":400,"ysize":400}]},"relevancy":175580930637824.000000,"priceSet":{"minPrice":{"value":"$0.45","integral":45},"maxPrice":{"value":"$194.95","integral":19495},"stores":34},"id":2534935499,"categoryId":8515},{"type":"PRODUCT","title":"Plastic Case for iPhone 4 - Black","description":"Description:Detachable Windmill Type Matte Hard Plastic Case Cover for iPhone 4 (Black / Magenta)Customised your iPhone with this wonderful Plastic Case which is a accessory for your iPhone 4 which is made of high quality and durable plastic, protect","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/plastic-case-for-iphone-4-black--pid2305624670/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2305624670","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2305624670","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2305624670","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2305624670","xsize":400,"ysize":400}]},"relevancy":132488642953216.000000,"priceSet":{"minPrice":{"value":"$0.99","integral":99},"maxPrice":{"value":"$303.68","integral":30368},"stores":33},"id":2305624670,"categoryId":8515},{"type":"PRODUCT","title":"Protective Silicone Case for iPhone 4","description":"Made of high quality PVC material Protects your iPhone 4 from any scratch and dirt Easy to install and remove, no any tool needed Cut-out design allows user can access all keypad / button and slot without having to remove the case","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/protective-silicone-case-for-iphone-4--pid2120981405/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2120981405","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2120981405","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2120981405","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2120981405","xsize":400,"ysize":400}]},"relevancy":108614681362432.000000,"priceSet":{"minPrice":{"value":"$1.70","integral":170},"maxPrice":{"value":"$99.99","integral":9999},"stores":11},"id":2120981405,"categoryId":8515},{"type":"PRODUCT","title":"Iphone® 4 Aerosport Case","description":"Do more than just protect your iPhone 4 with this case bundle from rooCASE. This 3 in 1 bundle include a snap-on case, screen protector and a Nike+ sensor shoe pouch that can be use on most running shoes. Color: Purple Design: Love Provides protection...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/iphone-4-aerosport-case--pid2203798762/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2203798762","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2203798762","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2203798762","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2203798762","xsize":400,"ysize":400}]},"relevancy":96203484168192.000000,"priceSet":{"minPrice":{"value":"$2.49","integral":249},"maxPrice":{"value":"$79.95","integral":7995},"stores":16},"id":2203798762,"categoryId":8515},{"type":"PRODUCT","title":"Case Reflect For Iphone 3G","description":"NCAA iPhone 3G faceplate features the schools primary logo silk screened on the front of the case.","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/case-reflect-for-iphone-3g--pid1114627445/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1114627445","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1114627445","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1114627445","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1114627445","xsize":400,"ysize":400}]},"relevancy":84727583211520.000000,"priceSet":{"minPrice":{"value":"$0.69","integral":69},"maxPrice":{"value":"$75.52","integral":7552},"stores":59},"id":1114627445,"categoryId":8515},{"type":"PRODUCT","title":"Infuse Protector Case for iPhone 4 Black","description":"Protect and personalize your iPhone 4 with this front and back image design Protector Case. Form-fitting front and back hard plastic covers Protects your cell phone without adding a lot of bulk Smooth glossy finish Snaps on to the front edges, sides...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/infuse-protector-case-for-iphone-4-black--pid2557462717/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2557462717","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2557462717","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2557462717","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2557462717","xsize":400,"ysize":400}]},"relevancy":80831066406912.000000,"priceSet":{"minPrice":{"value":"$0.59","integral":59},"maxPrice":{"value":"$79.00","integral":7900},"stores":24},"id":2557462717,"categoryId":8515},{"type":"PRODUCT","title":"Dragonfly iPhone 4 Kream Case - Black","description":"DF-0030219 - White, Kream Case for iPhone 4 by Dragon-Fly","url":{"value":"http://www.bizrate.com/dragonfly-iphone-4-kream-case-black--pid2442061740/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2442061740","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2442061740","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2442061740","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2442061740","xsize":400,"ysize":400}]},"relevancy":70900229603328.000000,"priceSet":{"minPrice":{"value":"$1.05","integral":105},"maxPrice":{"value":"$94.49","integral":9449},"stores":30},"id":2442061740,"categoryId":8515},{"type":"PRODUCT","title":"Apple iPhone 3G/3GS Silicone Case (Black)","description":"Snap on Apple iPhone 3G 3GS Synthetic Leather Hardshell Case! Premium Qualtiy Synthetic Leather cover provides style, comfort, and protection to your iPhone 3G & 3GS. It also adds a sophisticated elegance and cool to your fashion. The case allows Quick...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/apple-iphone-3g3gs-silicone-case-black--pid2004746863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2004746863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2004746863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2004746863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2004746863","xsize":400,"ysize":400}]},"relevancy":65194915004416.000000,"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$414.99","integral":41499},"stores":39},"id":2004746863,"categoryId":8515},{"type":"PRODUCT","title":"Otterbox iPhone 4 Defender Case - Black","description":"Your iPhone 4 has become a big part of your life. With FaceTime video, retina display, multitasking, HD video recording and more - you've got a lot to lose. You won't find a tougher case than the OtterBox Defender Series for iPhone 4. This three-layer...","manufacturer":"Universal","url":{"value":"http://www.bizrate.com/otterbox-iphone-4-defender-case-black--pid2584611575/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2584611575","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2584611575","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2584611575","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2584611575","xsize":400,"ysize":400}]},"relevancy":61515478597632.000000,"priceSet":{"minPrice":{"value":"$3.28","integral":328},"maxPrice":{"value":"$110.65","integral":11065},"stores":25},"id":2584611575,"categoryId":8515}],"includedResults":10,"totalResults":2000}}, +{"classification":{"relevancyScore":1000,"searchUrl":{"value":"http://www.bizrate.com/iphone-cases/index__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"}},"products":{"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$4,833.99","integral":483399}},"product":[{"type":"PRODUCT","title":"Silicone case for iPhone 3G/ 3GS","description":"Elite Horizontal Leather Pouch for Apple iPhone 3G/3Gs - Premium quality horizontal case for your Apple iPhone 3G/3Gs. This pouch is ideal for the style conscious on the go. This great looking case is made from high-quality leather with classic black...","manufacturer":"Apple","url":{"value":"http://www.bizrate.com/silicone-case-for-iphone-3g-3gs--pid1968262863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1968262863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1968262863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1968262863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1968262863","xsize":400,"ysize":400}]},"relevancy":310711221747712.000000,"priceSet":{"minPrice":{"value":"$1.56","integral":156},"maxPrice":{"value":"$29.99","integral":2999},"stores":14},"id":1968262863,"categoryId":8515},{"type":"PRODUCT","title":"Nonslip Checkered Silicone Skin Soft Case for iPhone 4 4G","description":"Specification:Product Name Silicone Skin Case Model for Apple iPhone 4 Color Black Material Soft Silicone Skin Weight 26g Package 1 x Case for Apple iPhone 4 Description:This is a non-OEM product.Accessory Only, Phone is not included.","manufacturer":"H&B","url":{"value":"http://www.bizrate.com/nonslip-checkered-silicone-skin-soft-case-for-iphone-4-4g--pid2534935499/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2534935499","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2534935499","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2534935499","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2534935499","xsize":400,"ysize":400}]},"relevancy":175580930637824.000000,"priceSet":{"minPrice":{"value":"$0.45","integral":45},"maxPrice":{"value":"$194.95","integral":19495},"stores":34},"id":2534935499,"categoryId":8515},{"type":"PRODUCT","title":"Plastic Case for iPhone 4 - Black","description":"Description:Detachable Windmill Type Matte Hard Plastic Case Cover for iPhone 4 (Black / Magenta)Customised your iPhone with this wonderful Plastic Case which is a accessory for your iPhone 4 which is made of high quality and durable plastic, protect","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/plastic-case-for-iphone-4-black--pid2305624670/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2305624670","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2305624670","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2305624670","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2305624670","xsize":400,"ysize":400}]},"relevancy":132488642953216.000000,"priceSet":{"minPrice":{"value":"$0.99","integral":99},"maxPrice":{"value":"$303.68","integral":30368},"stores":33},"id":2305624670,"categoryId":8515},{"type":"PRODUCT","title":"Protective Silicone Case for iPhone 4","description":"Made of high quality PVC material Protects your iPhone 4 from any scratch and dirt Easy to install and remove, no any tool needed Cut-out design allows user can access all keypad / button and slot without having to remove the case","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/protective-silicone-case-for-iphone-4--pid2120981405/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2120981405","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2120981405","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2120981405","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2120981405","xsize":400,"ysize":400}]},"relevancy":108614681362432.000000,"priceSet":{"minPrice":{"value":"$1.70","integral":170},"maxPrice":{"value":"$99.99","integral":9999},"stores":11},"id":2120981405,"categoryId":8515},{"type":"PRODUCT","title":"Iphone® 4 Aerosport Case","description":"Do more than just protect your iPhone 4 with this case bundle from rooCASE. This 3 in 1 bundle include a snap-on case, screen protector and a Nike+ sensor shoe pouch that can be use on most running shoes. Color: Purple Design: Love Provides protection...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/iphone-4-aerosport-case--pid2203798762/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2203798762","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2203798762","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2203798762","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2203798762","xsize":400,"ysize":400}]},"relevancy":96203484168192.000000,"priceSet":{"minPrice":{"value":"$2.49","integral":249},"maxPrice":{"value":"$79.95","integral":7995},"stores":16},"id":2203798762,"categoryId":8515},{"type":"PRODUCT","title":"Case Reflect For Iphone 3G","description":"NCAA iPhone 3G faceplate features the schools primary logo silk screened on the front of the case.","manufacturer":"Griffin","url":{"value":"http://www.bizrate.com/case-reflect-for-iphone-3g--pid1114627445/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=1114627445","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=1114627445","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=1114627445","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=1114627445","xsize":400,"ysize":400}]},"relevancy":84727583211520.000000,"priceSet":{"minPrice":{"value":"$0.69","integral":69},"maxPrice":{"value":"$75.52","integral":7552},"stores":59},"id":1114627445,"categoryId":8515},{"type":"PRODUCT","title":"Infuse Protector Case for iPhone 4 Black","description":"Protect and personalize your iPhone 4 with this front and back image design Protector Case. Form-fitting front and back hard plastic covers Protects your cell phone without adding a lot of bulk Smooth glossy finish Snaps on to the front edges, sides...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/infuse-protector-case-for-iphone-4-black--pid2557462717/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2557462717","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2557462717","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2557462717","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2557462717","xsize":400,"ysize":400}]},"relevancy":80831066406912.000000,"priceSet":{"minPrice":{"value":"$0.59","integral":59},"maxPrice":{"value":"$79.00","integral":7900},"stores":24},"id":2557462717,"categoryId":8515},{"type":"PRODUCT","title":"Dragonfly iPhone 4 Kream Case - Black","description":"DF-0030219 - White, Kream Case for iPhone 4 by Dragon-Fly","url":{"value":"http://www.bizrate.com/dragonfly-iphone-4-kream-case-black--pid2442061740/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2442061740","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2442061740","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2442061740","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2442061740","xsize":400,"ysize":400}]},"relevancy":70900229603328.000000,"priceSet":{"minPrice":{"value":"$1.05","integral":105},"maxPrice":{"value":"$94.49","integral":9449},"stores":30},"id":2442061740,"categoryId":8515},{"type":"PRODUCT","title":"Apple iPhone 3G/3GS Silicone Case (Black)","description":"Snap on Apple iPhone 3G 3GS Synthetic Leather Hardshell Case! Premium Qualtiy Synthetic Leather cover provides style, comfort, and protection to your iPhone 3G & 3GS. It also adds a sophisticated elegance and cool to your fashion. The case allows Quick...","manufacturer":"Luxmo","url":{"value":"http://www.bizrate.com/apple-iphone-3g3gs-silicone-case-black--pid2004746863/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2004746863","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2004746863","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2004746863","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2004746863","xsize":400,"ysize":400}]},"relevancy":65194915004416.000000,"priceSet":{"minPrice":{"value":"$0.01","integral":1},"maxPrice":{"value":"$414.99","integral":41499},"stores":39},"id":2004746863,"categoryId":8515},{"type":"PRODUCT","title":"Otterbox iPhone 4 Defender Case - Black","description":"Your iPhone 4 has become a big part of your life. With FaceTime video, retina display, multitasking, HD video recording and more - you've got a lot to lose. You won't find a tougher case than the OtterBox Defender Series for iPhone 4. This three-layer...","manufacturer":"Universal","url":{"value":"http://www.bizrate.com/otterbox-iphone-4-defender-case-black--pid2584611575/compareprices__rf--af1__af_assettype_id--10__af_creative_id--6__af_id--50085__af_placement_id--1.html"},"images":{"image":[{"value":"http://image10.bizrate-images.com/resize?sq=60&uid=2584611575","xsize":60,"ysize":60},{"value":"http://image10.bizrate-images.com/resize?sq=100&uid=2584611575","xsize":100,"ysize":100},{"value":"http://image10.bizrate-images.com/resize?sq=160&uid=2584611575","xsize":160,"ysize":160},{"value":"http://image10.bizrate-images.com/resize?sq=400&uid=2584611575","xsize":400,"ysize":400}]},"relevancy":61515478597632.000000,"priceSet":{"minPrice":{"value":"$3.28","integral":328},"maxPrice":{"value":"$110.65","integral":11065},"stores":25},"id":2584611575,"categoryId":8515}],"includedResults":10,"totalResults":2000}} +] + diff --git a/tests/auto/corelib/json/test2.json b/tests/auto/corelib/json/test2.json new file mode 100644 index 0000000000..303f879b62 --- /dev/null +++ b/tests/auto/corelib/json/test2.json @@ -0,0 +1 @@ +{ "foo": ["ab"] } diff --git a/tests/auto/corelib/json/tst_qtjson.cpp b/tests/auto/corelib/json/tst_qtjson.cpp new file mode 100644 index 0000000000..d5575b0e28 --- /dev/null +++ b/tests/auto/corelib/json/tst_qtjson.cpp @@ -0,0 +1,1535 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qjsonarray.h" +#include "qjsonobject.h" +#include "qjsonvalue.h" +#include "qjsondocument.h" + +class TestQtJson: public QObject +{ + Q_OBJECT +public: + TestQtJson(QObject *parent = 0); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + + void testValueSimple(); + void testNumbers(); + + void testObjectSimple(); + void testArraySimple(); + void testValueObject(); + void testValueArray(); + void testObjectNested(); + void testArrayNested(); + void testArrayNestedEmpty(); + void testObjectNestedEmpty(); + + void testValueRef(); + void testObjectIteration(); + void testArrayIteration(); + + void testObjectFind(); + + void testDocument(); + + void nullValues(); + void nullArrays(); + void nullObject(); + + void keySorting(); + + void undefinedValues(); + + void fromVariantMap(); + void toVariantMap(); + + void toJson(); + void fromJson(); + void fromBinary(); + void toAndFromBinary_data(); + void toAndFromBinary(); + void parseNumbers(); + void parseStrings(); + void parseDuplicateKeys(); + void testParser(); + + void compactArray(); + void compactObject(); + + void validation(); + + void assignToDocument(); + + void testDuplicateKeys(); + void testCompaction(); + void testDebugStream(); + void testCompactionError(); +}; + +TestQtJson::TestQtJson(QObject *parent) : QObject(parent) +{ +} + +void TestQtJson::initTestCase() +{ +} + +void TestQtJson::cleanupTestCase() +{ +} + +void TestQtJson::init() +{ +} + +void TestQtJson::cleanup() +{ +} + +void TestQtJson::testValueSimple() +{ + QJsonValue value(true); + QCOMPARE(value.type(), QJsonValue::Bool); + QCOMPARE(value.toDouble(), 0.); + QCOMPARE(value.toString(), QString()); + QCOMPARE(value.toBool(), true); + QCOMPARE(value.toObject(), QJsonObject()); + QCOMPARE(value.toArray(), QJsonArray()); + + value = 999.; + QCOMPARE(value.type(), QJsonValue::Double); + QCOMPARE(value.toDouble(), 999.); + QCOMPARE(value.toString(), QString()); + QCOMPARE(value.toBool(), false); + QCOMPARE(value.toObject(), QJsonObject()); + QCOMPARE(value.toArray(), QJsonArray()); + + value = QLatin1String("test"); + QCOMPARE(value.toDouble(), 0.); + QCOMPARE(value.toString(), QLatin1String("test")); + QCOMPARE(value.toBool(), false); + QCOMPARE(value.toObject(), QJsonObject()); + QCOMPARE(value.toArray(), QJsonArray()); + + value = true; + QCOMPARE(value.toDouble(), 0.); + QCOMPARE(value.toString(), QString()); + QCOMPARE(value.toBool(), true); + QCOMPARE(value.toObject(), QJsonObject()); + QCOMPARE(value.toArray(), QJsonArray()); + + value = 999.; + QCOMPARE(value.toDouble(), 999.); + QCOMPARE(value.toString(), QString()); + QCOMPARE(value.toBool(), false); + QCOMPARE(value.toObject(), QJsonObject()); + QCOMPARE(value.toArray(), QJsonArray()); + +} + +void TestQtJson::testNumbers() +{ + { + int numbers[] = { + 0, + -1, + 1, + (1<<26), + (1<<27), + (1<<28), + -(1<<26), + -(1<<27), + -(1<<28), + (1<<26) - 1, + (1<<27) - 1, + (1<<28) - 1, + -((1<<26) - 1), + -((1<<27) - 1), + -((1<<28) - 1) + }; + int n = sizeof(numbers)/sizeof(int); + + QJsonArray array; + for (int i = 0; i < n; ++i) + array.append((double)numbers[i]); + for (int i = 0; i < array.size(); ++i) { + QCOMPARE(array.at(i).type(), QJsonValue::Double); + QCOMPARE(array.at(i).toDouble(), (double)numbers[i]); + } + } + + { + double numbers[] = { + 0, + -1, + 1, + (1<<26), + (1<<27), + (1<<28), + -(1<<26), + -(1<<27), + -(1<<28), + (1<<26) - 1, + (1<<27) - 1, + (1<<28) - 1, + -((1<<26) - 1), + -((1<<27) - 1), + -((1<<28) - 1), + 1.1, + 0.1, + -0.1, + -1.1, + 1e200, + -1e200 + }; + int n = sizeof(numbers)/sizeof(double); + + QJsonArray array; + for (int i = 0; i < n; ++i) + array.append(numbers[i]); + for (int i = 0; i < array.size(); ++i) { + QCOMPARE(array.at(i).type(), QJsonValue::Double); + QCOMPARE(array.at(i).toDouble(), numbers[i]); + } + } + +} + +void TestQtJson::testObjectSimple() +{ + QJsonObject object; + object.insert("number", 999.); + QCOMPARE(object.value("number").type(), QJsonValue::Double); + QCOMPARE(object.value("number").toDouble(), 999.); + object.insert("string", QString::fromLatin1("test")); + QCOMPARE(object.value("string").type(), QJsonValue::String); + QCOMPARE(object.value("string").toString(), QString("test")); + object.insert("boolean", true); + QCOMPARE(object.value("boolean").toBool(), true); + + QStringList keys = object.keys(); + QVERIFY2(keys.contains("number"), "key number not found"); + QVERIFY2(keys.contains("string"), "key string not found"); + QVERIFY2(keys.contains("boolean"), "key boolean not found"); + + // if we put a JsonValue into the JsonObject and retreive + // it, it should be identical. + QJsonValue value(QLatin1String("foo")); + object.insert("value", value); + QCOMPARE(object.value("value"), value); + + int size = object.size(); + object.remove("boolean"); + QCOMPARE(object.size(), size - 1); + QVERIFY2(!object.contains("boolean"), "key boolean should have been removed"); + + QJsonValue taken = object.take("value"); +// QCOMPARE(taken, value); + QVERIFY2(!object.contains("value"), "key value should have been removed"); + + QString before = object.value("string").toString(); + object.insert("string", QString::fromLatin1("foo")); + QVERIFY2(object.value("string").toString() != before, "value should have been updated"); +} + +void TestQtJson::testArraySimple() +{ + QJsonArray array; + array.append(999.); + array.append(QString::fromLatin1("test")); + array.append(true); + + QJsonValue val = array.at(0); + QCOMPARE(array.at(0).toDouble(), 999.); + QCOMPARE(array.at(1).toString(), QString("test")); + QCOMPARE(array.at(2).toBool(), true); + QCOMPARE(array.size(), 3); + + // if we put a JsonValue into the JsonArray and retreive + // it, it should be identical. + QJsonValue value(QLatin1String("foo")); + array.append(value); + QCOMPARE(array.at(3), value); + + int size = array.size(); + array.removeAt(2); + --size; + QCOMPARE(array.size(), size); + + QJsonValue taken = array.takeAt(0); + --size; + QCOMPARE(taken.toDouble(), 999.); + QCOMPARE(array.size(), size); + + // check whether null values work + array.append(QJsonValue()); + ++size; + QCOMPARE(array.size(), size); + QCOMPARE(array.last().type(), QJsonValue::Null); + QCOMPARE(array.last(), QJsonValue()); + + QCOMPARE(array.first().type(), QJsonValue::String); + QCOMPARE(array.first(), QJsonValue(QLatin1String("test"))); + + array.prepend(false); + QCOMPARE(array.first().type(), QJsonValue::Bool); + QCOMPARE(array.first(), QJsonValue(false)); + + QCOMPARE(array.at(-1), QJsonValue(QJsonValue::Undefined)); + QCOMPARE(array.at(array.size()), QJsonValue(QJsonValue::Undefined)); + + array.replace(0, -555.); + QCOMPARE(array.first().type(), QJsonValue::Double); + QCOMPARE(array.first(), QJsonValue(-555.)); + QCOMPARE(array.at(1).type(), QJsonValue::String); + QCOMPARE(array.at(1), QJsonValue(QLatin1String("test"))); +} + +void TestQtJson::testValueObject() +{ + QJsonObject object; + object.insert("number", 999.); + object.insert("string", QLatin1String("test")); + object.insert("boolean", true); + + QJsonValue value(object); + + // if we don't modify the original JsonObject, toObject() + // on the JsonValue should return the same object (non-detached). + QCOMPARE(value.toObject(), object); + + // if we modify the original object, it should detach + object.insert("test", QJsonValue(QLatin1String("test"))); + QVERIFY2(value.toObject() != object, "object should have detached"); +} + +void TestQtJson::testValueArray() +{ + QJsonArray array; + array.append(999.); + array.append(QLatin1String("test")); + array.append(true); + + QJsonValue value(array); + + // if we don't modify the original JsonArray, toArray() + // on the JsonValue should return the same object (non-detached). + QCOMPARE(value.toArray(), array); + + // if we modify the original array, it should detach + array.append(QLatin1String("test")); + QVERIFY2(value.toArray() != array, "array should have detached"); +} + +void TestQtJson::testObjectNested() +{ + QJsonObject inner, outer; + inner.insert("number", 999.); + outer.insert("nested", inner); + + // if we don't modify the original JsonObject, value() + // should return the same object (non-detached). + QJsonObject value = outer.value("nested").toObject(); + QCOMPARE(value, inner); + QCOMPARE(value.value("number").toDouble(), 999.); + + // if we modify the original object, it should detach and not + // affect the nested object + inner.insert("number", 555.); + value = outer.value("nested").toObject(); + QVERIFY2(inner.value("number").toDouble() != value.value("number").toDouble(), + "object should have detached"); + + // array in object + QJsonArray array; + array.append(123.); + array.append(456.); + outer.insert("array", array); + QCOMPARE(outer.value("array").toArray(), array); + QCOMPARE(outer.value("array").toArray().at(1).toDouble(), 456.); + + // two deep objects + QJsonObject twoDeep; + twoDeep.insert("boolean", true); + inner.insert("nested", twoDeep); + outer.insert("nested", inner); + QCOMPARE(outer.value("nested").toObject().value("nested").toObject(), twoDeep); + QCOMPARE(outer.value("nested").toObject().value("nested").toObject().value("boolean").toBool(), + true); +} + +void TestQtJson::testArrayNested() +{ + QJsonArray inner, outer; + inner.append(999.); + outer.append(inner); + + // if we don't modify the original JsonArray, value() + // should return the same array (non-detached). + QJsonArray value = outer.at(0).toArray(); + QCOMPARE(value, inner); + QCOMPARE(value.at(0).toDouble(), 999.); + + // if we modify the original array, it should detach and not + // affect the nested array + inner.append(555.); + value = outer.at(0).toArray(); + QVERIFY2(inner.size() != value.size(), "array should have detached"); + + // objects in arrays + QJsonObject object; + object.insert("boolean", true); + outer.append(object); + QCOMPARE(outer.last().toObject(), object); + QCOMPARE(outer.last().toObject().value("boolean").toBool(), true); + + // two deep arrays + QJsonArray twoDeep; + twoDeep.append(QJsonValue(QString::fromLatin1("nested"))); + inner.append(twoDeep); + outer.append(inner); + QCOMPARE(outer.last().toArray().last().toArray(), twoDeep); + QCOMPARE(outer.last().toArray().last().toArray().at(0).toString(), QString("nested")); +} + +void TestQtJson::testArrayNestedEmpty() +{ + QJsonObject object; + QJsonArray inner; + object.insert("inner", inner); + QJsonValue val = object.value("inner"); + QJsonArray value = object.value("inner").toArray(); + QCOMPARE(value.size(), 0); + QCOMPARE(value, inner); + QCOMPARE(value.size(), 0); + object.insert("count", 0.); + QCOMPARE(object.value("inner").toArray().size(), 0); + QVERIFY(object.value("inner").toArray().isEmpty()); + QJsonDocument(object).toBinaryData(); + QCOMPARE(object.value("inner").toArray().size(), 0); +} + +void TestQtJson::testObjectNestedEmpty() +{ + QJsonObject object; + QJsonObject inner; + QJsonObject inner2; + object.insert("inner", inner); + object.insert("inner2", inner2); + QJsonObject value = object.value("inner").toObject(); + QCOMPARE(value.size(), 0); + QCOMPARE(value, inner); + QCOMPARE(value.size(), 0); + object.insert("count", 0.); + QCOMPARE(object.value("inner").toObject().size(), 0); + QCOMPARE(object.value("inner").type(), QJsonValue::Object); + QJsonDocument(object).toBinaryData(); + QVERIFY(object.value("inner").toObject().isEmpty()); + QVERIFY(object.value("inner2").toObject().isEmpty()); + QJsonDocument doc = QJsonDocument::fromBinaryData(QJsonDocument(object).toBinaryData()); + QVERIFY(!doc.isNull()); + QJsonObject reconstituted(doc.object()); + QCOMPARE(reconstituted.value("inner").toObject().size(), 0); + QCOMPARE(reconstituted.value("inner").type(), QJsonValue::Object); + QCOMPARE(reconstituted.value("inner2").type(), QJsonValue::Object); +} + +void TestQtJson::testValueRef() +{ + QJsonArray array; + array.append(1.); + array.append(2.); + array.append(3.); + array[1] = false; + + QCOMPARE(array.size(), 3); + QCOMPARE(array.at(0).toDouble(), 1.); + QCOMPARE(array.at(2).toDouble(), 3.); + QCOMPARE(array.at(1).type(), QJsonValue::Bool); + QCOMPARE(array.at(1).toBool(), false); + + QJsonObject object; + object[QLatin1String("key")] = true; + QCOMPARE(object.size(), 1); + object.insert(QLatin1String("null"), QJsonValue()); + QCOMPARE(object.value(QLatin1String("null")), QJsonValue()); + object[QLatin1String("null")] = 100.; + QCOMPARE(object.value(QLatin1String("null")).type(), QJsonValue::Double); + QJsonValue val = object[QLatin1String("null")]; + QCOMPARE(val.toDouble(), 100.); + QCOMPARE(object.size(), 2); +} + +void TestQtJson::testObjectIteration() +{ + QJsonObject object; + for (int i = 0; i < 10; ++i) + object[QString::number(i)] = (double)i; + + QCOMPARE(object.size(), 10); + + for (QJsonObject::iterator it = object.begin(); it != object.end(); ++it) { + QJsonValue value = it.value(); + QCOMPARE((double)it.key().toInt(), value.toDouble()); + } + + { + QJsonObject object2 = object; + QVERIFY(object == object2); + + QJsonValue val = *object2.begin(); + object2.erase(object2.begin()); + QCOMPARE(object.size(), 10); + QCOMPARE(object2.size(), 9); + + for (QJsonObject::const_iterator it = object2.constBegin(); it != object2.constEnd(); ++it) { + QJsonValue value = it.value(); + QVERIFY(it.value() != val); + QCOMPARE((double)it.key().toInt(), value.toDouble()); + } + } + + { + QJsonObject::Iterator it = object.begin(); + it += 5; + QCOMPARE(QJsonValue(it.value()).toDouble(), 5.); + it -= 3; + QCOMPARE(QJsonValue(it.value()).toDouble(), 2.); + QJsonObject::Iterator it2 = it + 5; + QCOMPARE(QJsonValue(it2.value()).toDouble(), 7.); + it2 = it - 1; + QCOMPARE(QJsonValue(it2.value()).toDouble(), 1.); + } + + { + QJsonObject::ConstIterator it = object.constBegin(); + it += 5; + QCOMPARE(QJsonValue(it.value()).toDouble(), 5.); + it -= 3; + QCOMPARE(QJsonValue(it.value()).toDouble(), 2.); + QJsonObject::ConstIterator it2 = it + 5; + QCOMPARE(QJsonValue(it2.value()).toDouble(), 7.); + it2 = it - 1; + QCOMPARE(QJsonValue(it2.value()).toDouble(), 1.); + } + + QJsonObject::Iterator it = object.begin(); + while (!object.isEmpty()) + it = object.erase(it); + QCOMPARE(object.size() , 0); + QVERIFY(it == object.end()); +} + +void TestQtJson::testArrayIteration() +{ + QJsonArray array; + for (int i = 0; i < 10; ++i) + array.append(i); + + QCOMPARE(array.size(), 10); + + int i = 0; + for (QJsonArray::iterator it = array.begin(); it != array.end(); ++it, ++i) { + QJsonValue value = (*it); + QCOMPARE((double)i, value.toDouble()); + } + + { + QJsonArray array2 = array; + QVERIFY(array == array2); + + QJsonValue val = *array2.begin(); + array2.erase(array2.begin()); + QCOMPARE(array.size(), 10); + QCOMPARE(array2.size(), 9); + + i = 1; + for (QJsonArray::const_iterator it = array2.constBegin(); it != array2.constEnd(); ++it, ++i) { + QJsonValue value = (*it); + QCOMPARE((double)i, value.toDouble()); + } + } + + { + QJsonArray::Iterator it = array.begin(); + it += 5; + QCOMPARE(QJsonValue((*it)).toDouble(), 5.); + it -= 3; + QCOMPARE(QJsonValue((*it)).toDouble(), 2.); + QJsonArray::Iterator it2 = it + 5; + QCOMPARE(QJsonValue(*it2).toDouble(), 7.); + it2 = it - 1; + QCOMPARE(QJsonValue(*it2).toDouble(), 1.); + } + + { + QJsonArray::ConstIterator it = array.constBegin(); + it += 5; + QCOMPARE(QJsonValue((*it)).toDouble(), 5.); + it -= 3; + QCOMPARE(QJsonValue((*it)).toDouble(), 2.); + QJsonArray::ConstIterator it2 = it + 5; + QCOMPARE(QJsonValue(*it2).toDouble(), 7.); + it2 = it - 1; + QCOMPARE(QJsonValue(*it2).toDouble(), 1.); + } + + QJsonArray::Iterator it = array.begin(); + while (!array.isEmpty()) + it = array.erase(it); + QCOMPARE(array.size() , 0); + QVERIFY(it == array.end()); +} + +void TestQtJson::testObjectFind() +{ + QJsonObject object; + for (int i = 0; i < 10; ++i) + object[QString::number(i)] = i; + + QCOMPARE(object.size(), 10); + + QJsonObject::iterator it = object.find(QLatin1String("1")); + QCOMPARE((*it).toDouble(), 1.); + it = object.find(QLatin1String("11")); + QVERIFY((*it).type() == QJsonValue::Undefined); + QVERIFY(it == object.end()); + + QJsonObject::const_iterator cit = object.constFind(QLatin1String("1")); + QCOMPARE((*cit).toDouble(), 1.); + cit = object.constFind(QLatin1String("11")); + QVERIFY((*it).type() == QJsonValue::Undefined); + QVERIFY(it == object.end()); +} + +void TestQtJson::testDocument() +{ + QJsonDocument doc; + QCOMPARE(doc.isEmpty(), true); + QCOMPARE(doc.isArray(), false); + QCOMPARE(doc.isObject(), false); + + QJsonObject object; + doc.setObject(object); + QCOMPARE(doc.isEmpty(), false); + QCOMPARE(doc.isArray(), false); + QCOMPARE(doc.isObject(), true); + + object.insert(QLatin1String("Key"), QLatin1String("Value")); + doc.setObject(object); + QCOMPARE(doc.isEmpty(), false); + QCOMPARE(doc.isArray(), false); + QCOMPARE(doc.isObject(), true); + QVERIFY(doc.object() == object); + QVERIFY(doc.array() == QJsonArray()); + + doc = QJsonDocument(); + QCOMPARE(doc.isEmpty(), true); + QCOMPARE(doc.isArray(), false); + QCOMPARE(doc.isObject(), false); + + QJsonArray array; + doc.setArray(array); + QCOMPARE(doc.isEmpty(), false); + QCOMPARE(doc.isArray(), true); + QCOMPARE(doc.isObject(), false); + + array.append(QLatin1String("Value")); + doc.setArray(array); + QCOMPARE(doc.isEmpty(), false); + QCOMPARE(doc.isArray(), true); + QCOMPARE(doc.isObject(), false); + QVERIFY(doc.array() == array); + QVERIFY(doc.object() == QJsonObject()); + + QJsonObject outer; + outer.insert(QLatin1String("outerKey"), 22); + QJsonObject inner; + inner.insert(QLatin1String("innerKey"), 42); + outer.insert(QLatin1String("innter"), inner); + QJsonArray innerArray; + innerArray.append(23); + outer.insert(QLatin1String("innterArray"), innerArray); + + QJsonDocument doc2(outer.value(QLatin1String("innter")).toObject()); + QVERIFY(doc2.object().contains(QLatin1String("innerKey"))); + QCOMPARE(doc2.object().value(QLatin1String("innerKey")), QJsonValue(42)); + + QJsonDocument doc3; + doc3.setObject(outer.value(QLatin1String("innter")).toObject()); + QCOMPARE(doc3.isArray(), false); + QCOMPARE(doc3.isObject(), true); + QVERIFY(doc3.object().contains(QLatin1String("innerKey"))); + QCOMPARE(doc3.object().value(QLatin1String("innerKey")), QJsonValue(42)); + + QJsonDocument doc4(outer.value(QLatin1String("innterArray")).toArray()); + QCOMPARE(doc4.isArray(), true); + QCOMPARE(doc4.isObject(), false); + QCOMPARE(doc4.array().size(), 1); + QCOMPARE(doc4.array().at(0), QJsonValue(23)); + + QJsonDocument doc5; + doc5.setArray(outer.value(QLatin1String("innterArray")).toArray()); + QCOMPARE(doc5.isArray(), true); + QCOMPARE(doc5.isObject(), false); + QCOMPARE(doc5.array().size(), 1); + QCOMPARE(doc5.array().at(0), QJsonValue(23)); +} + +void TestQtJson::nullValues() +{ + QJsonArray array; + array.append(QJsonValue()); + + QCOMPARE(array.size(), 1); + QCOMPARE(array.at(0), QJsonValue()); + + QJsonObject object; + object.insert(QString("key"), QJsonValue()); + QCOMPARE(object.contains("key"), true); + QCOMPARE(object.size(), 1); + QCOMPARE(object.value("key"), QJsonValue()); +} + +void TestQtJson::nullArrays() +{ + QJsonArray nullArray; + QJsonArray nonNull; + nonNull.append(QLatin1String("bar")); + + QCOMPARE(nullArray, QJsonArray()); + QVERIFY(nullArray != nonNull); + QVERIFY(nonNull != nullArray); + + QCOMPARE(nullArray.size(), 0); + QCOMPARE(nullArray.takeAt(0), QJsonValue(QJsonValue::Undefined)); + QCOMPARE(nullArray.first(), QJsonValue(QJsonValue::Undefined)); + QCOMPARE(nullArray.last(), QJsonValue(QJsonValue::Undefined)); + nullArray.removeAt(0); + nullArray.removeAt(-1); + + nullArray.append(QString("bar")); + nullArray.removeAt(0); + + QCOMPARE(nullArray.size(), 0); + QCOMPARE(nullArray.takeAt(0), QJsonValue(QJsonValue::Undefined)); + QCOMPARE(nullArray.first(), QJsonValue(QJsonValue::Undefined)); + QCOMPARE(nullArray.last(), QJsonValue(QJsonValue::Undefined)); + nullArray.removeAt(0); + nullArray.removeAt(-1); +} + +void TestQtJson::nullObject() +{ + QJsonObject nullObject; + QJsonObject nonNull; + nonNull.insert(QLatin1String("foo"), QLatin1String("bar")); + + QCOMPARE(nullObject, QJsonObject()); + QVERIFY(nullObject != nonNull); + QVERIFY(nonNull != nullObject); + + QCOMPARE(nullObject.size(), 0); + QCOMPARE(nullObject.keys(), QStringList()); + nullObject.remove("foo"); + QCOMPARE(nullObject, QJsonObject()); + QCOMPARE(nullObject.take("foo"), QJsonValue(QJsonValue::Undefined)); + QCOMPARE(nullObject.contains("foo"), false); + + nullObject.insert("foo", QString("bar")); + nullObject.remove("foo"); + + QCOMPARE(nullObject.size(), 0); + QCOMPARE(nullObject.keys(), QStringList()); + nullObject.remove("foo"); + QCOMPARE(nullObject, QJsonObject()); + QCOMPARE(nullObject.take("foo"), QJsonValue(QJsonValue::Undefined)); + QCOMPARE(nullObject.contains("foo"), false); +} + +void TestQtJson::keySorting() +{ + const char *json = "{ \"B\": true, \"A\": false }"; + QJsonDocument doc = QJsonDocument::fromJson(json); + + QCOMPARE(doc.isObject(), true); + + QJsonObject o = doc.object(); + QCOMPARE(o.size(), 2); + QJsonObject::const_iterator it = o.constBegin(); + QCOMPARE(it.key(), QLatin1String("A")); + ++it; + QCOMPARE(it.key(), QLatin1String("B")); +} + +void TestQtJson::undefinedValues() +{ + QJsonObject object; + object.insert("Key", QJsonValue(QJsonValue::Undefined)); + QCOMPARE(object.size(), 0); + + object.insert("Key", QLatin1String("Value")); + QCOMPARE(object.size(), 1); + QCOMPARE(object.value("Key").type(), QJsonValue::String); + QCOMPARE(object.value("foo").type(), QJsonValue::Undefined); + object.insert("Key", QJsonValue(QJsonValue::Undefined)); + QCOMPARE(object.size(), 0); + QCOMPARE(object.value("Key").type(), QJsonValue::Undefined); + + QJsonArray array; + array.append(QJsonValue(QJsonValue::Undefined)); + QCOMPARE(array.size(), 1); + QCOMPARE(array.at(0).type(), QJsonValue::Null); + + QCOMPARE(array.at(1).type(), QJsonValue::Undefined); + QCOMPARE(array.at(-1).type(), QJsonValue::Undefined); +} + + +void TestQtJson::fromVariantMap() +{ + QVariantMap map; + map.insert(QLatin1String("key1"), QLatin1String("value1")); + map.insert(QLatin1String("key2"), QLatin1String("value2")); + QJsonObject object = QJsonObject::fromVariantMap(map); + QCOMPARE(object.size(), 2); + QCOMPARE(object.value(QLatin1String("key1")), QJsonValue(QLatin1String("value1"))); + QCOMPARE(object.value(QLatin1String("key2")), QJsonValue(QLatin1String("value2"))); + + QVariantList list; + list.append(true); + list.append(QVariant()); + list.append(999.); + list.append(QLatin1String("foo")); + map.insert("list", list); + object = QJsonObject::fromVariantMap(map); + QCOMPARE(object.size(), 3); + QCOMPARE(object.value(QLatin1String("key1")), QJsonValue(QLatin1String("value1"))); + QCOMPARE(object.value(QLatin1String("key2")), QJsonValue(QLatin1String("value2"))); + QCOMPARE(object.value(QLatin1String("list")).type(), QJsonValue::Array); + QJsonArray array = object.value(QLatin1String("list")).toArray(); + QCOMPARE(array.size(), 4); + QCOMPARE(array.at(0).type(), QJsonValue::Bool); + QCOMPARE(array.at(0).toBool(), true); + QCOMPARE(array.at(1).type(), QJsonValue::Null); + QCOMPARE(array.at(2).type(), QJsonValue::Double); + QCOMPARE(array.at(2).toDouble(), 999.); + QCOMPARE(array.at(3).type(), QJsonValue::String); + QCOMPARE(array.at(3).toString(), QLatin1String("foo")); +} + +void TestQtJson::toVariantMap() +{ + QJsonObject object; + object.insert("Key", QString("Value")); + object.insert("null", QJsonValue()); + QJsonArray array; + array.append(true); + array.append(999.); + array.append(QLatin1String("string")); + array.append(QJsonValue()); + object.insert("Array", array); + + QVariantMap map = object.toVariantMap(); + + QCOMPARE(map.size(), 3); + QCOMPARE(map.value("Key"), QVariant(QString("Value"))); + QCOMPARE(map.value("null"), QVariant()); + QCOMPARE(map.value("Array").type(), QVariant::List); + QVariantList list = map.value("Array").toList(); + QCOMPARE(list.size(), 4); + QCOMPARE(list.at(0), QVariant(true)); + QCOMPARE(list.at(1), QVariant(999.)); + QCOMPARE(list.at(2), QVariant(QLatin1String("string"))); + QCOMPARE(list.at(3), QVariant()); +} + +void TestQtJson::toJson() +{ + QJsonObject object; + object.insert("\\Key\n", QString("Value")); + object.insert("null", QJsonValue()); + QJsonArray array; + array.append(true); + array.append(999.); + array.append(QLatin1String("string")); + array.append(QJsonValue()); + array.append(QLatin1String("\\\a\n\r\b\tabcABC\"")); + object.insert("Array", array); + + QByteArray json = QJsonDocument(object).toJson(); + + QByteArray expected = + "{\n" + " \"Array\": [\n" + " true,\n" + " 999,\n" + " \"string\",\n" + " null,\n" + " \"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"\n" + " ],\n" + " \"\\\\Key\\n\": \"Value\",\n" + " \"null\": null\n" + "}\n"; + QCOMPARE(json, expected); + + QJsonDocument doc; + doc.setObject(object); + json = doc.toJson(); + QCOMPARE(json, expected); + + doc.setArray(array); + json = doc.toJson(); + expected = + "[\n" + " true,\n" + " 999,\n" + " \"string\",\n" + " null,\n" + " \"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"\n" + "]\n"; + QCOMPARE(json, expected); +} + +void TestQtJson::fromJson() +{ + { + QByteArray json = "[\n true\n]\n"; + QJsonDocument doc = QJsonDocument::fromJson(json); + QVERIFY(!doc.isEmpty()); + QCOMPARE(doc.isArray(), true); + QCOMPARE(doc.isObject(), false); + QJsonArray array = doc.array(); + QCOMPARE(array.size(), 1); + QCOMPARE(array.at(0).type(), QJsonValue::Bool); + QCOMPARE(array.at(0).toBool(), true); + QCOMPARE(doc.toJson(), json); + } + { + QByteArray json = "[]"; + QJsonDocument doc = QJsonDocument::fromJson(json); + QVERIFY(!doc.isEmpty()); + QCOMPARE(doc.isArray(), true); + QCOMPARE(doc.isObject(), false); + QJsonArray array = doc.array(); + QCOMPARE(array.size(), 0); + } + { + QByteArray json = "{}"; + QJsonDocument doc = QJsonDocument::fromJson(json); + QVERIFY(!doc.isEmpty()); + QCOMPARE(doc.isArray(), false); + QCOMPARE(doc.isObject(), true); + QJsonObject object = doc.object(); + QCOMPARE(object.size(), 0); + } + { + QByteArray json = "{\n \"Key\": true\n}\n"; + QJsonDocument doc = QJsonDocument::fromJson(json); + QVERIFY(!doc.isEmpty()); + QCOMPARE(doc.isArray(), false); + QCOMPARE(doc.isObject(), true); + QJsonObject object = doc.object(); + QCOMPARE(object.size(), 1); + QCOMPARE(object.value("Key"), QJsonValue(true)); + QCOMPARE(doc.toJson(), json); + } + { + QByteArray json = "[ null, true, false, \"Foo\", 1, [], {} ]"; + QJsonDocument doc = QJsonDocument::fromJson(json); + QVERIFY(!doc.isEmpty()); + QCOMPARE(doc.isArray(), true); + QCOMPARE(doc.isObject(), false); + QJsonArray array = doc.array(); + QCOMPARE(array.size(), 7); + QCOMPARE(array.at(0).type(), QJsonValue::Null); + QCOMPARE(array.at(1).type(), QJsonValue::Bool); + QCOMPARE(array.at(1).toBool(), true); + QCOMPARE(array.at(2).type(), QJsonValue::Bool); + QCOMPARE(array.at(2).toBool(), false); + QCOMPARE(array.at(3).type(), QJsonValue::String); + QCOMPARE(array.at(3).toString(), QLatin1String("Foo")); + QCOMPARE(array.at(4).type(), QJsonValue::Double); + QCOMPARE(array.at(4).toDouble(), 1.); + QCOMPARE(array.at(5).type(), QJsonValue::Array); + QCOMPARE(array.at(5).toArray().size(), 0); + QCOMPARE(array.at(6).type(), QJsonValue::Object); + QCOMPARE(array.at(6).toObject().size(), 0); + } + { + QByteArray json = "{ \"0\": null, \"1\": true, \"2\": false, \"3\": \"Foo\", \"4\": 1, \"5\": [], \"6\": {} }"; + QJsonDocument doc = QJsonDocument::fromJson(json); + QVERIFY(!doc.isEmpty()); + QCOMPARE(doc.isArray(), false); + QCOMPARE(doc.isObject(), true); + QJsonObject object = doc.object(); + QCOMPARE(object.size(), 7); + QCOMPARE(object.value("0").type(), QJsonValue::Null); + QCOMPARE(object.value("1").type(), QJsonValue::Bool); + QCOMPARE(object.value("1").toBool(), true); + QCOMPARE(object.value("2").type(), QJsonValue::Bool); + QCOMPARE(object.value("2").toBool(), false); + QCOMPARE(object.value("3").type(), QJsonValue::String); + QCOMPARE(object.value("3").toString(), QLatin1String("Foo")); + QCOMPARE(object.value("4").type(), QJsonValue::Double); + QCOMPARE(object.value("4").toDouble(), 1.); + QCOMPARE(object.value("5").type(), QJsonValue::Array); + QCOMPARE(object.value("5").toArray().size(), 0); + QCOMPARE(object.value("6").type(), QJsonValue::Object); + QCOMPARE(object.value("6").toObject().size(), 0); + } +} + +void TestQtJson::fromBinary() +{ + QFile file(QLatin1String("test.json")); + file.open(QFile::ReadOnly); + QByteArray testJson = file.readAll(); + + QJsonDocument doc = QJsonDocument::fromJson(testJson); + QJsonDocument outdoc = QJsonDocument::fromBinaryData(doc.toBinaryData()); + QVERIFY(!outdoc.isNull()); + QVERIFY(doc == outdoc); + + QFile bfile(QLatin1String("test.bjson")); + bfile.open(QFile::ReadOnly); + QByteArray binary = bfile.readAll(); + + QJsonDocument bdoc = QJsonDocument::fromBinaryData(binary); + QVERIFY(!bdoc.isNull()); + QVERIFY(doc.toVariant() == bdoc.toVariant()); + QVERIFY(doc == bdoc); +} + +void TestQtJson::toAndFromBinary_data() +{ + QTest::addColumn("filename"); + QTest::newRow("test.json") << QString::fromLatin1("test.json"); + QTest::newRow("test2.json") << QString::fromLatin1("test2.json"); +} + +void TestQtJson::toAndFromBinary() +{ + QFETCH(QString, filename); + QFile file(filename); + QVERIFY(file.open(QFile::ReadOnly)); + QByteArray data = file.readAll(); + + QJsonDocument doc = QJsonDocument::fromJson(data); + QVERIFY(!doc.isNull()); + QJsonDocument outdoc = QJsonDocument::fromBinaryData(doc.toBinaryData()); + QVERIFY(!outdoc.isNull()); + QVERIFY(doc == outdoc); +} + +void TestQtJson::parseNumbers() +{ + { + // test number parsing + struct Numbers { + const char *str; + int n; + }; + Numbers numbers [] = { + { "0", 0 }, + { "1", 1 }, + { "10", 10 }, + { "-1", -1 }, + { "100000", 100000 }, + { "-999", -999 } + }; + int size = sizeof(numbers)/sizeof(Numbers); + for (int i = 0; i < size; ++i) { + QByteArray json = "[ "; + json += numbers[i].str; + json += " ]"; + QJsonDocument doc = QJsonDocument::fromJson(json); + QVERIFY(!doc.isEmpty()); + QCOMPARE(doc.isArray(), true); + QCOMPARE(doc.isObject(), false); + QJsonArray array = doc.array(); + QCOMPARE(array.size(), 1); + QJsonValue val = array.at(0); + QCOMPARE(val.type(), QJsonValue::Double); + QCOMPARE(val.toDouble(), (double)numbers[i].n); + } + } + { + // test number parsing + struct Numbers { + const char *str; + double n; + }; + Numbers numbers [] = { + { "0", 0 }, + { "1", 1 }, + { "10", 10 }, + { "-1", -1 }, + { "100000", 100000 }, + { "-999", -999 }, + { "1.1", 1.1 }, + { "1e10", 1e10 }, + { "-1.1", -1.1 }, + { "-1e10", -1e10 }, + { "-1E10", -1e10 }, + { "1.1e10", 1.1e10 }, + { "1.1e308", 1.1e308 }, + { "-1.1e308", -1.1e308 }, + { "1.1e-308", 1.1e-308 }, + { "-1.1e-308", -1.1e-308 }, + { "1.1e+308", 1.1e+308 }, + { "-1.1e+308", -1.1e+308 }, + { "1.e+308", 1.e+308 }, + { "-1.e+308", -1.e+308 } + }; + int size = sizeof(numbers)/sizeof(Numbers); + for (int i = 0; i < size; ++i) { + QByteArray json = "[ "; + json += numbers[i].str; + json += " ]"; + QJsonDocument doc = QJsonDocument::fromJson(json); + QVERIFY(!doc.isEmpty()); + QCOMPARE(doc.isArray(), true); + QCOMPARE(doc.isObject(), false); + QJsonArray array = doc.array(); + QCOMPARE(array.size(), 1); + QJsonValue val = array.at(0); + QCOMPARE(val.type(), QJsonValue::Double); + QCOMPARE(val.toDouble(), numbers[i].n); + } + } +} + +void TestQtJson::parseStrings() +{ + const char *strings [] = + { + "Foo", + "abc\\\"abc", + "abc\\\\abc", + "abc\\babc", + "abc\\fabc", + "abc\\nabc", + "abc\\rabc", + "abc\\tabc", + "abc\\u0019abc", + "abcЂabc", + }; + int size = sizeof(strings)/sizeof(const char *); + + for (int i = 0; i < size; ++i) { + QByteArray json = "[\n \""; + json += strings[i]; + json += "\"\n]\n"; + QJsonDocument doc = QJsonDocument::fromJson(json); + QVERIFY(!doc.isEmpty()); + QCOMPARE(doc.isArray(), true); + QCOMPARE(doc.isObject(), false); + QJsonArray array = doc.array(); + QCOMPARE(array.size(), 1); + QJsonValue val = array.at(0); + QCOMPARE(val.type(), QJsonValue::String); + + QCOMPARE(doc.toJson(), json); + } + + struct Pairs { + const char *in; + const char *out; + }; + Pairs pairs [] = { + { "abc\\/abc", "abc/abc" }, + { "abc\\u0402abc", "abcЂabc" }, + { "abc\\u0065abc", "abceabc" } + }; + size = sizeof(pairs)/sizeof(Pairs); + + for (int i = 0; i < size; ++i) { + QByteArray json = "[\n \""; + json += pairs[i].in; + json += "\"\n]\n"; + QByteArray out = "[\n \""; + out += pairs[i].out; + out += "\"\n]\n"; + QJsonDocument doc = QJsonDocument::fromJson(json); + QVERIFY(!doc.isEmpty()); + QCOMPARE(doc.isArray(), true); + QCOMPARE(doc.isObject(), false); + QJsonArray array = doc.array(); + QCOMPARE(array.size(), 1); + QJsonValue val = array.at(0); + QCOMPARE(val.type(), QJsonValue::String); + + QCOMPARE(doc.toJson(), out); + } + +} + +void TestQtJson::parseDuplicateKeys() +{ + const char *json = "{ \"B\": true, \"A\": null, \"B\": false }"; + + QJsonDocument doc = QJsonDocument::fromJson(json); + QCOMPARE(doc.isObject(), true); + + QJsonObject o = doc.object(); + QCOMPARE(o.size(), 2); + QJsonObject::const_iterator it = o.constBegin(); + QCOMPARE(it.key(), QLatin1String("A")); + QCOMPARE(it.value(), QJsonValue()); + ++it; + QCOMPARE(it.key(), QLatin1String("B")); + QCOMPARE(it.value(), QJsonValue(false)); +} + +void TestQtJson::testParser() +{ + QFile file(QLatin1String("test.json")); + file.open(QFile::ReadOnly); + QByteArray testJson = file.readAll(); + + QJsonDocument doc = QJsonDocument::fromJson(testJson); + QVERIFY(!doc.isEmpty()); +} + +void TestQtJson::compactArray() +{ + QJsonArray array; + array.append(QLatin1String("First Entry")); + array.append(QLatin1String("Second Entry")); + array.append(QLatin1String("Third Entry")); + QJsonDocument doc(array); + int s = doc.toBinaryData().size(); + array.removeAt(1); + doc.setArray(array); + QVERIFY(s > doc.toBinaryData().size()); + s = doc.toBinaryData().size(); + QCOMPARE(doc.toJson(), + QByteArray("[\n" + " \"First Entry\",\n" + " \"Third Entry\"\n" + "]\n")); + + array.removeAt(0); + doc.setArray(array); + QVERIFY(s > doc.toBinaryData().size()); + s = doc.toBinaryData().size(); + QCOMPARE(doc.toJson(), + QByteArray("[\n" + " \"Third Entry\"\n" + "]\n")); + + array.removeAt(0); + doc.setArray(array); + QVERIFY(s > doc.toBinaryData().size()); + s = doc.toBinaryData().size(); + QCOMPARE(doc.toJson(), + QByteArray("[\n" + "]\n")); + +} + +void TestQtJson::compactObject() +{ + QJsonObject object; + object.insert(QLatin1String("Key1"), QLatin1String("First Entry")); + object.insert(QLatin1String("Key2"), QLatin1String("Second Entry")); + object.insert(QLatin1String("Key3"), QLatin1String("Third Entry")); + QJsonDocument doc(object); + int s = doc.toBinaryData().size(); + object.remove(QLatin1String("Key2")); + doc.setObject(object); + QVERIFY(s > doc.toBinaryData().size()); + s = doc.toBinaryData().size(); + QCOMPARE(doc.toJson(), + QByteArray("{\n" + " \"Key1\": \"First Entry\",\n" + " \"Key3\": \"Third Entry\"\n" + "}\n")); + + object.remove(QLatin1String("Key1")); + doc.setObject(object); + QVERIFY(s > doc.toBinaryData().size()); + s = doc.toBinaryData().size(); + QCOMPARE(doc.toJson(), + QByteArray("{\n" + " \"Key3\": \"Third Entry\"\n" + "}\n")); + + object.remove(QLatin1String("Key3")); + doc.setObject(object); + QVERIFY(s > doc.toBinaryData().size()); + s = doc.toBinaryData().size(); + QCOMPARE(doc.toJson(), + QByteArray("{\n" + "}\n")); + +} + +void TestQtJson::validation() +{ + // this basically tests that we don't crash on corrupt data + QFile file(QLatin1String("test.json")); + file.open(QFile::ReadOnly); + QByteArray testJson = file.readAll(); + + QJsonDocument doc = QJsonDocument::fromJson(testJson); + + QByteArray binary = doc.toBinaryData(); + + // only test the first 1000 bytes. Testing the full file takes too long + for (int i = 0; i < 1000; ++i) { + QByteArray corrupted = binary; + corrupted[i] = 0xff; + QJsonDocument doc = QJsonDocument::fromBinaryData(corrupted); + if (doc.isNull()) + continue; + QByteArray json = doc.toJson(); + } + + + QFile file2(QLatin1String("foo.json")); + file2.open(QFile::ReadOnly); + testJson = file2.readAll(); + + doc = QJsonDocument::fromJson(testJson); + + binary = doc.toBinaryData(); + + for (int i = 0; i < binary.size(); ++i) { + QByteArray corrupted = binary; + corrupted[i] = 0xff; + QJsonDocument doc = QJsonDocument::fromBinaryData(corrupted); + if (doc.isNull()) + continue; + QByteArray json = doc.toJson(); + + corrupted = binary; + corrupted[i] = 0x00; + doc = QJsonDocument::fromBinaryData(corrupted); + if (doc.isNull()) + continue; + json = doc.toJson(); + } +} + +void TestQtJson::assignToDocument() +{ + { + const char *json = "{ \"inner\": { \"key\": true } }"; + QJsonDocument doc = QJsonDocument::fromJson(json); + + QJsonObject o = doc.object(); + QJsonValue inner = o.value("inner"); + + QJsonDocument innerDoc(inner.toObject()); + + QVERIFY(innerDoc != doc); + QVERIFY(innerDoc.object() == inner.toObject()); + } + { + const char *json = "[ [ true ] ]"; + QJsonDocument doc = QJsonDocument::fromJson(json); + + QJsonArray a = doc.array(); + QJsonValue inner = a.at(0); + + QJsonDocument innerDoc(inner.toArray()); + + QVERIFY(innerDoc != doc); + QVERIFY(innerDoc.array() == inner.toArray()); + } +} + + +void TestQtJson::testDuplicateKeys() +{ + QJsonObject obj; + obj.insert(QLatin1String("foo"), QLatin1String("bar")); + obj.insert(QLatin1String("foo"), QLatin1String("zap")); + QCOMPARE(obj.size(), 1); + QCOMPARE(obj.value(QLatin1String("foo")).toString(), QLatin1String("zap")); +} + +void TestQtJson::testCompaction() +{ + // modify object enough times to trigger compactionCounter + // and make sure the data is still valid + QJsonObject obj; + for (int i = 0; i < 33; ++i) { + obj.remove(QLatin1String("foo")); + obj.insert(QLatin1String("foo"), QLatin1String("bar")); + } + QCOMPARE(obj.size(), 1); + QCOMPARE(obj.value(QLatin1String("foo")).toString(), QLatin1String("bar")); + + QJsonDocument doc = QJsonDocument::fromBinaryData(QJsonDocument(obj).toBinaryData()); + QVERIFY(!doc.isNull()); + QVERIFY(!doc.isEmpty()); + QCOMPARE(doc.isArray(), false); + QCOMPARE(doc.isObject(), true); + QVERIFY(doc.object() == obj); +} + +void TestQtJson::testDebugStream() +{ + { + // QJsonObject + + QJsonObject object; + QTest::ignoreMessage(QtDebugMsg, "QJsonObject() "); + qDebug() << object; + + object.insert(QLatin1String("foo"), QLatin1String("bar")); + QTest::ignoreMessage(QtDebugMsg, "QJsonObject({\"foo\": \"bar\"}) "); + qDebug() << object; + } + + { + // QJsonArray + + QJsonArray array; + QTest::ignoreMessage(QtDebugMsg, "QJsonArray() "); + qDebug() << array; + + array.append(1); + array.append(QLatin1String("foo")); + QTest::ignoreMessage(QtDebugMsg, "QJsonArray([1,\"foo\"]) "); + qDebug() << array; + } + + { + // QJsonDocument + + QJsonDocument doc; + QTest::ignoreMessage(QtDebugMsg, "QJsonDocument() "); + qDebug() << doc; + + QJsonObject object; + object.insert(QLatin1String("foo"), QLatin1String("bar")); + doc.setObject(object); + QTest::ignoreMessage(QtDebugMsg, "QJsonDocument({\"foo\": \"bar\"}) "); + qDebug() << doc; + + QJsonArray array; + array.append(1); + array.append(QLatin1String("foo")); + QTest::ignoreMessage(QtDebugMsg, "QJsonDocument([1,\"foo\"]) "); + doc.setArray(array); + qDebug() << doc; + } + + { + // QJsonValue + + QJsonValue value; + + QTest::ignoreMessage(QtDebugMsg, "QJsonValue(null) "); + qDebug() << value; + + value = QJsonValue(true); // bool + QTest::ignoreMessage(QtDebugMsg, "QJsonValue(bool, true) "); + qDebug() << value; + + value = QJsonValue((double)4.2); // double + QTest::ignoreMessage(QtDebugMsg, "QJsonValue(double, 4.2) "); + qDebug() << value; + + value = QJsonValue((int)42); // int + QTest::ignoreMessage(QtDebugMsg, "QJsonValue(double, 42) "); + qDebug() << value; + + value = QJsonValue(QLatin1String("foo")); // string + QTest::ignoreMessage(QtDebugMsg, "QJsonValue(string, \"foo\") "); + qDebug() << value; + + QJsonArray array; + array.append(1); + array.append(QLatin1String("foo")); + value = QJsonValue(array); // array + QTest::ignoreMessage(QtDebugMsg, "QJsonValue(array, QJsonArray([1,\"foo\"]) ) "); + qDebug() << value; + + QJsonObject object; + object.insert(QLatin1String("foo"), QLatin1String("bar")); + value = QJsonValue(object); // object + QTest::ignoreMessage(QtDebugMsg, "QJsonValue(object, QJsonObject({\"foo\": \"bar\"}) ) "); + qDebug() << value; + } +} + +void TestQtJson::testCompactionError() +{ + QJsonObject schemaObject; + schemaObject.insert("_Type", QLatin1String("_SchemaType")); + schemaObject.insert("name", QLatin1String("Address")); + schemaObject.insert("schema", QJsonObject()); + { + QJsonObject content(schemaObject); + QJsonDocument doc(content); + QVERIFY(!doc.isNull()); + QByteArray hash = QCryptographicHash::hash(doc.toBinaryData(), QCryptographicHash::Md5).toHex(); + schemaObject.insert("_Version", QString::fromLatin1(hash.constData(), hash.size())); + } + + QJsonObject schema; + schema.insert("streetNumber", schema.value("number").toObject()); + schemaObject.insert("schema", schema); + { + QJsonObject content(schemaObject); + content.remove("_Uuid"); + content.remove("_Version"); + QJsonDocument doc(content); + QVERIFY(!doc.isNull()); + QByteArray hash = QCryptographicHash::hash(doc.toBinaryData(), QCryptographicHash::Md5).toHex(); + schemaObject.insert("_Version", QString::fromLatin1(hash.constData(), hash.size())); + } +} + +QTEST_MAIN(TestQtJson) +#include "tst_qtjson.moc" -- cgit v1.2.3