| // 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, ParseIntegerError) { | |
| SourceSink ss; | |
| ujson uj = ss.UJson(); | |
| uint32_t t; | |
| status_t s; | |
| // Empty string. | |
| s = ujson_parse_integer(&uj, (void *)&t, sizeof(t)); | |
| EXPECT_EQ(status_err(s), kResourceExhausted); | |
| // Non integer character. | |
| ss.Reset("q"); | |
| s = ujson_parse_integer(&uj, (void *)&t, sizeof(t)); | |
| EXPECT_EQ(status_err(s), kNotFound); | |
| } | |
| 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 |