class Spliterators {
  /**
   * Name for constant {@link Spliterator#DISTINCT}
   */
  private static final String SPLITERATOR_DISTINCT = "DISTINCT";
  /**
   * Name for constant {@link Spliterator#SORTED}
   */
  private static final String SPLITERATOR_SORTED = "SORTED";
  /**
   * Name for constant {@link Spliterator#ORDERED}
   */
  private static final String SPLITERATOR_ORDERED = "ORDERED";
  /**
   * Name for constant {@link Spliterator#SIZED}
   */
  private static final String SPLITERATOR_SIZED = "SIZED";
  /**
   * Name for constant {@link Spliterator#NONNULL}
   */
  private static final String SPLITERATOR_NONNULL = "NONNULL";
  /**
   * Name for constant {@link Spliterator#IMMUTABLE}
   */
  private static final String SPLITERATOR_IMMUTABLE = "IMMUTABLE";
  /**
   * Name for constant {@link Spliterator#CONCURRENT}
   */
  private static final String SPLITERATOR_CONCURRENT = "CONCURRENT";
  /**
   * Name for constant {@link Spliterator#SUBSIZED}
   */
  private static final String SPLITERATOR_SUBSIZED = "SUBSIZED";

  private static final Spliterators INSTANCE = new Spliterators();

  private final Iterables iterables = Iterables.instance();

  /**
   * Returns the singleton instance of this class.
   *
   * @return the singleton instance of this class.
   */
  public static Spliterators instance() {
    return INSTANCE;
  }

  @VisibleForTesting
  void setFailures(Failures failures) {
    iterables.failures = failures;
  }

  /**
   * Asserts the given <code>{@link Spliterator}</code> has the given characteristics.
   *
   * @param info contains information about the assertion.
   * @param actual the given {@code Spliterator}.
   * @param characteristics the expected characteristics.
   * @throws AssertionError if the actual {@code Spliterator} is {@code null}.
   * @throws AssertionError if the actual {@code Spliterator} does not have the expected characteristics.
   */
  public void assertHasCharacteristics(AssertionInfo info, Spliterator<?> actual, int... characteristics) {
    assertNotNull(info, actual);
    Set<String> actualCharacteristicNames = characteristicNames(actual.characteristics());
    Set<String> expectedCharacteristicNames = characteristicNames(characteristics);
    iterables.assertContains(info, actualCharacteristicNames, expectedCharacteristicNames.toArray(new String[0]));
  }

  /**
   * Asserts the given <code>{@link Spliterator}</code> has only the given characteristics and no else.
   *
   * @param info contains information about the assertion.
   * @param actual the given {@code Spliterator}.
   * @param characteristics the expected characteristics.
   * @throws AssertionError if the actual {@code Spliterator} is {@code null}.
   * @throws AssertionError if the actual {@code Spliterator} does not have the expected characteristics
   *                        or the actual {@code Spliterator} has additional characteristics.
   */
  public void assertHasOnlyCharacteristics(AssertionInfo info, Spliterator<?> actual, int... characteristics) {
    assertNotNull(info, actual);
    Set<String> actualCharacteristicNames = characteristicNames(actual.characteristics());
    Set<String> expectedCharacteristicNames = characteristicNames(characteristics);
    iterables.assertContainsOnly(info, actualCharacteristicNames, expectedCharacteristicNames.toArray(new String[0]));
  }

  private static Set<String> characteristicNames(int[] characteristics) {
    Set<String> names = new HashSet<>();
    for (int characteristic : characteristics) {
      names.addAll(characteristicNames(characteristic));
    }
    return names;
  }

  private static Set<String> characteristicNames(int characteristics) {<FILL_FUNCTION_BODY>}

  private static boolean hasCharacteristic(int characteristics, int expectedCharacteristic) {
    return (characteristics & expectedCharacteristic) == expectedCharacteristic;
  }
}

    Set<String> names = new HashSet<>();
    if (hasCharacteristic(characteristics, Spliterator.DISTINCT)) names.add(SPLITERATOR_DISTINCT);
    if (hasCharacteristic(characteristics, Spliterator.SORTED)) names.add(SPLITERATOR_SORTED);
    if (hasCharacteristic(characteristics, Spliterator.ORDERED)) names.add(SPLITERATOR_ORDERED);
    if (hasCharacteristic(characteristics, Spliterator.SIZED)) names.add(SPLITERATOR_SIZED);
    if (hasCharacteristic(characteristics, Spliterator.NONNULL)) names.add(SPLITERATOR_NONNULL);
    if (hasCharacteristic(characteristics, Spliterator.IMMUTABLE)) names.add(SPLITERATOR_IMMUTABLE);
    if (hasCharacteristic(characteristics, Spliterator.CONCURRENT)) names.add(SPLITERATOR_CONCURRENT);
    if (hasCharacteristic(characteristics, Spliterator.SUBSIZED)) names.add(SPLITERATOR_SUBSIZED);
    return names;
  
<no_super_class>