1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 package lockedregioncodeinjection;
15 
16 import org.junit.Assert;
17 import org.junit.Test;
18 
19 /**
20  * To run the unit tests:
21  *
22  * <pre>
23  * <code>
24  * set -x
25  *
26  * croot frameworks/base/tools/locked_region_code_injection
27  *
28  * # Clean
29  * mkdir -p out
30  * rm -fr out/*
31  *
32  * # Make booster
33  * javac -cp lib/asm-6.0_BETA.jar:lib/asm-commons-6.0_BETA.jar:lib/asm-tree-6.0_BETA.jar:lib/asm-analysis-6.0_BETA.jar:lib/guava-21.0.jar src&#47;*&#47;*.java -d out/
34  * pushd out
35  * jar cfe lockedregioncodeinjection.jar lockedregioncodeinjection.Main *&#47;*.class
36  * popd
37  *
38  * # Make unit tests.
39  * javac -cp lib/junit-4.12.jar test&#47;*&#47;*.java -d out/
40  *
41  * pushd out
42  * jar cfe test_input.jar lockedregioncodeinjection.Test *&#47;*.class
43  * popd
44  *
45  * # Run tool on unit tests.
46  * java -ea -cp lib/asm-6.0_BETA.jar:lib/asm-commons-6.0_BETA.jar:lib/asm-tree-6.0_BETA.jar:lib/asm-analysis-6.0_BETA.jar:lib/guava-21.0.jar:out/lockedregioncodeinjection.jar \
47  *     lockedregioncodeinjection.Main \
48  *     -i out/test_input.jar -o out/test_output.jar \
49  *     --targets 'Llockedregioncodeinjection/TestTarget;' \
50  *     --pre     'lockedregioncodeinjection/TestTarget.boost' \
51  *     --post    'lockedregioncodeinjection/TestTarget.unboost'
52  *
53  * # Run unit tests.
54  * java -ea -cp lib/hamcrest-core-1.3.jar:lib/junit-4.12.jar:out/test_output.jar \
55  *     org.junit.runner.JUnitCore lockedregioncodeinjection.TestMain
56  * </code>
57  * </pre>
58  */
59 public class TestMain {
60     @Test
testSimpleSynchronizedBlock()61     public void testSimpleSynchronizedBlock() {
62         TestTarget.resetCount();
63         TestTarget t = new TestTarget();
64 
65         Assert.assertEquals(TestTarget.boostCount, 0);
66         Assert.assertEquals(TestTarget.unboostCount, 0);
67         Assert.assertEquals(TestTarget.unboostCount, 0);
68 
69         synchronized (t) {
70             Assert.assertEquals(TestTarget.boostCount, 1);
71             Assert.assertEquals(TestTarget.unboostCount, 0);
72             TestTarget.invoke();
73         }
74 
75         Assert.assertEquals(TestTarget.boostCount, 1);
76         Assert.assertEquals(TestTarget.unboostCount, 1);
77         Assert.assertEquals(TestTarget.invokeCount, 1);
78     }
79 
80     @Test
testSimpleSynchronizedMethod()81     public void testSimpleSynchronizedMethod() {
82         TestTarget.resetCount();
83         TestTarget t = new TestTarget();
84 
85         Assert.assertEquals(TestTarget.boostCount, 0);
86         Assert.assertEquals(TestTarget.unboostCount, 0);
87 
88         t.synchronizedCall();
89 
90         Assert.assertEquals(TestTarget.boostCount, 1);
91         Assert.assertEquals(TestTarget.unboostCount, 1);
92         Assert.assertEquals(TestTarget.invokeCount, 1);
93     }
94 
95     @Test
testSimpleSynchronizedMethod2()96     public void testSimpleSynchronizedMethod2() {
97         TestTarget.resetCount();
98         TestTarget t = new TestTarget();
99 
100         Assert.assertEquals(TestTarget.boostCount, 0);
101         Assert.assertEquals(TestTarget.unboostCount, 0);
102 
103         t.synchronizedCallReturnInt();
104 
105         Assert.assertEquals(TestTarget.boostCount, 1);
106         Assert.assertEquals(TestTarget.unboostCount, 1);
107         Assert.assertEquals(TestTarget.invokeCount, 1);
108     }
109 
110     @Test
testSimpleSynchronizedMethod3()111     public void testSimpleSynchronizedMethod3() {
112         TestTarget.resetCount();
113         TestTarget t = new TestTarget();
114 
115         Assert.assertEquals(TestTarget.boostCount, 0);
116         Assert.assertEquals(TestTarget.unboostCount, 0);
117 
118         t.synchronizedCallReturnObject();
119 
120         Assert.assertEquals(TestTarget.boostCount, 1);
121         Assert.assertEquals(TestTarget.unboostCount, 1);
122         Assert.assertEquals(TestTarget.invokeCount, 1);
123     }
124 
125     @SuppressWarnings("unused")
126     @Test
testCaughtException()127     public void testCaughtException() {
128         TestTarget.resetCount();
129         TestTarget t = new TestTarget();
130         boolean caughtException = false;
131 
132         Assert.assertEquals(TestTarget.boostCount, 0);
133         Assert.assertEquals(TestTarget.unboostCount, 0);
134         Assert.assertEquals(TestTarget.unboostCount, 0);
135 
136         try {
137             synchronized (t) {
138                 Assert.assertEquals(TestTarget.boostCount, 1);
139                 Assert.assertEquals(TestTarget.unboostCount, 0);
140                 if (true) {
141                     throw new RuntimeException();
142                 }
143                 TestTarget.invoke();
144             }
145         } catch (Throwable e) {
146             caughtException = true;
147         }
148 
149         Assert.assertEquals(TestTarget.boostCount, 1);
150         Assert.assertEquals(TestTarget.unboostCount, 1);
151         Assert.assertEquals(TestTarget.invokeCount, 0); // Not called
152         Assert.assertTrue(caughtException);
153     }
154 
155     @SuppressWarnings("unused")
testUncaughtException()156     private void testUncaughtException() {
157         TestTarget t = new TestTarget();
158         synchronized (t) {
159             if (true) {
160                 throw new RuntimeException();
161             }
162             TestTarget.invoke();
163         }
164     }
165 
166     @SuppressWarnings("unused")
167     @Test
testHandledFinally()168     public void testHandledFinally() {
169         TestTarget.resetCount();
170         try {
171             testUncaughtException();
172         } catch (Throwable t) {
173 
174         }
175         Assert.assertEquals(TestTarget.boostCount, 1);
176         Assert.assertEquals(TestTarget.unboostCount, 1);
177         Assert.assertEquals(TestTarget.invokeCount, 0); // Not called
178     }
179 
180     @Test
testNestedSynchronizedBlock()181     public void testNestedSynchronizedBlock() {
182         TestTarget.resetCount();
183         TestTarget t = new TestTarget();
184 
185         Assert.assertEquals(TestTarget.boostCount, 0);
186         Assert.assertEquals(TestTarget.unboostCount, 0);
187         Assert.assertEquals(TestTarget.unboostCount, 0);
188 
189         synchronized (t) {
190             synchronized (t) {
191                 synchronized (t) {
192                     synchronized (t) {
193                         synchronized (t) {
194                             synchronized (t) {
195                                 Assert.assertEquals(TestTarget.boostCount, 6);
196                                 Assert.assertEquals(TestTarget.unboostCount, 0);
197                                 TestTarget.invoke();
198                             }
199                             Assert.assertEquals(TestTarget.unboostCount, 1);
200                         }
201                         Assert.assertEquals(TestTarget.unboostCount, 2);
202                     }
203                     Assert.assertEquals(TestTarget.unboostCount, 3);
204                 }
205                 Assert.assertEquals(TestTarget.unboostCount, 4);
206             }
207             Assert.assertEquals(TestTarget.unboostCount, 5);
208         }
209 
210         Assert.assertEquals(TestTarget.boostCount, 6);
211         Assert.assertEquals(TestTarget.unboostCount, 6);
212         Assert.assertEquals(TestTarget.invokeCount, 1);
213     }
214 
215     @Test
testMethodWithControlFlow()216     public void testMethodWithControlFlow() {
217         TestTarget.resetCount();
218         TestTarget t = new TestTarget();
219 
220         Assert.assertEquals(TestTarget.boostCount, 0);
221         Assert.assertEquals(TestTarget.unboostCount, 0);
222 
223         if ((t.hashCode() + " ").contains("1")) {
224             t.synchronizedCall();
225         } else {
226             t.synchronizedCall();
227         }
228 
229         // Should only be boosted once.
230         Assert.assertEquals(TestTarget.boostCount, 1);
231         Assert.assertEquals(TestTarget.unboostCount, 1);
232         Assert.assertEquals(TestTarget.invokeCount, 1);
233     }
234 
235     @Test
testUnboostThatThrows()236     public void testUnboostThatThrows() {
237         TestTarget.resetCount();
238         TestTarget t = new TestTarget();
239         boolean asserted = false;
240 
241         Assert.assertEquals(TestTarget.boostCount, 0);
242         Assert.assertEquals(TestTarget.unboostCount, 0);
243 
244         try {
245             t.synchronizedThrowsOnUnboost();
246         } catch (RuntimeException e) {
247             asserted = true;
248         }
249 
250         Assert.assertEquals(asserted, true);
251         Assert.assertEquals(TestTarget.boostCount, 1);
252         Assert.assertEquals(TestTarget.unboostCount, 0);
253         Assert.assertEquals(TestTarget.invokeCount, 1);
254     }
255 
256 }
257