SuspendableGetCharInsertion.java

1
package com.jsql.model.suspendable;
2
3
import com.jsql.model.InjectionModel;
4
import com.jsql.view.subscriber.Seal;
5
import com.jsql.model.exception.JSqlException;
6
import com.jsql.model.exception.StoppedByUserSlidingException;
7
import com.jsql.model.injection.strategy.blind.InjectionCharInsertion;
8
import com.jsql.model.injection.engine.MediatorEngine;
9
import com.jsql.model.injection.engine.model.Engine;
10
import com.jsql.model.suspendable.callable.CallablePageSource;
11
import com.jsql.util.I18nUtil;
12
import com.jsql.util.LogLevelUtil;
13
import org.apache.commons.lang3.RandomStringUtils;
14
import org.apache.commons.lang3.StringUtils;
15
import org.apache.logging.log4j.LogManager;
16
import org.apache.logging.log4j.Logger;
17
18
import java.util.*;
19
import java.util.concurrent.CompletionService;
20
import java.util.concurrent.ExecutionException;
21
import java.util.concurrent.ExecutorCompletionService;
22
import java.util.concurrent.ExecutorService;
23
import java.util.regex.Pattern;
24
import java.util.stream.Stream;
25
26
/**
27
 * Runnable class, define insertionCharacter to be used during injection,
28
 * i.e -1 in "...php?id=-1 union select...", sometimes it's -1, 0', 0, etc.
29
 * Find working insertion char when error message occurs in source.
30
 * Force to 1 if no insertion char works and empty value from user,
31
 * Force to user's value if no insertion char works,
32
 * Force to insertion char otherwise.
33
 */
34
public class SuspendableGetCharInsertion extends AbstractSuspendable {
35
    
36
    private static final Logger LOGGER = LogManager.getRootLogger();
37
38
    private static final String LABEL_PREFIX = "prefix";
39
40
    public SuspendableGetCharInsertion(InjectionModel injectionModel) {
41
        super(injectionModel);
42
    }
43
44
    @Override
45
    public String run(Input input) throws JSqlException {
46
        String characterInsertionByUser = input.payload();
47
        
48
        ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().threadUtil().getExecutor("CallableGetInsertionCharacter");
49
        CompletionService<CallablePageSource> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
50
51
        var charFromBooleanMatch = new String[1];
52
        List<String> charactersInsertion = this.initCallables(taskCompletionService, charFromBooleanMatch);
53
        
54
        var mediatorEngine = this.injectionModel.getMediatorEngine();
55
        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Fingerprinting database and character insertion with Order by match...");
56
57
        String charFromOrderBy = null;
58
        
59
        int total = charactersInsertion.size();
60 2 1. run : negated conditional → NO_COVERAGE
2. run : changed conditional boundary → NO_COVERAGE
        while (0 < total) {
61 1 1. run : negated conditional → NO_COVERAGE
            if (this.isSuspended()) {
62
                throw new StoppedByUserSlidingException();
63
            }
64
            try {
65
                CallablePageSource currentCallable = taskCompletionService.take().get();
66 1 1. run : Changed increment from -1 to 1 → NO_COVERAGE
                total--;
67
                String pageSource = currentCallable.getContent();
68
                
69
                List<Engine> enginesOrderByMatches = this.getEnginesOrderByMatch(mediatorEngine, pageSource);
70 1 1. run : negated conditional → NO_COVERAGE
                if (!enginesOrderByMatches.isEmpty()) {
71 1 1. run : negated conditional → NO_COVERAGE
                    if (this.injectionModel.getMediatorEngine().getEngineByUser() == this.injectionModel.getMediatorEngine().getAuto()) {
72 1 1. run : removed call to com/jsql/model/suspendable/SuspendableGetCharInsertion::setEngine → NO_COVERAGE
                        this.setEngine(mediatorEngine, enginesOrderByMatches);
73
74
                        LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Using [{}]", mediatorEngine.getEngine());
75 1 1. run : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
                        this.injectionModel.sendToViews(new Seal.ActivateEngine(mediatorEngine.getEngine()));
76
                    }
77
                    
78
                    charFromOrderBy = currentCallable.getCharacterInsertion();
79
                    LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "Character insertion [{}] matching with Order by and compatible with Error strategy", charFromOrderBy);
80
                    break;
81
                }
82
            } catch (InterruptedException e) {
83
                LOGGER.log(LogLevelUtil.IGNORE, e, e);
84 1 1. run : removed call to java/lang/Thread::interrupt → NO_COVERAGE
                Thread.currentThread().interrupt();
85
            } catch (ExecutionException e) {
86
                LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
87
            }
88
        }
89 1 1. run : removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE
        this.injectionModel.getMediatorUtils().threadUtil().shutdown(taskExecutor);
90 2 1. run : negated conditional → NO_COVERAGE
2. run : negated conditional → NO_COVERAGE
        if (charFromOrderBy == null && charFromBooleanMatch[0] != null) {
91
            charFromOrderBy = charFromBooleanMatch[0];
92
        }
93 1 1. run : replaced return value with "" for com/jsql/model/suspendable/SuspendableGetCharInsertion::run → NO_COVERAGE
        return this.getCharacterInsertion(characterInsertionByUser, charFromOrderBy);
94
    }
