package org.reasm.m68k.assembly.internal; import java.util.ArrayList; import java.util.List; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.reasm.AssemblyMessage; import org.reasm.commons.messages.StringTooLongErrorMessage; import org.reasm.commons.messages.ValueOutOfRangeErrorMessage; import org.reasm.m68k.M68KArchitecture; import org.reasm.m68k.messages.CountMustNotBeNegativeErrorMessage; import org.reasm.m68k.messages.InvalidCharacterInHexDirectiveErrorMessage; import org.reasm.m68k.messages.InvalidExpressionErrorMessage; import org.reasm.messages.OddNumberOfCharactersInHexDirectiveErrorMessage; import org.reasm.messages.OutOfMemoryErrorMessage; /** * Test class for directives whose main purpose is outputting data (e.g. <code>DC</code>). * * @author Francis Gagné */ @RunWith(Parameterized.class) public class OutputDirectivesTest extends BaseProgramsTest { @Nonnull private static final List<Object[]> TEST_DATA = new ArrayList<>(); static { // DC addDataItem(" DC", NO_DATA, WRONG_NUMBER_OF_OPERANDS); addDataItem(" DC ~", new byte[] { 0, 0 }, new InvalidExpressionErrorMessage("~")); addDataItem(" DC UNDEFINED", new byte[] { 0, 0 }, UNDEFINED_SYMBOL); addDataItem(" DC 0", new byte[] { 0, 0 }); addDataItem(" DC 0.0", new byte[] { 0, 0 }); addDataItem(" DC ''", new byte[] { 0, 0 }); addDataItem(" DC 'A'", new byte[] { 0, 0x41 }); addDataItem(" DC 'AB'", new byte[] { 0x41, 0x42 }); addDataItem(" DC 'ABC'", new byte[] { 0x41, 0x42 }, new StringTooLongErrorMessage("ABC")); // TODO: test with a built-in function symbol //addDataItem(" DC STRLEN", new byte[] { 0, 0 }, new FunctionCannotBeConvertedToRealErrorMessage()); addDataItem(" DC ,", new byte[] { 0, 0, 0, 0 }, new InvalidExpressionErrorMessage(""), new InvalidExpressionErrorMessage("")); addDataItem(" DC. 0", new byte[] { 0, 0 }, INVALID_SIZE_ATTRIBUTE_EMPTY); addDataItem(" DC.B 0", new byte[] { 0 }); addDataItem(" DC.B $FF", new byte[] { -1 }); addDataItem(" DC.B $100", new byte[] { 0 }, new ValueOutOfRangeErrorMessage(0x100)); addDataItem(" DC.B $FFFFFFFFFFFFFFFF", new byte[] { -1 }, new ValueOutOfRangeErrorMessage(-1)); addDataItem(" DC.B -$81", new byte[] { 0x7F }, new ValueOutOfRangeErrorMessage(-0x81)); addDataItem(" DC.B -$80", new byte[] { -0x80 }); addDataItem(" DC.B +$FF", new byte[] { -1 }); addDataItem(" DC.B +$100", new byte[] { 0 }, new ValueOutOfRangeErrorMessage(0x100)); addDataItem(" DC.B 'this string can be arbitrarily long'", new byte[] { 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x62, 0x65, 0x20, 0x61, 0x72, 0x62, 0x69, 0x74, 0x72, 0x61, 0x72, 0x69, 0x6C, 0x79, 0x20, 0x6C, 0x6F, 0x6E, 0x67 }); addDataItem(" DC.B 0, 1, 2, 3", new byte[] { 0, 1, 2, 3 }); addDataItem(" DC.B 'foo', 7", new byte[] { 0x66, 0x6F, 0x6F, 7 }); addDataItem(" DC.W 0", new byte[] { 0, 0 }); addDataItem(" DC.W $FF", new byte[] { 0, -1 }); addDataItem(" DC.W $FF00", new byte[] { -1, 0 }); addDataItem(" DC.W $FFFF", new byte[] { -1, -1 }); addDataItem(" DC.W $10000", new byte[] { 0, 0 }, new ValueOutOfRangeErrorMessage(0x10000)); addDataItem(" DC.W $FFFFFFFFFFFFFFFF", new byte[] { -1, -1 }, new ValueOutOfRangeErrorMessage(-1)); addDataItem(" DC.W -$8001", new byte[] { 0x7F, -1 }, new ValueOutOfRangeErrorMessage(-0x8001)); addDataItem(" DC.W -$8000", new byte[] { -0x80, 0 }); addDataItem(" DC.W +$FFFF", new byte[] { -1, -1 }); addDataItem(" DC.W +$10000", new byte[] { 0, 0 }, new ValueOutOfRangeErrorMessage(0x10000)); addDataItem(" DC.W 'AB'", new byte[] { 0x41, 0x42 }); addDataItem(" DC.W 0, 1, 2, 3", new byte[] { 0, 0, 0, 1, 0, 2, 0, 3 }); addDataItem(" DC.L 0", new byte[] { 0, 0, 0, 0 }); addDataItem(" DC.L $FF", new byte[] { 0, 0, 0, -1 }); addDataItem(" DC.L $FF00", new byte[] { 0, 0, -1, 0 }); addDataItem(" DC.L $FF0000", new byte[] { 0, -1, 0, 0 }); addDataItem(" DC.L $FF000000", new byte[] { -1, 0, 0, 0 }); addDataItem(" DC.L $FFFFFFFF", new byte[] { -1, -1, -1, -1 }); addDataItem(" DC.L $100000000", new byte[] { 0, 0, 0, 0 }, new ValueOutOfRangeErrorMessage(0x100000000L)); addDataItem(" DC.L $FFFFFFFFFFFFFFFF", new byte[] { -1, -1, -1, -1 }, new ValueOutOfRangeErrorMessage(-1)); addDataItem(" DC.L -$80000001", new byte[] { 0x7F, -1, -1, -1 }, new ValueOutOfRangeErrorMessage(-0x80000001L)); addDataItem(" DC.L -$80000000", new byte[] { -0x80, 0, 0, 0 }); addDataItem(" DC.L +$FFFFFFFF", new byte[] { -1, -1, -1, -1 }); addDataItem(" DC.L +$100000000", new byte[] { 0, 0, 0, 0 }, new ValueOutOfRangeErrorMessage(0x100000000L)); addDataItem(" DC.L 'ABCD'", new byte[] { 0x41, 0x42, 0x43, 0x44 }); addDataItem(" DC.L 0, 1, 2, 3", new byte[] { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3 }); addDataItem(" DC.Q 0", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DC.Q $FF", new byte[] { 0, 0, 0, 0, 0, 0, 0, -1 }); addDataItem(" DC.Q $FF00", new byte[] { 0, 0, 0, 0, 0, 0, -1, 0 }); addDataItem(" DC.Q $FF0000", new byte[] { 0, 0, 0, 0, 0, -1, 0, 0 }); addDataItem(" DC.Q $FF000000", new byte[] { 0, 0, 0, 0, -1, 0, 0, 0 }); addDataItem(" DC.Q $FF00000000", new byte[] { 0, 0, 0, -1, 0, 0, 0, 0 }); addDataItem(" DC.Q $FF0000000000", new byte[] { 0, 0, -1, 0, 0, 0, 0, 0 }); addDataItem(" DC.Q $FF000000000000", new byte[] { 0, -1, 0, 0, 0, 0, 0, 0 }); addDataItem(" DC.Q $FF00000000000000", new byte[] { -1, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DC.Q $FFFFFFFFFFFFFFFF", new byte[] { -1, -1, -1, -1, -1, -1, -1, -1 }); addDataItem(" DC.Q -$8000000000000001", new byte[] { 0x7F, -1, -1, -1, -1, -1, -1, -1 }); addDataItem(" DC.Q -$8000000000000000", new byte[] { -0x80, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DC.Q +$7FFFFFFFFFFFFFFF", new byte[] { 0x7F, -1, -1, -1, -1, -1, -1, -1 }); addDataItem(" DC.Q +$8000000000000000", new byte[] { -0x80, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DC.Q 'ABCDEFGH'", new byte[] { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 }); addDataItem(" DC.Q 0, 1, 2, 3", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3 }); addDataItem(" DC.S UNDEFINED", new byte[] { 0, 0, 0, 0 }, UNDEFINED_SYMBOL); addDataItem(" DC.S 0", new byte[] { 0, 0, 0, 0 }); addDataItem(" DC.S $F000000000000000", new byte[] { 0x5F, 0x70, 0x00, 0x00 }); addDataItem(" DC.S -$1000000000000000", new byte[] { (byte) 0xDD, (byte) 0x80, 0x00, 0x00 }); addDataItem(" DC.S 0.0", new byte[] { 0, 0, 0, 0 }); addDataItem(" DC.S 0.03125", new byte[] { 0x3D, 0x00, 0x00, 0x00 }); addDataItem(" DC.S '0.03125'", new byte[] { 0x3D, 0x00, 0x00, 0x00 }); // TODO: test with a built-in function symbol //addDataItem(" DC.S STRLEN", new byte[] { 0, 0, 0, 0 }, new FunctionCannotBeConvertedToRealErrorMessage()); addDataItem(" DC.S 0, 1, 2, 3", new byte[] { 0, 0, 0, 0, 0x3F, (byte) 0x80, 0, 0, 0x40, 0, 0, 0, 0x40, 0x40, 0, 0 }); addDataItem(" DC.D 0", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DC.D $F000000000000000", new byte[] { 0x43, (byte) 0xEE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); addDataItem(" DC.D -$1000000000000000", new byte[] { (byte) 0xC3, (byte) 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); addDataItem(" DC.D 0.03125", new byte[] { 0x3F, (byte) 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); addDataItem(" DC.D '0.03125'", new byte[] { 0x3F, (byte) 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); // TODO: test with a built-in function symbol //addDataItem(" DC.D STRLEN", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, new FunctionCannotBeConvertedToRealErrorMessage()); addDataItem(" DC.D 0, 1, 2, 3", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0x3F, (byte) 0xF0, 0, 0, 0, 0, 0, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0x40, 8, 0, 0, 0, 0, 0, 0 }); // TODO: implement DC.X //addDataItem(" DC.X 0", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); // TODO: implement DC.P //addDataItem(" DC.P 0", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DC.Z 0", new byte[] { 0, 0 }, INVALID_SIZE_ATTRIBUTE_Z); // DCB addDataItem(" DCB", NO_DATA, WRONG_NUMBER_OF_OPERANDS); addDataItem(" DCB 4", NO_DATA, WRONG_NUMBER_OF_OPERANDS); addDataItem(" DCB 4, ~", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, new InvalidExpressionErrorMessage("~")); addDataItem(" DCB 4, UNDEFINED", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, UNDEFINED_SYMBOL); addDataItem(" DCB 4, 0", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DCB 4, $137F", new byte[] { 0x13, 0x7F, 0x13, 0x7F, 0x13, 0x7F, 0x13, 0x7F }); addDataItem(" DCB 4, $9137F", new byte[] { 0x13, 0x7F, 0x13, 0x7F, 0x13, 0x7F, 0x13, 0x7F }, new ValueOutOfRangeErrorMessage(0x9137F)); addDataItem(" DCB 4, 'AB'", new byte[] { 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42 }); addDataItem(" DCB 0, 0", NO_DATA); addDataItem(" DCB -4, 0", NO_DATA, new CountMustNotBeNegativeErrorMessage()); addDataItem(" DCB +4, 0", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DCB 4.2, 0", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DCB '4.2', 0", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); // TODO: test with a built-in function symbol //addDataItem(" DCB STRLEN, 0", NO_DATA, new FunctionCannotBeConvertedToRealErrorMessage()); addDataItem(" DCB ~, 0", NO_DATA, new InvalidExpressionErrorMessage("~")); addDataItem(" DCB UNDEFINED, 0", NO_DATA, UNDEFINED_SYMBOL); addDataItem(" DCB 2, 4, 6", new byte[] { 0, 4, 0, 4 }, WRONG_NUMBER_OF_OPERANDS); addDataItem(" DCB. 4, $137F", new byte[] { 0x13, 0x7F, 0x13, 0x7F, 0x13, 0x7F, 0x13, 0x7F }, INVALID_SIZE_ATTRIBUTE_EMPTY); addDataItem(" DCB.B 4, $13", new byte[] { 0x13, 0x13, 0x13, 0x13 }); addDataItem(" DCB.W 4, $137F", new byte[] { 0x13, 0x7F, 0x13, 0x7F, 0x13, 0x7F, 0x13, 0x7F }); addDataItem(" DCB.L 4, $137F0248", new byte[] { 0x13, 0x7F, 0x02, 0x48, 0x13, 0x7F, 0x02, 0x48, 0x13, 0x7F, 0x02, 0x48, 0x13, 0x7F, 0x02, 0x48 }); addDataItem(" DCB.Q 4, $18293A4B5C6D7E0F", new byte[] { 0x18, 0x29, 0x3A, 0x4B, 0x5C, 0x6D, 0x7E, 0x0F, 0x18, 0x29, 0x3A, 0x4B, 0x5C, 0x6D, 0x7E, 0x0F, 0x18, 0x29, 0x3A, 0x4B, 0x5C, 0x6D, 0x7E, 0x0F, 0x18, 0x29, 0x3A, 0x4B, 0x5C, 0x6D, 0x7E, 0x0F }); addDataItem(" DCB.S 4, 0.03125", new byte[] { 0x3D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00 }); addDataItem(" DCB.D 4, 0.03125", new byte[] { 0x3F, (byte) 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, (byte) 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, (byte) 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, (byte) 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); // TODO: implement DCB.X //addDataItem(" DCB.X 4, 0", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0, 0, 0, 0 }); // TODO: implement DCB.P //addDataItem(" DCB.P 4, 0", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0, 0, 0, 0 }); addDataItem(" DCB.Z 4, $137F", new byte[] { 0x13, 0x7F, 0x13, 0x7F, 0x13, 0x7F, 0x13, 0x7F }, INVALID_SIZE_ATTRIBUTE_Z); // DS addDataItem(" DS", NO_DATA, WRONG_NUMBER_OF_OPERANDS); addDataItem(" DS 0", NO_DATA); addDataItem(" DS 1", new byte[] { 0, 0 }); addDataItem(" DS 13", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DS $8000000000000000", NO_DATA, new OutOfMemoryErrorMessage()); addDataItem(" DS -1", NO_DATA, new CountMustNotBeNegativeErrorMessage()); addDataItem(" DS ~", NO_DATA, new InvalidExpressionErrorMessage("~")); addDataItem(" DS 0, 0", NO_DATA, WRONG_NUMBER_OF_OPERANDS); addDataItem(" DS. 1", new byte[] { 0, 0 }, INVALID_SIZE_ATTRIBUTE_EMPTY); addDataItem(" DS.B 1", new byte[] { 0 }); addDataItem(" DS.W 1", new byte[] { 0, 0 }); addDataItem(" DS.L 1", new byte[] { 0, 0, 0, 0 }); addDataItem(" DS.Q 1", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DS.S 1", new byte[] { 0, 0, 0, 0 }); addDataItem(" DS.D 1", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DS.X 1", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DS.P 1", new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); addDataItem(" DS.Z 1", new byte[] { 0, 0 }, INVALID_SIZE_ATTRIBUTE_Z); // HEX final AssemblyMessage oddNumberOfCharactersInHexDirective = new OddNumberOfCharactersInHexDirectiveErrorMessage(); final AssemblyMessage invalidCharacterInHexDirectiveExclamationMark = new InvalidCharacterInHexDirectiveErrorMessage('!'); final AssemblyMessage invalidCharacterInHexDirectiveG = new InvalidCharacterInHexDirectiveErrorMessage('G'); addDataItem(" HEX", NO_DATA); addDataItem(" HEX !", NO_DATA, invalidCharacterInHexDirectiveExclamationMark); addDataItem(" HEX 0", NO_DATA, oddNumberOfCharactersInHexDirective); addDataItem(" HEX G", NO_DATA, invalidCharacterInHexDirectiveG); addDataItem(" HEX 0!", NO_DATA, invalidCharacterInHexDirectiveExclamationMark); addDataItem(" HEX 00", new byte[] { 0x00 }); addDataItem(" HEX 123G45,67", new byte[] { 0x12, 0x67 }, invalidCharacterInHexDirectiveG); addDataItem(" HEX 11", new byte[] { 0x11 }); addDataItem(" HEX 1 1", new byte[] { 0x11 }); addDataItem(" HEX FF", new byte[] { (byte) 0xFF }); addDataItem(" HEX F\tF", new byte[] { (byte) 0xFF }); addDataItem(" HEX 1122", new byte[] { 0x11, 0x22 }); addDataItem(" HEX 11 22", new byte[] { 0x11, 0x22 }); addDataItem(" HEX 11 22", new byte[] { 0x11, 0x22 }); addDataItem(" HEX 11 \t 22", new byte[] { 0x11, 0x22 }); addDataItem(" HEX 1,2", NO_DATA, oddNumberOfCharactersInHexDirective, oddNumberOfCharactersInHexDirective); addDataItem(" HEX 11,22", new byte[] { 0x11, 0x22 }); addDataItem(" HEX 01234567,89ABCDEF,fedcba", new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF, (byte) 0xFE, (byte) 0xDC, (byte) 0xBA }); addDataItem(" HEX.B", NO_DATA, SIZE_ATTRIBUTE_NOT_ALLOWED); } /** * Gets the test data for this parameterized test. * * @return the test data */ @Nonnull @Parameters public static List<Object[]> data() { return TEST_DATA; } private static void addDataItem(@Nonnull String code, @Nonnull byte[] output) { addDataItem(code, output, (AssemblyMessage) null); } private static void addDataItem(@Nonnull String code, @Nonnull byte[] output, @CheckForNull AssemblyMessage expectedMessage) { TEST_DATA.add(new Object[] { code, output, expectedMessage, null }); } private static void addDataItem(@Nonnull String code, @Nonnull byte[] output, @CheckForNull AssemblyMessage... expectedMessages) { TEST_DATA.add(new Object[] { code, output, null, expectedMessages }); } /** * Initializes a new OutputDirectivesTest. * * @param code * a line of code containing a directive * @param output * the generated output for the instruction * @param expectedMessage * an {@link AssemblyMessage} that is expected to be generated while assembling the line of code, or * <code>null</code> if no message is expected * @param expectedMessages * an array of {@link AssemblyMessage AssemblyMessages} that are expected to be generated while assembling the code. * Takes priority over <code>expectedMessage</code>. */ public OutputDirectivesTest(@Nonnull String code, @Nonnull byte[] output, @CheckForNull AssemblyMessage expectedMessage, @CheckForNull AssemblyMessage[] expectedMessages) { super(code, 2, output, M68KArchitecture.MC68000, expectedMessage, expectedMessages, null); } }