JsonUtil.java

1
package com.jsql.util;
2
3
import com.jsql.model.InjectionModel;
4
import com.jsql.model.exception.JSqlException;
5
import com.jsql.model.injection.method.AbstractMethodInjection;
6
import org.apache.commons.lang3.StringUtils;
7
import org.apache.logging.log4j.LogManager;
8
import org.apache.logging.log4j.Logger;
9
import org.json.JSONArray;
10
import org.json.JSONException;
11
import org.json.JSONObject;
12
13
import java.util.AbstractMap.SimpleEntry;
14
import java.util.ArrayList;
15
import java.util.Iterator;
16
import java.util.List;
17
import java.util.regex.Pattern;
18
19
public class JsonUtil {
20
    
21
    private static final Logger LOGGER = LogManager.getRootLogger();
22
23
    private final InjectionModel injectionModel;
24
    
25
    public JsonUtil(InjectionModel injectionModel) {
26
        this.injectionModel = injectionModel;
27
    }
28
29
    public static Object getJson(String param) {
30
        Object jsonEntity;  // Will test if current value is a JSON entity
31
        try {
32
            jsonEntity = new JSONObject(param);  // Test for JSON Object
33
        } catch (JSONException exceptionJSONObject) {
34
            try {
35
                jsonEntity = new JSONArray(param);  // Test for JSON Array
36
            } catch (JSONException exceptionJSONArray) {
37
                jsonEntity = new Object();  // Not a JSON entity
38
            }
39
        }
40 1 1. getJson : replaced return value with null for com/jsql/util/JsonUtil::getJson → KILLED
        return jsonEntity;
41
    }
42
43
    public static List<SimpleEntry<String, String>> createEntries(Object jsonEntity, String parentName, SimpleEntry<String, String> parentXPath) {
44
        List<SimpleEntry<String, String>> attributesXPath = new ArrayList<>();
45 1 1. createEntries : negated conditional → KILLED
        if (jsonEntity instanceof JSONObject) {
46 1 1. createEntries : removed call to com/jsql/util/JsonUtil::scanJsonObject → KILLED
            JsonUtil.scanJsonObject(jsonEntity, parentName, parentXPath, attributesXPath);
47 1 1. createEntries : negated conditional → KILLED
        } else if (jsonEntity instanceof JSONArray) {
48 1 1. createEntries : removed call to com/jsql/util/JsonUtil::scanJsonArray → KILLED
            JsonUtil.scanJsonArray(jsonEntity, parentName, parentXPath, attributesXPath);
49
        }
50 1 1. createEntries : replaced return value with Collections.emptyList for com/jsql/util/JsonUtil::createEntries → KILLED
        return attributesXPath;
51
    }
52
53
    private static void scanJsonArray(Object jsonEntity, String parentName, SimpleEntry<String, String> parentXPath, List<SimpleEntry<String, String>> attributesXPath) {
54
        var jsonArrayEntity = (JSONArray) jsonEntity;
55 2 1. scanJsonArray : negated conditional → KILLED
2. scanJsonArray : changed conditional boundary → KILLED
        for (var i = 0 ; i < jsonArrayEntity.length() ; i++) {
56
            Object value = jsonArrayEntity.get(i);
57
            String xpath = parentName +"["+ i +"]";
58
            
59
            // Not possible to make generic with scanJsonObject() because of JSONArray.put(int) != JSONObject.put(String)
60 2 1. scanJsonArray : negated conditional → KILLED
2. scanJsonArray : negated conditional → KILLED
            if (value instanceof JSONArray || value instanceof JSONObject) {
61
                attributesXPath.addAll(JsonUtil.createEntries(value, xpath, parentXPath));
62 1 1. scanJsonArray : negated conditional → KILLED
            } else if (value instanceof String) {
63
                SimpleEntry<String, String> stringValue = new SimpleEntry<>(xpath, (String) value);
64
                attributesXPath.add(stringValue);
65
                
66 1 1. scanJsonArray : negated conditional → SURVIVED
                if (parentXPath == null) {
67
                    jsonArrayEntity.put(i, value.toString().replaceAll(Pattern.quote(InjectionModel.STAR) +"$", StringUtils.EMPTY));
68 1 1. scanJsonArray : negated conditional → NO_COVERAGE
                } else if (stringValue.equals(parentXPath)) {
69
                    jsonArrayEntity.put(i, value + InjectionModel.STAR);
70
                }
71
            }
72
        }
73
    }
74
75
    private static void scanJsonObject(Object jsonEntity, String parentName, SimpleEntry<String, String> parentXPath, List<SimpleEntry<String, String>> attributesXPath) {
76
        var jsonObjectEntity = (JSONObject) jsonEntity;
77
        Iterator<?> keys = jsonObjectEntity.keys();
78 1 1. scanJsonObject : negated conditional → KILLED
        while (keys.hasNext()) {
79
            String key = (String) keys.next();
80
            var value = jsonObjectEntity.get(key);
81
            String xpath = parentName +"."+ key;
82
            
83
            // Not possible to make generic with scanJsonObject() because of JSONArray.put(int) != JSONObject.put(String)
84 2 1. scanJsonObject : negated conditional → KILLED
2. scanJsonObject : negated conditional → KILLED
            if (value instanceof JSONArray || value instanceof JSONObject) {
85
                attributesXPath.addAll(JsonUtil.createEntries(value, xpath, parentXPath));
86 1 1. scanJsonObject : negated conditional → KILLED
            } else if (value instanceof String) {
87
                
88
                SimpleEntry<String, String> stringValue = new SimpleEntry<>(xpath, (String) value);
89
                attributesXPath.add(stringValue);
90
                
91 1 1. scanJsonObject : negated conditional → KILLED
                if (parentXPath == null) {
92
                    jsonObjectEntity.put(key, value.toString().replaceAll(Pattern.quote(InjectionModel.STAR) +"$", StringUtils.EMPTY));
93 1 1. scanJsonObject : negated conditional → KILLED
                } else if (stringValue.equals(parentXPath)) {
94
                    jsonObjectEntity.put(key, value + InjectionModel.STAR);
95
                }
96
            }
97
        }
98
    }
99
    
100
    public boolean testJsonParam(AbstractMethodInjection methodInjection, SimpleEntry<String, String> paramStar) {
101
        var hasFoundInjection = false;
102
        
103
        // Remove STAR at the end of parameter, STAR will be added inside json data instead
104
        paramStar.setValue(paramStar.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY));
105
        
106
        // Will test if current value is a JSON entity
107
        Object jsonEntity = JsonUtil.getJson(paramStar.getValue());
108
        
109
        // Define a tree of JSON attributes with path as the key: root.a => value of a
110
        List<SimpleEntry<String, String>> attributesJson = JsonUtil.createEntries(jsonEntity, "root", null);
111
        
112
        // Loop through each JSON values
113
        for (SimpleEntry<String, String> parentXPath: attributesJson) {
114
            JsonUtil.createEntries(jsonEntity, "root", null);  // Erase previously defined *
115
            JsonUtil.createEntries(jsonEntity, "root", parentXPath);  // Add * to current parameter's value
116
117
            paramStar.setValue(jsonEntity.toString());  // Replace param value by marked one
118
            
119
            try {
120
                LOGGER.log(
121
                    LogLevelUtil.CONSOLE_INFORM,
122
                    "{} JSON {}={} with {}",
123 1 1. lambda$testJsonParam$0 : replaced return value with null for com/jsql/util/JsonUtil::lambda$testJsonParam$0 → NO_COVERAGE
                    () -> I18nUtil.valueByKey("LOG_CHECKING"),
124
                    parentXPath::getKey,
125 1 1. lambda$testJsonParam$1 : replaced return value with null for com/jsql/util/JsonUtil::lambda$testJsonParam$1 → NO_COVERAGE
                    () -> parentXPath.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY),
126
                    methodInjection::name
127
                );
128
                
129
                // Test current JSON value marked with * for injection
130
                // Keep original param
131
                hasFoundInjection = this.injectionModel.getMediatorStrategy().testStrategies(paramStar);
132
                
133
                // Injection successful
134
                break;
135
            } catch (JSqlException e) {
136
                // Injection failure
137
                LOGGER.log(
138
                    LogLevelUtil.CONSOLE_ERROR,
139
                    String.format(
140
                        "No injection found for JSON %s parameter %s=%s",
141
                        methodInjection.name(),
142
                        parentXPath.getKey(),
143
                        parentXPath.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY)
144
                    )
145
                );
146
            } finally {
147
                // Erase * at the end of each params
148
                // TODO useless
149
                methodInjection.getParams()
150 1 1. testJsonParam : removed call to java/util/List::forEach → NO_COVERAGE
                    .forEach(e -> e.setValue(
151
                        e.getValue().replaceAll(Pattern.quote(InjectionModel.STAR) +"$", StringUtils.EMPTY)
152
                    ));
153
                
154
                // Erase * from JSON if failure
155 1 1. testJsonParam : negated conditional → NO_COVERAGE
                if (!hasFoundInjection) {
156
                    paramStar.setValue(
157
                        paramStar.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY)
158
                    );
159
                }
