1 /*
2  * Copyright (C) 2012 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.google.common.collect;
16 
17 import static com.google.common.collect.BoundType.OPEN;
18 
19 import com.google.common.annotations.GwtIncompatible;
20 import com.google.common.testing.SerializableTester;
21 import java.util.Map.Entry;
22 import java.util.NoSuchElementException;
23 import junit.framework.TestCase;
24 
25 /**
26  * Tests for {@code ImmutableRangeMap}.
27  *
28  * @author Louis Wasserman
29  */
30 @GwtIncompatible // NavigableMap
31 public class ImmutableRangeMapTest extends TestCase {
32   private static final ImmutableList<Range<Integer>> RANGES;
33   private static final int MIN_BOUND = 0;
34   private static final int MAX_BOUND = 10;
35 
36   static {
37     ImmutableList.Builder<Range<Integer>> builder = ImmutableList.builder();
38 
all()39     builder.add(Range.<Integer>all());
40 
41     // Add one-ended ranges
42     for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
43       for (BoundType type : BoundType.values()) {
Range.upTo(i, type)44         builder.add(Range.upTo(i, type));
Range.downTo(i, type)45         builder.add(Range.downTo(i, type));
46       }
47     }
48 
49     // Add two-ended ranges
50     for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
51       for (int j = i + 1; j <= MAX_BOUND; j++) {
52         for (BoundType lowerType : BoundType.values()) {
53           for (BoundType upperType : BoundType.values()) {
54             if (i == j & lowerType == OPEN & upperType == OPEN) {
55               continue;
56             }
Range.range(i, lowerType, j, upperType)57             builder.add(Range.range(i, lowerType, j, upperType));
58           }
59         }
60       }
61     }
62     RANGES = builder.build();
63   }
64 
testBuilderRejectsEmptyRanges()65   public void testBuilderRejectsEmptyRanges() {
66     for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
67       ImmutableRangeMap.Builder<Integer, Integer> builder = ImmutableRangeMap.builder();
68       try {
69         builder.put(Range.closedOpen(i, i), 1);
70         fail("Expected IllegalArgumentException");
71       } catch (IllegalArgumentException expected) {
72         // success
73       }
74       try {
75         builder.put(Range.openClosed(i, i), 1);
76         fail("Expected IllegalArgumentException");
77       } catch (IllegalArgumentException expected) {
78       }
79     }
80   }
81 
testOverlapRejection()82   public void testOverlapRejection() {
83     for (Range<Integer> range1 : RANGES) {
84       for (Range<Integer> range2 : RANGES) {
85         boolean expectRejection =
86             range1.isConnected(range2) && !range1.intersection(range2).isEmpty();
87         ImmutableRangeMap.Builder<Integer, Integer> builder = ImmutableRangeMap.builder();
88         builder.put(range1, 1).put(range2, 2);
89         try {
90           ImmutableRangeMap<Integer, Integer> unused = builder.build();
91           assertFalse(expectRejection);
92         } catch (IllegalArgumentException e) {
93           assertTrue(expectRejection);
94         }
95       }
96     }
97   }
98 
testGet()99   public void testGet() {
100     for (Range<Integer> range1 : RANGES) {
101       for (Range<Integer> range2 : RANGES) {
102         if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
103           ImmutableRangeMap<Integer, Integer> rangeMap =
104               ImmutableRangeMap.<Integer, Integer>builder().put(range1, 1).put(range2, 2).build();
105 
106           for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
107             Integer expectedValue = null;
108             if (range1.contains(i)) {
109               expectedValue = 1;
110             } else if (range2.contains(i)) {
111               expectedValue = 2;
112             }
113 
114             assertEquals(expectedValue, rangeMap.get(i));
115           }
116         }
117       }
118     }
119   }
120 
testSpanEmpty()121   public void testSpanEmpty() {
122     try {
123       ImmutableRangeMap.of().span();
124       fail("Expected NoSuchElementException");
125     } catch (NoSuchElementException expected) {
126     }
127   }
128 
testSpanSingleRange()129   public void testSpanSingleRange() {
130     for (Range<Integer> range : RANGES) {
131       RangeMap<Integer, Integer> rangemap =
132           ImmutableRangeMap.<Integer, Integer>builder().put(range, 1).build();
133       assertEquals(range, rangemap.span());
134     }
135   }
136 
testSpanTwoRanges()137   public void testSpanTwoRanges() {
138     for (Range<Integer> range1 : RANGES) {
139       for (Range<Integer> range2 : RANGES) {
140         if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
141           RangeMap<Integer, Integer> rangemap =
142               ImmutableRangeMap.<Integer, Integer>builder().put(range1, 1).put(range2, 2).build();
143           assertEquals(range1.span(range2), rangemap.span());
144         }
145       }
146     }
147   }
148 
testGetEntry()149   public void testGetEntry() {
150     for (Range<Integer> range1 : RANGES) {
151       for (Range<Integer> range2 : RANGES) {
152         if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
153           ImmutableRangeMap<Integer, Integer> rangeMap =
154               ImmutableRangeMap.<Integer, Integer>builder().put(range1, 1).put(range2, 2).build();
155 
156           for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
157             Entry<Range<Integer>, Integer> expectedEntry = null;
158             if (range1.contains(i)) {
159               expectedEntry = Maps.immutableEntry(range1, 1);
160             } else if (range2.contains(i)) {
161               expectedEntry = Maps.immutableEntry(range2, 2);
162             }
163 
164             assertEquals(expectedEntry, rangeMap.getEntry(i));
165           }
166         }
167       }
168     }
169   }
170 
testGetLargeRangeMap()171   public void testGetLargeRangeMap() {
172     ImmutableRangeMap.Builder<Integer, Integer> builder = ImmutableRangeMap.builder();
173     for (int i = 0; i < 100; i++) {
174       builder.put(Range.closedOpen(i, i + 1), i);
175     }
176     ImmutableRangeMap<Integer, Integer> map = builder.build();
177     for (int i = 0; i < 100; i++) {
178       assertEquals(Integer.valueOf(i), map.get(i));
179     }
180   }
181 
182   @AndroidIncompatible // slow
testAsMapOfRanges()183   public void testAsMapOfRanges() {
184     for (Range<Integer> range1 : RANGES) {
185       for (Range<Integer> range2 : RANGES) {
186         if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
187           ImmutableRangeMap<Integer, Integer> rangeMap =
188               ImmutableRangeMap.<Integer, Integer>builder().put(range1, 1).put(range2, 2).build();
189 
190           ImmutableMap<Range<Integer>, Integer> expectedAsMap =
191               ImmutableMap.of(range1, 1, range2, 2);
192           ImmutableMap<Range<Integer>, Integer> asMap = rangeMap.asMapOfRanges();
193           ImmutableMap<Range<Integer>, Integer> descendingMap = rangeMap.asDescendingMapOfRanges();
194           assertEquals(expectedAsMap, asMap);
195           assertEquals(expectedAsMap, descendingMap);
196           SerializableTester.reserializeAndAssert(asMap);
197           SerializableTester.reserializeAndAssert(descendingMap);
198           assertEquals(
199               ImmutableList.copyOf(asMap.entrySet()).reverse(),
200               ImmutableList.copyOf(descendingMap.entrySet()));
201 
202           for (Range<Integer> query : RANGES) {
203             assertEquals(expectedAsMap.get(query), asMap.get(query));
204           }
205         }
206       }
207     }
208   }
209 
testSubRangeMap()210   public void testSubRangeMap() {
211     for (Range<Integer> range1 : RANGES) {
212       for (Range<Integer> range2 : RANGES) {
213         if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
214           for (Range<Integer> subRange : RANGES) {
215             ImmutableRangeMap<Integer, Integer> rangeMap =
216                 ImmutableRangeMap.<Integer, Integer>builder().put(range1, 1).put(range2, 2).build();
217 
218             ImmutableRangeMap.Builder<Integer, Integer> expectedBuilder =
219                 ImmutableRangeMap.builder();
220             for (Entry<Range<Integer>, Integer> entry : rangeMap.asMapOfRanges().entrySet()) {
221               if (entry.getKey().isConnected(subRange)
222                   && !entry.getKey().intersection(subRange).isEmpty()) {
223                 expectedBuilder.put(entry.getKey().intersection(subRange), entry.getValue());
224               }
225             }
226 
227             ImmutableRangeMap<Integer, Integer> expected = expectedBuilder.build();
228             assertEquals(expected, rangeMap.subRangeMap(subRange));
229           }
230         }
231       }
232     }
233   }
234 
testSerialization()235   public void testSerialization() {
236     ImmutableRangeMap<Integer, Integer> emptyRangeMap = ImmutableRangeMap.of();
237     SerializableTester.reserializeAndAssert(emptyRangeMap);
238 
239     ImmutableRangeMap<Integer, Integer> nonEmptyRangeMap =
240         new ImmutableRangeMap.Builder<Integer, Integer>()
241             .put(Range.closed(2, 4), 5)
242             .put(Range.open(6, 7), 3)
243             .put(Range.closedOpen(8, 10), 4)
244             .put(Range.openClosed(15, 17), 2)
245             .build();
246 
247     ImmutableMap<Range<Integer>, Integer> test = nonEmptyRangeMap.asMapOfRanges();
248 
249     for (Range<Integer> range : test.keySet()) {
250       SerializableTester.reserializeAndAssert(range);
251     }
252 
253     SerializableTester.reserializeAndAssert(test.keySet());
254 
255     SerializableTester.reserializeAndAssert(nonEmptyRangeMap);
256   }
257 }
258