fortsh Public
Go to file
T
Code
Use Git or checkout with SVN using the web URL.
No matching headings.
fortsh Interactive Test Framework
Automated testing framework for fortsh's interactive features using Python and pexpect.
Quick Start
# Activate the virtual environment
source tests/interactive/.venv/bin/activate
# Run all YAML spec tests
python tests/interactive/run_tests.py
# Run with specific fortsh binary
python tests/interactive/run_tests.py --fortsh ./bin/fortsh
# Run pytest tests
python tests/interactive/run_tests.py --pytest
# Generate markdown report
python tests/interactive/run_tests.py --report manual/results/$(date +%Y%m%d).md
Directory Structure
tests/interactive/
├── run_tests.py # Main test runner
├── fortsh_pty.py # PTY management class
├── conftest.py # Pytest fixtures
├── requirements.txt # Python dependencies
├── test_specs/ # YAML test specifications
│ ├── line_editing.yaml # Line editing tests (49 tests)
│ ├── history.yaml # History navigation/expansion (37 tests)
│ ├── completion.yaml # Tab completion tests (37 tests)
│ ├── signals_jobs.yaml # Signals and job control (40 tests)
│ ├── prompt_display.yaml # Prompt and display tests (39 tests)
│ └── posix.yaml # POSIX shell features (119 tests)
├── utils/
│ ├── keys.py # Key sequence definitions
│ └── matchers.py # Output matching utilities
├── manual/
│ └── results/ # Test result reports
└── README.md # This file
Writing Tests
YAML Specification Format
Tests can be defined declaratively in YAML:
metadata:
category: "Line Editing"
description: "Tests for cursor movement"
tests:
- name: "Left arrow moves cursor back"
steps:
- send: "echo test"
- send_key: "Left"
- send_key: "Left"
- send: "X"
- send_key: "Enter"
expect_output: "teXst"
match_type: "contains"
Available Step Types
| Step | Description | Example |
|---|---|---|
send |
Send text without newline | send: "echo hello" |
send_line |
Send text with Enter | send_line: "echo hello" |
send_key |
Send special key | send_key: "C-a" |
send_keys |
Send multiple keys | send_keys: ["Left", "Left"] |
wait |
Sleep for seconds | wait: 0.5 |
wait_for_prompt |
Wait for shell prompt | wait_for_prompt: true |
expect |
Wait for pattern | expect: "hello" |
resize |
Change terminal size | resize: {rows: 40, cols: 120} |
Match Types
| Type | Description |
|---|---|
exact |
Exact match (after strip) |
contains |
Substring match |
regex |
Regular expression |
startswith |
Prefix match |
endswith |
Suffix match |
Pytest Tests
For complex tests, use Python with pytest fixtures:
import pytest
@pytest.mark.line_editing
def test_ctrl_a_moves_to_beginning(fortsh):
fortsh.send("hello world")
fortsh.send_key("C-a")
fortsh.send("echo ")
fortsh.send_key("Enter")
output = fortsh.wait_for_prompt()
assert "hello world" in output
Available Fixtures
fortsh- Running fortsh session (rc disabled)fortsh_with_rc- Session with user's .fortshrcfortsh_factory- Create multiple sessionsfortsh_path- Path to fortsh binary
Key Sequences
Common keys are defined in utils/keys.py:
# Control keys
"C-a" # Beginning of line
"C-e" # End of line
"C-k" # Kill to end
"C-u" # Kill to beginning
"C-w" # Kill word
"C-y" # Yank
"C-c" # Interrupt
"C-z" # Suspend
"C-d" # EOF/Delete
"C-r" # Reverse search
# Alt/Meta keys
"M-b" # Back word
"M-f" # Forward word
# Arrow keys
"Up", "Down", "Left", "Right"
# Special
"Tab", "Enter", "Backspace", "Delete"
"Home", "End", "PageUp", "PageDown"
Test Categories
Tests are organized by feature (total 321 tests):
-
POSIX Shell Features (120+ tests)
- Basic operations
- Quoting and escaping
- Variables and expansion
- Pipelines and redirections
- Control structures (if/for/while/case)
- Functions and arithmetic
- Builtins
-
Line Editing (49 tests)
- Cursor movement
- Text modification
- Kill ring operations
- Word operations
-
History (37 tests)
- Arrow key navigation
- Ctrl+R search
- History expansion (!!, !$, etc.)
-
Completion (37 tests)
- Command completion
- Path/file completion
- Variable completion
-
Signals & Job Control (40 tests)
- SIGINT (Ctrl+C)
- SIGTSTP (Ctrl+Z)
- Background jobs
- Job specs (%n, %%, %+)
- fg/bg/jobs builtins
-
Prompt & Display (39 tests)
- PS1/PS2 escapes
- Terminal resize
- Colors and Unicode
Running Specific Tests
# Run single spec file
python tests/interactive/run_tests.py --spec line_editing.yaml
# Run pytest with markers
pytest tests/interactive -m line_editing
pytest tests/interactive -m "not slow"
# Run with verbose output
python tests/interactive/run_tests.py -v
Environment Variables
FORTSH- Path to fortsh binaryFORTSH_RC_FILE- Override rc file path
Adding New Tests
1. Add to existing YAML spec
# In test_specs/line_editing.yaml
tests:
- name: "My new test"
steps:
- send_line: "echo test"
expect_output: "test"
2. Create new YAML spec
# Create tests/interactive/test_specs/my_feature.yaml
3. Add pytest test
# Create tests/interactive/test_my_feature.py
def test_my_feature(fortsh):
output = fortsh.run_command("echo hello")
assert "hello" in output
CI Integration
For GitHub Actions with tmux:
- name: Run interactive tests
run: |
tmux new-session -d -s test
tmux send-keys -t test "python tests/interactive/run_tests.py" Enter
sleep 60
tmux capture-pane -t test -p > test_output.txt
grep -q "ALL TESTS PASSED" test_output.txt
Troubleshooting
"fortsh binary not found"
# Build fortsh first
make clean && make
# Or specify path
python tests/interactive/run_tests.py --fortsh /path/to/fortsh
Test timeouts
Increase timeout in test or PTY initialization:
pty = FortshPTY(timeout=10.0) # 10 seconds
Debugging tests
# In pytest test
def test_debug(fortsh):
fortsh.send_line("echo hello")
import time; time.sleep(5) # Pause to observe
output = fortsh.wait_for_prompt()
print(f"Output: {output}") # Will show with -s flag
Run with:
pytest tests/interactive -s --tb=long
Dependencies
- Python 3.8+
- pexpect >= 4.8
- PyYAML >= 6.0
- pytest >= 7.0
- colorama >= 0.4
Install with:
pip install -r tests/interactive/requirements.txt