blob: e07c77c610e63b71839ab07b5438d4c8c2d89593 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fuchsia/inspect/cpp/fidl.h>
#include <lib/fit/defer.h>
#include <lib/inspect/inspect.h>
#include <lib/inspect/reader.h>
#include <lib/inspect/testing/inspect.h>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace {
using inspect::Object;
using testing::AllOf;
using testing::IsEmpty;
using testing::UnorderedElementsAre;
using namespace inspect::testing;
TEST(InspectFidl, EmptyObject) {
Object obj;
auto child = obj.CreateChild("child");
auto int_metric = obj.CreateIntMetric("int", 0);
auto uint_metric = obj.CreateUIntMetric("uint", 0);
auto double_metric = obj.CreateDoubleMetric("double", 0);
auto str = obj.CreateStringProperty("str", "test");
auto bytes =
obj.CreateByteVectorProperty("bytes", inspect::VectorValue(3, 'a'));
auto lazy_metric = obj.CreateLazyMetric(
"lazy metric", [](component::Metric* out) { out->SetInt(0); });
auto lazy_string =
obj.CreateLazyStringProperty("lazy string", [] { return "test"; });
auto lazy_bytes = obj.CreateLazyByteVectorProperty(
"lazy bytes", [] { return inspect::VectorValue(3, 'a'); });
auto lazy_children =
obj.CreateChildrenCallback([](component::Object::ObjectVector* out) {});
auto output = obj.object();
EXPECT_STREQ("", output.name.c_str());
EXPECT_EQ(0u, output.properties->size());
EXPECT_EQ(0u, output.metrics->size());
EXPECT_EQ(0u, obj.children()->size());
}
TEST(InspectFidl, Object) {
Object obj("test");
auto output = obj.object();
EXPECT_STREQ("test", output.name.c_str());
EXPECT_EQ(0u, output.properties->size());
EXPECT_EQ(0u, output.metrics->size());
}
class ValueWrapper {
public:
ValueWrapper(Object obj, int val)
: object_(std::move(obj)),
value_(object_.CreateIntMetric("value", val)) {}
Object& object() { return object_; };
private:
Object object_;
inspect::IntMetric value_;
};
TEST(InspectFidl, Child) {
Object root("root");
{
// Create a child and check it exists.
auto obj = root.CreateChild("child");
EXPECT_THAT(*root.children(), UnorderedElementsAre("child"));
auto obj2 = root.CreateChild("child2");
EXPECT_THAT(*root.children(), UnorderedElementsAre("child", "child2"));
// Check assignment removes the old object.
obj = root.CreateChild("newchild");
EXPECT_THAT(*root.children(), UnorderedElementsAre("newchild", "child2"));
}
// Check that the child is removed when it goes out of scope.
EXPECT_THAT(*root.children(), IsEmpty());
}
TEST(InspectFidl, ChildChaining) {
Object root("root");
{
ValueWrapper v(root.CreateChild("child"), 100);
EXPECT_THAT(*root.children(), UnorderedElementsAre("child"));
auto obj = v.object().object();
EXPECT_THAT((*obj.metrics)[0].key, ::testing::Eq("value"));
}
// Check that the child is removed when it goes out of scope.
EXPECT_THAT(*root.children(), IsEmpty());
}
TEST(InspectFidl, ChildrenCallbacks) {
Object root("root");
{
inspect::ChildrenCallback callback =
root.CreateChildrenCallback([](component::Object::ObjectVector* out) {
out->push_back(component::ObjectDir::Make("temp").object());
});
EXPECT_THAT(*root.children(), UnorderedElementsAre("temp"));
}
// Check that the child is removed when it goes out of scope.
EXPECT_THAT(*root.children(), IsEmpty());
}
template <typename Type>
void DefaultMetricTest() {
Type default_metric;
default_metric.Add(1);
default_metric.Subtract(1);
default_metric.Set(1);
}
TEST(InspectFidl, Metrics) {
DefaultMetricTest<inspect::IntMetric>();
DefaultMetricTest<inspect::UIntMetric>();
DefaultMetricTest<inspect::DoubleMetric>();
Object root("root");
{
// Create a child and check it exists.
auto metric_int = root.CreateIntMetric("int", -10);
metric_int.Add(5);
metric_int.Subtract(4);
auto metric_uint = root.CreateUIntMetric("uint", 10);
metric_uint.Add(4);
metric_uint.Subtract(5);
auto metric_double = root.CreateDoubleMetric("double", 0.25);
metric_double.Add(1);
metric_double.Subtract(0.5);
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(MetricList(UnorderedElementsAre(
IntMetricIs("int", -9), UIntMetricIs("uint", 9),
DoubleMetricIs("double", 0.75))))));
}
// Check that the metrics are removed when they goes out of scope.
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(MetricList(IsEmpty()))));
{
// Test that a later metric overwrites an earlier metric with the same name.
auto metric_int = root.CreateIntMetric("value", -10);
auto metric_uint = root.CreateUIntMetric("value", 10);
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(MetricList(
UnorderedElementsAre(UIntMetricIs("value", 10))))));
// Deleting any of the owners deletes the value.
metric_int = root.CreateIntMetric("other", 0);
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(MetricList(
UnorderedElementsAre(IntMetricIs("other", 0))))));
// Adding to the deleted value does nothing.
metric_uint.Add(100);
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(MetricList(
UnorderedElementsAre(IntMetricIs("other", 0))))));
// Setting the deleted value recreates it.
// TODO(CF-275): Fix this behavior.
metric_uint.Set(100);
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(MetricList(UnorderedElementsAre(
UIntMetricIs("value", 100), IntMetricIs("other", 0))))));
}
}
TEST(InspectFidl, MetricCallbacks) {
Object root("root");
bool defer_called = false;
auto defer = fit::defer([&defer_called] { defer_called = true; });
{
int64_t metric_value = -100;
// Create a child and check it exists.
auto metric = root.CreateLazyMetric(
"value",
[defer = std::move(defer), &metric_value](component::Metric* value) {
value->SetInt(metric_value++);
});
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(MetricList(
UnorderedElementsAre(IntMetricIs("value", -100))))));
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(MetricList(
UnorderedElementsAre(IntMetricIs("value", -99))))));
EXPECT_FALSE(defer_called);
}
// Check that the callback is removed and destroyed (defer called) when it
// goes out of scope.
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(MetricList(IsEmpty()))));
EXPECT_TRUE(defer_called);
}
TEST(InspectFidl, Properties) {
Object root("root");
{
auto property_string = root.CreateStringProperty("str", "test");
property_string.Set("valid");
auto property_vector =
root.CreateByteVectorProperty("vec", inspect::VectorValue(3, 'a'));
EXPECT_THAT(
inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(PropertyList(UnorderedElementsAre(
StringPropertyIs("str", "valid"),
ByteVectorPropertyIs("vec", inspect::VectorValue(3, 'a')))))));
}
// Check that the properties are removed when they goes out of scope.
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(PropertyList(IsEmpty()))));
{
// Test that a later property overwrites an earlier property with the same
// name.
auto property_string = root.CreateStringProperty("string", "a");
auto property_other = root.CreateStringProperty("string", "b");
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(PropertyList(
UnorderedElementsAre(StringPropertyIs("string", "b"))))));
// Deleting any of the owners deletes the value.
property_string = root.CreateStringProperty("not_string", "b");
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(PropertyList(UnorderedElementsAre(
StringPropertyIs("not_string", "b"))))));
// Setting the deleted value recreates it.
// TODO(CF-275): Fix this behavior.
property_other.Set("c");
EXPECT_THAT(inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(PropertyList(
UnorderedElementsAre(StringPropertyIs("not_string", "b"),
StringPropertyIs("string", "c"))))));
}
}
TEST(InspectFidl, PropertyCallbacks) {
Object root("root");
bool defer_called1 = false, defer_called2 = false;
auto defer1 = fit::defer([&defer_called1] { defer_called1 = true; });
auto defer2 = fit::defer([&defer_called2] { defer_called2 = true; });
{
std::string val = "1";
inspect::VectorValue vec(3, 'a');
// Create a child and check it exists.
auto property_string = root.CreateLazyStringProperty(
"string", [defer = std::move(defer1), &val] {
val.append("2");
return val;
});
auto property_vector = root.CreateLazyByteVectorProperty(
"vector", [defer = std::move(defer2), &vec] {
vec.push_back('a');
return vec;
});
EXPECT_THAT(
inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(PropertyList(UnorderedElementsAre(
StringPropertyIs("string", "12"),
ByteVectorPropertyIs("vector", inspect::VectorValue(4, 'a')))))));
EXPECT_THAT(
inspect::ReadFromFidlObject(root.object()),
NodeMatches(AllOf(PropertyList(UnorderedElementsAre(
StringPropertyIs("string", "122"),
ByteVectorPropertyIs("vector", inspect::VectorValue(5, 'a')))))));
EXPECT_FALSE(defer_called1);
EXPECT_FALSE(defer_called2);
}
// Check that the callback is removed and destroyed (defer called) when it
// goes out of scope.
EXPECT_THAT(*root.object().properties, IsEmpty());
EXPECT_TRUE(defer_called1);
EXPECT_TRUE(defer_called2);
}
} // namespace