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.requireAtLeastOne;
019import static io.github.ascopes.jct.utils.IterableUtils.requireNonNullValues;
020import static org.assertj.core.api.Assertions.assertThat;
021
022import java.util.Collection;
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 elements the elements to check for.
056   * @return this assertion object.
057   * @throws NullPointerException     if any of the elements to test against are null.
058   * @throws IllegalArgumentException if the elements array is empty.
059   * @throws AssertionError           if the actual value is null, or if the value is not in the
060   *                                  given group of acceptable values.
061   */
062  @SafeVarargs
063  @SuppressWarnings("varargs")
064  public final A isAnyOf(E... elements) {
065    requireNonNullValues(elements, "elements");
066    requireAtLeastOne(elements, "elements");
067    isNotNull();
068
069    assertThat(List.of(actual))
070        .as(description())
071        .containsAnyOf(elements);
072
073    return myself;
074  }
075
076  /**
077   * Assert that the value is one of the given values.
078   *
079   * @param elements the elements to check for.
080   * @return this assertion object.
081   * @throws NullPointerException     if any of the elements to test against are null.
082   * @throws IllegalArgumentException if the elements collection is empty.
083   * @throws AssertionError           if the actual value is null, or if the value is not in the
084   *                                  given iterable of acceptable values.
085   */
086  public final A isAnyOfElements(Collection<E> elements) {
087    requireNonNullValues(elements, "elements");
088    requireAtLeastOne(elements, "elements");
089    isNotNull();
090
091    assertThat(List.of(actual))
092        .as(description())
093        .containsAnyElementsOf(elements);
094
095    return myself;
096  }
097
098  /**
099   * Assert that the value is none of the given values.
100   *
101   * @param elements any elements to check for.
102   * @return this assertion object.
103   * @throws NullPointerException     if any of the elements to test against are null.
104   * @throws IllegalArgumentException if the elements array is empty.
105   * @throws AssertionError           if the actual value is null, or if the value is in the given
106   *                                  group of acceptable values.
107   */
108  @SafeVarargs
109  public final A isNoneOf(E... elements) {
110    requireNonNullValues(elements, "elements");
111    requireAtLeastOne(elements, "elements");
112    isNotNull();
113
114    assertThat(List.of(actual))
115        .as(description())
116        .doesNotContain(elements);
117
118    return myself;
119  }
120
121  /**
122   * Assert that the value is one of the given values.
123   *
124   * @param elements the elements to check for.
125   * @return this assertion object.
126   * @throws NullPointerException     if any of the elements to test against are null.
127   * @throws IllegalArgumentException if the elements collection is empty.
128   * @throws AssertionError           if the actual value is null, or if the value is in the given
129   *                                  iterable of acceptable values.
130   */
131  public final A isNoneOfElements(Collection<E> elements) {
132    requireNonNullValues(elements, "elements");
133    requireAtLeastOne(elements, "elements");
134    isNotNull();
135
136    assertThat(List.of(actual))
137        .as(description())
138        .doesNotContainAnyElementsOf(elements);
139
140    return myself;
141  }
142
143  private String description() {
144    return String.format("%s enum value <%s>", actual.getClass().getSimpleName(), actual);
145  }
146}