diff options
Diffstat (limited to 'tests/auto/corelib/serialization/json')
5 files changed, 560 insertions, 157 deletions
diff --git a/tests/auto/corelib/serialization/json/CMakeLists.txt b/tests/auto/corelib/serialization/json/CMakeLists.txt index 77d15bedc3..c73a99a3b8 100644 --- a/tests/auto/corelib/serialization/json/CMakeLists.txt +++ b/tests/auto/corelib/serialization/json/CMakeLists.txt @@ -1,39 +1,35 @@ -# Generated from json.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_json Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_json LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +set(json_resource_files + "bom.json" + "test.json" + "test2.json" + "test3.json" + "simple.duplicates.json" + "test.duplicates.json" + "test3.duplicates.json" +) + qt_internal_add_test(tst_json SOURCES tst_qtjson.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate + Qt::TestPrivate + TESTDATA ${json_resource_files} ) -## Scopes: -##################################################################### - -#### Keys ignored in scope 2:.:.:json.pro:NOT ANDROID: -# TESTDATA = "bom.json" "test.json" "test3.json" "test2.json" - -if(ANDROID OR INTEGRITY) - # Resources: - set(json_resource_files - "bom.json" - "test.json" - "test2.json" - "test3.json" - ) - - qt_internal_add_resource(tst_json "json" - PREFIX - "/" - FILES - ${json_resource_files} - ) -endif() - qt_internal_extend_target(tst_json CONDITION NOT QT_FEATURE_doubleconversion AND NOT QT_FEATURE_system_doubleconversion DEFINES QT_NO_DOUBLECONVERSION diff --git a/tests/auto/corelib/serialization/json/simple.duplicates.json b/tests/auto/corelib/serialization/json/simple.duplicates.json new file mode 100644 index 0000000000..6f989e8aa9 --- /dev/null +++ b/tests/auto/corelib/serialization/json/simple.duplicates.json @@ -0,0 +1 @@ +{"":{"":0},"":0} diff --git a/tests/auto/corelib/serialization/json/test.duplicates.json b/tests/auto/corelib/serialization/json/test.duplicates.json new file mode 100644 index 0000000000..0d5af8ef74 --- /dev/null +++ b/tests/auto/corelib/serialization/json/test.duplicates.json @@ -0,0 +1,66 @@ +[ + "JSON Test Pattern pass1", + {"a":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "a": 1234567890, + "a": -9876.543210, + "a": 0.123456789e-12, + "a": 1.234567890E+34, + "a": 23456789012E66, + "a": 0, + "a": 1, + "a": " ", + "a": "\"", + "a": "\\", + "a": "\b\f\n\r\t", + "a": "/ & \/", + "a": "abcdefghijklmnopqrstuvwxyz", + "a": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "a": "0123456789", + "a": "digit", + "a": "`1~!@#$%^&*()_+-={':[,]}|;.</>?", + "a": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + "a": true, + "a": false, + "a": null, + "a":[ ], + "a":{ }, + "a": "50 St. James Street", + "a": "nix", + "a": "// /* <!-- --", + "a": " ", + "a":[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"a":[1,2,3,4,5,6,7], + "a": "\"a:[\"array with 1 element\"]}", + "a": "" \u0022 %22 0x22 034 "", + "a": "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00, +2e+00, +2e-00, +"rosebud", +{"a": "bar"}, +{"a":{"a":1000,"a":{"a":"nix"}},"a":{"a":{"a":{"a":"$0.01","a":1},"a":{"a":"$4,833.99","a":483399}},"a":[{"a":"PRODUCT","a":"Silicone c","a":"Elite Hori","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":310711221747712.000000,"a":{"a":{"a":"$1.56","a":156},"a":{"a":"$29.99","a":2999},"a":14},"a":1968262863,"a":8515},{"a":"PRODUCT","a":"Nonslip Ch","a":"Specificat","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":175580930637824.000000,"a":{"a":{"a":"$0.45","a":45},"a":{"a":"$194.95","a":19495},"a":34},"a":2534935499,"a":8515},{"a":"PRODUCT","a":"Plastic Ca","a":"Descriptio","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":132488642953216.000000,"a":{"a":{"a":"$0.99","a":99},"a":{"a":"$303.68","a":30368},"a":33},"a":2305624670,"a":8515},{"a":"PRODUCT","a":"Protective","a":"Made of hi","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":108614681362432.000000,"a":{"a":{"a":"$1.70","a":170},"a":{"a":"$99.99","a":9999},"a":11},"a":2120981405,"a":8515},{"a":"PRODUCT","a":"P® 4","a":"Do more th","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":96203484168192.000000,"a":{"a":{"a":"$2.49","a":249},"a":{"a":"$79.95","a":7995},"a":16},"a":2203798762,"a":8515},{"a":"PRODUCT","a":"Case Refle","a":"NCAA iPhon","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":84727583211520.000000,"a":{"a":{"a":"$0.69","a":69},"a":{"a":"$75.52","a":7552},"a":59},"a":1114627445,"a":8515},{"a":"PRODUCT","a":"Infuse Pro","a":"Protect an","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":80831066406912.000000,"a":{"a":{"a":"$0.59","a":59},"a":{"a":"$79.00","a":7900},"a":24},"a":2557462717,"a":8515},{"a":"PRODUCT","a":"Dragonfly ","a":"d","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":70900229603328.000000,"a":{"a":{"a":"$1.05","a":105},"a":{"a":"$94.49","a":9449},"a":30},"a":2442061740,"a":8515},{"a":"PRODUCT","a":"Pho","a":"Snap on Ap","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":65194915004416.000000,"a":{"a":{"a":"$0.01","a":1},"a":{"a":"$414.99","a":41499},"a":39},"a":2004746863,"a":8515},{"a":"PRODUCT","a":"Otterbox i","a":"Your iPhon","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":61515478597632.000000,"a":{"a":{"a":"$3.28","a":328},"a":{"a":"$110.65","a":11065},"a":25},"a":2584611575,"a":8515}],"a":10,"a":2000}}, +{"a":{"a":1000,"a":{"a":"nix"}},"a":{"a":{"a":{"a":"$0.01","a":1},"a":{"a":"$4,833.99","a":483399}},"a":[{"a":"PRODUCT","a":"Silicone c","a":"Elite Hori","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":310711221747712.000000,"a":{"a":{"a":"$1.56","a":156},"a":{"a":"$29.99","a":2999},"a":14},"a":1968262863,"a":8515},{"a":"PRODUCT","a":"Nonslip Ch","a":"Specificat","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":175580930637824.000000,"a":{"a":{"a":"$0.45","a":45},"a":{"a":"$194.95","a":19495},"a":34},"a":2534935499,"a":8515},{"a":"PRODUCT","a":"Plastic Ca","a":"Descriptio","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":132488642953216.000000,"a":{"a":{"a":"$0.99","a":99},"a":{"a":"$303.68","a":30368},"a":33},"a":2305624670,"a":8515},{"a":"PRODUCT","a":"Protective","a":"Made of hi","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":108614681362432.000000,"a":{"a":{"a":"$1.70","a":170},"a":{"a":"$99.99","a":9999},"a":11},"a":2120981405,"a":8515},{"a":"PRODUCT","a":"P® 4","a":"Do more th","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":96203484168192.000000,"a":{"a":{"a":"$2.49","a":249},"a":{"a":"$79.95","a":7995},"a":16},"a":2203798762,"a":8515},{"a":"PRODUCT","a":"Case Refle","a":"NCAA iPhon","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":84727583211520.000000,"a":{"a":{"a":"$0.69","a":69},"a":{"a":"$75.52","a":7552},"a":59},"a":1114627445,"a":8515},{"a":"PRODUCT","a":"Infuse Pro","a":"Protect an","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":80831066406912.000000,"a":{"a":{"a":"$0.59","a":59},"a":{"a":"$79.00","a":7900},"a":24},"a":2557462717,"a":8515},{"a":"PRODUCT","a":"Dragonfly ","a":"d","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":70900229603328.000000,"a":{"a":{"a":"$1.05","a":105},"a":{"a":"$94.49","a":9449},"a":30},"a":2442061740,"a":8515},{"a":"PRODUCT","a":"Pho","a":"Snap on Ap","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":65194915004416.000000,"a":{"a":{"a":"$0.01","a":1},"a":{"a":"$414.99","a":41499},"a":39},"a":2004746863,"a":8515},{"a":"PRODUCT","a":"Otterbox i","a":"Your iPhon","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":61515478597632.000000,"a":{"a":{"a":"$3.28","a":328},"a":{"a":"$110.65","a":11065},"a":25},"a":2584611575,"a":8515}],"a":10,"a":2000}}, +{"a":{"a":1000,"a":{"a":"nix"}},"a":{"a":{"a":{"a":"$0.01","a":1},"a":{"a":"$4,833.99","a":483399}},"a":[{"a":"PRODUCT","a":"Silicone c","a":"Elite Hori","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":310711221747712.000000,"a":{"a":{"a":"$1.56","a":156},"a":{"a":"$29.99","a":2999},"a":14},"a":1968262863,"a":8515},{"a":"PRODUCT","a":"Nonslip Ch","a":"Specificat","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":175580930637824.000000,"a":{"a":{"a":"$0.45","a":45},"a":{"a":"$194.95","a":19495},"a":34},"a":2534935499,"a":8515},{"a":"PRODUCT","a":"Plastic Ca","a":"Descriptio","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":132488642953216.000000,"a":{"a":{"a":"$0.99","a":99},"a":{"a":"$303.68","a":30368},"a":33},"a":2305624670,"a":8515},{"a":"PRODUCT","a":"Protective","a":"Made of hi","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":108614681362432.000000,"a":{"a":{"a":"$1.70","a":170},"a":{"a":"$99.99","a":9999},"a":11},"a":2120981405,"a":8515},{"a":"PRODUCT","a":"P® 4","a":"Do more th","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":96203484168192.000000,"a":{"a":{"a":"$2.49","a":249},"a":{"a":"$79.95","a":7995},"a":16},"a":2203798762,"a":8515},{"a":"PRODUCT","a":"Case Refle","a":"NCAA iPhon","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":84727583211520.000000,"a":{"a":{"a":"$0.69","a":69},"a":{"a":"$75.52","a":7552},"a":59},"a":1114627445,"a":8515},{"a":"PRODUCT","a":"Infuse Pro","a":"Protect an","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":80831066406912.000000,"a":{"a":{"a":"$0.59","a":59},"a":{"a":"$79.00","a":7900},"a":24},"a":2557462717,"a":8515},{"a":"PRODUCT","a":"Dragonfly ","a":"d","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":70900229603328.000000,"a":{"a":{"a":"$1.05","a":105},"a":{"a":"$94.49","a":9449},"a":30},"a":2442061740,"a":8515},{"a":"PRODUCT","a":"Pho","a":"Snap on Ap","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":65194915004416.000000,"a":{"a":{"a":"$0.01","a":1},"a":{"a":"$414.99","a":41499},"a":39},"a":2004746863,"a":8515},{"a":"PRODUCT","a":"Otterbox i","a":"Your iPhon","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":61515478597632.000000,"a":{"a":{"a":"$3.28","a":328},"a":{"a":"$110.65","a":11065},"a":25},"a":2584611575,"a":8515}],"a":10,"a":2000}}, +{"a":{"a":1000,"a":{"a":"nix"}},"a":{"a":{"a":{"a":"$0.01","a":1},"a":{"a":"$4,833.99","a":483399}},"a":[{"a":"PRODUCT","a":"Silicone c","a":"Elite Hori","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":310711221747712.000000,"a":{"a":{"a":"$1.56","a":156},"a":{"a":"$29.99","a":2999},"a":14},"a":1968262863,"a":8515},{"a":"PRODUCT","a":"Nonslip Ch","a":"Specificat","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":175580930637824.000000,"a":{"a":{"a":"$0.45","a":45},"a":{"a":"$194.95","a":19495},"a":34},"a":2534935499,"a":8515},{"a":"PRODUCT","a":"Plastic Ca","a":"Descriptio","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":132488642953216.000000,"a":{"a":{"a":"$0.99","a":99},"a":{"a":"$303.68","a":30368},"a":33},"a":2305624670,"a":8515},{"a":"PRODUCT","a":"Protective","a":"Made of hi","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":108614681362432.000000,"a":{"a":{"a":"$1.70","a":170},"a":{"a":"$99.99","a":9999},"a":11},"a":2120981405,"a":8515},{"a":"PRODUCT","a":"P® 4","a":"Do more th","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":96203484168192.000000,"a":{"a":{"a":"$2.49","a":249},"a":{"a":"$79.95","a":7995},"a":16},"a":2203798762,"a":8515},{"a":"PRODUCT","a":"Case Refle","a":"NCAA iPhon","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":84727583211520.000000,"a":{"a":{"a":"$0.69","a":69},"a":{"a":"$75.52","a":7552},"a":59},"a":1114627445,"a":8515},{"a":"PRODUCT","a":"Infuse Pro","a":"Protect an","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":80831066406912.000000,"a":{"a":{"a":"$0.59","a":59},"a":{"a":"$79.00","a":7900},"a":24},"a":2557462717,"a":8515},{"a":"PRODUCT","a":"Dragonfly ","a":"d","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":70900229603328.000000,"a":{"a":{"a":"$1.05","a":105},"a":{"a":"$94.49","a":9449},"a":30},"a":2442061740,"a":8515},{"a":"PRODUCT","a":"Pho","a":"Snap on Ap","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":65194915004416.000000,"a":{"a":{"a":"$0.01","a":1},"a":{"a":"$414.99","a":41499},"a":39},"a":2004746863,"a":8515},{"a":"PRODUCT","a":"Otterbox i","a":"Your iPhon","a":"someone","a":{"a":"nix"},"a":{"a":[{"a":"nix","a":60,"a":60},{"a":"nix","a":100,"a":100},{"a":"nix","a":160,"a":160},{"a":"nix","a":400,"a":400}]},"a":61515478597632.000000,"a":{"a":{"a":"$3.28","a":328},"a":{"a":"$110.65","a":11065},"a":25},"a":2584611575,"a":8515}],"a":10,"a":2000}} +] + diff --git a/tests/auto/corelib/serialization/json/test3.duplicates.json b/tests/auto/corelib/serialization/json/test3.duplicates.json new file mode 100644 index 0000000000..c635a2523f --- /dev/null +++ b/tests/auto/corelib/serialization/json/test3.duplicates.json @@ -0,0 +1,15 @@ +{ + "a": "John", + "a": "Smith", + "a": 25, + "a": { + "a": "21 2nd Street", + "a": "New York", + "a": "NY", + "a": "10021" + }, + "a": [ + { "a": "home", "a": "212 555-1234" }, + { "a": "fax", "a": "646 555-4567" } + ] +} diff --git a/tests/auto/corelib/serialization/json/tst_qtjson.cpp b/tests/auto/corelib/serialization/json/tst_qtjson.cpp index 3a57d3b8a5..54ef9be4f2 100644 --- a/tests/auto/corelib/serialization/json/tst_qtjson.cpp +++ b/tests/auto/corelib/serialization/json/tst_qtjson.cpp @@ -1,33 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2021 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// Copyright (C) 2022 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> +#include <QtTest/private/qcomparisontesthelper_p.h> +#include <QMap> +#include <QVariantList> QT_WARNING_DISABLE_DEPRECATED @@ -50,6 +28,7 @@ class tst_QtJson: public QObject private Q_SLOTS: void initTestCase(); + void compareCompiles(); void testValueSimple(); void testNumbers(); void testNumbers_2(); @@ -70,9 +49,12 @@ private Q_SLOTS: void testArrayNested(); void testArrayNestedEmpty(); void testArrayComfortOperators(); + void testArrayEquality_data(); + void testArrayEquality(); void testObjectNestedEmpty(); void testValueRef(); + void testValueRefComparison(); void testObjectIteration(); void testArrayIteration(); @@ -105,6 +87,7 @@ private Q_SLOTS: void toJson(); void toJsonSillyNumericValues(); void toJsonLargeNumericValues(); + void toJsonDenormalValues(); void fromJson(); void fromJsonErrors(); void parseNumbers(); @@ -175,6 +158,8 @@ private Q_SLOTS: void fromToVariantConversions(); void testIteratorComparison(); + + void noLeakOnNameClash_data(); void noLeakOnNameClash(); private: @@ -188,6 +173,31 @@ void tst_QtJson::initTestCase() testDataDir = QCoreApplication::applicationDirPath(); } +void tst_QtJson::compareCompiles() +{ + QTestPrivate::testEqualityOperatorsCompile<QJsonArray>(); + QTestPrivate::testAllComparisonOperatorsCompile<QJsonArray::iterator>(); + QTestPrivate::testAllComparisonOperatorsCompile<QJsonArray::const_iterator>(); + QTestPrivate::testAllComparisonOperatorsCompile<QJsonArray::iterator, + QJsonArray::const_iterator>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonDocument>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonObject>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonObject::iterator>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonObject::const_iterator>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonValue>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonValueConstRef>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonValueRef>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonArray, QJsonValue>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonObject, QJsonValue>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonObject, QJsonValueConstRef>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonObject, QJsonValueRef>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonValueConstRef, QJsonValue>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonValueRef, QJsonValue>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonValueRef, QJsonValueConstRef>(); + QTestPrivate::testEqualityOperatorsCompile<QJsonObject::iterator, + QJsonObject::const_iterator>(); +} + void tst_QtJson::testValueSimple() { QJsonObject object; @@ -390,17 +400,21 @@ void tst_QtJson::testNumbers_2() QVERIFY2(floatValues[power] == floatValues_1[power], QString("floatValues[%1] != floatValues_1[%1]").arg(power).toLatin1()); } + QT_TEST_EQUALITY_OPS(jDocument1, jDocument2, true); // The last value is below min denorm and should round to 0, everything else should contain a value QVERIFY2(floatValues_1[1075] == 0, "Value after min denorm should round to 0"); // Validate the last actual value is min denorm QVERIFY2(floatValues_1[1074] == 4.9406564584124654417656879286822e-324, QString("Min denorm value is incorrect: %1").arg(floatValues_1[1074]).toLatin1()); - // Validate that every value is half the value before it up to 1 - for (int index = 1074; index > 0; index--) { - QVERIFY2(floatValues_1[index] != 0, QString("2**- %1 should not be 0").arg(index).toLatin1()); - - QVERIFY2(floatValues_1[index - 1] == (floatValues_1[index] * 2), QString("Value should be double adjacent value at index %1").arg(index).toLatin1()); + if constexpr (std::numeric_limits<double>::has_denorm == std::denorm_present) { + // Validate that every value is half the value before it up to 1 + for (int index = 1074; index > 0; index--) { + QVERIFY2(floatValues_1[index] != 0, QString("2**- %1 should not be 0").arg(index).toLatin1()); + QVERIFY2(floatValues_1[index - 1] == (floatValues_1[index] * 2), QString("Value should be double adjacent value at index %1").arg(index).toLatin1()); + } + } else { + qInfo("Skipping denormal test as this system's double type lacks support"); } } @@ -418,6 +432,10 @@ void tst_QtJson::testNumbers_3() QJsonDocument jDocument2(QJsonDocument::fromJson(ba)); + QT_TEST_EQUALITY_OPS(jDocument1, jDocument2, true); + QT_TEST_EQUALITY_OPS(jDocument1, QJsonDocument(), false); + QT_TEST_EQUALITY_OPS(QJsonDocument(), QJsonDocument(), true); + double d1_1(jDocument2.object().value("d1").toDouble()); double d2_1(jDocument2.object().value("d2").toDouble()); QVERIFY(d1_1 != d2_1); @@ -435,7 +453,8 @@ void tst_QtJson::testNumbers_4() array << QJsonValue(-9223372036854775808.0); array << QJsonValue(+18446744073709551616.0); array << QJsonValue(-18446744073709551616.0); - const QByteArray json(QJsonDocument(array).toJson()); + QJsonDocument doc1 = QJsonDocument(array); + const QByteArray json(doc1.toJson()); const QByteArray expected = "[\n" " 1000000000000000,\n" @@ -456,7 +475,8 @@ void tst_QtJson::testNumbers_4() array2 << QJsonValue(Q_INT64_C(-9007199254740992)); array2 << QJsonValue(Q_INT64_C(+9223372036854775807)); array2 << QJsonValue(Q_INT64_C(-9223372036854775807)); - const QByteArray json2(QJsonDocument(array2).toJson()); + QJsonDocument doc2 = QJsonDocument(array2); + const QByteArray json2(doc2.toJson()); const QByteArray expected2 = "[\n" " 1000000000000000,\n" @@ -467,6 +487,8 @@ void tst_QtJson::testNumbers_4() " -9223372036854775807\n" "]\n"; QCOMPARE(json2, expected2); + + QT_TEST_EQUALITY_OPS(doc1, doc2, false); } void tst_QtJson::testNumberComparisons() @@ -515,6 +537,7 @@ void tst_QtJson::testObjectSimple() QJsonValue value(QLatin1String("foo")); object.insert("value", value); QCOMPARE(object.value("value"), value); + QT_TEST_EQUALITY_OPS(object.value("value"), value, true); int size = object.size(); object.remove("boolean"); @@ -523,6 +546,7 @@ void tst_QtJson::testObjectSimple() QJsonValue taken = object.take("value"); QCOMPARE(taken, value); + QT_TEST_EQUALITY_OPS(taken, value, true); QVERIFY2(!object.contains("value"), "key value should have been removed"); QString before = object.value("string").toString(); @@ -652,6 +676,7 @@ void tst_QtJson::testObjectInsertCopies() QCOMPARE(obj.size(), 2); QCOMPARE(obj.value("value"), "TEST"); QCOMPARE(obj.value("prop2"), "TEST"); + QT_TEST_EQUALITY_OPS(rv, obj["value"].toObject(), true); } { QJsonObject obj; @@ -784,15 +809,20 @@ void tst_QtJson::testValueObject() void tst_QtJson::testValueArray() { QJsonArray array; + QJsonArray otherArray = {"wrong value"}; + QJsonValue value(array); + QCOMPARE(value.toArray(), array); + QCOMPARE(value.toArray(otherArray), array); + array.append(999.); array.append(QLatin1String("test")); array.append(true); - - QJsonValue value(array); + 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); + QCOMPARE(value.toArray(otherArray), array); // if we modify the original array, it should detach array.append(QLatin1String("test")); @@ -802,14 +832,28 @@ void tst_QtJson::testValueArray() void tst_QtJson::testObjectNested() { QJsonObject inner, outer; + QJsonObject otherObject = {{"wrong key", "wrong value"}}; + QJsonValue v = inner; + QCOMPARE(v.toObject(), inner); + QCOMPARE(v.toObject(otherObject), inner); + QT_TEST_EQUALITY_OPS(v.toObject(), inner, true); + QT_TEST_EQUALITY_OPS(v.toObject(otherObject), inner, true); + inner.insert("number", 999.); outer.insert("nested", inner); + QT_TEST_EQUALITY_OPS(outer, inner, false); // if we don't modify the original JsonObject, value() // should return the same object (non-detached). QJsonObject value = outer.value("nested").toObject(); + v = value; QCOMPARE(value, inner); QCOMPARE(value.value("number").toDouble(), 999.); + QCOMPARE(v.toObject(), inner); + QCOMPARE(v.toObject(otherObject), inner); + QT_TEST_EQUALITY_OPS(v.toObject(), inner, true); + QT_TEST_EQUALITY_OPS(v.toObject(otherObject), inner, true); + QCOMPARE(v["number"].toDouble(), 999.); // if we modify the original object, it should detach and not // affect the nested object @@ -834,6 +878,7 @@ void tst_QtJson::testObjectNested() QCOMPARE(outer.value("nested").toObject().value("nested").toObject(), twoDeep); QCOMPARE(outer.value("nested").toObject().value("nested").toObject().value("boolean").toBool(), true); + QT_TEST_EQUALITY_OPS(outer.value("nested").toObject().value("nested").toObject(), twoDeep, true); } void tst_QtJson::testArrayNested() @@ -859,6 +904,7 @@ void tst_QtJson::testArrayNested() object.insert("boolean", true); outer.append(object); QCOMPARE(outer.last().toObject(), object); + QT_TEST_EQUALITY_OPS(outer.last().toObject(), object, true); QCOMPARE(outer.last().toObject().value("boolean").toBool(), true); // two deep arrays @@ -878,6 +924,7 @@ void tst_QtJson::testArrayNestedEmpty() QJsonValue val = object.value("inner"); QJsonArray value = object.value("inner").toArray(); QVERIFY(QJsonDocument(value).isArray()); + QT_TEST_EQUALITY_OPS(QJsonDocument(), QJsonDocument(value), false); QCOMPARE(value.size(), 0); QCOMPARE(value, inner); QCOMPARE(value.size(), 0); @@ -895,14 +942,46 @@ void tst_QtJson::testObjectNestedEmpty() object.insert("inner2", inner2); QJsonObject value = object.value("inner").toObject(); QVERIFY(QJsonDocument(value).isObject()); + QT_TEST_EQUALITY_OPS(QJsonDocument(), QJsonDocument(value), false); QCOMPARE(value.size(), 0); QCOMPARE(value, inner); + QT_TEST_EQUALITY_OPS(value, inner, true); QCOMPARE(value.size(), 0); object.insert("count", 0.); QCOMPARE(object.value("inner").toObject().size(), 0); QCOMPARE(object.value("inner").type(), QJsonValue::Object); } +void tst_QtJson::testArrayEquality_data() +{ + QTest::addColumn<QJsonArray>("array1"); + QTest::addColumn<QJsonArray>("array2"); + QTest::addColumn<bool>("expectedResult"); + QTest::addRow("QJsonArray(), QJsonArray{665, 666, 667}") + << QJsonArray() << QJsonArray{665, 666, 667} << false; + QTest::addRow("QJsonArray(), QJsonArray{}") + << QJsonArray() << QJsonArray{} <<true; + QTest::addRow("QJsonArray(), QJsonArray{123, QLatin1String(\"foo\")}") + << QJsonArray() << QJsonArray{123, QLatin1String("foo")} << false; + QTest::addRow( + "QJsonArray{123,QLatin1String(\"foo\")}, QJsonArray{123,QLatin1String(\"foo\")}") + << QJsonArray{123, QLatin1String("foo")} + << QJsonArray{123, QLatin1String("foo")} + << true; +} + +void tst_QtJson::testArrayEquality() +{ + QFETCH(QJsonArray, array1); + QFETCH(QJsonArray, array2); + QFETCH(bool, expectedResult); + + QJsonValue value = QJsonValue(array1); + + QT_TEST_EQUALITY_OPS(array1, array2, expectedResult); + QT_TEST_EQUALITY_OPS(value, array2, expectedResult); +} + void tst_QtJson::testArrayComfortOperators() { QJsonArray first; @@ -942,7 +1021,7 @@ void tst_QtJson::testValueRef() QCOMPARE(object.value(QLatin1String("null")), QJsonValue()); object[QLatin1String("null")] = 100.; QCOMPARE(object.value(QLatin1String("null")).type(), QJsonValue::Double); - QJsonValue val = qAsConst(object)[QLatin1String("null")]; + QJsonValue val = std::as_const(object)[QLatin1String("null")]; QCOMPARE(val.toDouble(), 100.); QCOMPARE(object.size(), 2); @@ -952,6 +1031,63 @@ void tst_QtJson::testValueRef() QCOMPARE(object.value(QLatin1String("key")), QJsonValue(42)); } +void tst_QtJson::testValueRefComparison() +{ + QJsonValue a0 = 42.; + QJsonValue a1 = QStringLiteral("142"); + +#define CHECK_IMPL(lhs, rhs, ineq) \ + QCOMPARE(lhs, rhs); \ + QVERIFY(!(lhs != rhs)); \ + QVERIFY(lhs != ineq); \ + QVERIFY(!(lhs == ineq)); \ + QVERIFY(ineq != rhs); \ + QVERIFY(!(ineq == rhs)); \ + /* end */ + +#define CHECK(lhs, rhs, ineq) \ + do { \ + CHECK_IMPL(lhs, rhs, ineq) \ + CHECK_IMPL(std::as_const(lhs), rhs, ineq) \ + CHECK_IMPL(lhs, std::as_const(rhs), ineq) \ + CHECK_IMPL(std::as_const(lhs), std::as_const(rhs), ineq) \ + } while (0) + + // check that the (in)equality operators aren't ambiguous in C++20: + QJsonArray a = {a0, a1}; + + static_assert(std::is_same_v<decltype(a[0]), QJsonValueRef>); + + auto r0 = a.begin()[0]; + auto r1 = a.begin()[1]; + auto c0 = std::as_const(a).begin()[0]; + // ref <> ref + CHECK(r0, r0, r1); + // cref <> ref + CHECK(c0, r0, r1); + // ref <> cref + CHECK(r0, c0, r1); + // ref <> val + CHECK(r0, a0, r1); + // cref <> val + CHECK(c0, a0, r1); + // val <> ref + CHECK(a0, r0, a1); + // val <> cref + CHECK(a0, c0, a1); + // val <> val + CHECK(a0, a0, a1); + + QT_TEST_EQUALITY_OPS(r0, r1, false); + QT_TEST_EQUALITY_OPS(r0, c0, true); + QT_TEST_EQUALITY_OPS(c0, r1, false); + QT_TEST_EQUALITY_OPS(a0, c0, true); + QT_TEST_EQUALITY_OPS(a0, r1, false); + +#undef CHECK +#undef CHECK_IMPL +} + void tst_QtJson::testObjectIteration() { QJsonObject object; @@ -965,8 +1101,9 @@ void tst_QtJson::testObjectIteration() for (QJsonObject::iterator it = object.begin(); it != object.end(); ++it) QFAIL("Iterator after property add-and-remove should be empty"); - for (int i = 0; i < 10; ++i) - object[QString::number(i)] = (double)i; + // insert in weird order to confirm keys are sorted + for (int i : {0, 9, 5, 7, 8, 2, 1, 3, 6, 4}) + object[QString::number(i)] = double(i); QCOMPARE(object.size(), 10); @@ -975,44 +1112,79 @@ void tst_QtJson::testObjectIteration() for (QJsonObject::iterator it = object.begin(); it != object.end(); ++it) { QJsonValue value = it.value(); QCOMPARE((double)it.key().toInt(), value.toDouble()); + QT_TEST_EQUALITY_OPS(it, QJsonObject::iterator(), false); } { QJsonObject object2 = object; QCOMPARE(object, object2); + QT_TEST_EQUALITY_OPS(object, object2, true); QJsonValue val = *object2.begin(); - object2.erase(object2.begin()); + auto next = object2.erase(object2.begin()); QCOMPARE(object.size(), 10); QCOMPARE(object2.size(), 9); + QVERIFY(next == object2.begin()); + QT_TEST_EQUALITY_OPS(next, object2.begin(), true); - for (QJsonObject::const_iterator it = object2.constBegin(); it != object2.constEnd(); ++it) { + double d = 1; // we erased the first item + for (auto it = object2.constBegin(); it != object2.constEnd(); ++it, d += 1) { QJsonValue value = it.value(); QVERIFY(it.value() != val); - QCOMPARE((double)it.key().toInt(), value.toDouble()); + QCOMPARE(it.value(), d); + QCOMPARE(it.value().toDouble(), d); + QCOMPARE(it.key().toInt(), value.toDouble()); } } { QJsonObject object2 = object; QCOMPARE(object, object2); + QT_TEST_EQUALITY_OPS(object, object2, true); + + QJsonValue val = *(object2.end() - 1); + auto next = object2.erase(object2.end() - 1); + QCOMPARE(object.size(), 10); + QCOMPARE(object2.size(), 9); + QVERIFY(next == object2.end()); + double d = 0; + for (auto it = object2.constBegin(); it != object2.constEnd(); ++it, d += 1) { + QJsonValue value = it.value(); + QVERIFY(it.value() != val); + QCOMPARE(it.value(), d); + QCOMPARE(it.value().toDouble(), d); + QCOMPARE(it.key().toInt(), value.toDouble()); + } + } + + { + QJsonObject object2 = object; + QCOMPARE(object, object2); + QT_TEST_EQUALITY_OPS(object, object2, true); QJsonObject::iterator it = object2.find(QString::number(5)); QJsonValue val = *it; - object2.erase(it); + auto next = object2.erase(it); QCOMPARE(object.size(), 10); QCOMPARE(object2.size(), 9); + QCOMPARE(*next, 6); - for (QJsonObject::const_iterator it = object2.constBegin(); it != object2.constEnd(); ++it) { + int i = 0; + for (auto it = object2.constBegin(); it != object2.constEnd(); ++it, ++i) { + if (i == 5) + ++i; QJsonValue value = it.value(); QVERIFY(it.value() != val); - QCOMPARE((double)it.key().toInt(), value.toDouble()); + QCOMPARE(it.value(), i); + QCOMPARE(it.value().toInt(), i); + QCOMPARE(it.key().toInt(), value.toDouble()); } } { QJsonObject::Iterator it = object.begin(); it += 5; + QT_TEST_ALL_COMPARISON_OPS(it, object.begin(), Qt::strong_ordering::greater); QCOMPARE(QJsonValue(it.value()).toDouble(), 5.); it -= 3; QCOMPARE(QJsonValue(it.value()).toDouble(), 2.); @@ -1027,10 +1199,14 @@ void tst_QtJson::testObjectIteration() it += 5; QCOMPARE(QJsonValue(it.value()).toDouble(), 5.); it -= 3; + QT_TEST_ALL_COMPARISON_OPS(object.constBegin(), it, Qt::strong_ordering::less); QCOMPARE(QJsonValue(it.value()).toDouble(), 2.); QJsonObject::ConstIterator it2 = it + 5; + QT_TEST_EQUALITY_OPS(it, it2, false); QCOMPARE(QJsonValue(it2.value()).toDouble(), 7.); it2 = it - 1; + QT_TEST_ALL_COMPARISON_OPS(it2, it, Qt::strong_ordering::less); + QT_TEST_ALL_COMPARISON_OPS(it2, it - 2, Qt::strong_ordering::greater); QCOMPARE(QJsonValue(it2.value()).toDouble(), 1.); } @@ -1039,6 +1215,17 @@ void tst_QtJson::testObjectIteration() it = object.erase(it); QCOMPARE(object.size() , 0); QCOMPARE(it, object.end()); + QT_TEST_ALL_COMPARISON_OPS(it, object.end(), Qt::strong_ordering::equal); + QT_TEST_ALL_COMPARISON_OPS(it, object.constEnd(), Qt::strong_ordering::equal); + QT_TEST_ALL_COMPARISON_OPS(it, object.begin(), + Qt::strong_ordering::equal); // because object is empty + QT_TEST_ALL_COMPARISON_OPS(it, object.constBegin(), Qt::strong_ordering::equal); + QT_TEST_ALL_COMPARISON_OPS(QJsonObject::Iterator(), + QJsonObject::Iterator(), Qt::strong_ordering::equal); + QT_TEST_ALL_COMPARISON_OPS(QJsonObject::ConstIterator(), + QJsonObject::Iterator(), Qt::strong_ordering::equal); + QT_TEST_ALL_COMPARISON_OPS(QJsonObject::ConstIterator(), + QJsonObject::ConstIterator(), Qt::strong_ordering::equal); } void tst_QtJson::testArrayIteration() @@ -1052,7 +1239,11 @@ void tst_QtJson::testArrayIteration() int i = 0; for (QJsonArray::iterator it = array.begin(); it != array.end(); ++it, ++i) { QJsonValue value = (*it); + QJsonArray::iterator it1 = it; QCOMPARE((double)i, value.toDouble()); + QT_TEST_EQUALITY_OPS(QJsonArray::iterator(), QJsonArray::iterator(), true); + QT_TEST_EQUALITY_OPS(QJsonArray::iterator(), it, false); + QT_TEST_EQUALITY_OPS(it1, it, true); } QCOMPARE(array.begin()->toDouble(), array.constBegin()->toDouble()); @@ -1062,14 +1253,38 @@ void tst_QtJson::testArrayIteration() QCOMPARE(array, array2); QJsonValue val = *array2.begin(); - array2.erase(array2.begin()); + auto next = array2.erase(array2.begin()); QCOMPARE(array.size(), 10); QCOMPARE(array2.size(), 9); + QVERIFY(next == array2.begin()); i = 1; - for (QJsonArray::const_iterator it = array2.constBegin(); it != array2.constEnd(); ++it, ++i) { + for (auto it = array2.constBegin(); it != array2.constEnd(); ++it, ++i) { + QJsonValue value = (*it); + QCOMPARE(value.toInt(), i); + QCOMPARE(value.toDouble(), i); + QCOMPARE(it->toInt(), i); + QCOMPARE(it->toDouble(), i); + } + } + + { + QJsonArray array2 = array; + QCOMPARE(array, array2); + + QJsonValue val = array2.last(); + auto next = array2.erase(array2.end() - 1); + QCOMPARE(array.size(), 10); + QCOMPARE(array2.size(), 9); + QVERIFY(next == array2.end()); + + i = 0; + for (auto it = array2.constBegin(); it != array2.constEnd(); ++it, ++i) { QJsonValue value = (*it); - QCOMPARE((double)i, value.toDouble()); + QCOMPARE(value.toInt(), i); + QCOMPARE(value.toDouble(), i); + QCOMPARE(it->toInt(), i); + QCOMPARE(it->toDouble(), i); } } @@ -1083,6 +1298,13 @@ void tst_QtJson::testArrayIteration() QCOMPARE(QJsonValue(*it2).toDouble(), 7.); it2 = it - 1; QCOMPARE(QJsonValue(*it2).toDouble(), 1.); + QT_TEST_EQUALITY_OPS(it, it2, false); + it = array.begin(); + QT_TEST_EQUALITY_OPS(it, array.begin(), true); + it2 = it + 5; + QT_TEST_ALL_COMPARISON_OPS(it2, it, Qt::strong_ordering::greater); + it += 5; + QT_TEST_EQUALITY_OPS(it, it2, true); } { @@ -1102,6 +1324,26 @@ void tst_QtJson::testArrayIteration() it = array.erase(it); QCOMPARE(array.size() , 0); QCOMPARE(it, array.end()); + QT_TEST_EQUALITY_OPS(it, array.end(), true); + + { + int i = 0; + for (QJsonArray::const_iterator it = array.constBegin(); + it != array.constEnd(); ++it, ++i) { + QJsonArray::const_iterator it1 = it; + QT_TEST_EQUALITY_OPS(QJsonArray::const_iterator(), QJsonArray::const_iterator(), true); + QT_TEST_EQUALITY_OPS(QJsonArray::const_iterator(), it, false); + QT_TEST_EQUALITY_OPS(it1, it, true); + } + } + + { + QJsonArray::iterator nonConstIt = array.begin(); + QJsonArray::const_iterator it = array.constBegin(); + QT_TEST_EQUALITY_OPS(nonConstIt, it, true); + it+=1; + QT_TEST_ALL_COMPARISON_OPS(nonConstIt, it, Qt::strong_ordering::less); + } } void tst_QtJson::testObjectFind() @@ -1115,14 +1357,12 @@ void tst_QtJson::testObjectFind() QJsonObject::iterator it = object.find(QLatin1String("1")); QCOMPARE((*it).toDouble(), 1.); it = object.find(QString("11")); - QCOMPARE((*it).type(), QJsonValue::Undefined); QCOMPARE(it, object.end()); QJsonObject::const_iterator cit = object.constFind(QLatin1String("1")); QCOMPARE((*cit).toDouble(), 1.); cit = object.constFind(QString("11")); - QCOMPARE((*it).type(), QJsonValue::Undefined); - QCOMPARE(it, object.end()); + QCOMPARE(cit, object.constEnd()); } void tst_QtJson::testDocument() @@ -1197,6 +1437,8 @@ void tst_QtJson::testDocument() QCOMPARE(doc5.isObject(), false); QCOMPARE(doc5.array().size(), 1); QCOMPARE(doc5.array().at(0), QJsonValue(23)); + + QT_TEST_EQUALITY_OPS(doc2, doc3, true); } void tst_QtJson::nullValues() @@ -1568,7 +1810,8 @@ void tst_QtJson::fromVariantHash() void tst_QtJson::toVariantMap() { - QCOMPARE(QMetaType::Type(QJsonValue(QJsonObject()).toVariant().type()), QMetaType::QVariantMap); // QTBUG-32524 + QCOMPARE(QMetaType::Type(QJsonValue(QJsonObject()).toVariant().typeId()), + QMetaType::QVariantMap); // QTBUG-32524 QJsonObject object; QVariantMap map = object.toVariantMap(); @@ -1588,7 +1831,7 @@ void tst_QtJson::toVariantMap() QCOMPARE(map.size(), 3); QCOMPARE(map.value("Key"), QVariant(QString("Value"))); QCOMPARE(map.value("null"), QVariant::fromValue(nullptr)); - QCOMPARE(map.value("Array").type(), QVariant::List); + QCOMPARE(map.value("Array").typeId(), QMetaType::QVariantList); QVariantList list = map.value("Array").toList(); QCOMPARE(list.size(), 4); QCOMPARE(list.at(0), QVariant(true)); @@ -1617,7 +1860,7 @@ void tst_QtJson::toVariantHash() QCOMPARE(hash.size(), 3); QCOMPARE(hash.value("Key"), QVariant(QString("Value"))); QCOMPARE(hash.value("null"), QVariant::fromValue(nullptr)); - QCOMPARE(hash.value("Array").type(), QVariant::List); + QCOMPARE(hash.value("Array").typeId(), QMetaType::QVariantList); QVariantList list = hash.value("Array").toList(); QCOMPARE(list.size(), 4); QCOMPARE(list.at(0), QVariant(true)); @@ -1628,7 +1871,8 @@ void tst_QtJson::toVariantHash() void tst_QtJson::toVariantList() { - QCOMPARE(QMetaType::Type(QJsonValue(QJsonArray()).toVariant().type()), QMetaType::QVariantList); // QTBUG-32524 + QCOMPARE(QMetaType::Type(QJsonValue(QJsonArray()).toVariant().typeId()), + QMetaType::QVariantList); // QTBUG-32524 QJsonArray array; QVariantList list = array.toVariantList(); @@ -1648,7 +1892,7 @@ void tst_QtJson::toVariantList() QCOMPARE(list.size(), 3); QCOMPARE(list[0], QVariant(QString("Value"))); QCOMPARE(list[1], QVariant::fromValue(nullptr)); - QCOMPARE(list[2].type(), QVariant::List); + QCOMPARE(list[2].typeId(), QMetaType::QVariantList); QVariantList vlist = list[2].toList(); QCOMPARE(vlist.size(), 4); QCOMPARE(vlist.at(0), QVariant(true)); @@ -1770,16 +2014,13 @@ void tst_QtJson::toJsonLargeNumericValues() QJsonArray array; array.append(QJsonValue(1.234567)); // actual precision bug in Qt 5.0.0 array.append(QJsonValue(1.7976931348623157e+308)); // JS Number.MAX_VALUE - array.append(QJsonValue(5e-324)); // JS Number.MIN_VALUE array.append(QJsonValue(std::numeric_limits<double>::min())); array.append(QJsonValue(std::numeric_limits<double>::max())); array.append(QJsonValue(std::numeric_limits<double>::epsilon())); - array.append(QJsonValue(std::numeric_limits<double>::denorm_min())); array.append(QJsonValue(0.0)); array.append(QJsonValue(-std::numeric_limits<double>::min())); array.append(QJsonValue(-std::numeric_limits<double>::max())); array.append(QJsonValue(-std::numeric_limits<double>::epsilon())); - array.append(QJsonValue(-std::numeric_limits<double>::denorm_min())); array.append(QJsonValue(-0.0)); array.append(QJsonValue(9007199254740992LL)); // JS Number max integer array.append(QJsonValue(-9007199254740992LL)); // JS Number min integer @@ -1793,27 +2034,21 @@ void tst_QtJson::toJsonLargeNumericValues() " 1.234567,\n" " 1.7976931348623157e+308,\n" #ifdef QT_NO_DOUBLECONVERSION // "shortest" double conversion is not very short then - " 4.9406564584124654e-324,\n" " 2.2250738585072014e-308,\n" " 1.7976931348623157e+308,\n" " 2.2204460492503131e-16,\n" - " 4.9406564584124654e-324,\n" " 0,\n" " -2.2250738585072014e-308,\n" " -1.7976931348623157e+308,\n" " -2.2204460492503131e-16,\n" - " -4.9406564584124654e-324,\n" #else - " 5e-324,\n" " 2.2250738585072014e-308,\n" " 1.7976931348623157e+308,\n" " 2.220446049250313e-16,\n" - " 5e-324,\n" " 0,\n" " -2.2250738585072014e-308,\n" " -1.7976931348623157e+308,\n" " -2.220446049250313e-16,\n" - " -5e-324,\n" #endif " 0,\n" " 9007199254740992,\n" @@ -1829,6 +2064,42 @@ void tst_QtJson::toJsonLargeNumericValues() QCOMPARE(json, expected); } +void tst_QtJson::toJsonDenormalValues() +{ + if constexpr (std::numeric_limits<double>::has_denorm == std::denorm_present) { + QJsonObject object; + QJsonArray array; + array.append(QJsonValue(5e-324)); // JS Number.MIN_VALUE + array.append(QJsonValue(std::numeric_limits<double>::denorm_min())); + array.append(QJsonValue(-std::numeric_limits<double>::denorm_min())); + object.insert("Array", array); + + QByteArray json = QJsonDocument(object).toJson(); + QByteArray expected = + "{\n" + " \"Array\": [\n" +#ifdef QT_NO_DOUBLECONVERSION // "shortest" double conversion is not very short then + " 4.9406564584124654e-324,\n" + " 4.9406564584124654e-324,\n" + " -4.9406564584124654e-324\n" +#else + " 5e-324,\n" + " 5e-324,\n" + " -5e-324\n" +#endif + " ]\n" + "}\n"; + + QCOMPARE(json, expected); + QJsonDocument doc; + doc.setObject(object); + json = doc.toJson(); + QCOMPARE(json, expected); + } else { + QSKIP("Skipping 'denorm' as this type lacks denormals on this system"); + } +} + void tst_QtJson::fromJson() { { @@ -2151,12 +2422,12 @@ void tst_QtJson::parseNumbers() QCOMPARE(val.toDouble(), (double)numbers[i].n); } } + // test number parsing + struct Numbers { + const char *str; + double n; + }; { - // test number parsing - struct Numbers { - const char *str; - double n; - }; Numbers numbers [] = { { "0", 0 }, { "1", 1 }, @@ -2172,8 +2443,6 @@ void tst_QtJson::parseNumbers() { "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 }, @@ -2195,6 +2464,29 @@ void tst_QtJson::parseNumbers() QCOMPARE(val.toDouble(), numbers[i].n); } } + if constexpr (std::numeric_limits<double>::has_denorm == std::denorm_present) { + Numbers numbers [] = { + { "1.1e-308", 1.1e-308 }, + { "-1.1e-308", -1.1e-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); + } + } else { + qInfo("Skipping denormal test as this system's double type lacks support"); + } } void tst_QtJson::parseStrings() @@ -2284,7 +2576,7 @@ void tst_QtJson::parseDuplicateKeys() void tst_QtJson::testParser() { QFile file(testDataDir + "/test.json"); - file.open(QFile::ReadOnly); + QVERIFY(file.open(QFile::ReadOnly)); QByteArray testJson = file.readAll(); QJsonDocument doc = QJsonDocument::fromJson(testJson); @@ -2340,6 +2632,13 @@ void tst_QtJson::testCompaction() } QCOMPARE(obj.size(), 1); QCOMPARE(obj.value(QLatin1String("foo")).toString(), QLatin1String("bar")); + + QJsonObject obj2; + + QT_TEST_EQUALITY_OPS(obj, obj2, false); + QT_TEST_EQUALITY_OPS(QJsonObject(), obj2, true); + obj2 = obj; + QT_TEST_EQUALITY_OPS(obj, obj2, true); } void tst_QtJson::testDebugStream() @@ -2619,57 +2918,57 @@ void tst_QtJson::testDetachBug() void tst_QtJson::valueEquals() { QCOMPARE(QJsonValue(), QJsonValue()); - QVERIFY(QJsonValue() != QJsonValue(QJsonValue::Undefined)); - QVERIFY(QJsonValue() != QJsonValue(true)); - QVERIFY(QJsonValue() != QJsonValue(1.)); - QVERIFY(QJsonValue() != QJsonValue(QJsonArray())); - QVERIFY(QJsonValue() != QJsonValue(QJsonObject())); + QT_TEST_EQUALITY_OPS(QJsonValue(), QJsonValue(QJsonValue::Undefined), false); + QT_TEST_EQUALITY_OPS(QJsonValue(), QJsonValue(true), false); + QT_TEST_EQUALITY_OPS(QJsonValue(), QJsonValue(1.), false); + QT_TEST_EQUALITY_OPS(QJsonValue(), QJsonValue(QJsonArray()), false); + QT_TEST_EQUALITY_OPS(QJsonValue(), QJsonValue(QJsonObject()), false); QCOMPARE(QJsonValue(true), QJsonValue(true)); - QVERIFY(QJsonValue(true) != QJsonValue(false)); - QVERIFY(QJsonValue(true) != QJsonValue(QJsonValue::Undefined)); - QVERIFY(QJsonValue(true) != QJsonValue()); - QVERIFY(QJsonValue(true) != QJsonValue(1.)); - QVERIFY(QJsonValue(true) != QJsonValue(QJsonArray())); - QVERIFY(QJsonValue(true) != QJsonValue(QJsonObject())); + QT_TEST_EQUALITY_OPS(QJsonValue(true), QJsonValue(false), false); + QT_TEST_EQUALITY_OPS(QJsonValue(true), QJsonValue(QJsonValue::Undefined), false); + QT_TEST_EQUALITY_OPS(QJsonValue(true), QJsonValue(), false); + QT_TEST_EQUALITY_OPS(QJsonValue(true), QJsonValue(1.), false); + QT_TEST_EQUALITY_OPS(QJsonValue(true), QJsonValue(QJsonArray()), false); + QT_TEST_EQUALITY_OPS(QJsonValue(true), QJsonValue(QJsonObject()), false); QCOMPARE(QJsonValue(1), QJsonValue(1)); - QVERIFY(QJsonValue(1) != QJsonValue(2)); + QT_TEST_EQUALITY_OPS(QJsonValue(1), QJsonValue(2), false); QCOMPARE(QJsonValue(1), QJsonValue(1.)); - QVERIFY(QJsonValue(1) != QJsonValue(1.1)); - QVERIFY(QJsonValue(1) != QJsonValue(QJsonValue::Undefined)); - QVERIFY(QJsonValue(1) != QJsonValue()); - QVERIFY(QJsonValue(1) != QJsonValue(true)); - QVERIFY(QJsonValue(1) != QJsonValue(QJsonArray())); - QVERIFY(QJsonValue(1) != QJsonValue(QJsonObject())); + QT_TEST_EQUALITY_OPS(QJsonValue(1), QJsonValue(1.1), false); + QT_TEST_EQUALITY_OPS(QJsonValue(1), QJsonValue(QJsonValue::Undefined), false); + QT_TEST_EQUALITY_OPS(QJsonValue(1), QJsonValue(), false); + QT_TEST_EQUALITY_OPS(QJsonValue(1), QJsonValue(true), false); + QT_TEST_EQUALITY_OPS(QJsonValue(1), QJsonValue(QJsonArray()), false); + QT_TEST_EQUALITY_OPS(QJsonValue(1), QJsonValue(QJsonObject()), false); QCOMPARE(QJsonValue(1.), QJsonValue(1.)); - QVERIFY(QJsonValue(1.) != QJsonValue(2.)); - QVERIFY(QJsonValue(1.) != QJsonValue(QJsonValue::Undefined)); - QVERIFY(QJsonValue(1.) != QJsonValue()); - QVERIFY(QJsonValue(1.) != QJsonValue(true)); - QVERIFY(QJsonValue(1.) != QJsonValue(QJsonArray())); - QVERIFY(QJsonValue(1.) != QJsonValue(QJsonObject())); + QT_TEST_EQUALITY_OPS(QJsonValue(1.), QJsonValue(2.), false); + QT_TEST_EQUALITY_OPS(QJsonValue(1.), QJsonValue(QJsonValue::Undefined), false); + QT_TEST_EQUALITY_OPS(QJsonValue(1.), QJsonValue(), false); + QT_TEST_EQUALITY_OPS(QJsonValue(1.), QJsonValue(true), false); + QT_TEST_EQUALITY_OPS(QJsonValue(1.), QJsonValue(QJsonArray()), false); + QT_TEST_EQUALITY_OPS(QJsonValue(1.), QJsonValue(QJsonObject()), false); QCOMPARE(QJsonValue(QJsonArray()), QJsonValue(QJsonArray())); QJsonArray nonEmptyArray; nonEmptyArray.append(true); - QVERIFY(QJsonValue(QJsonArray()) != nonEmptyArray); - QVERIFY(QJsonValue(QJsonArray()) != QJsonValue(QJsonValue::Undefined)); - QVERIFY(QJsonValue(QJsonArray()) != QJsonValue()); - QVERIFY(QJsonValue(QJsonArray()) != QJsonValue(true)); - QVERIFY(QJsonValue(QJsonArray()) != QJsonValue(1.)); - QVERIFY(QJsonValue(QJsonArray()) != QJsonValue(QJsonObject())); + QT_TEST_EQUALITY_OPS(QJsonValue(QJsonArray()), nonEmptyArray, false); + QT_TEST_EQUALITY_OPS(QJsonValue(QJsonArray()), QJsonValue(QJsonValue::Undefined), false); + QT_TEST_EQUALITY_OPS(QJsonValue(QJsonArray()), QJsonValue(), false); + QT_TEST_EQUALITY_OPS(QJsonValue(QJsonArray()), QJsonValue(true), false); + QT_TEST_EQUALITY_OPS(QJsonValue(QJsonArray()), QJsonValue(1.), false); + QT_TEST_EQUALITY_OPS(QJsonValue(QJsonArray()), QJsonValue(QJsonObject()), false); QCOMPARE(QJsonValue(QJsonObject()), QJsonValue(QJsonObject())); QJsonObject nonEmptyObject; nonEmptyObject.insert("Key", true); - QVERIFY(QJsonValue(QJsonObject()) != nonEmptyObject); - QVERIFY(QJsonValue(QJsonObject()) != QJsonValue(QJsonValue::Undefined)); - QVERIFY(QJsonValue(QJsonObject()) != QJsonValue()); - QVERIFY(QJsonValue(QJsonObject()) != QJsonValue(true)); - QVERIFY(QJsonValue(QJsonObject()) != QJsonValue(1.)); - QVERIFY(QJsonValue(QJsonObject()) != QJsonValue(QJsonArray())); + QT_TEST_EQUALITY_OPS(QJsonValue(QJsonObject()), nonEmptyObject, false); + QT_TEST_EQUALITY_OPS(QJsonValue(QJsonObject()), QJsonValue(QJsonValue::Undefined), false); + QT_TEST_EQUALITY_OPS(QJsonValue(QJsonObject()), QJsonValue(), false); + QT_TEST_EQUALITY_OPS(QJsonValue(QJsonObject()), QJsonValue(true), false); + QT_TEST_EQUALITY_OPS(QJsonValue(QJsonObject()), QJsonValue(1.), false); + QT_TEST_EQUALITY_OPS(QJsonValue(QJsonObject()), QJsonValue(QJsonArray()), false); QCOMPARE(QJsonValue("foo"), QJsonValue(QLatin1String("foo"))); QCOMPARE(QJsonValue("foo"), QJsonValue(QString("foo"))); @@ -2862,7 +3161,7 @@ void tst_QtJson::documentEquals() void tst_QtJson::bom() { QFile file(testDataDir + "/bom.json"); - file.open(QFile::ReadOnly); + QVERIFY(file.open(QFile::ReadOnly)); QByteArray json = file.readAll(); // Import json document into a QJsonDocument @@ -3183,7 +3482,7 @@ void tst_QtJson::documentFromVariant() // As JSON arrays they should be equal. QCOMPARE(da1.array(), da2.array()); - + QT_TEST_EQUALITY_OPS(da1, da2, true); QMap <QString, QVariant> map; map["key"] = string; @@ -3199,6 +3498,7 @@ void tst_QtJson::documentFromVariant() // As JSON objects they should be equal. QCOMPARE(do1.object(), do2.object()); + QT_TEST_EQUALITY_OPS(do1, do2, true); } void tst_QtJson::parseErrorOffset_data() @@ -3297,6 +3597,7 @@ void tst_QtJson::streamSerializationQJsonDocument() QDataStream load(buffer); load >> output; QCOMPARE(output, document); + QT_TEST_EQUALITY_OPS(output, document, true); } void tst_QtJson::streamSerializationQJsonArray_data() @@ -3541,16 +3842,13 @@ void tst_QtJson::fromToVariantConversions_data() QTest::newRow("NaN") << QVariant(qQNaN()) << QJsonValue(QJsonValue::Null) << QVariant::fromValue(nullptr); - const qulonglong ulongValue = (1ul << 63) + 1; - const double uLongToDouble = ulongValue; - qint64 n; - if (convertDoubleTo(uLongToDouble, &n)) { - QTest::newRow("ulonglong") << QVariant(ulongValue) << QJsonValue(uLongToDouble) - << QVariant(n); - } else { - QTest::newRow("ulonglong") << QVariant(ulongValue) << QJsonValue(uLongToDouble) - << QVariant(uLongToDouble); - } + static_assert(std::numeric_limits<double>::digits <= 63, + "double is too big on this platform, this test would fail"); + constexpr quint64 Threshold = Q_UINT64_C(1) << 63; + const qulonglong ulongValue = qulonglong(Threshold) + 1; + const double uLongToDouble = Threshold; + QTest::newRow("ulonglong") << QVariant(ulongValue) << QJsonValue(uLongToDouble) + << QVariant(uLongToDouble); } void tst_QtJson::fromToVariantConversions() @@ -3650,22 +3948,49 @@ void tst_QtJson::testIteratorComparison() QVERIFY(t.end() > t.begin()); } +void tst_QtJson::noLeakOnNameClash_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QByteArray>("result"); + QTest::addRow("simple") + << QStringLiteral("simple.duplicates.json") + << QByteArray(R"({"": 0})"); + QTest::addRow("test") + << QStringLiteral("test.duplicates.json") + << QByteArray(R"([ + "JSON Test Pattern pass1", {"a": ["array with 1 element"]}, {}, [], -42, true, + false, null, {"a": "A key can be any string"}, 0.5, 98.6, 99.44, 1066, 10, 1, + 0.1, 1, 2, 2, "rosebud", {"a": "bar"}, {"a": {"a": 2000}}, {"a": {"a": 2000}}, + {"a": {"a": 2000}}, {"a": {"a": 2000}} + ])"); + QTest::addRow("test3") + << QStringLiteral("test3.duplicates.json") + << QByteArray(R"({"a": [{"a": "212 555-1234"}, {"a": "646 555-4567"}]})"); +} + void tst_QtJson::noLeakOnNameClash() { - QJsonDocument doc = QJsonDocument::fromJson("{\"\":{\"\":0},\"\":0}"); - QVERIFY(!doc.isNull()); - const QJsonObject obj = doc.object(); + QFETCH(QString, fileName); + QFETCH(QByteArray, result); + + QFile file(testDataDir + u'/' + fileName); + QVERIFY(file.open(QFile::ReadOnly)); + QByteArray testJson = file.readAll(); + QVERIFY(!testJson.isEmpty()); + + QJsonParseError error; - // Removed the duplicate key. - QCOMPARE(obj.length(), 1); + // Retains the last one of each set of duplicate keys. + QJsonDocument doc = QJsonDocument::fromJson(testJson, &error); + QVERIFY2(!doc.isNull(), qPrintable(error.errorString())); + QJsonDocument expected = QJsonDocument::fromJson(result, &error); + QVERIFY2(!expected.isNull(), qPrintable(error.errorString())); - // Retained the last of the duplicates. - const QJsonValue val = obj.begin().value(); - QVERIFY(val.isDouble()); - QCOMPARE(val.toDouble(), 0.0); + QCOMPARE(doc, expected); + QT_TEST_EQUALITY_OPS(doc, expected, true); // It should not leak. - // In particular it should not forget to deref the container for the inner object. + // In particular it should not forget to deref the container for the inner objects. } QTEST_MAIN(tst_QtJson) |