/testability-explorer/src/test/java/com/google/test/metric/method/BlockDecomposerTest.java

http://testability-explorer.googlecode.com/ · Java · 452 lines · 313 code · 53 blank · 86 comment · 0 complexity · d04ccbc5713cf5036cf872a781227710 MD5 · raw file

  1. /*
  2. * Copyright 2007 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.google.test.metric.method;
  17. import static com.google.test.metric.JavaType.VOID;
  18. import java.util.Arrays;
  19. import java.util.List;
  20. import junit.framework.TestCase;
  21. import org.objectweb.asm.Label;
  22. import com.google.test.metric.JavaClassRepository;
  23. import com.google.test.metric.JavaType;
  24. import com.google.test.metric.LocalVariableInfo;
  25. import com.google.test.metric.Variable;
  26. import com.google.test.metric.method.op.stack.JSR;
  27. import com.google.test.metric.method.op.stack.Load;
  28. import com.google.test.metric.method.op.stack.RetSub;
  29. import com.google.test.metric.method.op.stack.Return;
  30. import com.google.test.metric.method.op.stack.StackOperation;
  31. import com.google.test.metric.method.op.stack.Store;
  32. import com.google.test.metric.method.op.stack.Throw;
  33. import com.google.test.metric.method.op.turing.Operation;
  34. public class BlockDecomposerTest extends TestCase {
  35. public void testSimpleLinearMethod() throws Exception {
  36. BlockDecomposer decomposer = new BlockDecomposer();
  37. Return ret = new Return(0, VOID);
  38. decomposer.addOp(ret);
  39. decomposer.decomposeIntoBlocks();
  40. Block block = decomposer.getMainBlock();
  41. assertEquals(list(ret), block.getOperations());
  42. }
  43. public void testUnconditionalBackwardGoto() throws Exception {
  44. BlockDecomposer decomposer = new BlockDecomposer();
  45. Label label = new Label();
  46. Load l1 = load(1);
  47. Load l2 = load(2);
  48. decomposer.addOp(l1);
  49. decomposer.label(label);
  50. decomposer.addOp(l2);
  51. decomposer.unconditionalGoto(label);
  52. decomposer.decomposeIntoBlocks();
  53. Block main = decomposer.getMainBlock();
  54. assertEquals(list(l1), main.getOperations());
  55. assertEquals(1, main.getNextBlocks().size());
  56. Block next = main.getNextBlocks().get(0);
  57. assertEquals(list(l2), next.getOperations());
  58. }
  59. public void testUnconditionalForwardGoto() throws Exception {
  60. BlockDecomposer decomposer = new BlockDecomposer();
  61. Label label = new Label();
  62. Load l1 = load(1);
  63. Load l2 = load(2);
  64. decomposer.addOp(l1);
  65. decomposer.unconditionalGoto(label);
  66. decomposer.label(label);
  67. decomposer.addOp(l2);
  68. decomposer.decomposeIntoBlocks();
  69. Block main = decomposer.getMainBlock();
  70. assertEquals(list(l1), main.getOperations());
  71. assertEquals(1, main.getNextBlocks().size());
  72. Block next = main.getNextBlocks().get(0);
  73. assertEquals(list(l2), next.getOperations());
  74. }
  75. public void testConditionalBackwardGoto() throws Exception {
  76. BlockDecomposer decomposer = new BlockDecomposer();
  77. Label label = new Label();
  78. Load l1 = load(1);
  79. Load l2 = load(2);
  80. Load l3 = load(3);
  81. decomposer.addOp(l1);
  82. decomposer.label(label);
  83. decomposer.addOp(l2);
  84. decomposer.conditionalGoto(label);
  85. decomposer.addOp(l3);
  86. decomposer.decomposeIntoBlocks();
  87. Block main = decomposer.getMainBlock();
  88. Block nextTrue = decomposer.getBlock(label);
  89. Block nextFlase = nextTrue.getNextBlocks().get(0);
  90. assertEquals(list(l1), main.getOperations());
  91. assertEquals(list(l2), nextTrue.getOperations());
  92. assertEquals(list(l3), nextFlase.getOperations());
  93. }
  94. public void testConditionalForwardGoto() throws Exception {
  95. BlockDecomposer decomposer = new BlockDecomposer();
  96. Label label = new Label();
  97. Load l1 = load(1);
  98. Load l2 = load(2);
  99. Load l3 = load(3);
  100. decomposer.addOp(l1); // main
  101. decomposer.conditionalGoto(label);
  102. decomposer.addOp(l2); // nextFalse
  103. decomposer.label(label);
  104. decomposer.addOp(l3); // nextTrue
  105. decomposer.decomposeIntoBlocks();
  106. Block main = decomposer.getMainBlock();
  107. Block nextFlase = main.getNextBlocks().get(0);
  108. Block nextTrue = decomposer.getBlock(label);
  109. assertEquals(list(l1), main.getOperations());
  110. assertEquals(list(l2), nextFlase.getOperations());
  111. assertEquals(list(l3), nextTrue.getOperations());
  112. }
  113. private <T> List<T> list(T...items) {
  114. return Arrays.asList(items);
  115. }
  116. public void testIgnoreExtraLabels() throws Exception {
  117. BlockDecomposer decomposer = new BlockDecomposer();
  118. Load l1 = load(1);
  119. Load l2 = load(2);
  120. decomposer.label(new Label());
  121. decomposer.addOp(l1);
  122. decomposer.addOp(l2);
  123. decomposer.label(new Label());
  124. decomposer.decomposeIntoBlocks();
  125. assertEquals(list(l1, l2), decomposer.getMainBlock().getOperations());
  126. }
  127. /**
  128. * load 1
  129. * jsr mySub
  130. * load 2
  131. * return
  132. *
  133. * mySub:
  134. * load 3
  135. * return;
  136. */
  137. public void testJSR() throws Exception {
  138. BlockDecomposer decomposer = new BlockDecomposer();
  139. decomposer.addOp(load(1));
  140. Label sub = new Label();
  141. decomposer.jumpSubroutine(sub, 0);
  142. decomposer.addOp(load(2));
  143. decomposer.addOp(new Return(0, VOID));
  144. decomposer.label(sub);
  145. decomposer.addOp(load(3));
  146. decomposer.addOp(new RetSub(0));
  147. decomposer.decomposeIntoBlocks();
  148. Block mainBlock = decomposer.getMainBlock();
  149. assertEquals(0, mainBlock.getNextBlocks().size());
  150. List<StackOperation> operations = mainBlock.getOperations();
  151. assertEquals("[load 1{int}, JSR sub_0, load 2{int}, return void]",
  152. operations.toString());
  153. JSR jsr = (JSR) operations.get(1);
  154. Block subBlock = jsr.getBlock();
  155. assertEquals("[load 3{int}, RETSUB]", subBlock.getOperations().toString());
  156. }
  157. private Load load(int value) {
  158. return new Load(0, new Constant(value, JavaType.INT));
  159. }
  160. public void testSwitch() throws Exception {
  161. BlockDecomposer decomposer = new BlockDecomposer();
  162. Load l1 = load(1);
  163. Label c1Label = new Label();
  164. Load c1 = load(2);
  165. Label defLabel = new Label();
  166. Load def = load(3);
  167. decomposer.addOp(l1);
  168. decomposer.tableSwitch(defLabel, c1Label);
  169. decomposer.label(c1Label);
  170. decomposer.addOp(c1);
  171. decomposer.label(defLabel);
  172. decomposer.addOp(def);
  173. decomposer.decomposeIntoBlocks();
  174. Block main = decomposer.getMainBlock();
  175. Block c1Block = decomposer.getBlock(c1Label);
  176. Block defBlock = decomposer.getBlock(defLabel);
  177. assertEquals(list(l1), main.getOperations());
  178. assertEquals(list(c1), c1Block.getOperations());
  179. assertEquals(list(def), defBlock.getOperations());
  180. assertEquals(list(c1Block, defBlock), main.getNextBlocks());
  181. }
  182. public void testTryCatchReturn() throws Exception {
  183. /*
  184. * try { | label:lTry
  185. * return 1; | label:lTryEnd
  186. * } catch { | label:lHandle
  187. * return 2;
  188. * }
  189. */
  190. Label lTry = new Label();
  191. Load l1 = load(1);
  192. Load l2 = load(2);
  193. Return ret = new Return(1, JavaType.INT);
  194. Label lTryEnd = new Label();
  195. Label lHandle = new Label();
  196. BlockDecomposer decomposer = new BlockDecomposer();
  197. decomposer.tryCatchBlock(lTry, lTryEnd, lHandle, null);
  198. decomposer.label(lTry);
  199. decomposer.addOp(l1);
  200. decomposer.label(lTryEnd); // the catch label comes before the last instruction.
  201. decomposer.addOp(ret);
  202. decomposer.label(lHandle);
  203. decomposer.addOp(l2);
  204. decomposer.addOp(ret);
  205. decomposer.decomposeIntoBlocks();
  206. Block tryBlock = decomposer.getBlock(lTry);
  207. Block handleBlock = decomposer.getBlock(lHandle);
  208. assertEquals(list(), tryBlock.getNextBlocks());
  209. assertEquals(list(l1, ret), tryBlock.getOperations());
  210. assertEquals("[load ?{java.lang.Throwable}, load 2{int}, return int]",
  211. handleBlock.getOperations().toString());
  212. }
  213. public void testGetExceptionHandlerBlocks() throws Exception {
  214. /*
  215. * try { | label:lTry
  216. * a = 1;
  217. * return 1; | label:lTryEnd
  218. * } catch { | label:lHandle
  219. * a = 2;
  220. * return 2;
  221. * }
  222. */
  223. Label lTry = new Label();
  224. Load l1 = load(1);
  225. Load l2 = load(2);
  226. Store store = new Store(-1, new Variable("a", JavaType.INT, false, false));
  227. Return ret = new Return(1, JavaType.INT);
  228. Label lTryEnd = new Label();
  229. Label lHandle = new Label();
  230. BlockDecomposer decomposer = new BlockDecomposer();
  231. decomposer.tryCatchBlock(lTry, lTryEnd, lHandle, null);
  232. decomposer.label(lTry);
  233. decomposer.addOp(l1);
  234. decomposer.addOp(store);
  235. decomposer.label(lTryEnd); // the catch label comes before the last instruction.
  236. decomposer.addOp(l1);
  237. decomposer.addOp(ret);
  238. decomposer.label(lHandle);
  239. decomposer.addOp(l2);
  240. decomposer.addOp(store);
  241. decomposer.addOp(l2);
  242. decomposer.addOp(ret);
  243. decomposer.decomposeIntoBlocks();
  244. Block mainBlock = decomposer.getMainBlock();
  245. assertEquals(0, mainBlock.getNextBlocks().size());
  246. assertEquals(list(l1, store, l1, ret), mainBlock.getOperations());
  247. Block catchBlock = decomposer.getBlock(lHandle);
  248. assertEquals(0, catchBlock.getNextBlocks().size());
  249. assertEquals(
  250. "[load ?{java.lang.Throwable}, load 2{int}, store a{int}, load 2{int}, return int]",
  251. catchBlock.getOperations().toString());
  252. assertEquals(
  253. "[a{int} <- 1{int}, return 1{int}, a{int} <- 2{int}, return 2{int}]",
  254. decomposer.getOperations().toString());
  255. }
  256. /**
  257. * public static class TryCatchFinally {
  258. * public void method() {
  259. * int b = 1;
  260. * try {
  261. * b = 2;
  262. * return;
  263. * } catch (RuntimeException e) {
  264. * b = 3;
  265. * } finally {
  266. * b = 4;
  267. * }
  268. * b = 5;
  269. * }
  270. * }
  271. *
  272. *
  273. * public void method();
  274. * Code:
  275. * 0: iconst_1
  276. * 1: istore_1
  277. * 2: iconst_2
  278. * 3: istore_1
  279. * 4: goto 20
  280. * 7: astore_2
  281. * 8: iconst_3
  282. * 9: istore_1
  283. * 10: iconst_4
  284. * 11: istore_1
  285. * 12: goto 22
  286. * 15: astore_3
  287. * 16: iconst_4
  288. * 17: istore_1
  289. * 18: aload_3
  290. * 19: athrow
  291. * 20: iconst_4
  292. * 21: istore_1
  293. * 22: iconst_5
  294. * 23: istore_1
  295. * 24: return
  296. * Exception table:
  297. * from to target type
  298. * 2 4 7 Class java/lang/RuntimeException
  299. * 2 10 15 any
  300. */
  301. public void testTryCatchFinally() throws Exception {
  302. BlockDecomposer decomposer = new BlockDecomposer();
  303. Label tryStart = new Label();
  304. Label tryEnd = new Label();
  305. Label runtimeHandler = new Label();
  306. Label catchEnd = new Label();
  307. Label finallyHandler = new Label();
  308. Label l20 = new Label();
  309. Label l22 = new Label();
  310. Variable b = new LocalVariableInfo("b", JavaType.INT);
  311. Variable e = new LocalVariableInfo("e", JavaType.OBJECT);
  312. Variable any = new LocalVariableInfo("any", JavaType.OBJECT);
  313. decomposer.tryCatchBlock(tryStart, tryEnd, runtimeHandler, "java/lang/RuntimeException");
  314. decomposer.tryCatchBlock(tryStart, catchEnd, finallyHandler, null);
  315. /* 0*/ decomposer.addOp(new Load(0, new Constant(1, JavaType.INT)));
  316. /* 1*/ decomposer.addOp(new Store(1, b));
  317. decomposer.label(tryStart);
  318. /* 2*/ decomposer.addOp(new Load(2, new Constant(2, JavaType.INT)));
  319. decomposer.label(tryEnd);
  320. /* 3*/ decomposer.addOp(new Store(3, b));
  321. /* 4*/ decomposer.unconditionalGoto(l20);
  322. decomposer.label(runtimeHandler);
  323. /* 7*/ decomposer.addOp(new Store(7, e));
  324. /* 8*/ decomposer.addOp(new Load(8, new Constant(3, JavaType.INT)));
  325. /* 9*/ decomposer.addOp(new Store(9, b));
  326. decomposer.label(catchEnd);
  327. /*10*/ decomposer.addOp(new Load(10, new Constant(4, JavaType.INT)));
  328. /*11*/ decomposer.addOp(new Store(11, b));
  329. /*12*/ decomposer.unconditionalGoto(l22);
  330. decomposer.label(finallyHandler);
  331. /*15*/ decomposer.addOp(new Store(15, any));
  332. /*16*/ decomposer.addOp(new Load(16, new Constant(4, JavaType.INT)));
  333. /*17*/ decomposer.addOp(new Store(17, b));
  334. /*18*/ decomposer.addOp(new Load(18, any));
  335. /*19*/ decomposer.addOp(new Throw(19));
  336. decomposer.label(l20);
  337. /*20*/ decomposer.addOp(new Load(20, new Constant(4, JavaType.INT)));
  338. /*21*/ decomposer.addOp(new Store(21, b));
  339. decomposer.label(l22);
  340. /*22*/ decomposer.addOp(new Load(22, new Constant(4, JavaType.INT)));
  341. /*23*/ decomposer.addOp(new Store(23, b));
  342. /*24*/ decomposer.addOp(new Return(24, JavaType.VOID));
  343. decomposer.decomposeIntoBlocks();
  344. assertEquals("[load 1{int}, store b{int}, load 2{int}, store b{int}]",
  345. decomposer.getBlock(tryStart).getOperations().toString());
  346. }
  347. public void testMethodWithNothing() throws Exception {
  348. BlockDecomposer decomposer = new BlockDecomposer();
  349. decomposer.decomposeIntoBlocks();
  350. List<Operation> operations = decomposer.getOperations();
  351. assertEquals(0, operations.size());
  352. }
  353. public void testTwoJsrSameLabel() throws Exception {
  354. BlockDecomposer decomposer = new BlockDecomposer();
  355. Label label = new Label();
  356. decomposer.jumpSubroutine(label, 0);
  357. decomposer.jumpSubroutine(label, 0);
  358. decomposer.decomposeIntoBlocks();
  359. Block main = decomposer.getMainBlock();
  360. assertEquals("[JSR sub_0, JSR sub_0]", main.getOperations().toString());
  361. }
  362. public void testMultipleHandlersSingleExceptionLoad() throws Exception {
  363. BlockDecomposer decomposer = new BlockDecomposer();
  364. Label start = new Label();
  365. Label end = new Label();
  366. Label handler = new Label();
  367. decomposer.tryCatchBlock(start, end, handler, null);
  368. decomposer.tryCatchBlock(start, end, handler, null);
  369. decomposer.label(start);
  370. decomposer.addOp(load(1));
  371. decomposer.label(end);
  372. decomposer.addOp(load(2));
  373. decomposer.label(handler);
  374. decomposer.addOp(load(3));
  375. decomposer.decomposeIntoBlocks();
  376. assertEquals(
  377. "[load ?{java.lang.Throwable}, load 1{int}, load 2{int}, load 3{int}]",
  378. decomposer.getMainBlock().getOperations().toString());
  379. }
  380. public static class TestClass {
  381. int value;
  382. int method() {
  383. value = 0;
  384. try {
  385. value = 1;
  386. return -1;
  387. } catch (NullPointerException e) {
  388. value = 2;
  389. return -2;
  390. } finally {
  391. value = 3;
  392. }
  393. }
  394. }
  395. public void testExperiment() throws Exception {
  396. JavaClassRepository repo = new JavaClassRepository();
  397. repo.getClass(TestClass.class.getCanonicalName());
  398. }
  399. }