95
96
    private void setEngine(MediatorEngine mediatorEngine, List<Engine> enginesOrderByMatches) {
97
        if (
98 1 1. setEngine : negated conditional → NO_COVERAGE
            enginesOrderByMatches.size() == 1
99 1 1. setEngine : negated conditional → NO_COVERAGE
            && enginesOrderByMatches.getFirst() != mediatorEngine.getEngine()
100
        ) {
101 1 1. setEngine : removed call to com/jsql/model/injection/engine/MediatorEngine::setEngine → NO_COVERAGE
            mediatorEngine.setEngine(enginesOrderByMatches.getFirst());
102 2 1. setEngine : negated conditional → NO_COVERAGE
2. setEngine : changed conditional boundary → NO_COVERAGE
        } else if (enginesOrderByMatches.size() > 1) {
103 1 1. setEngine : negated conditional → NO_COVERAGE
            if (enginesOrderByMatches.contains(mediatorEngine.getPostgres())) {
104 1 1. setEngine : removed call to com/jsql/model/injection/engine/MediatorEngine::setEngine → NO_COVERAGE
                mediatorEngine.setEngine(mediatorEngine.getPostgres());
105 1 1. setEngine : negated conditional → NO_COVERAGE
            } else if (enginesOrderByMatches.contains(mediatorEngine.getMysql())) {
106 1 1. setEngine : removed call to com/jsql/model/injection/engine/MediatorEngine::setEngine → NO_COVERAGE
                mediatorEngine.setEngine(mediatorEngine.getMysql());
107
            } else {
108 1 1. setEngine : removed call to com/jsql/model/injection/engine/MediatorEngine::setEngine → NO_COVERAGE
                mediatorEngine.setEngine(enginesOrderByMatches.getFirst());
109
            }
110
        }
111
    }
112
113
    private List<Engine> getEnginesOrderByMatch(MediatorEngine mediatorEngine, String pageSource) {
114 1 1. getEnginesOrderByMatch : replaced return value with Collections.emptyList for com/jsql/model/suspendable/SuspendableGetCharInsertion::getEnginesOrderByMatch → NO_COVERAGE
        return mediatorEngine.getEnginesForFingerprint()
115
            .stream()
116 2 1. lambda$getEnginesOrderByMatch$0 : replaced boolean return with true for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$0 → NO_COVERAGE
2. lambda$getEnginesOrderByMatch$0 : negated conditional → NO_COVERAGE
            .filter(engine -> engine != mediatorEngine.getAuto())
117 2 1. lambda$getEnginesOrderByMatch$1 : replaced boolean return with false for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$1 → NO_COVERAGE
2. lambda$getEnginesOrderByMatch$1 : replaced boolean return with true for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$1 → NO_COVERAGE
            .filter(engine -> StringUtils.isNotEmpty(
118
                engine.instance().getModelYaml().getStrategy().getConfiguration().getFingerprint().getOrderByErrorMessage()
119
            ))
120
            .filter(engine -> {
121
                Optional<String> optionalOrderByErrorMatch = Stream.of(
122
                    engine.instance().getModelYaml().getStrategy().getConfiguration().getFingerprint().getOrderByErrorMessage()
123
                    .split("[\\r\\n]+")
124
                )
125
                .filter(errorMessage ->
126 2 1. lambda$getEnginesOrderByMatch$2 : replaced boolean return with true for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$2 → NO_COVERAGE
2. lambda$getEnginesOrderByMatch$2 : replaced boolean return with false for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$2 → NO_COVERAGE
                    Pattern
127
                    .compile(".*" + errorMessage + ".*", Pattern.DOTALL)
128
                    .matcher(pageSource)
129
                    .matches()
130
                )
131
                .findAny();
132 1 1. lambda$getEnginesOrderByMatch$3 : negated conditional → NO_COVERAGE
                if (optionalOrderByErrorMatch.isPresent()) {
133
                    LOGGER.log(
134
                        LogLevelUtil.CONSOLE_SUCCESS,
135
                        String.format("Order by fingerprint matching vendor [%s]", engine)
136
                    );
137
                }
138 2 1. lambda$getEnginesOrderByMatch$3 : replaced boolean return with false for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$3 → NO_COVERAGE
2. lambda$getEnginesOrderByMatch$3 : replaced boolean return with true for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$3 → NO_COVERAGE
                return optionalOrderByErrorMatch.isPresent();
139
            })
140
            .toList();
141
    }
