tenseleyflow/shtick / cceeb7c

Browse files

update 'test bench'

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
cceeb7cbe5131ef4fa945b26770614b76427cebe
Parents
63d0695
Tree
643ed62

2 changed files

StatusFile+-
M test_shtick.py 212 14
D test_shtick.sh 0 236
test_shtick.pymodified
@@ -1,7 +1,7 @@
11
 #!/usr/bin/env python3
22
 """
3
-test_shtick_fixed.py - Comprehensive test suite for shtick commands
4
-Fixed to handle interactive prompts
3
+test_shtick_enhanced.py - Comprehensive test suite for shtick commands
4
+Enhanced with backup and group management tests
55
 """
66
 
77
 import subprocess
@@ -58,6 +58,9 @@ class ShtickTester:
5858
         """Set up test environment"""
5959
         self.test_dir = tempfile.mkdtemp(prefix="shtick_test_")
6060
         os.environ["HOME"] = self.test_dir
61
+        os.environ["SHTICK_ORIGINAL_HOME"] = (
62
+            self.original_home
63
+        )  # For security.py to work
6164
         os.makedirs(os.path.join(self.test_dir, ".config", "shtick"), exist_ok=True)
6265
 
6366
         # Create a settings file that disables auto_source_prompt to avoid timeouts
@@ -86,6 +89,7 @@ interactive_mode = false
8689
             os.environ["HOME"] = self.original_home
8790
         else:
8891
             os.environ.pop("HOME", None)
92
+        os.environ.pop("SHTICK_ORIGINAL_HOME", None)
8993
 
9094
     def run_command(self, args, input_text=None, env_override=None):
9195
         """Run a shtick command and return (output, return_code)"""
@@ -97,6 +101,7 @@ interactive_mode = false
97101
 
98102
         # Always ensure we're using our test HOME
99103
         env["HOME"] = self.test_dir
104
+        env["SHTICK_ORIGINAL_HOME"] = self.original_home  # For security.py
100105
 
101106
         try:
102107
             # For commands that might prompt, always provide 'n' as input
@@ -128,6 +133,8 @@ interactive_mode = false
128133
         description,
129134
         input_text=None,
130135
         env_override=None,
136
+        check_output=None,
137
+        check_not_output=None,
131138
     ):
132139
         """Run a test and check the result"""
133140
         self.tests_run += 1
@@ -136,12 +143,28 @@ interactive_mode = false
136143
 
137144
         output, actual_status = self.run_command(args, input_text, env_override)
138145
 
139
-        if actual_status == expected_status:
146
+        # Check status code
147
+        status_ok = actual_status == expected_status
148
+
149
+        # Check output if requested
150
+        output_ok = True
151
+        if check_output is not None:
152
+            output_ok = check_output in output
153
+        if check_not_output is not None and output_ok:
154
+            output_ok = check_not_output not in output
155
+
156
+        if status_ok and output_ok:
140157
             print(f"{GREEN}PASS{NC}")
141158
             self.tests_passed += 1
142159
         else:
143160
             print(f"{RED}FAIL{NC}")
144
-            print(f"  Expected status: {expected_status}, Got: {actual_status}")
161
+            if not status_ok:
162
+                print(f"  Expected status: {expected_status}, Got: {actual_status}")
163
+            if not output_ok:
164
+                if check_output is not None:
165
+                    print(f"  Expected output to contain: {check_output}")
166
+                if check_not_output is not None:
167
+                    print(f"  Expected output NOT to contain: {check_not_output}")
145168
             print(f"  Command: {' '.join(self.shtick_cmd + args)}")
146169
             print(f"  Output: {output[:500]}...")  # Truncate long output
147170
             self.tests_failed += 1
@@ -162,7 +185,7 @@ interactive_mode = false
162185
     def run_all_tests(self):
163186
         """Run all tests"""
164187
         print("===================================")
165
-        print("Shtick Command Test Suite (Python)")
188
+        print("Shtick Command Test Suite (Enhanced)")
166189
         print("===================================\n")
167190
 
168191
         self.setup()
@@ -238,7 +261,7 @@ interactive_mode = false
238261
                 "deactivate-inactive",
