1 /*
2  * Copyright (C) 2016 The Guava Authors
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.google.common.util.concurrent;
18 
19 import static com.google.common.base.Verify.verify;
20 import static com.google.common.truth.Truth.assertThat;
21 import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
22 import static com.google.common.util.concurrent.Futures.immediateFuture;
23 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
24 import static java.util.concurrent.Executors.newScheduledThreadPool;
25 import static java.util.concurrent.TimeUnit.SECONDS;
26 
27 import com.google.common.annotations.GwtCompatible;
28 import com.google.common.annotations.GwtIncompatible;
29 import com.google.common.base.Function;
30 import com.google.common.util.concurrent.ForwardingListenableFuture.SimpleForwardingListenableFuture;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.ScheduledExecutorService;
33 import java.util.concurrent.TimeoutException;
34 import junit.framework.TestCase;
35 
36 /**
37  * Tests for {@link FluentFuture}. The tests cover only the basics for the API. The actual logic is
38  * tested in {@link FuturesTest}.
39  */
40 @GwtCompatible(emulated = true)
41 public class FluentFutureTest extends TestCase {
testFromFluentFuture()42   public void testFromFluentFuture() {
43     FluentFuture<String> f = FluentFuture.from(SettableFuture.<String>create());
44     assertThat(FluentFuture.from(f)).isSameInstanceAs(f);
45   }
46 
testFromFluentFuturePassingAsNonFluent()47   public void testFromFluentFuturePassingAsNonFluent() {
48     ListenableFuture<String> f = FluentFuture.from(SettableFuture.<String>create());
49     assertThat(FluentFuture.from(f)).isSameInstanceAs(f);
50   }
51 
testFromNonFluentFuture()52   public void testFromNonFluentFuture() throws Exception {
53     ListenableFuture<String> f =
54         new SimpleForwardingListenableFuture<String>(immediateFuture("a")) {};
55     verify(!(f instanceof FluentFuture));
56     assertThat(FluentFuture.from(f).get()).isEqualTo("a");
57     // TODO(cpovirk): Test forwarding more extensively.
58   }
59 
testAddCallback()60   public void testAddCallback() {
61     FluentFuture<String> f = FluentFuture.from(immediateFuture("a"));
62     final boolean[] called = new boolean[1];
63     f.addCallback(
64         new FutureCallback<String>() {
65           @Override
66           public void onSuccess(String result) {
67             called[0] = true;
68           }
69 
70           @Override
71           public void onFailure(Throwable t) {}
72         },
73         directExecutor());
74     assertThat(called[0]).isTrue();
75   }
76 
testCatching()77   public void testCatching() throws Exception {
78     FluentFuture<?> f =
79         FluentFuture.from(immediateFailedFuture(new RuntimeException()))
80             .catching(
81                 Throwable.class,
82                 new Function<Throwable, Class<?>>() {
83                   @Override
84                   public Class<?> apply(Throwable input) {
85                     return input.getClass();
86                   }
87                 },
88                 directExecutor());
89     assertThat(f.get()).isEqualTo(RuntimeException.class);
90   }
91 
testCatchingAsync()92   public void testCatchingAsync() throws Exception {
93     FluentFuture<?> f =
94         FluentFuture.from(immediateFailedFuture(new RuntimeException()))
95             .catchingAsync(
96                 Throwable.class,
97                 new AsyncFunction<Throwable, Class<?>>() {
98                   @Override
99                   public ListenableFuture<Class<?>> apply(Throwable input) {
100                     return Futures.<Class<?>>immediateFuture(input.getClass());
101                   }
102                 },
103                 directExecutor());
104     assertThat(f.get()).isEqualTo(RuntimeException.class);
105   }
106 
testTransform()107   public void testTransform() throws Exception {
108     FluentFuture<Integer> f =
109         FluentFuture.from(immediateFuture(1))
110             .transform(
111                 new Function<Integer, Integer>() {
112                   @Override
113                   public Integer apply(Integer input) {
114                     return input + 1;
115                   }
116                 },
117                 directExecutor());
118     assertThat(f.get()).isEqualTo(2);
119   }
120 
testTransformAsync()121   public void testTransformAsync() throws Exception {
122     FluentFuture<Integer> f =
123         FluentFuture.from(immediateFuture(1))
124             .transformAsync(
125                 new AsyncFunction<Integer, Integer>() {
126                   @Override
127                   public ListenableFuture<Integer> apply(Integer input) {
128                     return immediateFuture(input + 1);
129                   }
130                 },
131                 directExecutor());
132     assertThat(f.get()).isEqualTo(2);
133   }
134 
135   @GwtIncompatible // withTimeout
testWithTimeout()136   public void testWithTimeout() throws Exception {
137     ScheduledExecutorService executor = newScheduledThreadPool(1);
138     try {
139       FluentFuture<?> f =
140           FluentFuture.from(SettableFuture.create()).withTimeout(0, SECONDS, executor);
141       try {
142         f.get();
143         fail();
144       } catch (ExecutionException e) {
145         assertThat(e).hasCauseThat().isInstanceOf(TimeoutException.class);
146       }
147     } finally {
148       executor.shutdown();
149     }
150   }
151 }
152