blob: 0225712cd14a7af955c75c37da63b36c062416bb [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/media/audio/lib/test/test_fixture.h"
#include <zircon/status.h>
#include <iomanip>
#include <ostream>
#include "src/lib/fxl/strings/string_printf.h"
namespace media::audio::test {
#ifdef NDEBUG
constexpr zx::duration kLoopTimeout = zx::sec(10);
#else
constexpr zx::duration kLoopTimeout = zx::sec(30);
#endif
void TestFixture::TearDown() {
ExpectNoUnexpectedErrors("during TearDown");
::gtest::RealLoopFixture::TearDown();
}
void TestFixture::ExpectCallbacks() {
std::vector<PendingCallback> retired_callbacks;
while (!pending_callbacks_.empty()) {
auto callback = pending_callbacks_.front();
pending_callbacks_.pop_front();
RunLoopWithTimeoutOrUntil(
[this, callback]() { return new_error_ || callback->sequence_num > 0; }, kLoopTimeout);
if (new_error_) {
new_error_ = false;
auto error_str = fxl::StringPrintf("while waiting for '%s'", callback->name.c_str());
ADD_FAILURE() << "Unexpected error " << error_str;
ExpectNoUnexpectedErrors(error_str);
pending_callbacks_.clear();
return;
}
if (callback->sequence_num == 0) {
ADD_FAILURE() << "Did not get a '" << callback->name << "' callback within "
<< kLoopTimeout.to_msecs() << " ms";
pending_callbacks_.clear();
return;
}
if (callback->ordered) {
if (!retired_callbacks.empty()) {
auto prev_callback = retired_callbacks.back();
if (callback->sequence_num <= prev_callback.sequence_num) {
std::ostringstream out_stream;
auto format_cb_entry = [&out_stream](const PendingCallback callback_entry) {
out_stream << std::right << std::setw(23)
<< (std::string("'") + callback_entry.name + "' [")
<< callback_entry.sequence_num << "]" << std::endl;
};
out_stream << " Expected order [Actual order]" << std::endl;
std::for_each(retired_callbacks.begin(), retired_callbacks.end(), format_cb_entry);
format_cb_entry(*callback);
ADD_FAILURE() << "Out-of-order callbacks: '" << callback->name
<< "' completed too early -- should have been after '" << prev_callback.name
<< "'" << std::endl
<< out_stream.str();
}
}
retired_callbacks.push_back(*callback);
}
}
}
void TestFixture::ExpectNoCallbacks(zx::duration timeout, const std::string& msg_for_failure) {
RunLoopWithTimeout(timeout);
ExpectNoUnexpectedErrors(msg_for_failure);
pending_callbacks_.clear();
}
void TestFixture::ExpectErrors(const std::vector<std::shared_ptr<ErrorHandler>>& errors) {
std::string names = "{";
std::string sep;
for (auto& eh : errors) {
names += eh->name;
sep = ", ";
}
names += "}";
RunLoopWithTimeoutOrUntil(
[errors]() {
for (auto& eh : errors) {
if (eh->error_code != eh->expected_error_code) {
return false;
}
}
return true;
},
kLoopTimeout);
new_error_ = false;
ExpectNoUnexpectedErrors(fxl::StringPrintf("when waiting error in %s", names.c_str()));
}
void TestFixture::ExpectNoUnexpectedErrors(const std::string& msg_for_failure) {
for (auto& [_, eh] : error_handlers_) {
EXPECT_EQ(eh->error_code, eh->expected_error_code)
<< msg_for_failure << ": " << eh->name << " had an unexpected error\nExpected error is "
<< zx_status_get_string(eh->expected_error_code) << "\nActual error is "
<< zx_status_get_string(eh->error_code);
}
}
std::pair<std::shared_ptr<TestFixture::ErrorHandler>, fit::function<void(zx_status_t)>>
TestFixture::NewErrorHandler(const std::string& name) {
auto eh = std::make_shared<ErrorHandler>();
eh->name = name;
return std::make_pair(eh, [this, eh](zx_status_t status) {
eh->error_code = status;
new_error_ = true;
});
}
std::shared_ptr<TestFixture::PendingCallback> TestFixture::NewPendingCallback(
const std::string& name, bool ordered) {
auto callback = std::make_shared<PendingCallback>();
callback->name = name;
callback->ordered = ordered;
pending_callbacks_.push_back(callback);
return callback;
}
bool TestFixture::ErrorOccurred() {
for (auto& [_, eh] : error_handlers_) {
if (eh->error_code != ZX_OK) {
return true;
}
}
return false;
}
} // namespace media::audio::test