142
143
    private List<String> initCallables(CompletionService<CallablePageSource> taskCompletionService, String[] charFromBooleanMatch) throws JSqlException {
144
        List<String> prefixValues = Arrays.asList(
145
            RandomStringUtils.secure().next(10, "012"),  // to trigger probable failure
146
            "1"  // to trigger eventual success
147
        );
148
        List<String> prefixQuotes = Arrays.asList(
149
            SuspendableGetCharInsertion.LABEL_PREFIX +"'",
150
            SuspendableGetCharInsertion.LABEL_PREFIX,
151
            SuspendableGetCharInsertion.LABEL_PREFIX +"`",  // TODO add ITs
152
            SuspendableGetCharInsertion.LABEL_PREFIX +"\"",
153
            SuspendableGetCharInsertion.LABEL_PREFIX +"%bf'"  // GBK slash encoding use case
154
        );
155
        List<String> prefixParentheses = Arrays.asList(StringUtils.EMPTY, ")", "))");
156
        List<String> charactersInsertion = new ArrayList<>();
157
        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Fingerprinting character insertion with Boolean match...");
158
        for (String prefixValue: prefixValues) {
159
            for (String prefixQuote: prefixQuotes) {
160
                for (String prefixParenthesis: prefixParentheses) {
161 1 1. initCallables : removed call to com/jsql/model/suspendable/SuspendableGetCharInsertion::checkInsertionChar → NO_COVERAGE
                    this.checkInsertionChar(charFromBooleanMatch, charactersInsertion, prefixValue, prefixQuote, prefixParenthesis);
162
                }
163
            }
164
        }
165
        for (String characterInsertion: charactersInsertion) {
166
            taskCompletionService.submit(
167
                new CallablePageSource(
168
                    characterInsertion
169
                    + StringUtils.SPACE  // covered by cleaning
170
                    + this.injectionModel.getMediatorEngine().getEngine().instance().sqlOrderBy(),
171
                    characterInsertion,
172
                    this.injectionModel,
173
                    "prefix#orderby"
174
                )
175
            );
176
        }
177 1 1. initCallables : replaced return value with Collections.emptyList for com/jsql/model/suspendable/SuspendableGetCharInsertion::initCallables → NO_COVERAGE
        return charactersInsertion;
178
    }
179
180
    private void checkInsertionChar(
181
        String[] charFromBooleanMatch,
182
        List<String> charactersInsertion,
183
        String prefixValue,
184
        String prefixQuote,
185
        String prefixParenthesis
186
    ) throws StoppedByUserSlidingException {
187
        String characterInsertion = prefixQuote.replace(SuspendableGetCharInsertion.LABEL_PREFIX, prefixValue) + prefixParenthesis;
188
        charactersInsertion.add(characterInsertion);
189
        // Skipping Boolean match when already found
190 1 1. checkInsertionChar : negated conditional → NO_COVERAGE
        if (charFromBooleanMatch[0] == null) {
191
            var injectionCharInsertion = new InjectionCharInsertion(
192
                this.injectionModel,
193
                characterInsertion,
194
                prefixQuote + prefixParenthesis
195
            );
196 1 1. checkInsertionChar : negated conditional → NO_COVERAGE
            if (injectionCharInsertion.isInjectable()) {
197 1 1. checkInsertionChar : negated conditional → NO_COVERAGE
                if (this.isSuspended()) {
198
                    throw new StoppedByUserSlidingException();
199
                }
200
                charFromBooleanMatch[0] = characterInsertion;
201
                LOGGER.log(
202
                    LogLevelUtil.CONSOLE_SUCCESS,
203
                    "Found character insertion [{}] using Boolean match",
204 1 1. lambda$checkInsertionChar$4 : replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$checkInsertionChar$4 → NO_COVERAGE
                    () -> charFromBooleanMatch[0]
205
                );
206
            }
207
        }
208
    }
