-
Notifications
You must be signed in to change notification settings - Fork 0
adding tests and script #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,12 +1,63 @@ | ||||||||||
| # Trigger | ||||||||||
|
|
||||||||||
| ## Overview | ||||||||||
| This project aims to create a clean, efficient shell. The current README was written quickly, but the code itself will be written without AI assistance. I plan to build the shell based on solid fundamentals and personal expertise. | ||||||||||
| This project aims to create a clean, efficient shell. The current README was written quickly, but the code itself will be written without AI assistance - exception being repetitive tasks like folder organization and testing. I plan to build the shell based on solid fundamentals and personal expertise. | ||||||||||
|
|
||||||||||
| ## Project Structure | ||||||||||
| The project is now organized into a clean, modular structure: | ||||||||||
|
|
||||||||||
| ``` | ||||||||||
| shell/ | ||||||||||
| ├── include/ # Header files | ||||||||||
| │ ├── input.h # Input reading and parsing | ||||||||||
| │ ├── execute.h # Command execution | ||||||||||
| │ └── builtins.h # Built-in commands | ||||||||||
| ├── src/ # Source files | ||||||||||
| │ ├── main.c # Main entry point | ||||||||||
| │ ├── input.c # Input handling implementation | ||||||||||
| │ ├── execute.c # Command execution implementation | ||||||||||
| │ └── builtins.c # Built-in commands implementation | ||||||||||
| ├── tests/ # Unit tests | ||||||||||
| │ ├── test_framework.h # Simple testing framework | ||||||||||
| │ ├── test_input.c # Input module tests | ||||||||||
| │ ├── test_execute.c # Execute module tests | ||||||||||
| │ └── test_builtins.c # Built-ins module tests | ||||||||||
| └── CMakeLists.txt # Build configuration | ||||||||||
|
||||||||||
| └── CMakeLists.txt # Build configuration | |
| ├── CMakeLists.txt # Build configuration | |
| └── run_tests.sh # Test runner script |
Copilot
AI
Feb 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The instructions for running the test script don't mention that the script may need to be made executable first with 'chmod +x run_tests.sh'. Consider adding this note to help users who encounter permission errors.
| # Quick way | |
| # Quick way | |
| # If you get a permission error, make the script executable first: | |
| # chmod +x run_tests.sh |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| #!/bin/bash | ||
|
|
||
| set -e | ||
|
|
||
| echo "Building project..." | ||
| cmake -B cmake-build-debug -S . | ||
| cmake --build cmake-build-debug | ||
|
|
||
| echo "" | ||
| echo "Running tests..." | ||
| echo "=================" | ||
| cd cmake-build-debug | ||
| ctest --output-on-failure | ||
|
|
||
| echo "" | ||
| echo "All tests completed successfully!" | ||
|
|
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,84 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <stdio.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <stdlib.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <string.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <unistd.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "../include/builtins.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "test_framework.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void test_num_builtins() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int count = trigger_num_builtins(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_EQUAL(3, count, "Should have 3 built-in commands"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void test_builtin_arrays_match() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int count = trigger_num_builtins(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Verify that builtin_str and builtin_func have the same size | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_TRUE(count > 0, "Should have at least one built-in command"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check that known builtins exist | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int found_cd = 0, found_help = 0, found_exit = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (int i = 0; i < count; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (strcmp(builtin_str[i], "cd") == 0) found_cd = 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (strcmp(builtin_str[i], "help") == 0) found_help = 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (strcmp(builtin_str[i], "exit") == 0) found_exit = 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_TRUE(found_cd, "Should have 'cd' built-in"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_TRUE(found_help, "Should have 'help' built-in"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_TRUE(found_exit, "Should have 'exit' built-in"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void test_cd_no_args() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| char *args[] = {"cd", NULL}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int result = trigger_cd(args); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Should return true (1) even when no directory provided | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ASSERT_TRUE(result, "cd with no args should return true"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void test_cd_to_tmp() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| char cwd_before[1024]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| char cwd_after[1024]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getcwd(cwd_before, sizeof(cwd_before)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| char *args[] = {"cd", "/tmp", NULL}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int result = trigger_cd(args); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getcwd(cwd_after, sizeof(cwd_after)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+44
to
+49
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getcwd(cwd_before, sizeof(cwd_before)); | |
| char *args[] = {"cd", "/tmp", NULL}; | |
| int result = trigger_cd(args); | |
| getcwd(cwd_after, sizeof(cwd_after)); | |
| if (getcwd(cwd_before, sizeof(cwd_before)) == NULL) { | |
| ASSERT_TRUE(0, "getcwd failed to get initial current directory"); | |
| return; | |
| } | |
| char *args[] = {"cd", "/tmp", NULL}; | |
| int result = trigger_cd(args); | |
| if (getcwd(cwd_after, sizeof(cwd_after)) == NULL) { | |
| ASSERT_TRUE(0, "getcwd failed to get current directory after cd"); | |
| return; | |
| } |
Copilot
AI
Feb 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The getcwd call on line 44 could return NULL if the current working directory path exceeds the buffer size or if there's an error. In such cases, cwd_before would contain an indeterminate value, which would cause undefined behavior when used with chdir on line 55. Consider checking if getcwd returns NULL and handling that case appropriately, or using a larger buffer size.
| getcwd(cwd_before, sizeof(cwd_before)); | |
| char *args[] = {"cd", "/tmp", NULL}; | |
| int result = trigger_cd(args); | |
| getcwd(cwd_after, sizeof(cwd_after)); | |
| if (getcwd(cwd_before, sizeof(cwd_before)) == NULL) { | |
| ASSERT_TRUE(0, "Failed to get current working directory before cd"); | |
| return; | |
| } | |
| char *args[] = {"cd", "/tmp", NULL}; | |
| int result = trigger_cd(args); | |
| if (getcwd(cwd_after, sizeof(cwd_after)) == NULL) { | |
| ASSERT_TRUE(0, "Failed to get current working directory after cd"); | |
| // Attempt to restore original directory even if checking after cd fails | |
| chdir(cwd_before); | |
| return; | |
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include "../include/execute.h" | ||
| #include "test_framework.h" | ||
|
|
||
| void test_execute_empty_command() { | ||
| char *args[] = {NULL}; | ||
| int result = trigger_execute(args); | ||
|
|
||
| ASSERT_TRUE(result, "Empty command should return true"); | ||
| } | ||
|
|
||
| void test_execute_builtin_help() { | ||
| char *args[] = {"help", NULL}; | ||
| int result = trigger_execute(args); | ||
|
|
||
| ASSERT_TRUE(result, "Execute 'help' should return true"); | ||
| } | ||
|
|
||
| void test_execute_builtin_exit() { | ||
| char *args[] = {"exit", NULL}; | ||
| int result = trigger_execute(args); | ||
|
|
||
| ASSERT_EQUAL(EXIT_SUCCESS, result, "Execute 'exit' should return EXIT_SUCCESS"); | ||
| } | ||
|
|
||
| void test_execute_external_command() { | ||
| // Test with 'true' command which always succeeds | ||
| char *args[] = {"/bin/true", NULL}; | ||
| int result = trigger_execute(args); | ||
|
|
||
| ASSERT_TRUE(result, "Execute '/bin/true' should return true"); | ||
| } | ||
|
|
||
| void test_launch_simple_command() { | ||
| // Test launching echo command | ||
| char *args[] = {"/bin/echo", "test", NULL}; | ||
| int result = trigger_launch(args); | ||
|
|
||
| ASSERT_TRUE(result, "Launch '/bin/echo test' should return true"); | ||
| } | ||
|
|
||
| int main() { | ||
| TEST_SUITE_START("Execute Module Tests"); | ||
|
|
||
| test_execute_empty_command(); | ||
| test_execute_builtin_help(); | ||
| test_execute_builtin_exit(); | ||
| test_execute_external_command(); | ||
| test_launch_simple_command(); | ||
|
|
||
| TEST_SUITE_END(); | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,64 @@ | ||||||||||
| #ifndef TEST_FRAMEWORK_H | ||||||||||
| #define TEST_FRAMEWORK_H | ||||||||||
|
|
||||||||||
| #include <stdio.h> | ||||||||||
| #include <string.h> | ||||||||||
|
|
||||||||||
| // Test statistics | ||||||||||
| static int tests_run = 0; | ||||||||||
| static int tests_passed = 0; | ||||||||||
| static int tests_failed = 0; | ||||||||||
|
|
||||||||||
| // Color codes for output | ||||||||||
| #define COLOR_GREEN "\033[0;32m" | ||||||||||
| #define COLOR_RED "\033[0;31m" | ||||||||||
| #define COLOR_YELLOW "\033[0;33m" | ||||||||||
| #define COLOR_RESET "\033[0m" | ||||||||||
|
|
||||||||||
| // Assertion macros | ||||||||||
| #define ASSERT_TRUE(condition, message) \ | ||||||||||
| do { \ | ||||||||||
| tests_run++; \ | ||||||||||
| if (condition) { \ | ||||||||||
| tests_passed++; \ | ||||||||||
| printf(COLOR_GREEN "✓" COLOR_RESET " %s\n", message); \ | ||||||||||
| } else { \ | ||||||||||
| tests_failed++; \ | ||||||||||
| printf(COLOR_RED "✗" COLOR_RESET " %s (line %d)\n", message, __LINE__); \ | ||||||||||
| } \ | ||||||||||
| } while(0) | ||||||||||
|
|
||||||||||
| #define ASSERT_FALSE(condition, message) \ | ||||||||||
| ASSERT_TRUE(!(condition), message) | ||||||||||
|
|
||||||||||
| #define ASSERT_EQUAL(expected, actual, message) \ | ||||||||||
| ASSERT_TRUE((expected) == (actual), message) | ||||||||||
|
|
||||||||||
| #define ASSERT_STR_EQUAL(expected, actual, message) \ | ||||||||||
| ASSERT_TRUE(strcmp((expected), (actual)) == 0, message) | ||||||||||
|
||||||||||
| ASSERT_TRUE(strcmp((expected), (actual)) == 0, message) | |
| ASSERT_TRUE((((expected) == NULL && (actual) == NULL) || \ | |
| ((expected) != NULL && (actual) != NULL && strcmp((expected), (actual)) == 0)), \ | |
| message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor grammatical issue: "exception being" should be "with the exception of" or "the exception being" for better clarity and grammatical correctness.