Git Bash Test Compatibility: A Deep Dive into Cross-Platform Bats Issues
Date: September 2, 2025 Context: Investigation and resolution of test failures on Git Bash/Windows
Executive Summary
We encountered widespread test failures when running the eed test suite on Git Bash/Windows, while all tests passed on Linux. Through systematic investigation, we discovered multiple platform-specific issues with bats test framework and developed comprehensive solutions. This document captures the technical journey, root causes, and proven solutions for future reference.
The Problem
Initial Symptoms
- Multiple test failures on Git Bash: 
test_eed_logging.bats,test_eed_preview.bats,test_eed_single_param.bats,test_eed_stdin.bats - All tests passed perfectly on Linux
 - Mysterious file corruption in safety tests
 - Pipeline-based tests consistently failing with "Command not found" errors
 
Example Failing Patterns
# This pattern consistently failed on Git Bash:
run bash -c "printf '1d\nw\nq\n' | $SCRIPT_UNDER_TEST --force test.txt -"
# Status: 127 (Command not found)
# Error: bash -c printf '1d\nw\nq\n' | /path/to/eed --force test.txt -
Root Cause Analysis
1. Missing Library Dependencies
Issue: eed_common.sh was using EED_REGEX_INPUT_MODE without sourcing eed_regex_patterns.sh
Symptoms:
- Logging tests failed because input mode detection returned empty regex
 - Content that should be skipped was being logged
 
Fix:
# Added to eed_common.sh
source "$(dirname "${BASH_SOURCE[0]}")/eed_regex_patterns.sh"
2. Bats Pipeline Simulation Issues
Issue: Bats implements pipe simulation differently on Windows vs Linux
Technical Details:
- Linux: Native shell pipes or compatible simulation work correctly
 - Windows/Git Bash: Bats' pipe parsing breaks complex pipeline commands
 - Pattern 
run bash -c "command | other"becomesbash -c command | other - The pipeline executes outside bats' control, losing exit code and output capture
 
Symptoms:
# What we wrote:
run bash -c "printf '1d\nw\nq\n' | $SCRIPT_UNDER_TEST --force test.txt -"
# What actually executed:
bash -c printf '1d\nw\nq\n' | /path/to/eed --force test.txt -
#           ^^^^^^^^^^^^^^^^^^ Only this part in bash -c
#                              ^^^^^^^^^^^^^^^^^^^^^^^^^ This runs outside bats
3. File System Stat Comparison Issues
Issue: stat output includes microsecond-precision access times that change on every file read
Technical Details:
- Tests compared full 
statoutput including access times - Reading files for verification changed access times
 - Caused false failures in file integrity tests
 
Before:
original_stat="$(stat sample.txt)"
# ... test runs ...
[[ "$(stat sample.txt)" == "$original_stat" ]]  # Always fails due to access time
4. Regex Pattern Compatibility
Issue: Git Bash regex handling differences in substitute command detection
Technical Details:
- Fallback regex was too restrictive: 
s(.)[^\\]*\1.*\1([0-9gp]+)?$ - Pattern 
[^\\]*excluded characters needed for patterns likeconsole\.log - Made regex more permissive while maintaining safety
 
Solutions Implemented
Solution 1: Fix Library Dependencies
# In lib/eed_common.sh - added missing source
source "$(dirname "${BASH_SOURCE[0]}")/eed_regex_patterns.sh"
Solution 2: Cross-Platform Pipeline Patterns
A. Heredoc Approach (Recommended for Complex Input)
# Before (fails on Git Bash):
run bash -c "printf '1c\nchanged\n.\nw\nq\n' | $SCRIPT_UNDER_TEST --force test.txt -"
# After (works everywhere):
run "$SCRIPT_UNDER_TEST" --force test.txt - << 'EOF'
1c
changed
.
w
q
EOF
B. GPT's Pipeline-in-Bash-C Pattern (For When Pipes Are Needed)
# Before (fails on Git Bash):
run bash -c "echo '$script' | '$SCRIPT_UNDER_TEST' --force '$TEST_FILE' -"
# After (works everywhere):
run bash -c 'set -o pipefail; echo "$1" | "$2" --force "$3" -' \
    bash "$script" "$SCRIPT_UNDER_TEST" "$TEST_FILE"
Key Elements:
- Single quotes around entire bash -c content
 set -o pipefailfor proper error propagation- Pass variables as arguments (
"$1","$2") to avoid quoting hell - Entire pipeline contained within one bash -c execution
 
