blob: 194e2c661ea23f9395d8066f445e9f495fd296d0 [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.
#ifndef ZXTEST_CPP_STREAMS_HELPER_H_
#define ZXTEST_CPP_STREAMS_HELPER_H_
#include <iostream>
#include <optional>
#include <sstream>
#include <zxtest/base/assertion.h>
#include <zxtest/base/types.h>
DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_status_value, status_value, zx_status_t (C::*)() const);
DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_status, status, zx_status_t (C::*)() const);
#define LIB_ZXTEST_RETURN_TAG_true return Tag()&
#define LIB_ZXTEST_RETURN_TAG_false
#define LIB_ZXTEST_RETURN_TAG(val) LIB_ZXTEST_RETURN_TAG_##val
template <typename T>
zx_status_t GetStatus(const T& status) {
if constexpr (has_status_value_v<T>) {
return status.status_value();
} else if constexpr (has_status_v<T>) {
return status.status();
} else {
return status;
}
}
struct Tag {};
class StreamableBase {
public:
StreamableBase(const zxtest::SourceLocation location)
: stream_(std::stringstream("")), location_(location) {}
// Lower precedence operator that returns void, such that the following
// expressions are valid in functions that return void:
//
// return Tag{} & StreamableBase{};
// return Tag{} & StreamableBase{} << "Stream operators are higher precedence than &";
//
friend void operator&(Tag, const StreamableBase&) {}
template <typename T>
StreamableBase& operator<<(T t) {
stream_ << t;
return *this;
}
protected:
std::stringstream stream_;
const zxtest::SourceLocation location_;
};
class StreamableFail : public StreamableBase {
public:
StreamableFail(const zxtest::SourceLocation location, bool is_fatal,
const cpp20::span<zxtest::Message*> traces)
: StreamableBase(location), is_fatal_(is_fatal), traces_(traces) {}
virtual ~StreamableFail() {
zxtest::Runner::GetInstance()->NotifyAssertion(
zxtest::Assertion(stream_.str(), location_, is_fatal_, traces_));
}
private:
bool is_fatal_ = false;
cpp20::span<zxtest::Message*> traces_;
};
class StreamableAssertion : public StreamableBase {
public:
template <typename Actual, typename Expected, typename CompareOp, typename PrintActual,
typename PrintExpected>
StreamableAssertion(const Actual& actual, const Expected& expected, const char* actual_symbol,
const char* expected_symbol, const zxtest::SourceLocation location,
bool is_fatal, const CompareOp& compare, const PrintActual& print_actual,
const PrintExpected& print_expected,
const cpp20::span<zxtest::Message*> traces)
: StreamableBase(location),
actual_symbol_(actual_symbol),
expected_symbol_(expected_symbol),
is_fatal_(is_fatal),
traces_(traces) {
actual_value_ = print_actual(actual);
expected_value_ = print_expected(expected);
is_triggered_ = !compare(actual, expected);
}
~StreamableAssertion() {
if (is_triggered_) {
zxtest::Runner::GetInstance()->NotifyAssertion(zxtest::Assertion(
stream_.str(), expected_symbol_.value(), expected_value_.value(), actual_symbol_.value(),
actual_value_.value(), location_, is_fatal_, traces_));
}
}
bool IsTriggered() { return is_triggered_; }
private:
std::optional<fbl::String> actual_value_;
std::optional<fbl::String> expected_value_;
std::optional<const char*> actual_symbol_;
std::optional<const char*> expected_symbol_;
bool is_fatal_ = false;
bool is_triggered_ = true;
cpp20::span<zxtest::Message*> traces_;
};
class StreamableSkip : public StreamableBase {
public:
StreamableSkip(const zxtest::SourceLocation location) : StreamableBase(location) {}
~StreamableSkip() {
zxtest::Message message(stream_.str(), location_);
zxtest::Runner::GetInstance()->SkipCurrent(message);
}
};
#endif // ZXTEST_CPP_STREAMS_HELPER_H_