diff --git a/chapter_5/exercise_5_10/expr.c b/chapter_5/exercise_5_10/expr.c index a8de7e1..3e1eed5 100644 --- a/chapter_5/exercise_5_10/expr.c +++ b/chapter_5/exercise_5_10/expr.c @@ -13,6 +13,7 @@ void push(float element); int main(int argc, char *argv[]) { char Error = 0; + int op_count = 0; // Using int instead of size_t for loop variable to match signed argc // This prevents sign comparison warnings @@ -29,19 +30,23 @@ int main(int argc, char *argv[]) { char op = *argv[i]; switch (op) { case '+': + op_count++; push(number1 + number2); break; case '-': + op_count++; push(number1 - number2); break; case '*': // This char might require to be escaped when passed // as an argument. + op_count++; push(number1 * number2); break; case '/': + op_count++; if (number2 == 0) { Error = 4; } else { @@ -87,15 +92,20 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - - printf("result: %.3f", pop()); + + if (op_count == 0 && argc > 2) { + printf("Error: Operator is missing!\n"); + return EXIT_FAILURE; + } else { + printf("result: %.3f", pop()); + } return EXIT_SUCCESS; } float pop(void) { if (stack_pointer > 0) { - return stack[stack_pointer--]; + return stack[--stack_pointer]; } printf("Error: the stack is empty.\n"); @@ -104,7 +114,7 @@ float pop(void) { void push(float element) { if (stack_pointer < STACK_SIZE) { - stack[++stack_pointer] = element; + stack[stack_pointer++] = element; } else { printf("Error: the stack is full.\n"); } diff --git a/chapter_5/exercise_5_10/expr_test.sh b/chapter_5/exercise_5_10/expr_test.sh new file mode 100755 index 0000000..dc15e28 --- /dev/null +++ b/chapter_5/exercise_5_10/expr_test.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +# check if file is present and executable +if [ ! -f expr ]; then + echo "File 'expr' found!" + exit 1 +fi + +if [ ! -x expr ]; then + echo "File 'expr' not executable!" + exit 1 +fi + +echo "=== Testing expr calculator ===" + +# Test 1: Simple addition +T=1 +result=$(./expr 2 3 +) +expected="result: 5.000" +if [[ "$result" == "$expected" ]]; then + echo "Test $T PASS: 2 + 3 = 5" +else + echo "Test $T FAIL: Expected '$expected', got '$result'" +fi + +# Test 2: Commutativity of addition +T=2 +result=$(./expr 3 2 +) +expected="result: 5.000" +if [[ "$result" == "$expected" ]]; then + echo "Test $T PASS: 3 + 2 = 5" +else + echo "Test $T FAIL: Expected '$expected', got '$result'" +fi + +# Test 3: Subtraction +T=3 +result=$(./expr 10 3 -) +expected="result: 7.000" +if [[ "$result" == "$expected" ]]; then + echo "Test $T PASS: 10 - 3 = 7" +else + echo "Test $T FAIL: Expected '$expected', got '$result'" +fi + +# Test 4: Complex expression +T=4 +# ------------------------------------ +# Expected: +# 5 --> [5] +# 1 --> [5, 1] +# 2 --> [5, 1, 2] +# + --> (1 + 2 = 3) --> [5, 3] +# 4 --> [5, 3, 4] +# * --> (3 * 4 = 12) --> [5, 12] +# + --> (5 + 12 = 17) --> [17] +# 3 --> [17, 3] +# - --> (17 - 3 = 14) --> [14] +# ------------------------------------ +result=$(./expr 5 1 2 + 4 \* + 3 -) +expected="result: 14.000" +if [[ "$result" == "$expected" ]]; then + echo "Test $T PASS: Complex RPN expression" +else + echo "Test $T FAIL: Expected '$expected', got '$result'" +fi + +# Test 5: Division by zero +T=5 +result=$(./expr 5 0 / 2>&1) +if [[ "$result" == *"division by zero"* ]]; then + echo "Test $T PASS: Division by zero detected" +else + echo "Test $T FAIL: Should detect division by zero" +fi + +# Test 6: Missing operator +T=6 +result=$(./expr 5 1) +expected="Error: Operator is missing!" +if [[ "$result" == "$expected" ]]; then + echo "Test $T PASS: Missing operator" +else + echo "Test $T FAIL: Expected '$expected', got '$result'" +fi + +echo "=== Tests Complete ===" \ No newline at end of file