I'm trying to write GameBoy emulator, but I'm not sure how should I test my CPU_LR39502 class. To avoid huge if-else-if / switch-case statements, I came up with idea to put opcode functor into map, which takes opcode as key:
class Functor
{
std::function<void()> m_function;
public:
Functor(std::function<void()>&& function)
{
m_function = std::move(function);
}
void operator()()
{
m_function();
}
};
class BaseOpcodeFunctor : public Functor
{
unsigned char m_opcode;
std::string m_disasmString;
public:
BaseOpcodeFunctor(std::function<void()>&& function,
unsigned char opcode,
std::string&& disasmString)
: Functor(std::move(function)),
m_opcode(opcode),
m_disasmString(std::move(disasmString)) {}
std::string disasm()
{
return m_disasmString;
}
unsigned char getAssignedOpcode()
{
return m_opcode;
}
};
And example of it:
class CPU_LR35902
{
...
std::map<unsigned char, BaseOpcodeFunctor> m_baseOpcodeMap;
public:
CPU_LR35902()
{
...
initializeBaseOpcodeMap();
}
...
private:
void addFunctorToBaseOpcodeMap(BaseOpcodeFunctor&& functor);
void initializeBaseOpcodeMap()
{
...
addFunctorToBaseOpcodeMap(BaseOpcodeFunctor([this]() {
bitwiseRotationLeft(REGISTER_A);
}, 0x07, "RLCA"));
}
void bitwiseRotationLeft(LR35902_8BIT_REGISTERS reg)
{
resetFlag(FLAG_Z);
resetFlag(FLAG_N);
resetFlag(FLAG_H);
setFlag(FLAG_C, registers_8bit.at(reg) >> 7);
registers_8bit.at(reg) <<= 1;
registers_8bit.at(reg) |= getFlag(FLAG_C);
}
...
};
And this somehow makes me think about two problems. I actually wanted to write implementation of opcode immediately when adding it to m_baseOpcodeMap, but to make it testable, I wrote implementation as a member function (here bitwiseRotationLeft as example) and I call it in lambda - and I'm not sure if this is correct approach.
Currently, to test some implementations, I've got something like this (using google test framework):
#include "cpu_lr35902.h"
#include <gtest/gtest.h>
class CPUTest : public ::testing::Test
{
protected:
CPU_LR35902 cpu_testable;
};
TEST_F(CPUTest, test_bitwiseRotationLeft)
{
cpu_testable.flags = 0;
cpu_testable.clearRegisters();
//0xA5 = 1010 0101, after: 0100 1011 = 0x4B
cpu_testable.registers_8bit.at(CPU_LR35902::REGISTER_A) = 0xA5;
cpu_testable.bitwiseRotationLeft(CPU_LR35902::REGISTER_A);
ASSERT_EQ(1, cpu_testable.getFlag(CPU_LR35902::FLAG_C));
ASSERT_EQ(0x4B, cpu_testable.registers_8bit.at(CPU_LR35902::REGISTER_A));
}
but to get access to private members of CPU_LR35902, I have to add
FRIEND_TEST(CPUTest, test_name);
in CPU_LR35902 class - after that I can reach private members of tested class in TEST_F, but I can't access them in CPUTest class (for SetUp / TearDown). Considering the fact, that I've got a little bit more of tests and I'm going to have a plenty of them, I think that adding FRIEND_TEST for every test makes everything somehow bad-looking. I'm in touch with C++ for some time, but I've got completely zero experience in using Google Test Framework and my intuition tells me that there must be a better way to do it. Any clues will be gladly appreciated :)