diff --git a/exercises/mycp/Makefile b/exercises/mycp/Makefile new file mode 100644 index 0000000..705a966 --- /dev/null +++ b/exercises/mycp/Makefile @@ -0,0 +1,56 @@ +# Nome del file eseguibile +TARGET = mycp + +# Compilatore +CC = gcc + +# Opzioni di compilazione (C11 + warning utili + debug info) +CFLAGS = -Wall -Wextra -fsanitize=address -lasan -std=c11 -g + +# File sorgente +SRC = main.c + +LOGFILE = test_results.log + +HTMLREPORT = test_report.html + +VALGRIND_OUTPUT = valgrind_output.txt + +.PHONY: all clean clean-tests test + +all: $(TARGET) + +$(TARGET): $(SRC) + $(CC) $(CFLAGS) -o $@ $^ + +test: clean-tests $(TARGET) + ./test_mycp.sh + +clean-tests: + @echo "[CLEANUP] Removing test files and logs..." + rm -f \ + test_input.txt \ + test_output.txt \ + bin_input \ + bin_output \ + readonly.txt \ + existing.txt \ + bigfile \ + bigfile_copy \ + *.copy \ + $(LOGFILE) \ + $(HTMLREPORT) \ + $(VALGRIND_OUTPUT) + +clean: clean-tests + rm -f $(TARGET) + +report: test + ./generate_report.sh + +valgrind: $(TARGET) + valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./mycp test_input.txt test_output.txt + +valgrind-test: $(TARGET) + ./valgrind_test.sh + diff --git a/exercises/mycp/generate_report.sh b/exercises/mycp/generate_report.sh new file mode 100755 index 0000000..21d0d8f --- /dev/null +++ b/exercises/mycp/generate_report.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +LOG=test_results.log +OUT=test_report.html + +echo "[INFO] Generating HTML report..." + +cat < "$OUT" + + + + +mycp Test Report + + + +

mycp Test Report

