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
15package com.google.common.collect;
16
17import static com.google.common.collect.BoundType.OPEN;
18
19import com.google.common.annotations.GwtIncompatible;
20
21import junit.framework.TestCase;
22
23import java.util.Map;
24import java.util.Map.Entry;
25import java.util.NoSuchElementException;
26
27/**
28 * Tests for {@code ImmutableRangeMap}.
29 *
30 * @author Louis Wasserman
31 */
32@GwtIncompatible("NavigableMap")
33public class ImmutableRangeMapTest extends TestCase {
34  private static final ImmutableList<Range<Integer>> RANGES;
35  private static final int MIN_BOUND = 0;
36  private static final int MAX_BOUND = 10;
37  static {
38    ImmutableList.Builder<Range<Integer>> builder = ImmutableList.builder();
39
40    builder.add(Range.<Integer>all());
41
42    // Add one-ended ranges
43    for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
44      for (BoundType type : BoundType.values()) {
45        builder.add(Range.upTo(i, type));
46        builder.add(Range.downTo(i, type));
47      }
48    }
49
50    // Add two-ended ranges
51    for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
52      for (int j = i + 1; j <= MAX_BOUND; j++) {
53        for (BoundType lowerType : BoundType.values()) {
54          for (BoundType upperType : BoundType.values()) {
55            if (i == j & lowerType == OPEN & upperType == OPEN) {
56              continue;
57            }
58            builder.add(Range.range(i, lowerType, j, upperType));
59          }
60        }
61      }
62    }
63    RANGES = builder.build();
64  }
65
66  public void testBuilderRejectsEmptyRanges() {
67    for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
68      ImmutableRangeMap.Builder<Integer, Integer> builder = ImmutableRangeMap.builder();
69      try {
70        builder.put(Range.closedOpen(i, i), 1);
71        fail("Expected IllegalArgumentException");
72      } catch (IllegalArgumentException expected) {
73        // success
74      }
75      try {
76        builder.put(Range.openClosed(i, i), 1);
77        fail("Expected IllegalArgumentException");
78      } catch (IllegalArgumentException expected) {
79      }
80    }
81  }
82
83  public void testOverlapRejection() {
84    for (Range<Integer> range1 : RANGES) {
85      for (Range<Integer> range2 : RANGES) {
86        boolean expectRejection =
87            range1.isConnected(range2) && !range1.intersection(range2).isEmpty();
88        ImmutableRangeMap.Builder<Integer, Integer> builder = ImmutableRangeMap.builder();
89        builder.put(range1, 1);
90        try {
91          builder.put(range2, 2);
92          assertFalse(expectRejection);
93        } catch (IllegalArgumentException e) {
94          assertTrue(expectRejection);
95        }
96      }
97    }
98  }
99
100  public void testGet() {
101    for (Range<Integer> range1 : RANGES) {
102      for (Range<Integer> range2 : RANGES) {
103        if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
104          ImmutableRangeMap<Integer, Integer> rangeMap =
105              ImmutableRangeMap.<Integer, Integer>builder().put(range1, 1).put(range2, 2).build();
106
107          for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
108            Integer expectedValue = null;
109            if (range1.contains(i)) {
110              expectedValue = 1;
111            } else if (range2.contains(i)) {
112              expectedValue = 2;
113            }
114
115            assertEquals(expectedValue, rangeMap.get(i));
116          }
117        }
118      }
119    }
120  }
121
122  public void testSpanEmpty() {
123    try {
124      ImmutableRangeMap.of().span();
125      fail("Expected NoSuchElementException");
126    } catch (NoSuchElementException expected) {
127    }
128  }
129
130  public void testSpanSingleRange() {
131    for (Range<Integer> range : RANGES) {
132      RangeMap<Integer, Integer> rangemap =
133          ImmutableRangeMap.<Integer, Integer>builder().put(range, 1).build();
134      assertEquals(range, rangemap.span());
135    }
136  }
137
138  public void testSpanTwoRanges() {
139    for (Range<Integer> range1 : RANGES) {
140      for (Range<Integer> range2 : RANGES) {
141        if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
142          RangeMap<Integer, Integer> rangemap =
143              ImmutableRangeMap.<Integer, Integer>builder().put(range1, 1).put(range2, 2).build();
144          assertEquals(range1.span(range2), rangemap.span());
145        }
146      }
147    }
148  }
149
150  public void testGetEntry() {
151    for (Range<Integer> range1 : RANGES) {
152      for (Range<Integer> range2 : RANGES) {
153        if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
154          ImmutableRangeMap<Integer, Integer> rangeMap =
155              ImmutableRangeMap.<Integer, Integer>builder().put(range1, 1).put(range2, 2).build();
156
157          for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
158            Entry<Range<Integer>, Integer> expectedEntry = null;
159            if (range1.contains(i)) {
160              expectedEntry = Maps.immutableEntry(range1, 1);
161            } else if (range2.contains(i)) {
162              expectedEntry = Maps.immutableEntry(range2, 2);
163            }
164
165            assertEquals(expectedEntry, rangeMap.getEntry(i));
166          }
167        }
168      }
169    }
170  }
171
172  public void testGetLargeRangeMap() {
173    ImmutableRangeMap.Builder<Integer, Integer> builder = ImmutableRangeMap.builder();
174    for (int i = 0; i < 100; i++) {
175      builder.put(Range.closedOpen(i, i + 1), i);
176    }
177    ImmutableRangeMap<Integer, Integer> map = builder.build();
178    for (int i = 0; i < 100; i++) {
179      assertEquals(Integer.valueOf(i), map.get(i));
180    }
181  }
182
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          assertEquals(expectedAsMap, asMap);
194
195          for (Range<Integer> query : RANGES) {
196            assertEquals(expectedAsMap.get(query), asMap.get(query));
197          }
198        }
199      }
200    }
201  }
202
203  public void testSubRangeMap() {
204    for (Range<Integer> range1 : RANGES) {
205      for (Range<Integer> range2 : RANGES) {
206        if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) {
207          for (Range<Integer> subRange : RANGES) {
208            ImmutableRangeMap<Integer, Integer> rangeMap =
209                ImmutableRangeMap.<Integer, Integer>builder()
210                  .put(range1, 1).put(range2, 2).build();
211
212            ImmutableRangeMap.Builder<Integer, Integer> expectedBuilder =
213                ImmutableRangeMap.builder();
214            for (Map.Entry<Range<Integer>, Integer> entry : rangeMap.asMapOfRanges().entrySet()) {
215              if (entry.getKey().isConnected(subRange)
216                  && !entry.getKey().intersection(subRange).isEmpty()) {
217                expectedBuilder.put(entry.getKey().intersection(subRange), entry.getValue());
218              }
219            }
220
221            ImmutableRangeMap<Integer, Integer> expected = expectedBuilder.build();
222            assertEquals(expected, rangeMap.subRangeMap(subRange));
223          }
224        }
225      }
226    }
227  }
228}
229