ParameterSpace.java
package com.github.dakusui.jcunitx.metamodel;
import com.github.dakusui.jcunitx.core.AArray;
import com.github.dakusui.jcunitx.factorspace.Constraint;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import static java.lang.String.format;
import static java.util.Collections.unmodifiableList;
import static java.util.stream.Collectors.toList;
/**
* A test input parameter space.
* It consists of parameters and constraints over them.
*
* This interface defines the user-facing model of the system under test.
*/
public interface ParameterSpace {
/**
* Encodes the given {@code seeds} into its internal representation.
* **NOTE:** that the {@code seeds} need to be complete, that means all the parameters in a seed must have a concrete value.
* This is a limitation of the current version of JCUnit, because in the CIT area "seeding" is done for the
*
* @param parameterSpace The parameter space in which the {@code seeds} are defined.
* @param seeds A set of test cases from which the final test suite is generated.
* @return A list of encoded seeds.
*/
static List<AArray> encodeSeeds(ParameterSpace parameterSpace, List<AArray> seeds) {
return seeds.stream()
.map(parameterSpace::encodeSeed)
.collect(toList());
}
/**
* Returns the list of parameter names.
*
* @return The list of parameter names.
*/
List<String> getParameterNames();
/**
* Returns a parameter specified by the {@code name}.
*
* @param name The name of the parameter
* @param <P> The type of the parameter values.
* @return A parameter specified by {@code name}
*/
<P> Parameter<P> getParameter(String name);
/**
* Returns a list of constraints defined over the parameters in this space.
*
* @return The list of constraints.
*/
List<Constraint> getConstraints();
/**
* This corresponds to the "Encode" stage in the "Engine" pipeline.
*
* @param seed A seed
* @return An encoded seed
*/
default AArray encodeSeed(AArray seed) {
AArray.Builder builder = AArray.builder();
getParameterNames()
.forEach(each -> getParameter(each).decomposeValue(seed.get(each)).ifPresent(builder::putAll));
return builder.build();
}
class Builder {
List<Parameter<?>> parameters = new LinkedList<>();
List<Constraint> constraints = new LinkedList<>();
public Builder addParameter(Parameter<?> parameter) {
this.parameters.add(parameter);
return this;
}
public Builder addAllParameters(Collection<? extends Parameter<?>> parameters) {
parameters.forEach(Builder.this::addParameter);
return this;
}
public Builder addConstraint(Constraint constraint) {
this.constraints.add(constraint);
return this;
}
public Builder addAllConstraints(Collection<? extends Constraint> constraints) {
constraints.forEach(Builder.this::addConstraint);
return this;
}
public ParameterSpace build() {
return new ParameterSpace() {
@Override
public List<String> getParameterNames() {
return parameters.stream().map(Parameter::getName).collect(toList());
}
@SuppressWarnings("unchecked")
@Override
public <P> Parameter<P> getParameter(String name) {
return (Parameter<P>) (parameters.stream()
.filter(parameter -> parameter.getName().equals(name))
.findFirst()
.orElseThrow(() -> new RuntimeException(undefinedParameterMessage(name))));
}
private String undefinedParameterMessage(String name) {
return format(
"Parameter '%s' was requested but not found. Existing parameters are %s",
name,
getParameterNames()
);
}
@Override
public List<Constraint> getConstraints() {
return unmodifiableList(constraints);
}
@Override
public String toString() {
return format("parameters:%s,constraints:%s", parameters, constraints);
}
};
}
}
}