+
+EOF
+
+sed \
+  -e 's/✔/✔<\/span>/g' \
+  -e 's/✘/✘<\/span>/g' \
+  -e 's/✅/✅<\/span>/g' \
+  -e 's/❌/❌<\/span>/g' \
+  "$LOG" >> "$OUT"
+
+cat <> "$OUT"
+
+ + +EOF + +echo "✅ HTML report saved to $OUT" + diff --git a/exercises/mycp/main.c b/exercises/mycp/main.c new file mode 100644 index 0000000..a7f999c --- /dev/null +++ b/exercises/mycp/main.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +#define BUFF_LEN 4096 + + +int main(int argc, char *argv[]) { + // Check number of arguments + if (argc < 3) { + fprintf(stderr, "Usage: %s SOURCE DEST\n", argv[0]); + return EXIT_FAILURE; + } + + // Get arguments + const char *src = argv[1]; + const char *dst = argv[2]; + + // Open source file in read only mode + int srcfd = open(src, O_RDONLY); + if (srcfd == -1) { + perror("Failed open source file"); + return EXIT_FAILURE; + } + + // Open destination file in write mode, if exists trunc file otherwise create a new file + int dstfd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (dstfd == -1) { + perror("Failed open destination file"); + if (close(srcfd) == -1) { + perror("Failed close source file"); + } + return EXIT_FAILURE; + } + + int exit_code = EXIT_SUCCESS; + char buff[BUFF_LEN]; // reading data buffer + ssize_t read_bytes; + while ((read_bytes = read(srcfd, buff, BUFF_LEN)) != 0) { + if (read_bytes == -1) { + // There is an error for reading source file + if (errno == EINTR) continue; + perror("Failed to read source file"); + exit_code = EXIT_FAILURE; + break; + } + + // Write buffer at destination file + if (write(dstfd, buff, read_bytes) == -1) { + perror("Error to write to destination file"); + exit_code = EXIT_FAILURE; + break; + } + } + + // Try to close files + if (close(srcfd) == -1) { + perror("Failed to close source file"); + exit_code = EXIT_FAILURE; + } + if (close(dstfd) == -1) { + perror("Failed to close destination file"); + exit_code = EXIT_FAILURE; + } + + return exit_code; +} diff --git a/exercises/mycp/test_mycp.sh b/exercises/mycp/test_mycp.sh new file mode 100755 index 0000000..17f8778 --- /dev/null +++ b/exercises/mycp/test_mycp.sh @@ -0,0 +1,89 @@ +#!/bin/sh + +EXEC=./mycp +LOGFILE=test_results.log +PASS=0 +FAIL=0 + +echo "[INFO] Running tests for $EXEC" > "$LOGFILE" +echo "[INFO] Date: $(date)" >> "$LOGFILE" +echo "===================================" >> "$LOGFILE" + +log() { + echo "$1" | tee -a "$LOGFILE" +} + +check() { + DESC="$1" + CMD="$2" + EXPECT="$3" + + log "[TEST] $DESC" + eval "$CMD" > /dev/null 2>&1 + RET=$? + + if [ "$RET" -eq "$EXPECT" ]; then + log " ✔ SUCCESS (exit code $RET)" + PASS=$((PASS + 1)) + else + log " ✘ FAIL (exit code $RET, expected $EXPECT)" + FAIL=$((FAIL + 1)) + fi +} + +compare_files() { + FILE1="$1" + FILE2="$2" + if cmp -s "$FILE1" "$FILE2"; then + log " ✔ Files are identical" + else + log " ✘ Files differ!" + FAIL=$((FAIL + 1)) + fi +} + +# Test 1 +echo "Hello World" > test_input.txt +check "Copy text file" "$EXEC test_input.txt test_output.txt" 0 +compare_files test_input.txt test_output.txt + +# Test 2 +cp /bin/ls bin_input +check "Copy binary file" "$EXEC bin_input bin_output" 0 +compare_files bin_input bin_output + +# Test 3 +check "Source file does not exist" "$EXEC nofile.txt shouldnotexist" 1 + +# Test 4 +check "Missing arguments" "$EXEC" 1 + +# Test 5 +echo "readonly" > readonly.txt +chmod 444 readonly.txt +check "Write to read-only file" "$EXEC test_input.txt readonly.txt" 1 +chmod 644 readonly.txt + +# Test 6 +echo "old content" > existing.txt +check "Overwrite existing file" "$EXEC test_input.txt existing.txt" 0 +compare_files test_input.txt existing.txt + +# Test 7 +dd if=/dev/urandom of=bigfile bs=1K count=128 status=none +check "Copy large file (128KB)" "$EXEC bigfile bigfile_copy" 0 +compare_files bigfile bigfile_copy + +# Summary +log "" +log "Tests passed: $PASS" +log "Tests failed: $FAIL" + +if [ "$FAIL" -eq 0 ]; then + log "✅ All tests passed" + exit 0 +else + log "❌ Some tests failed" + exit 1 +fi + diff --git a/exercises/mycp/valgrind_test.sh b/exercises/mycp/valgrind_test.sh new file mode 100755 index 0000000..4cfde4e --- /dev/null +++ b/exercises/mycp/valgrind_test.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +EXEC=./mycp +LOGFILE=valgrind_output.txt +INPUT=test_input.txt +OUTPUT=test_output.txt + +echo "Testing with Valgrind..." > "$LOGFILE" +echo "Input: $INPUT → Output: $OUTPUT" >> "$LOGFILE" +echo "----------------------------------------" >> "$LOGFILE" + +# Prepara input file +echo "Valgrind test content" > "$INPUT" + +valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes \ + "$EXEC" "$INPUT" "$OUTPUT" 2>> "$LOGFILE" + +echo "✅ Valgrind test completed. Output in $LOGFILE." +