| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 |  | 
 | #include "sw/device/lib/ujson/ujson.h" | 
 |  | 
 | #include <gtest/gtest.h> | 
 | #include <string> | 
 |  | 
 | #include "sw/device/lib/base/status.h" | 
 | #include "sw/device/lib/ujson/test_helpers.h" | 
 |  | 
 | namespace { | 
 | using test_helpers::SourceSink; | 
 |  | 
 | TEST(UJson, GetC) { | 
 |   SourceSink ss("abc123"); | 
 |   ujson_t uj = ss.UJson(); | 
 |  | 
 |   EXPECT_EQ(ujson_getc(&uj).value, 'a'); | 
 |   EXPECT_EQ(ujson_getc(&uj).value, 'b'); | 
 |   EXPECT_EQ(ujson_getc(&uj).value, 'c'); | 
 |   EXPECT_EQ(status_err(ujson_ungetc(&uj, 'd')), kOk); | 
 |   EXPECT_EQ(ujson_getc(&uj).value, 'd'); | 
 |   EXPECT_EQ(ujson_getc(&uj).value, '1'); | 
 |   EXPECT_EQ(ujson_getc(&uj).value, '2'); | 
 |   EXPECT_EQ(ujson_getc(&uj).value, '3'); | 
 |   EXPECT_EQ(status_err(ujson_getc(&uj)), kResourceExhausted); | 
 | } | 
 |  | 
 | TEST(UJson, PutBuf) { | 
 |   SourceSink ss; | 
 |   ujson_t uj = ss.UJson(); | 
 |  | 
 |   EXPECT_TRUE(status_ok(ujson_putbuf(&uj, "abc", 3))); | 
 |   EXPECT_TRUE(status_ok(ujson_putbuf(&uj, "123", 3))); | 
 |   EXPECT_EQ(ss.Sink(), "abc123"); | 
 | } | 
 |  | 
 | TEST(UJson, Consume) { | 
 |   SourceSink ss("  \t\r\nax"); | 
 |   ujson_t uj = ss.UJson(); | 
 |  | 
 |   EXPECT_EQ(status_err(ujson_consume(&uj, 'a')), kOk); | 
 |   EXPECT_EQ(status_err(ujson_consume(&uj, 'b')), kNotFound); | 
 | } | 
 |  | 
 | TEST(UJson, ParseQuotedString) { | 
 |   SourceSink ss(R"json( | 
 |         "Hello World\r\n" | 
 |     )json"); | 
 |   ujson_t uj = ss.UJson(); | 
 |   char buf[256]; | 
 |   status_t s; | 
 |  | 
 |   s = ujson_parse_qs(&uj, buf, sizeof(buf)); | 
 |   EXPECT_TRUE(status_ok(s)); | 
 |   EXPECT_EQ(s.value, 13); | 
 |   std::string vala(buf); | 
 |   EXPECT_EQ(vala, "Hello World\r\n"); | 
 |  | 
 |   ss.Reset(); | 
 |   s = ujson_parse_qs(&uj, buf, 6); | 
 |   EXPECT_TRUE(status_ok(s)); | 
 |   EXPECT_EQ(s.value, 5); | 
 |   std::string valb(buf); | 
 |   EXPECT_EQ(valb, "Hello"); | 
 | } | 
 |  | 
 | TEST(UJson, ParseQuotedStringInvalidString) { | 
 |   SourceSink ss("abc"); | 
 |   ujson_t uj = ss.UJson(); | 
 |   char buf[256]; | 
 |   status_t s; | 
 |  | 
 |   s = ujson_parse_qs(&uj, buf, sizeof(buf)); | 
 |   EXPECT_EQ(status_err(s), kNotFound); | 
 | } | 
 |  | 
 | TEST(UJson, ParseQuotedStringShortBuffer) { | 
 |   SourceSink ss("\"abc"); | 
 |   ujson_t uj = ss.UJson(); | 
 |   char buf[256]; | 
 |   status_t s; | 
 |  | 
 |   s = ujson_parse_qs(&uj, buf, sizeof(buf)); | 
 |   EXPECT_EQ(status_err(s), kResourceExhausted); | 
 | } | 
 |  | 
 | TEST(UJson, ParseBoolean) { | 
 |   SourceSink ss("true"); | 
 |   ujson_t uj = ss.UJson(); | 
 |   status_t s; | 
 |   bool val = false; | 
 |  | 
 |   // Parse the token "true". | 
 |   s = ujson_deserialize_bool(&uj, &val); | 
 |   EXPECT_TRUE(status_ok(s)); | 
 |   EXPECT_TRUE(val); | 
 |  | 
 |   // Parse the token "false". | 
 |   ss.Reset("false"); | 
 |   val = true; | 
 |   s = ujson_deserialize_bool(&uj, &val); | 
 |   EXPECT_TRUE(status_ok(s)); | 
 |   EXPECT_FALSE(val); | 
 |  | 
 |   // Check various non-true/false values. | 
 |   ss.Reset("xyz"); | 
 |   s = ujson_deserialize_bool(&uj, &val); | 
 |   EXPECT_FALSE(status_ok(s)); | 
 |   ss.Reset("trust"); | 
 |   s = ujson_deserialize_bool(&uj, &val); | 
 |   EXPECT_FALSE(status_ok(s)); | 
 |   ss.Reset("fast"); | 
 |   s = ujson_deserialize_bool(&uj, &val); | 
 |   EXPECT_FALSE(status_ok(s)); | 
 | } | 
 |  | 
 | #define INT(type_, str_, value_)                                  \ | 
 |   do {                                                            \ | 
 |     SourceSink ss(str_);                                          \ | 
 |     ujson_t uj = ss.UJson();                                      \ | 
 |     type_ t;                                                      \ | 
 |     status_t s = ujson_parse_integer(&uj, (void *)&t, sizeof(t)); \ | 
 |     EXPECT_EQ(status_err(s), kOk);                                \ | 
 |     EXPECT_EQ(t, value_);                                         \ | 
 |   } while (0) | 
 |  | 
 | #define SIMPLE_INT(type_, value_) INT(type_, #value_, value_) | 
 |  | 
 | TEST(UJson, ParseInteger) { | 
 |   SIMPLE_INT(int64_t, -1); | 
 |   SIMPLE_INT(uint64_t, 9223372036854775808); | 
 |   SIMPLE_INT(uint32_t, 12345678); | 
 |   SIMPLE_INT(int32_t, -12345678); | 
 |   SIMPLE_INT(int16_t, -1); | 
 |   SIMPLE_INT(int8_t, -1); | 
 |  | 
 |   // Won't fit, we should get zero. | 
 |   INT(uint8_t, "256", 0); | 
 |   // This value overflows int64 and becomes its own negative. | 
 |   INT(int64_t, "9223372036854775808", -9223372036854775808); | 
 | } | 
 | #undef INT | 
 | #undef SIMPLE_INT | 
 |  | 
 | TEST(UJson, SerializeString) { | 
 |   SourceSink ss; | 
 |   ujson uj = ss.UJson(); | 
 |  | 
 |   EXPECT_TRUE(status_ok(ujson_serialize_string(&uj, "abc123"))); | 
 |   EXPECT_EQ(ss.Sink(), R"json("abc123")json"); | 
 |  | 
 |   ss.Reset(); | 
 |   EXPECT_TRUE(status_ok(ujson_serialize_string(&uj, "\"\\\b\f\n\r\t"))); | 
 |   EXPECT_EQ(ss.Sink(), R"json("\"\\\b\f\n\r\t")json"); | 
 |  | 
 |   ss.Reset(); | 
 |   EXPECT_TRUE(status_ok(ujson_serialize_string(&uj, "\xFF\x01\x99"))); | 
 |   EXPECT_EQ(ss.Sink(), R"json("\u00ff\u0001\u0099")json"); | 
 | } | 
 |  | 
 | TEST(UJson, SerializeBool) { | 
 |   SourceSink ss; | 
 |   ujson uj = ss.UJson(); | 
 |   bool val; | 
 |  | 
 |   val = true; | 
 |   EXPECT_TRUE(status_ok(ujson_serialize_bool(&uj, &val))); | 
 |   EXPECT_EQ(ss.Sink(), R"json(true)json"); | 
 |  | 
 |   ss.Reset(); | 
 |   val = false; | 
 |   EXPECT_TRUE(status_ok(ujson_serialize_bool(&uj, &val))); | 
 |   EXPECT_EQ(ss.Sink(), R"json(false)json"); | 
 | } | 
 |  | 
 | #define INT(type_, str_, value_)                   \ | 
 |   do {                                             \ | 
 |     SourceSink ss;                                 \ | 
 |     ujson_t uj = ss.UJson();                       \ | 
 |     type_ t = value_;                              \ | 
 |     status_t s = ujson_serialize_##type_(&uj, &t); \ | 
 |     EXPECT_EQ(status_err(s), kOk);                 \ | 
 |     EXPECT_EQ(ss.Sink(), str_);                    \ | 
 |   } while (0) | 
 |  | 
 | TEST(UJson, SerializeIntegers) { | 
 |   INT(uint64_t, "9223372036854775808", 1UL << 63); | 
 |   INT(uint32_t, "4294967295", 0xFFFFFFFF); | 
 |   INT(uint16_t, "32768", 0x8000); | 
 |   INT(uint8_t, "129", 129); | 
 |  | 
 |   INT(int64_t, "-9223372036854775808", 1UL << 63); | 
 |   INT(int32_t, "-1", 0xFFFFFFFF); | 
 |   INT(int16_t, "-32768", 0x8000); | 
 |   INT(int8_t, "-2", 0xfe); | 
 | } | 
 |  | 
 | TEST(UJson, SerializeStatus) { | 
 |   SourceSink ss; | 
 |   ujson uj = ss.UJson(); | 
 |   status_t val; | 
 |  | 
 |   val = OK_STATUS(1234); | 
 |   EXPECT_TRUE(status_ok(ujson_serialize_status_t(&uj, &val))); | 
 |   EXPECT_EQ(ss.Sink(), R"json({"Ok":[1234]})json"); | 
 | } | 
 |  | 
 | TEST(UJson, DeerializeStatus) { | 
 |   SourceSink ss(R"json({"Ok":[1234]})json"); | 
 |   ujson uj = ss.UJson(); | 
 |   status_t val; | 
 |   const char *code; | 
 |   char mod_id[4] = {0}; | 
 |   int32_t arg; | 
 |  | 
 |   // Parse an Ok value with an argument. | 
 |   EXPECT_TRUE(status_ok(ujson_deserialize_status_t(&uj, &val))); | 
 |   status_extract(val, &code, &arg, mod_id); | 
 |   EXPECT_EQ(status_err(val), kOk); | 
 |   EXPECT_EQ(arg, 1234); | 
 |  | 
 |   // Parse an error value with a module and argument. | 
 |   // The module_id should get truncated to 3 characters. | 
 |   ss.Reset(R"json({"InvalidArgument": ["foobar", 77]})json"); | 
 |   EXPECT_TRUE(status_ok(ujson_deserialize_status_t(&uj, &val))); | 
 |   status_extract(val, &code, &arg, mod_id); | 
 |   EXPECT_EQ(status_err(val), kInvalidArgument); | 
 |   EXPECT_EQ(std::string(mod_id), "FOO"); | 
 |   EXPECT_EQ(arg, 77); | 
 | } | 
 |  | 
 | }  // namespace |