1 /*
2  * Copyright (C) 2019 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 
17 package com.android.internal.infra;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.testng.Assert.expectThrows;
22 
23 import android.os.Parcel;
24 
25 import androidx.test.runner.AndroidJUnit4;
26 
27 import org.junit.Test;
28 import org.junit.runner.RunWith;
29 
30 import java.util.concurrent.CountDownLatch;
31 import java.util.concurrent.ExecutionException;
32 import java.util.function.BiFunction;
33 
34 /**
35  * Unit test for {@link AndroidFuture}.
36  *
37  * <p>To run it:
38  * {@code atest FrameworksCoreTests:com.android.internal.infra.AndroidFutureTest}
39  */
40 
41 @RunWith(AndroidJUnit4.class)
42 public class AndroidFutureTest {
43     @Test
testGet()44     public void testGet() throws Exception {
45         AndroidFuture<Integer> future = new AndroidFuture<>();
46         future.complete(5);
47         assertThat(future.get()).isEqualTo(5);
48     }
49 
50     @Test
testWhenComplete_AlreadyComplete()51     public void testWhenComplete_AlreadyComplete() throws Exception {
52         AndroidFuture<Integer> future = new AndroidFuture<>();
53         future.complete(5);
54         CountDownLatch latch = new CountDownLatch(1);
55         future.whenComplete((obj, err) -> {
56             assertThat(obj).isEqualTo(5);
57             assertThat(err).isNull();
58             latch.countDown();
59         });
60         latch.await();
61     }
62 
63     @Test
testWhenComplete_NotYetComplete()64     public void testWhenComplete_NotYetComplete() throws Exception {
65         AndroidFuture<Integer> future = new AndroidFuture<>();
66         CountDownLatch latch = new CountDownLatch(1);
67         future.whenComplete((obj, err) -> {
68             assertThat(obj).isEqualTo(5);
69             assertThat(err).isNull();
70             latch.countDown();
71         });
72         assertThat(latch.getCount()).isEqualTo(1);
73         future.complete(5);
74         latch.await();
75         assertThat(latch.getCount()).isEqualTo(0);
76     }
77 
78     @Test
testCompleteExceptionally()79     public void testCompleteExceptionally() {
80         AndroidFuture<Integer> future = new AndroidFuture<>();
81         Exception origException = new UnsupportedOperationException();
82         future.completeExceptionally(origException);
83         ExecutionException executionException =
84                 expectThrows(ExecutionException.class, future::get);
85         assertThat(executionException.getCause()).isSameInstanceAs(origException);
86     }
87 
88     @Test
testCompleteExceptionally_Listener()89     public void testCompleteExceptionally_Listener() throws Exception {
90         AndroidFuture<Integer> future = new AndroidFuture<>();
91         Exception origException = new UnsupportedOperationException();
92         future.completeExceptionally(origException);
93         CountDownLatch latch = new CountDownLatch(1);
94         future.whenComplete((obj, err) -> {
95             assertThat(obj).isNull();
96             assertThat(err).isSameInstanceAs(origException);
97             latch.countDown();
98         });
99         latch.await();
100     }
101 
102     @Test
testWriteToParcel()103     public void testWriteToParcel() throws Exception {
104         Parcel parcel = Parcel.obtain();
105         AndroidFuture<Integer> future1 = new AndroidFuture<>();
106         future1.complete(5);
107         future1.writeToParcel(parcel, 0);
108 
109         parcel.setDataPosition(0);
110         AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel);
111         assertThat(future2.get()).isEqualTo(5);
112     }
113 
114     @Test
testWriteToParcel_Exception()115     public void testWriteToParcel_Exception() throws Exception {
116         Parcel parcel = Parcel.obtain();
117         AndroidFuture<Integer> future1 = new AndroidFuture<>();
118         future1.completeExceptionally(new UnsupportedOperationException());
119         future1.writeToParcel(parcel, 0);
120 
121         parcel.setDataPosition(0);
122         AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel);
123         ExecutionException executionException =
124                 expectThrows(ExecutionException.class, future2::get);
125 
126         Throwable cause = executionException.getCause();
127         String msg = cause.getMessage();
128         assertThat(cause).isInstanceOf(UnsupportedOperationException.class);
129         assertThat(msg).contains(getClass().getName());
130         assertThat(msg).contains("testWriteToParcel_Exception");
131     }
132 
133     @Test
testWriteToParcel_Incomplete()134     public void testWriteToParcel_Incomplete() throws Exception {
135         Parcel parcel = Parcel.obtain();
136         AndroidFuture<Integer> future1 = new AndroidFuture<>();
137         future1.writeToParcel(parcel, 0);
138 
139         parcel.setDataPosition(0);
140         AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel);
141         future2.complete(5);
142         assertThat(future1.get()).isEqualTo(5);
143     }
144 
145     @Test
testWriteToParcel_Incomplete_Exception()146     public void testWriteToParcel_Incomplete_Exception() throws Exception {
147         Parcel parcel = Parcel.obtain();
148         AndroidFuture<Integer> future1 = new AndroidFuture<>();
149         future1.writeToParcel(parcel, 0);
150 
151         parcel.setDataPosition(0);
152         AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel);
153         future2.completeExceptionally(new UnsupportedOperationException());
154         ExecutionException executionException =
155                 expectThrows(ExecutionException.class, future1::get);
156         assertThat(executionException.getCause()).isInstanceOf(UnsupportedOperationException.class);
157     }
158 
159     @Test
testThenCombine()160     public void testThenCombine() throws Exception {
161         String nearFutureString = "near future comes";
162         AndroidFuture<String> nearFuture = AndroidFuture.supply(() -> nearFutureString);
163         String farFutureString = " before far future.";
164         AndroidFuture<String> farFuture = AndroidFuture.supply(() -> farFutureString);
165         AndroidFuture<String> combinedFuture =
166                 nearFuture.thenCombine(farFuture, ((s1, s2) -> s1 + s2));
167 
168         assertThat(combinedFuture.get()).isEqualTo(nearFutureString + farFutureString);
169     }
170 
171     @Test
testThenCombine_functionThrowingException()172     public void testThenCombine_functionThrowingException() throws Exception {
173         String nearFutureString = "near future comes";
174         AndroidFuture<String> nearFuture = AndroidFuture.supply(() -> nearFutureString);
175         String farFutureString = " before far future.";
176         AndroidFuture<String> farFuture = AndroidFuture.supply(() -> farFutureString);
177         UnsupportedOperationException exception = new UnsupportedOperationException(
178                 "Unsupported operation exception thrown!");
179         BiFunction<String, String, String> throwingFunction = (s1, s2) -> {
180             throw exception;
181         };
182         AndroidFuture<String> combinedFuture = nearFuture.thenCombine(farFuture, throwingFunction);
183 
184         ExecutionException thrown = expectThrows(ExecutionException.class,
185                 () -> combinedFuture.get());
186 
187         assertThat(thrown.getCause()).isSameInstanceAs(exception);
188     }
189 }
190