summaryrefslogtreecommitdiffstats
path: root/libtests/qtest/json_parse.test
blob: 699544f66f4fd1c8c79458c93de8665c7dd0dde4 (plain) (blame)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/env perl
require 5.008;
use warnings;
use strict;
use File::Copy;
use File::Compare;

chdir("json_parse") or die "chdir testdir failed: $!\n";

require TestDriver;

my $td = new TestDriver('json_parse');

my $json_mod = 0;
if ($^O ne 'msys')
{
    # Emperical evidence and considerable debugging reveals that in
    # some versions of perl (e.g. the one with git bash on the GitHub
    # actions Windows 2022 build environment), using the JSON module
    # defeats the functionality of binmode when writing test output
    # files, thus invalidating NORMALIZE_NEWLINES. This causes test
    # failures and spurious upadtes to save files in CI on MSVC.
    eval {
        require JSON;
        $json_mod = 1;
    };
    if ($@)
    {
        $td->emphasize("JSON.pm not found -- using stored actual outputs");
    }
}

cleanup();

my $good = 11;

for (my $i = 1; $i <= $good; ++$i)
{
    my $n = sprintf("%02d", $i);

    unlink "out.json";
    my $r = system("json_parse good-$n.json > out.json 2>&1");
    if ($td->runtest("json_parse accepted $n",
                     {$td->STRING => "$r\n"},
                     {$td->STRING => "0\n"},
                     $td->NORMALIZE_NEWLINES))
    {
        if ($json_mod)
        {
            if ($td->runtest("check output $n",
                             {$td->STRING => normalize_json("out.json")},
                             {$td->STRING => normalize_json("good-$n.json")},
                             $td->NORMALIZE_NEWLINES))
            {
                if (compare("out.json", "save-$n.json"))
                {
                    copy("out.json", "save-$n.json");
                    $td->emphasize("updated save-$n.json from out.json");
                }
            }
        }
        else
        {
            $td->runtest("check output $n against saved",
                         {$td->FILE => "out.json"},
                         {$td->FILE => "save-$n.json"},
                         $td->NORMALIZE_NEWLINES);
        }
    }
    else
    {
        $td->runtest("skip checking output $n",
                     {$td->FILE => "out.json"},
                     {$td->STRING => ""});
    }

    $td->runtest("good $n reactor",
                 {$td->COMMAND => "json_parse good-$n.json --react"},
                 {$td->FILE => "good-$n-react.out", $td->EXIT_STATUS => 0},
                 $td->NORMALIZE_NEWLINES);
}

my @bad = (
    "junk after string",        # 1
    "junk after array",         # 2
    "junk after dictionary",    # 3
    "bad number",               # 4
    "invalid keyword",          # 5
    "missing colon",            # 6
    "missing comma in dict",    # 7
    "missing comma in array",   # 8
    "dict key not string",      # 9
    "unexpected } in array",    # 10
    "unexpected } at top",      # 11
    "unexpected } in dict",     # 12
    "unexpected ] in dict",     # 13
    "unexpected ] at top",      # 14
    "unexpected :",             # 15
    "unexpected ,",             # 16
    "premature end array",      # 17
    "null character",           # 18
    "unexpected character",     # 19
    "point in exponent",        # 20
    "duplicate point",          # 21
    "duplicate e",              # 22
    "stray +",                  # 23
    "bad character in number",  # 24
    "bad character in keyword", # 25
    "bad backslash character",  # 26
    "unterminated string",      # 27
    "unterminated after \\",    # 28
    "leading +",                # 29
    "decimal with no digits",   # 30
    "minus with no digits",     # 31
    "leading zero",             # 32
    "leading zero negative",    # 33
    "premature end after u",    # 34
    "bad hex digit",            # 35
    "parser depth exceeded",    # 36
    "stray low surrogate",      # 37
    "high high surrogate",      # 38
    "dangling high surrogate",  # 39
    "duplicate dictionary key", # 40
    "decimal point after minus",# 41
    "e after minus",            # 42
    "missing digit after e",    # 43
    "missing digit after e+/-", # 44
    "tab char in string",       # 45
    "cr char in string",        # 46
    "lf char in string",        # 47
    "bs char in string",        # 48
    );

my $i = 0;
foreach my $d (@bad)
{
    ++$i;
    my $n = sprintf("%02d", $i);
    $td->runtest("$n: $d",
                 {$td->COMMAND => "json_parse bad-$n.json"},
                 {$td->FILE => "bad-$n.out", $td->EXIT_STATUS => 2},
                 $td->NORMALIZE_NEWLINES);
}

cleanup();

$td->report((3 * $good) + scalar(@bad));

sub cleanup
{
    unlink "out.json";
}

sub normalize_json
{
    my $file = shift;
    open(F, "<$file") or die "can't open $file: $file: $!\n";
    $/ = undef;
    my $encoded = scalar(<F>);
    close(F);
    my $j = JSON->new->allow_nonref;
    $j->canonical();
    $j->utf8->pretty->encode($j->utf8->decode($encoded));
}