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

Mutations

43

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

48

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

49

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

50

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

51

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

53

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

58

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

63

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

65

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

69

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

71

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

81

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

87

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

89

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

94

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

96

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

126

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

128

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

153

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

158

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

165

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