lineguard 0.1.5

A fast and reliable file linter that ensures proper line endings and clean formatting
Documentation
# Contributing to LineGuard

Thank you for your interest in contributing to LineGuard! This document provides guidelines and instructions for contributing to the project.

## Development Process

LineGuard follows strict Test-Driven Development (TDD) practices. Every feature must be developed following this cycle:

1. **Write Test First** - Create minimal failing test
2. **Make Test Pass** - Write minimal code to pass
3. **Commit** - Commit working code
4. **Refactor** - Improve code quality
5. **Quality Checks** - Run all checks before final commit

## Getting Started

### Prerequisites

- Rust 1.70+ (install via [rustup]https://rustup.rs/)
- Git
- cargo-tarpaulin (for coverage): `cargo install cargo-tarpaulin`

### Setup

```bash
# Clone the repository
git clone https://github.com/hydai/lineguard
cd lineguard

# Build the project
cargo build

# Run tests
cargo test

# Run quality checks
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
```

## Testing Guidelines

### Test Structure

```
src/
├── checker/
│   ├── mod.rs          # Public API
│   ├── core.rs         # Core logic with tests
│   ├── file_checker.rs # File operations with tests
│   └── tests.rs        # Additional unit tests
├── reporter/
│   ├── mod.rs          # Public API
│   ├── human.rs        # Human reporter with tests
│   ├── json.rs         # JSON reporter with tests
│   └── github.rs       # GitHub reporter with tests
└── testing/            # Test infrastructure
    ├── mocks/          # Mock implementations
    └── builders/       # Test data builders

tests/                  # Integration tests
├── cli_tests.rs
├── fix_tests.rs
└── ...
```

### Writing Tests

#### Unit Tests

Place unit tests in the same file as the code being tested:

```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_function_behavior() {
        // Arrange
        let input = "test";

        // Act
        let result = function_under_test(input);

        // Assert
        assert_eq!(result, expected);
    }
}
```

#### Integration Tests

Place integration tests in the `tests/` directory:

```rust
use assert_cmd::Command;
use predicates::prelude::*;

#[test]
fn test_cli_behavior() {
    let mut cmd = Command::cargo_bin("lineguard").unwrap();
    cmd.arg("--help");

    cmd.assert()
        .success()
        .stdout(predicate::str::contains("LineGuard"));
}
```

### Using Mock Implementations

LineGuard provides mock implementations for testing without real I/O:

#### MockFileSystem

```rust
use lineguard::testing::mocks::{MockFileSystem, file_metadata};

#[test]
fn test_file_operations() {
    let mut fs = MockFileSystem::new();

    // Add a file with content (metadata is set automatically)
    fs.add_file("test.txt", "Hello\n");

    // Optionally set custom metadata
    fs.set_metadata("test.txt", file_metadata(6));

    // Simulate errors
    fs.add_error("error.txt", std::io::Error::new(
        std::io::ErrorKind::PermissionDenied,
        "Access denied"
    ));

    // Use in tests
    let content = fs.read_to_string(Path::new("test.txt")).unwrap();
    assert_eq!(content, "Hello\n");
}
```

#### MockOutput

```rust
#[test]
fn test_output_operations() {
    use lineguard::reporter::Color;
    use lineguard::testing::mocks::MockOutput;

    let mut output = MockOutput::new();

    // Write content
    output.write_line("Hello").unwrap();

    // Check buffer
    assert_eq!(output.get_output(), "Hello\n");

    // Test colored output
    output.write_colored("Error", Color::Red).unwrap();
    assert!(output.contains_colored("Error", Color::Red));
}
```

#### Test Builders

```rust
use lineguard::testing::builders::{TestFileBuilder, TestScenario};

#[test]
fn test_with_builders() {
    // Build test file content
    let (path, content) = TestFileBuilder::new("test.txt")
        .with_line("First line")
        .with_trailing_spaces()
        .without_final_newline()
        .build();

    // Build test scenario
    let scenario = TestScenario::new()
        .with_file("src/main.rs", "valid content\n")
        .with_file("src/bad.rs", "trailing spaces  \n")
        .build();
}
```

### Coverage Requirements

- Overall project: 90%+
- Core modules (checker, reporter): 85%+
- New features: Must include tests
- Bug fixes: Must include regression tests

Check coverage:

```bash
# Unit test coverage
cargo tarpaulin --lib --print-summary

# All test coverage
cargo tarpaulin --all --print-summary

# Generate HTML report
cargo tarpaulin --lib --out html
# Open tarpaulin-report.html in browser
```

## Code Style

### Formatting

- Use `cargo fmt` for consistent formatting
- Run before every commit: `cargo fmt --all`

### Linting

- Fix all clippy warnings: `cargo clippy --all-targets --all-features -- -D warnings`
- Common issues:
  - Use `&str` instead of `&String`
  - Use `&[T]` instead of `&Vec<T>`
  - Avoid unnecessary clones

### Naming Conventions

- Functions: `snake_case`
- Types: `PascalCase`
- Constants: `SCREAMING_SNAKE_CASE`
- Modules: `snake_case`

### Documentation

- Add doc comments to all public items
- Include examples in doc comments
- Run `cargo doc --open` to preview

```rust
/// Checks a file for line ending issues.
///
/// # Arguments
///
/// * `path` - Path to the file to check
///
/// # Examples
///
/// ```
/// use lineguard::check_file;
///
/// let result = check_file(&PathBuf::from("test.txt"));
/// assert!(result.issues.is_empty());
/// ```
pub fn check_file(path: &Path) -> CheckResult {
    // Implementation
}
```

## Making Changes

### 1. Create a Branch

```bash
git checkout -b feature/your-feature-name
# or
git checkout -b fix/issue-description
```

### 2. Follow TDD Cycle

```bash
# 1. Write failing test
# Edit test file...

# 2. Run test (should fail)
cargo test test_new_feature

# 3. Implement feature
# Edit source file...

# 4. Run test (should pass)
cargo test test_new_feature

# 5. Run all checks
cargo fmt --all
cargo clippy --all-targets --all-features -- -D warnings
cargo test
```

### 3. Commit Changes

```bash
# Stage changes
git add -A

# Commit with descriptive message
git commit -m "feat: add support for custom ignore patterns"
```

Commit message format:
- `feat:` New feature
- `fix:` Bug fix
- `docs:` Documentation changes
- `test:` Test changes
- `refactor:` Code refactoring
- `chore:` Maintenance tasks

### 4. Push and Create PR

```bash
git push origin feature/your-feature-name
```

Then create a Pull Request on GitHub.

## CI/CD Pipeline

All PRs must pass:

1. **Quick Tests** - Unit tests on all platforms
2. **Full Tests** - All tests including integration
3. **Code Quality** - Formatting and linting
4. **Security Audit** - Dependency scanning
5. **Coverage** - Must maintain 90%+ coverage

## Performance Considerations

- Use streaming for large files (>10MB)
- Leverage parallel processing with rayon
- Avoid unnecessary allocations
- Profile with `cargo flamegraph` for bottlenecks

## Need Help?

- Check existing issues and PRs
- Read the [implementation plan]docs/planning/IMPLEMENTATION_PLAN.md
- Ask questions in issues
- Review test examples in the codebase

## License

By contributing, you agree that your contributions will be licensed under the Apache License 2.0.