239262
                 ["deactivate", "work"],
240263
                 0,
241
-                "Deactivate already inactive group",
264
+                "Deactivate already inactive group (idempotent)",
242265
             )
243266
 
244267
             # Test 5: Remove operations - provide input for selection
@@ -254,7 +277,7 @@ interactive_mode = false
254277
                 "remove-nonexistent",
255278
                 ["remove-persistent", "alias", "nonexistent"],
256279
                 0,
257
-                "Remove non-existent item",
280
+                "Remove non-existent item (no-op)",
258281
             )
259282
 
260283
             # Re-add for next test
@@ -408,23 +431,198 @@ interactive_mode = false
408431
 
409432
             # Test 13: Backup functionality
410433
             print(f"\n{YELLOW}Testing backup functionality:{NC}")
434
+            # Add some content first
435
+            self.run_command(["alias", "backup_test=echo backup"])
411436
             self.test_command("backup-create", ["backup", "create"], 0, "Create backup")
437
+            self.test_command(
438
+                "backup-create-named",
439
+                ["backup", "create", "-n", "test_backup"],
440
+                0,
441
+                "Create named backup",
442
+            )
412443
             self.test_command("backup-list", ["backup", "list"], 0, "List backups")
413444
 
414
-            # Test 14: Group management
415
-            print(f"\n{YELLOW}Testing group management:{NC}")
445
+            # Modify config
446
+            self.run_command(["alias", "after_backup=echo after"])
447
+
448
+            # Restore and verify
449
+            self.test_command(
450
+                "backup-restore",
451
+                ["backup", "restore", "test_backup"],
452
+                0,
453
+                "Restore from backup",
454
+            )
455
+
456
+            # Verify restore worked by checking if the new alias is gone
457
+            output, _ = self.run_command(["list"])
458
+            if "after_backup" not in output:
459
+                print(
460
+                    f"[{self.tests_run + 1}] verify-restore: Backup restore worked correctly ... {GREEN}PASS{NC}"
461
+                )
462
+                self.tests_passed += 1
463
+            else:
464
+                print(
465
+                    f"[{self.tests_run + 1}] verify-restore: Backup restore failed ... {RED}FAIL{NC}"
466
+                )
467
+                self.tests_failed += 1
468
+            self.tests_run += 1
469
+
470
+            # Test 14: Group management - NOW WITH REAL FUNCTIONALITY!
471
+            print(f"\n{YELLOW}Testing group management (enhanced):{NC}")
472
+
473
+            # Test creating a new group
474
+            self.test_command(
475
+                "group-create",
476
+                ["group", "create", "testgroup"],
477
+                0,
478
+                "Create new group",
479
+                check_output="✓ Created group 'testgroup'",
480
+                check_not_output="will be created when you add",
481
+            )
482
+
483
+            # Verify the group exists in status
484
+            output, _ = self.run_command(["status"])
485
+            if "testgroup: 0 items" in output:
486
+                print(
487
+                    f"[{self.tests_run + 1}] verify-group-exists: Created group shows in status ... {GREEN}PASS{NC}"
488
+                )
489
+                self.tests_passed += 1
490
+            else:
491
+                print(
492
+                    f"[{self.tests_run + 1}] verify-group-exists: Created group should show in status ... {RED}FAIL{NC}"
493
+                )
494
+                print(f"  Status output: {output}")
495
+                self.tests_failed += 1
496
+            self.tests_run += 1
497
+
498
+            # Verify we can activate the empty group
499
+            self.test_command(
500
+                "activate-empty-group",
501
+                ["activate", "testgroup"],
502
+                0,
503
+                "Activate empty group",
504
+            )
505
+
506
+            # Verify the group shows as active
507
+            output, _ = self.run_command(["status"])
508
+            if "testgroup: 0 items (ACTIVE)" in output:
509
+                print(
510
+                    f"[{self.tests_run + 1}] verify-group-active: Empty group shows as active ... {GREEN}PASS{NC}"
511
+                )
512
+                self.tests_passed += 1
513
+            else:
514
+                print(
515
+                    f"[{self.tests_run + 1}] verify-group-active: Empty group should show as active ... {RED}FAIL{NC}"
516
+                )
517
+                print(f"  Status output: {output}")
518
+                self.tests_failed += 1
519
+            self.tests_run += 1
520
+
521
+            # Test adding to the newly created group
522
+            self.test_command(
523
+                "add-to-created-group",
524
+                ["add", "alias", "testgroup", "tg=echo testgroup"],
525
+                0,
526
+                "Add item to newly created group",
527
+            )
528
+
529
+            # Verify the group now has 1 item
530
+            output, _ = self.run_command(["status"])
531
+            if "testgroup: 1 items (ACTIVE)" in output:
532
+                print(
533
+                    f"[{self.tests_run + 1}] verify-group-has-item: Group shows 1 item after add ... {GREEN}PASS{NC}"
534
+                )
535
+                self.tests_passed += 1
536
+            else:
537
+                print(
538
+                    f"[{self.tests_run + 1}] verify-group-has-item: Group should show 1 item ... {RED}FAIL{NC}"
539
+                )
540
+                print(f"  Status output: {output}")
541
+                self.tests_failed += 1
542
+            self.tests_run += 1
543
+
544
+            # Test creating duplicate group
416545
             self.test_command(
417
-                "group-create", ["group", "create", "testgroup"], 0, "Create new group"
546
+                "group-create-duplicate",
547
+                ["group", "create", "testgroup"],
548
+                1,
549
+                "Cannot create duplicate group",
550
+                check_output="already exists",
418551
             )
