001/*
002 * Copyright (C) 2022 - 2023, 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 java.util.Objects.requireNonNull;
019import static org.assertj.core.api.FactoryBasedNavigableListAssert.assertThat;
020
021import io.github.ascopes.jct.containers.ContainerGroup;
022import java.util.ArrayList;
023import java.util.List;
024import org.apiguardian.api.API;
025import org.apiguardian.api.API.Status;
026import org.assertj.core.api.AbstractAssert;
027import org.assertj.core.api.AbstractListAssert;
028import org.assertj.core.api.Assertions;
029import org.assertj.core.api.ObjectAssert;
030import org.jspecify.annotations.Nullable;
031
032/**
033 * Base assertions that can be performed on a container group.
034 *
035 * @param <I> the assertion implementation type.
036 * @param <C> the container group type.
037 * @author Ashley Scopes
038 * @since 0.0.1
039 */
040@API(since = "0.0.1", status = Status.STABLE)
041public abstract class AbstractContainerGroupAssert<I extends AbstractContainerGroupAssert<I, C>, C extends ContainerGroup>
042    extends AbstractAssert<I, C> {
043
044  /**
045   * Default number of matches to show when performing fuzzy matching.
046   *
047   * <p>This is defined here to allow consistent behaviour across various fuzzy matching
048   * operations in all implementations.
049   */
050  protected static final int FUZZY_CUTOFF = 5;
051
052  /**
053   * Initialize the container group assertions.
054   *
055   * @param containerGroup the container group to assert upon.
056   * @param selfType       the type of the assertion implementation to use.
057   */
058  protected AbstractContainerGroupAssert(@Nullable C containerGroup, Class<?> selfType) {
059    super(containerGroup, selfType);
060  }
061
062  /**
063   * Get assertions to perform on the location of this container group.
064   *
065   * @return the assertions to perform.
066   * @throws AssertionError if the object being asserted upon is null.
067   */
068  public LocationAssert location() {
069    isNotNull();
070    return new LocationAssert(actual.getLocation());
071  }
072
073  /**
074   * Get assertions for the services loaded by the given service loader.
075   *
076   * @param clazz the class to look up in the service loader.
077   * @param <T>   the service type.
078   * @return the assertions across the resultant services that are loaded for the given class.
079   * @throws AssertionError       if the object being asserted upon is null.
080   * @throws NullPointerException if the provided class parameter is null.
081   */
082  public <T> AbstractListAssert<?, List<? extends T>, T, ? extends ObjectAssert<T>> services(
083      Class<T> clazz
084  ) {
085    requireNonNull(clazz, "class must not be null");
086    isNotNull();
087
088    var items = new ArrayList<T>();
089    actual.getServiceLoader(clazz).iterator().forEachRemaining(items::add);
090
091    return assertThat(items, Assertions::assertThat);
092  }
093}