209
    
210
    private String getCharacterInsertion(String characterInsertionByUser, String characterInsertionDetected) {
211
        String characterInsertionDetectedFixed = characterInsertionDetected;
212 1 1. getCharacterInsertion : negated conditional → NO_COVERAGE
        if (characterInsertionDetectedFixed == null) {
213
            characterInsertionDetectedFixed = characterInsertionByUser;
214
            String logCharacterInsertion = characterInsertionDetectedFixed;
215
            LOGGER.log(
216
                LogLevelUtil.CONSOLE_ERROR,
217
                "No character insertion found, forcing to [{}]",
218 1 1. lambda$getCharacterInsertion$5 : replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getCharacterInsertion$5 → NO_COVERAGE
                () -> logCharacterInsertion.replace(InjectionModel.STAR, StringUtils.EMPTY)
219
            );
220 1 1. getCharacterInsertion : negated conditional → NO_COVERAGE
        } else if (!characterInsertionByUser.replace(InjectionModel.STAR, StringUtils.EMPTY).equals(characterInsertionDetectedFixed)) {
221
            String characterInsertionByUserFormat = characterInsertionByUser.replace(InjectionModel.STAR, StringUtils.EMPTY);
222
            LOGGER.log(
223
                LogLevelUtil.CONSOLE_INFORM,
224
                "Using [{}] and matching [{}]",
225 1 1. lambda$getCharacterInsertion$6 : replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getCharacterInsertion$6 → NO_COVERAGE
                () -> this.injectionModel.getMediatorEngine().getEngine(),
226 1 1. lambda$getCharacterInsertion$7 : replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getCharacterInsertion$7 → NO_COVERAGE
                () -> characterInsertionDetected
227
            );
228
            LOGGER.log(
229
                LogLevelUtil.CONSOLE_DEFAULT,
230
                "Disable search for char insertion in Preferences to force the value [{}]",
231 1 1. lambda$getCharacterInsertion$8 : replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getCharacterInsertion$8 → NO_COVERAGE
                () -> characterInsertionByUserFormat
232
            );
233
        } else {
234
            LOGGER.log(
235
                LogLevelUtil.CONSOLE_INFORM,
236
                "{} [{}]",
237 1 1. lambda$getCharacterInsertion$9 : replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getCharacterInsertion$9 → NO_COVERAGE
                () -> I18nUtil.valueByKey("LOG_USING_INSERTION_CHARACTER"),
238 1 1. lambda$getCharacterInsertion$10 : replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getCharacterInsertion$10 → NO_COVERAGE
                () -> characterInsertionDetected.replace(InjectionModel.STAR, StringUtils.EMPTY)
239
            );
240
        }
241 1 1. getCharacterInsertion : replaced return value with "" for com/jsql/model/suspendable/SuspendableGetCharInsertion::getCharacterInsertion → NO_COVERAGE
        return characterInsertionDetectedFixed;
242
    }
243
}

Mutations

60

1.1
Location : run
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : run
Killed by : none
changed conditional boundary → NO_COVERAGE

61

1.1
Location : run
Killed by : none
negated conditional → NO_COVERAGE

66

1.1
Location : run
Killed by : none
Changed increment from -1 to 1 → NO_COVERAGE

70

1.1
Location : run
Killed by : none
negated conditional → NO_COVERAGE

71

1.1
Location : run
Killed by : none
negated conditional → NO_COVERAGE

72

1.1
Location : run
Killed by : none
removed call to com/jsql/model/suspendable/SuspendableGetCharInsertion::setEngine → NO_COVERAGE

75

1.1
Location : run
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

84

1.1
Location : run
Killed by : none
removed call to java/lang/Thread::interrupt → NO_COVERAGE

89

1.1
Location : run
Killed by : none
removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE

90

1.1
Location : run
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : run
Killed by : none
negated conditional → NO_COVERAGE

93

1.1
Location : run
Killed by : none
replaced return value with "" for com/jsql/model/suspendable/SuspendableGetCharInsertion::run → NO_COVERAGE

98

1.1
Location : setEngine
Killed by : none
negated conditional → NO_COVERAGE

99

1.1
Location : setEngine
Killed by : none
negated conditional → NO_COVERAGE

101

1.1
Location : setEngine
Killed by : none
removed call to com/jsql/model/injection/engine/MediatorEngine::setEngine → NO_COVERAGE

102

