-
Notifications
You must be signed in to change notification settings - Fork 0
/
runEvoSuite.sh
executable file
·349 lines (320 loc) · 14.4 KB
/
runEvoSuite.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
#!/bin/bash
source utils.sh
source runEvoSuite_configuration.sh
DEBUG=1
#set -x #Comment to disable debug output of this script (this is a full verbosity mode; you should use the debug functionality from utils.sh instead)
getoptWorks=""
checkGetopt getoptWorks
if [[ "$getoptWorks" -eq "0" ]]; then
debug "getopt is working"
else
error "getopt command is not working, please check that getopt is installed and available" 1
fi
LONGOPTIONS=targetClassname:,sourceDir:,binDir:,testDir:,classpath:,configFile:,seed:,help
OPTIONS=t:,s:,b:,e:,c:,f:,d:,h
#Display script usage
#error : if 0 the usage comes from normal behaviour, if > 0 then it comes from an error and will exit with this as exit code
#extra information : an additional message
function usage() {
local code="$1"
local extraMsg="$2"
local msg="Runs EvoSuite for a particular class and a given configuration for EvoSuite, then it runs JaCoCo to meassure line and branch coverage.\nUsage:\nrunEvoSuite.sh -[-h]elp to show this message\nrunEvoSuite.sh -[-t]argetClassname <target> -[-s]ourceDir <path> -[-b]inDir <path> -[-]t[e]stDir <path> -[-c]lasspath <paths> -[-]con[f]igFile <path> -[-]see[d] <int>n\tTarget class is a full classname.\n\tSource and Bin paths refers to where the sources (.java) and compiled (.class) files are located respectivelly.\n\tThe classpath refers to additional paths needed, these must be separated by ':'.\n\tThe config file refers to a .evoconfig file with the EvoSuite configuration to use (see example.evoconfig).\n\tThe seed will be used by EvoSuite and it must be a positive integer."
if [[ "$code" -eq "0" ]]; then
[ ! -z "$extraMsg" ] && infoMessage "$extraMsg"
infoMessage "$msg"
exit 0
else
if [ -z "$extraMsg" ]; then
error "Wrong usage\n$msg" "$code"
else
error "Wrong usage\n${extraMsg}\n$msg" "$code"
fi
fi
}
#Arguments
classname=""
classnameSet=0
sourceDir=""
sourceDirSet=0
binDir=""
binDirSet=0
testDir=""
testDirSet=0
additionalClasspath=""
additionalClasspathSet=0
configFile=""
configFileSet=0
seed=0
seedSet=0
PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTIONS --name "$0" -- "$@")
getoptExitCode="$?"
if [[ "$getoptExitCode" -ne "0" ]]; then
error "Error while parsing arguments ($getoptExitCode)" 1
fi
eval set -- "$PARSED"
while true; do
case "$1" in
--targetClassname | -t)
classname="$2"
[ -z "$classname" ] || $(echo "$classname" | egrep -q "^[[:space:]]+$") && error "key,value separator is empty or contains only spaces" 2
classnameSet=1
shift 2
;;
--sourceDir | -s)
sourceDir="$2"
[ -z "$sourceDir" ] || $(echo "$sourceDir" | egrep -q "^[[:space:]]+$") && error "source directory path (${sourceDir}) is empty or contains only spaces" 3
[ ! -d "$sourceDir" ] && error "source directory ($sourceDir) does not exists or is not a directory" 3
sourceDirSet=1
shift 2
;;
--binDir | -b)
binDir="$2"
[ -z "$binDir" ] || $(echo "$binDir" | egrep -q "^[[:space:]]+$") && error "bin directory path (${binDir}) is empty or contains only spaces" 4
[ ! -d "$binDir" ] && error "bin directory ($binDir) does not exists or is not a directory" 4
binDirSet=1
shift 2
;;
--testDir | -e)
testDir="$2"
[ -z "$testDir" ] || $(echo "$testDir" | egrep -q "^[[:space:]]+$") && error "tests directory path (${testDir}) is empty or contains only spaces" 5
[ -d "$testDir" ] && [ ! -z "$(ls -A ${testDir})" ] && error "tests directory exists and is not empty" 5
testDirSet=1
shift 2
;;
--classpath | -c)
additionalClasspath="$2"
[ -z "$additionalClasspath" ] || $(echo "$additionalClasspath" | egrep -q "^[[:space:]]+$") && error "additional classpath (${additionalClasspath}) is empty or contains only spaces" 6
$(echo "$additionalClasspath" | egrep -q "(^:.*)|(.*:$)") && error "additional classpath ($additionalClasspath) cannot start or end with ':'" 6
additionalClasspathSet=1
shift 2
;;
--configFile | -f)
configFile="$2"
[ -z "$configFile" ] || $(echo "$configFile" | egrep -q "^[[:space:]]+$") && error "config file path (${configFile}) is empty or contains only spaces" 7
$(echo "$configFile" | egrep -qv ".*\.evoconfig$") && error "config file ($configFile) does not have extension '.evoconfig'" 7
[ ! -f "$configFile" ] && error "config file (${configFile}) does not exists" 7
configFileSet=1
shift 2
;;
--seed | -d)
seed="$2"
$(echo "$seed" | grep -qE "^[[:digit:]]+$") || error "Seed must be a positive number ($seed)" 8
seedSet=1
shift 2
;;
--help | -h)
usage 0 ""
;;
--)
shift
break
;;
*)
echo "Invalid arguments"
exit 3
;;
esac
done
[[ "$classnameSet" -ne "1" ]] && usage 8 "Classname was not set"
[[ "$sourceDirSet" -ne "1" ]] && usage 8 "Source directory was not set"
if [[ "$binDirSet" -ne "1" ]]; then
binDir="$sourceDir"
binDirSet=1
warning "No binary directory set, will be using source directory instead"
fi
[[ "$testDirSet" -ne "1" ]] && usage 8 "Tests directory was not set"
[[ "$additionalClasspathSet" -ne "1" ]] && debug "No additional classpath was set"
[[ "$configFileSet" -ne "1" ]] && usage 8 "Configuration file was not set"
[[ "$seedSet" -ne "1" ]] && usage 8 "Seed was not set"
infoMessage "Parsing EvoSuite configuration from ${configFile} ..."
evoArguments=""
evoProperties=""
parseFromConfigFile "${configFile}" "=" " " "#" "[[:lower:]]" "--" evoArguments
parseFromConfigFile "${configFile}" "=" "=" "#" "D" "-" evoProperties
evosuiteArguments=""
append "$evoArguments" "$evoProperties" " " evosuiteArguments
debug "EvoSuite configuration parsed\nArguments: ${evoArguments}\nProperties: ${evoProperties}\nEvoSuite all arguments: ${evosuiteArguments}"
classnameAsPath=$(echo "$classname" | sed 's;\.;/;g')
#############################################################################################################################################
#Runs evosuite for the given arguments:
#class : class for which to generate tests
#project classpath : classpath to project related code and libraries
#output dir : where tests will be placed
#argumentsAndProperties : arguments and properties for EvoSuite (excluding Dtest_dir, Djunit_suffix, and --seed)
#seed : the seed to be used by EvoSuite
function evosuite() {
infoMessage "Running EvoSuite..."
#-base_dir $outputDir
local class="$1"
local projectCP="$2"
local outputDir="$3"
local argumentsAndProperties="$4"
local eseed="$5"
if [ ! -z "$EVOSUITE_ADDITIONAL_FLAGS" ]; then
debug "Running cmd: java -jar $EVOSUITE_JAR -class $class -projectCP $projectCP -Dtest_dir=$outputDir -Djunit_suffix=$ES_JUNIT_SUFFIX $EVOSUITE_ADDITIONAL_FLAGS --seed $eseed ${argumentsAndProperties}"
java -jar $EVOSUITE_JAR -class $class -projectCP $projectCP -Dtest_dir="$outputDir" -Djunit_suffix="$ES_JUNIT_SUFFIX" "$EVOSUITE_ADDITIONAL_FLAGS" --seed "$eseed" ${argumentsAndProperties} 2>&1 | tee -a "$EVOSUITE_LOG"
else
debug "Running cmd: java -jar $EVOSUITE_JAR -class $class -projectCP $projectCP -Dtest_dir=$outputDir -Djunit_suffix=$ES_JUNIT_SUFFIX --seed $eseed ${argumentsAndProperties}"
java -jar $EVOSUITE_JAR -class $class -projectCP $projectCP -Dtest_dir="$outputDir" -Djunit_suffix="$ES_JUNIT_SUFFIX" --seed "$eseed" ${argumentsAndProperties} 2>&1 | tee -a "$EVOSUITE_LOG"
fi
}
#Compiles evosuite generated tests
#target : class to compile
#root folder : folder to where the tests where saved
#classpath : required classpath
#exitCode(R) : where to return the exit code
function compileEvosuiteTests() {
infoMessage "Compiling EvoSuite tests..."
local target="$1"
local rootFolder="$2"
local classpath="$3"
pushd $rootFolder
local exitCode=""
debug "Running cmd: javac -cp $classpath:$JUNIT:$TESTING_JARS_ES $target"
javac -cp "$classpath:$JUNIT:$TESTING_JARS_ES" "$target"
exitCode="$?"
debug "Exit code: $exitCode"
popd
eval "$4='$exitCode'"
}
function getTestsFrom() {
local from="$1"
local es_tests=""
local backupIFS="$IFS"
IFS='
'
[ -e "${from}" ] && for x in `find "${from}" | awk "/${ES_JUNIT_SUFFIX}\.java/"`; do
testClass=$(echo $x | sed "s|${from}||g" | sed "s|\.java||g" | sed "s|\/|.|g")
if [ -z "$es_tests" ] ; then
es_tests="$testClass"
else
es_tests="${es_tests} $testClass"
fi
debug "Test found: $testClass"
done
debug "EvoSuite tests: ${es_tests}"
local all_tests="$es_tests"
eval "$2='$all_tests'"
IFS="$backupIFS"
}
#Runs jacoco for coverage, and generates a report
#classpath : the classpath to use
#testpath : the classpath to tests
#sourcefiles : the source files of classes to cover
#classfiles : where the class files are located (e.g.: bin/ classes/ build/)
#tests : tests to run
#classToAnalyze : the class to analyze
function jacoco() {
infoMessage "Running JaCoCo..."
local classpath="$1"
local testpath="$2"
local sourcefiles="$3"
local classfiles="$4"
local tests="$5"
local classToAnalyze="$6"
local classToAnalyzeAsPath=$(echo "$classToAnalyze" | sed 's|\.|/|g')
local fullPathToClassToAnalize=""
local fullPathToSourceOfClassToAnalize=""
local JUNIT_RUNNER=org.junit.runner.JUnitCore
appendPaths "$classfiles" "${classToAnalyzeAsPath}.class" 0 fullPathToClassToAnalize
appendPaths "$sourcefiles" "${classToAnalyzeAsPath}.java" 0 fullPathToSourceOfClassToAnalize
if [[ "$USE_OFFLINE_INSTRUMENTATION" -eq "1" ]]; then
infoMessage "Using offline instrumentation approach"
local classToAnalizePackage=$(dirname "${classToAnalyzeAsPath}.java")
local instrumentationDestination=""
appendPaths "$OFFLINE_INSTR_DIR_LOCATION" "$classToAnalizePackage" "0" instrumentationDestination
debug "Running cmd: java -jar $JACOCO_CLI instrument $fullPathToClassToAnalize --dest $instrumentationDestination"
java -jar "$JACOCO_CLI" instrument "$fullPathToClassToAnalize" --dest "$instrumentationDestination"
exitCode="$?"
debug "Exit code: $exitCode"
if [[ "$exitCode" -ne "0" ]]; then
error "JaCoCo instrumentation failed (${exitCode})" 501
fi
debug "Deactivating original file $fullPathToClassToAnalize"
mv "$fullPathToClassToAnalize" "${fullPathToClassToAnalize}.bak"
exitCode="$?"
if [[ "$exitCode" -ne "0" ]]; then
error "Deactivating original file failed (${exitCode})" 502
fi
debug "Running tests with instrumented class"
debug "Running cmd: java -cp $classpath:$testpath:$JUNIT:$HAMCREST:$TESTING_JARS_ES:$JACOCO_AGENT -Djacoco-agent.destfile=${JACOCO_EXEC_FILE} org.junit.runner.JUnitCore $tests"
java -cp "$classpath:$testpath:$JUNIT:$HAMCREST:$TESTING_JARS_ES:$JACOCO_AGENT:$OFFLINE_INSTR_DIR_LOCATION" -Djacoco-agent.destfile=${JACOCO_EXEC_FILE} $JUNIT_RUNNER $tests
exitCode="$?"
debug "Restoring original file $fullPathToClassToAnalize"
mv "${fullPathToClassToAnalize}.bak" "$fullPathToClassToAnalize"
exitCodeMv="$?"
if [[ "$exitCodeMv" -ne "0" ]]; then
error "Restoring original file failed (${exitCodeMv}) tests may have also failed if the following is not 0 ($exitCode)" 503
fi
if [[ "$exitCode" -ne "0" ]]; then
error "Failed to run tests with instrumented class (${exitCode})" 504
fi
else
infoMessage "Using Java Agent approach"
debug "Running cmd: java -javaagent: $JACOCO_AGENT -cp $classpath:$testpath:$JUNIT:$HAMCREST:$TESTING_JARS_ES org.junit.runner.JUnitCore $tests"
java -javaagent:"$JACOCO_AGENT" -cp "$classpath:$testpath:$JUNIT:$HAMCREST:$TESTING_JARS_ES" $JUNIT_RUNNER $tests
exitCode="$?"
if [[ "$exitCode" -ne "0" ]]; then
error "Failed to run tests with JaCoCo agent (${exitCode})" 501
fi
fi
debug "All tests executed, generating JaCoCo raw report"
if [ ! -e "$JACOCO_EXEC_FILE" ]; then
infoMessage "No JaCoCo exec file found ($JACOCO_EXEC_FILE), this is most likely due to no test exercised the target class ($classToAnalyze)"
echo "File $JACOCO_EXEC_FILE not found, is probably that no test exercised the target class ($classToAnalyze)" > "$JACOCO_REPORT_RESUMED_FILE"
else
debug "Running cmd: java -jar $JACOCO_CLI report jacoco.exec --classfiles $fullPathToClassToAnalize --sourcefiles $fullPathToSourceOfClassToAnalize --xml jacoco.report.xml"
java -jar "$JACOCO_CLI" report "jacoco.exec" --classfiles "$fullPathToClassToAnalize" --sourcefiles "$fullPathToSourceOfClassToAnalize" --xml "jacoco.report.xml"
exitCode="$?"
if [[ "$exitCode" -ne "0" ]]; then
error "Error generating JaCoCo raw report (${exitCode})" 505
fi
sed -i 's;<!DOCTYPE report PUBLIC "-//JACOCO//DTD Report 1.1//EN" "report.dtd">;;g' "jacoco.report.xml"
infoMessage "Generating resumed JaCoCo report (saving to file $JACOCO_REPORT_RESUMED_FILE)"
$JACOCO_REPORT "jacoco.report.xml" --class "$classToAnalyze" >"$JACOCO_REPORT_RESUMED_FILE"
fi
}
function prepareTestsForJacoco() {
infoMessage "Preparing tests for JaCoCo..."
if [[ "$USE_OFFLINE_INSTRUMENTATION" -eq "1" ]]; then
infoMessage "Using offline instrumentation, tests will be left intact"
else
local from="$1"
find "$from" | awk '/\.java/' | xargs -I {} grep -l "separateClassLoader = true," {} | xargs -I {} sed -i "s|separateClassLoader = true,|separateClassLoader = false,|g" {}
exitCode="$?"
if [[ "$exitCode" -ne "0" ]]; then
error "An error ocurred while preparing tests for JaCoCo" 500
fi
fi
}
#MAIN
if [[ "$USE_OFFLINE_INSTRUMENTATION" -eq "1" ]]; then
if [[ -d "$OFFLINE_INSTR_DIR_LOCATION" ]] && [ ! -z "$(ls -A $OFFLINE_INSTR_DIR_LOCATION)" ]; then
error "Directory $USE_OFFLINE_INSTRUMENTATION exists and is not empty" 101
elif [[ ! -d "$OFFLINE_INSTR_DIR_LOCATION" ]]; then
debug "Generating offline instrumentation folder ($OFFLINE_INSTR_DIR_LOCATION)"
mkdir "$OFFLINE_INSTR_DIR_LOCATION"
fi
fi
#TIMES
evosuiteTime=""
############################################################################################################
#TEST GENERATION
START=$(date +%s.%N)
evosuite "$classname" "${CURRENT_DIR}/$binDir" "${CURRENT_DIR}/$testDir" "$evosuiteArguments" "$seed"
ecode="$?"
if [[ "$ecode" -ne "0" ]]; then
error "EvoSuite failed ($ecode)" 201
fi
END=$(date +%s.%N)
evosuiteTime=$(echo "$END - $START" | bc)
infoMessage "EvoSuite took $evosuiteTime"
prepareTestsForJacoco "${CURRENT_DIR}/$testDir"
compileEvosuiteTests "$classnameAsPath${ES_JUNIT_SUFFIX}.java" "${CURRENT_DIR}/${testDir}" "${CURRENT_DIR}/${binDir}:${CURRENT_DIR}/${testDir}" ecode
if [[ "$ecode" -ne "0" ]]; then
error "EvoSuite tests compilation failed ($ecode)" 301
fi
tests=""
getTestsFrom "${CURRENT_DIR}/$testDir" tests
#COVERAGE
jacoco "${CURRENT_DIR}/$binDir" "${CURRENT_DIR}/$testDir" "${CURRENT_DIR}/$sourceDir" "${CURRENT_DIR}/$binDir" "$tests" "$classname"