160
            }
161
        }
162 2 1. testJsonParam : replaced boolean return with true for com/jsql/util/JsonUtil::testJsonParam → NO_COVERAGE
2. testJsonParam : replaced boolean return with false for com/jsql/util/JsonUtil::testJsonParam → NO_COVERAGE
        return hasFoundInjection;
163
    }
164
}

Mutations

40

1.1
Location : getJson
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_3]
replaced return value with null for com/jsql/util/JsonUtil::getJson → KILLED

45

1.1
Location : createEntries
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

46

1.1
Location : createEntries
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
removed call to com/jsql/util/JsonUtil::scanJsonObject → KILLED

47

1.1
Location : createEntries
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

48

1.1
Location : createEntries
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
removed call to com/jsql/util/JsonUtil::scanJsonArray → KILLED

50

1.1
Location : createEntries
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
replaced return value with Collections.emptyList for com/jsql/util/JsonUtil::createEntries → KILLED

55

1.1
Location : scanJsonArray
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

2.2
Location : scanJsonArray
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
changed conditional boundary → KILLED

60

1.1
Location : scanJsonArray
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

2.2
Location : scanJsonArray
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

62

1.1
Location : scanJsonArray
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

66

1.1
Location : scanJsonArray
Killed by : none
negated conditional → SURVIVED
Covering tests

68

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

78

1.1
Location : scanJsonObject
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

84

1.1
Location : scanJsonObject
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

2.2
Location : scanJsonObject
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

86

1.1
Location : scanJsonObject
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

91

1.1
Location : scanJsonObject
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_0]/[iteration:0]
negated conditional → KILLED

93

1.1
Location : scanJsonObject
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_0]/[iteration:0]
negated conditional → KILLED

123

1.1
Location : lambda$testJsonParam$0
Killed by : none
replaced return value with null for com/jsql/util/JsonUtil::lambda$testJsonParam$0 → NO_COVERAGE

125

1.1
Location : lambda$testJsonParam$1
Killed by : none
replaced return value with null for com/jsql/util/JsonUtil::lambda$testJsonParam$1 → NO_COVERAGE

150

1.1
Location : testJsonParam
Killed by : none
removed call to java/util/List::forEach → NO_COVERAGE

155

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

162

1.1
Location : testJsonParam
Killed by : none
replaced boolean return with true for com/jsql/util/JsonUtil::testJsonParam → NO_COVERAGE

2.2
Location : testJsonParam
Killed by : none
replaced boolean return with false for com/jsql/util/JsonUtil::testJsonParam → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.19.1