blob: b555daab96cca675fbf2bf7bdb2be829db283e43 [file]
#include "mpact/sim/decoder/bin_encoding_info.h"
#include "absl/log/check.h"
#include "absl/status/status.h"
#include "googletest/include/gtest/gtest.h"
#include "mpact/sim/decoder/decoder_error_listener.h"
#include "mpact/sim/decoder/format.h"
#include "mpact/sim/decoder/instruction_group.h"
// This file provides for testing of the BinEncodingInfo class interfaces, with
// the exception of PropagateExtractors, as that cannot be tested in isolation.
namespace {
using ::mpact::sim::decoder::DecoderErrorListener;
using ::mpact::sim::decoder::bin_format::BinEncodingInfo;
constexpr char kOpcodeEnumName[] = "OpcodeEnumName";
constexpr char kIncludeFile0[] = "IncludeFile0";
constexpr char kIncludeFile1[] = "IncludeFile1";
constexpr char kIncludeFile2[] = "IncludeFile2";
constexpr const char *kIncludeFiles[] = {kIncludeFile0, kIncludeFile1,
kIncludeFile2};
constexpr char kFormat0[] = "Format0";
constexpr char kFormat1[] = "Format1";
constexpr char kFormat2[] = "Format2";
constexpr char kGroup0[] = "Group0";
constexpr char kBinDecoder[] = "BinDecoder";
constexpr int kFormatWidth32 = 32;
constexpr int kFormatWidth16 = 16;
class BinEncodingInfoTest : public ::testing::Test {
protected:
BinEncodingInfoTest() {
error_listener_ = new DecoderErrorListener();
bin_encoding_info_ = new BinEncodingInfo(kOpcodeEnumName, error_listener_);
}
~BinEncodingInfoTest() override {
for (auto &[name, instruction_group_ptr] :
bin_encoding_info_->instruction_group_map()) {
delete instruction_group_ptr;
}
delete bin_encoding_info_;
delete error_listener_;
}
DecoderErrorListener *error_listener_ = nullptr;
BinEncodingInfo *bin_encoding_info_ = nullptr;
};
// Test for proper initialization of object.
TEST_F(BinEncodingInfoTest, Constructed) {
EXPECT_FALSE(error_listener_->HasError());
EXPECT_TRUE(bin_encoding_info_->format_map().empty());
EXPECT_TRUE(bin_encoding_info_->include_files().empty());
EXPECT_TRUE(bin_encoding_info_->instruction_group_map().empty());
EXPECT_EQ(bin_encoding_info_->decoder(), nullptr);
EXPECT_EQ(bin_encoding_info_->error_listener(), error_listener_);
}
// Test that include files are properly added/kept.
TEST_F(BinEncodingInfoTest, AddIncludeFile) {
EXPECT_TRUE(bin_encoding_info_->include_files().empty());
for (auto const &include_file : kIncludeFiles) {
bin_encoding_info_->AddIncludeFile(include_file);
}
EXPECT_FALSE(bin_encoding_info_->include_files().empty());
for (auto const &include_file : kIncludeFiles) {
EXPECT_TRUE(bin_encoding_info_->include_files().contains(include_file));
}
EXPECT_FALSE(bin_encoding_info_->include_files().contains("NoIncludeFile"));
}
// Test that formats are properly added/kept.
TEST_F(BinEncodingInfoTest, AddFormat) {
// Adding a new format should work.
auto res0 = bin_encoding_info_->AddFormat(kFormat0, kFormatWidth32);
EXPECT_TRUE(res0.status().ok());
auto *format = res0.value();
EXPECT_EQ(format->name(), kFormat0);
EXPECT_EQ(format->declared_width(), kFormatWidth32);
// Make sure we get the format back when calling GetFormat.
auto *get_format = bin_encoding_info_->GetFormat(kFormat0);
EXPECT_EQ(get_format, format);
// Adding the same format again should fail.
res0 = bin_encoding_info_->AddFormat(kFormat0, kFormatWidth32);
EXPECT_EQ(absl::StatusCode::kAlreadyExists, res0.status().code());
// Add a different format should work.
auto res1 = bin_encoding_info_->AddFormat(kFormat1, kFormatWidth16);
EXPECT_TRUE(res1.status().ok());
format = res1.value();
EXPECT_EQ(format->name(), kFormat1);
EXPECT_EQ(format->declared_width(), kFormatWidth16);
// Add format with parent.
auto res2 = bin_encoding_info_->AddFormat(kFormat2, kFormatWidth32, kFormat0);
EXPECT_TRUE(res2.status().ok());
format = res2.value();
EXPECT_EQ(format->name(), kFormat2);
EXPECT_EQ(format->declared_width(), kFormatWidth32);
// Can't add the same format twice.
res2 = bin_encoding_info_->AddFormat(kFormat2, kFormatWidth32, kFormat0);
EXPECT_EQ(absl::StatusCode::kAlreadyExists, res2.status().code());
// Format map. Verify that the formats are in the map.
auto &format_map = bin_encoding_info_->format_map();
EXPECT_EQ(format_map.size(), 3);
EXPECT_NE(format_map.find(kFormat0), format_map.end());
EXPECT_NE(format_map.find(kFormat1), format_map.end());
EXPECT_NE(format_map.find(kFormat2), format_map.end());
}
// Instruction groups.
TEST_F(BinEncodingInfoTest, AddInstructionGroup) {
EXPECT_TRUE(bin_encoding_info_->instruction_group_map().empty());
// Add an instruction group.
auto res = bin_encoding_info_->AddInstructionGroup(kGroup0, kFormatWidth32,
kFormat0);
EXPECT_TRUE(res.status().ok());
auto *instruction_group = res.value();
EXPECT_EQ(instruction_group->name(), kGroup0);
EXPECT_EQ(instruction_group->width(), kFormatWidth32);
EXPECT_EQ(instruction_group->format_name(), kFormat0);
EXPECT_EQ(instruction_group->opcode_enum(), kOpcodeEnumName);
// Adding it a second time doesn't work.
res = bin_encoding_info_->AddInstructionGroup(kGroup0, kFormatWidth32,
kFormat0);
EXPECT_EQ(absl::StatusCode::kAlreadyExists, res.status().code());
}
// Bin decoder.
TEST_F(BinEncodingInfoTest, AddDecoder) {
// Add BinDecoder.
auto *bin_dec = bin_encoding_info_->AddBinDecoder(kBinDecoder);
EXPECT_NE(bin_dec, nullptr);
EXPECT_FALSE(error_listener_->HasError());
// Try adding it again.
bin_dec = bin_encoding_info_->AddBinDecoder(kBinDecoder);
EXPECT_EQ(bin_dec, nullptr);
EXPECT_TRUE(error_listener_->HasError());
}
} // namespace