552
+
553
+            # Check the TOML file contains empty sections
554
+            config_path = os.path.join(
555
+                self.test_dir, ".config", "shtick", "config.toml"
556
+            )
557
+            if os.path.exists(config_path):
558
+                with open(config_path, "r") as f:
559
+                    toml_content = f.read()
560
+                    # Check for either nested format (with tomli_w) or flat format (fallback)
561
+                    has_nested = (
562
+                        "[testgroup]" in toml_content
563
+                        and "[testgroup.aliases]" in toml_content
564
+                    )
565
+                    has_flat = "[testgroup.aliases]" in toml_content
566
+                    if has_nested or has_flat:
567
+                        print(
568
+                            f"[{self.tests_run + 1}] verify-toml-structure: TOML has proper empty group structure ... {GREEN}PASS{NC}"
569
+                        )
570
+                        self.tests_passed += 1
571
+                    else:
572
+                        print(
573
+                            f"[{self.tests_run + 1}] verify-toml-structure: TOML should have empty group sections ... {RED}FAIL{NC}"
574
+                        )
575
+                        print(f"  TOML content:\n{toml_content[:500]}")
576
+                        self.tests_failed += 1
577
+                    self.tests_run += 1
578
+
579
+            # Still test unimplemented features
419580
             self.test_command(
420581
                 "group-rename",
421582
                 ["group", "rename", "testgroup", "newgroup"],
422
-                0,
423
-                "Rename group",
583
+                1,
584
+                "Rename group (not implemented)",
585
+                check_output="not yet implemented",
424586
             )
425587
             self.test_command(
426
-                "group-remove", ["group", "remove", "newgroup", "-f"], 0, "Remove group"
588
+                "group-remove",
589
+                ["group", "remove", "testgroup", "-f"],
590
+                1,
591
+                "Remove group (not implemented)",
592
+                check_output="not yet implemented",
593
+            )
594
+
595
+            # Test 15: Exit code consistency
596
+            print(f"\n{YELLOW}Testing exit code consistency:{NC}")
597
+            # Test that user cancellation uses exit code 2
598
+            output, status = self.run_command(
599
+                ["settings", "init"], input_text="\x03"
600
+            )  # Ctrl+C
601
+            if status == 2 or "Cancelled" in output:
602
+                print(
603
+                    f"[{self.tests_run + 1}] user-cancel-exit-code: User cancellation returns code 2 ... {GREEN}PASS{NC}"
604
+                )
605
+                self.tests_passed += 1
606
+            else:
607
+                print(
608
+                    f"[{self.tests_run + 1}] user-cancel-exit-code: User cancellation should return code 2 ... {RED}FAIL{NC}"
609
+                )
610
+                print(f"  Got status: {status}, output: {output}")
611
+                self.tests_failed += 1
612
+            self.tests_run += 1
613
+
614
+            # Test 16: No-output commands should still exit properly
615
+            print(f"\n{YELLOW}Testing commands with no output still exit properly:{NC}")
616
+            # Create an empty config scenario
617
+            empty_dir = tempfile.mkdtemp()
618
+            self.test_command(
619
+                "list-empty-explicit-exit",
620
+                ["list"],
621
+                0,
622
+                "List with empty config exits 0",
623
+                env_override={"HOME": empty_dir},
427624
             )
