Skip to content
This repository was archived by the owner on Sep 12, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/bash

# Git pre-push hook to run validation pipeline
# This prevents pushing code that fails known tests or linting

set -e

echo "🔍 Running pre-push validation pipeline..."

# Run formatting check
echo "📝 Checking code formatting..."
if ! mix format --check-formatted; then
echo "❌ Code formatting check failed. Run 'mix format' to fix."
exit 1
fi

# Run regression tests (critical - these should never break)
echo "🧪 Running regression tests..."
if ! mix test.regression; then
echo "❌ Regression tests failed. These tests should always pass!"
exit 1
fi

# Run static analysis
echo "🔍 Running static analysis (Credo)..."
if ! mix credo --strict; then
echo "❌ Credo analysis failed. Fix issues before pushing."
exit 1
fi

# Run type checking (optional - can be slow)
# Uncomment if you want type checking in the pre-push hook
# echo "🔬 Running type checking (Dialyzer)..."
# if ! mix dialyzer; then
# echo "❌ Dialyzer type checking failed."
# exit 1
# fi

echo "✅ All validation checks passed! Ready to push."
21 changes: 9 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,10 @@ jobs:
- name: Run Dialyzer
run: mix dialyzer

scion-tests:
name: SCION Test Suite
regression-tests:
name: Regression Test Suite
runs-on: ubuntu-latest
needs: test
continue-on-error: true

steps:
- name: Checkout code
Expand All @@ -231,13 +230,11 @@ jobs:
restore-keys: |
deps-${{ runner.os }}-27.3-1.18.3-

- name: Run SCION basic tests
run: mix test --include spec:basic
- name: Install dependencies
run: mix deps.get

- name: Upload SCION test results
uses: actions/upload-artifact@v4
if: always()
with:
name: scion-test-results
path: _build/test/lib/sc/test-results.xml
retention-days: 30
- name: Compile project
run: mix compile

