blob: 67269768b6b95ace5ae1fff56297b886eaf9d78c [file] [log] [blame]
// Copyright 2021 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/lib/util/status_builder.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#ifdef HAVE_GLOG
#include <string>
#include <vector>
#include <glog/logging.h>
#endif // HAVE_GLOG
namespace cobalt {
using testing::HasSubstr;
TEST(StatusBuilder, Ok) {
Status status = util::StatusBuilder(StatusCode::OK).Build();
ASSERT_EQ(StatusCode::OK, status.error_code());
}
TEST(StatusBuilder, BasicConstructor) {
Status status = util::StatusBuilder(StatusCode::INTERNAL, "Internal error").Build();
ASSERT_EQ(StatusCode::INTERNAL, status.error_code());
ASSERT_EQ("Internal error", status.error_message());
}
TEST(StatusBuilder, SetCodeWorks) {
Status status = util::StatusBuilder(StatusCode::OK).SetCode(StatusCode::INVALID_ARGUMENT).Build();
ASSERT_EQ(StatusCode::INVALID_ARGUMENT, status.error_code());
}
TEST(StatusBuilder, WithContextWorks) {
Status status = util::StatusBuilder(StatusCode::RESOURCE_EXHAUSTED)
.WithContext("number", 10)
.WithContext("string", "value")
.WithContext("bool", true)
.Build();
ASSERT_EQ(StatusCode::RESOURCE_EXHAUSTED, status.error_code());
ASSERT_THAT(status.error_details(), HasSubstr("number=10"));
ASSERT_THAT(status.error_details(), HasSubstr("string=value"));
ASSERT_THAT(status.error_details(), HasSubstr("bool=1"));
}
TEST(StatusBuilder, AppendMsgWorks) {
Status status =
util::StatusBuilder(StatusCode::UNIMPLEMENTED, "Base msg").AppendMsg(" more message").Build();
ASSERT_EQ(StatusCode::UNIMPLEMENTED, status.error_code());
ASSERT_EQ(status.error_message(), "Base msg more message");
}
TEST(StatusBuilder, ErrorMessageLimit) {
util::StatusBuilder builder(StatusCode::UNIMPLEMENTED, "Base msg");
for (int i = 0; i < 100; i++) {
builder.AppendMsg(" more message");
}
Status status = builder.Build();
ASSERT_EQ(status.error_message().size(), 256ul);
}
TEST(StatusBuilder, ContextFormatterWorks) {
ReportDefinition rd;
rd.set_report_name("Report name");
Status status = util::StatusBuilder(StatusCode::UNIMPLEMENTED)
.WithContexts(rd)
.WithContext("CustomName", rd)
.Build();
ASSERT_EQ(StatusCode::UNIMPLEMENTED, status.error_code());
ASSERT_THAT(status.error_details(), HasSubstr("Report=Report name"));
ASSERT_THAT(status.error_details(), HasSubstr("CustomName=Report name"));
}
namespace {
struct TestStruct {
int v;
float v2;
};
} // namespace
namespace util {
template <>
class ContextFormatter<TestStruct> {
public:
explicit ContextFormatter(const TestStruct &v) : v_(v) {}
inline static std::string default_key() { return "TestStruct"; }
inline void write_value(std::ostream &stream) const {
stream << "V(" << v_.v << "/" << v_.v2 << ")";
}
private:
const TestStruct &v_;
};
} // namespace util
TEST(StatusBuilder, CustomContextFormatter) {
TestStruct ts;
ts.v = 100;
ts.v2 = 12.10f;
Status status = util::StatusBuilder(StatusCode::ABORTED)
.WithContexts(ts)
.WithContext("local_name", ts)
.Build();
ASSERT_EQ(StatusCode::ABORTED, status.error_code());
ASSERT_THAT(status.error_details(), HasSubstr("TestStruct=V(100/12.1)"));
ASSERT_THAT(status.error_details(), HasSubstr("local_name=V(100/12.1)"));
}
// Testing the logging code. Currently only runs on platforms with GLOG.
#ifdef HAVE_GLOG
class LogSink : public ::google::LogSink {
public:
std::vector<std::string> errors;
void send(::google::LogSeverity severity, const char *full_filename, const char *base_filename,
int line, const struct ::tm *tm_time, const char *message,
size_t message_len) override {
errors.push_back(ToString(severity, base_filename, line, tm_time, message, message_len));
}
};
void ConstructAndDrop(util::StatusBuilder builder) { std::move(builder).Build(); }
TEST(StatusBuilder, LogWorks) {
LogSink sink;
::google::AddLogSink(&sink);
ConstructAndDrop(
util::StatusBuilder(StatusCode::NOT_FOUND, "Msg1").Log(util::StatusBuilder::LogLevel::ERROR));
ConstructAndDrop(util::StatusBuilder(StatusCode::NOT_FOUND, "Msg2").LogError());
ConstructAndDrop(util::StatusBuilder(StatusCode::NOT_FOUND, "Msg3").LogWarning());
ConstructAndDrop(util::StatusBuilder(StatusCode::NOT_FOUND, "Msg4").LogInfo());
ASSERT_EQ(size_t{4}, sink.errors.size());
ASSERT_THAT(sink.errors[0], HasSubstr("NOT_FOUND: Msg1"));
ASSERT_THAT(sink.errors[1], HasSubstr("NOT_FOUND: Msg2"));
ASSERT_THAT(sink.errors[2], HasSubstr("NOT_FOUND: Msg3"));
ASSERT_THAT(sink.errors[3], HasSubstr("NOT_FOUND: Msg4"));
::google::RemoveLogSink(&sink);
}
#endif // HAVE_GLOG
} // namespace cobalt