• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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.base;
18 
19 import static com.google.common.testing.SerializableTester.reserialize;
20 
21 import com.google.common.annotations.GwtCompatible;
22 import com.google.common.annotations.GwtIncompatible;
23 import com.google.common.collect.Lists;
24 import com.google.common.testing.NullPointerTester;
25 
26 import junit.framework.TestCase;
27 
28 import java.io.Serializable;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.concurrent.TimeUnit;
32 import java.util.concurrent.TimeoutException;
33 import java.util.concurrent.atomic.AtomicInteger;
34 import java.util.concurrent.atomic.AtomicReference;
35 
36 /**
37  * Tests com.google.common.base.Suppliers.
38  *
39  * @author Laurence Gonsalves
40  * @author Harry Heymann
41  */
42 @GwtCompatible(emulated = true)
43 public class SuppliersTest extends TestCase {
testCompose()44   public void testCompose() {
45     Supplier<Integer> fiveSupplier = new Supplier<Integer>() {
46       @Override
47       public Integer get() {
48         return 5;
49       }
50     };
51 
52     Function<Number, Integer> intValueFunction =
53         new Function<Number, Integer>() {
54           @Override
55           public Integer apply(Number x) {
56             return x.intValue();
57           }
58         };
59 
60     Supplier<Integer> squareSupplier = Suppliers.compose(intValueFunction,
61         fiveSupplier);
62 
63     assertEquals(Integer.valueOf(5), squareSupplier.get());
64   }
65 
testComposeWithLists()66   public void testComposeWithLists() {
67     Supplier<ArrayList<Integer>> listSupplier
68         = new Supplier<ArrayList<Integer>>() {
69       @Override
70       public ArrayList<Integer> get() {
71         return Lists.newArrayList(0);
72       }
73     };
74 
75     Function<List<Integer>, List<Integer>> addElementFunction =
76         new Function<List<Integer>, List<Integer>>() {
77           @Override
78           public List<Integer> apply(List<Integer> list) {
79             ArrayList<Integer> result = Lists.newArrayList(list);
80             result.add(1);
81             return result;
82           }
83         };
84 
85     Supplier<List<Integer>> addSupplier = Suppliers.compose(addElementFunction,
86         listSupplier);
87 
88     List<Integer> result = addSupplier.get();
89     assertEquals(Integer.valueOf(0), result.get(0));
90     assertEquals(Integer.valueOf(1), result.get(1));
91   }
92 
93   static class CountingSupplier implements Supplier<Integer>, Serializable {
94     private static final long serialVersionUID = 0L;
95     transient int calls = 0;
96     @Override
get()97     public Integer get() {
98       calls++;
99       return calls * 10;
100     }
101   }
102 
testMemoize()103   public void testMemoize() {
104     CountingSupplier countingSupplier = new CountingSupplier();
105     Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
106     checkMemoize(countingSupplier, memoizedSupplier);
107   }
108 
testMemoize_redudantly()109   public void testMemoize_redudantly() {
110     CountingSupplier countingSupplier = new CountingSupplier();
111     Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
112     assertSame(memoizedSupplier, Suppliers.memoize(memoizedSupplier));
113   }
114 
115   @GwtIncompatible("SerializableTester")
testMemoizeSerialized()116   public void testMemoizeSerialized() {
117     CountingSupplier countingSupplier = new CountingSupplier();
118     Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
119     checkMemoize(countingSupplier, memoizedSupplier);
120     // Calls to the original memoized supplier shouldn't affect its copy.
121     memoizedSupplier.get();
122 
123     Supplier<Integer> copy = reserialize(memoizedSupplier);
124     memoizedSupplier.get();
125 
126     CountingSupplier countingCopy = (CountingSupplier)
127         ((Suppliers.MemoizingSupplier<Integer>) copy).delegate;
128     checkMemoize(countingCopy, copy);
129   }
130 
checkMemoize( CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier)131   private void checkMemoize(
132       CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier) {
133     // the underlying supplier hasn't executed yet
134     assertEquals(0, countingSupplier.calls);
135 
136     assertEquals(10, (int) memoizedSupplier.get());
137 
138     // now it has
139     assertEquals(1, countingSupplier.calls);
140 
141     assertEquals(10, (int) memoizedSupplier.get());
142 
143     // it still should only have executed once due to memoization
144     assertEquals(1, countingSupplier.calls);
145   }
146 
testMemoizeExceptionThrown()147   public void testMemoizeExceptionThrown() {
148     Supplier<Integer> exceptingSupplier = new Supplier<Integer>() {
149       @Override
150       public Integer get() {
151         throw new NullPointerException();
152       }
153     };
154 
155     Supplier<Integer> memoizedSupplier = Suppliers.memoize(exceptingSupplier);
156 
157     // call get() twice to make sure that memoization doesn't interfere
158     // with throwing the exception
159     for (int i = 0; i < 2; i++) {
160       try {
161         memoizedSupplier.get();
162         fail("failed to throw NullPointerException");
163       } catch (NullPointerException e) {
164         // this is what should happen
165       }
166     }
167   }
168 
169   @GwtIncompatible("Thread.sleep")
testMemoizeWithExpiration()170   public void testMemoizeWithExpiration() throws InterruptedException {
171     CountingSupplier countingSupplier = new CountingSupplier();
172 
173     Supplier<Integer> memoizedSupplier = Suppliers.memoizeWithExpiration(
174         countingSupplier, 75, TimeUnit.MILLISECONDS);
175 
176     checkExpiration(countingSupplier, memoizedSupplier);
177   }
178 
179   @GwtIncompatible("Thread.sleep, SerializationTester")
testMemoizeWithExpirationSerialized()180   public void testMemoizeWithExpirationSerialized()
181       throws InterruptedException {
182     CountingSupplier countingSupplier = new CountingSupplier();
183 
184     Supplier<Integer> memoizedSupplier = Suppliers.memoizeWithExpiration(
185         countingSupplier, 75, TimeUnit.MILLISECONDS);
186     // Calls to the original memoized supplier shouldn't affect its copy.
187     memoizedSupplier.get();
188 
189     Supplier<Integer> copy = reserialize(memoizedSupplier);
190     memoizedSupplier.get();
191 
192     CountingSupplier countingCopy = (CountingSupplier)
193         ((Suppliers.ExpiringMemoizingSupplier<Integer>) copy).delegate;
194     checkExpiration(countingCopy, copy);
195   }
196 
197   @GwtIncompatible("Thread.sleep")
checkExpiration( CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier)198   private void checkExpiration(
199       CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier)
200       throws InterruptedException {
201     // the underlying supplier hasn't executed yet
202     assertEquals(0, countingSupplier.calls);
203 
204     assertEquals(10, (int) memoizedSupplier.get());
205     // now it has
206     assertEquals(1, countingSupplier.calls);
207 
208     assertEquals(10, (int) memoizedSupplier.get());
209     // it still should only have executed once due to memoization
210     assertEquals(1, countingSupplier.calls);
211 
212     Thread.sleep(150);
213 
214     assertEquals(20, (int) memoizedSupplier.get());
215     // old value expired
216     assertEquals(2, countingSupplier.calls);
217 
218     assertEquals(20, (int) memoizedSupplier.get());
219     // it still should only have executed twice due to memoization
220     assertEquals(2, countingSupplier.calls);
221   }
222 
testOfInstanceSuppliesSameInstance()223   public void testOfInstanceSuppliesSameInstance() {
224     Object toBeSupplied = new Object();
225     Supplier<Object> objectSupplier = Suppliers.ofInstance(toBeSupplied);
226     assertSame(toBeSupplied,objectSupplier.get());
227     assertSame(toBeSupplied,objectSupplier.get()); // idempotent
228   }
229 
testOfInstanceSuppliesNull()230   public void testOfInstanceSuppliesNull() {
231     Supplier<Integer> nullSupplier = Suppliers.ofInstance(null);
232     assertNull(nullSupplier.get());
233   }
234 
235   @GwtIncompatible("Thread")
236 
testExpiringMemoizedSupplierThreadSafe()237   public void testExpiringMemoizedSupplierThreadSafe() throws Throwable {
238     Function<Supplier<Boolean>, Supplier<Boolean>> memoizer =
239         new Function<Supplier<Boolean>, Supplier<Boolean>>() {
240       @Override public Supplier<Boolean> apply(Supplier<Boolean> supplier) {
241         return Suppliers.memoizeWithExpiration(
242             supplier, Long.MAX_VALUE, TimeUnit.NANOSECONDS);
243       }
244     };
245     testSupplierThreadSafe(memoizer);
246   }
247 
248   @GwtIncompatible("Thread")
249 
testMemoizedSupplierThreadSafe()250   public void testMemoizedSupplierThreadSafe() throws Throwable {
251     Function<Supplier<Boolean>, Supplier<Boolean>> memoizer =
252         new Function<Supplier<Boolean>, Supplier<Boolean>>() {
253       @Override public Supplier<Boolean> apply(Supplier<Boolean> supplier) {
254         return Suppliers.memoize(supplier);
255       }
256     };
257     testSupplierThreadSafe(memoizer);
258   }
259 
260   @GwtIncompatible("Thread")
testSupplierThreadSafe( Function<Supplier<Boolean>, Supplier<Boolean>> memoizer)261   public void testSupplierThreadSafe(
262       Function<Supplier<Boolean>, Supplier<Boolean>> memoizer)
263       throws Throwable {
264     final AtomicInteger count = new AtomicInteger(0);
265     final AtomicReference<Throwable> thrown =
266         new AtomicReference<Throwable>(null);
267     final int numThreads = 3;
268     final Thread[] threads = new Thread[numThreads];
269     final long timeout = TimeUnit.SECONDS.toNanos(60);
270 
271     final Supplier<Boolean> supplier = new Supplier<Boolean>() {
272       boolean isWaiting(Thread thread) {
273         switch (thread.getState()) {
274           case BLOCKED:
275           case WAITING:
276           case TIMED_WAITING:
277           return true;
278           default:
279           return false;
280         }
281       }
282 
283       int waitingThreads() {
284         int waitingThreads = 0;
285         for (Thread thread : threads) {
286           if (isWaiting(thread)) {
287             waitingThreads++;
288           }
289         }
290         return waitingThreads;
291       }
292 
293       @Override
294       public Boolean get() {
295         // Check that this method is called exactly once, by the first
296         // thread to synchronize.
297         long t0 = System.nanoTime();
298         while (waitingThreads() != numThreads - 1) {
299           if (System.nanoTime() - t0 > timeout) {
300             thrown.set(new TimeoutException(
301                 "timed out waiting for other threads to block" +
302                 " synchronizing on supplier"));
303             break;
304           }
305           Thread.yield();
306         }
307         count.getAndIncrement();
308         return Boolean.TRUE;
309       }
310     };
311 
312     final Supplier<Boolean> memoizedSupplier = memoizer.apply(supplier);
313 
314     for (int i = 0; i < numThreads; i++) {
315       threads[i] = new Thread() {
316         @Override public void run() {
317           assertSame(Boolean.TRUE, memoizedSupplier.get());
318         }
319       };
320     }
321     for (Thread t : threads) {
322       t.start();
323     }
324     for (Thread t : threads) {
325       t.join();
326     }
327 
328     if (thrown.get() != null) {
329       throw thrown.get();
330     }
331     assertEquals(1, count.get());
332   }
333 
334   @GwtIncompatible("Thread")
335 
testSynchronizedSupplierThreadSafe()336   public void testSynchronizedSupplierThreadSafe()
337       throws InterruptedException {
338     final Supplier<Integer> nonThreadSafe = new Supplier<Integer>() {
339       int counter = 0;
340       @Override
341       public Integer get() {
342         int nextValue = counter + 1;
343         Thread.yield();
344         counter = nextValue;
345         return counter;
346       }
347     };
348 
349     final int numThreads = 10;
350     final int iterations = 1000;
351     Thread[] threads = new Thread[numThreads];
352     for (int i = 0; i < numThreads; i++) {
353       threads[i] = new Thread() {
354         @Override public void run() {
355           for (int j = 0; j < iterations; j++) {
356             Suppliers.synchronizedSupplier(nonThreadSafe).get();
357           }
358         }
359       };
360     }
361     for (Thread t : threads) {
362       t.start();
363     }
364     for (Thread t : threads) {
365       t.join();
366     }
367 
368     assertEquals(numThreads * iterations + 1, (int) nonThreadSafe.get());
369   }
370 
testSupplierFunction()371   public void testSupplierFunction() {
372     Supplier<Integer> supplier = Suppliers.ofInstance(14);
373     Function<Supplier<Integer>, Integer> supplierFunction =
374         Suppliers.supplierFunction();
375 
376     assertEquals(14, (int) supplierFunction.apply(supplier));
377   }
378 
379   @GwtIncompatible("SerializationTester")
testSerialization()380   public void testSerialization() {
381     assertEquals(
382         Integer.valueOf(5), reserialize(Suppliers.ofInstance(5)).get());
383     assertEquals(Integer.valueOf(5), reserialize(Suppliers.compose(
384         Functions.identity(), Suppliers.ofInstance(5))).get());
385     assertEquals(Integer.valueOf(5),
386         reserialize(Suppliers.memoize(Suppliers.ofInstance(5))).get());
387     assertEquals(Integer.valueOf(5),
388         reserialize(Suppliers.memoizeWithExpiration(
389             Suppliers.ofInstance(5), 30, TimeUnit.SECONDS)).get());
390     assertEquals(Integer.valueOf(5), reserialize(
391         Suppliers.synchronizedSupplier(Suppliers.ofInstance(5))).get());
392   }
393 
394   @GwtIncompatible("NullPointerTest")
testNullPointers()395   public void testNullPointers() throws Exception {
396     NullPointerTester tester = new NullPointerTester();
397     tester.testAllPublicStaticMethods(Suppliers.class);
398   }
399 }
400