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.
047public class NavigableSetNavigationTester<E> extends AbstractSetTester<E> {
048
049  private NavigableSet<E> navigableSet;
050  private List<E> values;
051  private E a;
052  private E b;
053  private E c;
054
055  @Override
056  public void setUp() throws Exception {
057    super.setUp();
058    navigableSet = (NavigableSet<E>) getSet();
059    values =
060        Helpers.copyToList(
061            getSubjectGenerator()
062                .getSampleElements(getSubjectGenerator().getCollectionSize().getNumElements()));
063    Collections.sort(values, navigableSet.comparator());
064
065    // some tests assume SEVERAL == 3
066    if (values.size() >= 1) {
067      a = values.get(0);
068      if (values.size() >= 3) {
069        b = values.get(1);
070        c = values.get(2);
071      }
072    }
073  }
074
075  /** Resets the contents of navigableSet to have elements a, c, for the navigation tests. */
076  protected void resetWithHole() {
077    super.resetContainer(getSubjectGenerator().create(a, c));
078    navigableSet = (NavigableSet<E>) getSet();
079  }
080
081  @CollectionFeature.Require(SUPPORTS_REMOVE)
082  @CollectionSize.Require(ZERO)
083  public void testEmptySetPollFirst() {
084    assertNull(navigableSet.pollFirst());
085  }
086
087  @CollectionSize.Require(ZERO)
088  public void testEmptySetNearby() {
089    assertNull(navigableSet.lower(e0()));
090    assertNull(navigableSet.floor(e0()));
091    assertNull(navigableSet.ceiling(e0()));
092    assertNull(navigableSet.higher(e0()));
093  }
094
095  @CollectionFeature.Require(SUPPORTS_REMOVE)
096  @CollectionSize.Require(ZERO)
097  public void testEmptySetPollLast() {
098    assertNull(navigableSet.pollLast());
099  }
100
101  @CollectionFeature.Require(SUPPORTS_REMOVE)
102  @CollectionSize.Require(ONE)
103  public void testSingletonSetPollFirst() {
104    assertEquals(a, navigableSet.pollFirst());
105    assertTrue(navigableSet.isEmpty());
106  }
107
108  @CollectionSize.Require(ONE)
109  public void testSingletonSetNearby() {
110    assertNull(navigableSet.lower(e0()));
111    assertEquals(a, navigableSet.floor(e0()));
112    assertEquals(a, navigableSet.ceiling(e0()));
113    assertNull(navigableSet.higher(e0()));
114  }
115
116  @CollectionFeature.Require(SUPPORTS_REMOVE)
117  @CollectionSize.Require(ONE)
118  public void testSingletonSetPollLast() {
119    assertEquals(a, navigableSet.pollLast());
120    assertTrue(navigableSet.isEmpty());
121  }
122
123  @CollectionFeature.Require(SUPPORTS_REMOVE)
124  @CollectionSize.Require(SEVERAL)
125  public void testPollFirst() {
126    assertEquals(a, navigableSet.pollFirst());
127    assertEquals(values.subList(1, values.size()), Helpers.copyToList(navigableSet));
128  }
129
130  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
131  public void testPollFirstUnsupported() {
132    assertThrows(UnsupportedOperationException.class, () -> navigableSet.pollFirst());
133  }
134
135  @CollectionSize.Require(SEVERAL)
136  public void testLowerHole() {
137    resetWithHole();
138    assertEquals(null, navigableSet.lower(a));
139    assertEquals(a, navigableSet.lower(b));
140    assertEquals(a, navigableSet.lower(c));
141  }
142
143  @CollectionSize.Require(SEVERAL)
144  public void testFloorHole() {
145    resetWithHole();
146    assertEquals(a, navigableSet.floor(a));
147    assertEquals(a, navigableSet.floor(b));
148    assertEquals(c, navigableSet.floor(c));
149  }
150
151  @CollectionSize.Require(SEVERAL)
152  public void testCeilingHole() {
153    resetWithHole();
154    assertEquals(a, navigableSet.ceiling(a));
155    assertEquals(c, navigableSet.ceiling(b));
156    assertEquals(c, navigableSet.ceiling(c));
157  }
158
159  @CollectionSize.Require(SEVERAL)
160  public void testHigherHole() {
161    resetWithHole();
162    assertEquals(c, navigableSet.higher(a));
163    assertEquals(c, navigableSet.higher(b));
164    assertEquals(null, navigableSet.higher(c));
165  }
166
167  /*
168   * TODO(cpovirk): make "too small" and "too large" elements available for better navigation
169   * testing. At that point, we may be able to eliminate the "hole" tests, which would mean that
170   * ContiguousSet's tests would no longer need to suppress them.
171   */
172  @CollectionSize.Require(SEVERAL)
173  public void testLower() {
174    assertEquals(null, navigableSet.lower(a));
175    assertEquals(a, navigableSet.lower(b));
176    assertEquals(b, navigableSet.lower(c));
177  }
178
179  @CollectionSize.Require(SEVERAL)
180  public void testFloor() {
181    assertEquals(a, navigableSet.floor(a));
182    assertEquals(b, navigableSet.floor(b));
183    assertEquals(c, navigableSet.floor(c));
184  }
185
186  @CollectionSize.Require(SEVERAL)
187  public void testCeiling() {
188    assertEquals(a, navigableSet.ceiling(a));
189    assertEquals(b, navigableSet.ceiling(b));
190    assertEquals(c, navigableSet.ceiling(c));
191  }
192
193  @CollectionSize.Require(SEVERAL)
194  public void testHigher() {
195    assertEquals(b, navigableSet.higher(a));
196    assertEquals(c, navigableSet.higher(b));
197    assertEquals(null, navigableSet.higher(c));
198  }
199
200  @CollectionFeature.Require(SUPPORTS_REMOVE)
201  @CollectionSize.Require(SEVERAL)
202  public void testPollLast() {
203    assertEquals(c, navigableSet.pollLast());
204    assertEquals(values.subList(0, values.size() - 1), Helpers.copyToList(navigableSet));
205  }
206
207  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
208  public void testPollLastUnsupported() {
209    assertThrows(UnsupportedOperationException.class, () -> navigableSet.pollLast());
210  }
211
212  @CollectionSize.Require(SEVERAL)
213  public void testDescendingNavigation() {
214    List<E> descending = new ArrayList<>();
215    for (Iterator<E> i = navigableSet.descendingIterator(); i.hasNext(); ) {
216      descending.add(i.next());
217    }
218    Collections.reverse(descending);
219    assertEquals(values, descending);
220  }
221
222  public void testEmptySubSet() {
223    NavigableSet<E> empty = navigableSet.subSet(e0(), false, e0(), false);
224    assertEquals(new TreeSet<E>(), empty);
225  }
226
227  /*
228   * TODO(cpovirk): more testing of subSet/headSet/tailSet/descendingSet? and/or generate derived
229   * suites?
230   */
231
232  /**
233   * Returns the {@link Method} instances for the test methods in this class that create a set with
234   * a "hole" in it so that set tests of {@code ContiguousSet} can suppress them with {@code
235   * FeatureSpecificTestSuiteBuilder.suppressing()}.
236   */
237  /*
238   * TODO(cpovirk): or we could make HOLES_FORBIDDEN a feature. Or we could declare that
239   * implementations are permitted to throw IAE if a hole is requested, and we could update
240   * test*Hole to permit IAE. (But might this ignore genuine bugs?) But see the TODO above
241   * testLower, which could make this all unnecessary
242   */
243  public static Method[] getHoleMethods() {
244    return new Method[] {
245      Helpers.getMethod(NavigableSetNavigationTester.class, "testLowerHole"),
246      Helpers.getMethod(NavigableSetNavigationTester.class, "testFloorHole"),
247      Helpers.getMethod(NavigableSetNavigationTester.class, "testCeilingHole"),
248      Helpers.getMethod(NavigableSetNavigationTester.class, "testHigherHole"),
249    };
250  }
251}