Skip to content

Instantly share code, notes, and snippets.

@bit-hack
Last active February 2, 2023 15:52
Show Gist options
  • Save bit-hack/f697f21540035e9f7938872287828415 to your computer and use it in GitHub Desktop.
Save bit-hack/f697f21540035e9f7938872287828415 to your computer and use it in GitHub Desktop.
cover_test
#pragma once
#define ENABLE_COVERAGE 1
#if ENABLE_COVERAGE
#define COVER_LOCATION printf("%s:%u ", __FILE__, __LINE__)
#define COVER_TOKEN printf(" // COVERED\n")
#define COVER_ONCE(TEXT) \
{ \
static uint32_t covered = 0; \
if (!covered) { \
covered = 1; \
COVER_LOCATION; \
COVER_TOKEN; \
} \
}
#define COVER_COND(TEXT, EXPR) \
if (EXPR) { \
COVER_LOCATION; \
COVER_TOKEN; \
}
#define COVER(TEXT) \
{ \
COVER_LOCATION; \
COVER_TOKEN; \
}
#else
#define COVER_ONCE(TEXT)
#define COVER_COND(TEXT, EXPR)
#define COVER(TEXT)
#endif // ENABLE_COVERAGE
#!/usr/bin/python
from __future__ import print_function
import re
import argparse
# match lines such as:
# cover.c:45: COVER_ONCE("loop was executed");
RE_COVER_POINT = re.compile('(\w+.c):(\d+):\s*(COVER[_\w]*)\("([^"]+)"')
# match lines such as:
# cover.c:45 // COVER
RE_COVER_HIT = re.compile('(\w+.c):(\d+)\s+\/\/ COVERED')
class CoverLocation(object):
def __init__(self, file, line):
self.file = file
self.line = line
def __repr__(self):
return '{}:{}'.format(self.file, self.line)
def __eq__(self, obj):
return self.file == obj.file and self.line == obj.line
def __hash__(self):
return hash((self.file, self.line))
class CoverPoint(object):
def __init__(self, line):
match = RE_COVER_POINT.match(line)
if not match:
raise RuntimeError('unable to parse cover point: "{}"'.format(line))
self.file = match.group(1)
self.line = int(match.group(2))
self.type = match.group(3)
self.text = match.group(4)
def location(self):
return CoverLocation(self.file, self.line)
def __repr__(self):
return '{:<16} {}'.format(self.type, self.text)
class CoverHit(object):
def __init__(self, line):
match = RE_COVER_HIT.match(line)
if not match:
raise RuntimeError('unable to parse hit point: "{}"'.format(line))
self.file = match.group(1)
self.line = int(match.group(2))
def location(self):
return CoverLocation(self.file, self.line)
class CoverDict(object):
def __init__(self, filename):
self.table = {}
self.build(filename)
def add_cover_point(self, point):
self.table[ point.location() ] = point
def build(self, filename):
with open(filename, 'r') as fd:
for l in fd.readlines():
self.add_cover_point(CoverPoint(l))
def dict(self):
return self.table
class CoverHitList(object):
def __init__(self):
self.hits = []
def accumulate(self, filename):
with open(filename, 'r') as fd:
for l in fd.readlines():
self.add_hit(CoverHit(l))
def add_hit(self, hit):
self.hits.append(hit)
def list(self):
return self.hits
def parse_args():
parser = argparse.ArgumentParser(
prog='cover.py',
description='coverage correlation tool'
)
parser.add_argument('--coverpoints', required=True)
parser.add_argument('hits', nargs='+')
return parser.parse_args()
def correlate(cover_dict, hit_list):
points = {}
# fill table with all un-hit cover points
for loc, cover_point in cover_dict.dict().items():
points[loc] = (0, cover_point)
# increment hit count for every hit we see
for hit in hit_list.list():
loc = hit.location()
if loc not in points:
raise RuntimeError('hit with no matching cover point at {}'.format(loc))
points[loc] = (points[loc][0] + 1, points[loc][1])
# report list of cover points sorted by hit count
print('location hits type message')
for point in sorted(points.items(), key=lambda p: p[1][0]):
location = point[0]
cover_tuple = point[1]
hit_count = cover_tuple[0]
cover_point = cover_tuple[1]
print('{:<16} {:<8} {}'.format(str(location), hit_count, cover_point))
# usage:
# ./cover.py --coverpoints cover_points.cov cover_hit.cov ...
def main():
args = parse_args()
cover_dict = CoverDict(args.coverpoints)
hit_list = CoverHitList()
for hit_file in args.hits:
hit_list.accumulate(hit_file)
correlate(cover_dict, hit_list)
if __name__ == '__main__':
main()
#!/bin/bash
set -e
# remove our cover point and hits
rm -rf *.cov
# recompile our test program
rm -rf a.out
gcc test.c test_file2.c
# extract cover points
grep -rn --with-filename COVER --include=*.c | grep -v -E "printf|//|#" > cover_points.cov
# run program to generate hit points
a.out > cover_hit.cov
# generate the coverage report
python ./cover.py --coverpoints cover_points.cov cover_hit.cov
#include <stdint.h>
#include <stdio.h>
#include "cover.h"
void test_func(int param);
int main(int argc, char **args) {
COVER("main was executed");
test_func(0);
test_func(123);
return 0;
}
#include <stdint.h>
#include <stdio.h>
#include "cover.h"
void test_func(int param) {
COVER_COND("test_func param equals 123", param == 123);
// COVER("This is not a valid cover point");
int i=0;
for (i=0; i<32; ++i) {
COVER_ONCE("loop was executed");
if (i & 2) {
COVER("this event is happened");
}
COVER_COND("super important code!!", i == 33);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment