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    }