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