Software APIs
ujson_test.cc
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "sw/device/lib/ujson/ujson.h"
6 
7 #include <gtest/gtest.h>
8 #include <string>
9 
10 #include "sw/device/lib/base/status.h"
11 #include "sw/device/lib/ujson/test_helpers.h"
12 
13 namespace {
15 
16 TEST(UJson, GetC) {
17  SourceSink ss("abc123");
18  ujson_t uj = ss.UJson();
19 
20  EXPECT_EQ(ujson_getc(&uj).value, 'a');
21  EXPECT_EQ(ujson_getc(&uj).value, 'b');
22  EXPECT_EQ(ujson_getc(&uj).value, 'c');
23  EXPECT_EQ(status_err(ujson_ungetc(&uj, 'd')), kOk);
24  EXPECT_EQ(ujson_getc(&uj).value, 'd');
25  EXPECT_EQ(ujson_getc(&uj).value, '1');
26  EXPECT_EQ(ujson_getc(&uj).value, '2');
27  EXPECT_EQ(ujson_getc(&uj).value, '3');
28  EXPECT_EQ(status_err(ujson_getc(&uj)), kResourceExhausted);
29 }
30 
31 TEST(UJson, PutBuf) {
32  SourceSink ss;
33  ujson_t uj = ss.UJson();
34 
35  EXPECT_TRUE(status_ok(ujson_putbuf(&uj, "abc", 3)));
36  EXPECT_TRUE(status_ok(ujson_putbuf(&uj, "123", 3)));
37  EXPECT_EQ(ss.Sink(), "abc123");
38 }
39 
40 TEST(UJson, Consume) {
41  SourceSink ss(" \t\r\nax");
42  ujson_t uj = ss.UJson();
43 
44  EXPECT_EQ(status_err(ujson_consume(&uj, 'a')), kOk);
45  EXPECT_EQ(status_err(ujson_consume(&uj, 'b')), kNotFound);
46 }
47 
48 TEST(UJson, ParseQuotedString) {
49  SourceSink ss(R"json(
50  "Hello World\r\n"
51  )json");
52  ujson_t uj = ss.UJson();
53  char buf[256];
54  status_t s;
55 
56  s = ujson_parse_qs(&uj, buf, sizeof(buf));
57  EXPECT_TRUE(status_ok(s));
58  EXPECT_EQ(s.value, 13);
59  std::string vala(buf);
60  EXPECT_EQ(vala, "Hello World\r\n");
61 
62  ss.Reset();
63  s = ujson_parse_qs(&uj, buf, 6);
64  EXPECT_TRUE(status_ok(s));
65  EXPECT_EQ(s.value, 5);
66  std::string valb(buf);
67  EXPECT_EQ(valb, "Hello");
68 }
69 
70 TEST(UJson, ParseQuotedStringInvalidString) {
71  SourceSink ss("abc");
72  ujson_t uj = ss.UJson();
73  char buf[256];
74  status_t s;
75 
76  s = ujson_parse_qs(&uj, buf, sizeof(buf));
77  EXPECT_EQ(status_err(s), kNotFound);
78 }
79 
80 TEST(UJson, ParseQuotedStringShortBuffer) {
81  SourceSink ss("\"abc");
82  ujson_t uj = ss.UJson();
83  char buf[256];
84  status_t s;
85 
86  s = ujson_parse_qs(&uj, buf, sizeof(buf));
87  EXPECT_EQ(status_err(s), kResourceExhausted);
88 }
89 
90 TEST(UJson, ParseBoolean) {
91  SourceSink ss("true");
92  ujson_t uj = ss.UJson();
93  status_t s;
94  bool val = false;
95 
96  // Parse the token "true".
97  s = ujson_deserialize_bool(&uj, &val);
98  EXPECT_TRUE(status_ok(s));
99  EXPECT_TRUE(val);
100 
101  // Parse the token "false".
102  ss.Reset("false");
103  val = true;
104  s = ujson_deserialize_bool(&uj, &val);
105  EXPECT_TRUE(status_ok(s));
106  EXPECT_FALSE(val);
107 
108  // Check various non-true/false values.
109  ss.Reset("xyz");
110  s = ujson_deserialize_bool(&uj, &val);
111  EXPECT_FALSE(status_ok(s));
112  ss.Reset("trust");
113  s = ujson_deserialize_bool(&uj, &val);
114  EXPECT_FALSE(status_ok(s));
115  ss.Reset("fast");
116  s = ujson_deserialize_bool(&uj, &val);
117  EXPECT_FALSE(status_ok(s));
118 }
119 
120 #define INT(type_, str_, value_) \
121  do { \
122  SourceSink ss(str_); \
123  ujson_t uj = ss.UJson(); \
124  type_ t; \
125  status_t s = ujson_parse_integer(&uj, (void *)&t, sizeof(t)); \
126  EXPECT_EQ(status_err(s), kOk); \
127  EXPECT_EQ(t, value_); \
128  } while (0)
129 
130 #define SIMPLE_INT(type_, value_) INT(type_, #value_, value_)
131 
132 TEST(UJson, ParseInteger) {
133  SIMPLE_INT(int64_t, -1);
134  SIMPLE_INT(uint64_t, 9223372036854775808);
135  SIMPLE_INT(uint32_t, 12345678);
136  SIMPLE_INT(int32_t, -12345678);
137  SIMPLE_INT(int16_t, -1);
138  SIMPLE_INT(int8_t, -1);
139 
140  // Won't fit, we should get zero.
141  INT(uint8_t, "256", 0);
142  // This value overflows int64 and becomes its own negative.
143  INT(int64_t, "9223372036854775808", -9223372036854775808);
144 }
145 #undef INT
146 #undef SIMPLE_INT
147 
148 TEST(UJson, ParseIntegerError) {
149  SourceSink ss;
150  ujson uj = ss.UJson();
151  uint32_t t;
152  status_t s;
153 
154  // Empty string.
155  s = ujson_parse_integer(&uj, (void *)&t, sizeof(t));
156  EXPECT_EQ(status_err(s), kResourceExhausted);
157 
158  // Non integer character.
159  ss.Reset("q");
160  s = ujson_parse_integer(&uj, (void *)&t, sizeof(t));
161  EXPECT_EQ(status_err(s), kNotFound);
162 
163  // A number that can NOT be represented in a 64-bit unsigned integer.
164  // number = UINT64_MAX + 1.
165  ss.Reset("18446744073709551616");
166  s = ujson_parse_integer(&uj, (void *)&t, sizeof(t));
167  EXPECT_EQ(status_err(s), kOutOfRange);
168 
169  // A number that can NOT be represented in a 64-bit unsigned integer.
170  // number / 10 > UINT64_MAX / 10.
171  ss.Reset("18446744073709551620");
172  s = ujson_parse_integer(&uj, (void *)&t, sizeof(t));
173  EXPECT_EQ(status_err(s), kOutOfRange);
174 
175  // Negative number that can NOT be represented in a 64-bit signed integer.
176  ss.Reset("-9223372036854775809");
177  s = ujson_parse_integer(&uj, (void *)&t, sizeof(t));
178  EXPECT_EQ(status_err(s), kOutOfRange);
179 }
180 
181 TEST(UJson, SerializeString) {
182  SourceSink ss;
183  ujson uj = ss.UJson();
184 
185  EXPECT_TRUE(status_ok(ujson_serialize_string(&uj, "abc123")));
186  EXPECT_EQ(ss.Sink(), R"json("abc123")json");
187 
188  ss.Reset();
189  EXPECT_TRUE(status_ok(ujson_serialize_string(&uj, "\"\\\b\f\n\r\t")));
190  EXPECT_EQ(ss.Sink(), R"json("\"\\\b\f\n\r\t")json");
191 
192  ss.Reset();
193  EXPECT_TRUE(status_ok(ujson_serialize_string(&uj, "\xFF\x01\x99")));
194  EXPECT_EQ(ss.Sink(), R"json("\u00ff\u0001\u0099")json");
195 }
196 
197 TEST(UJson, SerializeBool) {
198  SourceSink ss;
199  ujson uj = ss.UJson();
200  bool val;
201 
202  val = true;
203  EXPECT_TRUE(status_ok(ujson_serialize_bool(&uj, &val)));
204  EXPECT_EQ(ss.Sink(), R"json(true)json");
205 
206  ss.Reset();
207  val = false;
208  EXPECT_TRUE(status_ok(ujson_serialize_bool(&uj, &val)));
209  EXPECT_EQ(ss.Sink(), R"json(false)json");
210 }
211 
212 #define INT(type_, str_, value_) \
213  do { \
214  SourceSink ss; \
215  ujson_t uj = ss.UJson(); \
216  type_ t = value_; \
217  status_t s = ujson_serialize_##type_(&uj, &t); \
218  EXPECT_EQ(status_err(s), kOk); \
219  EXPECT_EQ(ss.Sink(), str_); \
220  } while (0)
221 
222 TEST(UJson, SerializeIntegers) {
223  INT(uint64_t, "9223372036854775808", 1UL << 63);
224  INT(uint32_t, "4294967295", 0xFFFFFFFF);
225  INT(uint16_t, "32768", 0x8000);
226  INT(uint8_t, "129", 129);
227 
228  INT(int64_t, "-9223372036854775808", 1UL << 63);
229  INT(int32_t, "-1", 0xFFFFFFFF);
230  INT(int16_t, "-32768", 0x8000);
231  INT(int8_t, "-2", 0xfe);
232 }
233 
234 TEST(UJson, SerializeStatus) {
235  SourceSink ss;
236  ujson uj = ss.UJson();
237  status_t val;
238 
239  val = OK_STATUS(1234);
240  EXPECT_TRUE(status_ok(ujson_serialize_status_t(&uj, &val)));
241  EXPECT_EQ(ss.Sink(), R"json({"Ok":1234})json");
242 }
243 
244 TEST(UJson, DeerializeStatus) {
245  SourceSink ss(R"json({"Ok":1234})json");
246  ujson uj = ss.UJson();
247  status_t val;
248  const char *code;
249  char mod_id[4] = {0};
250  int32_t arg;
251 
252  // Parse an Ok value with an argument.
253  EXPECT_TRUE(status_ok(ujson_deserialize_status_t(&uj, &val)));
254  OT_DISCARD(status_extract(val, &code, &arg, mod_id));
255  EXPECT_EQ(status_err(val), kOk);
256  EXPECT_EQ(arg, 1234);
257 
258  // Parse an error value with a module and argument.
259  // The module_id should get truncated to 3 characters.
260  ss.Reset(R"json({"InvalidArgument": ["foobar", 77]})json");
261  EXPECT_TRUE(status_ok(ujson_deserialize_status_t(&uj, &val)));
262  OT_DISCARD(status_extract(val, &code, &arg, mod_id));
263  EXPECT_EQ(status_err(val), kInvalidArgument);
264  EXPECT_EQ(std::string(mod_id), "FOO");
265  EXPECT_EQ(arg, 77);
266 }
267 
268 } // namespace