diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7c75d96 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Ensure shell scripts always use LF line endings +*.sh text eol=lf diff --git a/.gitignore b/.gitignore index 2b915ce..7eb8ffc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,8 @@ *.o *.a chunk_server_data_* +# Coverage reports +coverage_report/ +*.gcov +*.gcda +*.gcno diff --git a/Makefile b/Makefile index d8c62fc..5e4b4b0 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ CFLAGS = -Wall -Wextra -ggdb +COVERAGE_CFLAGS = $(CFLAGS) --coverage +COVERAGE_LFLAGS = --coverage ifeq ($(OS),Windows_NT) LFLAGS = -lws2_32 @@ -13,16 +15,27 @@ CFILES = $(shell find src -name '*.c') HFILES = $(shell find src -name '*.h') OFILES = $(CFILES:.c=.o) -.PHONY: all clean +.PHONY: all clean coverage coverage-report coverage-html all: mousefs$(EXT) mousefs_random_test$(EXT) example_client$(EXT) libmousefs.a +coverage: mousefs_random_test_coverage$(EXT) + +coverage-report: + @./scripts/measure_coverage.sh 5 + +coverage-html: + @./scripts/measure_coverage.sh 5 --html + mousefs$(EXT): $(CFILES) $(HFILES) gcc -o $@ $(CFILES) $(CFLAGS) $(LFLAGS) -Iinc -DBUILD_SERVER mousefs_random_test$(EXT): $(CFILES) $(HFILES) gcc -o $@ $(CFILES) $(CFLAGS) $(LFLAGS) -Iinc -DBUILD_TEST +mousefs_random_test_coverage$(EXT): $(CFILES) $(HFILES) + gcc -o $@ $(CFILES) $(COVERAGE_CFLAGS) $(LFLAGS) $(COVERAGE_LFLAGS) -Iinc -DBUILD_TEST + example_client$(EXT): libmousefs.a gcc -o $@ examples/main.c $(CFLAGS) -lmousefs $(LFLAGS) -Iinc -L. @@ -33,12 +46,18 @@ libmousefs.a: $(OFILES) ar rcs $@ $^ clean: - rm -f \ - mousefs.exe \ - mousefs.out \ - mousefs_random_test.exe \ - mousefs_random_test.out \ - example_client.exe \ - example_client.out \ - libmousefs.a \ - src/*.o + rm -f \ + mousefs.exe \ + mousefs.out \ + mousefs_random_test.exe \ + mousefs_random_test.out \ + mousefs_random_test_coverage.exe \ + mousefs_random_test_coverage.out \ + example_client.exe \ + example_client.out \ + libmousefs.a \ + src/*.o \ + src/*.gcda \ + src/*.gcno \ + *.gcda \ + *.gcno diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..bcaac89 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,48 @@ +# Branch Coverage Measurement + +This directory contains scripts for measuring branch coverage of the random simulation. + +## Prerequisites + +The HTML report generation requires `lcov`: + +```bash +sudo apt-get install lcov +``` + +## Usage + +### Quick text summary (5 second simulation) +```bash +make coverage-report +``` + +### HTML report with branch details (5 second simulation) +```bash +make coverage-html +``` + +### Custom duration +```bash +./scripts/measure_coverage.sh 10 # 10 second run, text output +./scripts/measure_coverage.sh 10 --html # 10 second run, HTML output +``` + +## What gets measured + +The coverage tool: +- Builds the test binary with coverage instrumentation (`--coverage` flag) +- Runs the random simulation for the specified duration +- Generates reports showing which branches were executed + +## Output + +**Text report**: Shows per-file and total branch coverage percentages + +**HTML report**: Interactive report generated by lcov/genhtml showing: +- Overall coverage summary +- Per-file coverage breakdown +- Source code with execution counts +- Branch coverage details + +The HTML report is generated in `coverage_report/index.html` diff --git a/scripts/fix_line_endings.sh b/scripts/fix_line_endings.sh new file mode 100755 index 0000000..d2af20f --- /dev/null +++ b/scripts/fix_line_endings.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Fix line endings for coverage scripts + +echo "Fixing line endings for coverage scripts..." + +# Convert CRLF to LF +dos2unix scripts/measure_coverage.sh 2>/dev/null || sed -i 's/\r$//' scripts/measure_coverage.sh +dos2unix scripts/generate_coverage_html.sh 2>/dev/null || sed -i 's/\r$//' scripts/generate_coverage_html.sh + +# Ensure execute permissions +chmod +x scripts/measure_coverage.sh +chmod +x scripts/generate_coverage_html.sh + +echo "Done! Line endings fixed and execute permissions set." +echo "" +echo "You can now run:" +echo " make coverage-report" +echo " make coverage-html" diff --git a/scripts/generate_coverage_html.sh b/scripts/generate_coverage_html.sh new file mode 100755 index 0000000..c29788b --- /dev/null +++ b/scripts/generate_coverage_html.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Generate HTML coverage report using lcov + +set -e + +OUTPUT_DIR="coverage_report" + +# Check if lcov is installed +if ! command -v lcov &> /dev/null; then + echo "Error: lcov is not installed" + echo "Please install it with: sudo apt-get install lcov" + exit 1 +fi + +# Capture coverage data with branch coverage enabled +echo "Capturing coverage data..." +lcov --capture --directory . --output-file coverage.info --rc lcov_branch_coverage=1 + +# Filter out system headers if any exist +echo "Filtering coverage data..." +lcov --remove coverage.info '/usr/*' --output-file coverage.info --ignore-errors unused --rc lcov_branch_coverage=1 || cp coverage.info coverage.info.bak + +# Generate HTML report +echo "Generating HTML report..." +genhtml coverage.info --output-directory "$OUTPUT_DIR" --branch-coverage --rc lcov_branch_coverage=1 + +# Clean up +rm -f coverage.info + +echo "HTML report generated in $OUTPUT_DIR/" +echo "Open $OUTPUT_DIR/index.html in your browser" diff --git a/scripts/measure_coverage.sh b/scripts/measure_coverage.sh new file mode 100755 index 0000000..876ea3e --- /dev/null +++ b/scripts/measure_coverage.sh @@ -0,0 +1,113 @@ +#!/bin/bash +# Script to measure branch coverage of the random simulation + +set -e + +# Colors for output +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +echo -e "${BLUE}========================================${NC}" +echo -e "${BLUE}Branch Coverage Measurement Tool${NC}" +echo -e "${BLUE}========================================${NC}" +echo + +# Clean previous coverage data +echo -e "${YELLOW}Cleaning previous coverage data...${NC}" +rm -f src/*.gcda src/*.gcno *.gcda *.gcno +make clean > /dev/null 2>&1 + +# Build with coverage +echo -e "${YELLOW}Building with coverage instrumentation...${NC}" +make coverage + +# Run the simulation for a limited time +echo -e "${YELLOW}Running simulation...${NC}" +SIMULATION_TIME=${1:-5} # Default to 5 seconds if not specified +echo "Running for ${SIMULATION_TIME} seconds..." + +# Run simulation in background and kill it after specified time +timeout ${SIMULATION_TIME}s ./mousefs_random_test_coverage.out || true + +# Generate coverage reports +echo +echo -e "${YELLOW}Generating coverage reports...${NC}" + +# Find all .gcda files and generate coverage reports +GCDA_FILES=$(find . -name "*.gcda") + +TOTAL_BRANCHES=0 +TAKEN_BRANCHES=0 + +# Generate gcov reports from the coverage data files +for gcda_file in $GCDA_FILES; do + # Extract the source file name from the gcda filename + # Files are named like: mousefs_random_test_coverage.out-basic.gcda + basename=$(basename "$gcda_file" .gcda) + source_name=${basename#*-} # Remove prefix up to and including '-' + + # Run gcov to generate the .gcov file + gcov -b "$gcda_file" > /dev/null 2>&1 || true +done + +# Parse gcov output to count branches +echo +echo -e "${BLUE}========================================${NC}" +echo -e "${BLUE}Branch Coverage Summary${NC}" +echo -e "${BLUE}========================================${NC}" +echo + +# Process each .gcov file +for gcov_file in *.c.gcov; do + if [ -f "$gcov_file" ]; then + # Extract branch statistics from the gcov file + branches=$(grep -c "^branch" "$gcov_file" 2>/dev/null) + if [ -z "$branches" ]; then branches=0; fi + + if [ "$branches" -gt 0 ]; then + taken_count=$(grep "^branch" "$gcov_file" 2>/dev/null | grep -c "taken [1-9]" 2>/dev/null || echo "0") + # Clean up the value - remove any whitespace/newlines + taken_count=$(echo "$taken_count" | tr -d '[:space:]') + if [ -z "$taken_count" ] || [ "$taken_count" = "" ]; then taken_count=0; fi + + TOTAL_BRANCHES=$((TOTAL_BRANCHES + branches)) + TAKEN_BRANCHES=$((TAKEN_BRANCHES + taken_count)) + percentage=$((taken_count * 100 / branches)) + filename=$(echo "$gcov_file" | sed 's/.gcov$//') + printf "%-40s %5d / %5d branches (%3d%%)\n" "$filename" "$taken_count" "$branches" "$percentage" + fi + fi +done + +echo +echo -e "${BLUE}========================================${NC}" +if [ "$TOTAL_BRANCHES" -gt 0 ]; then + COVERAGE_PERCENT=$((TAKEN_BRANCHES * 100 / TOTAL_BRANCHES)) + echo -e "${GREEN}Total: $TAKEN_BRANCHES / $TOTAL_BRANCHES branches reached (${COVERAGE_PERCENT}%)${NC}" +else + echo -e "${YELLOW}No branch coverage data found${NC}" +fi +echo -e "${BLUE}========================================${NC}" +echo + +# Generate HTML report if requested +if [ "$2" == "--html" ]; then + echo -e "${YELLOW}Generating HTML coverage report...${NC}" + # Get the directory where this script is located + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + "$SCRIPT_DIR/generate_coverage_html.sh" + echo -e "${GREEN}HTML report generated in coverage_report/index.html${NC}" + echo "Open with: firefox coverage_report/index.html (or your preferred browser)" + echo +fi + +# Clean up gcov files unless HTML was requested +if [ "$2" != "--html" ] && [ "$2" != "--detailed" ]; then + echo -e "${YELLOW}Cleaning up coverage files...${NC}" + rm -f *.gcov +fi + +echo +echo -e "${GREEN}Coverage measurement complete!${NC}" diff --git a/src/main_test.c b/src/main_test.c index 294a0e7..17d0cfb 100644 --- a/src/main_test.c +++ b/src/main_test.c @@ -8,12 +8,20 @@ static sig_atomic_t simulation_should_stop = false; +static void signal_handler(int signum) +{ + (void)signum; + simulation_should_stop = true; +} + int main(int argc, char **argv) { (void)argc; (void)argv; - // TODO: set simulation_should_stop=true on ctrl+C + // Set up signal handlers for clean shutdown + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); startup_simulation(2);