| // 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 |