625
+            shutil.rmtree(empty_dir)
428626
 
429627
         finally:
430628
             self.cleanup()
@@ -449,7 +647,7 @@ def main():
449647
     """Run the test suite"""
450648
     # Check if we should run in non-interactive mode
451649
     if len(sys.argv) > 1 and sys.argv[1] == "--help":
452
-        print("Usage: test_shtick_fixed.py")
650
+        print("Usage: test_shtick_enhanced.py")
453651
         print("Run comprehensive tests for shtick command line tool")
454652
         return 0
455653
 
test_shtick.shdeleted
@@ -1,236 +0,0 @@
1
-#!/bin/bash
2
-# test_shtick_fixed.sh - Test suite for shtick commands with proper PATH handling
3
-
4
-set -e  # Exit on error
5
-
6
-# Colors for output
7
-RED='\033[0;31m'
8
-GREEN='\033[0;32m'
9
-YELLOW='\033[1;33m'
10
-NC='\033[0m' # No Color
11
-
12
-# Test counters
13
-TESTS_RUN=0
14
-TESTS_PASSED=0
15
-TESTS_FAILED=0
16
-
17
-# Test config directory
18
-TEST_DIR="/tmp/shtick_test_$$"
19
-export HOME="$TEST_DIR"
20
-CONFIG_DIR="$TEST_DIR/.config/shtick"
21
-
22
-# Find shtick command - try multiple approaches
23
-find_shtick() {
24
-    # Method 1: Check if shtick is in PATH
25
-    if command -v shtick >/dev/null 2>&1; then
26
-        SHTICK_CMD="shtick"
27
-        echo "Found shtick in PATH: $(command -v shtick)"
28
-        return 0
29
-    fi
30
-    
31
-    # Method 2: Check if we're in development directory with cli.py
32
-    if [ -f "./shtick/cli.py" ]; then
33
-        SHTICK_CMD="python -m shtick.cli"
34
-        echo "Found shtick module in current directory, using: $SHTICK_CMD"
35
-        return 0
36
-    fi
37
-    
38
-    # Method 3: Check parent directory
39
-    if [ -f "../shtick/cli.py" ]; then
40
-        SHTICK_CMD="python -m shtick.cli"
41
-        echo "Found shtick module in parent directory"
42
-        cd ..
43
-        return 0
44
-    fi
45
-    
46
-    # Method 4: Try direct python execution
47
-    if [ -f "cli.py" ]; then
48
-        SHTICK_CMD="python cli.py"
49
-        echo "Found cli.py in current directory, using: $SHTICK_CMD"
50
-        return 0
51
-    fi
52
-    
53
-    echo "ERROR: Cannot find shtick command!"
54
-    echo "Please ensure either:"
55
-    echo "  1. shtick is installed and in your PATH"
56
-    echo "  2. You're running this from the shtick source directory"
57
-    echo "  3. The shtick package is properly installed with 'pip install -e .'"
58
-    exit 1
59
-}
60
-
61
-# Clean up function
62
-cleanup() {
63
-    rm -rf "$TEST_DIR"
64
-}
65
-trap cleanup EXIT
66
-
67
-# Setup test environment
68
-setup() {
69
-    rm -rf "$TEST_DIR"
70
-    mkdir -p "$CONFIG_DIR"
71
-    cd "$TEST_DIR"
72
-}
73
-
74
-# Test function
75
-test_command() {
76
-    local test_name="$1"
77
-    local command="$2"
78
-    local expected_status="$3"
79
-    local description="$4"
80
-    
81
-    TESTS_RUN=$((TESTS_RUN + 1))
82
-    
83
-    echo -n "[$TESTS_RUN] $test_name: $description ... "
84
-    
85
-    # Replace 'shtick' with actual command
86
-    command="${command//shtick/$SHTICK_CMD}"
87
-    
88
-    # Run command and capture status
89
-    set +e
90
-    output=$(eval "$command" 2>&1)
91
-    actual_status=$?
92
-    set -e
93
-    
94
-    if [ $actual_status -eq $expected_status ]; then
95
-        echo -e "${GREEN}PASS${NC}"
96
-        TESTS_PASSED=$((TESTS_PASSED + 1))
97
-    else
98
-        echo -e "${RED}FAIL${NC}"
99
-        echo "  Expected status: $expected_status, Got: $actual_status"
100
-        echo "  Command: $command"
101
-        echo "  Output: $output"
102
-        TESTS_FAILED=$((TESTS_FAILED + 1))
103
-    fi
104
-}
105
-
106
-# Verify shtick is working
107
-verify_shtick() {
108
-    echo "Verifying shtick command..."
109
-    set +e
110
-    output=$($SHTICK_CMD --help 2>&1)
111
-    status=$?
112
-    set -e
113
-    
114
-    if [ $status -ne 0 ]; then
115
-        echo -e "${RED}ERROR: shtick command not working!${NC}"
116
-        echo "Command: $SHTICK_CMD --help"
117
-        echo "Status: $status"
118
-        echo "Output: $output"
119
-        exit 1
120
-    fi
121
-    echo -e "${GREEN}✓ shtick command verified${NC}"
122
-    echo
123
-}
124
-
125
-# Header
126
-echo "==================================="
127
-echo "Shtick Command Test Suite"
128
-echo "==================================="
129
-echo
130
-
131
-# Find shtick command
132
-find_shtick
133
-
134
-# Setup
135
-setup
136
-
137
-# Verify shtick works
138
-verify_shtick
139
-
140
-# Save original directory to return to later
141
-ORIGINAL_DIR=$(pwd)
142
-
143
-# Test 1: Basic commands without config
144
-echo -e "${YELLOW}Testing basic commands without config:${NC}"
145
-test_command "status-no-config" "shtick status" 0 "Status should work without config"
146
-test_command "list-no-config" "shtick list" 0 "List should work without config"
147
-test_command "shells" "shtick shells" 0 "Shells command should always work"
148
-
149
-# Test 2: Adding items (creates config)
150
-echo -e "\n${YELLOW}Testing add commands:${NC}"
151
-test_command "add-alias" "shtick alias ll='ls -la'" 0 "Add persistent alias"
152
-test_command "add-env" "shtick env DEBUG=1" 0 "Add persistent env var"
153
-test_command "add-function" "shtick function greet='echo Hello'" 0 "Add persistent function"
154
-
155
-# Test 3: Invalid add commands
156
-echo -e "\n${YELLOW}Testing invalid add commands:${NC}"
157
-test_command "add-invalid-key" "shtick alias '123bad=value'" 1 "Invalid key should fail"
158
-test_command "add-no-equals" "shtick alias 'no_equals_sign'" 1 "Missing = should fail"
159
-test_command "add-empty-key" "shtick alias '=value'" 1 "Empty key should fail"
160
-test_command "add-empty-value" "shtick alias 'key='" 1 "Empty value should fail"
161
-
162
-# Test 4: Group operations
163
-echo -e "\n${YELLOW}Testing group operations:${NC}"
164
-test_command "add-to-group" "shtick add alias work ll='ls -la'" 0 "Add to specific group"
165
-test_command "activate-group" "shtick activate work" 0 "Activate existing group"
166
-test_command "activate-nonexistent" "shtick activate nonexistent" 1 "Activate non-existent group should fail"
167
-test_command "deactivate-group" "shtick deactivate work" 0 "Deactivate active group"
168
-test_command "deactivate-inactive" "shtick deactivate work" 0 "Deactivate already inactive group"
169
-
170
-# Test 5: Remove operations
171
-echo -e "\n${YELLOW}Testing remove operations:${NC}"
172
-test_command "remove-existing" "echo 1 | shtick remove-persistent alias ll" 0 "Remove existing alias"
173
-test_command "remove-nonexistent" "shtick remove-persistent alias nonexistent" 0 "Remove non-existent item"
174
-test_command "remove-fuzzy" "echo 1 | shtick remove alias work ll" 0 "Remove with fuzzy match"
175
-
176
-# Test 6: Generate command
177
-echo -e "\n${YELLOW}Testing generate command:${NC}"
178
-test_command "generate-default" "shtick generate --terse" 0 "Generate with default config"
179
-test_command "generate-custom" "shtick generate $CONFIG_DIR/config.toml --terse" 0 "Generate with custom config path"
180
-test_command "generate-nonexistent" "shtick generate /tmp/nonexistent.toml" 1 "Generate with non-existent config should fail"
181
-
182
-# Test 7: Source command
183
-echo -e "\n${YELLOW}Testing source command:${NC}"
184
-test_command "source-bash" "SHELL=/bin/bash shtick source" 0 "Source command for bash"
185
-test_command "source-no-shell" "SHELL= shtick source" 1 "Source without shell should fail"
186
-
187
-# Test 8: Settings commands
188
-echo -e "\n${YELLOW}Testing settings commands:${NC}"
189
-test_command "settings-show" "shtick settings show" 0 "Show settings"
190
-test_command "settings-init" "shtick settings init" 0 "Initialize settings"
191
-test_command "settings-set-bool" "shtick settings set behavior.auto_source_prompt false" 0 "Set boolean setting"
192
-test_command "settings-set-invalid" "shtick settings set invalid.key value" 1 "Set invalid setting should fail"
193
-
194
-# Test 9: Edge cases
195
-echo -e "\n${YELLOW}Testing edge cases:${NC}"
196
-test_command "persistent-activate" "shtick activate persistent" 1 "Cannot activate persistent group"
197
-test_command "persistent-deactivate" "shtick deactivate persistent" 1 "Cannot deactivate persistent group"
198
-test_command "very-long-key" "shtick alias $(printf 'a%.0s' {1..65})=value" 1 "Key over 64 chars should fail"
199
-
200
-# Test 10: Special characters and escaping
201
-echo -e "\n${YELLOW}Testing special characters:${NC}"
202
-test_command "alias-with-quotes" "shtick alias msg='echo \"Hello World\"'" 0 "Alias with quotes"
203
-test_command "alias-with-dollar" 'shtick alias home="cd \$HOME"' 0 "Alias with dollar sign"
204
-test_command "multiline-function" 'shtick function hello="echo line1
205
-echo line2"' 0 "Multiline function"
206
-
207
-# Test 11: List and status with content
208
-echo -e "\n${YELLOW}Testing list and status with content:${NC}"
209
-test_command "list-with-content" "shtick list" 0 "List with items"
210
-test_command "list-long-format" "shtick list -l" 0 "List in long format"
211
-test_command "status-with-content" "shtick status" 0 "Status with configuration"
212
-
213
-# Test 12: Conflict handling
214
-echo -e "\n${YELLOW}Testing conflict handling:${NC}"
215
-test_command "add-conflict-alias" "shtick add alias temp ll='ls -lah'" 0 "Add conflicting alias to different group"
216
-test_command "check-conflict-warning" "shtick alias ll='ls -la' 2>&1 | grep -q 'exists in groups'" 0 "Should warn about conflicts"
217
-
218
-# Return to original directory
219
-cd "$ORIGINAL_DIR"
220
-
221
-# Summary
222
-echo
223
-echo "==================================="
224
-echo "Test Summary"
225
-echo "==================================="
226
-echo "Tests run:    $TESTS_RUN"
227
-echo -e "Tests passed: ${GREEN}$TESTS_PASSED${NC}"
228
-echo -e "Tests failed: ${RED}$TESTS_FAILED${NC}"
229
-
230
-if [ $TESTS_FAILED -eq 0 ]; then
231
-    echo -e "\n${GREEN}All tests passed!${NC}"
232
-    exit 0
233
-else
234
-    echo -e "\n${RED}Some tests failed!${NC}"
235
-    exit 1
236
-fi