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.assertj.core.api.AbstractAssert;
025import org.jspecify.annotations.Nullable;
026
027/**
028 * Abstract base class for an assertion on an {@link Enum}.
029 *
030 * @param <A> the implementation type.
031 * @param <E> the enum type.
032 * @author Ashley Scopes
033 * @since 0.0.1
034 */
035public abstract class AbstractEnumAssert<A extends AbstractEnumAssert<A, E>, E extends Enum<E>>
036    extends AbstractAssert<A, E> {
037
038  /**
039   * Initialize this enum assertion.
040   *
041   * @param value    the value to assert upon.
042   * @param selfType the type of this assertion implementation.
043   */
044  @SuppressWarnings("DataFlowIssue")
045  protected AbstractEnumAssert(@Nullable E value, Class<?> selfType) {
046    super(value, selfType);
047  }
048
049  /**
050   * Assert that the value is one of the given values.
051   *
052   * @param elements the elements to check for.
053   * @return this assertion object.
054   * @throws NullPointerException     if any of the elements to test against are null.
055   * @throws IllegalArgumentException if the elements array is empty.
056   * @throws AssertionError           if the actual value is null, or if the value is not in the
057   *                                  given group of acceptable values.
058   */
059  @SafeVarargs
060  @SuppressWarnings("varargs")
061  public final A isAnyOf(E... elements) {
062    requireNonNullValues(elements, "elements");
063    requireAtLeastOne(elements, "elements");
064    isNotNull();
065
066    assertThat(List.of(actual))
067        .as(description())
068        .containsAnyOf(elements);
069
070    return myself;
071  }
072
073  /**
074   * Assert that the value is one of the given values.
075   *
076   * @param elements the elements to check for.
077   * @return this assertion object.
078   * @throws NullPointerException     if any of the elements to test against are null.
079   * @throws IllegalArgumentException if the elements collection is empty.
080   * @throws AssertionError           if the actual value is null, or if the value is not in the
081   *                                  given iterable of acceptable values.
082   */
083  public final A isAnyOfElements(Collection<E> elements) {
084    requireNonNullValues(elements, "elements");
085    requireAtLeastOne(elements, "elements");
086    isNotNull();
087
088    assertThat(List.of(actual))
089        .as(description())
090        .containsAnyElementsOf(elements);
091
092    return myself;
093  }
094
095  /**
096   * Assert that the value is none of the given values.
097   *
098   * @param elements any elements to check for.
099   * @return this assertion object.
100   * @throws NullPointerException     if any of the elements to test against are null.
101   * @throws IllegalArgumentException if the elements array is empty.
102   * @throws AssertionError           if the actual value is null, or if the value is in the given
103   *                                  group of acceptable values.
104   */
105  @SafeVarargs
106  public final A isNoneOf(E... elements) {
107    requireNonNullValues(elements, "elements");
108    requireAtLeastOne(elements, "elements");
109    isNotNull();
110
111    assertThat(List.of(actual))
112        .as(description())
113        .doesNotContain(elements);
114
115    return myself;
116  }
117
118  /**
119   * Assert that the value is one of the given values.
120   *
121   * @param elements the elements to check for.
122   * @return this assertion object.
123   * @throws NullPointerException     if any of the elements to test against are null.
124   * @throws IllegalArgumentException if the elements collection is empty.
125   * @throws AssertionError           if the actual value is null, or if the value is in the given
126   *                                  iterable of acceptable values.
127   */
128  public final A isNoneOfElements(Collection<E> elements) {
129    requireNonNullValues(elements, "elements");
130    requireAtLeastOne(elements, "elements");
131    isNotNull();
132
133    assertThat(List.of(actual))
134        .as(description())
135        .doesNotContainAnyElementsOf(elements);
136
137    return myself;
138  }
139
140  private String description() {
141    return String.format("%s enum value <%s>", actual.getClass().getSimpleName(), actual);
142  }
143}