001/*
002 * Copyright (C) 2010 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect.testing.testers;
018
019import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
020import static com.google.common.collect.testing.features.CollectionSize.ONE;
021import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
022import static com.google.common.collect.testing.features.CollectionSize.ZERO;
023import static org.junit.Assert.assertThrows;
024
025import com.google.common.annotations.GwtIncompatible;
026import com.google.common.collect.testing.Helpers;
027import com.google.common.collect.testing.features.CollectionFeature;
028import com.google.common.collect.testing.features.CollectionSize;
029import java.lang.reflect.Method;
030import java.util.ArrayList;
031import java.util.Collections;
032import java.util.Iterator;
033import java.util.List;
034import java.util.NavigableSet;
035import java.util.TreeSet;
036import org.junit.Ignore;
037
038/**
039 * A generic JUnit test which tests operations on a NavigableSet. Can't be invoked directly; please
040 * see {@code NavigableSetTestSuiteBuilder}.
041 *
042 * @author Jesse Wilson
043 * @author Louis Wasserman
044 */
045@GwtIncompatible
046@Ignore // Affects only Android test runner, which respects JUnit 4 annotations on JUnit 3 tests.
047@SuppressWarnings("JUnit4ClassUsedInJUnit3")
048public class NavigableSetNavigationTester<E> extends AbstractSetTester<E> {
049
050  private NavigableSet<E> navigableSet;
051  private List<E> values;
052  private E a;
053  private E b;
054  private E c;
055
056  @Override
057  public void setUp() throws Exception {
058    super.setUp();
059    navigableSet = (NavigableSet<E>) getSet();
060    values =
061        Helpers.copyToList(
062            getSubjectGenerator()
063                .getSampleElements(getSubjectGenerator().getCollectionSize().getNumElements()));
064    Collections.sort(values, navigableSet.comparator());
065
066    // some tests assume SEVERAL == 3
067    if (values.size() >= 1) {
068      a = values.get(0);
069      if (values.size() >= 3) {
070        b = values.get(1);
071        c = values.get(2);
072      }
073    }
074  }
075
076  /** Resets the contents of navigableSet to have elements a, c, for the navigation tests. */
077  protected void resetWithHole() {
078    super.resetContainer(getSubjectGenerator().create(a, c));
079    navigableSet = (NavigableSet<E>) getSet();
080  }
081
082  @CollectionFeature.Require(SUPPORTS_REMOVE)
083  @CollectionSize.Require(ZERO)
084  public void testEmptySetPollFirst() {
085    assertNull(navigableSet.pollFirst());
086  }
087
088  @CollectionSize.Require(ZERO)
089  public void testEmptySetNearby() {
090    assertNull(navigableSet.lower(e0()));
091    assertNull(navigableSet.floor(e0()));
092    assertNull(navigableSet.ceiling(e0()));
093    assertNull(navigableSet.higher(e0()));
094  }
095
096  @CollectionFeature.Require(SUPPORTS_REMOVE)
097  @CollectionSize.Require(ZERO)
098  public void testEmptySetPollLast() {
099    assertNull(navigableSet.pollLast());
100  }
101
102  @CollectionFeature.Require(SUPPORTS_REMOVE)
103  @CollectionSize.Require(ONE)
104  public void testSingletonSetPollFirst() {
105    assertEquals(a, navigableSet.pollFirst());
106    assertTrue(navigableSet.isEmpty());
107  }
108
109  @CollectionSize.Require(ONE)
110  public void testSingletonSetNearby() {
111    assertNull(navigableSet.lower(e0()));
112    assertEquals(a, navigableSet.floor(e0()));
113    assertEquals(a, navigableSet.ceiling(e0()));
114    assertNull(navigableSet.higher(e0()));
115  }
116
117  @CollectionFeature.Require(SUPPORTS_REMOVE)
118  @CollectionSize.Require(ONE)
119  public void testSingletonSetPollLast() {
120    assertEquals(a, navigableSet.pollLast());
121    assertTrue(navigableSet.isEmpty());
122  }
123
124  @CollectionFeature.Require(SUPPORTS_REMOVE)
125  @CollectionSize.Require(SEVERAL)
126  public void testPollFirst() {
127    assertEquals(a, navigableSet.pollFirst());
128    assertEquals(values.subList(1, values.size()), Helpers.copyToList(navigableSet));
129  }
130
131  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
132  public void testPollFirstUnsupported() {
133    assertThrows(UnsupportedOperationException.class, () -> navigableSet.pollFirst());
134  }
135
136  @CollectionSize.Require(SEVERAL)
137  public void testLowerHole() {
138    resetWithHole();
139    assertEquals(null, navigableSet.lower(a));
140    assertEquals(a, navigableSet.lower(b));
141    assertEquals(a, navigableSet.lower(c));
142  }
143
144  @CollectionSize.Require(SEVERAL)
145  public void testFloorHole() {
146    resetWithHole();
147    assertEquals(a, navigableSet.floor(a));
148    assertEquals(a, navigableSet.floor(b));
149    assertEquals(c, navigableSet.floor(c));
150  }
151
152  @CollectionSize.Require(SEVERAL)
153  public void testCeilingHole() {
154    resetWithHole();
155    assertEquals(a, navigableSet.ceiling(a));
156    assertEquals(c, navigableSet.ceiling(b));
157    assertEquals(c, navigableSet.ceiling(c));
158  }
159
160  @CollectionSize.Require(SEVERAL)
161  public void testHigherHole() {
162    resetWithHole();
163    assertEquals(c, navigableSet.higher(a));
164    assertEquals(c, navigableSet.higher(b));
165    assertEquals(null, navigableSet.higher(c));
166  }
167
168  /*
169   * TODO(cpovirk): make "too small" and "too large" elements available for better navigation
170   * testing. At that point, we may be able to eliminate the "hole" tests, which would mean that
171   * ContiguousSet's tests would no longer need to suppress them.
172   */
173  @CollectionSize.Require(SEVERAL)
174  public void testLower() {
175    assertEquals(null, navigableSet.lower(a));
176    assertEquals(a, navigableSet.lower(b));
177    assertEquals(b, navigableSet.lower(c));
178  }
179
180  @CollectionSize.Require(SEVERAL)
181  public void testFloor() {
182    assertEquals(a, navigableSet.floor(a));
183    assertEquals(b, navigableSet.floor(b));
184    assertEquals(c, navigableSet.floor(c));
185  }
186
187  @CollectionSize.Require(SEVERAL)
188  public void testCeiling() {
189    assertEquals(a, navigableSet.ceiling(a));
190    assertEquals(b, navigableSet.ceiling(b));
191    assertEquals(c, navigableSet.ceiling(c));
192  }
193
194  @CollectionSize.Require(SEVERAL)
195  public void testHigher() {
196    assertEquals(b, navigableSet.higher(a));
197    assertEquals(c, navigableSet.higher(b));
198    assertEquals(null, navigableSet.higher(c));
199  }
200
201  @CollectionFeature.Require(SUPPORTS_REMOVE)
202  @CollectionSize.Require(SEVERAL)
203  public void testPollLast() {
204    assertEquals(c, navigableSet.pollLast());
205    assertEquals(values.subList(0, values.size() - 1), Helpers.copyToList(navigableSet));
206  }
207
208  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
209  public void testPollLastUnsupported() {
210    assertThrows(UnsupportedOperationException.class, () -> navigableSet.pollLast());
211  }
212
213  @CollectionSize.Require(SEVERAL)
214  public void testDescendingNavigation() {
215    List<E> descending = new ArrayList<>();
216    for (Iterator<E> i = navigableSet.descendingIterator(); i.hasNext(); ) {
217      descending.add(i.next());
218    }
219    Collections.reverse(descending);
220    assertEquals(values, descending);
221  }
222
223  public void testEmptySubSet() {
224    NavigableSet<E> empty = navigableSet.subSet(e0(), false, e0(), false);
225    assertEquals(new TreeSet<E>(), empty);
226  }
227
228  /*
229   * TODO(cpovirk): more testing of subSet/headSet/tailSet/descendingSet? and/or generate derived
230   * suites?
231   */
232
233  /**
234   * Returns the {@link Method} instances for the test methods in this class that create a set with
235   * a "hole" in it so that set tests of {@code ContiguousSet} can suppress them with {@code
236   * FeatureSpecificTestSuiteBuilder.suppressing()}.
237   */
238  /*
239   * TODO(cpovirk): or we could make HOLES_FORBIDDEN a feature. Or we could declare that
240   * implementations are permitted to throw IAE if a hole is requested, and we could update
241   * test*Hole to permit IAE. (But might this ignore genuine bugs?) But see the TODO above
242   * testLower, which could make this all unnecessary
243   */
244  public static Method[] getHoleMethods() {
245    return new Method[] {
246      Helpers.getMethod(NavigableSetNavigationTester.class, "testLowerHole"),
247      Helpers.getMethod(NavigableSetNavigationTester.class, "testFloorHole"),
248      Helpers.getMethod(NavigableSetNavigationTester.class, "testCeilingHole"),
249      Helpers.getMethod(NavigableSetNavigationTester.class, "testHigherHole"),
250    };
251  }
252}