blob: 8d36cbc821547894d740c63a8541544db9da3141 [file]
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/trace_processor/util/json_value.h"
#include <limits>
#include "test/gtest_and_gmock.h"
namespace perfetto::trace_processor::json {
namespace {
// The most valuable test - exercises the entire serialize/parse pipeline
// with nested structures. If basic functionality breaks, this catches it.
TEST(DomTest, RoundTrip) {
Dom original(Type::kObject);
original["string"] = "test";
original["int"] = 42;
original["double"] = 3.14159;
original["bool"] = true;
original["null"] = Dom();
original["nested"] = Dom(Type::kObject);
original["nested"]["inner"] = "value";
original["array"] = Dom(Type::kArray);
original["array"].Append(1);
original["array"].Append("two");
std::string json = Serialize(original);
auto parsed = Parse(json);
ASSERT_TRUE(parsed.ok());
EXPECT_EQ((*parsed)["string"].AsString(), "test");
EXPECT_EQ((*parsed)["int"].AsInt(), 42);
EXPECT_DOUBLE_EQ((*parsed)["double"].AsDouble(), 3.14159);
EXPECT_TRUE((*parsed)["bool"].AsBool());
EXPECT_TRUE((*parsed)["null"].IsNull());
EXPECT_EQ((*parsed)["nested"]["inner"].AsString(), "value");
EXPECT_EQ((*parsed)["array"][0].AsInt(), 1);
EXPECT_EQ((*parsed)["array"][1].AsString(), "two");
}
// Tests deep copy independence - could catch shallow copy bugs
TEST(DomTest, CopyDeepNested) {
Dom original(Type::kObject);
original["a"] = Dom(Type::kObject);
original["a"]["b"] = 42;
Dom copy = original.Copy();
original["a"]["b"] = 999;
EXPECT_EQ(copy["a"]["b"].AsInt(), 42); // Copy unaffected
}
// Tests auto-conversion behavior which is non-obvious and could regress
TEST(DomTest, AutoConversion) {
// Mutable access on non-object converts to object
Dom v1(42);
v1["key"] = "value";
EXPECT_TRUE(v1.IsObject());
// Const access doesn't create entries
const Dom obj(Type::kObject);
EXPECT_TRUE(obj["missing"].IsNull());
EXPECT_EQ(obj.size(), 0u);
}
// Tests escape sequence handling in parsing
TEST(DomTest, ParseEscapes) {
auto r1 = Parse(R"({"a":"line\nwith\ttabs\"and\\slashes"})");
ASSERT_TRUE(r1.ok());
EXPECT_EQ((*r1)["a"].AsString(), "line\nwith\ttabs\"and\\slashes");
auto r2 = Parse(R"({"u":"\u0048\u0065\u006c\u006c\u006f"})");
ASSERT_TRUE(r2.ok());
EXPECT_EQ((*r2)["u"].AsString(), "Hello");
}
TEST(DomTest, ParseErrors) {
EXPECT_FALSE(Parse("{invalid}").ok());
EXPECT_FALSE(Parse("").ok());
}
} // namespace
} // namespace perfetto::trace_processor::json