3
0
mirror of https://github.com/Qortal/AT.git synced 2025-02-14 19:25:51 +00:00
AT/Java/tests/OpCodeTests.java
catbref 454d4bed35 OpCode refactoring, versioned constants, refactored tests
API is now an abstract class instead of an Interface. This is to
allow protected methods that give access to package-scoped methods
and variables inside MachineState.

MachineState now supports a different set of constants based on AT
version.

MachineState's methods and variables have had their scopes tightened
up and getters/setters added where appropriate.

MachineState.parseHeader() inlined into the constructor that calls it
so it can set public final variables.

Some reordering and additional comments in MachineState.

OpCode enum entries refactored so that:
a) variables provided via MachineState "state" are not explicitly
passed as well

b) args to each opcode are pre-fetched from the codeByteBuffer before
calling and only need to be cast before use. this comes almost
"for free" thanks to OpCodeParam.fetch

Calling functions from OpCode now cleaner as there's no write-access
to programCounter, only changing codeByteBuffer's position.

Also in OpCode, state.getProgramCounter() now provides a consistent
before-opcode position for branches, jumps, etc.

Lots of repeated code refactored out of unit tests into ExecutableTest
class. ExecutableTest also provides helper methods for examining
post-execution data values, stack positions and entries.
2018-10-05 15:56:32 +01:00

218 lines
6.4 KiB
Java

