001/*
002 * Copyright 2023 the original author or authors.
003 * <p>
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 * <p>
008 * https://www.apache.org/licenses/LICENSE-2.0
009 * <p>
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 de.cuioss.test.valueobjects.objects.impl;
017
018import static java.util.Objects.requireNonNull;
019
020import java.util.ArrayList;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024
025import de.cuioss.test.valueobjects.objects.ParameterizedInstantiator;
026import de.cuioss.test.valueobjects.objects.RuntimeProperties;
027import de.cuioss.test.valueobjects.property.PropertyMetadata;
028import de.cuioss.test.valueobjects.property.PropertySupport;
029import lombok.Getter;
030
031/**
032 * Base class for creating objects with a fixed set of parameter to be used.
033 * This can be constructor and or factory based
034 * {@link ParameterizedInstantiator}.
035 *
036 * @author Oliver Wolff
037 * @param <T>
038 */
039public abstract class AbstractOrderedArgsInstantiator<T> implements ParameterizedInstantiator<T> {
040
041    @Getter
042    private final RuntimeProperties runtimeProperties;
043
044    /**
045     * Constructor.
046     *
047     * @param runtimeProperties must not be null. defines the attributes in the
048     *                          exact order to be used for the constructor:
049     *                          {@link RuntimeProperties#getAllProperties()}
050     */
051    protected AbstractOrderedArgsInstantiator(final RuntimeProperties runtimeProperties) {
052        requireNonNull(runtimeProperties);
053
054        this.runtimeProperties = runtimeProperties;
055    }
056
057    /**
058     * Wraps the given {@link Class} elements to a corresponding array
059     *
060     * @param parameter may be null
061     * @return the array
062     */
063    static Class<?>[] toClassArray(final List<Class<?>> parameter) {
064        if (null == parameter || parameter.isEmpty()) {
065            return new Class<?>[0];
066        }
067        final var parameterArray = new Class<?>[parameter.size()];
068        for (var i = 0; i < parameterArray.length; i++) {
069            parameterArray[i] = parameter.get(i);
070        }
071        return parameterArray;
072    }
073
074    @Override
075    public T newInstance(final List<PropertySupport> properties, final boolean generatePropertyValues) {
076        final Map<String, PropertySupport> given = new HashMap<>();
077        properties.forEach(p -> given.put(p.getName(), p));
078        final List<Object> parameter = new ArrayList<>();
079        for (final PropertySupport support : resolveFixedArgumentList()) {
080            if (given.containsKey(support.getName())) {
081                // Use given element
082                final var givenSupport = given.get(support.getName());
083                if (generatePropertyValues) {
084                    givenSupport.generateTestValue();
085                }
086                parameter.add(givenSupport.getGeneratedValue());
087            } else {
088                if (null != support.getGeneratedValue()) {
089                    // A Test value is already set
090                } else if (support.isRequired() || support.isPrimitive()) {
091                    support.generateTestValue();
092                }
093                parameter.add(support.getGeneratedValue());
094            }
095        }
096        return doInstantiate(parameter.toArray());
097    }
098
099    /**
100     * The actual instantiation method for the {@link Object}s
101     *
102     * @param args Object[] of parameter to be passed to Constructor / factory ,
103     *             method
104     * @return the instantiated {@link Object}
105     */
106    protected abstract T doInstantiate(Object... args);
107
108    @Override
109    public T newInstance(final List<PropertyMetadata> properties) {
110        return newInstance(RuntimeProperties.mapToPropertySupport(properties, false), true);
111    }
112
113    @Override
114    public T newInstanceMinimal() {
115        return newInstance(getRuntimeProperties().getRequiredAsPropertySupport(false), true);
116    }
117
118    @Override
119    public T newInstanceFull() {
120        return newInstance(resolveFixedArgumentList(), true);
121    }
122
123    protected List<PropertySupport> resolveFixedArgumentList() {
124        return getRuntimeProperties().getAllAsPropertySupport(false);
125    }
126
127}