1.1
Location : setEngine
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : setEngine
Killed by : none
changed conditional boundary → NO_COVERAGE

103

1.1
Location : setEngine
Killed by : none
negated conditional → NO_COVERAGE

104

1.1
Location : setEngine
Killed by : none
removed call to com/jsql/model/injection/engine/MediatorEngine::setEngine → NO_COVERAGE

105

1.1
Location : setEngine
Killed by : none
negated conditional → NO_COVERAGE

106

1.1
Location : setEngine
Killed by : none
removed call to com/jsql/model/injection/engine/MediatorEngine::setEngine → NO_COVERAGE

108

1.1
Location : setEngine
Killed by : none
removed call to com/jsql/model/injection/engine/MediatorEngine::setEngine → NO_COVERAGE

114

1.1
Location : getEnginesOrderByMatch
Killed by : none
replaced return value with Collections.emptyList for com/jsql/model/suspendable/SuspendableGetCharInsertion::getEnginesOrderByMatch → NO_COVERAGE

116

1.1
Location : lambda$getEnginesOrderByMatch$0
Killed by : none
replaced boolean return with true for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$0 → NO_COVERAGE

2.2
Location : lambda$getEnginesOrderByMatch$0
Killed by : none
negated conditional → NO_COVERAGE

117

1.1
Location : lambda$getEnginesOrderByMatch$1
Killed by : none
replaced boolean return with false for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$1 → NO_COVERAGE

2.2
Location : lambda$getEnginesOrderByMatch$1
Killed by : none
replaced boolean return with true for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$1 → NO_COVERAGE

126

1.1
Location : lambda$getEnginesOrderByMatch$2
Killed by : none
replaced boolean return with true for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$2 → NO_COVERAGE

2.2
Location : lambda$getEnginesOrderByMatch$2
Killed by : none
replaced boolean return with false for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$2 → NO_COVERAGE

132

1.1
Location : lambda$getEnginesOrderByMatch$3
Killed by : none
negated conditional → NO_COVERAGE

138

1.1
Location : lambda$getEnginesOrderByMatch$3
Killed by : none
replaced boolean return with false for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$3 → NO_COVERAGE

2.2
Location : lambda$getEnginesOrderByMatch$3
Killed by : none
replaced boolean return with true for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getEnginesOrderByMatch$3 → NO_COVERAGE

161

1.1
Location : initCallables
Killed by : none
removed call to com/jsql/model/suspendable/SuspendableGetCharInsertion::checkInsertionChar → NO_COVERAGE

177

1.1
Location : initCallables
Killed by : none
replaced return value with Collections.emptyList for com/jsql/model/suspendable/SuspendableGetCharInsertion::initCallables → NO_COVERAGE

190

1.1
Location : checkInsertionChar
Killed by : none
negated conditional → NO_COVERAGE

196

1.1
Location : checkInsertionChar
Killed by : none
negated conditional → NO_COVERAGE

197

1.1
Location : checkInsertionChar
Killed by : none
negated conditional → NO_COVERAGE

204

1.1
Location : lambda$checkInsertionChar$4
Killed by : none
replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$checkInsertionChar$4 → NO_COVERAGE

212

1.1
Location : getCharacterInsertion
Killed by : none
negated conditional → NO_COVERAGE

218

1.1
Location : lambda$getCharacterInsertion$5
Killed by : none
replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getCharacterInsertion$5 → NO_COVERAGE

220

1.1
Location : getCharacterInsertion
Killed by : none
negated conditional → NO_COVERAGE

225

1.1
Location : lambda$getCharacterInsertion$6
Killed by : none
replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getCharacterInsertion$6 → NO_COVERAGE

226

1.1
Location : lambda$getCharacterInsertion$7
Killed by : none
replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getCharacterInsertion$7 → NO_COVERAGE

231

1.1
Location : lambda$getCharacterInsertion$8
Killed by : none
replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getCharacterInsertion$8 → NO_COVERAGE

237

1.1
Location : lambda$getCharacterInsertion$9
Killed by : none
replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getCharacterInsertion$9 → NO_COVERAGE

238

1.1
Location : lambda$getCharacterInsertion$10
Killed by : none
replaced return value with null for com/jsql/model/suspendable/SuspendableGetCharInsertion::lambda$getCharacterInsertion$10 → NO_COVERAGE

241

1.1
Location : getCharacterInsertion
Killed by : none
replaced return value with "" for com/jsql/model/suspendable/SuspendableGetCharInsertion::getCharacterInsertion → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.22.1