import static common.TestUtils.hexToBytes;
import static org.junit.Assert.*;
import org.ciyam.at.ExecutionException;
import org.ciyam.at.OpCode;
import org.junit.Test;
import common.ExecutableTest;
public class OpCodeTests extends ExecutableTest {
@Test
public void testNOP() throws ExecutionException {
codeByteBuffer.put(OpCode.NOP.value);
codeByteBuffer.put(OpCode.FIN_IMD.value);
execute(true);
assertTrue(state.getIsFinished());
assertFalse(state.getHadFatalError());
// Check data unchanged
for (int i = 0; i < 0x0020; ++i)
assertEquals(0L, getData(i));
}
@Test
public void testJMP_ADR() throws ExecutionException {
int targetAddr = 0x12;
codeByteBuffer.put(OpCode.JMP_ADR.value).putInt(targetAddr);
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(1L);
// targetAddr:
assertEquals(targetAddr, codeByteBuffer.position());
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(2L);
codeByteBuffer.put(OpCode.FIN_IMD.value);
execute(true);
assertTrue(state.getIsFinished());
assertFalse(state.getHadFatalError());
assertEquals("Data does not match", 2L, getData(0));
}
@Test
public void testSLP_DAT() throws ExecutionException {
int blockHeight = 12345;
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(blockHeight);
codeByteBuffer.put(OpCode.SLP_DAT.value).putInt(0);
codeByteBuffer.put(OpCode.FIN_IMD.value);
execute(true);
assertTrue(state.getIsSleeping());
assertFalse(state.getIsFinished());
assertFalse(state.getHadFatalError());
assertEquals("Sleep-until block height incorrect", blockHeight, getData(0));
}
@Test
public void testFIZ_DATtrue() throws ExecutionException {
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(0L);
codeByteBuffer.put(OpCode.FIZ_DAT.value).putInt(0);
codeByteBuffer.put(OpCode.SLP_IMD.value);
execute(true);
assertTrue(state.getIsFinished());
assertFalse(state.getIsSleeping());
assertFalse(state.getHadFatalError());
}
@Test
public void testFIZ_DATfalse() throws ExecutionException {
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(1111L);
codeByteBuffer.put(OpCode.FIZ_DAT.value).putInt(0);
codeByteBuffer.put(OpCode.SLP_IMD.value);
execute(true);
assertFalse(state.getIsFinished());
assertTrue(state.getIsSleeping());
assertFalse(state.getHadFatalError());
}
@Test
public void testSTZ_DATtrue() throws ExecutionException {
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(0L);
codeByteBuffer.put(OpCode.SET_PCS.value);
int stopAddress = codeByteBuffer.position();
codeByteBuffer.put(OpCode.STZ_DAT.value).putInt(0);
codeByteBuffer.put(OpCode.FIN_IMD.value);
execute(true);
assertTrue(state.getIsStopped());
assertFalse(state.getIsFinished());
assertFalse(state.getHadFatalError());
assertEquals("Program counter incorrect", stopAddress, state.getProgramCounter());
}
@Test
public void testSTZ_DATfalse() throws ExecutionException {
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(1111L);
codeByteBuffer.put(OpCode.SET_PCS.value);
codeByteBuffer.put(OpCode.STZ_DAT.value).putInt(0);
codeByteBuffer.put(OpCode.FIN_IMD.value);
execute(true);
assertFalse(state.getIsStopped());
assertTrue(state.getIsFinished());
assertFalse(state.getHadFatalError());
}
@Test
public void testFIN_IMD() throws ExecutionException {
codeByteBuffer.put(OpCode.FIN_IMD.value);
codeByteBuffer.put(OpCode.STP_IMD.value);
execute(true);
assertTrue(state.getIsFinished());
assertFalse(state.getIsStopped());
assertFalse(state.getHadFatalError());
}
@Test
public void testSTP_IMD() throws ExecutionException {
codeByteBuffer.put(OpCode.SET_PCS.value);
int stopAddress = codeByteBuffer.position();
codeByteBuffer.put(OpCode.NOP.value);
codeByteBuffer.put(OpCode.STP_IMD.value);
codeByteBuffer.put(OpCode.FIN_IMD.value);
execute(true);
assertTrue(state.getIsStopped());
assertFalse(state.getIsFinished());
assertFalse(state.getHadFatalError());
assertEquals("Program counter incorrect", stopAddress, state.getProgramCounter());
}
@Test
public void testSLP_IMD() throws ExecutionException {
codeByteBuffer.put(OpCode.SLP_IMD.value);
int nextAddress = codeByteBuffer.position();
codeByteBuffer.put(OpCode.FIN_IMD.value);
execute(true);
assertTrue(state.getIsSleeping());
assertFalse(state.getIsFinished());
assertFalse(state.getHadFatalError());
assertEquals("Program counter incorrect", nextAddress, state.getProgramCounter());
}
@Test
public void testERR_ADR() throws ExecutionException {
// Note: non-fatal error because error handler IS set
int errorAddr = 0x29;
codeByteBuffer.put(OpCode.ERR_ADR.value).putInt(errorAddr);
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(12345L);
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(1).putLong(0L);
codeByteBuffer.put(OpCode.DIV_DAT.value).putInt(0).putInt(1); // divide by zero
codeByteBuffer.put(OpCode.FIN_IMD.value);
// errorAddr:
assertEquals(errorAddr, codeByteBuffer.position());
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(2).putLong(1L);
codeByteBuffer.put(OpCode.FIN_IMD.value);
execute(true);
assertTrue(state.getIsFinished());
assertFalse(state.getHadFatalError());
assertEquals("Error flag not set", 1L, getData(2));
}
@Test
public void testPCS() throws ExecutionException {
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).put(hexToBytes("0000000011111111"));
codeByteBuffer.put(OpCode.SET_PCS.value);
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).put(hexToBytes("0000000022222222"));
codeByteBuffer.put(OpCode.SET_PCS.value);
codeByteBuffer.put(OpCode.SET_PCS.value);
int expectedStopAddress = codeByteBuffer.position();
codeByteBuffer.put(OpCode.FIN_IMD.value);
execute(true);
assertEquals(expectedStopAddress, state.getOnStopAddress());
assertTrue(state.getIsFinished());
assertFalse(state.getHadFatalError());
}
@Test
public void testPCS2() throws ExecutionException {
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).put(hexToBytes("0000000011111111"));
codeByteBuffer.put(OpCode.SET_PCS.value);
int expectedStopAddress = codeByteBuffer.position();
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).put(hexToBytes("0000000022222222"));
codeByteBuffer.put(OpCode.FIN_IMD.value);
execute(true);
assertEquals(expectedStopAddress, state.getOnStopAddress());
assertTrue(state.getIsFinished());
assertFalse(state.getHadFatalError());
}
}