I have a script
#!/bin/bash
#create path to redirect output.json to same directory as output.txt
path=$(dirname $1)
#create variables for name line, test lines and result line
firstline=$(cat $1 | head -n 1 | cut -d "[" -f2 | cut -d "]" -f1)
testname=$(echo $firstline)
tests=$(cat $1 | tail -n 3 | head -n -2)
results=$(cat $1 | tail -n1)
#create main JSON variable
json=$(jq -n --arg tn "$testname" '{testname:$tn,tests:[],summary:{}}')
#test's names, status, duration and updating JSON variable
IFS=$'\n'
for i in $tests
do
if [[ $i == not* ]]
then
stat=false
else
stat=true
fi
if [[ $i =~ expecting(. ?)[0-9] ]]
then
var=${BASH_REMATCH[0]}
name=${var%,*}
fi
if [[ $i =~ [0-9]*ms ]]
then
test_duration=${BASH_REMATCH[0]}
fi
json=$(echo $json | jq \
--arg na "$name" \
--arg st "$stat" \
--arg dur "$test_duration" \
'.tests = [{name:$na,status:$st|test("true"),duration:$dur}]')
done
#final success, failed, rating, duration and finishing JSON variable
IFS=$'\n'
for l in $results
do
if [[ $l =~ [0-9] ]]
then
success=${BASH_REMATCH[0]}
fi
if [[ $l =~ ,.[0-9] ]]
then
v=${BASH_REMATCH[0]}
failed=${v:2}
fi
if [[ $l =~ [0-9] .[0-9] % ]] || [[ $l =~ [0-9] % ]]
then
va=${BASH_REMATCH[0]}
rating=${va%%%}
fi
if [[ $l =~ [0-9]*ms ]]
then
duration=${BASH_REMATCH[0]}
fi
json=$(echo $json | jq \
--arg suc "$success" \
--arg fa "$failed" \
--arg rat "$rating" \
--arg dur "$duration" \
'.summary = {success:$suc|tonumber,failed:$fa|tonumber,rating:$rat|tonumber,duration:$dur}')
done
#redirect variable's output to file
echo $json | jq "." > $path"/output.json"
Output.json looks like:
{
"testname": "Behave test",
"tests": [
{
"name": "some text",
"status": true,
"duration": "7ms"
},
{
"name": "some text",
"status": false,
"duration": "27ms"
}
],
"summary": {
"success": 1,
"failed": 1,
"rating": 50,
"duration": "34ms"
}
}
Output is much more than in my example above. My question is, how I can calculate "summary" values and put it to json?
- "success" - tests with status true;
- "failed" - tests with status false;
- "rating" - success / total, and it can be float or int
- "duration" - sum of "duration" field
I will be very grateful for help.
CodePudding user response:
This adds (or replaces) a .summary
field which is calculated by reduce
ing the .tests
array to an object, initialized as {success: 0, failed: 0}
. For each array item, either .success
or .failed
is incremented, depending on the current array item's boolean .state
field. The .rating
field is incremented unconditionally, thus counting the total number of items which is later used to calculate the true rating. As for the duration, the array item's .duration
field is converted into a number by chopping off the ms
suffix, and added to the summary's (numeric) .duration
field. After the reduction, the rating is corrected by dividing the the success count by it (and multiplied by 100
for convenience). The ? // 0
part catches division by zero issues, in case the .tests
array was empty. Finally, the .duration
field is re-equipped with the ms
suffix.
.summary = (reduce .tests[] as $t ({success: 0, failed: 0};
(if $t.status then .success else .failed end, .rating) = 1
| .duration = ($t.duration | rtrimstr("ms") | tonumber)
) | .rating = (100 * (.success / .rating)? // 0) | .duration |= "\(.//0)ms")
{
"testname": "Behave test",
"tests": [
{
"name": "some text",
"status": true,
"duration": "7ms"
},
{
"name": "some text",
"status": false,
"duration": "27ms"
}
],
"summary": {
"success": 1,
"failed": 1,
"rating": 50,
"duration": "34ms"
}
}