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 java.util.Objects.requireNonNull;
019import static org.assertj.core.api.Assertions.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.ObjectAssert;
029import org.jspecify.annotations.Nullable;
030
031/**
032 * Base assertions that can be performed on a container group.
033 *
034 * @param <I> the assertion implementation type.
035 * @param <C> the container group type.
036 * @author Ashley Scopes
037 * @since 0.0.1
038 */
039@API(since = "0.0.1", status = Status.STABLE)
040public abstract class AbstractContainerGroupAssert<I extends AbstractContainerGroupAssert<I, C>, C extends ContainerGroup>
041    extends AbstractAssert<I, C> {
042
043  /**
044   * Initialize the container group assertions.
045   *
046   * @param containerGroup the container group to assert upon.
047   * @param selfType       the type of the assertion implementation to use.
048   */
049  @SuppressWarnings("DataFlowIssue")
050  protected AbstractContainerGroupAssert(@Nullable C containerGroup, Class<?> selfType) {
051    super(containerGroup, selfType);
052  }
053
054  /**
055   * Get assertions to perform on the location of this container group.
056   *
057   * @return the assertions to perform.
058   * @throws AssertionError if the object being asserted upon is null.
059   */
060  public LocationAssert location() {
061    isNotNull();
062    return new LocationAssert(actual.getLocation());
063  }
064
065  /**
066   * Get assertions for the services loaded by the given service loader.
067   *
068   * @param type the class to look up in the service loader.
069   * @param <T>  the service type.
070   * @return the assertions across the resultant services that are loaded for the given class.
071   * @throws AssertionError       if the object being asserted upon is null.
072   * @throws NullPointerException if the provided class parameter is null.
073   */
074  public <T> AbstractListAssert<?, List<? extends T>, T, ? extends ObjectAssert<T>> services(
075      Class<T> type
076  ) {
077    requireNonNull(type, "type must not be null");
078    isNotNull();
079
080    var items = new ArrayList<T>();
081    actual.getServiceLoader(type).iterator().forEachRemaining(items::add);
082
083    return assertThat(items);
084  }
085}