xref: /aosp_15_r20/external/dagger2/javatests/dagger/internal/DoubleCheckTest.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
1 /*
2  * Copyright (C) 2016 The Dagger 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 dagger.internal;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.junit.Assert.fail;
21 
22 import com.google.common.collect.Lists;
23 import com.google.common.collect.Sets;
24 import com.google.common.util.concurrent.Uninterruptibles;
25 import dagger.Lazy;
26 import java.util.List;
27 import java.util.Set;
28 import java.util.concurrent.Callable;
29 import java.util.concurrent.CountDownLatch;
30 import java.util.concurrent.ExecutorService;
31 import java.util.concurrent.Executors;
32 import java.util.concurrent.Future;
33 import java.util.concurrent.atomic.AtomicInteger;
34 import java.util.concurrent.atomic.AtomicReference;
35 import org.junit.Test;
36 import org.junit.runner.RunWith;
37 import org.junit.runners.JUnit4;
38 
39 @RunWith(JUnit4.class)
40 public class DoubleCheckTest {
41   @Test
provider_nullPointerException()42   public void provider_nullPointerException() {
43     try {
44       DoubleCheck.provider(null);
45       fail();
46     } catch (NullPointerException expected) {
47     }
48   }
49 
50   @Test
lazy_nullPointerException()51   public void lazy_nullPointerException() {
52     try {
53       DoubleCheck.lazy(null);
54       fail();
55     } catch (NullPointerException expected) {
56     }
57   }
58 
59   private static final Provider<Object> DOUBLE_CHECK_OBJECT_PROVIDER =
60       DoubleCheck.provider(Object::new);
61 
62   @Test
doubleWrapping_provider()63   public void doubleWrapping_provider() {
64     assertThat(DoubleCheck.provider(DOUBLE_CHECK_OBJECT_PROVIDER))
65         .isSameInstanceAs(DOUBLE_CHECK_OBJECT_PROVIDER);
66   }
67 
68   @Test
doubleWrapping_lazy()69   public void doubleWrapping_lazy() {
70     assertThat(DoubleCheck.lazy(DOUBLE_CHECK_OBJECT_PROVIDER))
71         .isSameInstanceAs(DOUBLE_CHECK_OBJECT_PROVIDER);
72   }
73 
74   @Test
get()75   public void get() throws Exception {
76     int numThreads = 10;
77     ExecutorService executor = Executors.newFixedThreadPool(numThreads);
78 
79     final CountDownLatch latch = new CountDownLatch(numThreads);
80     LatchedProvider provider = new LatchedProvider(latch);
81     final Lazy<Object> lazy = DoubleCheck.lazy(provider);
82 
83     List<Callable<Object>> tasks = Lists.newArrayListWithCapacity(numThreads);
84     for (int i = 0; i < numThreads; i++) {
85       tasks.add(
86           () -> {
87             latch.countDown();
88             return lazy.get();
89           });
90     }
91 
92     List<Future<Object>> futures = executor.invokeAll(tasks);
93 
94     assertThat(provider.provisions.get()).isEqualTo(1);
95     Set<Object> results = Sets.newIdentityHashSet();
96     for (Future<Object> future : futures) {
97       results.add(future.get());
98     }
99     assertThat(results).hasSize(1);
100   }
101 
102   private static class LatchedProvider implements Provider<Object> {
103     final AtomicInteger provisions;
104     final CountDownLatch latch;
105 
LatchedProvider(CountDownLatch latch)106     LatchedProvider(CountDownLatch latch) {
107       this.latch = latch;
108       this.provisions = new AtomicInteger();
109     }
110 
111     @Override
get()112     public Object get() {
113       if (latch != null) {
114         Uninterruptibles.awaitUninterruptibly(latch);
115       }
116       provisions.incrementAndGet();
117       return new Object();
118     }
119   }
120 
reentranceWithoutCondition_throwsStackOverflow()121   @Test public void reentranceWithoutCondition_throwsStackOverflow() {
122     final AtomicReference<Provider<Object>> doubleCheckReference =
123         new AtomicReference<>();
124     Provider<Object> doubleCheck = DoubleCheck.provider(() -> doubleCheckReference.get().get());
125     doubleCheckReference.set(doubleCheck);
126     try {
127       doubleCheck.get();
128       fail();
129     } catch (StackOverflowError expected) {}
130   }
131 
reentranceReturningSameInstance()132   @Test public void reentranceReturningSameInstance() {
133     final AtomicReference<Provider<Object>> doubleCheckReference =
134         new AtomicReference<>();
135     final AtomicInteger invocationCount = new AtomicInteger();
136     final Object object = new Object();
137     Provider<Object> doubleCheck = DoubleCheck.provider(() -> {
138         if (invocationCount.incrementAndGet() == 1) {
139          doubleCheckReference.get().get();
140        }
141        return object;
142      });
143     doubleCheckReference.set(doubleCheck);
144     assertThat(doubleCheck.get()).isSameInstanceAs(object);
145   }
146 
reentranceReturningDifferentInstances_throwsIllegalStateException()147   @Test public void reentranceReturningDifferentInstances_throwsIllegalStateException() {
148     final AtomicReference<Provider<Object>> doubleCheckReference =
149         new AtomicReference<>();
150     final AtomicInteger invocationCount = new AtomicInteger();
151     Provider<Object> doubleCheck = DoubleCheck.provider(() -> {
152        if (invocationCount.incrementAndGet() == 1) {
153          doubleCheckReference.get().get();
154        }
155        return new Object();
156      });
157     doubleCheckReference.set(doubleCheck);
158     try {
159       doubleCheck.get();
160       fail();
161     } catch (IllegalStateException expected) {}
162   }
163 
164   @Test
instanceFactoryAsLazyDoesNotWrap()165   public void instanceFactoryAsLazyDoesNotWrap() {
166     Factory<Object> factory = InstanceFactory.create(new Object());
167     assertThat(DoubleCheck.lazy(factory)).isSameInstanceAs(factory);
168   }
169 }
170