blob: 824cb891a18b6977ec843dd5c15ecfd1875de67d [file] [log] [blame]
#include "aos/common/queue_testutils.h"
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include "gtest/gtest.h"
#include "aos/common/queue.h"
#include "aos/common/logging/logging_impl.h"
#include "aos/common/once.h"
using ::aos::logging::LogMessage;
namespace aos {
namespace common {
namespace testing {
namespace {
class TestLogImplementation : public logging::HandleMessageLogImplementation {
public:
const ::std::vector<LogMessage> &messages() { return messages_; }
// This class has to be a singleton so that everybody can get access to the
// same instance to read out the messages etc.
static TestLogImplementation *GetInstance() {
static Once<TestLogImplementation> once(CreateInstance);
return once.Get();
}
// Clears out all of the messages already recorded.
void ClearMessages() {
messages_.clear();
}
// Prints out all of the messages (like when a test fails).
void PrintAllMessages() {
for (auto it = messages_.begin(); it != messages_.end(); ++it) {
logging::internal::PrintMessage(stdout, *it);
}
}
private:
TestLogImplementation() {}
static TestLogImplementation *CreateInstance() {
return new TestLogImplementation();
}
virtual void HandleMessage(const LogMessage &message) override {
if (message.level == FATAL) {
logging::internal::PrintMessage(stdout, message);
}
messages_.push_back(message);
}
::std::vector<LogMessage> messages_;
};
class MyTestEventListener : public ::testing::EmptyTestEventListener {
virtual void OnTestStart(const ::testing::TestInfo &/*test_info*/) {
TestLogImplementation::GetInstance()->ClearMessages();
}
virtual void OnTestEnd(const ::testing::TestInfo &test_info) {
if (test_info.result()->Failed()) {
printf("Test %s failed. Printing out all log messages.\n",
test_info.name());
fputs("\tThis will include already printed WARNING and up messages.\n",
stdout);
fputs("\tIt will also include duplicates of all gtest failures.\n",
stdout);
TestLogImplementation::GetInstance()->PrintAllMessages();
}
}
virtual void OnTestPartResult( const ::testing::TestPartResult &result) {
if (result.failed()) {
const char *failure_type = "unknown";
switch (result.type()) {
case ::testing::TestPartResult::Type::kNonFatalFailure:
failure_type = "EXPECT";
break;
case ::testing::TestPartResult::Type::kFatalFailure:
failure_type = "ASSERT";
break;
case ::testing::TestPartResult::Type::kSuccess:
break;
}
log_do(ERROR, "%s: %d: gtest %s failure\n%s\n",
result.file_name(),
result.line_number(),
failure_type,
result.message());
}
}
};
void *DoEnableTestLogging() {
logging::Init();
logging::AddImplementation(TestLogImplementation::GetInstance());
::testing::UnitTest::GetInstance()->listeners().Append(
new MyTestEventListener());
return NULL;
}
Once<void> enable_test_logging_once(DoEnableTestLogging);
const size_t kCoreSize = 0x100000;
void TerminateExitHandler() {
_exit(EXIT_SUCCESS);
}
} // namespace
GlobalCoreInstance::GlobalCoreInstance() {
global_core = &global_core_data_;
global_core->owner = true;
// Use mmap(2) manually instead of through malloc(3) so that we can pass
// MAP_SHARED which allows forked processes to communicate using the
// "shared" memory.
void *memory = mmap(NULL, kCoreSize, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
CHECK_NE(memory, MAP_FAILED);
aos_core_use_address_as_shared_mem(memory, kCoreSize);
EnableTestLogging();
}
GlobalCoreInstance::~GlobalCoreInstance() {
PCHECK(munmap(global_core->mem_struct, kCoreSize));
global_core = NULL;
}
void EnableTestLogging() {
enable_test_logging_once.Get();
}
void PreventExit() {
CHECK_EQ(atexit(TerminateExitHandler), 0);
}
} // namespace testing
} // namespace common
} // namespace aos