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