| 1 | package com.github.dakusui.pcond.core.refl; | |
| 2 | ||
| 3 | import com.github.dakusui.pcond.internals.InternalChecks; | |
| 4 | import com.github.dakusui.pcond.internals.InternalUtils; | |
| 5 | ||
| 6 | import java.lang.reflect.Method; | |
| 7 | import java.util.*; | |
| 8 | import java.util.stream.IntStream; | |
| 9 | ||
| 10 | import static com.github.dakusui.pcond.core.refl.MethodSelector.Utils.isAssignableWithBoxingFrom; | |
| 11 | import static com.github.dakusui.pcond.internals.InternalChecks.requireArgument; | |
| 12 | import static java.lang.String.format; | |
| 13 | import static java.util.Objects.requireNonNull; | |
| 14 | import static java.util.stream.Collectors.toList; | |
| 15 | ||
| 16 | /** | |
| 17 | * //@formater:off | |
| 18 | * An interface representing an object that selects {@link Method}s from given ones. | |
| 19 | * | |
| 20 | * This interface is used to choose methods that are appropriate to invoke with | |
| 21 | * given arguments. | |
| 22 | * //@formater:on | |
| 23 | */ | |
| 24 | public interface MethodSelector extends Formattable { | |
| 25 | /** | |
| 26 | * Selects methods that can be invoked with given {@code args}. | |
| 27 | * | |
| 28 | * @param methods Methods from which returned methods are selected. | |
| 29 | * @param args Arguments to be passed to selected methods. | |
| 30 | * @return Selected methods. | |
| 31 | */ | |
| 32 | List<Method> select(List<Method> methods, Object[] args); | |
| 33 | ||
| 34 | /** | |
| 35 | * Returns a string that describes this object. | |
| 36 | * | |
| 37 | * @return A description of this object | |
| 38 | */ | |
| 39 | String describe(); | |
| 40 | ||
| 41 | /** | |
| 42 | * Returns a composed {@link MethodSelector} that first applies this and | |
| 43 | * then applies {@code another}. | |
| 44 | * | |
| 45 | * @param another The method selector to apply after this. | |
| 46 | * @return The composed method selector | |
| 47 | */ | |
| 48 | default MethodSelector andThen(MethodSelector another) { | |
| 49 |
1
1. andThen : replaced return value with null for com/github/dakusui/pcond/core/refl/MethodSelector::andThen → KILLED |
return new MethodSelector() { |
| 50 | @Override | |
| 51 | public List<Method> select(List<Method> methods, Object[] args) { | |
| 52 |
1
1. select : replaced return value with Collections.emptyList for com/github/dakusui/pcond/core/refl/MethodSelector$1::select → KILLED |
return another.select(MethodSelector.this.select(methods, args), args); |
| 53 | } | |
| 54 | ||
| 55 | @Override | |
| 56 | public String describe() { | |
| 57 |
1
1. describe : replaced return value with "" for com/github/dakusui/pcond/core/refl/MethodSelector$1::describe → KILLED |
return format("%s&&%s", MethodSelector.this.describe(), another.describe()); |
| 58 | } | |
| 59 | }; | |
| 60 | } | |
| 61 | ||
| 62 | /** | |
| 63 | * Formats this object using the {@link MethodSelector#describe()} method. | |
| 64 | */ | |
| 65 | @Override | |
| 66 | default void formatTo(Formatter formatter, int flags, int width, int precision) { | |
| 67 | formatter.format("%s", this.describe()); | |
| 68 | } | |
| 69 | ||
| 70 | class Default implements MethodSelector { | |
| 71 | @Override | |
| 72 | public List<Method> select(List<Method> methods, Object[] args) { | |
| 73 |
1
1. select : replaced return value with Collections.emptyList for com/github/dakusui/pcond/core/refl/MethodSelector$Default::select → KILLED |
return methods |
| 74 | .stream() | |
| 75 |
2
1. lambda$select$0 : replaced boolean return with false for com/github/dakusui/pcond/core/refl/MethodSelector$Default::lambda$select$0 → KILLED 2. lambda$select$0 : replaced boolean return with true for com/github/dakusui/pcond/core/refl/MethodSelector$Default::lambda$select$0 → KILLED |
.filter(m -> areArgsCompatible(m.getParameterTypes(), args)) |
| 76 | .collect(toList()); | |
| 77 | } | |
| 78 | ||
| 79 | @Override | |
| 80 | public String describe() { | |
| 81 |
1
1. describe : replaced return value with "" for com/github/dakusui/pcond/core/refl/MethodSelector$Default::describe → KILLED |
return "default"; |
| 82 | } | |
| 83 | ||
| 84 | private static boolean areArgsCompatible(Class<?>[] formalParameters, Object[] args) { | |
| 85 |
1
1. areArgsCompatible : negated conditional → KILLED |
if (formalParameters.length != args.length) |
| 86 |
1
1. areArgsCompatible : replaced boolean return with true for com/github/dakusui/pcond/core/refl/MethodSelector$Default::areArgsCompatible → KILLED |
return false; |
| 87 |
2
1. areArgsCompatible : changed conditional boundary → KILLED 2. areArgsCompatible : negated conditional → KILLED |
for (int i = 0; i < args.length; i++) { |
| 88 |
1
1. areArgsCompatible : negated conditional → KILLED |
if (args[i] == null) |
| 89 |
1
1. areArgsCompatible : negated conditional → KILLED |
if (formalParameters[i].isPrimitive()) |
| 90 |
1
1. areArgsCompatible : replaced boolean return with true for com/github/dakusui/pcond/core/refl/MethodSelector$Default::areArgsCompatible → KILLED |
return false; |
| 91 | else | |
| 92 | continue; | |
| 93 |
1
1. areArgsCompatible : negated conditional → KILLED |
if (!isAssignableWithBoxingFrom(formalParameters[i], Utils.toClass(args[i]))) |
| 94 |
1
1. areArgsCompatible : replaced boolean return with true for com/github/dakusui/pcond/core/refl/MethodSelector$Default::areArgsCompatible → KILLED |
return false; |
| 95 | } | |
| 96 |
1
1. areArgsCompatible : replaced boolean return with false for com/github/dakusui/pcond/core/refl/MethodSelector$Default::areArgsCompatible → KILLED |
return true; |
| 97 | } | |
| 98 | } | |
| 99 | ||
| 100 | /** | |
| 101 | * A method selector that selects "narrower" methods over "wider" ones. | |
| 102 | */ | |
| 103 | class PreferNarrower implements MethodSelector { | |
| 104 | @Override | |
| 105 | public List<Method> select(List<Method> methods, Object[] args) { | |
| 106 |
2
1. select : changed conditional boundary → KILLED 2. select : negated conditional → KILLED |
if (methods.size() < 2) |
| 107 |
1
1. select : replaced return value with Collections.emptyList for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::select → KILLED |
return methods; |
| 108 | List<Method> ret = new LinkedList<>(); | |
| 109 | for (Method i : methods) { | |
| 110 |
6
1. lambda$select$0 : replaced boolean return with true for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::lambda$select$0 → SURVIVED 2. lambda$select$0 : negated conditional → KILLED 3. lambda$select$1 : changed conditional boundary → KILLED 4. lambda$select$1 : negated conditional → KILLED 5. lambda$select$1 : replaced boolean return with true for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::lambda$select$1 → KILLED 6. select : negated conditional → KILLED |
if (methods.stream().filter(j -> j != i).noneMatch(j -> compareNarrowness(j, i) > 0)) |
| 111 | ret.add(i); | |
| 112 | } | |
| 113 |
1
1. select : replaced return value with Collections.emptyList for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::select → KILLED |
return ret; |
| 114 | } | |
| 115 | ||
| 116 | @Override | |
| 117 | public String describe() { | |
| 118 |
1
1. describe : replaced return value with "" for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::describe → KILLED |
return "preferNarrower"; |
| 119 | } | |
| 120 | ||
| 121 | /** | |
| 122 | * If {@code a} is 'narrower' than {@code b}, positive integer will be returned. | |
| 123 | * If {@code b} is 'narrower' than {@code a}, negative integer will be returned. | |
| 124 | * Otherwise {@code zero}. | |
| 125 | * | |
| 126 | * 'Narrower' means that every parameter of {@code a} is assignable to corresponding | |
| 127 | * one of {@code b}, but any of {@code b} cannot be assigned to {@code a}'s | |
| 128 | * corresponding parameter. | |
| 129 | * | |
| 130 | * @param a A method. | |
| 131 | * @param b A method to be compared with {@code a}. | |
| 132 | * @return a negative integer, zero, or a positive integer as method {@code a} | |
| 133 | * is less compatible than, as compatible as, or more compatible than | |
| 134 | * the method {@code b} object. | |
| 135 | */ | |
| 136 | private static int compareNarrowness(Method a, Method b) { | |
| 137 |
2
1. compareNarrowness : negated conditional → SURVIVED 2. compareNarrowness : negated conditional → KILLED |
if (isCompatibleWith(a, b) && isCompatibleWith(b, a)) |
| 138 | return 0; | |
| 139 |
2
1. compareNarrowness : negated conditional → KILLED 2. compareNarrowness : negated conditional → KILLED |
if (!isCompatibleWith(a, b) && !isCompatibleWith(b, a)) |
| 140 | return 0; | |
| 141 |
2
1. compareNarrowness : negated conditional → KILLED 2. compareNarrowness : replaced int return with 0 for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::compareNarrowness → KILLED |
return isCompatibleWith(a, b) |
| 142 | ? -1 | |
| 143 | : 1; | |
| 144 | } | |
| 145 | ||
| 146 | private static boolean isCompatibleWith(Method a, Method b) { | |
| 147 |
1
1. isCompatibleWith : removed call to com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::requireSameParameterCounts → KILLED |
requireSameParameterCounts(a, b); |
| 148 |
1
1. isCompatibleWith : negated conditional → KILLED |
if (Objects.equals(a, b)) |
| 149 |
1
1. isCompatibleWith : replaced boolean return with false for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::isCompatibleWith → SURVIVED |
return true; |
| 150 |
2
1. isCompatibleWith : replaced boolean return with false for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::isCompatibleWith → KILLED 2. isCompatibleWith : replaced boolean return with true for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::isCompatibleWith → KILLED |
return IntStream |
| 151 | .range(0, a.getParameterCount()) | |
| 152 |
2
1. lambda$isCompatibleWith$2 : replaced boolean return with false for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::lambda$isCompatibleWith$2 → KILLED 2. lambda$isCompatibleWith$2 : replaced boolean return with true for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::lambda$isCompatibleWith$2 → KILLED |
.allMatch(i -> isAssignableWithBoxingFrom(a.getParameterTypes()[i], b.getParameterTypes()[i])); |
| 153 | } | |
| 154 | ||
| 155 | private static void requireSameParameterCounts(Method a, Method b) { | |
| 156 | requireArgument( | |
| 157 | requireNonNull(a), | |
| 158 |
2
1. lambda$requireSameParameterCounts$3 : negated conditional → KILLED 2. lambda$requireSameParameterCounts$3 : replaced boolean return with true for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::lambda$requireSameParameterCounts$3 → KILLED |
(Method v) -> v.getParameterCount() == requireNonNull(b).getParameterCount(), |
| 159 |
1
1. lambda$requireSameParameterCounts$4 : replaced return value with "" for com/github/dakusui/pcond/core/refl/MethodSelector$PreferNarrower::lambda$requireSameParameterCounts$4 → KILLED |
() -> format("Parameter counts are different: a: %s, b: %s", a, b)); |
| 160 | } | |
| 161 | } | |
| 162 | ||
| 163 | class PreferExact implements MethodSelector { | |
| 164 | @Override | |
| 165 | public List<Method> select(List<Method> methods, Object[] args) { | |
| 166 |
2
1. select : changed conditional boundary → SURVIVED 2. select : negated conditional → SURVIVED |
if (methods.size() < 2) |
| 167 |
1
1. select : replaced return value with Collections.emptyList for com/github/dakusui/pcond/core/refl/MethodSelector$PreferExact::select → KILLED |
return methods; |
| 168 | List<Method> work = methods; | |
| 169 | for (Object ignored : args) { | |
| 170 | List<Method> tmp = new ArrayList<>(work); | |
| 171 |
1
1. select : negated conditional → SURVIVED |
if (!tmp.isEmpty()) { |
| 172 | work = tmp; | |
| 173 | break; | |
| 174 | } | |
| 175 | } | |
| 176 |
1
1. select : replaced return value with Collections.emptyList for com/github/dakusui/pcond/core/refl/MethodSelector$PreferExact::select → KILLED |
return work; |
| 177 | } | |
| 178 | ||
| 179 | @Override | |
| 180 | public String describe() { | |
| 181 |
1
1. describe : replaced return value with "" for com/github/dakusui/pcond/core/refl/MethodSelector$PreferExact::describe → KILLED |
return "preferExact"; |
| 182 | } | |
| 183 | } | |
| 184 | ||
| 185 | enum Utils { | |
| 186 | ; | |
| 187 | ||
| 188 | static boolean isAssignableWithBoxingFrom(Class<?> a, Class<?> b) { | |
| 189 |
1
1. isAssignableWithBoxingFrom : negated conditional → KILLED |
if (a.isAssignableFrom(b)) |
| 190 |
1
1. isAssignableWithBoxingFrom : replaced boolean return with false for com/github/dakusui/pcond/core/refl/MethodSelector$Utils::isAssignableWithBoxingFrom → KILLED |
return true; |
| 191 |
2
1. isAssignableWithBoxingFrom : negated conditional → KILLED 2. isAssignableWithBoxingFrom : negated conditional → KILLED |
if (InternalChecks.isPrimitiveWrapperClassOrPrimitive(a) && InternalChecks.isPrimitiveWrapperClassOrPrimitive(b)) |
| 192 |
2
1. isAssignableWithBoxingFrom : replaced boolean return with true for com/github/dakusui/pcond/core/refl/MethodSelector$Utils::isAssignableWithBoxingFrom → SURVIVED 2. isAssignableWithBoxingFrom : replaced boolean return with false for com/github/dakusui/pcond/core/refl/MethodSelector$Utils::isAssignableWithBoxingFrom → KILLED |
return InternalChecks.isWiderThanOrEqualTo(toWrapperIfPrimitive(a), toWrapperIfPrimitive(b)); |
| 193 |
1
1. isAssignableWithBoxingFrom : replaced boolean return with true for com/github/dakusui/pcond/core/refl/MethodSelector$Utils::isAssignableWithBoxingFrom → KILLED |
return false; |
| 194 | } | |
| 195 | ||
| 196 | private static Class<?> toWrapperIfPrimitive(Class<?> in) { | |
| 197 |
1
1. toWrapperIfPrimitive : negated conditional → KILLED |
if (in.isPrimitive()) |
| 198 |
1
1. toWrapperIfPrimitive : replaced return value with null for com/github/dakusui/pcond/core/refl/MethodSelector$Utils::toWrapperIfPrimitive → KILLED |
return InternalUtils.wrapperClassOf(in); |
| 199 |
1
1. toWrapperIfPrimitive : replaced return value with null for com/github/dakusui/pcond/core/refl/MethodSelector$Utils::toWrapperIfPrimitive → KILLED |
return in; |
| 200 | } | |
| 201 | ||
| 202 | private static Class<?> toClass(Object value) { | |
| 203 |
1
1. toClass : replaced return value with null for com/github/dakusui/pcond/core/refl/MethodSelector$Utils::toClass → KILLED |
return value.getClass(); |
| 204 | } | |
| 205 | } | |
| 206 | } | |
Mutations | ||
| 49 |
1.1 |
|
| 52 |
1.1 |
|
| 57 |
1.1 |
|
| 73 |
1.1 |
|
| 75 |
1.1 2.2 |
|
| 81 |
1.1 |
|
| 85 |
1.1 |
|
| 86 |
1.1 |
|
| 87 |
1.1 2.2 |
|
| 88 |
1.1 |
|
| 89 |
1.1 |
|
| 90 |
1.1 |
|
| 93 |
1.1 |
|
| 94 |
1.1 |
|
| 96 |
1.1 |
|
| 106 |
1.1 2.2 |
|
| 107 |
1.1 |
|
| 110 |
1.1 2.2 3.3 4.4 5.5 6.6 |
|
| 113 |
1.1 |
|
| 118 |
1.1 |
|
| 137 |
1.1 2.2 |
|
| 139 |
1.1 2.2 |
|
| 141 |
1.1 2.2 |
|
| 147 |
1.1 |
|
| 148 |
1.1 |
|
| 149 |
1.1 |
|
| 150 |
1.1 2.2 |
|
| 152 |
1.1 2.2 |
|
| 158 |
1.1 2.2 |
|
| 159 |
1.1 |
|
| 166 |
1.1 2.2 |
|
| 167 |
1.1 |
|
| 171 |
1.1 |
|
| 176 |
1.1 |
|
| 181 |
1.1 |
|
| 189 |
1.1 |
|
| 190 |
1.1 |
|
| 191 |
1.1 2.2 |
|
| 192 |
1.1 2.2 |
|
| 193 |
1.1 |
|
| 197 |
1.1 |
|
| 198 |
1.1 |
|
| 199 |
1.1 |
|
| 203 |
1.1 |