blob: 06f5069a0e386c93af00ac38dab8fc26fd72d5c8 [file] [log] [blame]
// 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