- name: Run regression tests
run: mix test.regression
15 changes: 13 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,25 @@ When verifying code changes, always follow this sequence (also automated via pre
4. `mix dialyzer` - Run Dialyzer static analysis for type checking

**Git Hooks:**
- `./scripts/setup-git-hooks.sh` - Install pre-push hook for validation pipeline
- Pre-push hook automatically runs the validation workflow to catch issues before CI
- Located at `.git/hooks/pre-push` (executable)
- Blocks push if any validation step fails

**Regression Testing:**
- `test/passing_tests.json` - Registry of tests that should always pass
- Tracks internal tests, SCION tests, and W3C tests separately
- Updated manually when new tests start passing consistently
- Used by CI pipeline to catch regressions early

**Testing:**
- `mix test` - Run all internal tests (excludes SCION/W3C by default)
- `mix test --include scion --include scxml_w3` - Run all tests including SCION and W3C tests
- `mix test.regression` - Run regression tests that should always pass
- `mix test.baseline` - Check which tests are currently passing (for updating regression suite)
- `mix test --cover` - Run all tests with coverage reporting (maintain 95%+ coverage)
- `mix coveralls` - Alternative coverage command
- `mix coveralls.detail` - Run tests with detailed coverage report showing uncovered lines
- `mix test` - Run all tests without coverage
- `mix test test/sc/location_test.exs` - Run location tracking tests
- `mix test test/sc/parser/scxml_test.exs` - Run specific SCXML parser tests (uses pattern matching)
- `mix test test/sc/interpreter/compound_state_test.exs` - Run compound state tests
Expand Down Expand Up @@ -255,4 +265,5 @@ XML content within triple quotes uses 4-space base indentation.

The implementation follows the W3C SCXML specification closely and includes comprehensive test coverage from both W3C and SCION test suites. The current interpreter provides a solid foundation for basic SCXML functionality with clear areas identified for future enhancement.

- Always refer to state machines as state charts
- Always refer to state machines as state charts
- Always run 'mix format' after writing an Elixir file.
137 changes: 104 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,35 @@ An Elixir implementation of SCXML (State Chart XML) state charts with a focus on
- ✅ **State Chart Interpreter** - Runtime engine for executing SCXML state charts
- ✅ **Comprehensive Validation** - Document validation with detailed error reporting
- ✅ **Compound States** - Support for hierarchical states with automatic initial child entry
- ✅ **Parallel States** - Support for concurrent state regions with simultaneous execution
- ✅ **O(1) Performance** - Optimized state and transition lookups via Maps
- ✅ **Event Processing** - Internal and external event queues per SCXML specification
- ✅ **Parse → Validate → Optimize Architecture** - Clean separation of concerns
- ✅ **Pre-push Hook** - Automated local validation workflow to catch issues early
- ✅ **Regression Testing** - Automated tracking of passing tests to prevent regressions
- ✅ **Git Hooks** - Pre-push validation workflow to catch issues early
- ✅ **Test Infrastructure** - Compatible with SCION and W3C test suites

## Current Status

**SCION Test Results:** 107/225 tests passing (47.6% pass rate)
**SCION Test Results:** 30/127 tests passing (23.6% pass rate)
**W3C Test Results:** 0/59 tests passing (0% pass rate)
**Regression Suite:** 22 tests (all critical functionality)

### Working Features
- Basic state transitions and event-driven changes
- Hierarchical states with optimized O(d) ancestor lookup using parent pointers
- Document validation and error reporting with comprehensive hierarchy checks
- SAX-based XML parsing with accurate location tracking
- Performance-optimized active configuration generation
- ✅ **Basic state transitions** and event-driven changes
- ✅ **Hierarchical states** with optimized O(1) state lookup and automatic initial child entry
- ✅ **Parallel states** with concurrent execution of multiple regions
- ✅ **Document validation** and error reporting with comprehensive structural checks
- ✅ **SAX-based XML parsing** with accurate location tracking for error reporting
- ✅ **Performance optimizations** - O(1) state/transition lookups, optimized active configuration
- ✅ **Source field optimization** - Transitions include source state for faster event processing

### Planned Features
- Parallel states (`<parallel>`)
- History states (`<history>`)
- Conditional transitions with expression evaluation
- Executable content (`<script>`, `<assign>`, `<send>`, etc.)
- Conditional transitions with expression evaluation (`cond` attribute)
- Internal and targetless transitions
- Executable content (`<script>`, `<assign>`, `<send>`, `<onentry>`, `<onexit>`, etc.)
- Expression evaluation and datamodel support
- Enhanced validation for complex SCXML constructs

## Installation
Expand Down Expand Up @@ -117,35 +124,49 @@ The project maintains high code quality through automated checks:

```bash
# Local validation workflow (also runs via pre-push hook)
mix format
mix test --cover
mix credo --strict
mix dialyzer
mix format # Auto-fix formatting
mix test.regression # Run critical regression tests (22 tests)
mix credo --strict # Static code analysis
mix dialyzer # Type checking
```

### Pre-push Hook
### Regression Testing

A git pre-push hook automatically runs the validation workflow to catch issues before CI:
The project uses automated regression testing to prevent breaking existing functionality:

```bash
git push origin feature-branch
# Automatically runs: format check, tests, credo, dialyzer
# Push is blocked if any step fails
# Run only tests that should always pass (22 tests)
mix test.regression

# Check which tests are currently passing to update regression suite
mix test.baseline

# Install git hooks for automated validation
./scripts/setup-git-hooks.sh
```

The regression suite tracks:
- **Internal tests**: All `test/sc/**/*_test.exs` files (supports wildcards)
- **SCION tests**: 8 known passing tests (basic + hierarchy + parallel)
- **W3C tests**: Currently none passing

### Running Tests

```bash
# All tests
# All internal tests (excludes SCION/W3C by default)
mix test

# With coverage
mix coveralls
# All tests including SCION and W3C test suites
mix test --include scion --include scxml_w3

# SCION basic tests
mix test --include scion --include spec:basic --exclude scxml_w3
# Only regression tests (22 critical tests)
mix test.regression

# Specific test file
# With coverage reporting
mix coveralls

# Specific test categories
mix test --include scion test/scion_tests/basic/
mix test test/sc/parser/scxml_test.exs
```

Expand Down Expand Up @@ -190,16 +211,19 @@ The implementation includes several key optimizations for production use:
- **Built During Validation**: Lookup maps only created for valid documents
- **Memory Efficient**: Uses existing document structure, no duplication

### **Compound State Entry**
### **Compound and Parallel State Entry**
```elixir
# Automatic hierarchical entry
{:ok, state_chart} = SC.Interpreter.initialize(document)
active_states = SC.Interpreter.active_states(state_chart)
# Returns only leaf states (compound states entered automatically)
# Returns only leaf states (compound/parallel states entered automatically)

# Fast ancestor computation when needed
ancestors = SC.Interpreter.active_ancestors(state_chart)
# O(1) state lookups + O(d) ancestor traversal

# Parallel states enter ALL child regions simultaneously
# Compound states enter initial child recursively
```

### **Parse → Validate → Optimize Flow**
Expand All @@ -210,18 +234,63 @@ ancestors = SC.Interpreter.active_ancestors(state_chart)
**Performance Impact:**
- O(1) vs O(n) state lookups during interpretation
- O(1) vs O(n) transition queries for event processing
- Source field optimization eliminates expensive lookups during event processing
- Critical for responsive event processing in complex state charts

## Regression Testing System

The project includes a sophisticated regression testing system to ensure stability:

### **Test Registry** (`test/passing_tests.json`)
```json
{
"internal_tests": ["test/sc_test.exs", "test/sc/**/*_test.exs"],
"scion_tests": ["test/scion_tests/basic/basic0_test.exs", ...],
"w3c_tests": []
}
```

### **Wildcard Support**
- Supports glob patterns like `test/sc/**/*_test.exs`
- Automatically expands to all matching test files
- Maintains clean, maintainable test registry

### **CI Integration**
- Regression tests run before full test suite in CI
- Prevents merging code that breaks core functionality
- Fast feedback loop (22 tests vs 290 total tests)

### **Local Development**
```bash
# Check current regression status
mix test.regression

# Update regression baseline after adding features
mix test.baseline
# Manually add newly passing tests to test/passing_tests.json

# Pre-push hook automatically runs regression tests
git push origin feature-branch
```

## Contributing

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes following the code quality workflow
4. Add tests for new functionality
5. Ensure all CI checks pass
6. Commit your changes (`git commit -m 'Add amazing feature'`)
7. Push to the branch (`git push origin feature/amazing-feature`)
8. Open a Pull Request
3. Install git hooks: `./scripts/setup-git-hooks.sh`
4. Make your changes following the code quality workflow:
- `mix format` (auto-fix formatting)
- Add tests for new functionality
- `mix test.regression` (ensure no regressions)
- `mix credo --strict` (static analysis)
- `mix dialyzer` (type checking)
5. Update regression tests if you fix failing SCION/W3C tests:
- Run `mix test.baseline` to see current status
- Add newly passing tests to `test/passing_tests.json`
6. Ensure all CI checks pass
7. Commit your changes (`git commit -m 'Add amazing feature'`)
8. Push to the branch (pre-push hook will run automatically)
9. Open a Pull Request

### Code Style

Expand All @@ -231,6 +300,8 @@ ancestors = SC.Interpreter.active_ancestors(state_chart)
- Comprehensive test coverage (95%+ maintained)
- Detailed documentation with `@moduledoc` and `@doc`
- Pattern matching preferred over multiple assertions in tests
- Git pre-push hook enforces validation workflow automatically
- Regression tests ensure core functionality never breaks

## License

Expand Down
2 changes: 1 addition & 1 deletion coveralls.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"skip_files": [ "test/support" ],
"skip_files": [ "test/support", "lib/mix/tasks/test.*.ex" ],
"coverage_options": {
"treat_no_relevant_lines_as_covered": true,
"output_dir": "cover/",
Expand Down
Loading