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  @SuppressWarnings("DataFlowIssue")
048  protected AbstractEnumAssert(@Nullable E value, Class<?> selfType) {
049    super(value, selfType);
050  }
051
052  /**
053   * Assert that the value is one of the given values.
054   *
055   * @param first the first value to check for.
056   * @param more  any additional values to check for.
057   * @return this assertion object.
058   * @throws NullPointerException if any of the elements to test against are null.
059   * @throws AssertionError       if the actual value is null, or if the value is not in the given
060   *                              group of acceptable values.
061   */
062  @SafeVarargs
063  public final A isAnyOf(E first, E... more) {
064    requireNonNull(first, "first must not be null");
065    requireNonNullValues(more, "more");
066
067    return isAnyOfElements(IterableUtils.combineOneOrMore(first, more));
068  }
069
070  /**
071   * Assert that the value is one of the given values.
072   *
073   * @param elements the elements to check for.
074   * @return this assertion object.
075   * @throws NullPointerException if any of the elements to test against are null.
076   * @throws AssertionError       if the actual value is null, or if the value is not in the given
077   *                              iterable of acceptable values.
078   */
079  public final A isAnyOfElements(Iterable<E> elements) {
080    requireNonNullValues(elements, "elements");
081
082    isNotNull();
083
084    assertThat(List.of(actual))
085        .as(description())
086        .containsAnyElementsOf(elements);
087
088    return myself;
089  }
090
091  /**
092   * Assert that the value is none of the given values.
093   *
094   * @param first the first value to check for.
095   * @param more  any additional values to check for.
096   * @return this assertion object.
097   * @throws NullPointerException if any of the elements to test against are null.
098   * @throws AssertionError       if the actual value is null, or if the value is in the given group
099   *                              of acceptable values.
100   */
101  @SafeVarargs
102  public final A isNoneOf(E first, E... more) {
103    requireNonNull(first, "first must not be null");
104    requireNonNullValues(more, "more");
105
106    return isNoneOfElements(IterableUtils.combineOneOrMore(first, more));
107  }
108
109  /**
110   * Assert that the value is one of the given values.
111   *
112   * @param elements the elements to check for.
113   * @return this assertion object.
114   * @throws NullPointerException if any of the elements to test against are null.
115   * @throws AssertionError       if the actual value is null, or if the value is in the given
116   *                              iterable of acceptable values.
117   */
118  public final A isNoneOfElements(Iterable<E> elements) {
119    requireNonNullValues(elements, "elements");
120
121    isNotNull();
122
123    assertThat(List.of(actual))
124        .as(description())
125        .doesNotContainAnyElementsOf(elements);
126
127    return myself;
128  }
129
130  private String description() {
131    return String.format("%s enum value <%s>", actual.getClass().getSimpleName(), actual);
132  }
133}