1 /*
2  * Copyright (C) 2023 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 android.media.bettertogether.cts;
17 
18 import static com.google.common.truth.Truth.assertWithMessage;
19 
20 import org.junit.rules.ExternalResource;
21 import org.junit.rules.TestRule;
22 
23 import java.util.ArrayDeque;
24 import java.util.ArrayList;
25 import java.util.Queue;
26 
27 /**
28  * {@link TestRule} for releasing resources once a test ends.
29  *
30  * <p><b>Minimal Example:</b>
31  *
32  * <pre>{@code
33  * public class FooTest {
34  *     @Rule public final ResourceReleaser mResourceReleaser = new ResourceReleaser();
35  *
36  *     @Test
37  *     public void registerFoo_doesSomething() {
38  *         Foo foo = new Foo();
39  *         foo.register();
40  *         mResourceReleaser.add(foo::unregister);
41  *
42  *         // Do assertions here.
43  *     }
44  * }
45  *
46  * }</pre>
47  */
48 public final class ResourceReleaser extends ExternalResource {
49 
50     private final Queue<Runnable> mPendingRunnables = new ArrayDeque<>();
51 
52     /**
53      * Adds a {@link Runnable} for execution after the end of the test run, regardless of the test
54      * result.
55      */
add(Runnable runnable)56     public void add(Runnable runnable) {
57         mPendingRunnables.add(runnable);
58     }
59 
60     @Override
after()61     public void after() {
62         ArrayList<Throwable> throwables = new ArrayList<>();
63         while (!mPendingRunnables.isEmpty()) {
64             Runnable runnable = mPendingRunnables.remove();
65             try {
66                 runnable.run();
67             } catch (Throwable e) {
68                 throwables.add(e);
69             }
70         }
71         assertWithMessage("Ran into exceptions while releasing resources.")
72                 .that(throwables)
73                 .isEmpty();
74     }
75 }
76