Skip to content

Commit b692916

Browse files
Tests/add file tree tests (#7)
* Add documentation to file tree funcs * Add tests for file tree create * add tests for tree add child * Add tests for file_tree_build_recursive * Add tests for file_tree_build * Add tests for file_tree_free' * Add unit tests for file_tree_select * Add unit tests file_tree_count_selected * Add unit tests delete_selected_recursive * Add tests file_tree_delete_selected * Add tests for file_tree_get_list_recurive * Add ability to suppress src printf
1 parent 698f131 commit b692916

8 files changed

Lines changed: 5210 additions & 22 deletions

File tree

include/cisco_cli.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ void file_tree_build(serial_conn_t *conn, dir_node_t **root);
121121
void file_tree_free(dir_node_t *node);
122122
void file_tree_select(dir_node_t *node, int selected);
123123
int file_tree_count_selected(dir_node_t *node);
124+
void file_tree_delete_selected_recursive(serial_conn_t *conn, dir_node_t *node, int *success_count, int *fail_count);
124125
void file_tree_delete_selected(serial_conn_t *conn, dir_node_t *node);
126+
int file_tree_get_flat_list_recursive(dir_node_t *node, dir_node_t **list, int max_count, int *current_count);
125127
int file_tree_get_flat_list(dir_node_t *node, dir_node_t **list, int max_count);
126128

127129
// UI functions

src/cisco_commands.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ int cisco_init_flash(serial_conn_t *conn, int timeout) {
132132
* will occur if the returned list is not properly freed.
133133
*/
134134
int cisco_get_directory_listing(serial_conn_t *conn, const char *path, file_entry_t **files, int timeout) {
135+
// Validate input parameters
136+
if (!conn || !path || !files) {
137+
return -1;
138+
}
139+
135140
char command[MAX_LINE_LEN];
136141
char buffer[MAX_LINE_LEN * 10]; // Large buffer for directory listing
137142
char *line, *saveptr;

src/file_tree.c

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
#include "cisco_cli.h"
22

3+
// Creates a new directory tree node with the given name, path, and type
34
dir_node_t *file_tree_create(const char *name, const char *path, file_type_t type) {
45
dir_node_t *node = malloc(sizeof(dir_node_t));
56
if (!node) return NULL;
67

7-
strncpy(node->name, name, MAX_PATH_LEN - 1);
8+
// Handle NULL parameters safely
9+
if (name) {
10+
strncpy(node->name, name, MAX_PATH_LEN - 1);
11+
} else {
12+
node->name[0] = '\0';
13+
}
814
node->name[MAX_PATH_LEN - 1] = '\0';
915

10-
strncpy(node->path, path, MAX_PATH_LEN - 1);
16+
if (path) {
17+
strncpy(node->path, path, MAX_PATH_LEN - 1);
18+
} else {
19+
node->path[0] = '\0';
20+
}
1121
node->path[MAX_PATH_LEN - 1] = '\0';
1222

1323
node->type = type;
@@ -19,8 +29,9 @@ dir_node_t *file_tree_create(const char *name, const char *path, file_type_t typ
1929
node->next = NULL;
2030

2131
return node;
22-
}
32+
}
2333

34+
// Adds a child node to a parent node in the tree
2435
void file_tree_add_child(dir_node_t *parent, dir_node_t *child) {
2536
if (!parent || !child) return;
2637

@@ -38,7 +49,13 @@ void file_tree_add_child(dir_node_t *parent, dir_node_t *child) {
3849
}
3950
}
4051

52+
// Recursively builds the file tree by fetching directory listings from the device
4153
void file_tree_build_recursive(serial_conn_t *conn, dir_node_t *parent, const char *path) {
54+
// Validate input parameters
55+
if (!conn || !parent || !path) {
56+
return;
57+
}
58+
4259
file_entry_t *files = NULL;
4360
int file_count = cisco_get_directory_listing(conn, path, &files, 3);
4461

@@ -61,7 +78,11 @@ void file_tree_build_recursive(serial_conn_t *conn, dir_node_t *parent, const ch
6178
}
6279
}
6380

81+
// Initializes and builds the root file tree structure
6482
void file_tree_build(serial_conn_t *conn, dir_node_t **root) {
83+
// Validate input parameters
84+
if (!root) return;
85+
6586
// Create root node
6687
*root = file_tree_create("flash:/", "flash:/", FILE_TYPE_DIRECTORY);
6788
if (!*root) return;
@@ -70,6 +91,7 @@ void file_tree_build(serial_conn_t *conn, dir_node_t **root) {
7091
file_tree_build_recursive(conn, *root, "flash:/");
7192
}
7293

94+
// Recursively frees all memory allocated for the file tree
7395
void file_tree_free(dir_node_t *node) {
7496
if (!node) return;
7597

@@ -85,6 +107,7 @@ void file_tree_free(dir_node_t *node) {
85107
free(node);
86108
}
87109

110+
// Sets the selection state of a node and all its children
88111
void file_tree_select(dir_node_t *node, int selected) {
89112
if (!node) return;
90113

@@ -100,6 +123,7 @@ void file_tree_select(dir_node_t *node, int selected) {
100123
}
101124
}
102125

126+
// Counts the total number of selected nodes in the tree
103127
int file_tree_count_selected(dir_node_t *node) {
104128
if (!node) return 0;
105129

@@ -115,6 +139,7 @@ int file_tree_count_selected(dir_node_t *node) {
115139
return count;
116140
}
117141

142+
// Recursively deletes selected files and directories from the device
118143
void file_tree_delete_selected_recursive(serial_conn_t *conn, dir_node_t *node, int *success_count, int *fail_count) {
119144
if (!node) return;
120145

@@ -138,14 +163,15 @@ void file_tree_delete_selected_recursive(serial_conn_t *conn, dir_node_t *node,
138163
result = cisco_delete_file(conn, node->path, 3);
139164
}
140165

141-
if (result == 0) {
166+
if (result == 0 && success_count != NULL) {
142167
(*success_count)++;
143-
} else {
168+
} else if (result != 0 && fail_count != NULL) {
144169
(*fail_count)++;
145170
}
146171
}
147172
}
148173

174+
// Deletes all selected files and directories and reports results
149175
void file_tree_delete_selected(serial_conn_t *conn, dir_node_t *node) {
150176
int success_count = 0, fail_count = 0;
151177

@@ -155,13 +181,15 @@ void file_tree_delete_selected(serial_conn_t *conn, dir_node_t *node) {
155181
printf("Deletion complete: %d successful, %d failed\n", success_count, fail_count);
156182
}
157183

158-
// Utility function to get all nodes in a flat list for UI display
184+
// Recursively builds a flat list of visible nodes for UI display
159185
int file_tree_get_flat_list_recursive(dir_node_t *node, dir_node_t **list, int max_count, int *current_count) {
160-
if (!node || *current_count >= max_count) return *current_count;
186+
if (!node || !list || !current_count || *current_count >= max_count) return 0;
161187

188+
// Always include the current node in the list
162189
list[*current_count] = node;
163190
(*current_count)++;
164191

192+
// Only include children if the current node is expanded
165193
if (node->expanded) {
166194
dir_node_t *child = node->children;
167195
while (child != NULL && *current_count < max_count) {
@@ -173,6 +201,7 @@ int file_tree_get_flat_list_recursive(dir_node_t *node, dir_node_t **list, int m
173201
return *current_count;
174202
}
175203

204+
// Creates a flat list of all visible nodes in the tree for UI rendering
176205
int file_tree_get_flat_list(dir_node_t *node, dir_node_t **list, int max_count) {
177206
int count = 0;
178207
return file_tree_get_flat_list_recursive(node, list, max_count, &count);

tests/Makefile

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,68 @@ LDFLAGS = -lpthread -Wl,--gc-sections
44

55
# Source files for the streamlined framework
66
TEST_FRAMEWORK_SRC = framework/test_framework.c
7-
TEST_SRC = unit/test_cisco_commands.c
8-
SOURCE_SRC = ../src/cisco_commands.c
7+
TEST_SRC = unit/test_cisco_commands.c unit/test_file_tree.c
8+
SOURCE_SRC = ../src/cisco_commands.c ../src/file_tree.c
99

1010
# Object files
1111
TEST_FRAMEWORK_OBJ = $(TEST_FRAMEWORK_SRC:.c=.o)
1212
TEST_OBJ = $(TEST_SRC:.c=.o)
1313
SOURCE_OBJ = $(SOURCE_SRC:.c=.o)
1414

15-
# Test executable
15+
# Test executables
1616
TEST_EXEC = test_cisco_commands
17+
FILE_TREE_TEST_EXEC = test_file_tree
1718

1819
# Default target
19-
all: $(TEST_EXEC)
20+
all: $(TEST_EXEC) $(FILE_TREE_TEST_EXEC)
2021

21-
# Build test executable
22-
$(TEST_EXEC): $(TEST_FRAMEWORK_OBJ) $(TEST_OBJ) $(SOURCE_OBJ)
22+
# Build test executables
23+
$(TEST_EXEC): $(TEST_FRAMEWORK_OBJ) unit/test_cisco_commands.o ../src/cisco_commands.o
24+
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
25+
26+
$(FILE_TREE_TEST_EXEC): $(TEST_FRAMEWORK_OBJ) unit/test_file_tree.o ../src/file_tree.o ../src/cisco_commands.o
2327
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
2428

2529
# Compile test framework
2630
$(TEST_FRAMEWORK_OBJ): $(TEST_FRAMEWORK_SRC) framework/test_framework.h
2731
$(CC) $(CFLAGS) -c $< -o $@
2832

29-
# Compile test file
30-
$(TEST_OBJ): $(TEST_SRC) framework/test_framework.h ../include/cisco_cli.h
33+
# Compile test files
34+
unit/test_cisco_commands.o: unit/test_cisco_commands.c framework/test_framework.h ../include/cisco_cli.h
35+
$(CC) $(CFLAGS) -c $< -o $@
36+
37+
unit/test_file_tree.o: unit/test_file_tree.c framework/test_framework.h ../include/cisco_cli.h
38+
$(CC) $(CFLAGS) -c $< -o $@
39+
40+
# Compile source files
41+
../src/cisco_commands.o: ../src/cisco_commands.c ../include/cisco_cli.h
3142
$(CC) $(CFLAGS) -c $< -o $@
3243

33-
# Compile source file (only the one we need for testing)
34-
$(SOURCE_OBJ): $(SOURCE_SRC) ../include/cisco_cli.h
44+
../src/file_tree.o: ../src/file_tree.c ../include/cisco_cli.h
3545
$(CC) $(CFLAGS) -c $< -o $@
3646

3747
# Run tests
38-
test: $(TEST_EXEC)
48+
test: $(TEST_EXEC) $(FILE_TREE_TEST_EXEC)
49+
@echo "Running cisco_commands tests..."
3950
./$(TEST_EXEC)
51+
@echo "Running file_tree tests..."
52+
./$(FILE_TREE_TEST_EXEC)
4053

4154
# Run tests with verbose output
42-
test-verbose: $(TEST_EXEC)
55+
test-verbose: $(TEST_EXEC) $(FILE_TREE_TEST_EXEC)
56+
@echo "Running cisco_commands tests with verbose output..."
4357
./$(TEST_EXEC) --verbose
58+
@echo "Running file_tree tests with verbose output..."
59+
./$(FILE_TREE_TEST_EXEC) --verbose
4460

4561
# Clean
4662
clean:
47-
rm -f $(TEST_FRAMEWORK_OBJ) $(TEST_OBJ) $(SOURCE_OBJ) $(TEST_EXEC)
63+
rm -f $(TEST_FRAMEWORK_OBJ) unit/*.o ../src/*.o $(TEST_EXEC) $(FILE_TREE_TEST_EXEC)
4864

4965
# Help
5066
help:
5167
@echo "Available targets:"
52-
@echo " all - Build test executable"
68+
@echo " all - Build all test executables"
5369
@echo " test - Run all tests"
5470
@echo " test-verbose- Run all tests with verbose output"
5571
@echo " clean - Clean test files"

tests/framework/test_framework.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
#include "test_framework.h"
1616
#include "../include/cisco_cli.h"
17+
#include <unistd.h>
18+
#include <fcntl.h>
19+
#include <stdio.h>
1720

1821
// ============================================================================
1922
// Mock Framework Implementation
@@ -150,8 +153,14 @@ static int run_single_test(const char *test_name, test_func_t test_func) {
150153
printf(" Running: %s", test_name);
151154
fflush(stdout);
152155

156+
// Suppress stdout during test execution to avoid printf output from functions under test
157+
suppress_stdout();
158+
153159
int result = test_func();
154160

161+
// Restore stdout after test execution
162+
restore_stdout();
163+
155164
if (result) {
156165
printf(" ✓ PASS\n");
157166
test_stats.passed_tests++;
@@ -220,6 +229,47 @@ int run_test_suite(const char *suite_name) {
220229
return run_all_tests();
221230
}
222231

232+
// ============================================================================
233+
// Output Suppression Functions
234+
// ============================================================================
235+
236+
// Global variables to store original stdout
237+
static int original_stdout_fd = -1;
238+
static int stdout_suppressed = 0;
239+
240+
/**
241+
* @brief Suppress stdout output during test execution
242+
*/
243+
void suppress_stdout(void) {
244+
if (!stdout_suppressed) {
245+
// Store the original stdout file descriptor
246+
original_stdout_fd = dup(STDOUT_FILENO);
247+
248+
// Redirect stdout to /dev/null to suppress output
249+
freopen("/dev/null", "w", stdout);
250+
stdout_suppressed = 1;
251+
}
252+
}
253+
254+
/**
255+
* @brief Restore stdout output after test execution
256+
*/
257+
void restore_stdout(void) {
258+
if (stdout_suppressed && original_stdout_fd != -1) {
259+
// Close the current stdout (which points to /dev/null)
260+
fclose(stdout);
261+
262+
// Restore the original stdout file descriptor
263+
dup2(original_stdout_fd, STDOUT_FILENO);
264+
close(original_stdout_fd);
265+
original_stdout_fd = -1;
266+
267+
// Reopen stdout as a FILE* for the restored file descriptor
268+
stdout = fopen("/dev/stdout", "w");
269+
stdout_suppressed = 0;
270+
}
271+
}
272+
223273
// ============================================================================
224274
// Utility Functions
225275
// ============================================================================

tests/framework/test_framework.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,4 +281,18 @@ TEST_SETUP(serial);
281281
*/
282282
TEST_TEARDOWN(serial);
283283

284+
// ============================================================================
285+
// Output Suppression Functions
286+
// ============================================================================
287+
288+
/**
289+
* @brief Suppress stdout output during test execution
290+
*/
291+
void suppress_stdout(void);
292+
293+
/**
294+
* @brief Restore stdout output after test execution
295+
*/
296+
void restore_stdout(void);
297+
284298
#endif // TEST_FRAMEWORK_V2_H

tests/unit/test_cisco_commands.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1221,7 +1221,7 @@ TEST(delete_directory_special_characters_in_path) {
12211221
// ============================================================================
12221222

12231223
int main(void) {
1224-
printf("Running cisco_commands unit tests (v2)...\n");
1224+
printf("Running cisco_commands unit tests...\n");
12251225

12261226
int result = run_all_tests();
12271227

0 commit comments

Comments
 (0)