001 package sysModel.classFile.code;
002
003 import sysModel.classFile.code.instructions.*;
004 import junit.framework.TestCase;
005
006 import java.io.IOException;
007 import java.util.Arrays;
008
009 /**
010 * Unit tests for InstructionList class.
011 *
012 * @author Mathias Ricken
013 */
014 public class InstructionListTest extends TestCase {
015 protected final byte[] TEST_CODE = new byte[]{
016 Opcode.ALOAD_0, // 0
017 Opcode.IFEQ, 0, 0, // 1
018 Opcode.GOTO, 0, 0, // 4
019 Opcode.GOTO_W, 0, 0, 0, 0, // 7
020 Opcode.ALOAD, 0, // 12
021 Opcode.WIDE, Opcode.ALOAD, 0, 0, // 14
022 Opcode.IINC, 0, 0, // 18
023 Opcode.WIDE, Opcode.IINC, 0, 0, 0, 0, // 21
024 Opcode.TABLESWITCH, /*default*/(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf1, /*low*/0, 0, 0, 5, /*high*/0, 0, 0, 7,
025 /*5*/(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf3, /*6*/(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf7, /*7*/(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xfa, // 27
026 Opcode.LOOKUPSWITCH, /*pad*/ 0, 0, 0, /*default*/(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xe7, /*n*/0, 0, 0, 2, /*key*/0, 0, 0, 0,
027 /*offset*/0, 0, 0, 0, /*key*/ 0, 0, 0, 1, /*offset*/ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x1c, // 52
028 Opcode.RETURN // 80
029 };
030
031 protected final byte[] TEST_CODE2 = new byte[]{
032 Opcode.ALOAD_0,
033 Opcode.ALOAD_1,
034 Opcode.INVOKESTATIC, 0, 0,
035 Opcode.RETURN
036 };
037
038 protected final byte[] TEST_CODE_INVALID = new byte[]{
039 Opcode.ALOAD
040 };
041
042 protected final byte[] TEST_CODE_EMPTY = new byte[]{};
043
044 protected final byte[] TEST_CODE_INSERTDELETE = new byte[]{
045 Opcode.GOTO, (byte)0x00, (byte)0x0A, // 0
046 Opcode.GOTO, (byte)0x00, (byte)0x03, // 3
047 Opcode.NOP, // 6
048 Opcode.GOTO, (byte)0xFF, (byte)0xFC, // 7
049 Opcode.GOTO, (byte)0xFF, (byte)0xFD // 10
050 };
051
052 protected final byte[] TEST_CODE_DELETE_RESULT = new byte[]{
053 Opcode.GOTO, (byte)0x00, (byte)0x09, // 0
054 Opcode.GOTO, (byte)0x00, (byte)0x03, // 3
055 Opcode.GOTO, (byte)0xFF, (byte)0xFD, // 6
056 Opcode.GOTO, (byte)0xFF, (byte)0xFD // 9
057 };
058
059 protected final byte[] TEST_CODE_DELETE_RESULT2 = new byte[]{
060 Opcode.GOTO, (byte)0x00, (byte)0x06, // 0
061 Opcode.GOTO, (byte)0x00, (byte)0x03, // 3
062 Opcode.GOTO, (byte)0xFF, (byte)0xFD // 6
063 };
064
065 protected final byte[] TEST_CODE_INSERT_RESULT = new byte[]{
066 Opcode.GOTO, (byte)0x00, (byte)0x0B, // 0
067 Opcode.GOTO, (byte)0x00, (byte)0x03, // 3
068 Opcode.NOP, // 6
069 Opcode.NOP, // 7
070 Opcode.GOTO, (byte)0xFF, (byte)0xFB, // 8
071 Opcode.GOTO, (byte)0xFF, (byte)0xFD // 11
072 };
073
074 protected final byte[] TEST_CODE_INSERT_RESULT2 = new byte[]{
075 Opcode.GOTO, (byte)0x00, (byte)0x25, // 0
076 Opcode.GOTO, (byte)0x00, (byte)0x03, // 3
077 Opcode.TABLESWITCH, 0, /*default*/(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x1A, /*low*/ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x05,
078 /*high*/(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x07, /*5*/(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xfd,
079 /*6*/(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x1B, /*7*/(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x1F, // 6
080 Opcode.NOP, // 32
081 Opcode.NOP, // 33
082 Opcode.GOTO, (byte)0xFF, (byte)0xE1, // 34
083 Opcode.GOTO, (byte)0xFF, (byte)0xFD // 37
084 };
085
086 protected final byte[] TEST_CODE_INSERT_RESULT3 = new byte[]{
087 Opcode.GOTO, (byte)0x00, (byte)0x25, // 0
088 Opcode.GOTO, (byte)0x00, (byte)0x03, // 3
089 Opcode.NOP, // 6
090 Opcode.TABLESWITCH, /*default*/(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x19, /*low*/ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x05,
091 /*high*/(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x07, /*5*/(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xfc,
092 /*6*/(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x1A, /*7*/(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x1E, // 7
093 Opcode.NOP, // 32
094 Opcode.NOP, // 33
095 Opcode.GOTO, (byte)0xFF, (byte)0xE1, // 34
096 Opcode.GOTO, (byte)0xFF, (byte)0xFD // 37
097 };
098
099 public void testCtorAndGetCode() throws IOException {
100 InstructionList ilist = new InstructionList(TEST_CODE);
101
102 byte[] generatedCode = ilist.getCode();
103 assertTrue("Generated bytecode not the same", Arrays.equals(TEST_CODE, generatedCode));
104
105 ilist.setCode(TEST_CODE2);
106
107 generatedCode = ilist.getCode();
108 assertTrue("Generated bytecode not the same", Arrays.equals(TEST_CODE2, generatedCode));
109 }
110
111 public void testExceptions() {
112 try {
113 InstructionList ilist = new InstructionList(TEST_CODE_INVALID);
114 fail("Should have thrown IllegalArgumentException, invalid block length");
115 }
116 catch(IllegalArgumentException e) {
117 // passed
118 }
119 catch(Throwable t) {
120 fail("Should have thrown IllegalArgumentException, invalid block length");
121 }
122
123 InstructionList ilist = new InstructionList(TEST_CODE_EMPTY);
124 try {
125 ilist.setCode(TEST_CODE_INVALID);
126 fail("Should have thrown IllegalArgumentException, invalid block length");
127 }
128 catch(IllegalArgumentException e) {
129 // passed
130 }
131 catch(Throwable t) {
132 fail("Should have thrown IllegalArgumentException, invalid block length");
133 }
134
135 ilist = new InstructionList(TEST_CODE);
136 try {
137 ilist.setIndex(-1);
138 fail("Should have thrown IndexOutOfBoundsException, invalid index");
139 }
140 catch(IndexOutOfBoundsException e) {
141 // passed
142 }
143 catch(Throwable t) {
144 fail("Should have thrown IndexOutOfBoundsException, invalid block length");
145 }
146 try {
147 ilist.setIndex(11);
148 fail("Should have thrown IndexOutOfBoundsException, invalid index");
149 }
150 catch(IndexOutOfBoundsException e) {
151 // passed
152 }
153 catch(Throwable t) {
154 fail("Should have thrown IndexOutOfBoundsException, invalid block length");
155 }
156 }
157
158 public void testIndex() {
159 InstructionList ilist = new InstructionList(TEST_CODE);
160
161 assertEquals("Wrong index", 0, ilist.getIndex());
162 assertEquals("Wrong opcode", Opcode.ALOAD_0, ilist.getOpcode());
163 assertEquals("Wrong instruction", GenericInstruction.class, ilist.getInstr().getClass());
164 assertEquals("Problem in advanceIndex", true, ilist.advanceIndex());
165
166 assertEquals("Wrong index", 1, ilist.getIndex());
167 assertEquals("Wrong opcode", Opcode.IFEQ, ilist.getOpcode());
168 assertEquals("Wrong instruction", BranchInstruction.class, ilist.getInstr().getClass());
169 assertEquals("Problem in advanceIndex", true, ilist.advanceIndex());
170
171 assertEquals("Wrong index", 2, ilist.getIndex());
172 assertEquals("Wrong opcode", Opcode.GOTO, ilist.getOpcode());
173 assertEquals("Wrong instruction", BranchInstruction.class, ilist.getInstr().getClass());
174 assertEquals("Problem in advanceIndex", true, ilist.advanceIndex());
175
176 assertEquals("Wrong index", 3, ilist.getIndex());
177 assertEquals("Wrong opcode", Opcode.GOTO_W, ilist.getOpcode());
178 assertEquals("Wrong instruction", WideBranchInstruction.class, ilist.getInstr().getClass());
179 assertEquals("Problem in advanceIndex", true, ilist.advanceIndex());
180
181 assertEquals("Wrong index", 4, ilist.getIndex());
182 assertEquals("Wrong opcode", Opcode.ALOAD, ilist.getOpcode());
183 assertEquals("Wrong instruction", GenericInstruction.class, ilist.getInstr().getClass());
184 assertEquals("Problem in advanceIndex", true, ilist.advanceIndex());
185
186 assertEquals("Wrong index", 5, ilist.getIndex());
187 assertEquals("Wrong opcode", Opcode.WIDE, ilist.getOpcode());
188 assertEquals("Wrong instruction", WideInstruction.class, ilist.getInstr().getClass());
189 assertEquals("Problem in advanceIndex", true, ilist.advanceIndex());
190
191 assertEquals("Wrong index", 6, ilist.getIndex());
192 assertEquals("Wrong opcode", Opcode.IINC, ilist.getOpcode());
193 assertEquals("Wrong instruction", GenericInstruction.class, ilist.getInstr().getClass());
194 assertEquals("Problem in advanceIndex", true, ilist.advanceIndex());
195
196 assertEquals("Wrong index", 7, ilist.getIndex());
197 assertEquals("Wrong opcode", Opcode.WIDE, ilist.getOpcode());
198 assertEquals("Wrong instruction", WideInstruction.class, ilist.getInstr().getClass());
199 assertEquals("Problem in advanceIndex", true, ilist.advanceIndex());
200
201 assertEquals("Wrong index", 8, ilist.getIndex());
202 assertEquals("Wrong opcode", Opcode.TABLESWITCH, ilist.getOpcode());
203 assertEquals("Wrong instruction", TableSwitchInstruction.class, ilist.getInstr().getClass());
204 assertEquals("Problem in advanceIndex", true, ilist.advanceIndex());
205
206 assertEquals("Wrong index", 9, ilist.getIndex());
207 assertEquals("Wrong opcode", Opcode.LOOKUPSWITCH, ilist.getOpcode());
208 assertEquals("Wrong instruction", LookupSwitchInstruction.class, ilist.getInstr().getClass());
209 assertEquals("Problem in advanceIndex", true, ilist.advanceIndex());
210
211 assertEquals("Wrong index", 10, ilist.getIndex());
212 assertEquals("Wrong opcode", Opcode.RETURN, ilist.getOpcode());
213 assertEquals("Wrong instruction", GenericInstruction.class, ilist.getInstr().getClass());
214 assertEquals("Problem in advanceIndex", false, ilist.advanceIndex());
215 }
216
217 public void testFindOpcode() {
218 InstructionList ilist = new InstructionList(TEST_CODE);
219
220 assertEquals("Should have found ALOAD_0", true, ilist.findOpcode(Opcode.ALOAD_0));
221 assertEquals("Wrong index", 0, ilist.getIndex());
222
223 assertEquals("Should have found ALOAD", true, ilist.findOpcode(Opcode.ALOAD));
224 assertEquals("Wrong index", 4, ilist.getIndex());
225 ilist.advanceIndex();
226
227 assertEquals("Should have not have found ALOAD", false, ilist.findOpcode(Opcode.ALOAD));
228 assertEquals("Wrong index", 11, ilist.getIndex());
229 }
230
231 public void testFindInstr() {
232 InstructionList ilist = new InstructionList(TEST_CODE);
233 LineNumberTable lnt = new LineNumberTable(TEST_CODE);
234
235 assertEquals("Should have found ALOAD_0", true, ilist.findInstruction(
236 new GenericInstruction(TEST_CODE, (short)0, (short)0, lnt)));
237 assertEquals("Wrong index", 0, ilist.getIndex());
238
239 assertEquals("Should have found ALOAD", true, ilist.findInstruction(
240 new GenericInstruction(TEST_CODE, (short)12, (short)12, lnt)));
241 assertEquals("Wrong index", 4, ilist.getIndex());
242 ilist.advanceIndex();
243
244 assertEquals("Should have not found ALOAD", false, ilist.findInstruction(
245 new GenericInstruction(TEST_CODE, (short)12, (short)12, lnt)));
246 assertEquals("Wrong index", 11, ilist.getIndex());
247
248 ilist.setIndex(0);
249
250 assertEquals("Should have not found ALOAD", false, ilist.findInstruction(
251 new GenericInstruction(new byte[]{Opcode.ALOAD, 1}, (short)0, (short)12, lnt)));
252 assertEquals("Wrong index", 11, ilist.getIndex());
253 }
254
255 public void testDelete() {
256 InstructionList ilist = new InstructionList(TEST_CODE_INSERTDELETE);
257
258 ilist.setIndex(2);
259 assertEquals("Should not be at end yet", true, ilist.deleteInstr(null));
260 assertEquals("At wrong index", 2, ilist.getIndex());
261 assertEquals("Wrong result", new InstructionList(TEST_CODE_DELETE_RESULT), ilist);
262
263 ilist.setIndex(3);
264 assertEquals("Should be at end", false, ilist.deleteInstr(null));
265 assertEquals("At wrong index", 3, ilist.getIndex());
266 assertEquals("Wrong result", new InstructionList(TEST_CODE_DELETE_RESULT2), ilist);
267 }
268
269 public void testInsert() {
270 InstructionList ilist = new InstructionList(TEST_CODE_INSERTDELETE);
271
272 ilist.setIndex(2);
273 ilist.insertInstr(new GenericInstruction(new byte[]{Opcode.NOP}), null);
274 assertEquals("At wrong index", 2, ilist.getIndex());
275 assertEquals("Wrong result", new InstructionList(TEST_CODE_INSERT_RESULT), ilist);
276
277 ilist.insertInstr(new TableSwitchInstruction(2, 5, 7, new int[]{1, 3, 5}), null);
278 assertEquals("At wrong index", 2, ilist.getIndex());
279 assertEquals("Wrong result", new InstructionList(TEST_CODE_INSERT_RESULT2), ilist);
280
281 // this causes the TABLESWITCH instruction to repad
282 ilist.insertInstr(new GenericInstruction(new byte[]{Opcode.NOP}), null);
283 assertEquals("At wrong index", 2, ilist.getIndex());
284 assertEquals("Wrong result", new InstructionList(TEST_CODE_INSERT_RESULT3), ilist);
285 }
286 }