View Javadoc
1   /*
2    * Copyright (C) 2011 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.cache;
18  
19  import static com.google.common.cache.CacheBuilderSpec.parse;
20  import static com.google.common.cache.TestingWeighers.constantWeigher;
21  
22  import com.google.common.base.Suppliers;
23  import com.google.common.cache.LocalCache.Strength;
24  import com.google.common.testing.EqualsTester;
25  
26  import junit.framework.TestCase;
27  
28  import java.util.concurrent.TimeUnit;
29  
30  /**
31   * Tests CacheBuilderSpec.
32   * TODO(user): tests of a few invalid input conditions, boundary conditions.
33   *
34   * @author Adam Winer
35   */
36  public class CacheBuilderSpecTest extends TestCase {
37    public void testParse_empty() {
38      CacheBuilderSpec spec = parse("");
39      assertNull(spec.initialCapacity);
40      assertNull(spec.maximumSize);
41      assertNull(spec.maximumWeight);
42      assertNull(spec.concurrencyLevel);
43      assertNull(spec.keyStrength);
44      assertNull(spec.valueStrength);
45      assertNull(spec.writeExpirationTimeUnit);
46      assertNull(spec.accessExpirationTimeUnit);
47      assertCacheBuilderEquivalence(CacheBuilder.newBuilder(), CacheBuilder.from(spec));
48    }
49  
50    public void testParse_initialCapacity() {
51      CacheBuilderSpec spec = parse("initialCapacity=10");
52      assertEquals(10, spec.initialCapacity.intValue());
53      assertNull(spec.maximumSize);
54      assertNull(spec.maximumWeight);
55      assertNull(spec.concurrencyLevel);
56      assertNull(spec.keyStrength);
57      assertNull(spec.valueStrength);
58      assertNull(spec.writeExpirationTimeUnit);
59      assertNull(spec.accessExpirationTimeUnit);
60      assertCacheBuilderEquivalence(
61          CacheBuilder.newBuilder().initialCapacity(10), CacheBuilder.from(spec));
62    }
63  
64    public void testParse_initialCapacityRepeated() {
65      try {
66        parse("initialCapacity=10, initialCapacity=20");
67        fail("Expected exception");
68      } catch (IllegalArgumentException expected) {
69        // expected
70      }
71    }
72  
73    public void testParse_maximumSize() {
74      CacheBuilderSpec spec = parse("maximumSize=9000");
75      assertNull(spec.initialCapacity);
76      assertEquals(9000, spec.maximumSize.longValue());
77      assertNull(spec.concurrencyLevel);
78      assertNull(spec.keyStrength);
79      assertNull(spec.valueStrength);
80      assertNull(spec.writeExpirationTimeUnit);
81      assertNull(spec.accessExpirationTimeUnit);
82      assertCacheBuilderEquivalence(
83          CacheBuilder.newBuilder().maximumSize(9000), CacheBuilder.from(spec));
84    }
85  
86    public void testParse_maximumSizeRepeated() {
87      try {
88        parse("maximumSize=10, maximumSize=20");
89        fail("Expected exception");
90      } catch (IllegalArgumentException expected) {
91        // expected
92      }
93    }
94  
95    public void testParse_maximumWeight() {
96      CacheBuilderSpec spec = parse("maximumWeight=9000");
97      assertNull(spec.initialCapacity);
98      assertEquals(9000, spec.maximumWeight.longValue());
99      assertNull(spec.concurrencyLevel);
100     assertNull(spec.keyStrength);
101     assertNull(spec.valueStrength);
102     assertNull(spec.writeExpirationTimeUnit);
103     assertNull(spec.accessExpirationTimeUnit);
104     assertCacheBuilderEquivalence(
105         CacheBuilder.newBuilder().maximumWeight(9000), CacheBuilder.from(spec));
106   }
107 
108   public void testParse_maximumWeightRepeated() {
109     try {
110       parse("maximumWeight=10, maximumWeight=20");
111       fail("Expected exception");
112     } catch (IllegalArgumentException expected) {
113       // expected
114     }
115   }
116 
117   public void testParse_maximumSizeAndMaximumWeight() {
118     try {
119       parse("maximumSize=10, maximumWeight=20");
120       fail("Expected exception");
121     } catch (IllegalArgumentException expected) {
122       // expected
123     }
124   }
125 
126   public void testParse_concurrencyLevel() {
127     CacheBuilderSpec spec = parse("concurrencyLevel=32");
128     assertNull(spec.initialCapacity);
129     assertNull(spec.maximumSize);
130     assertNull(spec.maximumWeight);
131     assertEquals(32, spec.concurrencyLevel.intValue());
132     assertNull(spec.keyStrength);
133     assertNull(spec.valueStrength);
134     assertNull(spec.writeExpirationTimeUnit);
135     assertNull(spec.accessExpirationTimeUnit);
136     assertCacheBuilderEquivalence(
137         CacheBuilder.newBuilder().concurrencyLevel(32), CacheBuilder.from(spec));
138   }
139 
140   public void testParse_concurrencyLevelRepeated() {
141     try {
142       parse("concurrencyLevel=10, concurrencyLevel=20");
143       fail("Expected exception");
144     } catch (IllegalArgumentException expected) {
145       // expected
146     }
147   }
148 
149   public void testParse_weakKeys() {
150     CacheBuilderSpec spec = parse("weakKeys");
151     assertNull(spec.initialCapacity);
152     assertNull(spec.maximumSize);
153     assertNull(spec.maximumWeight);
154     assertNull(spec.concurrencyLevel);
155     assertEquals(Strength.WEAK, spec.keyStrength);
156     assertNull(spec.valueStrength);
157     assertNull(spec.writeExpirationTimeUnit);
158     assertNull(spec.accessExpirationTimeUnit);
159     assertCacheBuilderEquivalence(
160         CacheBuilder.newBuilder().weakKeys(), CacheBuilder.from(spec));
161   }
162 
163   public void testParse_weakKeysCannotHaveValue() {
164     try {
165       parse("weakKeys=true");
166       fail("Expected exception");
167     } catch (IllegalArgumentException expected) {
168       // expected
169     }
170   }
171 
172   public void testParse_repeatedKeyStrength() {
173     try {
174       parse("weakKeys, weakKeys");
175       fail("Expected exception");
176     } catch (IllegalArgumentException expected) {
177       // expected
178     }
179   }
180 
181   public void testParse_softValues() {
182     CacheBuilderSpec spec = parse("softValues");
183     assertNull(spec.initialCapacity);
184     assertNull(spec.maximumSize);
185     assertNull(spec.maximumWeight);
186     assertNull(spec.concurrencyLevel);
187     assertNull(spec.keyStrength);
188     assertEquals(Strength.SOFT, spec.valueStrength);
189     assertNull(spec.writeExpirationTimeUnit);
190     assertNull(spec.accessExpirationTimeUnit);
191     assertCacheBuilderEquivalence(
192         CacheBuilder.newBuilder().softValues(), CacheBuilder.from(spec));
193   }
194 
195   public void testParse_softValuesCannotHaveValue() {
196     try {
197       parse("softValues=true");
198       fail("Expected exception");
199     } catch (IllegalArgumentException expected) {
200       // expected
201     }
202   }
203 
204   public void testParse_weakValues() {
205     CacheBuilderSpec spec = parse("weakValues");
206     assertNull(spec.initialCapacity);
207     assertNull(spec.maximumSize);
208     assertNull(spec.maximumWeight);
209     assertNull(spec.concurrencyLevel);
210     assertNull(spec.keyStrength);
211     assertEquals(Strength.WEAK, spec.valueStrength);
212     assertNull(spec.writeExpirationTimeUnit);
213     assertNull(spec.accessExpirationTimeUnit);
214     assertCacheBuilderEquivalence(
215         CacheBuilder.newBuilder().weakValues(), CacheBuilder.from(spec));
216   }
217 
218   public void testParse_weakValuesCannotHaveValue() {
219     try {
220       parse("weakValues=true");
221       fail("Expected exception");
222     } catch (IllegalArgumentException expected) {
223       // expected
224     }
225   }
226 
227   public void testParse_repeatedValueStrength() {
228     try {
229       parse("softValues, softValues");
230       fail("Expected exception");
231     } catch (IllegalArgumentException expected) {
232       // expected
233     }
234 
235     try {
236       parse("softValues, weakValues");
237       fail("Expected exception");
238     } catch (IllegalArgumentException expected) {
239       // expected
240     }
241 
242     try {
243       parse("weakValues, softValues");
244       fail("Expected exception");
245     } catch (IllegalArgumentException expected) {
246       // expected
247     }
248 
249     try {
250       parse("weakValues, weakValues");
251       fail("Expected exception");
252     } catch (IllegalArgumentException expected) {
253       // expected
254     }
255   }
256 
257   public void testParse_writeExpirationDays() {
258     CacheBuilderSpec spec = parse("expireAfterWrite=10d");
259     assertNull(spec.initialCapacity);
260     assertNull(spec.maximumSize);
261     assertNull(spec.maximumWeight);
262     assertNull(spec.concurrencyLevel);
263     assertNull(spec.keyStrength);
264     assertNull(spec.valueStrength);
265     assertEquals(TimeUnit.DAYS, spec.writeExpirationTimeUnit);
266     assertEquals(10L, spec.writeExpirationDuration);
267     assertNull(spec.accessExpirationTimeUnit);
268     assertCacheBuilderEquivalence(
269         CacheBuilder.newBuilder().expireAfterWrite(10L, TimeUnit.DAYS), CacheBuilder.from(spec));
270   }
271 
272   public void testParse_writeExpirationHours() {
273     CacheBuilderSpec spec = parse("expireAfterWrite=150h");
274     assertEquals(TimeUnit.HOURS, spec.writeExpirationTimeUnit);
275     assertEquals(150L, spec.writeExpirationDuration);
276     assertCacheBuilderEquivalence(
277         CacheBuilder.newBuilder().expireAfterWrite(150L, TimeUnit.HOURS), CacheBuilder.from(spec));
278   }
279 
280   public void testParse_writeExpirationMinutes() {
281     CacheBuilderSpec spec = parse("expireAfterWrite=10m");
282     assertEquals(TimeUnit.MINUTES, spec.writeExpirationTimeUnit);
283     assertEquals(10L, spec.writeExpirationDuration);
284     assertCacheBuilderEquivalence(
285         CacheBuilder.newBuilder().expireAfterWrite(10L, TimeUnit.MINUTES), CacheBuilder.from(spec));
286   }
287 
288   public void testParse_writeExpirationSeconds() {
289     CacheBuilderSpec spec = parse("expireAfterWrite=10s");
290     assertEquals(TimeUnit.SECONDS, spec.writeExpirationTimeUnit);
291     assertEquals(10L, spec.writeExpirationDuration);
292     assertCacheBuilderEquivalence(
293         CacheBuilder.newBuilder().expireAfterWrite(10L, TimeUnit.SECONDS), CacheBuilder.from(spec));
294   }
295 
296   public void testParse_writeExpirationRepeated() {
297     try {
298       parse(
299           "expireAfterWrite=10s,expireAfterWrite=10m");
300       fail("Expected exception");
301     } catch (IllegalArgumentException expected) {
302       // expected
303     }
304   }
305 
306   public void testParse_accessExpirationDays() {
307     CacheBuilderSpec spec = parse("expireAfterAccess=10d");
308     assertNull(spec.initialCapacity);
309     assertNull(spec.maximumSize);
310     assertNull(spec.maximumWeight);
311     assertNull(spec.concurrencyLevel);
312     assertNull(spec.keyStrength);
313     assertNull(spec.valueStrength);
314     assertNull(spec.writeExpirationTimeUnit);
315     assertEquals(TimeUnit.DAYS, spec.accessExpirationTimeUnit);
316     assertEquals(10L, spec.accessExpirationDuration);
317     assertCacheBuilderEquivalence(
318         CacheBuilder.newBuilder().expireAfterAccess(10L, TimeUnit.DAYS), CacheBuilder.from(spec));
319   }
320 
321   public void testParse_accessExpirationHours() {
322     CacheBuilderSpec spec = parse("expireAfterAccess=150h");
323     assertEquals(TimeUnit.HOURS, spec.accessExpirationTimeUnit);
324     assertEquals(150L, spec.accessExpirationDuration);
325     assertCacheBuilderEquivalence(
326         CacheBuilder.newBuilder().expireAfterAccess(150L, TimeUnit.HOURS), CacheBuilder.from(spec));
327   }
328 
329   public void testParse_accessExpirationMinutes() {
330     CacheBuilderSpec spec = parse("expireAfterAccess=10m");
331     assertEquals(TimeUnit.MINUTES, spec.accessExpirationTimeUnit);
332     assertEquals(10L, spec.accessExpirationDuration);
333     assertCacheBuilderEquivalence(
334         CacheBuilder.newBuilder().expireAfterAccess(10L, TimeUnit.MINUTES),
335         CacheBuilder.from(spec));
336   }
337 
338   public void testParse_accessExpirationSeconds() {
339     CacheBuilderSpec spec = parse("expireAfterAccess=10s");
340     assertEquals(TimeUnit.SECONDS, spec.accessExpirationTimeUnit);
341     assertEquals(10L, spec.accessExpirationDuration);
342     assertCacheBuilderEquivalence(
343         CacheBuilder.newBuilder().expireAfterAccess(10L, TimeUnit.SECONDS),
344         CacheBuilder.from(spec));
345   }
346 
347   public void testParse_accessExpirationRepeated() {
348     try {
349       parse(
350           "expireAfterAccess=10s,expireAfterAccess=10m");
351       fail("Expected exception");
352     } catch (IllegalArgumentException expected) {
353       // expected
354     }
355   }
356 
357   public void testParse_recordStats() {
358     CacheBuilderSpec spec = parse("recordStats");
359     assertTrue(spec.recordStats);
360     assertCacheBuilderEquivalence(CacheBuilder.newBuilder().recordStats(), CacheBuilder.from(spec));
361   }
362 
363   public void testParse_recordStatsValueSpecified() {
364     try {
365       parse("recordStats=True");
366       fail("Expected exception");
367     } catch (IllegalArgumentException expected) {
368       // expected
369     }
370   }
371 
372   public void testParse_recordStatsRepeated() {
373     try {
374       parse("recordStats,recordStats");
375       fail("Expected exception");
376     } catch (IllegalArgumentException expected) {
377       // expected
378     }
379   }
380 
381   public void testParse_accessExpirationAndWriteExpiration() {
382     CacheBuilderSpec spec = parse("expireAfterAccess=10s,expireAfterWrite=9m");
383     assertEquals(TimeUnit.MINUTES, spec.writeExpirationTimeUnit);
384     assertEquals(9L, spec.writeExpirationDuration);
385     assertEquals(TimeUnit.SECONDS, spec.accessExpirationTimeUnit);
386     assertEquals(10L, spec.accessExpirationDuration);
387     assertCacheBuilderEquivalence(
388         CacheBuilder.newBuilder()
389           .expireAfterAccess(10L, TimeUnit.SECONDS)
390           .expireAfterWrite(9L, TimeUnit.MINUTES),
391         CacheBuilder.from(spec));
392   }
393 
394   public void testParse_multipleKeys() {
395     CacheBuilderSpec spec = parse("initialCapacity=10,maximumSize=20,concurrencyLevel=30,"
396         + "weakKeys,weakValues,expireAfterAccess=10m,expireAfterWrite=1h");
397     assertEquals(10, spec.initialCapacity.intValue());
398     assertEquals(20, spec.maximumSize.intValue());
399     assertNull(spec.maximumWeight);
400     assertEquals(30, spec.concurrencyLevel.intValue());
401     assertEquals(Strength.WEAK, spec.keyStrength);
402     assertEquals(Strength.WEAK, spec.valueStrength);
403     assertEquals(TimeUnit.HOURS, spec.writeExpirationTimeUnit);
404     assertEquals(TimeUnit.MINUTES, spec.accessExpirationTimeUnit);
405     assertEquals(1L, spec.writeExpirationDuration);
406     assertEquals(10L, spec.accessExpirationDuration);
407     CacheBuilder<?, ?> expected = CacheBuilder.newBuilder()
408         .initialCapacity(10)
409         .maximumSize(20)
410         .concurrencyLevel(30)
411         .weakKeys()
412         .weakValues()
413         .expireAfterAccess(10L, TimeUnit.MINUTES)
414         .expireAfterWrite(1L, TimeUnit.HOURS);
415     assertCacheBuilderEquivalence(expected, CacheBuilder.from(spec));
416   }
417 
418   public void testParse_whitespaceAllowed() {
419     CacheBuilderSpec spec = parse(" initialCapacity=10,\nmaximumSize=20,\t\r"
420         + "weakKeys \t ,softValues \n , \r  expireAfterWrite \t =  15s\n\n");
421     assertEquals(10, spec.initialCapacity.intValue());
422     assertEquals(20, spec.maximumSize.intValue());
423     assertNull(spec.maximumWeight);
424     assertNull(spec.concurrencyLevel);
425     assertEquals(Strength.WEAK, spec.keyStrength);
426     assertEquals(Strength.SOFT, spec.valueStrength);
427     assertEquals(TimeUnit.SECONDS, spec.writeExpirationTimeUnit);
428     assertEquals(15L, spec.writeExpirationDuration);
429     assertNull(spec.accessExpirationTimeUnit);
430     CacheBuilder<?, ?> expected = CacheBuilder.newBuilder()
431         .initialCapacity(10)
432         .maximumSize(20)
433         .weakKeys()
434         .softValues()
435         .expireAfterWrite(15L, TimeUnit.SECONDS);
436     assertCacheBuilderEquivalence(expected, CacheBuilder.from(spec));
437   }
438 
439   public void testParse_unknownKey() {
440     try {
441       parse("foo=17");
442       fail("Expected exception");
443     } catch (IllegalArgumentException expected) {
444       // expected
445     }
446   }
447 
448   public void testParse_extraCommaIsInvalid() {
449     try {
450       parse("weakKeys,");
451       fail("Expected exception");
452     } catch (IllegalArgumentException expected) {
453       // expected
454     }
455 
456     try {
457       parse(",weakKeys");
458       fail("Expected exception");
459     } catch (IllegalArgumentException expected) {
460       // expected
461     }
462 
463     try {
464       parse("weakKeys,,softValues");
465       fail("Expected exception");
466     } catch (IllegalArgumentException expected) {
467       // expected
468     }
469   }
470 
471   public void testEqualsAndHashCode() {
472     new EqualsTester()
473         .addEqualityGroup(parse(""), parse(""))
474         .addEqualityGroup(parse("concurrencyLevel=7"), parse("concurrencyLevel=7"))
475         .addEqualityGroup(parse("concurrencyLevel=15"), parse("concurrencyLevel=15"))
476         .addEqualityGroup(parse("initialCapacity=7"), parse("initialCapacity=7"))
477         .addEqualityGroup(parse("initialCapacity=15"), parse("initialCapacity=15"))
478         .addEqualityGroup(parse("maximumSize=7"), parse("maximumSize=7"))
479         .addEqualityGroup(parse("maximumSize=15"), parse("maximumSize=15"))
480         .addEqualityGroup(parse("maximumWeight=7"), parse("maximumWeight=7"))
481         .addEqualityGroup(parse("maximumWeight=15"), parse("maximumWeight=15"))
482         .addEqualityGroup(parse("expireAfterAccess=60s"), parse("expireAfterAccess=1m"))
483         .addEqualityGroup(parse("expireAfterAccess=60m"), parse("expireAfterAccess=1h"))
484         .addEqualityGroup(parse("expireAfterWrite=60s"), parse("expireAfterWrite=1m"))
485         .addEqualityGroup(parse("expireAfterWrite=60m"), parse("expireAfterWrite=1h"))
486         .addEqualityGroup(parse("weakKeys"), parse("weakKeys"))
487         .addEqualityGroup(parse("softValues"), parse("softValues"))
488         .addEqualityGroup(parse("weakValues"), parse("weakValues"))
489         .addEqualityGroup(parse("recordStats"), parse("recordStats"))
490         .testEquals();
491   }
492 
493   public void testMaximumWeight_withWeigher() {
494     CacheBuilder<Object, Object> builder = CacheBuilder.from(parse("maximumWeight=9000"));
495     builder
496         .weigher(constantWeigher(42))
497         .build(CacheLoader.from(Suppliers.ofInstance(null)));
498   }
499 
500   public void testMaximumWeight_withoutWeigher() {
501     CacheBuilder<Object, Object> builder = CacheBuilder.from(parse("maximumWeight=9000"));
502     try {
503       builder.build(CacheLoader.from(Suppliers.ofInstance(null)));
504       fail();
505     } catch (IllegalStateException expected) {}
506   }
507 
508   public void testMaximumSize_withWeigher() {
509     CacheBuilder<Object, Object> builder = CacheBuilder.from(parse("maximumSize=9000"));
510     builder
511         .weigher(constantWeigher(42))
512         .build(CacheLoader.from(Suppliers.ofInstance(null)));
513   }
514 
515   public void testMaximumSize_withoutWeigher() {
516     CacheBuilder<Object, Object> builder = CacheBuilder.from(parse("maximumSize=9000"));
517     builder.build(CacheLoader.from(Suppliers.ofInstance(null)));
518   }
519 
520   public void testDisableCaching() {
521     // Functional test: assert that CacheBuilderSpec.disableCaching()
522     // disables caching.  It's irrelevant how it does so.
523     CacheBuilder<Object, Object> builder = CacheBuilder.from(CacheBuilderSpec.disableCaching());
524     Object key = new Object();
525     Object value = new Object();
526     LoadingCache<Object, Object> cache = builder.build(
527         CacheLoader.from(Suppliers.ofInstance(value)));
528     assertSame(value, cache.getUnchecked(key));
529     assertEquals(0, cache.size());
530     assertFalse(cache.asMap().containsKey(key));
531   }
532 
533   public void testCacheBuilderFrom_string() {
534     CacheBuilder<?, ?> fromString = CacheBuilder.from(
535         "initialCapacity=10,maximumSize=20,concurrencyLevel=30,"
536         + "weakKeys,weakValues,expireAfterAccess=10m");
537     CacheBuilder<?, ?> expected = CacheBuilder.newBuilder()
538         .initialCapacity(10)
539         .maximumSize(20)
540         .concurrencyLevel(30)
541         .weakKeys()
542         .weakValues()
543         .expireAfterAccess(10L, TimeUnit.MINUTES);
544     assertCacheBuilderEquivalence(expected, fromString);
545   }
546 
547   private static void assertCacheBuilderEquivalence(CacheBuilder<?, ?> a, CacheBuilder<?, ?> b) {
548     assertEquals("concurrencyLevel", a.concurrencyLevel, b.concurrencyLevel);
549     assertEquals("expireAfterAccessNanos", a.expireAfterAccessNanos, b.expireAfterAccessNanos);
550     assertEquals("expireAfterWriteNanos", a.expireAfterWriteNanos, b.expireAfterWriteNanos);
551     assertEquals("initialCapacity", a.initialCapacity, b.initialCapacity);
552     assertEquals("maximumSize", a.maximumSize, b.maximumSize);
553     assertEquals("maximumWeight", a.maximumWeight, b.maximumWeight);
554     assertEquals("refreshNanos", a.refreshNanos, b.refreshNanos);
555     assertEquals("keyEquivalence", a.keyEquivalence, b.keyEquivalence);
556     assertEquals("keyStrength", a.keyStrength, b.keyStrength);
557     assertEquals("removalListener", a.removalListener, b.removalListener);
558     assertEquals("weigher", a.weigher, b.weigher);
559     assertEquals("valueEquivalence", a.valueEquivalence, b.valueEquivalence);
560     assertEquals("valueStrength", a.valueStrength, b.valueStrength);
561     assertEquals("statsCounterSupplier", a.statsCounterSupplier, b.statsCounterSupplier);
562     assertEquals("ticker", a.ticker, b.ticker);
563     assertEquals("recordStats", a.isRecordingStats(), b.isRecordingStats());
564   }
565 }