3
0
mirror of https://github.com/Qortal/AT.git synced 2025-01-31 03:12:14 +00:00
AT/Java/tests/SerializationTests.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

109 lines
3.2 KiB
Java

import static common.TestUtils.hexToBytes;
import static org.junit.Assert.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import org.ciyam.at.ExecutionException;
import org.ciyam.at.FunctionCode;
import org.ciyam.at.MachineState;
import org.ciyam.at.OpCode;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import common.TestAPI;
import common.TestLogger;
public class SerializationTests {
public TestLogger logger;
public TestAPI api;
public MachineState state;
public ByteBuffer codeByteBuffer;
@Before
public void beforeTest() {
logger = new TestLogger();
api = new TestAPI();
codeByteBuffer = ByteBuffer.allocate(256).order(ByteOrder.LITTLE_ENDIAN);
}
@After
public void afterTest() {
codeByteBuffer = null;
api = null;
logger = null;
}
private byte[] simulate() {
// version 0003, reserved 0000, code 0100 * 1, data 0020 * 8, call stack 0010 * 4, user stack 0010 * 4
byte[] headerBytes = hexToBytes("0300" + "0000" + "0001" + "2000" + "1000" + "1000");
byte[] codeBytes = codeByteBuffer.array();
byte[] dataBytes = new byte[0];
state = new MachineState(api, logger, headerBytes, codeBytes, dataBytes);
return executeAndCheck(state);
}
private byte[] continueSimulation(byte[] savedState) {
state = MachineState.fromBytes(api, logger, savedState);
// Pretend we're on next block
api.bumpCurrentBlockHeight();
return executeAndCheck(state);
}
private byte[] executeAndCheck(MachineState state) {
state.execute();
byte[] stateBytes = state.toBytes();
MachineState restoredState = MachineState.fromBytes(api, logger, stateBytes);
byte[] restoredStateBytes = restoredState.toBytes();
assertTrue("Serialization->Deserialization->Reserialization error", Arrays.equals(stateBytes, restoredStateBytes));
return stateBytes;
}
@Test
public void testPCS2() 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.FIN_IMD.value);
simulate();
assertEquals(0x0e, (int) state.getOnStopAddress());
assertTrue(state.getIsFinished());
assertFalse(state.getHadFatalError());
}
@Test
public void testStopWithStacks() throws ExecutionException {
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(0).putLong(100); // 0000
codeByteBuffer.put(OpCode.SET_PCS.value); // 000d
codeByteBuffer.put(OpCode.JMP_SUB.value).putInt(0x002a); // 000e
codeByteBuffer.put(OpCode.SET_VAL.value).putInt(1).putLong(10); // 0013
codeByteBuffer.put(OpCode.ADD_DAT.value).putInt(0).putInt(1); // 0020
codeByteBuffer.put(OpCode.STP_IMD.value); // 0029
codeByteBuffer.put(OpCode.EXT_FUN_DAT.value).putShort(FunctionCode.ECHO.value).putInt(0); // 002a
codeByteBuffer.put(OpCode.PSH_DAT.value).putInt(0); // 0031
codeByteBuffer.put(OpCode.RET_SUB.value); // 0036
byte[] savedState = simulate();
assertEquals(0x0e, (int) state.getOnStopAddress());
assertTrue(state.getIsStopped());
assertFalse(state.getHadFatalError());
savedState = continueSimulation(savedState);
savedState = continueSimulation(savedState);
}
}