mirror of
https://github.com/edmccard/twoapple-reboot.git
synced 2024-11-10 11:04:39 +00:00
Begin documentation of test framework.
This commit is contained in:
parent
a4af7191be
commit
581fe45c89
173
test/base.d
173
test/base.d
@ -18,6 +18,115 @@ else
|
||||
enum cumulative = false;
|
||||
|
||||
|
||||
/*
|
||||
* A test is a combination of setups, an expectation, a runner, and a
|
||||
* reporter.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A setup function for a given opcode puts cpu, data, info, and msg
|
||||
* into the appropriate state and then calls the next function (see
|
||||
* testCallNext) with the modified values. To setup multiple
|
||||
* scenarios, just call the next function multiple times.
|
||||
*
|
||||
* Values for cpu registers are set up using the setXXX(cpu, val)
|
||||
* functions; see testCallNext and OpInfo for descriptions of other
|
||||
* types of information that may need to be set up.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* // prepare the accumulator with a value different from expected
|
||||
* setA(cpu, ~0x10);
|
||||
* // prepare memory with LDA #$10 at address $1000
|
||||
* setPC(cpu, 0x1000);
|
||||
* callNext("LDA immediate, positive", [Block(0x1000, [0xA9, 0x10])]);
|
||||
*/
|
||||
alias void delegate(ubyte opcode, CpuInfo cpu, Block[] data, OpInfo info,
|
||||
string msg, TestSetup* next)
|
||||
testsetup;
|
||||
|
||||
|
||||
/*
|
||||
* A mixin that simplifies calling the next setup function.
|
||||
*
|
||||
* newMsg will be appended to the current msg and passed to the next
|
||||
* function.
|
||||
*
|
||||
* To place values in memory, pass an array of Blocks as the second
|
||||
* parameter. It will be appended to the current data.
|
||||
*/
|
||||
template testCallNext()
|
||||
{
|
||||
void callNext(string newMsg = "", Block[] newData = [])
|
||||
{
|
||||
if (*next !is null)
|
||||
next.run(opcode, cpu, data ~ newData, info, msg ~ newMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A block of memory with a given base address.
|
||||
*
|
||||
* For example, `Block(0x1000, [0xA9, 0x10])`
|
||||
*/
|
||||
struct Block
|
||||
{
|
||||
const ushort base;
|
||||
const(ubyte[]) data;
|
||||
|
||||
string toString() const
|
||||
{
|
||||
return format("Block(%0.4X, [%s])", base, formatMemory(data));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Information about expected opcode execution.
|
||||
struct OpInfo
|
||||
{
|
||||
// The effective address, if any.
|
||||
ushort addr;
|
||||
// The data to be read or written, if any.
|
||||
ubyte data;
|
||||
// The length of the opcode + operands.
|
||||
int len;
|
||||
}
|
||||
|
||||
|
||||
class TestSetup
|
||||
{
|
||||
testsetup setup;
|
||||
TestSetup next;
|
||||
|
||||
auto static opCall(testsetup d)
|
||||
{
|
||||
auto obj = new TestSetup();
|
||||
obj.setup = d;
|
||||
return obj;
|
||||
}
|
||||
|
||||
void run(ubyte opcode, CpuInfo cpu = CpuInfo(), Block[] data = [],
|
||||
OpInfo info = OpInfo(), string msg = "")
|
||||
{
|
||||
setup(opcode, cpu, data, info, msg, &next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
TestSetup connect(TestSetup first, TestSetup[] rest...)
|
||||
{
|
||||
if (!(rest.empty))
|
||||
{
|
||||
auto x = first;
|
||||
while (x.next !is null) x = x.next;
|
||||
x.next = connect(rest[0], rest[1..$]);
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Emulates zero page, stack, and 3 additional pages of "main memory"
|
||||
* starting at a user-defined address. Accesses outside the defined
|
||||
@ -115,19 +224,6 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// A block of memory with a given base address.
|
||||
struct Block
|
||||
{
|
||||
const ushort base;
|
||||
const(ubyte[]) data;
|
||||
|
||||
string toString() const
|
||||
{
|
||||
return format("Block(%0.4X, [%s])", base, formatMemory(data));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Formats data as a string of 2-digit hex bytes, separated by spaces.
|
||||
*
|
||||
@ -145,57 +241,6 @@ string formatMemory(const(ubyte[]) data, size_t max = 3)
|
||||
}
|
||||
|
||||
|
||||
struct OpInfo
|
||||
{
|
||||
ushort addr;
|
||||
ubyte data;
|
||||
int len;
|
||||
bool write;
|
||||
}
|
||||
|
||||
alias void delegate(ubyte, CpuInfo, Block[], OpInfo, string, TestSetup*)
|
||||
testsetup;
|
||||
|
||||
class TestSetup
|
||||
{
|
||||
testsetup setup;
|
||||
TestSetup next;
|
||||
|
||||
auto static opCall(testsetup d)
|
||||
{
|
||||
auto obj = new TestSetup();
|
||||
obj.setup = d;
|
||||
return obj;
|
||||
}
|
||||
|
||||
void run(ubyte opcode, CpuInfo cpu = CpuInfo(), Block[] data = [],
|
||||
OpInfo info = OpInfo(), string msg = "")
|
||||
{
|
||||
setup(opcode, cpu, data, info, msg, &next);
|
||||
}
|
||||
}
|
||||
|
||||
TestSetup connect(TestSetup first, TestSetup[] rest...)
|
||||
{
|
||||
if (!(rest.empty))
|
||||
{
|
||||
auto x = first;
|
||||
while (x.next !is null) x = x.next;
|
||||
x.next = connect(rest[0], rest[1..$]);
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
template testCallNext()
|
||||
{
|
||||
void callNext(string newMsg = "", Block[] newData = [])
|
||||
{
|
||||
if (*next !is null)
|
||||
next.run(opcode, cpu, data ~ newData, info, msg ~ newMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Does nothing.
|
||||
auto setup_none()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user