1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package libcore.dalvik.system;
17 
18 import java.util.Collections;
19 import java.util.List;
20 import org.junit.Rule;
21 import org.junit.Test;
22 import org.junit.rules.TestRule;
23 import org.junit.runner.JUnitCore;
24 import org.junit.runner.RunWith;
25 import org.junit.runner.notification.Failure;
26 import org.junit.runners.JUnit4;
27 
28 import dalvik.system.CloseGuard;
29 
30 import static org.junit.Assert.assertEquals;
31 import static org.junit.Assert.fail;
32 
33 @RunWith(JUnit4.class)
34 public class CloseGuardSupportTest {
35 
36     @Test
testDoesReleaseResource()37     public void testDoesReleaseResource() {
38         List<Failure> failures = JUnitCore.runClasses(DoesReleaseResource.class).getFailures();
39         assertEquals(Collections.emptyList(), failures);
40     }
41 
42     public static class DoesReleaseResource {
43         @Rule public TestRule rule = CloseGuardSupport.getRule();
test()44         @Test public void test() {
45             CloseGuard closeGuard = CloseGuard.get();
46             closeGuard.open("test resource");
47             closeGuard.close();
48         }
49     }
50 
51     @Test
testDoesReleaseResourceTwice()52     public void testDoesReleaseResourceTwice() {
53         List<Failure> failures = JUnitCore.runClasses(DoesReleaseResourceTwice.class).getFailures();
54         assertEquals(Collections.emptyList(), failures);
55     }
56 
57     public static class DoesReleaseResourceTwice {
58         @Rule public TestRule rule = CloseGuardSupport.getRule();
test()59         @Test public void test() {
60             CloseGuard closeGuard = CloseGuard.get();
61             closeGuard.open("test resource");
62             closeGuard.close();
63             closeGuard.close();
64         }
65     }
66 
67     @Test
testDoesNotReleaseResource()68     public void testDoesNotReleaseResource() {
69         List<Failure> failures = JUnitCore.runClasses(DoesNotReleaseResource.class).getFailures();
70         assertEquals("Failure count", 1, failures.size());
71         Failure failure = failures.get(0);
72         checkResourceNotReleased(failure, "Unreleased resources found in test");
73     }
74 
75     public static class DoesNotReleaseResource {
76         @Rule public TestRule rule = CloseGuardSupport.getRule();
test()77         @Test public void test() {
78             CloseGuard closeGuard = CloseGuard.get();
79             closeGuard.open("test resource");
80         }
81     }
82 
83     @Test
testDoesNotReleaseResourceDueToFailure()84     public void testDoesNotReleaseResourceDueToFailure() {
85         List<Failure> failures = JUnitCore
86                 .runClasses(DoesNotReleaseResourceDueToFailure.class)
87                 .getFailures();
88         assertEquals("Failure count", 1, failures.size());
89         Failure failure = failures.get(0);
90         checkResourceNotReleased(failure, "failure");
91     }
92 
93     public static class DoesNotReleaseResourceDueToFailure {
94         @Rule public TestRule rule = CloseGuardSupport.getRule();
test()95         @Test public void test() {
96             CloseGuard closeGuard = CloseGuard.get();
97             closeGuard.open("test resource");
98             fail("failure");
99         }
100     }
101 
102     @Test
testResourceOwnerDoesNotOverrideFinalize()103     public void testResourceOwnerDoesNotOverrideFinalize() {
104         List<Failure> failures = JUnitCore
105                 .runClasses(ResourceOwnerDoesNotOverrideFinalize.class)
106                 .getFailures();
107         assertEquals("Failure count", 1, failures.size());
108         Failure failure = failures.get(0);
109         assertEquals("Class java.lang.String does not have a finalize() method",
110                 failure.getMessage());
111     }
112 
113     public static class ResourceOwnerDoesNotOverrideFinalize {
114         @Rule public TestRule rule = CloseGuardSupport.getRule();
115         @Test
test()116         public void test() {
117             CloseGuardSupport.getFinalizerChecker().accept("not resource owner", 0);
118         }
119     }
120 
121     @Test
testResourceOwnerOverridesFinalizeButDoesNotReportLeak()122     public void testResourceOwnerOverridesFinalizeButDoesNotReportLeak() {
123         List<Failure> failures = JUnitCore
124                 .runClasses(ResourceOwnerOverridesFinalizeButDoesNotReportLeak.class)
125                 .getFailures();
126         assertEquals("Failure count", 1, failures.size());
127         Failure failure = failures.get(0);
128         assertEquals("Expected 1 unreleased resources, found 0;"
129                         + " see suppressed exceptions for details",
130                 failure.getMessage());
131     }
132 
133     public static class ResourceOwnerOverridesFinalizeButDoesNotReportLeak {
134         @Rule public TestRule rule = CloseGuardSupport.getRule();
135         @Test
test()136         public void test() {
137             CloseGuardSupport.getFinalizerChecker().accept(new Object() {
138                 @Override
139                 protected void finalize() throws Throwable {
140                     super.finalize();
141                 }
142             }, 1);
143         }
144     }
145 
146     @Test
testResourceOwnerOverridesFinalizeAndReportsLeak()147     public void testResourceOwnerOverridesFinalizeAndReportsLeak() {
148         List<Failure> failures = JUnitCore
149                 .runClasses(ResourceOwnerOverridesFinalizeAndReportsLeak.class)
150                 .getFailures();
151         assertEquals("Failure count", 1, failures.size());
152         Failure failure = failures.get(0);
153         checkResourceNotReleased(failure, "Unreleased resources found in test");
154     }
155 
156     public static class ResourceOwnerOverridesFinalizeAndReportsLeak {
157         @Rule public TestRule rule = CloseGuardSupport.getRule();
158         @Test
test()159         public void test() {
160             CloseGuardSupport.getFinalizerChecker().accept(new Object() {
161                 private CloseGuard guard = CloseGuard.get();
162                 {
163                     guard.open("test resource");
164                 }
165                 @Override
166                 protected void finalize() throws Throwable {
167                     guard.warnIfOpen();
168                     super.finalize();
169                 }
170             }, 1);
171         }
172     }
173 
checkResourceNotReleased(Failure failure, String expectedMessage)174     private void checkResourceNotReleased(Failure failure, String expectedMessage) {
175         @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
176         Throwable exception = failure.getException();
177         assertEquals(expectedMessage, exception.getMessage());
178         Throwable[] suppressed = exception.getSuppressed();
179         assertEquals("Suppressed count", 1, suppressed.length);
180         exception = suppressed[0];
181         assertEquals("Explicit termination method 'test resource' not called",
182                 exception.getMessage());
183     }
184 }
185