From a629f9de01c2a0135696fad8c090479913e09d90 Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Mon, 30 Jun 2025 22:25:31 +0200 Subject: [PATCH] Solved exercise 2 - create a simple tree program clone --- exercises/tree/Makefile | 27 +++++++++++++ exercises/tree/main.c | 15 +++++++ exercises/tree/test/run_tests.sh | 68 ++++++++++++++++++++++++++++++++ exercises/tree/test/test_dirs.sh | 10 +++++ exercises/tree/tree.c | 35 ++++++++++++++++ exercises/tree/tree.h | 7 ++++ 6 files changed, 162 insertions(+) create mode 100644 exercises/tree/Makefile create mode 100644 exercises/tree/main.c create mode 100755 exercises/tree/test/run_tests.sh create mode 100755 exercises/tree/test/test_dirs.sh create mode 100644 exercises/tree/tree.c create mode 100644 exercises/tree/tree.h diff --git a/exercises/tree/Makefile b/exercises/tree/Makefile new file mode 100644 index 0000000..148b6c9 --- /dev/null +++ b/exercises/tree/Makefile @@ -0,0 +1,27 @@ +CC = gcc +CFLAGS = -Wall -Wextra -std=c11 -g +SRC = main.c tree.c +OBJ = $(SRC:.c=.o) +EXEC = tree + +# Main target +all: $(EXEC) + +# Build executable +$(EXEC): $(OBJ) + $(CC) $(CFLAGS) -o $@ $^ + +# Run test suite +test: all + @cd test && ./run_tests.sh + +# Clean object files and executable +clean: + rm -f $(OBJ) $(EXEC) + +# Full cleanup (also test artifacts) +distclean: clean + cd test && rm -f actual_output.txt valgrind.log expected_output.txt && rm -rf testdir + +.PHONY: all test clean distclean + diff --git a/exercises/tree/main.c b/exercises/tree/main.c new file mode 100644 index 0000000..250c3d8 --- /dev/null +++ b/exercises/tree/main.c @@ -0,0 +1,15 @@ +#include +#include +#include "tree.h" + +int main(int argc, char *argv[]) { + const char *path = (argc > 1) ? argv[1] : "."; + + if (print_tree(path, 0) == -1) { + perror("Error traversing directory"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + diff --git a/exercises/tree/test/run_tests.sh b/exercises/tree/test/run_tests.sh new file mode 100755 index 0000000..125b1ba --- /dev/null +++ b/exercises/tree/test/run_tests.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +TREE_EXEC="../tree" +TEST_DIR="testdir" +REF_OUTPUT="expected_output.txt" +OUT_FILE="actual_output.txt" +VALGRIND_LOG="valgrind.log" + +# Preparazione struttura di test +setup() { + rm -rf "$TEST_DIR" + mkdir -p "$TEST_DIR/sub1" + mkdir -p "$TEST_DIR/sub2" + touch "$TEST_DIR/file1.txt" + touch "$TEST_DIR/sub1/file2.txt" + touch "$TEST_DIR/sub2/file3.txt" + + cat > "$REF_OUTPUT" < "$OUT_FILE" + + if diff -q "$OUT_FILE" "$REF_OUTPUT"; then + echo "[✓] Output matches expected output." + else + echo "[✗] Output differs!" + diff "$OUT_FILE" "$REF_OUTPUT" + return 1 + fi +} + +# Valgrind check +run_valgrind() { + echo "[*] Running Valgrind..." + valgrind --leak-check=full --log-file="$VALGRIND_LOG" "$TREE_EXEC" "$TEST_DIR" > /dev/null + + if grep -q "no leaks are possible" "$VALGRIND_LOG"; then + echo "[✓] Valgrind: No memory leaks." + else + echo "[✗] Valgrind detected memory issues:" + cat "$VALGRIND_LOG" + return 1 + fi +} + +cleanup() { + rm -rf "$TEST_DIR" "$OUT_FILE" "$VALGRIND_LOG" "$REF_OUTPUT" +} + +main() { + setup + run_test || exit 1 + run_valgrind || exit 1 + cleanup + echo "[✓] All tests passed." +} + +main + diff --git a/exercises/tree/test/test_dirs.sh b/exercises/tree/test/test_dirs.sh new file mode 100755 index 0000000..de16ab7 --- /dev/null +++ b/exercises/tree/test/test_dirs.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# Crea una struttura di directory per test + +mkdir -p testdir/{sub1,sub2} +touch testdir/file1.txt +touch testdir/sub1/file2.txt +touch testdir/sub2/file3.txt + +echo "Directory structure created." + diff --git a/exercises/tree/tree.c b/exercises/tree/tree.c new file mode 100644 index 0000000..85c5967 --- /dev/null +++ b/exercises/tree/tree.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include +#include "tree.h" + +int print_tree(const char *path, int depth) { + DIR *dir = opendir(path); + if (!dir) return -1; + + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + // Skip . and .. + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + + for (int i = 0; i < depth; i++) printf(" "); + printf("|-- %s\n", entry->d_name); + + // Construct full path + char full_path[4096]; + snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name); + + struct stat st; + if (stat(full_path, &st) == 0 && S_ISDIR(st.st_mode)) { + print_tree(full_path, depth + 1); + } + } + + closedir(dir); + return 0; +} + diff --git a/exercises/tree/tree.h b/exercises/tree/tree.h new file mode 100644 index 0000000..ee75897 --- /dev/null +++ b/exercises/tree/tree.h @@ -0,0 +1,7 @@ +#ifndef TREE_H +#define TREE_H + +int print_tree(const char *path, int depth); + +#endif +