001/*
002 * Copyright (C) 2022 - 2024, the original author or 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 */
016package io.github.ascopes.jct.assertions;
017
018import static io.github.ascopes.jct.utils.IterableUtils.requireNonNullValues;
019import static java.util.Objects.requireNonNull;
020import static org.assertj.core.api.Assertions.assertThat;
021
022import io.github.ascopes.jct.utils.IterableUtils;
023import java.util.List;
024import org.apiguardian.api.API;
025import org.apiguardian.api.API.Status;
026import org.assertj.core.api.AbstractAssert;
027import org.jspecify.annotations.Nullable;
028
029/**
030 * Abstract base class for an assertion on an {@link Enum}.
031 *
032 * @param <A> the implementation type.
033 * @param <E> the enum type.
034 * @author Ashley Scopes
035 * @since 0.0.1
036 */
037@API(since = "0.0.1", status = Status.STABLE)
038public abstract class AbstractEnumAssert<A extends AbstractEnumAssert<A, E>, E extends Enum<E>>
039    extends AbstractAssert<A, E> {
040
041  /**
042   * Initialize this enum assertion.
043   *
044   * @param value    the value to assert upon.
045   * @param selfType the type of this assertion implementation.
046   */
047  protected AbstractEnumAssert(@Nullable E value, Class<?> selfType) {
048    super(value, selfType);
049  }
050
051  /**
052   * Assert that the value is one of the given values.
053   *
054   * @param first the first value to check for.
055   * @param more  any additional values to check for.
056   * @return this assertion object.
057   * @throws NullPointerException if any of the elements to test against are null.
058   * @throws AssertionError       if the actual value is null, or if the value is not in the given
059   *                              group of acceptable values.
060   */
061  @SafeVarargs
062  public final A isAnyOf(E first, E... more) {
063    requireNonNull(first, "first must not be null");
064    requireNonNullValues(more, "more");
065
066    return isAnyOfElements(IterableUtils.combineOneOrMore(first, more));
067  }
068
069  /**
070   * Assert that the value is one of the given values.
071   *
072   * @param elements the elements to check for.
073   * @return this assertion object.
074   * @throws NullPointerException if any of the elements to test against are null.
075   * @throws AssertionError       if the actual value is null, or if the value is not in the given
076   *                              iterable of acceptable values.
077   */
078  public final A isAnyOfElements(Iterable<E> elements) {
079    requireNonNullValues(elements, "elements");
080
081    isNotNull();
082
083    assertThat(List.of(actual))
084        .as(description())
085        .containsAnyElementsOf(elements);
086
087    return myself;
088  }
089
090  /**
091   * Assert that the value is none of the given values.
092   *
093   * @param first the first value to check for.
094   * @param more  any additional values to check for.
095   * @return this assertion object.
096   * @throws NullPointerException if any of the elements to test against are null.
097   * @throws AssertionError       if the actual value is null, or if the value is in the given group
098   *                              of acceptable values.
099   */
100  @SafeVarargs
101  public final A isNoneOf(E first, E... more) {
102    requireNonNull(first, "first must not be null");
103    requireNonNullValues(more, "more");
104
105    return isNoneOfElements(IterableUtils.combineOneOrMore(first, more));
106  }
107
108  /**
109   * Assert that the value is one of the given values.
110   *
111   * @param elements the elements to check for.
112   * @return this assertion object.
113   * @throws NullPointerException if any of the elements to test against are null.
114   * @throws AssertionError       if the actual value is null, or if the value is in the given
115   *                              iterable of acceptable values.
116   */
117  public final A isNoneOfElements(Iterable<E> elements) {
118    requireNonNullValues(elements, "elements");
119
120    isNotNull();
121
122    assertThat(List.of(actual))
123        .as(description())
124        .doesNotContainAnyElementsOf(elements);
125
126    return myself;
127  }
128
129  private String description() {
130    return String.format("%s enum value <%s>", actual.getClass().getSimpleName(), actual);
131  }
132}