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 */
16package dalvik.system;
17
18import org.junit.Rule;
19import org.junit.Test;
20import org.junit.rules.TestRule;
21import org.junit.runner.Description;
22import org.junit.runners.model.Statement;
23
24/**
25 * Tests {@link CloseGuard}.
26 */
27public class CloseGuardTest {
28
29    /**
30     * Resets the {@link CloseGuard#ENABLED} state back to the value it had when the test started.
31     */
32    @Rule
33    public TestRule rule = this::preserveEnabledState;
34
35    private Statement preserveEnabledState(final Statement base, Description description) {
36        return new Statement() {
37            @Override
38            public void evaluate() throws Throwable {
39                boolean oldEnabledState = CloseGuard.isEnabled();
40                try {
41                    base.evaluate();
42                } finally {
43                    CloseGuard.setEnabled(oldEnabledState);
44                }
45            }
46        };
47    }
48
49    @Test
50    public void testEnabled_NotOpen() throws Throwable {
51        CloseGuard.setEnabled(true);
52        ResourceOwner owner = new ResourceOwner();
53        assertUnreleasedResources(owner, 0);
54    }
55
56    @Test
57    public void testEnabled_OpenNotClosed() throws Throwable {
58        CloseGuard.setEnabled(true);
59        ResourceOwner owner = new ResourceOwner();
60        owner.open();
61        assertUnreleasedResources(owner, 1);
62    }
63
64    @Test
65    public void testEnabled_OpenThenClosed() throws Throwable {
66        CloseGuard.setEnabled(true);
67        ResourceOwner owner = new ResourceOwner();
68        owner.open();
69        owner.close();
70        assertUnreleasedResources(owner, 0);
71    }
72
73    @Test
74    public void testEnabledWhenCreated_DisabledWhenOpen() throws Throwable {
75        CloseGuard.setEnabled(true);
76        ResourceOwner owner = new ResourceOwner();
77        CloseGuard.setEnabled(false);
78        owner.open();
79
80        // Although the resource was not released it should not report it because CloseGuard was
81        // not enabled when the CloseGuard was opened.
82        assertUnreleasedResources(owner, 0);
83    }
84
85    @Test
86    public void testEnabledWhenOpened_DisabledWhenFinalized() throws Throwable {
87        CloseGuard.setEnabled(true);
88        ResourceOwner owner = new ResourceOwner();
89        owner.open();
90        CloseGuard.setEnabled(false);
91
92        // Although the resource was not released it should not report it because CloseGuard was
93        // not enabled when the CloseGuard was finalized.
94        assertUnreleasedResources(owner, 0);
95    }
96
97    @Test
98    public void testDisabled_NotOpen() throws Throwable {
99        CloseGuard.setEnabled(false);
100        ResourceOwner owner = new ResourceOwner();
101        assertUnreleasedResources(owner, 0);
102    }
103
104    @Test
105    public void testDisabled_OpenNotClosed() throws Throwable {
106        CloseGuard.setEnabled(false);
107        ResourceOwner owner = new ResourceOwner();
108        owner.open();
109        assertUnreleasedResources(owner, 0);
110    }
111
112    @Test
113    public void testDisabled_OpenThenClosed() throws Throwable {
114        CloseGuard.setEnabled(false);
115        ResourceOwner owner = new ResourceOwner();
116        owner.open();
117        owner.close();
118        assertUnreleasedResources(owner, 0);
119    }
120
121    @Test
122    public void testDisabledWhenCreated_EnabledWhenOpen() throws Throwable {
123        CloseGuard.setEnabled(false);
124        ResourceOwner owner = new ResourceOwner();
125        CloseGuard.setEnabled(true);
126        owner.open();
127
128        // Although the resource was not released it should not report it because CloseGuard was
129        // not enabled when the CloseGuard was created.
130        assertUnreleasedResources(owner, 0);
131    }
132
133    private void assertUnreleasedResources(ResourceOwner owner, int expectedCount)
134            throws Throwable {
135        try {
136            CloseGuardSupport.getFinalizerChecker().accept(owner, expectedCount);
137        } finally {
138            // Close the resource so that CloseGuard does not generate a warning for real when it
139            // is actually finalized.
140            owner.close();
141        }
142    }
143
144    /**
145     * A test user of {@link CloseGuard}.
146     */
147    private static class ResourceOwner {
148
149        private final CloseGuard closeGuard;
150
151        ResourceOwner() {
152            closeGuard = CloseGuard.get();
153        }
154
155        public void open() {
156            closeGuard.open("close");
157        }
158
159        public void close() {
160            closeGuard.close();
161        }
162
163        /**
164         * Make finalize public so that it can be tested directly without relying on garbage
165         * collection to trigger it.
166         */
167        @Override
168        public void finalize() throws Throwable {
169            closeGuard.warnIfOpen();
170            super.finalize();
171        }
172    }
173}
174