Solution 3: Robust File Integrity Testing
# Before (fails due to access time changes):
original_stat="$(stat sample.txt)"
[[ "$(stat sample.txt)" == "$original_stat" ]]
# After (only check relevant attributes):
original_size="$(stat -c %s sample.txt)"
original_mtime="$(stat -c %Y sample.txt)"
original_inode="$(stat -c %i sample.txt)"
[[ "$(stat -c %s sample.txt)" == "$original_size" ]]     # Size unchanged
[[ "$(stat -c %Y sample.txt)" == "$original_mtime" ]]   # Modify time unchanged
[[ "$(stat -c %i sample.txt)" == "$original_inode" ]]   # Inode unchanged
Solution 4: Improved Regex Patterns
# Before (too restrictive):
fallback='s(.)[^\\]*\1.*\1([0-9gp]+)?$'
# After (handles escaped characters properly):
fallback='s([^[:space:]]).*\1.*\1([0-9gp]*)?$'
Testing and Validation
Proof-of-Concept Tests
We created tests/test_printf_pipeline.bats to validate our understanding:
- Direct printf pipelines work perfectly (bypassing bats)
 - GPT's approach works reliably (pipeline within bash -c)
 - Problematic patterns consistently fail (pipeline across bash -c boundary)
 
Results
- Before: Multiple test failures, warnings, file corruption fears
 - After: 256 tests pass, 0 failures, 1 expected skip, 0 warnings
 
Key Learnings
1. Platform-Specific Tool Behavior
- Never assume cross-platform tools work identically
 - Bats, while excellent, has platform-specific implementation differences
 - Always test on target platforms, not just development environment
 
2. Root Cause Investigation Methodology
- Don't guess, investigate systematically
 - Use 
bats -xfor detailed execution traces - Test hypotheses with isolated proof-of-concept code
 - Distinguish between symptoms and root causes
 
3. Regex and Shell Compatibility
- Git Bash supports modern regex features when used correctly
 - Issues often stem from tooling layer, not shell capabilities
 - Platform differences in command parsing require careful attention
 
4. Test Design Best Practices
- Avoid external dependencies in tests (like 
python3for JSON validation) - Use heredoc for complex multiline input - most reliable approach
 - Compare only stable file attributes - avoid access times
 - Separate concerns - one test per scenario for better debugging
 
Recommended Patterns for Future Development
✅ DO: Use Heredoc for Complex Input
run "$COMMAND" file.txt - << 'EOF'
multiline
script
content
EOF
✅ DO: GPT's Pattern for Necessary Pipelines
run bash -c 'set -o pipefail; echo "$1" | "$2" --flags "$3"' \
    bash "$input" "$command" "$target"
❌ DON'T: Pipeline Across bash -c Boundary
run bash -c "printf '...' | command ..."  # Breaks on Git Bash
❌ DON'T: Compare Volatile File Attributes
[[ "$(stat file.txt)" == "$original_stat" ]]  # Access time changes
Files Modified
Core Library
lib/eed_common.sh: Added missing regex patterns sourcelib/eed_regex_patterns.sh: Improved substitute regex fallback
Test Files
tests/test_eed_single_param.bats: Printf pipeline → heredoctests/test_eed_stdin.bats: Printf pipeline → heredoc + GPT patterntests/test_safety_override_integration.bats: All patterns → GPT approachtests/test_ai_file_lifecycle.bats: Removed python3 dependencytests/test_eed_preview.bats: Fixed stat comparison + separated safety tests
New Infrastructure
tests/test_printf_pipeline.bats: Comprehensive pipeline pattern validation
Impact and Metrics
- Test Reliability: 256/256 tests now pass consistently on Git Bash
 - Warning Elimination: 0 BW01 warnings (previously multiple)
 - Cross-Platform Compatibility: Patterns work on both Windows and Linux
 - Maintainability: Cleaner test patterns, better separation of concerns
 - Documentation: Comprehensive understanding of platform differences
 
Future Considerations
When Adding New Tests
- Use heredoc approach for complex multiline input
 - Apply GPT's pattern when pipelines are absolutely necessary
 - Avoid comparing volatile file system attributes
 - Test on both platforms before considering complete
 
When Debugging Cross-Platform Issues
- Use 
bats -xto see exact command execution - Create isolated test cases to verify hypotheses
 - Check for tool-specific implementation differences
 - Don't assume the issue is with your code - could be tooling
 
Monitoring
- Watch for new BW01 warnings as indicator of problematic patterns
 - Ensure CI/CD tests both Linux and Windows environments
 - Regular cross-platform test execution during development
 
This investigation demonstrates the importance of thorough cross-platform testing and systematic root cause analysis. The solutions we implemented not only fixed immediate issues but established robust patterns for future development.
Key Takeaway: When tools behave differently across platforms, the solution isn't to work around the differences, but to understand them deeply and adopt patterns that work reliably everywhere.