blob: a8cc13f1a73f7d838b167b653911511dd74d4eec [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 "src/developer/debug/zxdb/expr/pretty_type.h"
#include <gtest/gtest.h>
#include "src/developer/debug/zxdb/common/test_with_loop.h"
#include "src/developer/debug/zxdb/expr/eval_context.h"
#include "src/developer/debug/zxdb/expr/format_node.h"
#include "src/developer/debug/zxdb/expr/format_options.h"
#include "src/developer/debug/zxdb/expr/format_test_support.h"
#include "src/developer/debug/zxdb/expr/mock_eval_context.h"
#include "src/developer/debug/zxdb/symbols/type_test_support.h"
// NOTE: Some of the tests are in pretty_type_manager_unittest.cc. Those test the actual
// instantiation of the PrettyType classes for STL, etc. while this file tests the PrettyType
// classes in the abstract.
namespace zxdb {
namespace {
class PrettyTypeTest : public TestWithLoop {};
} // namespace
TEST_F(PrettyTypeTest, RecursiveVariant) {
// This declares the following structure to encode a variant of two values:
//
// template<Value, NextNode> union Node {
// Value value;
// NextNode next;
// };
//
// struct Variant<int32_t, double> {
// uint32_t index;
// Node<int32_t, Node<double, void>> base;
// }
auto node_double_void =
MakeCollectionType(DwarfTag::kUnionType, "Node<double, void>", {{"value", MakeDoubleType()}});
auto node_int_double =
MakeCollectionType(DwarfTag::kUnionType, "Node<int, Node<double, void>>",
{{"value", MakeInt32Type()}, {"next", node_double_void}});
const char kVariantName[] = "Variant<int32_t, double>";
auto variant_type = MakeCollectionType(DwarfTag::kStructureType, kVariantName,
{{"index", MakeUint32Type()}, {"base", node_int_double}});
PrettyRecursiveVariant pretty("Variant", "base", "index", "next", "value", "Variant::npos", {});
auto eval_context = fxl::MakeRefCounted<MockEvalContext>();
FormatOptions options;
// NONE VARIANT
// 4-byte index = -1, 8-byte value is irrelevant.
FormatNode none_node("none",
ExprValue(variant_type, {0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}));
none_node.set_type(kVariantName);
bool complete = false;
pretty.Format(&none_node, options, eval_context,
fit::defer_callback([&complete]() { complete = true; }));
EXPECT_TRUE(complete); // Expect synchronous completion.
EXPECT_EQ("none = Variant<int32_t, double>, Variant::npos\n",
GetDebugTreeForFormatNode(&none_node));
// INT VARIANT
// 4-byte index = 0, 4-byte int32 value = 42, 4 bytes padding.
FormatNode int_node("int_one", ExprValue(variant_type, {0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0}));
int_node.set_type(kVariantName);
complete = false;
pretty.Format(&int_node, options, eval_context,
fit::defer_callback([&complete]() { complete = true; }));
EXPECT_TRUE(complete); // Expect synchronous completion.
// It should have made one child which we need to describe now.
ASSERT_EQ(1u, int_node.children().size());
SyncFillAndDescribeFormatNode(eval_context, int_node.children()[0].get(), options);
EXPECT_EQ(
"int_one = Variant<int32_t, double>, Variant\n"
" = int32_t, 42\n",
GetDebugTreeForFormatNode(&int_node));
// DOUBLE VARIANT
// 4-byte index = 1, 8 byte double value.
std::vector<uint8_t> data{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const double kSourceDouble = 3.14159;
memcpy(&data[4], &kSourceDouble, sizeof(double));
FormatNode double_node("double_one", ExprValue(variant_type, data));
double_node.set_type(kVariantName);
complete = false;
pretty.Format(&double_node, options, eval_context,
fit::defer_callback([&complete]() { complete = true; }));
EXPECT_TRUE(complete); // Expect synchronous completion.
// It should have made one child which we need to describe now.
ASSERT_EQ(1u, double_node.children().size());
SyncFillAndDescribeFormatNode(eval_context, double_node.children()[0].get(), options);
EXPECT_EQ(
"double_one = Variant<int32_t, double>, Variant\n"
" = double, 3.14159\n",
GetDebugTreeForFormatNode(&double_node));
}
TEST_F(PrettyTypeTest, PrettyWrappedValue) {
// Make a structure with one value that will be our pretty-printed value.
auto structure =
MakeCollectionType(DwarfTag::kStructureType, "TestStruct", {{"value", MakeInt32Type()}});
ExprValue value(static_cast<int32_t>(42), structure);
PrettyWrappedValue pretty("TestStruct", "[<", ">]", "value");
FormatNode node("result", value);
node.set_type("TestStruct");
auto eval_context = fxl::MakeRefCounted<MockEvalContext>();
FormatOptions options;
bool complete = false;
pretty.Format(&node, options, eval_context,
fit::defer_callback([&complete]() { complete = true; }));
EXPECT_TRUE(complete); // Expect synchronous completion.
SyncFillAndDescribeFormatNode(eval_context, node.children()[0].get(), options);
EXPECT_EQ(
"result = TestStruct, TestStruct\n"
" = int32_t, 42\n",
GetDebugTreeForFormatNode(&node));
EXPECT_EQ("[<", node.wrapper_prefix());
EXPECT_EQ(">]", node.wrapper_suffix());
}
} // namespace zxdb