#!/bin/bash

# Copyright (c) 2022 Daniel Adam
#
# Licensed under the Apache License, Version 2.0 (the "License"),
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#
# Helper script to collect coverage data generated by gcov
#

set -e

usage() {
	local readonly EXIT_STATUS=$1

cat << HELP_USAGE
Usage: $(basename $0) [-b|--build-dir DIR] [-h|--help] [-o|--output FILE]

Description:
    Helper script to collect coverage data

Options:
    -b|--build-dir DIR      directory where CMake build system is generated in (default: build)
    -h|--help               show help
    -o|--output FILE        path output file (default: coverage.json in the script directory)
HELP_USAGE

	exit ${EXIT_STATUS}
}

readonly SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)
readonly REPOSITORY_DIR=$(cd "${SCRIPT_DIR}/.." &> /dev/null && pwd)

BUILD_DIR=build
OUTPUT=${SCRIPT_DIR}/coverage.json
while getopts "b:ho:-:" optchar; do
	case "${optchar}" in
		-)
			case "${OPTARG}" in
				build-dir)
					BUILD_DIR="${!OPTIND}";
					OPTIND=$(($OPTIND+1))
					;;
				help)
					usage 0
					;;
				output)
					OUTPUT="${!OPTIND}";
					OPTIND=$(($OPTIND+1))
					;;
				*)
					echo "ERROR: Unknown option --${OPTARG}" >&2
					echo ""
					usage 1
					;;
			esac
			;;
		b)
			BUILD_DIR=${OPTARG}
			;;
		h)
			usage 0
			;;
		o)
			OUTPUT=${OPTARG}
			;;
		*)
			echo "ERROR: Unknown option -${OPTARG}" >&2
			echo ""
			usage 1
			;;
	esac
done

if [[ -z "${BUILD_DIR}" ]]; then
	echo "invalid build-dir value '${BUILD_DIR}'" >&2
	exit 1
fi

# change directory to root of repository so relative paths work
cd "${REPOSITORY_DIR}/${BUILD_DIR}"

# check whether gcc or clang has been used
COMPILER=gcc
if cmake -LA . | grep CMAKE_C_COMPILER | grep clang 2>/dev/null 1>&2; then
	COMPILER=clang
fi
echo "Detected compiler: ${COMPILER}"

GCOV=gcov
if [[ "${COMPILER}" == "clang" ]]; then
	if which llvm-cov 2>/dev/null 1>&2; then
		GCOV="llvm-cov gcov"
	fi
	if which llvm-cov-10 2>/dev/null 1>&2; then
		GCOV="llvm-cov-10 gcov"
	fi
fi

if ! which gcovr 2>/dev/null 1>&2; then
	echo "gcovr not installed" >&2
	exit 1
fi

gcovr --version
GCOVR_VERSION=$(gcovr --version | head -1 | awk 'NR==1 {print $2}')

# --exclude-lines-by-pattern is available from gcovr 5.0
GCOVR_OPTS=()
# use awk for float comparison
if awk "BEGIN {exit !(${GCOVR_VERSION} >= 5.0)}"; then
	echo "gcovr v5.0+ detected"
	pattern=".*("
	pattern+="assert|OC_LOG|OC_LOG_WITH_COMPONENT|OC_TRACE|OC_DBG|OC_INFO|OC_TRACE|OC_WRN|OC_ERR|OC_LOGipaddr|OC_LOGipaddr_local|OC_LOGbytes|OC_PRINTipaddr|OC_PRINTipaddr_local|SNPRINTFbytes"
	pattern+="|OC_PRINTipaddr|OC_PRINTipaddr_local|SNPRINTFbytes"
	pattern+="|OC_LOG|OC_LOG_WITH_COMPONENT|OC_TRACE|OC_DBG|OC_INFO|OC_NOTE|OC_WRN|OC_ERR|OC_LOGipaddr|OC_LOGipaddr_local|OC_LOGbytes"
	pattern+="|COAP_ERR|COAP_WRN|COAP_NOTE|COAP_INFO|COAP_DBG|COAP_TRACE"
	pattern+="|OC_CLOUD_ERR|OC_CLOUD_WRN|OC_CLOUD_NOTE|OC_CLOUD_INFO|OC_CLOUD_DBG|OC_CLOUD_TRACE"
	pattern+=")\(.*"
	GCOVR_OPTS+=("--exclude-lines-by-pattern" "${pattern}")
fi

gcovr --verbose --root .. \
	--exclude "../deps/.*" \
	--gcov-executable "${GCOV}" \
	--exclude-unreachable-branches \
	${GCOVR_OPTS[@]} \
	--json --output "${OUTPUT}"
