File size: 5,227 Bytes
d2816aa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "tests.h"

void test_json_parser(testing &t) {
    // Test parsing a simple JSON object
    t.test("simple JSON object parsing", [](testing &t) {
        auto json = build_peg_parser([](common_peg_parser_builder & p) { return p.json(); });

        std::string    input = R"({"name": "test", "value": 42, "flag": true})";
        common_peg_parse_context ctx(input);

        auto result = json.parse(ctx);

        t.assert_equal("result_is_success", true, result.success());
        t.assert_equal("result_end", input.size(), result.end);
    });

    // Test parsing a JSON array with mixed types
    t.test("JSON array with mixed types", [](testing &t) {
        auto json = build_peg_parser([](common_peg_parser_builder & p) { return p.json(); });

        std::string    input = R"([1, "hello", true, null, 3.14])";
        common_peg_parse_context ctx(input);

        auto result = json.parse(ctx);

        t.assert_equal("result_is_success", true, result.success());
        t.assert_equal("result_end", input.size(), result.end);
    });

    // Test parsing nested JSON with objects and arrays
    t.test("nested JSON with objects and arrays", [](testing &t) {
        auto json = build_peg_parser([](common_peg_parser_builder & p) { return p.json(); });

        std::string input =
            R"({"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}], "count": 2, "metadata": {"version": "1.0", "tags": ["admin", "user"]}})";
        common_peg_parse_context ctx(input);

        auto result = json.parse(ctx);

        t.assert_equal("result_is_success", true, result.success());
        t.assert_equal("result_end", input.size(), result.end);
    });

    // Test need_more_input() parsing - incomplete object
    t.test("need_more_input() parsing - incomplete object", [](testing &t) {
        auto json = build_peg_parser([](common_peg_parser_builder & p) { return p.json(); });

        std::string    input = R"({"name": "test", "value": )";
        common_peg_parse_context ctx(input, COMMON_PEG_PARSE_FLAG_LENIENT);

        auto result = json.parse(ctx);

        t.assert_equal("result_is_need_more_input", true, result.need_more_input());
    });

    // Test need_more_input() parsing - incomplete array
    t.test("need_more_input() parsing - incomplete array", [](testing &t) {
        auto json = build_peg_parser([](common_peg_parser_builder & p) { return p.json(); });

        std::string    input = R"([1, 2, 3, )";
        common_peg_parse_context ctx(input, COMMON_PEG_PARSE_FLAG_LENIENT);

        auto result = json.parse(ctx);

        t.assert_equal("result_is_need_more_input", true, result.need_more_input());
    });

    // Test need_more_input() parsing - incomplete nested structure
    t.test("need_more_input() parsing - incomplete nested structure", [](testing &t) {
        auto json = build_peg_parser([](common_peg_parser_builder & p) { return p.json(); });

        std::string    input = R"({"data": {"nested": )";
        common_peg_parse_context ctx(input, COMMON_PEG_PARSE_FLAG_LENIENT);

        auto result = json.parse(ctx);

        t.assert_equal("result_is_need_more_input", true, result.need_more_input());
    });

    // Test need_more_input() parsing - incomplete escape sequence in a string value
    t.test("need_more_input() parsing - incomplete escape sequence", [](testing &t) {
        auto json = build_peg_parser([](common_peg_parser_builder & p) { return p.json(); });

        std::vector<std::string> inputs {
            R"({"text": "hello\)",     // dangling backslash
            R"({"text": "hello\u)",    // incomplete unicode escape sequence
            R"({"text": "hello\u00)",
        };

        for (const auto & input : inputs) {
            t.test(input, [&](testing &t) {
                common_peg_parse_context ctx(input, COMMON_PEG_PARSE_FLAG_LENIENT);

                auto result = json.parse(ctx);

                t.assert_equal("result_is_need_more_input", true, result.need_more_input());

                // the incomplete escape sequence is not part of the partial value
                t.assert_equal("result_end", input.find('\\'), result.end);
            });
        }
    });

    t.test("object member", [](testing &t) {
        auto parser = build_peg_parser([](common_peg_parser_builder & p) {
            return p.json_member("name", "\"" + p.chars("[a-z]") + "\"");
        });

        t.test("success", [&](testing &t) {
            std::string input = R"("name": "bob")";
            common_peg_parse_context ctx(input);

            auto result = parser.parse(ctx);
            t.assert_true("success", result.success());
        });

        t.test("partial", [&](testing &t) {
            std::string input = R"("name": "bo)";
            common_peg_parse_context ctx(input, COMMON_PEG_PARSE_FLAG_LENIENT);

            auto result = parser.parse(ctx);
            t.assert_true("need more input", result.need_more_input());
        });

        t.test("failed", [&](testing &t) {
            std::string input = R"([])";
            common_peg_parse_context ctx(input);

            auto result = parser.parse(ctx);
            t.assert_true("fail", result.fail());
        });
    });
}