1//     __ _____ _____ _____
2//  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
3// |  |  |__   |  |  | | | |  version 3.11.2
4// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5//
6// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7// SPDX-License-Identifier: MIT
8
9#include "doctest_compatibility.h"
10
11#include <nlohmann/json.hpp>
12using nlohmann::json;
13
14#include <list>
15
16namespace
17{
18TEST_CASE("Use arbitrary stdlib container")
19{
20    std::string raw_data = "[1,2,3,4]";
21    std::list<char> data(raw_data.begin(), raw_data.end());
22
23    json as_json = json::parse(data.begin(), data.end());
24    CHECK(as_json.at(0) == 1);
25    CHECK(as_json.at(1) == 2);
26    CHECK(as_json.at(2) == 3);
27    CHECK(as_json.at(3) == 4);
28}
29
30struct MyContainer
31{
32    const char* data;
33};
34
35const char* begin(const MyContainer& c)
36{
37    return c.data;
38}
39
40const char* end(const MyContainer& c)
41{
42    return c.data + strlen(c.data); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
43}
44
45TEST_CASE("Custom container non-member begin/end")
46{
47
48    MyContainer data{"[1,2,3,4]"};
49    json as_json = json::parse(data);
50    CHECK(as_json.at(0) == 1);
51    CHECK(as_json.at(1) == 2);
52    CHECK(as_json.at(2) == 3);
53    CHECK(as_json.at(3) == 4);
54
55}
56
57TEST_CASE("Custom container member begin/end")
58{
59    struct MyContainer2
60    {
61        const char* data;
62
63        const char* begin() const
64        {
65            return data;
66        }
67
68        const char* end() const
69        {
70            return data + strlen(data); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
71        }
72    };
73
74    MyContainer2 data{"[1,2,3,4]"};
75    json as_json = json::parse(data);
76    CHECK(as_json.at(0) == 1);
77    CHECK(as_json.at(1) == 2);
78    CHECK(as_json.at(2) == 3);
79    CHECK(as_json.at(3) == 4);
80}
81
82TEST_CASE("Custom iterator")
83{
84    const char* raw_data = "[1,2,3,4]";
85
86    struct MyIterator
87    {
88        using difference_type = std::size_t;
89        using value_type = char;
90        using pointer = const char*;
91        using reference = const char&;
92        using iterator_category = std::input_iterator_tag;
93
94        MyIterator& operator++()
95        {
96            ++ptr; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
97            return *this;
98        }
99
100        reference operator*() const
101        {
102            return *ptr;
103        }
104
105        bool operator!=(const MyIterator& rhs) const
106        {
107            return ptr != rhs.ptr;
108        }
109
110        const char* ptr;
111    };
112
113    // avoid -Wunused-local-typedefs
114    CHECK(std::is_same<MyIterator::difference_type, std::size_t>::value);
115    CHECK(std::is_same<MyIterator::value_type, char>::value);
116    CHECK(std::is_same<MyIterator::pointer, const char*>::value);
117    CHECK(std::is_same<MyIterator::reference, const char&>::value);
118    CHECK(std::is_same<MyIterator::iterator_category, std::input_iterator_tag>::value);
119
120    MyIterator begin{raw_data};
121    MyIterator end{raw_data + strlen(raw_data)}; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
122
123    json as_json = json::parse(begin, end);
124    CHECK(as_json.at(0) == 1);
125    CHECK(as_json.at(1) == 2);
126    CHECK(as_json.at(2) == 3);
127    CHECK(as_json.at(3) == 4);
128}
129
130} // namespace
131