From 0c07fdafe9919985c0e08a0e453c4d92c31cc419 Mon Sep 17 00:00:00 2001 From: Steven Zimmerman Date: Sun, 29 Mar 2026 15:42:57 -0400 Subject: [PATCH 1/9] ci: fix deprecation workflow and CI detection tests --- .github/workflows/deprecation.yml | 60 +++++++++++++- .../tests/annotation_format_tests.rs | 80 +++++++++++++++---- 2 files changed, 123 insertions(+), 17 deletions(-) diff --git a/.github/workflows/deprecation.yml b/.github/workflows/deprecation.yml index 057ae41..54b0a00 100644 --- a/.github/workflows/deprecation.yml +++ b/.github/workflows/deprecation.yml @@ -18,12 +18,56 @@ jobs: - name: Build deprecated crates run: | echo "Building all deprecated facade crates..." - cargo build -p lintdiff-domain -p lintdiff-core -p lintdiff-ingest + deprecated_crates=() + if [ -d "${{ github.workspace }}/crates/lintdiff-domain" ]; then + deprecated_crates+=("lintdiff-domain") + else + echo "✅ Skipping lintdiff-domain (already removed)" + fi + if [ -d "${{ github.workspace }}/crates/lintdiff-core" ]; then + deprecated_crates+=("lintdiff-core") + else + echo "✅ Skipping lintdiff-core (already removed)" + fi + if [ -d "${{ github.workspace }}/crates/lintdiff-ingest" ]; then + deprecated_crates+=("lintdiff-ingest") + else + echo "✅ Skipping lintdiff-ingest (already removed)" + fi + + if [ ${#deprecated_crates[@]} -eq 0 ]; then + echo "✅ No deprecated facade crates found; skipping build." + exit 0 + fi + + cargo build ${deprecated_crates[@]/#/ -p } - name: Check deprecated crates compile without errors run: | echo "Checking deprecated crates compile successfully..." - cargo check -p lintdiff-domain -p lintdiff-core -p lintdiff-ingest + deprecated_crates=() + if [ -d "${{ github.workspace }}/crates/lintdiff-domain" ]; then + deprecated_crates+=("lintdiff-domain") + else + echo "✅ Skipping lintdiff-domain (already removed)" + fi + if [ -d "${{ github.workspace }}/crates/lintdiff-core" ]; then + deprecated_crates+=("lintdiff-core") + else + echo "✅ Skipping lintdiff-core (already removed)" + fi + if [ -d "${{ github.workspace }}/crates/lintdiff-ingest" ]; then + deprecated_crates+=("lintdiff-ingest") + else + echo "✅ Skipping lintdiff-ingest (already removed)" + fi + + if [ ${#deprecated_crates[@]} -eq 0 ]; then + echo "✅ No deprecated facade crates found; skipping checks." + exit 0 + fi + + cargo check ${deprecated_crates[@]/#/ -p } # Job 2: Verify deprecation warnings are emitted verify-warnings: @@ -35,6 +79,10 @@ jobs: - name: Check deprecation warnings in lintdiff-domain run: | + if [ ! -d "${{ github.workspace }}/crates/lintdiff-domain" ]; then + echo "✅ Skipping lintdiff-domain (already removed)" + exit 0 + fi echo "Checking that lintdiff-domain emits deprecation warning..." # Create a temporary test file that uses the deprecated crate mkdir -p /tmp/deptest/src @@ -66,6 +114,10 @@ jobs: - name: Check deprecation warnings in lintdiff-core run: | + if [ ! -d "${{ github.workspace }}/crates/lintdiff-core" ]; then + echo "✅ Skipping lintdiff-core (already removed)" + exit 0 + fi echo "Checking that lintdiff-core emits deprecation warning..." mkdir -p /tmp/deptest-core cat > /tmp/deptest-core/Cargo.toml << 'EOF' @@ -96,6 +148,10 @@ jobs: - name: Check deprecation warnings in lintdiff-ingest run: | + if [ ! -d "${{ github.workspace }}/crates/lintdiff-ingest" ]; then + echo "✅ Skipping lintdiff-ingest (already removed)" + exit 0 + fi echo "Checking that lintdiff-ingest emits deprecation warning..." mkdir -p /tmp/deptest-ingest cat > /tmp/deptest-ingest/Cargo.toml << 'EOF' diff --git a/crates/lintdiff-annotation-format/tests/annotation_format_tests.rs b/crates/lintdiff-annotation-format/tests/annotation_format_tests.rs index 7e81223..f49a37f 100644 --- a/crates/lintdiff-annotation-format/tests/annotation_format_tests.rs +++ b/crates/lintdiff-annotation-format/tests/annotation_format_tests.rs @@ -262,37 +262,87 @@ mod ci_platform_detection { #[test] fn detects_gitlab_ci_when_set() { - temp_env::with_var("GITLAB_CI", Some("true"), || { - assert_eq!(detect_ci(), CiPlatform::GitLabCI); - }); + temp_env::with_vars( + [ + ("GITHUB_ACTIONS", None::<&str>), + ("GITLAB_CI", Some("true")), + ("TF_BUILD", None::<&str>), + ("CIRCLECI", None::<&str>), + ("TRAVIS", None::<&str>), + ("JENKINS_URL", None::<&str>), + ], + || { + assert_eq!(detect_ci(), CiPlatform::GitLabCI); + }, + ); } #[test] fn detects_azure_devops_when_set() { - temp_env::with_var("TF_BUILD", Some("True"), || { - assert_eq!(detect_ci(), CiPlatform::AzureDevOps); - }); + temp_env::with_vars( + [ + ("GITHUB_ACTIONS", None::<&str>), + ("GITLAB_CI", None::<&str>), + ("TF_BUILD", Some("True")), + ("CIRCLECI", None::<&str>), + ("TRAVIS", None::<&str>), + ("JENKINS_URL", None::<&str>), + ], + || { + assert_eq!(detect_ci(), CiPlatform::AzureDevOps); + }, + ); } #[test] fn detects_circleci_when_set() { - temp_env::with_var("CIRCLECI", Some("true"), || { - assert_eq!(detect_ci(), CiPlatform::CircleCI); - }); + temp_env::with_vars( + [ + ("GITHUB_ACTIONS", None::<&str>), + ("GITLAB_CI", None::<&str>), + ("TF_BUILD", None::<&str>), + ("CIRCLECI", Some("true")), + ("TRAVIS", None::<&str>), + ("JENKINS_URL", None::<&str>), + ], + || { + assert_eq!(detect_ci(), CiPlatform::CircleCI); + }, + ); } #[test] fn detects_travis_ci_when_set() { - temp_env::with_var("TRAVIS", Some("true"), || { - assert_eq!(detect_ci(), CiPlatform::TravisCI); - }); + temp_env::with_vars( + [ + ("GITHUB_ACTIONS", None::<&str>), + ("GITLAB_CI", None::<&str>), + ("TF_BUILD", None::<&str>), + ("CIRCLECI", None::<&str>), + ("TRAVIS", Some("true")), + ("JENKINS_URL", None::<&str>), + ], + || { + assert_eq!(detect_ci(), CiPlatform::TravisCI); + }, + ); } #[test] fn detects_jenkins_when_set() { - temp_env::with_var("JENKINS_URL", Some("http://jenkins:8080"), || { - assert_eq!(detect_ci(), CiPlatform::Jenkins); - }); + temp_env::with_vars( + [ + ("GITHUB_ACTIONS", None::<&str>), + ("GITLAB_CI", None::<&str>), + ("TF_BUILD", None::<&str>), + ("CIRCLECI", None::<&str>), + ("TRAVIS", None::<&str>), + ("JENKINS_URL", Some("http://jenkins:8080")), + ], + || { + assert_eq!(detect_ci(), CiPlatform::Jenkins); + }, + ); } #[test] From 80e9004df324bd558f1da920caab6ebc186a7de6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2026 19:24:41 +0000 Subject: [PATCH 2/9] ci(deps): bump the actions group with 6 updates Bumps the actions group with 6 updates: | Package | From | To | | --- | --- | --- | | [actions/upload-artifact](https://github.com/actions/upload-artifact) | `4` | `7` | | [actions/checkout](https://github.com/actions/checkout) | `4` | `6` | | [codecov/codecov-action](https://github.com/codecov/codecov-action) | `4` | `6` | | [actions/cache](https://github.com/actions/cache) | `4` | `5` | | [actions/download-artifact](https://github.com/actions/download-artifact) | `4` | `8` | | [actions/github-script](https://github.com/actions/github-script) | `7` | `8` | Updates `actions/upload-artifact` from 4 to 7 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v7) Updates `actions/checkout` from 4 to 6 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) Updates `codecov/codecov-action` from 4 to 6 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v4...v6) Updates `actions/cache` from 4 to 5 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v4...v5) Updates `actions/download-artifact` from 4 to 8 - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v4...v8) Updates `actions/github-script` from 7 to 8 - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions - dependency-name: codecov/codecov-action dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions - dependency-name: actions/cache dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions - dependency-name: actions/download-artifact dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions - dependency-name: actions/github-script dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions ... Signed-off-by: dependabot[bot] --- .github/workflows/bench.yml | 4 ++-- .github/workflows/ci.yml | 6 +++--- .github/workflows/coverage.yml | 4 ++-- .github/workflows/deny.yml | 2 +- .github/workflows/deprecation.yml | 6 +++--- .github/workflows/fuzz.yml | 14 +++++++------- .github/workflows/mutation.yml | 8 ++++---- .github/workflows/release.yml | 16 ++++++++-------- .github/workflows/semver.yml | 2 +- action.yml | 2 +- 10 files changed, 32 insertions(+), 32 deletions(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index b29a502..d5fdd24 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -14,12 +14,12 @@ jobs: bench: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: Swatinem/rust-cache@v2 - name: Run benchmarks run: cargo bench --workspace - name: Upload results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: criterion-results path: target/criterion diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf247ae..c8c39a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: Swatinem/rust-cache@v2 - uses: dtolnay/rust-toolchain@stable with: @@ -25,7 +25,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: Swatinem/rust-cache@v2 - uses: dtolnay/rust-toolchain@stable with: @@ -36,7 +36,7 @@ jobs: bdd: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: Swatinem/rust-cache@v2 - uses: dtolnay/rust-toolchain@stable - name: BDD (cucumber) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 10e853f..6a102d7 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -9,14 +9,14 @@ jobs: coverage: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: Swatinem/rust-cache@v2 - name: Install cargo-llvm-cov run: cargo install cargo-llvm-cov - name: Generate coverage run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info - name: Upload to codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v6 with: files: lcov.info fail_ci_if_error: true diff --git a/.github/workflows/deny.yml b/.github/workflows/deny.yml index 7ba2c2d..68058bc 100644 --- a/.github/workflows/deny.yml +++ b/.github/workflows/deny.yml @@ -11,7 +11,7 @@ jobs: deny: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: EmbarkStudios/cargo-deny-action@v2 with: arguments: --all-features diff --git a/.github/workflows/deprecation.yml b/.github/workflows/deprecation.yml index 54b0a00..3a05f6d 100644 --- a/.github/workflows/deprecation.yml +++ b/.github/workflows/deprecation.yml @@ -11,7 +11,7 @@ jobs: build-deprecated: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: Swatinem/rust-cache@v2 - uses: dtolnay/rust-toolchain@stable @@ -73,7 +73,7 @@ jobs: verify-warnings: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: Swatinem/rust-cache@v2 - uses: dtolnay/rust-toolchain@stable @@ -184,7 +184,7 @@ jobs: report-consumers: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: Swatinem/rust-cache@v2 - uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 2bc752d..8f0337a 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -55,7 +55,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Rust nightly uses: dtolnay/rust-toolchain@nightly @@ -63,7 +63,7 @@ jobs: components: rust-src - name: Cache cargo registry - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.cargo/registry @@ -74,7 +74,7 @@ jobs: ${{ runner.os }}-cargo- - name: Cache fuzz corpus - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | fuzz/corpus @@ -194,7 +194,7 @@ jobs: steps.check-target.outputs.exists == 'true' && steps.should-run.outputs.run == 'true' && steps.fuzz.outputs.crashed == 'true' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: crash-${{ matrix.target }}-${{ github.run_id }} path: | @@ -207,7 +207,7 @@ jobs: steps.check-target.outputs.exists == 'true' && steps.should-run.outputs.run == 'true' && always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: corpus-${{ matrix.target }}-${{ github.run_id }} path: fuzz/corpus/${{ matrix.target }} @@ -255,7 +255,7 @@ jobs: fi - name: Download all artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: pattern: 'crash-*' path: crashes @@ -287,7 +287,7 @@ jobs: - name: Create issue on crash if: steps.check-crashes.outputs.crashes_found == 'true' && github.event_name == 'schedule' - uses: actions/github-script@v7 + uses: actions/github-script@v8 with: script: | const title = `🐛 Fuzzing Crash Detected (Run #${{ github.run_number }})`; diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 20921bc..271c3fd 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -52,14 +52,14 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Rust stable uses: dtolnay/rust-toolchain@stable # Cache cargo registry and build artifacts for faster runs - name: Cache cargo registry - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.cargo/registry @@ -260,7 +260,7 @@ jobs: # Upload mutation reports as artifacts - name: Upload mutation reports - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: mutation-reports path: mutants-out/ @@ -269,7 +269,7 @@ jobs: # Create GitHub issue if mutation score drops below threshold - name: Create issue for low mutation score if: steps.aggregate.outputs.overall_score < env.MUTATION_THRESHOLD && github.event_name == 'schedule' - uses: actions/github-script@v7 + uses: actions/github-script@v8 with: script: | const score = '${{ steps.aggregate.outputs.overall_score }}'; diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8fba98d..fe50d7a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -64,7 +64,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup Rust toolchain uses: dtolnay/rust-toolchain@stable @@ -72,7 +72,7 @@ jobs: targets: ${{ matrix.target }} - name: Cache cargo registry - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.cargo/registry @@ -82,7 +82,7 @@ jobs: ${{ runner.os }}-cargo- - name: Cache target directory - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: target key: ${{ runner.os }}-${{ matrix.target }}-target-${{ hashFiles('**/Cargo.lock') }} @@ -122,7 +122,7 @@ jobs: cd ../../.. sha256sum lintdiff-${{ needs.prepare.outputs.version }}-${{ matrix.target }}.zip > lintdiff-${{ needs.prepare.outputs.version }}-${{ matrix.target }}.zip.sha256 - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: lintdiff-${{ matrix.target }} path: | @@ -132,7 +132,7 @@ jobs: needs: [prepare, build] runs-on: ubuntu-latest steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: merge-multiple: true @@ -142,7 +142,7 @@ jobs: echo "Checksums:" cat checksums-${{ needs.prepare.outputs.version }}.txt - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: checksums path: checksums-${{ needs.prepare.outputs.version }}.txt @@ -151,11 +151,11 @@ jobs: needs: [prepare, build, checksums] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 0 - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: merge-multiple: true diff --git a/.github/workflows/semver.yml b/.github/workflows/semver.yml index 87ebaac..bb2d0be 100644 --- a/.github/workflows/semver.yml +++ b/.github/workflows/semver.yml @@ -13,7 +13,7 @@ jobs: semver: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 0 # Need full history for baseline comparison - uses: Swatinem/rust-cache@v2 diff --git a/action.yml b/action.yml index c780edd..7a7916d 100644 --- a/action.yml +++ b/action.yml @@ -175,7 +175,7 @@ runs: - name: Upload report artifact if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: lintdiff-report path: ${{ inputs.working_directory }}/artifacts/lintdiff/ From a3af65c92af0fb911a905f5e512723dab971b62d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2026 19:26:45 +0000 Subject: [PATCH 3/9] deps(deps): bump the dependencies group with 11 updates Bumps the dependencies group with 11 updates: | Package | From | To | | --- | --- | --- | | [criterion](https://github.com/criterion-rs/criterion.rs) | `0.5.1` | `0.8.2` | | [thiserror](https://github.com/dtolnay/thiserror) | `1.0.69` | `2.0.18` | | [clap](https://github.com/clap-rs/clap) | `4.5.56` | `4.5.60` | | [toml](https://github.com/toml-rs/toml) | `0.8.23` | `1.1.0+spec-1.1.0` | | [sha2](https://github.com/RustCrypto/hashes) | `0.10.9` | `0.11.0` | | [uselesskey](https://github.com/EffortlessMetrics/uselesskey) | `0.2.0` | `0.5.1` | | [tempfile](https://github.com/Stebalien/tempfile) | `3.26.0` | `3.27.0` | | [proptest](https://github.com/proptest-rs/proptest) | `1.9.0` | `1.11.0` | | [jsonschema](https://github.com/Stranger6667/jsonschema) | `0.28.3` | `0.45.0` | | [tokio](https://github.com/tokio-rs/tokio) | `1.49.0` | `1.50.0` | | [regex](https://github.com/rust-lang/regex) | `1.12.2` | `1.12.3` | Updates `criterion` from 0.5.1 to 0.8.2 - [Release notes](https://github.com/criterion-rs/criterion.rs/releases) - [Changelog](https://github.com/criterion-rs/criterion.rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/criterion-rs/criterion.rs/compare/0.5.1...criterion-v0.8.2) Updates `thiserror` from 1.0.69 to 2.0.18 - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.69...2.0.18) Updates `clap` from 4.5.56 to 4.5.60 - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.56...clap_complete-v4.5.60) Updates `toml` from 0.8.23 to 1.1.0+spec-1.1.0 - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.23...toml-v1.1.0) Updates `sha2` from 0.10.9 to 0.11.0 - [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.10.9...sha2-v0.11.0) Updates `uselesskey` from 0.2.0 to 0.5.1 - [Release notes](https://github.com/EffortlessMetrics/uselesskey/releases) - [Changelog](https://github.com/EffortlessMetrics/uselesskey/blob/main/CHANGELOG.md) - [Commits](https://github.com/EffortlessMetrics/uselesskey/compare/v0.2.0...v0.5.1) Updates `tempfile` from 3.26.0 to 3.27.0 - [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md) - [Commits](https://github.com/Stebalien/tempfile/compare/v3.26.0...v3.27.0) Updates `proptest` from 1.9.0 to 1.11.0 - [Release notes](https://github.com/proptest-rs/proptest/releases) - [Changelog](https://github.com/proptest-rs/proptest/blob/main/CHANGELOG.md) - [Commits](https://github.com/proptest-rs/proptest/compare/v1.9.0...v1.11.0) Updates `jsonschema` from 0.28.3 to 0.45.0 - [Release notes](https://github.com/Stranger6667/jsonschema/releases) - [Changelog](https://github.com/Stranger6667/jsonschema/blob/master/CHANGELOG.md) - [Commits](https://github.com/Stranger6667/jsonschema/compare/rust-v0.28.3...ruby-v0.45.0) Updates `tokio` from 1.49.0 to 1.50.0 - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.49.0...tokio-1.50.0) Updates `regex` from 1.12.2 to 1.12.3 - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.12.2...1.12.3) --- updated-dependencies: - dependency-name: criterion dependency-version: 0.8.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: thiserror dependency-version: 2.0.18 dependency-type: direct:production update-type: version-update:semver-major dependency-group: dependencies - dependency-name: clap dependency-version: 4.5.60 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dependencies - dependency-name: toml dependency-version: 1.1.0+spec-1.1.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: dependencies - dependency-name: sha2 dependency-version: 0.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: uselesskey dependency-version: 0.5.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: tempfile dependency-version: 3.27.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: proptest dependency-version: 1.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: jsonschema dependency-version: 0.45.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: tokio dependency-version: 1.50.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: regex dependency-version: 1.12.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dependencies ... Signed-off-by: dependabot[bot] --- Cargo.lock | 1526 +++++++++++++++++++++++------- Cargo.toml | 10 +- crates/lintdiff-types/Cargo.toml | 2 +- 3 files changed, 1187 insertions(+), 351 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c203119..9dddea6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,6 +25,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloca" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" +dependencies = [ + "cc", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "anes" version = "0.1.6" @@ -150,11 +165,33 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "aws-lc-rs" +version = "1.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "base16ct" -version = "0.2.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" [[package]] name = "base64" @@ -185,9 +222,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "blake3" @@ -200,7 +237,7 @@ dependencies = [ "cc", "cfg-if", "constant_time_eq", - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] @@ -212,6 +249,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + [[package]] name = "borrow-or-share" version = "0.2.4" @@ -259,9 +305,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "1.0.4" @@ -297,9 +351,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.56" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" dependencies = [ "clap_builder", "clap_derive", @@ -307,9 +361,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.56" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" dependencies = [ "anstream", "anstyle", @@ -332,9 +386,24 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.7" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "cmov" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +checksum = "de0758edba32d61d1fd9f4d69491b47604b91ee2f7e6b33de7e54ca4ebe55dc3" [[package]] name = "colorchoice" @@ -342,6 +411,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "console" version = "0.16.2" @@ -361,6 +440,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "constant_time_eq" version = "0.4.2" @@ -376,6 +461,28 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpubits" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef0c543070d296ea414df2dd7625d1b24866ce206709d8a4a424f28377f5861" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -385,27 +492,35 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "criterion" -version = "0.5.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" dependencies = [ + "alloca", "anes", "cast", "ciborium", "clap", "criterion-plot", - "is-terminal", - "itertools 0.10.5", + "itertools 0.13.0", "num-traits", - "once_cell", "oorandom", + "page_size", "plotters", "rayon", "regex", "serde", - "serde_derive", "serde_json", "tinytemplate", "walkdir", @@ -413,12 +528,12 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.5.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" dependencies = [ "cast", - "itertools 0.10.5", + "itertools 0.13.0", ] [[package]] @@ -454,12 +569,17 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-bigint" -version = "0.5.5" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +checksum = "42a0d26b245348befa0c121944541476763dcc46ede886c88f9d12e1697d27c3" dependencies = [ - "generic-array", - "rand_core 0.6.4", + "cpubits", + "ctutils", + "getrandom 0.4.2", + "hybrid-array", + "num-traits", + "rand_core 0.10.0", + "serdect", "subtle", "zeroize", ] @@ -474,6 +594,38 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "getrandom 0.4.2", + "hybrid-array", + "rand_core 0.10.0", +] + +[[package]] +name = "crypto-primes" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21f41f23de7d24cdbda7f0c4d9c0351f99a4ceb258ef30e5c1927af8987ffe5a" +dependencies = [ + "crypto-bigint", + "libm", + "rand_core 0.10.0", +] + +[[package]] +name = "ctutils" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1005a6d4446f5120ef475ad3d2af2b30c49c2c9c6904258e3bb30219bebed5e4" +dependencies = [ + "cmov", + "subtle", +] + [[package]] name = "cucumber" version = "0.22.1" @@ -538,10 +690,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "curve25519-dalek-derive", - "digest", - "fiat-crypto", + "digest 0.10.7", + "fiat-crypto 0.2.9", "rustc_version", "subtle", "zeroize", @@ -584,8 +736,19 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", - "pem-rfc7468", + "const-oid 0.9.6", + "pem-rfc7468 0.7.0", + "zeroize", +] + +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "const-oid 0.10.2", + "pem-rfc7468 1.0.0", "zeroize", ] @@ -642,10 +805,21 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +dependencies = [ + "block-buffer 0.12.0", + "const-oid 0.10.2", + "crypto-common 0.2.1", + "ctutils", ] [[package]] @@ -659,18 +833,25 @@ dependencies = [ "syn", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "ecdsa" -version = "0.16.9" +version = "0.17.0-rc.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +checksum = "91bbdd377139884fafcad8dc43a760a3e1e681aa26db910257fa6535b70e1829" dependencies = [ - "der", - "digest", + "der 0.8.0", + "digest 0.11.2", "elliptic-curve", "rfc6979", - "signature", - "spki", + "signature 3.0.0-rc.10", + "spki 0.8.0-rc.4", + "zeroize", ] [[package]] @@ -679,8 +860,8 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "pkcs8", - "signature", + "pkcs8 0.10.2", + "signature 2.2.0", ] [[package]] @@ -693,7 +874,7 @@ dependencies = [ "ed25519", "rand_core 0.6.4", "serde", - "sha2", + "sha2 0.10.9", "subtle", "zeroize", ] @@ -706,20 +887,21 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "elliptic-curve" -version = "0.13.8" +version = "0.14.0-rc.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +checksum = "e84043d573efd4ac9d2d125817979a379204bf7e328b25a4a30487e8d100e618" dependencies = [ "base16ct", "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "hkdf", - "pem-rfc7468", - "pkcs8", - "rand_core 0.6.4", + "crypto-common 0.2.1", + "digest 0.11.2", + "hybrid-array", + "once_cell", + "pem-rfc7468 1.0.0", + "pkcs8 0.11.0-rc.11", + "rand_core 0.10.0", + "rustcrypto-ff", + "rustcrypto-group", "sec1", "subtle", "zeroize", @@ -758,9 +940,9 @@ dependencies = [ [[package]] name = "fancy-regex" -version = "0.14.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298" +checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8" dependencies = [ "bit-set", "regex-automata", @@ -774,20 +956,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "ff" -version = "0.13.1" +name = "fiat-crypto" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "fiat-crypto" -version = "0.2.9" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" [[package]] name = "find-msvc-tools" @@ -842,9 +1020,9 @@ dependencies = [ [[package]] name = "fluent-uri" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1918b65d96df47d3591bed19c5cca17e3fa5d0707318e4b5ef2eae01764df7e5" +checksum = "bc74ac4d8359ae70623506d512209619e5cf8f347124910440dbc221714b328e" dependencies = [ "borrow-or-share", "ref-cast", @@ -857,6 +1035,18 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -876,6 +1066,12 @@ dependencies = [ "num", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures" version = "0.3.31" @@ -973,7 +1169,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", - "zeroize", ] [[package]] @@ -992,11 +1187,27 @@ name = "getrandom" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 6.0.0", + "rand_core 0.10.0", "wasip2", + "wasip3", ] [[package]] @@ -1041,14 +1252,22 @@ dependencies = [ ] [[package]] -name = "group" -version = "0.13.0" +name = "h2" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] @@ -1068,11 +1287,25 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "heck" @@ -1080,34 +1313,19 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - [[package]] name = "hmac" -version = "0.12.1" +version = "0.13.0-rc.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "60017b071c523c9e5a55dd1253582bff6150c5e96a7e8511e419de1ab5ee97f9" dependencies = [ - "digest", + "digest 0.11.2", ] [[package]] @@ -1155,6 +1373,17 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" +[[package]] +name = "hybrid-array" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8655f91cd07f2b9d0c24137bd650fe69617773435ee5ec83022377777ce65ef1" +dependencies = [ + "subtle", + "typenum", + "zeroize", +] + [[package]] name = "hyper" version = "1.8.1" @@ -1165,6 +1394,7 @@ dependencies = [ "bytes", "futures-channel", "futures-core", + "h2", "http", "http-body", "httparse", @@ -1176,6 +1406,22 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.19" @@ -1281,6 +1527,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "idna" version = "1.1.0" @@ -1326,6 +1578,8 @@ checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] @@ -1378,17 +1632,6 @@ dependencies = [ "serde", ] -[[package]] -name = "is-terminal" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.61.2", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -1397,9 +1640,9 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" -version = "0.10.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -1420,37 +1663,95 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] -name = "js-sys" -version = "0.3.85" +name = "jni" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ - "once_cell", - "wasm-bindgen", + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", ] [[package]] -name = "jsonschema" -version = "0.28.3" +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonschema" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f66fe41fa46a5c83ed1c717b7e0b4635988f427083108c8cf0a882cc13441" +checksum = "6f29616f6e19415398eb186964fb7cbbeef572c79bede3622a8277667924bbe3" dependencies = [ "ahash", - "base64", "bytecount", + "data-encoding", "email_address", "fancy-regex", "fraction", + "getrandom 0.3.4", "idna", "itoa", "num-cmp", - "once_cell", + "num-traits", "percent-encoding", "referencing", + "regex", "regex-syntax", "reqwest", + "rustls", "serde", "serde_json", + "unicode-general-category", "uuid-simd", ] @@ -1460,9 +1761,15 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin", + "spin 0.9.8", ] +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" version = "0.2.183" @@ -1507,7 +1814,7 @@ dependencies = [ "proptest", "serde", "temp-env", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1522,7 +1829,7 @@ dependencies = [ "lintdiff-render", "lintdiff-types", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1531,7 +1838,7 @@ version = "0.1.0" dependencies = [ "lintdiff-types", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1542,7 +1849,7 @@ dependencies = [ "lintdiff-types", "serde_json", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.18", "time", "toml", ] @@ -1602,7 +1909,7 @@ dependencies = [ "serde", "serde_json", "temp-env", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1611,7 +1918,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1621,7 +1928,7 @@ dependencies = [ "lintdiff-glob", "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1629,7 +1936,7 @@ name = "lintdiff-code-url" version = "0.1.0" dependencies = [ "proptest", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1639,7 +1946,7 @@ dependencies = [ "serde", "serde_json", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.18", "toml", ] @@ -1649,7 +1956,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1658,7 +1965,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1677,7 +1984,7 @@ dependencies = [ "lintdiff-types", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1686,7 +1993,7 @@ version = "0.1.0" dependencies = [ "lintdiff-types", "proptest", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1695,7 +2002,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1704,7 +2011,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1713,7 +2020,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1751,7 +2058,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1767,7 +2074,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1785,7 +2092,7 @@ dependencies = [ "hex", "lintdiff-types", "proptest", - "sha2", + "sha2 0.11.0", ] [[package]] @@ -1795,7 +2102,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1803,7 +2110,7 @@ name = "lintdiff-glob" version = "0.1.0" dependencies = [ "proptest", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1820,7 +2127,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1829,7 +2136,7 @@ version = "0.1.0" dependencies = [ "fluent", "fluent-bundle", - "thiserror 1.0.69", + "thiserror 2.0.18", "unic-langid", ] @@ -1852,7 +2159,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1880,7 +2187,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1898,7 +2205,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1915,7 +2222,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1965,7 +2272,7 @@ name = "lintdiff-render-utils" version = "0.1.0" dependencies = [ "proptest", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1975,7 +2282,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1985,7 +2292,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1995,7 +2302,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", "time", ] @@ -2013,7 +2320,7 @@ name = "lintdiff-severity" version = "0.1.0" dependencies = [ "proptest", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -2022,7 +2329,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -2039,7 +2346,7 @@ name = "lintdiff-sort" version = "0.1.0" dependencies = [ "proptest", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -2048,7 +2355,7 @@ version = "0.1.0" dependencies = [ "proptest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -2075,7 +2382,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", "time", ] @@ -2090,7 +2397,7 @@ dependencies = [ "jsonschema", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", "time", ] @@ -2100,7 +2407,7 @@ version = "0.1.0" dependencies = [ "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -2110,7 +2417,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -2322,6 +2629,12 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + [[package]] name = "outref" version = "0.5.2" @@ -2330,26 +2643,39 @@ checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] name = "p256" -version = "0.13.2" +version = "0.14.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +checksum = "44f0a10fe314869359cb2901342b045f4e5a962ef9febc006f03d2a8c848fe4c" dependencies = [ "ecdsa", "elliptic-curve", + "primefield", "primeorder", - "sha2", + "sha2 0.11.0", ] [[package]] name = "p384" -version = "0.13.1" +version = "0.14.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +checksum = "b079e66810c55ab3d6ba424e056dc4aefcdb8046c8c3f3816142edbdd7af7721" dependencies = [ "ecdsa", "elliptic-curve", + "fiat-crypto 0.3.0", + "primefield", "primeorder", - "sha2", + "sha2 0.11.0", +] + +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", ] [[package]] @@ -2421,6 +2747,15 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pem-rfc7468" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -2465,9 +2800,19 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der", - "pkcs8", - "spki", + "der 0.7.10", + "pkcs8 0.10.2", + "spki 0.7.3", +] + +[[package]] +name = "pkcs1" +version = "0.8.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088e" +dependencies = [ + "der 0.8.0", + "spki 0.8.0-rc.4", ] [[package]] @@ -2476,8 +2821,18 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der", - "spki", + "der 0.7.10", + "spki 0.7.3", +] + +[[package]] +name = "pkcs8" +version = "0.11.0-rc.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12922b6296c06eb741b02d7b5161e3aaa22864af38dfa025a1a3ba3f68c84577" +dependencies = [ + "der 0.8.0", + "spki 0.8.0-rc.4", ] [[package]] @@ -2532,11 +2887,35 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "primefield" +version = "0.14.0-rc.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6543f5eec854fbf74ba5ef651fbdc9408919b47c3e1526623687135c16d12e9" +dependencies = [ + "crypto-bigint", + "crypto-common 0.2.1", + "rand_core 0.10.0", + "rustcrypto-ff", + "subtle", + "zeroize", +] + [[package]] name = "primeorder" -version = "0.13.6" +version = "0.14.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +checksum = "569d9ad6ef822bb0322c7e7d84e5e286244050bd5246cac4c013535ae91c2c90" dependencies = [ "elliptic-curve", ] @@ -2552,9 +2931,9 @@ dependencies = [ [[package]] name = "proptest" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" dependencies = [ "bit-set", "bit-vec", @@ -2590,6 +2969,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.8.5" @@ -2610,6 +2995,16 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +dependencies = [ + "getrandom 0.4.2", + "rand_core 0.10.0", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -2630,6 +3025,16 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand_chacha" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e6af7f3e25ded52c41df4e0b1af2d047e45896c2f3281792ed68a1c243daedb" +dependencies = [ + "ppv-lite86", + "rand_core 0.10.0", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -2648,6 +3053,12 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + [[package]] name = "rand_xorshift" version = "0.4.0" @@ -2679,14 +3090,15 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.13.2" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +checksum = "10b99e0098aa4082912d4c649628623db6aba77335e4f4569ff5083a6448b32e" dependencies = [ "pem", "ring", "rustls-pki-types", "time", + "x509-parser", "yasna", ] @@ -2721,22 +3133,24 @@ dependencies = [ [[package]] name = "referencing" -version = "0.28.3" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0dcb5ab28989ad7c91eb1b9531a37a1a137cc69a0499aee4117cae4a107c464" +checksum = "b8a618c14f8ba29d8193bb55e2bf13e4fb2b1115313ecb7ae94b43100c7ac7d5" dependencies = [ "ahash", "fluent-uri", - "once_cell", + "getrandom 0.3.4", + "hashbrown 0.16.1", + "parking_lot", "percent-encoding", "serde_json", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -2763,29 +3177,34 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" -version = "0.12.28" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ "base64", "bytes", "futures-channel", "futures-core", "futures-util", + "h2", "http", "http-body", "http-body-util", "hyper", + "hyper-rustls", "hyper-util", "js-sys", "log", "percent-encoding", "pin-project-lite", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", - "serde_urlencoded", "sync_wrapper", "tokio", + "tokio-rustls", "tower", "tower-http", "tower-service", @@ -2797,9 +3216,9 @@ dependencies = [ [[package]] name = "rfc6979" -version = "0.4.0" +version = "0.5.0-rc.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +checksum = "23a3127ee32baec36af75b4107082d9bd823501ec14a4e016be4b6b37faa74ae" dependencies = [ "hmac", "subtle", @@ -2825,20 +3244,39 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ - "const-oid", - "digest", + "const-oid 0.9.6", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", - "pkcs1", - "pkcs8", + "pkcs1 0.7.5", + "pkcs8 0.10.2", "rand_core 0.6.4", - "signature", - "spki", + "signature 2.2.0", + "spki 0.7.3", "subtle", "zeroize", ] +[[package]] +name = "rsa" +version = "0.10.0-rc.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ed3e93fc7e473e464b9726f4759659e72bc8665e4b8ea227547024f416d905" +dependencies = [ + "const-oid 0.10.2", + "crypto-bigint", + "crypto-primes", + "digest 0.11.2", + "pkcs1 0.8.0-rc.4", + "pkcs8 0.11.0-rc.11", + "rand_core 0.10.0", + "sha2 0.11.0", + "signature 3.0.0-rc.10", + "spki 0.8.0-rc.4", + "zeroize", +] + [[package]] name = "rustc-hash" version = "2.1.1" @@ -2854,6 +3292,27 @@ dependencies = [ "semver", ] +[[package]] +name = "rustcrypto-ff" +version = "0.14.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5db129183b2c139d7d87d08be57cba626c715789db17aec65c8866bfd767d1f" +dependencies = [ + "rand_core 0.10.0", + "subtle", +] + +[[package]] +name = "rustcrypto-group" +version = "0.14.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c4b1463f274a3ff6fb2f44da43e576cb9424367bd96f185ead87b52fe00523" +dependencies = [ + "rand_core 0.10.0", + "rustcrypto-ff", + "subtle", +] + [[package]] name = "rusticata-macros" version = "4.1.0" @@ -2877,47 +3336,115 @@ dependencies = [ ] [[package]] -name = "rustls-pki-types" -version = "1.14.0" +name = "rustls" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", "zeroize", ] [[package]] -name = "rustversion" -version = "1.0.22" +name = "rustls-native-certs" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] [[package]] -name = "rusty-fork" -version = "0.3.1" +name = "rustls-pki-types" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ - "fnv", - "quick-error", - "tempfile", - "wait-timeout", + "zeroize", ] [[package]] -name = "ryu" -version = "1.0.22" +name = "rustls-platform-verifier" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" - -[[package]] -name = "same-file" -version = "1.0.6" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "rusty-fork" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2937,18 +3464,41 @@ dependencies = [ [[package]] name = "sec1" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +checksum = "f46b9a5ab87780a3189a1d704766579517a04ad59de653b7aad7d38e8a15f7dc" dependencies = [ "base16ct", - "der", - "generic-array", - "pkcs8", + "ctutils", + "der 0.8.0", + "hybrid-array", "subtle", "zeroize", ] +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "self_cell" version = "1.2.2" @@ -3006,22 +3556,20 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.9" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98" dependencies = [ - "serde", + "serde_core", ] [[package]] -name = "serde_urlencoded" -version = "0.7.1" +name = "serdect" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +checksum = "9af4a3e75ebd5599b30d4de5768e00b5095d518a79fefc3ecbaf77e665d1ec06" dependencies = [ - "form_urlencoded", - "itoa", - "ryu", + "base16ct", "serde", ] @@ -3032,8 +3580,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.2", ] [[package]] @@ -3048,10 +3607,20 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] +[[package]] +name = "signature" +version = "3.0.0-rc.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f1880df446116126965eeec169136b2e0251dba37c6223bcc819569550edea3" +dependencies = [ + "digest 0.11.2", + "rand_core 0.10.0", +] + [[package]] name = "slab" version = "0.4.12" @@ -3097,6 +3666,12 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" + [[package]] name = "spki" version = "0.7.3" @@ -3104,7 +3679,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der", + "der 0.7.10", +] + +[[package]] +name = "spki" +version = "0.8.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8baeff88f34ed0691978ec34440140e1572b68c7dd4a495fd14a3dc1944daa80" +dependencies = [ + "base64ct", + "der 0.8.0", ] [[package]] @@ -3209,12 +3794,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.26.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.2", "once_cell", "rustix", "windows-sys 0.61.2", @@ -3335,10 +3920,11 @@ dependencies = [ [[package]] name = "tokio" -version = "1.49.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ + "bytes", "libc", "mio", "pin-project-lite", @@ -3358,46 +3944,67 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" -version = "0.8.23" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc" dependencies = [ - "serde", + "indexmap", + "serde_core", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_parser", + "toml_writer", + "winnow", ] [[package]] name = "toml_datetime" -version = "0.6.11" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" dependencies = [ - "serde", + "serde_core", ] [[package]] -name = "toml_edit" -version = "0.22.27" +name = "toml_parser" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_write", "winnow", ] [[package]] -name = "toml_write" -version = "0.1.2" +name = "toml_writer" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" [[package]] name = "tower" @@ -3528,6 +4135,12 @@ dependencies = [ "tinystr", ] +[[package]] +name = "unicode-general-category" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b993bddc193ae5bd0d623b49ec06ac3e9312875fdae725a975c51db1cc1677f" + [[package]] name = "unicode-ident" version = "1.0.22" @@ -3578,9 +4191,9 @@ dependencies = [ [[package]] name = "uselesskey" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b699dcd2fe0ab8ee5b415da7b8eb9fb27f9f31d89c6349ea4ac26ce82b5e8f" +checksum = "85cb7c9ebbc99ebeeb242466b1f5b65ce18314fa65124116ae30abf6792da86f" dependencies = [ "uselesskey-core", "uselesskey-ecdsa", @@ -3594,11 +4207,10 @@ dependencies = [ [[package]] name = "uselesskey-core" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61a36f8ac29336006b4ca03f78f12e34e43964a0bd9d1ff334b42675cd74aed" +checksum = "aa6972fd4eace29958c694b1a674484efd61e161780ba512d3187366afa3391f" dependencies = [ - "rand_chacha 0.3.1", "thiserror 2.0.18", "uselesskey-core-cache", "uselesskey-core-factory", @@ -3609,56 +4221,57 @@ dependencies = [ [[package]] name = "uselesskey-core-base62" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9d98f9dcaa04ef5b5454e3acbe9a127ca32bb6920814edf6dab3d3f3d595e6" +checksum = "6df7fbeea26d8a864ff26f26a495e573d341c07020d66fd98d9c1277cb16a555" dependencies = [ - "rand_core 0.6.4", + "rand_chacha 0.10.0", + "rand_core 0.10.0", + "uselesskey-core-seed", ] [[package]] name = "uselesskey-core-cache" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fe24e6fffaa91e0467d19e49749810942341a973870a16409128c28c8772540" +checksum = "70b7fb00acbeb3c5494f6ffe3b7a6a01202b851cc651842dc1e2f382b47a0606" dependencies = [ "dashmap", - "spin", + "spin 0.10.0", "uselesskey-core-id", ] [[package]] name = "uselesskey-core-factory" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4773ce6e936d7a8030cc7a5dce244a6716feaac6c285abacf9624772e239eca9" +checksum = "2bf46a46655ddc51eed1c165cd69357f6fd5af027536de050d45c8d53b248a6c" dependencies = [ - "rand_chacha 0.3.1", - "rand_core 0.6.4", + "rand 0.10.0", "uselesskey-core-cache", "uselesskey-core-id", ] [[package]] name = "uselesskey-core-hash" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a033348427ea4ef1bccdffd0e82d37d838a39d0bfc21d17796ed2f8bee55d9d" +checksum = "e481e13c5ae0dafd07f1f1ed0a6a91abccc64f7baf6905737a52f17928956b78" dependencies = [ "blake3", ] [[package]] name = "uselesskey-core-hmac-spec" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6ff4c0724e3c445014222e47078b033c72c1a37b1265f17f2c246b4f2f577f" +checksum = "77c943c6343e0606f6c22a311e83ae9d4ed5bfa84ec0ab42cdea010be9d78a85" [[package]] name = "uselesskey-core-id" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87a3fdc12173dab526dff81813cfabe2b0c5b565660306dc4485592a55b4aae" +checksum = "6de7ab748e8513664720a90a1f96f354ff52ae10cab703c85d55ef106944f8c2" dependencies = [ "uselesskey-core-hash", "uselesskey-core-seed", @@ -3666,9 +4279,9 @@ dependencies = [ [[package]] name = "uselesskey-core-jwk" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e477c5baebd0ff4211e519a2cd5ff7d68ba33456ba1a642225ac5850bf6841d" +checksum = "806ed9f67d074e2b22bfb72d13ea67a894e0657cbb0a2cda62904715081e704b" dependencies = [ "uselesskey-core-jwk-builder", "uselesskey-core-jwk-shape", @@ -3676,9 +4289,9 @@ dependencies = [ [[package]] name = "uselesskey-core-jwk-builder" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17064dd1aaed3b96eda6c8bb1fc601c5064905b747a0bca162601c05c511eed3" +checksum = "2ded0b9720985f21a5f7d18e189b9503e32e4fe268e093ab3d98916323857e54" dependencies = [ "serde_json", "uselesskey-core-jwk-shape", @@ -3687,9 +4300,9 @@ dependencies = [ [[package]] name = "uselesskey-core-jwk-shape" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "550655ae663ba809ebe2622e42c4c9c5d10d1be24d46a166d7edae7f8349be82" +checksum = "aab164de44609506d89da8bcf59fc93d0b12a42eaf97eca159abfe419e4d1263" dependencies = [ "serde", "serde_json", @@ -3697,15 +4310,15 @@ dependencies = [ [[package]] name = "uselesskey-core-jwks-order" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6500f2509bf0210e632be9018180f7af8c7ddd2a37137e8b91fe0402be2a0bc7" +checksum = "e15b69e734f2e7595e1ff6daa1b6a19d664b5b715051d4330b10a22eda19b1e7" [[package]] name = "uselesskey-core-keypair-material" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a3c5a6edacd46be157a4ab027b037bc2d4548dde732acd7991fac59c5c74aaa" +checksum = "707fb74cd170ea3bdc1bca7f904db6d3b52a07ca983653d9a94f0834362c8390" dependencies = [ "uselesskey-core", "uselesskey-core-kid", @@ -3713,9 +4326,9 @@ dependencies = [ [[package]] name = "uselesskey-core-kid" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a024c1f2966436baa4e302fa5bc878312f4526d9a1a624575b421776245fb7c" +checksum = "9a1f14829f539079c19f56f22d29bcd253d1a38f63fd58c712bd0b4479265022" dependencies = [ "base64", "blake3", @@ -3723,9 +4336,9 @@ dependencies = [ [[package]] name = "uselesskey-core-negative" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8db160b7424fa04d1bbe69d9b8cde990a0c6b1a744122c7d9046318ce9e0784" +checksum = "e416a896ba31c86eb26b0f9674372594d4a59ff5d73a8e17b32adf3d0620fa61" dependencies = [ "uselesskey-core-negative-der", "uselesskey-core-negative-pem", @@ -3733,67 +4346,71 @@ dependencies = [ [[package]] name = "uselesskey-core-negative-der" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5be41e3fcadac186f9ad88852eb3b2a9b4905b3c6dfbeb2252b6cc44ba0c730" +checksum = "5045f08ad993e0b44b866ae2063dd1fd531838a4cde554ecbb31d67c77d16313" dependencies = [ "uselesskey-core-hash", ] [[package]] name = "uselesskey-core-negative-pem" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804b7f55793d170397c73a98a883a4fde193d2f86ab49a6769c9aa33c0465567" +checksum = "bc8655e538f40ed19d05dacbf873984cae15eba9cdf607a004c8566f100e228d" dependencies = [ "uselesskey-core-hash", ] [[package]] name = "uselesskey-core-seed" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0664d542017cd3c2a0444547a46ed533c93de60e8baddc9e3c60b53cb4f726fc" +checksum = "0d5f8a13d928d399fe950487fbac66f7b11b8a6544ff0021bc0316305dcaf68f" dependencies = [ "blake3", + "rand_chacha 0.10.0", + "rand_core 0.10.0", ] [[package]] name = "uselesskey-core-sink" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650162c195beeb6e746822fb0760e62e9d71df66b129192d315d63f08f9d82c1" +checksum = "27f16a6c364acde821cba60dfc983f24794cac577d554ddb7f67b98020bce834" dependencies = [ "tempfile", ] [[package]] name = "uselesskey-core-token" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1ba93c056ce7d888b5ef4558378cb1ae37ed872c74e2010057652eb33885a7b" +checksum = "e215853878d4a4a31221e1509403e2e029c3cff72b4b70c5d6faa1ec99ce73dc" dependencies = [ "uselesskey-core-token-shape", ] [[package]] name = "uselesskey-core-token-shape" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3801ef858163ad79472c4750fc5decb4b425bcf5a4282310ef3239174dd6eb48" +checksum = "0073b187565328858e4ece4e8c6bf94fa83c08eff401c0f7e986623008d25c19" dependencies = [ "base64", - "rand_core 0.6.4", + "rand_chacha 0.10.0", + "rand_core 0.10.0", "serde_json", "uselesskey-core-base62", + "uselesskey-core-seed", "uselesskey-token-spec", ] [[package]] name = "uselesskey-core-x509" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a6f3ac0e4c75a05c962a00041a75c423c874adee59602e75e3448d4be7541f" +checksum = "b227b7d146f980bb4b78fd5fc7a1405c2798c97c2730c2e175d32351cf4fedc0" dependencies = [ "uselesskey-core-x509-derive", "uselesskey-core-x509-negative", @@ -3802,30 +4419,32 @@ dependencies = [ [[package]] name = "uselesskey-core-x509-chain-negative" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21339be6a19eac894190a3f49e73d1114cc17dcd331018c8b6f960fa69d15dec" +checksum = "77066ba2bb0adeebd0d716f41667cbc506f65ad00495397d6de4bcff54fe9365" dependencies = [ "uselesskey-core-x509-spec", ] [[package]] name = "uselesskey-core-x509-derive" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688a59f81768aee406c6c659526c7f86b64553071a8c85d800fdcc02b6e20023" +checksum = "30b3567b6301544a05c3bb5b78bd204c14655e2488a2ddb9a161ebc248315d26" dependencies = [ - "rand_core 0.6.4", + "rand_chacha 0.10.0", + "rand_core 0.10.0", "rcgen", "time", "uselesskey-core-hash", + "uselesskey-core-seed", ] [[package]] name = "uselesskey-core-x509-negative" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2562c09b4ebfaac060d0a94ca4faf830ec9794e85afa9a2ae0f563a040e8e0d8" +checksum = "6a55369c06e476ec528c976b8056533001f75f146cae0e795c92bb02ed92ec6e" dependencies = [ "uselesskey-core-x509-chain-negative", "uselesskey-core-x509-spec", @@ -3833,21 +4452,22 @@ dependencies = [ [[package]] name = "uselesskey-core-x509-spec" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324933e46b3d86461e283389c7e796ef3caae0315ed45dcc92180951e9094b3" +checksum = "286c74c6b370dbe744ce75572c0a1f317d95776de987e581814084d0daf8d9cc" [[package]] name = "uselesskey-ecdsa" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3042f497b62766b42abc43be8cda667c7a394291a8810554ca01ad732e6431c" +checksum = "75e6fa165a879b75ca9c49042960c9aaa00a5cbb3cf933113d57bce4594a0541" dependencies = [ "base64", "elliptic-curve", "p256", "p384", - "rand_core 0.6.4", + "rand_chacha 0.10.0", + "rand_core 0.10.0", "serde_json", "uselesskey-core", "uselesskey-core-keypair-material", @@ -3856,14 +4476,13 @@ dependencies = [ [[package]] name = "uselesskey-ed25519" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348541b7157c5e43dd7b1e642cc4c733afa1a6dd7c86b6e4d6bb1f01005b4588" +checksum = "473203a10d4c44948cf507a18cc39ebe5ecb69588b6743adadc662899c0a1766" dependencies = [ "base64", "ed25519-dalek", - "pkcs8", - "rand_core 0.6.4", + "pkcs8 0.10.2", "serde_json", "uselesskey-core", "uselesskey-core-keypair-material", @@ -3872,12 +4491,13 @@ dependencies = [ [[package]] name = "uselesskey-hmac" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433957b0edee4a3c2e946af20bed2fc1cab0da6f9a2763d7e26cd8f8d974caa4" +checksum = "103d1015630e5f48529a6f51805b06591e3fe0829a9e95040fd18cb05ba19322" dependencies = [ "base64", - "rand_core 0.6.4", + "rand_chacha 0.10.0", + "rand_core 0.10.0", "uselesskey-core", "uselesskey-core-hmac-spec", "uselesskey-core-kid", @@ -3886,9 +4506,9 @@ dependencies = [ [[package]] name = "uselesskey-jwk" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be0d688e80908a7c68c01a6409304bea54e02a3a5f59e94b730ca7301ddadfe" +checksum = "83866bbfff1713b5789be3ad285907ffa6ea3328fec2966f951bce0bd1b5ba69" dependencies = [ "uselesskey-core-jwk", "uselesskey-core-jwk-builder", @@ -3896,12 +4516,17 @@ dependencies = [ [[package]] name = "uselesskey-rsa" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17fa5011811f2ce3ab875b68a0d8cb208010ff9377123c1d185ee0ab74ba9f8b" +checksum = "d5579cadfac51dc59aea6fbb77d42dbc57991b2369418630f74fd9231d1cc743" dependencies = [ "base64", - "rsa", + "rand_chacha 0.10.0", + "rand_chacha 0.3.1", + "rand_core 0.10.0", + "rand_core 0.6.4", + "rsa 0.10.0-rc.17", + "rsa 0.9.10", "serde_json", "uselesskey-core", "uselesskey-core-keypair-material", @@ -3910,9 +4535,9 @@ dependencies = [ [[package]] name = "uselesskey-token" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39f950c63cfcfd10cdda50f454417a250e543991d138ddeed9bf9b07b5490d76" +checksum = "d8f36830ad3a36af362be10defa0e518163e841281f5993f6dffa47a176779f7" dependencies = [ "uselesskey-core", "uselesskey-core-token", @@ -3921,19 +4546,21 @@ dependencies = [ [[package]] name = "uselesskey-token-spec" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583a99d15a08daa5193369c205192622107e54f06d22ab1255769f29c6317431" +checksum = "8e935f0fdf3799535b759c45a5fada29f796d4cdb3274a753175bd34f80dac5b" [[package]] name = "uselesskey-x509" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc3800df82ab437b9524b5675f6f479c2e20089c631b14ad5b6a0e75528b0531" +checksum = "e88570a61395fed4a20e560644d1a11ca9058245784c6157a837172e95526de3" dependencies = [ "base64", + "rand_chacha 0.3.1", + "rand_core 0.6.4", "rcgen", - "rsa", + "rsa 0.10.0-rc.17", "rustls-pki-types", "time", "uselesskey-core", @@ -3955,16 +4582,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "uuid-simd" version = "0.8.0" @@ -3972,7 +4589,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b082222b4f6619906941c17eb2297fff4c2fb96cb60164170522942a200bd8" dependencies = [ "outref", - "uuid", "vsimd", ] @@ -4031,6 +4647,15 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.108" @@ -4090,6 +4715,40 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "web-sys" version = "0.3.85" @@ -4100,6 +4759,31 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.11" @@ -4109,12 +4793,27 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -4142,6 +4841,21 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -4175,6 +4889,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -4187,6 +4907,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -4199,6 +4925,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -4223,6 +4955,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -4235,6 +4973,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -4247,6 +4991,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -4259,6 +5009,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -4273,18 +5029,97 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.14" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" -dependencies = [ - "memchr", -] +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" [[package]] name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "writeable" @@ -4304,6 +5139,7 @@ dependencies = [ "lazy_static", "nom 7.1.3", "oid-registry", + "ring", "rusticata-macros", "thiserror 2.0.18", "time", diff --git a/Cargo.toml b/Cargo.toml index 77eca52..4836833 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,17 +88,17 @@ homepage = "https://crates.io/crates/lintdiff" documentation = "https://docs.rs/lintdiff" [workspace.dependencies] -criterion = "0.5" +criterion = "0.8" serde = { version = "1", features = ["derive"] } serde_json = "1" -thiserror = "1" +thiserror = "2" clap = { version = "4", features = ["derive"] } -toml = "0.8" +toml = "1.1" globset = "0.4" -sha2 = "0.10" +sha2 = "0.11" hex = "0.4" time = { version = "0.3", features = ["formatting", "parsing"] } -uselesskey = { version = "0.2.0", features = ["token", "x509", "jwk"] } +uselesskey = { version = "0.5.1", features = ["token", "x509", "jwk"] } tempfile = "3" temp-env = "0.3" proptest = "1" diff --git a/crates/lintdiff-types/Cargo.toml b/crates/lintdiff-types/Cargo.toml index 4e61a71..4065556 100644 --- a/crates/lintdiff-types/Cargo.toml +++ b/crates/lintdiff-types/Cargo.toml @@ -20,4 +20,4 @@ thiserror.workspace = true time.workspace = true [dev-dependencies] -jsonschema = "0.28" +jsonschema = "0.45" From eeddddf70fa7dc392c0053b213d9a22ee0fd08b5 Mon Sep 17 00:00:00 2001 From: Steven Zimmerman Date: Sun, 29 Mar 2026 15:45:48 -0400 Subject: [PATCH 4/9] chore: run rustfmt on workspace --- crates/lintdiff-annotation-format/src/lib.rs | 86 ++-- .../tests/annotation_format_tests.rs | 146 +++---- crates/lintdiff-app/src/lib.rs | 2 +- crates/lintdiff-bdd-harness/src/lib.rs | 2 +- crates/lintdiff-budget/tests/budget_tests.rs | 6 +- crates/lintdiff-ci-env/src/lib.rs | 35 +- crates/lintdiff-ci-env/tests/ci_env_tests.rs | 60 ++- crates/lintdiff-cli/tests/bdd.rs | 28 +- crates/lintdiff-code-norm/src/lib.rs | 6 +- crates/lintdiff-code-policy/src/lib.rs | 55 +-- .../tests/code_policy_tests.rs | 58 ++- crates/lintdiff-code-url/src/lib.rs | 40 +- .../lintdiff-code-url/tests/code_url_tests.rs | 109 +++-- .../tests/config_types_tests.rs | 15 +- crates/lintdiff-config/tests/config_tests.rs | 10 +- crates/lintdiff-counts/src/lib.rs | 36 +- crates/lintdiff-counts/tests/counts_tests.rs | 90 ++-- crates/lintdiff-diagnostic-level/src/lib.rs | 7 +- .../tests/diagnostic_level_tests.rs | 35 +- crates/lintdiff-diff-paths/src/lib.rs | 51 +-- .../tests/diff_paths_tests.rs | 14 +- crates/lintdiff-diff-stats/src/lib.rs | 21 +- .../tests/diff_stats_tests.rs | 15 +- .../tests/disposition_tests.rs | 14 +- crates/lintdiff-escape/tests/escape_tests.rs | 30 +- crates/lintdiff-exit/tests/exit_tests.rs | 3 +- crates/lintdiff-explain-builder/src/lib.rs | 33 +- .../tests/explain_builder_tests.rs | 398 +++++++++--------- crates/lintdiff-explain-summary/src/lib.rs | 48 ++- crates/lintdiff-explain/src/lib.rs | 25 +- .../lintdiff-explain/tests/explain_tests.rs | 10 +- crates/lintdiff-finding-builder/src/lib.rs | 8 +- .../tests/finding_builder_tests.rs | 27 +- crates/lintdiff-finding/src/lib.rs | 3 +- .../lintdiff-finding/tests/finding_tests.rs | 4 +- crates/lintdiff-git-info/src/lib.rs | 19 +- .../lintdiff-git-info/tests/git_info_tests.rs | 48 ++- crates/lintdiff-glob/src/lib.rs | 30 +- crates/lintdiff-glob/tests/glob_tests.rs | 4 +- .../tests/host_info_tests.rs | 74 ++-- crates/lintdiff-hunk-header/src/lib.rs | 11 +- .../tests/hunk_header_tests.rs | 22 +- .../tests/line_merge_tests.rs | 21 +- crates/lintdiff-locale-detect/src/lib.rs | 39 +- .../tests/locale_tests.rs | 10 +- crates/lintdiff-location/src/lib.rs | 14 +- .../lintdiff-location/tests/location_tests.rs | 2 +- crates/lintdiff-message-norm/src/lib.rs | 60 ++- .../tests/message_norm_tests.rs | 18 +- crates/lintdiff-message-truncate/src/lib.rs | 11 +- .../tests/message_truncate_tests.rs | 8 +- crates/lintdiff-path-norm/src/lib.rs | 39 +- .../tests/path_norm_tests.rs | 10 +- crates/lintdiff-range-merge/src/lib.rs | 36 +- .../tests/range_merge_tests.rs | 22 +- crates/lintdiff-render-annotations/src/lib.rs | 28 +- .../tests/annotations_tests.rs | 114 ++++- crates/lintdiff-render-markdown/src/lib.rs | 13 +- .../tests/markdown_tests.rs | 30 +- crates/lintdiff-render-utils/src/lib.rs | 19 +- .../tests/render_utils_tests.rs | 33 +- crates/lintdiff-report-builder/src/lib.rs | 50 +-- .../tests/report_builder_tests.rs | 14 +- crates/lintdiff-report-schema/src/lib.rs | 12 +- .../tests/report_schema_tests.rs | 108 +++-- crates/lintdiff-run-info/src/lib.rs | 18 +- .../lintdiff-run-info/tests/run_info_tests.rs | 25 +- crates/lintdiff-schema-diff/src/lib.rs | 53 ++- .../tests/schema_diff_tests.rs | 13 +- crates/lintdiff-severity-map/src/lib.rs | 91 ++-- .../tests/severity_map_tests.rs | 180 +++++--- crates/lintdiff-severity/src/lib.rs | 8 +- .../lintdiff-severity/tests/severity_tests.rs | 14 +- crates/lintdiff-slugify/src/lib.rs | 18 +- .../lintdiff-slugify/tests/slugify_tests.rs | 79 ++-- crates/lintdiff-sort/src/lib.rs | 5 +- crates/lintdiff-sort/tests/sort_tests.rs | 46 +- crates/lintdiff-span-intersect/src/lib.rs | 64 +-- .../tests/span_intersect_tests.rs | 98 +---- crates/lintdiff-span/src/lib.rs | 5 +- crates/lintdiff-stats/src/lib.rs | 6 +- crates/lintdiff-stats/tests/stats_tests.rs | 41 +- crates/lintdiff-timestamp/src/lib.rs | 17 +- .../tests/timestamp_tests.rs | 21 +- crates/lintdiff-truncate/src/lib.rs | 12 +- crates/lintdiff-verdict-reason/src/lib.rs | 108 +++-- .../tests/verdict_reason_tests.rs | 86 ++-- crates/lintdiff-verdict/src/lib.rs | 7 +- .../lintdiff-verdict/tests/verdict_tests.rs | 8 +- 89 files changed, 1985 insertions(+), 1487 deletions(-) diff --git a/crates/lintdiff-annotation-format/src/lib.rs b/crates/lintdiff-annotation-format/src/lib.rs index 0fa2462..9925fb9 100644 --- a/crates/lintdiff-annotation-format/src/lib.rs +++ b/crates/lintdiff-annotation-format/src/lib.rs @@ -457,11 +457,18 @@ pub fn format_github_annotation(annotation: &Annotation) -> String { let message = escape_github_message(&annotation.message); annotation.column.map_or_else( - || format!("::{} file={},line={}::{}", level, annotation.path, annotation.line, message), - |col| format!( - "::{} file={},line={},col={}::{}", - level, annotation.path, annotation.line, col, message - ), + || { + format!( + "::{} file={},line={}::{}", + level, annotation.path, annotation.line, message + ) + }, + |col| { + format!( + "::{} file={},line={},col={}::{}", + level, annotation.path, annotation.line, col, message + ) + }, ) } @@ -555,11 +562,18 @@ pub fn format_circleci_annotation(annotation: &Annotation) -> String { let message = &annotation.message; annotation.column.map_or_else( - || format!("{}:{}: {}: {}", annotation.path, annotation.line, level, message), - |col| format!( - "{}:{}:{}: {}: {}", - annotation.path, annotation.line, col, level, message - ), + || { + format!( + "{}:{}: {}: {}", + annotation.path, annotation.line, level, message + ) + }, + |col| { + format!( + "{}:{}:{}: {}: {}", + annotation.path, annotation.line, col, level, message + ) + }, ) } @@ -586,9 +600,7 @@ pub fn format_circleci_annotation(annotation: &Annotation) -> String { #[must_use] pub fn format_default_annotation(annotation: &Annotation) -> String { let severity = format!("{:?}", annotation.severity); - let col_str = annotation - .column - .map_or(String::new(), |c| format!(":{c}")); + let col_str = annotation.column.map_or(String::new(), |c| format!(":{c}")); format!( "{}:{}{}: {}: {}", @@ -658,8 +670,14 @@ mod tests { CiPlatform::TravisCI.annotation_format(), AnnotationFormat::Default ); - assert_eq!(CiPlatform::Jenkins.annotation_format(), AnnotationFormat::Default); - assert_eq!(CiPlatform::Unknown.annotation_format(), AnnotationFormat::Default); + assert_eq!( + CiPlatform::Jenkins.annotation_format(), + AnnotationFormat::Default + ); + assert_eq!( + CiPlatform::Unknown.annotation_format(), + AnnotationFormat::Default + ); } } @@ -675,7 +693,10 @@ mod tests { AnnotationFormat::CircleCI.resolve(), AnnotationFormat::CircleCI ); - assert_eq!(AnnotationFormat::Default.resolve(), AnnotationFormat::Default); + assert_eq!( + AnnotationFormat::Default.resolve(), + AnnotationFormat::Default + ); } #[test] @@ -816,13 +837,8 @@ mod tests { #[test] fn format_annotation_circleci_with_column() { - let annotation = Annotation::new( - "test.rs", - 100, - Some(5), - AnnotationSeverity::Notice, - "Note", - ); + let annotation = + Annotation::new("test.rs", 100, Some(5), AnnotationSeverity::Notice, "Note"); let output = format_annotation(AnnotationFormat::CircleCI, &annotation); assert!(output.starts_with("test.rs:100:5:")); @@ -899,14 +915,10 @@ mod tests { #[test] fn format_gitlab_uses_correct_severity() { - let fatal = - Annotation::simple("f.rs", 1, AnnotationSeverity::Fatal, "fatal"); - let error = - Annotation::simple("e.rs", 1, AnnotationSeverity::Error, "error"); - let warning = - Annotation::simple("w.rs", 1, AnnotationSeverity::Warning, "warning"); - let notice = - Annotation::simple("n.rs", 1, AnnotationSeverity::Notice, "notice"); + let fatal = Annotation::simple("f.rs", 1, AnnotationSeverity::Fatal, "fatal"); + let error = Annotation::simple("e.rs", 1, AnnotationSeverity::Error, "error"); + let warning = Annotation::simple("w.rs", 1, AnnotationSeverity::Warning, "warning"); + let notice = Annotation::simple("n.rs", 1, AnnotationSeverity::Notice, "notice"); assert!(format_gitlab_annotation(&fatal).contains("critical")); assert!(format_gitlab_annotation(&error).contains("error")); @@ -954,7 +966,8 @@ mod tests { #[test] fn format_circleci_includes_column_when_present() { - let annotation = Annotation::new("test.rs", 10, Some(5), AnnotationSeverity::Error, "E"); + let annotation = + Annotation::new("test.rs", 10, Some(5), AnnotationSeverity::Error, "E"); let output = format_circleci_annotation(&annotation); assert!(output.starts_with("test.rs:10:5:")); @@ -994,8 +1007,7 @@ mod tests { #[test] fn format_default_without_column() { - let annotation = - Annotation::simple("lib.rs", 5, AnnotationSeverity::Warning, "Warn"); + let annotation = Annotation::simple("lib.rs", 5, AnnotationSeverity::Warning, "Warn"); let output = format_default_annotation(&annotation); assert!(output.starts_with("lib.rs:5:")); @@ -1008,8 +1020,7 @@ mod tests { #[test] fn empty_message() { - let annotation = - Annotation::simple("empty.rs", 1, AnnotationSeverity::Notice, ""); + let annotation = Annotation::simple("empty.rs", 1, AnnotationSeverity::Notice, ""); let github = format_github_annotation(&annotation); assert!(github.ends_with("::")); // Empty message after :: @@ -1070,7 +1081,8 @@ mod tests { #[test] fn column_number_one() { - let annotation = Annotation::new("first.rs", 1, Some(1), AnnotationSeverity::Error, "E"); + let annotation = + Annotation::new("first.rs", 1, Some(1), AnnotationSeverity::Error, "E"); let output = format_github_annotation(&annotation); assert!(output.contains("col=1")); diff --git a/crates/lintdiff-annotation-format/tests/annotation_format_tests.rs b/crates/lintdiff-annotation-format/tests/annotation_format_tests.rs index f49a37f..12fa065 100644 --- a/crates/lintdiff-annotation-format/tests/annotation_format_tests.rs +++ b/crates/lintdiff-annotation-format/tests/annotation_format_tests.rs @@ -5,7 +5,7 @@ use lintdiff_annotation_format::{ detect_ci, format_annotation, format_azure_annotation, format_circleci_annotation, - format_default_annotation, format_gitlab_annotation, format_github_annotation, is_azure_devops, + format_default_annotation, format_github_annotation, format_gitlab_annotation, is_azure_devops, is_circleci, is_github_actions, is_gitlab_ci, Annotation, AnnotationFormat, AnnotationSeverity, CiPlatform, }; @@ -57,10 +57,7 @@ mod annotation_format_enum { #[test] fn gitlab_format_resolves_to_itself() { - assert_eq!( - AnnotationFormat::Gitlab.resolve(), - AnnotationFormat::Gitlab - ); + assert_eq!(AnnotationFormat::Gitlab.resolve(), AnnotationFormat::Gitlab); } #[test] @@ -157,12 +154,18 @@ mod ci_platform_detection { #[test] fn jenkins_maps_to_default_format() { - assert_eq!(CiPlatform::Jenkins.annotation_format(), AnnotationFormat::Default); + assert_eq!( + CiPlatform::Jenkins.annotation_format(), + AnnotationFormat::Default + ); } #[test] fn unknown_maps_to_default_format() { - assert_eq!(CiPlatform::Unknown.annotation_format(), AnnotationFormat::Default); + assert_eq!( + CiPlatform::Unknown.annotation_format(), + AnnotationFormat::Default + ); } } @@ -496,8 +499,7 @@ mod annotation_struct { #[test] fn simple_creates_annotation_without_column() { - let annotation = - Annotation::simple("main.rs", 1, AnnotationSeverity::Notice, "Info"); + let annotation = Annotation::simple("main.rs", 1, AnnotationSeverity::Notice, "Info"); assert_eq!(annotation.path, "main.rs"); assert_eq!(annotation.line, 1); @@ -589,12 +591,8 @@ mod github_formatting { #[test] fn formats_notice_correctly() { - let annotation = Annotation::simple( - "docs/readme.md", - 5, - AnnotationSeverity::Notice, - "Notice", - ); + let annotation = + Annotation::simple("docs/readme.md", 5, AnnotationSeverity::Notice, "Notice"); let output = format_github_annotation(&annotation); assert!(output.starts_with("::notice")); @@ -649,8 +647,7 @@ mod github_formatting { #[test] fn escapes_comma_in_message() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "a, b, c"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "a, b, c"); let output = format_github_annotation(&annotation); assert!(output.contains("%2C")); @@ -685,12 +682,8 @@ mod github_formatting { #[test] fn escapes_multiple_special_chars() { - let annotation = Annotation::simple( - "file.rs", - 1, - AnnotationSeverity::Error, - "a:b,c%d\ne", - ); + let annotation = + Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "a:b,c%d\ne"); let output = format_github_annotation(&annotation); assert!(output.contains("%3A")); // : @@ -724,8 +717,7 @@ mod gitlab_formatting { #[test] fn uses_info_for_notice() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Notice, "Info"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Notice, "Info"); let output = format_gitlab_annotation(&annotation); assert!(output.contains("info")); @@ -733,8 +725,7 @@ mod gitlab_formatting { #[test] fn uses_critical_for_fatal() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Fatal, "Fatal"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Fatal, "Fatal"); let output = format_gitlab_annotation(&annotation); assert!(output.contains("critical")); @@ -796,8 +787,7 @@ mod azure_formatting { #[test] fn uses_information_for_notice() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Notice, "Info"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Notice, "Info"); let output = format_azure_annotation(&annotation); assert!(output.contains("type=information")); @@ -809,8 +799,7 @@ mod azure_formatting { #[test] fn escapes_bracket() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "Error]"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "Error]"); let output = format_azure_annotation(&annotation); assert!(output.contains("%5D")); @@ -818,8 +807,7 @@ mod azure_formatting { #[test] fn escapes_semicolon() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "a; b"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "a; b"); let output = format_azure_annotation(&annotation); assert!(output.contains("%3B")); @@ -827,8 +815,7 @@ mod azure_formatting { #[test] fn escapes_newline() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "a\nb"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "a\nb"); let output = format_azure_annotation(&annotation); assert!(output.contains("%0A")); @@ -866,8 +853,7 @@ mod circleci_formatting { #[test] fn uses_notice_for_notice() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Notice, "Info"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Notice, "Info"); let output = format_circleci_annotation(&annotation); assert!(output.contains("notice")); @@ -908,14 +894,10 @@ mod default_formatting { #[test] fn formats_severity_as_debug_format() { - let warning = - Annotation::simple("f.rs", 1, AnnotationSeverity::Warning, "w"); - let notice = - Annotation::simple("f.rs", 1, AnnotationSeverity::Notice, "n"); - let error = - Annotation::simple("f.rs", 1, AnnotationSeverity::Error, "e"); - let fatal = - Annotation::simple("f.rs", 1, AnnotationSeverity::Fatal, "f"); + let warning = Annotation::simple("f.rs", 1, AnnotationSeverity::Warning, "w"); + let notice = Annotation::simple("f.rs", 1, AnnotationSeverity::Notice, "n"); + let error = Annotation::simple("f.rs", 1, AnnotationSeverity::Error, "e"); + let fatal = Annotation::simple("f.rs", 1, AnnotationSeverity::Fatal, "f"); assert!(format_default_annotation(&warning).contains("Warning")); assert!(format_default_annotation(¬ice).contains("Notice")); @@ -934,8 +916,7 @@ mod generic_format_annotation { #[test] fn routes_to_github_format() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "msg"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "msg"); let output = format_annotation(AnnotationFormat::Github, &annotation); assert!(output.starts_with("::error")); @@ -943,8 +924,7 @@ mod generic_format_annotation { #[test] fn routes_to_gitlab_format() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Warning, "msg"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Warning, "msg"); let output = format_annotation(AnnotationFormat::Gitlab, &annotation); assert!(output.starts_with("file.rs:1:")); @@ -952,8 +932,7 @@ mod generic_format_annotation { #[test] fn routes_to_azure_format() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "msg"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "msg"); let output = format_annotation(AnnotationFormat::Azure, &annotation); assert!(output.starts_with("##vso[task.logissue")); @@ -961,8 +940,7 @@ mod generic_format_annotation { #[test] fn routes_to_circleci_format() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "msg"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "msg"); let output = format_annotation(AnnotationFormat::CircleCI, &annotation); assert!(output.starts_with("file.rs:1:")); @@ -970,8 +948,7 @@ mod generic_format_annotation { #[test] fn routes_to_default_format() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "msg"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "msg"); let output = format_annotation(AnnotationFormat::Default, &annotation); assert!(output.starts_with("file.rs:1:")); @@ -990,8 +967,7 @@ mod edge_cases { #[test] fn empty_message_github() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, ""); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, ""); let output = format_github_annotation(&annotation); assert!(output.ends_with("::")); @@ -999,8 +975,7 @@ mod edge_cases { #[test] fn empty_message_gitlab() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, ""); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, ""); let output = format_gitlab_annotation(&annotation); // Should still have structure: path:line: severity: message @@ -1009,8 +984,7 @@ mod edge_cases { #[test] fn empty_message_azure() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, ""); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, ""); let output = format_azure_annotation(&annotation); assert!(output.ends_with(']')); @@ -1022,8 +996,7 @@ mod edge_cases { #[test] fn line_number_one() { - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "msg"); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "msg"); let output = format_github_annotation(&annotation); assert!(output.contains("line=1")); @@ -1049,13 +1022,8 @@ mod edge_cases { #[test] fn large_column_number() { - let annotation = Annotation::new( - "file.rs", - 1, - Some(10_000), - AnnotationSeverity::Error, - "msg", - ); + let annotation = + Annotation::new("file.rs", 1, Some(10_000), AnnotationSeverity::Error, "msg"); let output = format_github_annotation(&annotation); assert!(output.contains("col=10000")); @@ -1067,12 +1035,8 @@ mod edge_cases { #[test] fn path_with_spaces() { - let annotation = Annotation::simple( - "src/my module/file.rs", - 1, - AnnotationSeverity::Error, - "msg", - ); + let annotation = + Annotation::simple("src/my module/file.rs", 1, AnnotationSeverity::Error, "msg"); let output = format_github_annotation(&annotation); assert!(output.contains("src/my module/file.rs")); @@ -1080,12 +1044,8 @@ mod edge_cases { #[test] fn path_with_special_chars() { - let annotation = Annotation::simple( - "src/file-name_test.rs", - 1, - AnnotationSeverity::Error, - "msg", - ); + let annotation = + Annotation::simple("src/file-name_test.rs", 1, AnnotationSeverity::Error, "msg"); let output = format_github_annotation(&annotation); assert!(output.contains("file-name_test.rs")); @@ -1093,12 +1053,8 @@ mod edge_cases { #[test] fn windows_style_path() { - let annotation = Annotation::simple( - "src\\module\\file.rs", - 1, - AnnotationSeverity::Error, - "msg", - ); + let annotation = + Annotation::simple("src\\module\\file.rs", 1, AnnotationSeverity::Error, "msg"); let output = format_github_annotation(&annotation); assert!(output.contains("src\\module\\file.rs")); @@ -1123,12 +1079,8 @@ mod edge_cases { #[test] fn unicode_message() { - let annotation = Annotation::simple( - "file.rs", - 1, - AnnotationSeverity::Error, - "错误: 你好世界 🌍", - ); + let annotation = + Annotation::simple("file.rs", 1, AnnotationSeverity::Error, "错误: 你好世界 🌍"); let output = format_default_annotation(&annotation); assert!(output.contains("错误")); @@ -1152,8 +1104,7 @@ mod edge_cases { #[test] fn very_long_message() { let long_msg = "x".repeat(10000); - let annotation = - Annotation::simple("file.rs", 1, AnnotationSeverity::Error, &long_msg); + let annotation = Annotation::simple("file.rs", 1, AnnotationSeverity::Error, &long_msg); let output = format_github_annotation(&annotation); assert!(output.contains(&long_msg)); @@ -1162,8 +1113,7 @@ mod edge_cases { #[test] fn very_long_path() { let long_path = format!("src/{}", "a".repeat(500)); - let annotation = - Annotation::simple(&long_path, 1, AnnotationSeverity::Error, "msg"); + let annotation = Annotation::simple(&long_path, 1, AnnotationSeverity::Error, "msg"); let output = format_github_annotation(&annotation); assert!(output.contains(&long_path)); diff --git a/crates/lintdiff-app/src/lib.rs b/crates/lintdiff-app/src/lib.rs index 2fa26c7..d4e4f01 100644 --- a/crates/lintdiff-app/src/lib.rs +++ b/crates/lintdiff-app/src/lib.rs @@ -8,8 +8,8 @@ use lintdiff_app_io::{ write_text, AppIoError, }; use lintdiff_diff::parse_unified_diff; -use lintdiff_ingest_core::{ingest_on_diff, IngestOnDiffParams}; use lintdiff_feature_flags::set_feature_flags_from_assignments; +use lintdiff_ingest_core::{ingest_on_diff, IngestOnDiffParams}; use lintdiff_render::{ render_github_annotations, render_markdown, MarkdownOptions, DEFAULT_REPORT_PATH, }; diff --git a/crates/lintdiff-bdd-harness/src/lib.rs b/crates/lintdiff-bdd-harness/src/lib.rs index b9c2ef9..5bea5f6 100644 --- a/crates/lintdiff-bdd-harness/src/lib.rs +++ b/crates/lintdiff-bdd-harness/src/lib.rs @@ -1,10 +1,10 @@ use std::io::Cursor; pub use lintdiff_bdd_grid::{FeatureFlagGrid, FeatureFlagGridRow}; -use lintdiff_ingest_core::{ingest_on_diff, IngestOnDiffParams}; use lintdiff_diagnostics::parse_cargo_messages; use lintdiff_diff::parse_unified_diff; use lintdiff_feature_flags::set_feature_flag_by_name_and_value; +use lintdiff_ingest_core::{ingest_on_diff, IngestOnDiffParams}; use lintdiff_types::{LintdiffConfig, NormPath, Report, RunInfo, ToolInfo, TOOL_NAME}; const TEST_TOOL_VERSION: &str = "test"; diff --git a/crates/lintdiff-budget/tests/budget_tests.rs b/crates/lintdiff-budget/tests/budget_tests.rs index ee03b45..d02d0ae 100644 --- a/crates/lintdiff-budget/tests/budget_tests.rs +++ b/crates/lintdiff-budget/tests/budget_tests.rs @@ -2,10 +2,12 @@ //! //! These tests cover all public API functions and edge cases. -use lintdiff_budget::{Budget, BudgetConfig, BudgetCounter, BudgetExceeded, BudgetTracker, RemainingBudget}; +use lintdiff_budget::{ + Budget, BudgetConfig, BudgetCounter, BudgetExceeded, BudgetTracker, RemainingBudget, +}; +use lintdiff_config_types::FailOn; use lintdiff_counts::SeverityCounts; use lintdiff_counts::SeverityLevel; -use lintdiff_config_types::FailOn; // ============================================================================ // BudgetConfig Tests diff --git a/crates/lintdiff-ci-env/src/lib.rs b/crates/lintdiff-ci-env/src/lib.rs index 4b45d43..a4adcb7 100644 --- a/crates/lintdiff-ci-env/src/lib.rs +++ b/crates/lintdiff-ci-env/src/lib.rs @@ -224,10 +224,9 @@ impl PullRequestInfo { let source_branch = env::var("CI_MERGE_REQUEST_SOURCE_BRANCH_NAME") .unwrap_or_else(|_| env::var("CI_COMMIT_REF_NAME").unwrap_or_default()); - let target_branch = - env::var("CI_MERGE_REQUEST_TARGET_BRANCH_NAME").unwrap_or_else(|_| { - env::var("CI_DEFAULT_BRANCH").unwrap_or_else(|_| "main".to_string()) - }); + let target_branch = env::var("CI_MERGE_REQUEST_TARGET_BRANCH_NAME").unwrap_or_else(|_| { + env::var("CI_DEFAULT_BRANCH").unwrap_or_else(|_| "main".to_string()) + }); Some(Self { number, @@ -252,9 +251,13 @@ impl PullRequestInfo { } fn detect_travis_ci() -> Option { - let number = env::var("TRAVIS_PULL_REQUEST") - .ok() - .and_then(|s| if s == "false" { None } else { s.parse().ok() })?; + let number = env::var("TRAVIS_PULL_REQUEST").ok().and_then(|s| { + if s == "false" { + None + } else { + s.parse().ok() + } + })?; let source_branch = env::var("TRAVIS_PULL_REQUEST_BRANCH").unwrap_or_default(); let target_branch = env::var("TRAVIS_BRANCH").unwrap_or_default(); @@ -273,8 +276,8 @@ impl PullRequestInfo { .and_then(|s| s.parse().ok())?; let source_branch = env::var("BUILD_SOURCEBRANCHNAME").unwrap_or_default(); - let target_branch = env::var("SYSTEM_PULLREQUEST_TARGETBRANCH") - .unwrap_or_else(|_| "main".to_string()); + let target_branch = + env::var("SYSTEM_PULLREQUEST_TARGETBRANCH").unwrap_or_else(|_| "main".to_string()); Some(Self { number, @@ -535,7 +538,12 @@ impl CommitInfo { // Try to get branch from GITHUB_REF if let Ok(github_ref) = env::var("GITHUB_REF") { if github_ref.starts_with("refs/heads/") { - info.branch = Some(github_ref.strip_prefix("refs/heads/").unwrap_or(&github_ref).to_string()); + info.branch = Some( + github_ref + .strip_prefix("refs/heads/") + .unwrap_or(&github_ref) + .to_string(), + ); } } @@ -600,7 +608,12 @@ impl CommitInfo { // BUILD_SOURCEBRANCH is like refs/heads/main if let Ok(source_branch) = env::var("BUILD_SOURCEBRANCH") { if source_branch.starts_with("refs/heads/") { - info.branch = Some(source_branch.strip_prefix("refs/heads/").unwrap_or(&source_branch).to_string()); + info.branch = Some( + source_branch + .strip_prefix("refs/heads/") + .unwrap_or(&source_branch) + .to_string(), + ); } else { info.branch = Some(source_branch); } diff --git a/crates/lintdiff-ci-env/tests/ci_env_tests.rs b/crates/lintdiff-ci-env/tests/ci_env_tests.rs index 3c56f30..6c96661 100644 --- a/crates/lintdiff-ci-env/tests/ci_env_tests.rs +++ b/crates/lintdiff-ci-env/tests/ci_env_tests.rs @@ -194,7 +194,10 @@ fn test_is_ci_returns_true_in_github_actions() { #[test] fn test_is_ci_returns_true_in_gitlab_ci() { with_vars( - vec![("GITHUB_ACTIONS", None::<&str>), ("GITLAB_CI", Some("true"))], + vec![ + ("GITHUB_ACTIONS", None::<&str>), + ("GITLAB_CI", Some("true")), + ], || { assert!(CiPlatform::is_ci()); }, @@ -290,7 +293,10 @@ fn test_pr_info_detect_gitlab_ci() { ("GITHUB_ACTIONS", None::<&str>), ("GITLAB_CI", Some("true")), ("CI_MERGE_REQUEST_IID", Some("42")), - ("CI_MERGE_REQUEST_SOURCE_BRANCH_NAME", Some("feature-branch")), + ( + "CI_MERGE_REQUEST_SOURCE_BRANCH_NAME", + Some("feature-branch"), + ), ("CI_MERGE_REQUEST_TARGET_BRANCH_NAME", Some("main")), ], || { @@ -311,7 +317,10 @@ fn test_pr_info_detect_circleci() { ("GITHUB_ACTIONS", None::<&str>), ("GITLAB_CI", None::<&str>), ("CIRCLECI", Some("true")), - ("CIRCLE_PULL_REQUEST", Some("https://github.com/owner/repo/pull/123")), + ( + "CIRCLE_PULL_REQUEST", + Some("https://github.com/owner/repo/pull/123"), + ), ("CIRCLE_BRANCH", Some("feature")), ], || { @@ -511,7 +520,10 @@ fn test_commit_info_detect_github_actions() { with_vars( vec![ ("GITHUB_ACTIONS", Some("true")), - ("GITHUB_SHA", Some("abcdef1234567890abcdef1234567890abcdef12")), + ( + "GITHUB_SHA", + Some("abcdef1234567890abcdef1234567890abcdef12"), + ), ("GITHUB_REF", Some("refs/heads/main")), ], || { @@ -531,7 +543,10 @@ fn test_commit_info_detect_gitlab_ci() { vec![ ("GITHUB_ACTIONS", None::<&str>), ("GITLAB_CI", Some("true")), - ("CI_COMMIT_SHA", Some("1234567890abcdef1234567890abcdef12345678")), + ( + "CI_COMMIT_SHA", + Some("1234567890abcdef1234567890abcdef12345678"), + ), ("CI_COMMIT_REF_NAME", Some("develop")), ("CI_COMMIT_MESSAGE", Some("Fix bug")), ("CI_COMMIT_AUTHOR", Some("John Doe")), @@ -556,7 +571,10 @@ fn test_commit_info_detect_circleci() { ("GITHUB_ACTIONS", None::<&str>), ("GITLAB_CI", None::<&str>), ("CIRCLECI", Some("true")), - ("CIRCLE_SHA1", Some("fedcba0987654321fedcba0987654321fedcba09")), + ( + "CIRCLE_SHA1", + Some("fedcba0987654321fedcba0987654321fedcba09"), + ), ("CIRCLE_BRANCH", Some("feature-xyz")), ], || { @@ -581,7 +599,10 @@ fn test_commit_info_detect_bitbucket() { ("TF_BUILD", None::<&str>), ("JENKINS_URL", None::<&str>), ("BITBUCKET_BUILD_NUMBER", Some("1")), - ("BITBUCKET_COMMIT", Some("1111111111111111111111111111111111111111")), + ( + "BITBUCKET_COMMIT", + Some("1111111111111111111111111111111111111111"), + ), ("BITBUCKET_BRANCH", Some("release")), ], || { @@ -858,7 +879,10 @@ fn test_mock_github_actions_environment() { vec![ ("GITHUB_ACTIONS", Some("true")), ("GITHUB_REPOSITORY", Some("test-owner/test-repo")), - ("GITHUB_SHA", Some("1234567890abcdef1234567890abcdef12345678")), + ( + "GITHUB_SHA", + Some("1234567890abcdef1234567890abcdef12345678"), + ), ("GITHUB_REF", Some("refs/heads/test-branch")), ], || { @@ -913,9 +937,15 @@ fn test_mock_circleci_environment() { ("CIRCLECI", Some("true")), ("CIRCLE_PROJECT_USERNAME", Some("circle-org")), ("CIRCLE_PROJECT_REPONAME", Some("circle-repo")), - ("CIRCLE_SHA1", Some("1111111111111111111111111111111111111111")), + ( + "CIRCLE_SHA1", + Some("1111111111111111111111111111111111111111"), + ), ("CIRCLE_BRANCH", Some("circle-branch")), - ("CIRCLE_PULL_REQUEST", Some("https://github.com/circle-org/circle-repo/pull/50")), + ( + "CIRCLE_PULL_REQUEST", + Some("https://github.com/circle-org/circle-repo/pull/50"), + ), ], || { let env = CiEnvironment::detect(); @@ -940,7 +970,10 @@ fn test_mock_azure_pipelines_environment() { ("TRAVIS", None::<&str>), ("TF_BUILD", Some("True")), ("BUILD_REPOSITORY_NAME", Some("azure-org/azure-repo")), - ("BUILD_SOURCEVERSION", Some("2222222222222222222222222222222222222222")), + ( + "BUILD_SOURCEVERSION", + Some("2222222222222222222222222222222222222222"), + ), ("BUILD_SOURCEBRANCH", Some("refs/heads/azure-branch")), ("SYSTEM_PULLREQUEST_PULLREQUESTNUMBER", Some("75")), ], @@ -970,7 +1003,10 @@ fn test_mock_drone_ci_environment() { ("APPVEYOR", None::<&str>), ("DRONE", Some("true")), ("DRONE_REPO", Some("drone-org/drone-repo")), - ("DRONE_COMMIT_SHA", Some("3333333333333333333333333333333333333333")), + ( + "DRONE_COMMIT_SHA", + Some("3333333333333333333333333333333333333333"), + ), ("DRONE_BRANCH", Some("drone-branch")), ("DRONE_COMMIT_MESSAGE", Some("Test commit")), ("DRONE_COMMIT_AUTHOR", Some("Test Author")), diff --git a/crates/lintdiff-cli/tests/bdd.rs b/crates/lintdiff-cli/tests/bdd.rs index 92fa7d0..243ba17 100644 --- a/crates/lintdiff-cli/tests/bdd.rs +++ b/crates/lintdiff-cli/tests/bdd.rs @@ -124,12 +124,12 @@ async fn when_ingest(world: &mut LintdiffWorld) { &world.diagnostics, &world.config, )); - + // Set exit code based on verdict for error cases if world.error_message.is_some() { return; // Exit code already set } - + // For skip verdict with empty diagnostics, set exit code 0 let r = world.report.as_ref().expect("report produced"); if r.verdict.status == lintdiff_types::VerdictStatus::Skip { @@ -324,22 +324,34 @@ async fn when_full_pipeline(world: &mut LintdiffWorld) { let r = world.report.as_ref().expect("report produced"); world.markdown = Some(render_markdown(r, MarkdownOptions::default())); world.annotations = Some(render_github_annotations(r, 100)); - + // Determine exit code based on verdict and fail_on configuration - let fail_on = world.config.fail_on.as_ref().unwrap_or(&lintdiff_types::FailOn::Error); + let fail_on = world + .config + .fail_on + .as_ref() + .unwrap_or(&lintdiff_types::FailOn::Error); let has_errors = r.verdict.counts.error > 0; let has_warnings = r.verdict.counts.warn > 0; - + // Check if any denied codes caused errors let is_fail = r.verdict.status == lintdiff_types::VerdictStatus::Fail; - + world.exit_code = Some(match fail_on { lintdiff_types::FailOn::Never => 0, lintdiff_types::FailOn::Error => { - if has_errors || is_fail { 2 } else { 0 } + if has_errors || is_fail { + 2 + } else { + 0 + } } lintdiff_types::FailOn::Warn => { - if has_errors || has_warnings || is_fail { 2 } else { 0 } + if has_errors || has_warnings || is_fail { + 2 + } else { + 0 + } } }); } diff --git a/crates/lintdiff-code-norm/src/lib.rs b/crates/lintdiff-code-norm/src/lib.rs index 1d4388a..53757c2 100644 --- a/crates/lintdiff-code-norm/src/lib.rs +++ b/crates/lintdiff-code-norm/src/lib.rs @@ -167,11 +167,7 @@ pub fn normalize_whitespace_with_options(s: &str, trim: bool, collapse: bool) -> line.to_string() }; - let final_line = if trim { - processed.trim() - } else { - &processed - }; + let final_line = if trim { processed.trim() } else { &processed }; if i > 0 { result.push('\n'); diff --git a/crates/lintdiff-code-policy/src/lib.rs b/crates/lintdiff-code-policy/src/lib.rs index 3781591..80037d3 100644 --- a/crates/lintdiff-code-policy/src/lib.rs +++ b/crates/lintdiff-code-policy/src/lib.rs @@ -453,8 +453,7 @@ impl PolicyEvaluator { let matches = self.match_pattern(rule, code); if !matches.is_empty() { results.push( - PolicyResult::new(rule.clone(), matches, rule.policy) - .with_file_path(path), + PolicyResult::new(rule.clone(), matches, rule.policy).with_file_path(path), ); } } @@ -504,20 +503,16 @@ impl PolicyEvaluator { // Calculate the actual line end position (including newline if present) let line_len = line.len(); let line_end = line_start + line_len; - + // Check if there's a newline character after this line let has_newline = if line_end < code.len() { code.as_bytes()[line_end] == b'\n' } else { false }; - + // The actual line end in the original code - let actual_line_end = if has_newline { - line_end + 1 - } else { - line_end - }; + let actual_line_end = if has_newline { line_end + 1 } else { line_end }; // Check if the glob pattern matches this line if glob.is_match(line) { @@ -552,18 +547,15 @@ impl PolicyEvaluator { .collect(); let mut matches = Vec::new(); - + // Empty pattern matches at position 0 if pattern.is_empty() { let line_num = 1; let line_start = 0; let line_end = code.find('\n').map_or(code.len(), |i| i); let line_text = code[line_start..line_end].to_string(); - - matches.push( - Match::new(0, 0, line_num, line_text) - .with_column(1), - ); + + matches.push(Match::new(0, 0, line_num, line_text).with_column(1)); return matches; } @@ -667,7 +659,7 @@ pub fn find_matching_lines(glob: &str, code: &str) -> Result, PolicyE } else { format!("*{glob}*") }; - + let compiled = Glob::new(&glob_pattern)?; let mut matches = Vec::new(); let mut line_start = 0; @@ -677,23 +669,24 @@ pub fn find_matching_lines(glob: &str, code: &str) -> Result, PolicyE // Calculate the actual line end position (including newline if present) let line_len = line.len(); let line_end = line_start + line_len; - + // Check if there's a newline character after this line let has_newline = if line_end < code.len() { code.as_bytes()[line_end] == b'\n' } else { false }; - + // The actual line end in the original code - let actual_line_end = if has_newline { - line_end + 1 - } else { - line_end - }; + let actual_line_end = if has_newline { line_end + 1 } else { line_end }; if compiled.is_match(line) { - matches.push(Match::new(line_start, actual_line_end, line_num, line.to_string())); + matches.push(Match::new( + line_start, + actual_line_end, + line_num, + line.to_string(), + )); } line_start = actual_line_end; @@ -728,16 +721,12 @@ pub fn count_matching_lines(glob: &str, code: &str) -> Result usize { // Clamp the position to the text length let pos = byte_pos.min(text.len()); - + // Find the nearest character boundary before or at the position // This prevents panics when byte_pos is in the middle of a multi-byte character let safe_pos = text.floor_char_boundary(pos); - - text[..safe_pos] - .chars() - .filter(|&c| c == '\n') - .count() - + 1 + + text[..safe_pos].chars().filter(|&c| c == '\n').count() + 1 } /// Get the column number for a byte position in text (within its line). @@ -745,10 +734,10 @@ pub fn line_number_at(text: &str, byte_pos: usize) -> usize { pub fn column_number_at(text: &str, byte_pos: usize) -> usize { // Clamp the position to the text length let pos = byte_pos.min(text.len()); - + // Find the nearest character boundary before or at the position let safe_pos = text.floor_char_boundary(pos); - + let line_start = text[..safe_pos].rfind('\n').map_or(0, |i| i + 1); safe_pos - line_start + 1 } diff --git a/crates/lintdiff-code-policy/tests/code_policy_tests.rs b/crates/lintdiff-code-policy/tests/code_policy_tests.rs index 4d12f31..3cee15c 100644 --- a/crates/lintdiff-code-policy/tests/code_policy_tests.rs +++ b/crates/lintdiff-code-policy/tests/code_policy_tests.rs @@ -8,9 +8,9 @@ //! - Property-based tests with proptest use lintdiff_code_policy::{ - count_matching_lines, find_matching_lines, glob_matches_pattern, line_number_at, - regex_matches_pattern, CodePolicy, Match, PolicyEvaluator, PolicyResult, PolicyRule, - PatternType, Severity, column_number_at, + column_number_at, count_matching_lines, find_matching_lines, glob_matches_pattern, + line_number_at, regex_matches_pattern, CodePolicy, Match, PatternType, PolicyEvaluator, + PolicyResult, PolicyRule, Severity, }; // ============================================================================= @@ -185,29 +185,26 @@ mod policy_rule_tests { #[test] fn rule_with_severity_sets_severity() { - let rule = PolicyRule::new("test", CodePolicy::Deny) - .with_severity(Severity::Critical); + let rule = PolicyRule::new("test", CodePolicy::Deny).with_severity(Severity::Critical); assert_eq!(rule.severity, Some(Severity::Critical)); } #[test] fn rule_with_message_sets_message() { - let rule = PolicyRule::new("test", CodePolicy::Deny) - .with_message("Avoid using this pattern"); + let rule = + PolicyRule::new("test", CodePolicy::Deny).with_message("Avoid using this pattern"); assert_eq!(rule.message, Some("Avoid using this pattern".to_string())); } #[test] fn rule_with_file_filter_sets_filter() { - let rule = PolicyRule::new("test", CodePolicy::Deny) - .with_file_filter("src/**/*.rs"); + let rule = PolicyRule::new("test", CodePolicy::Deny).with_file_filter("src/**/*.rs"); assert_eq!(rule.file_filter, Some("src/**/*.rs".to_string())); } #[test] fn rule_with_id_sets_id() { - let rule = PolicyRule::new("test", CodePolicy::Deny) - .with_id("POLICY-001"); + let rule = PolicyRule::new("test", CodePolicy::Deny).with_id("POLICY-001"); assert_eq!(rule.id, Some("POLICY-001".to_string())); } @@ -236,16 +233,14 @@ mod policy_rule_tests { #[test] fn rule_applies_to_file_with_filter_matches_correctly() { - let rule = PolicyRule::new("test", CodePolicy::Deny) - .with_file_filter("*.rs"); + let rule = PolicyRule::new("test", CodePolicy::Deny).with_file_filter("*.rs"); assert!(rule.applies_to_file("main.rs").unwrap()); assert!(!rule.applies_to_file("main.txt").unwrap()); } #[test] fn rule_applies_to_file_with_globstar_filter() { - let rule = PolicyRule::new("test", CodePolicy::Deny) - .with_file_filter("src/**/*.rs"); + let rule = PolicyRule::new("test", CodePolicy::Deny).with_file_filter("src/**/*.rs"); assert!(rule.applies_to_file("src/lib.rs").unwrap()); assert!(rule.applies_to_file("src/foo/bar.rs").unwrap()); assert!(!rule.applies_to_file("tests/lib.rs").unwrap()); @@ -253,8 +248,7 @@ mod policy_rule_tests { #[test] fn rule_clone_works() { - let rule = PolicyRule::new("test", CodePolicy::Deny) - .with_message("Test message"); + let rule = PolicyRule::new("test", CodePolicy::Deny).with_message("Test message"); let cloned = rule.clone(); assert_eq!(rule.pattern, cloned.pattern); assert_eq!(rule.policy, cloned.policy); @@ -328,8 +322,8 @@ mod policy_result_tests { #[test] fn result_with_file_path_adds_path() { let rule = PolicyRule::new("test", CodePolicy::Deny); - let result = PolicyResult::new(rule, vec![], CodePolicy::Deny) - .with_file_path("src/main.rs"); + let result = + PolicyResult::new(rule, vec![], CodePolicy::Deny).with_file_path("src/main.rs"); assert_eq!(result.file_path, Some("src/main.rs".to_string())); } @@ -367,7 +361,8 @@ mod policy_result_tests { rule, vec![Match::new(0, 4, 1, "test".to_string())], CodePolicy::Deny, - ).with_file_path("test.rs"); + ) + .with_file_path("test.rs"); let cloned = result.clone(); assert_eq!(result.file_path, cloned.file_path); assert_eq!(result.matches.len(), cloned.matches.len()); @@ -602,8 +597,7 @@ mod file_evaluation_tests { fn evaluate_file_applies_file_filter() { let mut evaluator = PolicyEvaluator::new(); evaluator.add_rule( - PolicyRule::glob("todo!()", CodePolicy::Deny) - .with_file_filter("src/**/*.rs"), + PolicyRule::glob("todo!()", CodePolicy::Deny).with_file_filter("src/**/*.rs"), ); let code = "fn main() { todo!() }"; @@ -631,10 +625,7 @@ mod file_evaluation_tests { #[test] fn evaluate_file_with_no_matching_rules_returns_empty() { let mut evaluator = PolicyEvaluator::new(); - evaluator.add_rule( - PolicyRule::glob("todo!()", CodePolicy::Deny) - .with_file_filter("*.txt"), - ); + evaluator.add_rule(PolicyRule::glob("todo!()", CodePolicy::Deny).with_file_filter("*.txt")); let code = "fn main() { todo!() }"; let results = evaluator.evaluate_file("src/main.rs", code); @@ -988,8 +979,7 @@ fn main() { // Allow println! in main evaluator.add_rule( - PolicyRule::glob("println!", CodePolicy::Allow) - .with_file_filter("src/main.rs"), + PolicyRule::glob("println!", CodePolicy::Allow).with_file_filter("src/main.rs"), ); let code = r#" @@ -1006,10 +996,12 @@ fn main() { // Should have results for unwrap (deny) and TODO (suppress) assert!(results.len() >= 2); - let deny_results: Vec<_> = results.iter() + let deny_results: Vec<_> = results + .iter() .filter(|r| r.policy == CodePolicy::Deny) .collect(); - let suppress_results: Vec<_> = results.iter() + let suppress_results: Vec<_> = results + .iter() .filter(|r| r.policy == CodePolicy::Suppress) .collect(); @@ -1033,8 +1025,7 @@ fn main() { fn workflow_file_filter_excludes_tests() { let mut evaluator = PolicyEvaluator::new(); evaluator.add_rule( - PolicyRule::glob("todo!()", CodePolicy::Deny) - .with_file_filter("src/**/*.rs"), + PolicyRule::glob("todo!()", CodePolicy::Deny).with_file_filter("src/**/*.rs"), ); let code = "fn test() { todo!() }"; @@ -1170,7 +1161,8 @@ mod serde_tests { rule, vec![Match::new(0, 4, 1, "test".to_string())], CodePolicy::Deny, - ).with_file_path("test.rs"); + ) + .with_file_path("test.rs"); assert!(result.has_matches()); } } diff --git a/crates/lintdiff-code-url/src/lib.rs b/crates/lintdiff-code-url/src/lib.rs index 77f68ca..c256e1e 100644 --- a/crates/lintdiff-code-url/src/lib.rs +++ b/crates/lintdiff-code-url/src/lib.rs @@ -22,7 +22,6 @@ //! assert_eq!(url, "https://github.com/user/repo/blob/main/src/lib.rs#L42"); //! ``` - /// Configuration for generating source code URLs. #[derive(Debug, Clone)] pub struct CodeUrlConfig { @@ -81,7 +80,8 @@ impl CodeUrlConfig { /// ``` #[must_use] pub fn detect_provider(&self) -> UrlProvider { - self.provider.unwrap_or_else(|| UrlProvider::from_url(&self.base_url)) + self.provider + .unwrap_or_else(|| UrlProvider::from_url(&self.base_url)) } /// Generate a URL to a specific file and line. @@ -374,11 +374,8 @@ impl CodeUrlBuilder { #[must_use] pub fn github(owner: &str, repo: &str, git_ref: &str) -> Self { Self { - config: CodeUrlConfig::new( - format!("https://github.com/{owner}/{repo}"), - git_ref, - ) - .with_provider(UrlProvider::GitHub), + config: CodeUrlConfig::new(format!("https://github.com/{owner}/{repo}"), git_ref) + .with_provider(UrlProvider::GitHub), } } @@ -395,11 +392,8 @@ impl CodeUrlBuilder { #[must_use] pub fn gitlab(owner: &str, repo: &str, git_ref: &str) -> Self { Self { - config: CodeUrlConfig::new( - format!("https://gitlab.com/{owner}/{repo}"), - git_ref, - ) - .with_provider(UrlProvider::GitLab), + config: CodeUrlConfig::new(format!("https://gitlab.com/{owner}/{repo}"), git_ref) + .with_provider(UrlProvider::GitLab), } } @@ -416,11 +410,8 @@ impl CodeUrlBuilder { #[must_use] pub fn bitbucket(owner: &str, repo: &str, git_ref: &str) -> Self { Self { - config: CodeUrlConfig::new( - format!("https://bitbucket.org/{owner}/{repo}"), - git_ref, - ) - .with_provider(UrlProvider::Bitbucket), + config: CodeUrlConfig::new(format!("https://bitbucket.org/{owner}/{repo}"), git_ref) + .with_provider(UrlProvider::Bitbucket), } } @@ -580,8 +571,17 @@ mod tests { #[test] fn test_add_line_fragment() { - assert_eq!(add_line_fragment("http://example.com", None, None), "http://example.com"); - assert_eq!(add_line_fragment("http://example.com", Some(42), None), "http://example.com#L42"); - assert_eq!(add_line_fragment("http://example.com", Some(10), Some(20)), "http://example.com#L10-L20"); + assert_eq!( + add_line_fragment("http://example.com", None, None), + "http://example.com" + ); + assert_eq!( + add_line_fragment("http://example.com", Some(42), None), + "http://example.com#L42" + ); + assert_eq!( + add_line_fragment("http://example.com", Some(10), Some(20)), + "http://example.com#L10-L20" + ); } } diff --git a/crates/lintdiff-code-url/tests/code_url_tests.rs b/crates/lintdiff-code-url/tests/code_url_tests.rs index addcac7..32f237f 100644 --- a/crates/lintdiff-code-url/tests/code_url_tests.rs +++ b/crates/lintdiff-code-url/tests/code_url_tests.rs @@ -36,14 +36,20 @@ mod github_tests { fn github_file_url_with_line_range() { let config = CodeUrlConfig::new("https://github.com/user/repo", "main"); let url = config.file_url("src/lib.rs", Some(10), Some(20)); - assert_eq!(url, "https://github.com/user/repo/blob/main/src/lib.rs#L10-L20"); + assert_eq!( + url, + "https://github.com/user/repo/blob/main/src/lib.rs#L10-L20" + ); } #[test] fn github_file_url_with_commit_sha() { let config = CodeUrlConfig::new("https://github.com/user/repo", "abc123def456"); let url = config.file_url("src/lib.rs", Some(1), None); - assert_eq!(url, "https://github.com/user/repo/blob/abc123def456/src/lib.rs#L1"); + assert_eq!( + url, + "https://github.com/user/repo/blob/abc123def456/src/lib.rs#L1" + ); } #[test] @@ -67,21 +73,30 @@ mod github_tests { fn github_builder_file_url() { let builder = CodeUrlBuilder::github("owner", "repo", "develop"); let url = builder.file_url("src/main.rs"); - assert_eq!(url, "https://github.com/owner/repo/blob/develop/src/main.rs"); + assert_eq!( + url, + "https://github.com/owner/repo/blob/develop/src/main.rs" + ); } #[test] fn github_builder_line_url() { let builder = CodeUrlBuilder::github("owner", "repo", "main"); let url = builder.line_url("src/lib.rs", 42); - assert_eq!(url, "https://github.com/owner/repo/blob/main/src/lib.rs#L42"); + assert_eq!( + url, + "https://github.com/owner/repo/blob/main/src/lib.rs#L42" + ); } #[test] fn github_builder_range_url() { let builder = CodeUrlBuilder::github("owner", "repo", "main"); let url = builder.range_url("src/lib.rs", 10, 20); - assert_eq!(url, "https://github.com/owner/repo/blob/main/src/lib.rs#L10-L20"); + assert_eq!( + url, + "https://github.com/owner/repo/blob/main/src/lib.rs#L10-L20" + ); } #[test] @@ -104,7 +119,10 @@ mod github_tests { let builder = CodeUrlBuilder::github("user", "repo", "main"); let location = CodeLocation::file("src/lib.rs").with_line_range(5, 15); let url = builder.url(&location); - assert_eq!(url, "https://github.com/user/repo/blob/main/src/lib.rs#L5-L15"); + assert_eq!( + url, + "https://github.com/user/repo/blob/main/src/lib.rs#L5-L15" + ); } } @@ -126,21 +144,30 @@ mod gitlab_tests { fn gitlab_file_url_with_line() { let config = CodeUrlConfig::new("https://gitlab.com/user/repo", "main"); let url = config.file_url("src/lib.rs", Some(42), None); - assert_eq!(url, "https://gitlab.com/user/repo/-/blob/main/src/lib.rs#L42"); + assert_eq!( + url, + "https://gitlab.com/user/repo/-/blob/main/src/lib.rs#L42" + ); } #[test] fn gitlab_file_url_with_line_range() { let config = CodeUrlConfig::new("https://gitlab.com/user/repo", "main"); let url = config.file_url("src/lib.rs", Some(10), Some(20)); - assert_eq!(url, "https://gitlab.com/user/repo/-/blob/main/src/lib.rs#L10-L20"); + assert_eq!( + url, + "https://gitlab.com/user/repo/-/blob/main/src/lib.rs#L10-L20" + ); } #[test] fn gitlab_file_url_with_tag() { let config = CodeUrlConfig::new("https://gitlab.com/user/repo", "v1.0.0"); let url = config.file_url("src/lib.rs", Some(1), None); - assert_eq!(url, "https://gitlab.com/user/repo/-/blob/v1.0.0/src/lib.rs#L1"); + assert_eq!( + url, + "https://gitlab.com/user/repo/-/blob/v1.0.0/src/lib.rs#L1" + ); } #[test] @@ -154,21 +181,30 @@ mod gitlab_tests { fn gitlab_builder_file_url() { let builder = CodeUrlBuilder::gitlab("owner", "repo", "develop"); let url = builder.file_url("src/main.rs"); - assert_eq!(url, "https://gitlab.com/owner/repo/-/blob/develop/src/main.rs"); + assert_eq!( + url, + "https://gitlab.com/owner/repo/-/blob/develop/src/main.rs" + ); } #[test] fn gitlab_builder_line_url() { let builder = CodeUrlBuilder::gitlab("owner", "repo", "main"); let url = builder.line_url("src/lib.rs", 42); - assert_eq!(url, "https://gitlab.com/owner/repo/-/blob/main/src/lib.rs#L42"); + assert_eq!( + url, + "https://gitlab.com/owner/repo/-/blob/main/src/lib.rs#L42" + ); } #[test] fn gitlab_builder_range_url() { let builder = CodeUrlBuilder::gitlab("owner", "repo", "main"); let url = builder.range_url("src/lib.rs", 10, 20); - assert_eq!(url, "https://gitlab.com/owner/repo/-/blob/main/src/lib.rs#L10-L20"); + assert_eq!( + url, + "https://gitlab.com/owner/repo/-/blob/main/src/lib.rs#L10-L20" + ); } #[test] @@ -183,7 +219,10 @@ mod gitlab_tests { let builder = CodeUrlBuilder::gitlab("user", "repo", "main"); let location = CodeLocation::file("src/lib.rs").with_line(42); let url = builder.url(&location); - assert_eq!(url, "https://gitlab.com/user/repo/-/blob/main/src/lib.rs#L42"); + assert_eq!( + url, + "https://gitlab.com/user/repo/-/blob/main/src/lib.rs#L42" + ); } } @@ -205,7 +244,10 @@ mod bitbucket_tests { fn bitbucket_file_url_with_line() { let config = CodeUrlConfig::new("https://bitbucket.org/user/repo", "main"); let url = config.file_url("src/lib.rs", Some(42), None); - assert_eq!(url, "https://bitbucket.org/user/repo/src/main/src/lib.rs#lines-42"); + assert_eq!( + url, + "https://bitbucket.org/user/repo/src/main/src/lib.rs#lines-42" + ); } #[test] @@ -239,7 +281,10 @@ mod bitbucket_tests { fn bitbucket_builder_file_url() { let builder = CodeUrlBuilder::bitbucket("owner", "repo", "develop"); let url = builder.file_url("src/main.rs"); - assert_eq!(url, "https://bitbucket.org/owner/repo/src/develop/src/main.rs"); + assert_eq!( + url, + "https://bitbucket.org/owner/repo/src/develop/src/main.rs" + ); } #[test] @@ -290,8 +335,7 @@ mod azure_devops_tests { #[test] fn azure_file_url_no_line() { - let config = - CodeUrlConfig::new("https://dev.azure.com/org/project/_git/repo", "main"); + let config = CodeUrlConfig::new("https://dev.azure.com/org/project/_git/repo", "main"); let url = config.file_url("src/lib.rs", None, None); assert_eq!( url, @@ -301,8 +345,7 @@ mod azure_devops_tests { #[test] fn azure_file_url_with_line() { - let config = - CodeUrlConfig::new("https://dev.azure.com/org/project/_git/repo", "main"); + let config = CodeUrlConfig::new("https://dev.azure.com/org/project/_git/repo", "main"); let url = config.file_url("src/lib.rs", Some(42), None); assert_eq!( url, @@ -312,8 +355,7 @@ mod azure_devops_tests { #[test] fn azure_file_url_with_line_range() { - let config = - CodeUrlConfig::new("https://dev.azure.com/org/project/_git/repo", "main"); + let config = CodeUrlConfig::new("https://dev.azure.com/org/project/_git/repo", "main"); let url = config.file_url("src/lib.rs", Some(10), Some(20)); assert_eq!( url, @@ -323,8 +365,7 @@ mod azure_devops_tests { #[test] fn azure_commit_url() { - let config = - CodeUrlConfig::new("https://dev.azure.com/org/project/_git/repo", "main"); + let config = CodeUrlConfig::new("https://dev.azure.com/org/project/_git/repo", "main"); let url = config.commit_url("abc123def456"); assert_eq!( url, @@ -495,7 +536,9 @@ mod code_location_tests { #[test] fn code_location_with_column() { - let location = CodeLocation::file("src/lib.rs").with_line(42).with_column(5); + let location = CodeLocation::file("src/lib.rs") + .with_line(42) + .with_column(5); assert_eq!(location.path, "src/lib.rs"); assert_eq!(location.line, Some(42)); assert_eq!(location.column, Some(5)); @@ -557,7 +600,10 @@ mod edge_case_tests { // Even though URL looks like GitHub, explicit provider should be used assert_eq!(config.detect_provider(), UrlProvider::GitLab); let url = config.file_url("src/lib.rs", Some(42), None); - assert_eq!(url, "https://github.com/user/repo/-/blob/main/src/lib.rs#L42"); + assert_eq!( + url, + "https://github.com/user/repo/-/blob/main/src/lib.rs#L42" + ); } } @@ -572,14 +618,20 @@ mod additional_tests { fn github_with_tag_ref() { let config = CodeUrlConfig::new("https://github.com/user/repo", "v2.0.0"); let url = config.file_url("src/lib.rs", Some(1), None); - assert_eq!(url, "https://github.com/user/repo/blob/v2.0.0/src/lib.rs#L1"); + assert_eq!( + url, + "https://github.com/user/repo/blob/v2.0.0/src/lib.rs#L1" + ); } #[test] fn gitlab_with_tag_ref() { let config = CodeUrlConfig::new("https://gitlab.com/user/repo", "v2.0.0"); let url = config.file_url("src/lib.rs", Some(1), None); - assert_eq!(url, "https://gitlab.com/user/repo/-/blob/v2.0.0/src/lib.rs#L1"); + assert_eq!( + url, + "https://gitlab.com/user/repo/-/blob/v2.0.0/src/lib.rs#L1" + ); } #[test] @@ -634,8 +686,7 @@ mod additional_tests { #[test] fn special_chars_in_path() { - let config = - CodeUrlConfig::new("https://dev.azure.com/org/project/_git/repo", "main"); + let config = CodeUrlConfig::new("https://dev.azure.com/org/project/_git/repo", "main"); // Azure DevOps uses query params, so path should be URL-encoded (but not slashes) let url = config.file_url("src/my file.rs", None, None); assert_eq!( diff --git a/crates/lintdiff-config-types/tests/config_types_tests.rs b/crates/lintdiff-config-types/tests/config_types_tests.rs index 892e000..c942e94 100644 --- a/crates/lintdiff-config-types/tests/config_types_tests.rs +++ b/crates/lintdiff-config-types/tests/config_types_tests.rs @@ -42,12 +42,18 @@ mod output_format_tests { #[test] fn parse_actions_alias() { - assert_eq!(OutputFormat::parse("actions").unwrap(), OutputFormat::GitHub); + assert_eq!( + OutputFormat::parse("actions").unwrap(), + OutputFormat::GitHub + ); } #[test] fn parse_markdown_format() { - assert_eq!(OutputFormat::parse("markdown").unwrap(), OutputFormat::Markdown); + assert_eq!( + OutputFormat::parse("markdown").unwrap(), + OutputFormat::Markdown + ); } #[test] @@ -59,7 +65,10 @@ mod output_format_tests { fn parse_case_insensitive() { assert_eq!(OutputFormat::parse("JSON").unwrap(), OutputFormat::Json); assert_eq!(OutputFormat::parse("Text").unwrap(), OutputFormat::Text); - assert_eq!(OutputFormat::parse("MARKDOWN").unwrap(), OutputFormat::Markdown); + assert_eq!( + OutputFormat::parse("MARKDOWN").unwrap(), + OutputFormat::Markdown + ); } #[test] diff --git a/crates/lintdiff-config/tests/config_tests.rs b/crates/lintdiff-config/tests/config_tests.rs index 0b91d9d..2df9f64 100644 --- a/crates/lintdiff-config/tests/config_tests.rs +++ b/crates/lintdiff-config/tests/config_tests.rs @@ -96,14 +96,8 @@ fn test_output_format_default_is_json() { #[test] fn test_output_format_from_str_valid() { - assert_eq!( - "json".parse::().unwrap(), - OutputFormat::Json - ); - assert_eq!( - "JSON".parse::().unwrap(), - OutputFormat::Json - ); + assert_eq!("json".parse::().unwrap(), OutputFormat::Json); + assert_eq!("JSON".parse::().unwrap(), OutputFormat::Json); assert_eq!( "markdown".parse::().unwrap(), diff --git a/crates/lintdiff-counts/src/lib.rs b/crates/lintdiff-counts/src/lib.rs index 86b194d..dbb6bd2 100644 --- a/crates/lintdiff-counts/src/lib.rs +++ b/crates/lintdiff-counts/src/lib.rs @@ -37,7 +37,13 @@ impl SeverityCounts { /// Create counts from individual values. #[must_use] - pub const fn from_values(hints: u64, notes: u64, warnings: u64, errors: u64, fatals: u64) -> Self { + pub const fn from_values( + hints: u64, + notes: u64, + warnings: u64, + errors: u64, + fatals: u64, + ) -> Self { Self { hints, notes, @@ -187,7 +193,10 @@ impl FileCounts { /// Increment a severity for a file. pub fn increment(&mut self, path: impl Into, severity: SeverityLevel) { self.total.increment(severity); - self.by_file.entry(path.into()).or_default().increment(severity); + self.by_file + .entry(path.into()) + .or_default() + .increment(severity); } /// Get counts for a specific file. @@ -654,7 +663,10 @@ mod tests { summary.record("a.rs", "cat1", SeverityLevel::Hint); summary.record("b.rs", "cat2", SeverityLevel::Error); let s = format!("{summary}"); - assert_eq!(s, "2 files, 2 categories, 1 hints, 0 notes, 0 warnings, 1 errors, 0 fatals"); + assert_eq!( + s, + "2 files, 2 categories, 1 hints, 0 notes, 0 warnings, 1 errors, 0 fatals" + ); } #[test] @@ -789,7 +801,7 @@ mod tests { let mut fc = FileCounts::new(); fc.add_file("a.rs", SeverityCounts::from_values(1, 2, 3, 4, 5)); fc.add_file("b.rs", SeverityCounts::from_values(2, 3, 4, 5, 6)); - + let total = fc.total(); assert_eq!(total.hints, 3); assert_eq!(total.notes, 5); @@ -803,7 +815,7 @@ mod tests { let mut cc = CategoryCounts::new(); cc.add_category("cat1", SeverityCounts::from_values(1, 2, 3, 4, 5)); cc.add_category("cat2", SeverityCounts::from_values(2, 3, 4, 5, 6)); - + let total = cc.total(); assert_eq!(total.hints, 3); assert_eq!(total.notes, 5); @@ -820,7 +832,7 @@ mod tests { counts.increment(SeverityLevel::Warning); counts.increment(SeverityLevel::Error); counts.increment(SeverityLevel::Fatal); - + assert_eq!(counts.hints, 1); assert_eq!(counts.notes, 1); assert_eq!(counts.warnings, 1); @@ -835,7 +847,7 @@ mod tests { fc.increment("a.rs", SeverityLevel::Hint); fc.increment("a.rs", SeverityLevel::Warning); fc.increment("a.rs", SeverityLevel::Error); - + assert_eq!(fc.file_count(), 1); let counts = fc.get("a.rs").expect("should exist"); assert_eq!(counts.hints, 1); @@ -850,7 +862,7 @@ mod tests { cc.increment("cat", SeverityLevel::Hint); cc.increment("cat", SeverityLevel::Warning); cc.increment("cat", SeverityLevel::Error); - + assert_eq!(cc.category_count(), 1); let counts = cc.get("cat").expect("should exist"); assert_eq!(counts.hints, 1); @@ -864,11 +876,11 @@ mod tests { let mut summary = CountSummary::new(); summary.record("a.rs", "cat1", SeverityLevel::Hint); summary.record("a.rs", "cat2", SeverityLevel::Warning); - + assert_eq!(summary.total(), 2); assert_eq!(summary.by_file.file_count(), 1); assert_eq!(summary.by_category.category_count(), 2); - + let file_counts = summary.by_file.get("a.rs").expect("should exist"); assert_eq!(file_counts.total(), 2); } @@ -879,12 +891,12 @@ mod tests { let counts = SeverityCounts::from_values(1, 1, 1, 1, 0); let rate = counts.pass_rate().expect("pass rate should exist"); assert!((rate - 0.5).abs() < f64::EPSILON); - + // 25% pass rate: 1 non-problem out of 4 total let counts2 = SeverityCounts::from_values(1, 0, 1, 1, 1); let rate2 = counts2.pass_rate().expect("pass rate should exist"); assert!((rate2 - 0.25).abs() < f64::EPSILON); - + // 75% pass rate: 3 non-problems out of 4 total let counts3 = SeverityCounts::from_values(2, 1, 1, 0, 0); let rate3 = counts3.pass_rate().expect("pass rate should exist"); diff --git a/crates/lintdiff-counts/tests/counts_tests.rs b/crates/lintdiff-counts/tests/counts_tests.rs index ab8619d..40b3c17 100644 --- a/crates/lintdiff-counts/tests/counts_tests.rs +++ b/crates/lintdiff-counts/tests/counts_tests.rs @@ -47,7 +47,13 @@ fn severity_counts_total_sums_all_fields() { #[test] fn severity_counts_total_handles_large_values() { - let counts = SeverityCounts::from_values(u64::MAX / 5, u64::MAX / 5, u64::MAX / 5, u64::MAX / 5, u64::MAX / 5); + let counts = SeverityCounts::from_values( + u64::MAX / 5, + u64::MAX / 5, + u64::MAX / 5, + u64::MAX / 5, + u64::MAX / 5, + ); assert!(counts.total() > 0); } @@ -290,7 +296,7 @@ fn file_counts_multiple_files_with_different_counts() { fc.add_file("a.rs", SeverityCounts::from_values(1, 0, 0, 0, 0)); fc.add_file("b.rs", SeverityCounts::from_values(0, 2, 0, 0, 0)); fc.add_file("c.rs", SeverityCounts::from_values(0, 0, 3, 0, 0)); - + assert_eq!(fc.file_count(), 3); assert_eq!(fc.total().hints, 1); assert_eq!(fc.total().notes, 2); @@ -392,7 +398,7 @@ fn category_counts_multiple_categories_with_different_counts() { cc.add_category("cat1", SeverityCounts::from_values(1, 0, 0, 0, 0)); cc.add_category("cat2", SeverityCounts::from_values(0, 2, 0, 0, 0)); cc.add_category("cat3", SeverityCounts::from_values(0, 0, 3, 0, 0)); - + assert_eq!(cc.category_count(), 3); assert_eq!(cc.total().hints, 1); assert_eq!(cc.total().notes, 2); @@ -446,18 +452,21 @@ fn count_summary_record_increases_total() { fn count_summary_record_updates_all_components() { let mut summary = CountSummary::new(); summary.record("a.rs", "cat", SeverityLevel::Error); - + // Check severity counts assert_eq!(summary.severity.errors, 1); - + // Check file counts assert_eq!(summary.by_file.file_count(), 1); let file_counts = summary.by_file.get("a.rs").expect("file should exist"); assert_eq!(file_counts.errors, 1); - + // Check category counts assert_eq!(summary.by_category.category_count(), 1); - let cat_counts = summary.by_category.get("cat").expect("category should exist"); + let cat_counts = summary + .by_category + .get("cat") + .expect("category should exist"); assert_eq!(cat_counts.errors, 1); } @@ -466,7 +475,7 @@ fn count_summary_record_multiple_same_file() { let mut summary = CountSummary::new(); summary.record("a.rs", "cat1", SeverityLevel::Hint); summary.record("a.rs", "cat2", SeverityLevel::Warning); - + assert_eq!(summary.total(), 2); assert_eq!(summary.by_file.file_count(), 1); assert_eq!(summary.by_category.category_count(), 2); @@ -498,12 +507,12 @@ fn count_summary_has_blocking_false_with_only_warnings() { fn count_summary_merge_combines_all_data() { let mut a = CountSummary::new(); a.record("a.rs", "cat1", SeverityLevel::Hint); - + let mut b = CountSummary::new(); b.record("b.rs", "cat2", SeverityLevel::Error); - + a.merge(b); - + assert_eq!(a.total(), 2); assert_eq!(a.by_file.file_count(), 2); assert_eq!(a.by_category.category_count(), 2); @@ -514,12 +523,12 @@ fn count_summary_merge_combines_all_data() { fn count_summary_merge_same_file_accumulates() { let mut a = CountSummary::new(); a.record("a.rs", "cat1", SeverityLevel::Hint); - + let mut b = CountSummary::new(); b.record("a.rs", "cat2", SeverityLevel::Error); - + a.merge(b); - + assert_eq!(a.by_file.file_count(), 1); let file_counts = a.by_file.get("a.rs").expect("file should exist"); assert_eq!(file_counts.hints, 1); @@ -549,16 +558,22 @@ fn count_summary_display_formats_correctly() { let mut summary = CountSummary::new(); summary.record("a.rs", "cat1", SeverityLevel::Hint); summary.record("b.rs", "cat2", SeverityLevel::Error); - + let s = format!("{summary}"); - assert_eq!(s, "2 files, 2 categories, 1 hints, 0 notes, 0 warnings, 1 errors, 0 fatals"); + assert_eq!( + s, + "2 files, 2 categories, 1 hints, 0 notes, 0 warnings, 1 errors, 0 fatals" + ); } #[test] fn count_summary_display_empty() { let summary = CountSummary::new(); let s = format!("{summary}"); - assert_eq!(s, "0 files, 0 categories, 0 hints, 0 notes, 0 warnings, 0 errors, 0 fatals"); + assert_eq!( + s, + "0 files, 0 categories, 0 hints, 0 notes, 0 warnings, 0 errors, 0 fatals" + ); } #[test] @@ -595,7 +610,7 @@ fn severity_level_equality() { assert_eq!(SeverityLevel::Warning, SeverityLevel::Warning); assert_eq!(SeverityLevel::Error, SeverityLevel::Error); assert_eq!(SeverityLevel::Fatal, SeverityLevel::Fatal); - + assert_ne!(SeverityLevel::Hint, SeverityLevel::Note); assert_ne!(SeverityLevel::Warning, SeverityLevel::Error); } @@ -605,7 +620,7 @@ fn severity_counts_equality() { let a = SeverityCounts::from_values(1, 2, 3, 4, 5); let b = SeverityCounts::from_values(1, 2, 3, 4, 5); let c = SeverityCounts::from_values(5, 4, 3, 2, 1); - + assert_eq!(a, b); assert_ne!(a, c); } @@ -655,15 +670,24 @@ fn large_counts_handling() { #[test] fn file_counts_with_path_containing_special_chars() { let mut fc = FileCounts::new(); - fc.add_file("src/path/with spaces/file.rs", SeverityCounts::from_values(1, 0, 0, 0, 0)); - fc.add_file("src/unicode/日本語.rs", SeverityCounts::from_values(1, 0, 0, 0, 0)); + fc.add_file( + "src/path/with spaces/file.rs", + SeverityCounts::from_values(1, 0, 0, 0, 0), + ); + fc.add_file( + "src/unicode/日本語.rs", + SeverityCounts::from_values(1, 0, 0, 0, 0), + ); assert_eq!(fc.file_count(), 2); } #[test] fn category_counts_with_special_names() { let mut cc = CategoryCounts::new(); - cc.add_category("clippy::result_unit_err", SeverityCounts::from_values(1, 0, 0, 0, 0)); + cc.add_category( + "clippy::result_unit_err", + SeverityCounts::from_values(1, 0, 0, 0, 0), + ); cc.add_category("rustc::E0433", SeverityCounts::from_values(0, 1, 0, 0, 0)); assert_eq!(cc.category_count(), 2); } @@ -671,7 +695,7 @@ fn category_counts_with_special_names() { #[test] fn count_summary_complex_scenario() { let mut summary = CountSummary::new(); - + // Record multiple findings across files and categories summary.record("src/main.rs", "clippy::style", SeverityLevel::Warning); summary.record("src/main.rs", "clippy::style", SeverityLevel::Warning); @@ -679,7 +703,7 @@ fn count_summary_complex_scenario() { summary.record("src/lib.rs", "rustc::unused", SeverityLevel::Warning); summary.record("src/lib.rs", "rustc::unused", SeverityLevel::Hint); summary.record("src/utils.rs", "clippy::perf", SeverityLevel::Fatal); - + assert_eq!(summary.total(), 6); assert_eq!(summary.by_file.file_count(), 3); assert_eq!(summary.by_category.category_count(), 4); @@ -694,23 +718,23 @@ fn count_summary_complex_scenario() { fn count_summary_merge_empty() { let mut a = CountSummary::new(); a.record("a.rs", "cat", SeverityLevel::Hint); - + let b = CountSummary::new(); - + a.merge(b); - + assert_eq!(a.total(), 1); } #[test] fn count_summary_merge_into_empty() { let mut a = CountSummary::new(); - + let mut b = CountSummary::new(); b.record("b.rs", "cat", SeverityLevel::Error); - + a.merge(b); - + assert_eq!(a.total(), 1); assert!(a.has_blocking()); } @@ -722,7 +746,7 @@ fn file_counts_increment_multiple_severities() { fc.increment("a.rs", SeverityLevel::Hint); fc.increment("a.rs", SeverityLevel::Warning); fc.increment("a.rs", SeverityLevel::Error); - + let counts = fc.get("a.rs").expect("file should exist"); assert_eq!(counts.hints, 2); assert_eq!(counts.warnings, 1); @@ -737,7 +761,7 @@ fn category_counts_increment_multiple_severities() { cc.increment("cat", SeverityLevel::Note); cc.increment("cat", SeverityLevel::Warning); cc.increment("cat", SeverityLevel::Fatal); - + let counts = cc.get("cat").expect("category should exist"); assert_eq!(counts.notes, 2); assert_eq!(counts.warnings, 1); @@ -761,7 +785,7 @@ fn pass_rate_precision() { let counts = SeverityCounts::from_values(3, 1, 0, 0, 0); // 4/4 = 1.0 let rate = counts.pass_rate().expect("should have rate"); assert!((rate - 1.0).abs() < f64::EPSILON); - + let counts2 = SeverityCounts::from_values(1, 1, 1, 1, 0); // 2/4 = 0.5 let rate2 = counts2.pass_rate().expect("should have rate"); assert!((rate2 - 0.5).abs() < f64::EPSILON); diff --git a/crates/lintdiff-diagnostic-level/src/lib.rs b/crates/lintdiff-diagnostic-level/src/lib.rs index d55adf2..678ca28 100644 --- a/crates/lintdiff-diagnostic-level/src/lib.rs +++ b/crates/lintdiff-diagnostic-level/src/lib.rs @@ -599,8 +599,7 @@ impl DiagnosticLevelParser { /// assert_eq!(parser.parse("severe"), DiagnosticLevel::Error); /// ``` pub fn with_custom_mapping(&mut self, from: &str, to: DiagnosticLevel) -> &mut Self { - self.custom_mappings - .insert(from.to_lowercase(), to); + self.custom_mappings.insert(from.to_lowercase(), to); self } @@ -623,12 +622,12 @@ impl DiagnosticLevelParser { #[must_use] pub fn parse(&self, s: &str) -> DiagnosticLevel { let lower = s.to_lowercase(); - + // Check custom mappings first if let Some(&level) = self.custom_mappings.get(&lower) { return level; } - + // Fall back to default parsing parse_level(s) } diff --git a/crates/lintdiff-diagnostic-level/tests/diagnostic_level_tests.rs b/crates/lintdiff-diagnostic-level/tests/diagnostic_level_tests.rs index dd2991b..a852717 100644 --- a/crates/lintdiff-diagnostic-level/tests/diagnostic_level_tests.rs +++ b/crates/lintdiff-diagnostic-level/tests/diagnostic_level_tests.rs @@ -357,32 +357,50 @@ mod canonical_severity_conversion { #[test] fn hint_to_canonical_is_info() { - assert_eq!(to_canonical(&DiagnosticLevel::Hint), CanonicalSeverity::Info); + assert_eq!( + to_canonical(&DiagnosticLevel::Hint), + CanonicalSeverity::Info + ); } #[test] fn note_to_canonical_is_info() { - assert_eq!(to_canonical(&DiagnosticLevel::Note), CanonicalSeverity::Info); + assert_eq!( + to_canonical(&DiagnosticLevel::Note), + CanonicalSeverity::Info + ); } #[test] fn warning_to_canonical_is_warning() { - assert_eq!(to_canonical(&DiagnosticLevel::Warning), CanonicalSeverity::Warning); + assert_eq!( + to_canonical(&DiagnosticLevel::Warning), + CanonicalSeverity::Warning + ); } #[test] fn error_to_canonical_is_error() { - assert_eq!(to_canonical(&DiagnosticLevel::Error), CanonicalSeverity::Error); + assert_eq!( + to_canonical(&DiagnosticLevel::Error), + CanonicalSeverity::Error + ); } #[test] fn fatal_to_canonical_is_error() { - assert_eq!(to_canonical(&DiagnosticLevel::Fatal), CanonicalSeverity::Error); + assert_eq!( + to_canonical(&DiagnosticLevel::Fatal), + CanonicalSeverity::Error + ); } #[test] fn unknown_to_canonical_is_unknown() { - assert_eq!(to_canonical(&DiagnosticLevel::Unknown), CanonicalSeverity::Unknown); + assert_eq!( + to_canonical(&DiagnosticLevel::Unknown), + CanonicalSeverity::Unknown + ); } #[test] @@ -660,10 +678,7 @@ mod edge_cases { fn diagnostic_level_parse_returns_error_for_invalid() { let result = DiagnosticLevel::parse("invalid"); assert!(result.is_err()); - assert_eq!( - result.unwrap_err().input(), - "invalid" - ); + assert_eq!(result.unwrap_err().input(), "invalid"); } #[test] diff --git a/crates/lintdiff-diff-paths/src/lib.rs b/crates/lintdiff-diff-paths/src/lib.rs index 4d6b199..0d32b09 100644 --- a/crates/lintdiff-diff-paths/src/lib.rs +++ b/crates/lintdiff-diff-paths/src/lib.rs @@ -426,9 +426,7 @@ impl DiffPaths { #[must_use] pub fn is_rename(&self) -> bool { match (self.old_path_normalized(), self.new_path_normalized()) { - (Some(old), Some(new)) => { - !is_dev_null(old) && !is_dev_null(new) && old != new - } + (Some(old), Some(new)) => !is_dev_null(old) && !is_dev_null(new) && old != new, _ => false, } } @@ -449,9 +447,7 @@ impl DiffPaths { #[must_use] pub fn is_modification(&self) -> bool { match (self.old_path_normalized(), self.new_path_normalized()) { - (Some(old), Some(new)) => { - !is_dev_null(old) && !is_dev_null(new) && old == new - } + (Some(old), Some(new)) => !is_dev_null(old) && !is_dev_null(new) && old == new, _ => false, } } @@ -530,8 +526,14 @@ impl DiffPaths { #[must_use] pub fn strip_diff_prefixes(&self) -> Self { Self { - old_path: self.old_path.as_ref().map(|p| normalize_path(p).into_owned()), - new_path: self.new_path.as_ref().map(|p| normalize_path(p).into_owned()), + old_path: self + .old_path + .as_ref() + .map(|p| normalize_path(p).into_owned()), + new_path: self + .new_path + .as_ref() + .map(|p| normalize_path(p).into_owned()), old_timestamp: self.old_timestamp.clone(), new_timestamp: self.new_timestamp.clone(), } @@ -582,7 +584,7 @@ impl DiffPaths { #[must_use] pub fn matches_path(&self, pattern: &str) -> bool { let normalized_pattern = strip_diff_prefix(pattern); - + self.old_path_normalized() == Some(normalized_pattern) || self.new_path_normalized() == Some(normalized_pattern) } @@ -602,7 +604,8 @@ impl DiffPaths { pub fn path_ends_with(&self, suffix: &str) -> bool { self.old_path_normalized() .is_some_and(|p| p.ends_with(suffix)) - || self.new_path_normalized() + || self + .new_path_normalized() .is_some_and(|p| p.ends_with(suffix)) } } @@ -631,7 +634,7 @@ pub fn strip_diff_prefix(path: &str) -> &str { if is_dev_null(path) { return path; } - + // Strip diff prefixes (a/, b/, i/) from the start of the path // Only strip once to avoid over-stripping paths like "a/a/b" path.strip_prefix("a/") @@ -677,18 +680,18 @@ pub fn normalize_path(path: &str) -> std::borrow::Cow<'_, str> { if is_dev_null(path) { return std::borrow::Cow::Borrowed(path); } - + // First convert backslashes to forward slashes let converted = if path.contains('\\') { std::borrow::Cow::Owned(path.replace('\\', "/")) } else { std::borrow::Cow::Borrowed(path) }; - + // Then strip diff prefixes recursively until none remain let mut stripped = strip_diff_prefix(&converted); let mut prev_len = converted.len(); - + loop { let next = strip_diff_prefix(stripped); if next.len() >= prev_len { @@ -698,7 +701,7 @@ pub fn normalize_path(path: &str) -> std::borrow::Cow<'_, str> { prev_len = stripped.len(); stripped = next; } - + if stripped.len() == converted.len() { // No prefix was stripped, return the converted version converted @@ -734,12 +737,12 @@ fn split_path_and_timestamp(s: &str) -> (&str, Option<&str>) { if let Some(idx) = s.find('\t') { return (&s[..idx], Some(&s[idx + 1..])); } - + // Then try double-space separated (some formats use this) if let Some(idx) = s.find(" ") { return (&s[..idx], Some(s[idx + 2..].trim())); } - + (s, None) } @@ -940,7 +943,7 @@ mod tests { fn test_diff_paths_parse_standard() { let header = "--- a/src/lib.rs\n+++ b/src/lib.rs\n"; let paths = DiffPaths::parse(header).unwrap().unwrap(); - + assert_eq!(paths.old_path, Some("a/src/lib.rs".to_string())); assert_eq!(paths.new_path, Some("b/src/lib.rs".to_string())); assert!(paths.is_modification()); @@ -950,7 +953,7 @@ mod tests { fn test_diff_paths_parse_creation() { let header = "--- /dev/null\n+++ b/new_file.rs\n"; let paths = DiffPaths::parse(header).unwrap().unwrap(); - + assert!(paths.is_creation()); assert_eq!(paths.canonical_path(), Some("b/new_file.rs")); } @@ -959,7 +962,7 @@ mod tests { fn test_diff_paths_parse_deletion() { let header = "--- a/old_file.rs\n+++ /dev/null\n"; let paths = DiffPaths::parse(header).unwrap().unwrap(); - + assert!(paths.is_deletion()); assert_eq!(paths.canonical_path(), Some("a/old_file.rs")); } @@ -982,7 +985,7 @@ mod tests { .unwrap() .unwrap(); let stripped = paths.strip_prefix("a/"); - + assert_eq!(stripped.old_path, Some("src/lib.rs".to_string())); // b/ prefix not stripped since we only asked for a/ assert_eq!(stripped.new_path, Some("b/src/lib.rs".to_string())); @@ -994,7 +997,7 @@ mod tests { .unwrap() .unwrap(); let normalized = paths.strip_diff_prefixes(); - + assert_eq!(normalized.old_path, Some("src/lib.rs".to_string())); assert_eq!(normalized.new_path, Some("src/lib.rs".to_string())); } @@ -1003,7 +1006,7 @@ mod tests { fn test_parse_with_timestamp() { let header = "--- a/file.rs\t2024-01-01 12:00:00\n+++ b/file.rs\t2024-01-02 13:00:00\n"; let paths = DiffPaths::parse(header).unwrap().unwrap(); - + assert_eq!(paths.old_timestamp, Some("2024-01-01 12:00:00".to_string())); assert_eq!(paths.new_timestamp, Some("2024-01-02 13:00:00".to_string())); } @@ -1012,7 +1015,7 @@ mod tests { fn test_error_display() { let err = DiffPathsError::new("test error"); assert_eq!(format!("{}", err), "test error"); - + let err_with_line = DiffPathsError::with_line("test error", "bad line"); assert_eq!(format!("{}", err_with_line), "test error: \"bad line\""); } diff --git a/crates/lintdiff-diff-paths/tests/diff_paths_tests.rs b/crates/lintdiff-diff-paths/tests/diff_paths_tests.rs index a791231..03786a7 100644 --- a/crates/lintdiff-diff-paths/tests/diff_paths_tests.rs +++ b/crates/lintdiff-diff-paths/tests/diff_paths_tests.rs @@ -142,7 +142,10 @@ mod strip_diff_prefix_tests { #[test] fn nested_paths() { - assert_eq!(strip_diff_prefix("a/deep/nested/path.rs"), "deep/nested/path.rs"); + assert_eq!( + strip_diff_prefix("a/deep/nested/path.rs"), + "deep/nested/path.rs" + ); } #[test] @@ -713,7 +716,9 @@ mod normalized_paths_tests { #[test] fn normalized_handles_dev_null() { - let paths = DiffPaths::parse("--- /dev/null\n+++ b/new.rs\n").unwrap().unwrap(); + let paths = DiffPaths::parse("--- /dev/null\n+++ b/new.rs\n") + .unwrap() + .unwrap(); assert_eq!(paths.old_path_normalized(), Some("/dev/null")); } @@ -1170,10 +1175,7 @@ mod edge_cases_tests { let header = "--- a/a/b/c/d/e/f/g/h/file.rs\n+++ b/a/b/c/d/e/f/g/h/file.rs\n"; let paths = DiffPaths::parse(header).unwrap().unwrap(); - assert_eq!( - paths.old_path_normalized(), - Some("a/b/c/d/e/f/g/h/file.rs") - ); + assert_eq!(paths.old_path_normalized(), Some("a/b/c/d/e/f/g/h/file.rs")); } #[test] diff --git a/crates/lintdiff-diff-stats/src/lib.rs b/crates/lintdiff-diff-stats/src/lib.rs index ed94187..2485a19 100644 --- a/crates/lintdiff-diff-stats/src/lib.rs +++ b/crates/lintdiff-diff-stats/src/lib.rs @@ -99,7 +99,12 @@ pub struct FileDiffStats { impl FileDiffStats { /// Create new file diff stats. #[must_use] - pub fn new(path: impl Into, lines_added: usize, lines_removed: usize, change_type: ChangeType) -> Self { + pub fn new( + path: impl Into, + lines_added: usize, + lines_removed: usize, + change_type: ChangeType, + ) -> Self { Self { path: path.into(), lines_added, @@ -393,11 +398,16 @@ pub fn format_stats(stats: &DiffStats) -> String { let mut parts = Vec::new(); // Files summary - parts.push(format!("{} file{} changed", stats.files_changed, if stats.files_changed == 1 { "" } else { "s" })); + parts.push(format!( + "{} file{} changed", + stats.files_changed, + if stats.files_changed == 1 { "" } else { "s" } + )); // Line changes if stats.lines_added > 0 || stats.lines_removed > 0 { - parts.push(format!("{} insertion{}, {} deletion{}", + parts.push(format!( + "{} insertion{}, {} deletion{}", stats.lines_added, if stats.lines_added == 1 { "" } else { "s" }, stats.lines_removed, @@ -430,7 +440,10 @@ pub fn format_stats_short(stats: &DiffStats) -> String { return "0".to_string(); } - format!("+{}-{} files:{}", stats.lines_added, stats.lines_removed, stats.files_changed) + format!( + "+{}-{} files:{}", + stats.lines_added, stats.lines_removed, stats.files_changed + ) } /// Format diff stats as a markdown table. diff --git a/crates/lintdiff-diff-stats/tests/diff_stats_tests.rs b/crates/lintdiff-diff-stats/tests/diff_stats_tests.rs index 4e3abd7..8f7d242 100644 --- a/crates/lintdiff-diff-stats/tests/diff_stats_tests.rs +++ b/crates/lintdiff-diff-stats/tests/diff_stats_tests.rs @@ -956,7 +956,12 @@ proptest::proptest! { #[test] fn change_type_all_variants_covered() { // Ensure all variants are tested - let variants = [ChangeType::Added, ChangeType::Deleted, ChangeType::Modified, ChangeType::Renamed]; + let variants = [ + ChangeType::Added, + ChangeType::Deleted, + ChangeType::Modified, + ChangeType::Renamed, + ]; for variant in variants { // Just ensure we can use each variant let _ = variant.to_string(); @@ -1076,13 +1081,13 @@ fn diff_stats_new_is_const_fn() { #[test] fn change_type_hash_consistency() { use std::collections::HashSet; - + let mut set = HashSet::new(); set.insert(ChangeType::Added); set.insert(ChangeType::Deleted); set.insert(ChangeType::Modified); set.insert(ChangeType::Renamed); - + assert_eq!(set.len(), 4); assert!(set.contains(&ChangeType::Added)); } @@ -1090,10 +1095,10 @@ fn change_type_hash_consistency() { #[test] fn file_diff_stats_hash_consistency() { use std::collections::HashSet; - + let mut set = HashSet::new(); set.insert(FileDiffStats::added("test.rs", 10)); set.insert(FileDiffStats::added("test.rs", 10)); // Duplicate - + assert_eq!(set.len(), 1); } diff --git a/crates/lintdiff-disposition/tests/disposition_tests.rs b/crates/lintdiff-disposition/tests/disposition_tests.rs index 50d88ba..ad72673 100644 --- a/crates/lintdiff-disposition/tests/disposition_tests.rs +++ b/crates/lintdiff-disposition/tests/disposition_tests.rs @@ -10,7 +10,9 @@ //! 7. DispositionWithReason Display (5 tests) //! 8. Edge cases (4 tests) -use lintdiff_disposition::{Disposition, DispositionParseError, DispositionReason, DispositionWithReason}; +use lintdiff_disposition::{ + Disposition, DispositionParseError, DispositionReason, DispositionWithReason, +}; // ============================================================================= // 1. Disposition classification methods (10 tests) @@ -230,14 +232,8 @@ mod disposition_parsing { #[test] fn test_parse_skipped() { - assert_eq!( - Disposition::parse("skipped").unwrap(), - Disposition::Skipped - ); - assert_eq!( - Disposition::parse("SKIPPED").unwrap(), - Disposition::Skipped - ); + assert_eq!(Disposition::parse("skipped").unwrap(), Disposition::Skipped); + assert_eq!(Disposition::parse("SKIPPED").unwrap(), Disposition::Skipped); } #[test] diff --git a/crates/lintdiff-escape/tests/escape_tests.rs b/crates/lintdiff-escape/tests/escape_tests.rs index 886ab51..294c172 100644 --- a/crates/lintdiff-escape/tests/escape_tests.rs +++ b/crates/lintdiff-escape/tests/escape_tests.rs @@ -2,7 +2,10 @@ use std::borrow::Cow; -use lintdiff_escape::{escape, escape_github, escape_html, escape_json, escape_markdown, escape_plain, needs_escaping, OutputFormat}; +use lintdiff_escape::{ + escape, escape_github, escape_html, escape_json, escape_markdown, escape_plain, needs_escaping, + OutputFormat, +}; // ============================================================================= // GitHub Actions Escaping Tests @@ -47,10 +50,7 @@ mod github_tests { #[test] fn test_combined_special_chars() { - assert_eq!( - escape_github("Error: 100%\nDone"), - "Error%3A 100%25%0ADone" - ); + assert_eq!(escape_github("Error: 100%\nDone"), "Error%3A 100%25%0ADone"); assert_eq!( escape_github("::error::50%\r\n"), "%3A%3Aerror%3A%3A50%25%0D%0A" @@ -415,11 +415,20 @@ mod zero_copy_tests { #[test] fn test_escape_function_zero_copy() { let s = "no special chars"; - assert!(matches!(escape(s, OutputFormat::GitHubActions), Cow::Borrowed(_))); - assert!(matches!(escape(s, OutputFormat::Markdown), Cow::Borrowed(_))); + assert!(matches!( + escape(s, OutputFormat::GitHubActions), + Cow::Borrowed(_) + )); + assert!(matches!( + escape(s, OutputFormat::Markdown), + Cow::Borrowed(_) + )); assert!(matches!(escape(s, OutputFormat::Html), Cow::Borrowed(_))); assert!(matches!(escape(s, OutputFormat::Json), Cow::Borrowed(_))); - assert!(matches!(escape(s, OutputFormat::PlainText), Cow::Borrowed(_))); + assert!(matches!( + escape(s, OutputFormat::PlainText), + Cow::Borrowed(_) + )); } } @@ -432,7 +441,10 @@ mod output_format_tests { #[test] fn test_debug_impl() { - assert_eq!(format!("{:?}", OutputFormat::GitHubActions), "GitHubActions"); + assert_eq!( + format!("{:?}", OutputFormat::GitHubActions), + "GitHubActions" + ); assert_eq!(format!("{:?}", OutputFormat::Markdown), "Markdown"); assert_eq!(format!("{:?}", OutputFormat::PlainText), "PlainText"); assert_eq!(format!("{:?}", OutputFormat::Html), "Html"); diff --git a/crates/lintdiff-exit/tests/exit_tests.rs b/crates/lintdiff-exit/tests/exit_tests.rs index 973c93e..c29f2eb 100644 --- a/crates/lintdiff-exit/tests/exit_tests.rs +++ b/crates/lintdiff-exit/tests/exit_tests.rs @@ -142,8 +142,7 @@ mod from_verdict { #[test] fn returns_success_with_reasons() { - let verdict = - make_verdict_with_reasons(VerdictStatus::Warn, vec!["Found 3 warnings"]); + let verdict = make_verdict_with_reasons(VerdictStatus::Warn, vec!["Found 3 warnings"]); assert_eq!( ExitCode::from_verdict(&verdict, FailOn::Error), ExitCode::Success diff --git a/crates/lintdiff-explain-builder/src/lib.rs b/crates/lintdiff-explain-builder/src/lib.rs index c091622..ef71edb 100644 --- a/crates/lintdiff-explain-builder/src/lib.rs +++ b/crates/lintdiff-explain-builder/src/lib.rs @@ -176,17 +176,19 @@ impl ExplainSection { let header_row: String = headers .iter() .enumerate() - .map(|(i, h)| format!(" {} ", pad_right(h, widths.get(i).copied().unwrap_or(0)))) + .map(|(i, h)| { + format!(" {} ", pad_right(h, widths.get(i).copied().unwrap_or(0))) + }) .collect::>() .join("|"); - + // Build separator let separator: String = widths .iter() .map(|&w| format!("{}{}{}", "-".repeat(w + 2), "", "")) .collect::>() .join("|"); - + // Build data rows let data_rows: String = rows .iter() @@ -195,7 +197,10 @@ impl ExplainSection { .iter() .enumerate() .map(|(i, cell)| { - format!(" {} ", pad_right(cell, widths.get(i).copied().unwrap_or(0))) + format!( + " {} ", + pad_right(cell, widths.get(i).copied().unwrap_or(0)) + ) }) .collect::>() .join("|"); @@ -469,7 +474,8 @@ impl ExplainBuilder { items.push(item.to_string()); return self; } - self.sections.push(ExplainSection::bullets(vec![item.to_string()])); + self.sections + .push(ExplainSection::bullets(vec![item.to_string()])); self } @@ -477,8 +483,7 @@ impl ExplainBuilder { /// /// The language is used for syntax highlighting in markdown. pub fn add_code_block(&mut self, code: &str, language: &str) -> &mut Self { - self.sections - .push(ExplainSection::code(code, language)); + self.sections.push(ExplainSection::code(code, language)); self } @@ -1000,10 +1005,7 @@ mod tests { #[test] fn test_section_to_markdown_table() { - let section = ExplainSection::table( - vec!["A".to_string()], - vec![vec!["1".to_string()]], - ); + let section = ExplainSection::table(vec!["A".to_string()], vec![vec!["1".to_string()]]); let config = ExplainConfig::default(); let output = section.to_markdown(&config); assert!(output.contains("| A |")); @@ -1037,10 +1039,7 @@ mod tests { #[test] fn test_section_to_plain_text_table() { - let section = ExplainSection::table( - vec!["A".to_string()], - vec![vec!["1".to_string()]], - ); + let section = ExplainSection::table(vec!["A".to_string()], vec![vec!["1".to_string()]]); let config = ExplainConfig::default(); let output = section.to_plain_text(&config); assert!(output.contains("A")); @@ -1090,7 +1089,7 @@ mod tests { .add_bullet("Bullet") .add_code_block("code", "rust") .add_table(&["H"], &[&["D"]]); - + assert_eq!(builder.title(), Some("Title")); assert_eq!(builder.summary(), Some("Summary")); assert_eq!(builder.sections().len(), 4); @@ -1132,7 +1131,7 @@ mod tests { builder.add_bullet("A2"); builder.add_text("Separator"); builder.add_bullet("B1"); - + // Should have 3 sections: Bullets, Text, Bullets assert_eq!(builder.sections().len(), 3); } diff --git a/crates/lintdiff-explain-builder/tests/explain_builder_tests.rs b/crates/lintdiff-explain-builder/tests/explain_builder_tests.rs index 1660f79..be56aab 100644 --- a/crates/lintdiff-explain-builder/tests/explain_builder_tests.rs +++ b/crates/lintdiff-explain-builder/tests/explain_builder_tests.rs @@ -3,7 +3,10 @@ //! These tests follow the Given-When-Then pattern to ensure comprehensive //! coverage of the builder functionality. -use lintdiff_explain_builder::{ExplainBuilder, ExplainConfig, ExplainSection, explain_simple, format_as_markdown, format_as_plain_text}; +use lintdiff_explain_builder::{ + explain_simple, format_as_markdown, format_as_plain_text, ExplainBuilder, ExplainConfig, + ExplainSection, +}; // ============================================================================= // Feature: ExplainBuilder Creation @@ -16,10 +19,10 @@ mod builder_creation { fn given_new_builder_when_checked_then_is_empty() { // Given let builder = ExplainBuilder::new(); - + // When let is_empty = builder.is_empty(); - + // Then assert!(is_empty); } @@ -28,10 +31,10 @@ mod builder_creation { fn given_default_builder_when_checked_then_is_empty() { // Given let builder = ExplainBuilder::default(); - + // When let is_empty = builder.is_empty(); - + // Then assert!(is_empty); } @@ -40,10 +43,10 @@ mod builder_creation { fn given_builder_with_config_when_created_then_has_config() { // Given let config = ExplainConfig::new().with_indent(4); - + // When let builder = ExplainBuilder::with_config(config); - + // Then assert_eq!(builder.config().indent, 4); } @@ -52,10 +55,10 @@ mod builder_creation { fn given_new_builder_when_title_set_then_not_empty() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.with_title("Title"); - + // Then assert!(!builder.is_empty()); } @@ -64,10 +67,10 @@ mod builder_creation { fn given_new_builder_when_summary_set_then_not_empty() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.with_summary("Summary"); - + // Then assert!(!builder.is_empty()); } @@ -76,10 +79,10 @@ mod builder_creation { fn given_new_builder_when_bullet_added_then_not_empty() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.add_bullet("Item"); - + // Then assert!(!builder.is_empty()); } @@ -96,10 +99,10 @@ mod title_management { fn given_builder_when_title_set_then_can_retrieve() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.with_title("My Title"); - + // Then assert_eq!(builder.title(), Some("My Title")); } @@ -109,10 +112,10 @@ mod title_management { // Given let mut builder = ExplainBuilder::new(); builder.with_title("Title"); - + // When builder.clear(); - + // Then assert!(builder.title().is_none()); } @@ -122,10 +125,10 @@ mod title_management { // Given let mut builder = ExplainBuilder::new(); builder.with_title("Old Title"); - + // When builder.with_title("New Title"); - + // Then assert_eq!(builder.title(), Some("New Title")); } @@ -134,10 +137,10 @@ mod title_management { fn given_empty_title_when_set_then_is_stored() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.with_title(""); - + // Then assert_eq!(builder.title(), Some("")); } @@ -146,10 +149,10 @@ mod title_management { fn given_unicode_title_when_set_then_is_stored() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.with_title("日本語タイトル 🦀"); - + // Then assert_eq!(builder.title(), Some("日本語タイトル 🦀")); } @@ -166,10 +169,10 @@ mod summary_management { fn given_builder_when_summary_set_then_can_retrieve() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.with_summary("My summary text"); - + // Then assert_eq!(builder.summary(), Some("My summary text")); } @@ -179,10 +182,10 @@ mod summary_management { // Given let mut builder = ExplainBuilder::new(); builder.with_summary("Summary"); - + // When builder.clear(); - + // Then assert!(builder.summary().is_none()); } @@ -192,10 +195,10 @@ mod summary_management { // Given let mut builder = ExplainBuilder::new(); let summary = "Line 1\nLine 2\nLine 3"; - + // When builder.with_summary(summary); - + // Then assert_eq!(builder.summary(), Some(summary)); } @@ -212,10 +215,10 @@ mod bullet_points { fn given_builder_when_single_bullet_added_then_has_one_section() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.add_bullet("Item 1"); - + // Then assert_eq!(builder.sections().len(), 1); } @@ -224,10 +227,10 @@ mod bullet_points { fn given_builder_when_two_bullets_added_consecutively_then_single_bullets_section() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.add_bullet("Item 1").add_bullet("Item 2"); - + // Then assert_eq!(builder.sections().len(), 1); if let ExplainSection::Bullets(items) = &builder.sections()[0] { @@ -242,10 +245,10 @@ mod bullet_points { // Given let mut builder = ExplainBuilder::new(); builder.add_bullet("A1"); - + // When builder.add_text("Separator").add_bullet("B1"); - + // Then assert_eq!(builder.sections().len(), 3); } @@ -254,10 +257,10 @@ mod bullet_points { fn given_empty_bullet_when_added_then_is_stored() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.add_bullet(""); - + // Then if let ExplainSection::Bullets(items) = &builder.sections()[0] { assert_eq!(items[0], ""); @@ -270,12 +273,12 @@ mod bullet_points { fn given_many_bullets_when_added_then_all_stored() { // Given let mut builder = ExplainBuilder::new(); - + // When for i in 0..100 { builder.add_bullet(&format!("Item {}", i)); } - + // Then if let ExplainSection::Bullets(items) = &builder.sections()[0] { assert_eq!(items.len(), 100); @@ -296,10 +299,10 @@ mod code_blocks { fn given_code_block_when_added_then_has_code_section() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.add_code_block("fn main() {}", "rust"); - + // Then assert_eq!(builder.sections().len(), 1); if let ExplainSection::Code { code, language } = &builder.sections()[0] { @@ -314,10 +317,10 @@ mod code_blocks { fn given_code_block_empty_language_when_added_then_stored() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.add_code_block("code", ""); - + // Then if let ExplainSection::Code { language, .. } = &builder.sections()[0] { assert_eq!(language, ""); @@ -331,12 +334,15 @@ mod code_blocks { // Given let mut builder = ExplainBuilder::new(); let code = "fn a() {}\nfn b() {}\nfn c() {}"; - + // When builder.add_code_block(code, "rust"); - + // Then - if let ExplainSection::Code { code: stored_code, .. } = &builder.sections()[0] { + if let ExplainSection::Code { + code: stored_code, .. + } = &builder.sections()[0] + { assert!(stored_code.contains("fn a()")); assert!(stored_code.contains("fn b()")); assert!(stored_code.contains("fn c()")); @@ -349,12 +355,12 @@ mod code_blocks { fn given_multiple_code_blocks_when_added_then_separate_sections() { // Given let mut builder = ExplainBuilder::new(); - + // When builder .add_code_block("code1", "rust") .add_code_block("code2", "python"); - + // Then assert_eq!(builder.sections().len(), 2); } @@ -371,10 +377,10 @@ mod tables { fn given_table_when_added_then_has_table_section() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.add_table(&["A", "B"], &[&["1", "2"]]); - + // Then assert_eq!(builder.sections().len(), 1); if let ExplainSection::Table { headers, rows } = &builder.sections()[0] { @@ -389,10 +395,10 @@ mod tables { fn given_table_no_rows_when_added_then_headers_preserved() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.add_table(&["Col1", "Col2"], &[]); - + // Then if let ExplainSection::Table { headers, rows } = &builder.sections()[0] { assert_eq!(headers.len(), 2); @@ -406,10 +412,10 @@ mod tables { fn given_table_no_headers_when_added_then_empty_table() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.add_table(&[], &[&["1", "2"]]); - + // Then if let ExplainSection::Table { headers, .. } = &builder.sections()[0] { assert!(headers.is_empty()); @@ -422,15 +428,23 @@ mod tables { fn given_table_many_rows_when_added_then_all_preserved() { // Given let mut builder = ExplainBuilder::new(); - let row_data: Vec<[String; 2]> = (0..50).map(|i| [i.to_string(), "val".to_string()]).collect(); - let row_refs: Vec<[&str; 2]> = row_data.iter().map(|r| [&r[0] as &str, &r[1] as &str]).collect(); + let row_data: Vec<[String; 2]> = (0..50) + .map(|i| [i.to_string(), "val".to_string()]) + .collect(); + let row_refs: Vec<[&str; 2]> = row_data + .iter() + .map(|r| [&r[0] as &str, &r[1] as &str]) + .collect(); let row_slices: Vec<&[&str]> = row_refs.iter().map(|r| &r[..]).collect(); - + // When builder.add_table(&["ID", "Value"], &row_slices); - + // Then - if let ExplainSection::Table { rows: stored_rows, .. } = &builder.sections()[0] { + if let ExplainSection::Table { + rows: stored_rows, .. + } = &builder.sections()[0] + { assert_eq!(stored_rows.len(), 50); } else { panic!("Expected Table section"); @@ -441,10 +455,10 @@ mod tables { fn given_table_uneven_rows_when_added_then_preserved_as_is() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.add_table(&["A", "B", "C"], &[&["1", "2"]]); - + // Then if let ExplainSection::Table { rows, .. } = &builder.sections()[0] { assert_eq!(rows[0].len(), 2); @@ -465,10 +479,10 @@ mod sections { fn given_section_when_added_then_has_section_item() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.add_section("Heading", "Content"); - + // Then if let ExplainSection::Section { heading, content } = &builder.sections()[0] { assert_eq!(heading, "Heading"); @@ -482,10 +496,10 @@ mod sections { fn given_section_empty_content_when_added_then_stored() { // Given let mut builder = ExplainBuilder::new(); - + // When builder.add_section("Heading", ""); - + // Then if let ExplainSection::Section { content, .. } = &builder.sections()[0] { assert_eq!(content, ""); @@ -498,12 +512,12 @@ mod sections { fn given_multiple_sections_when_added_then_all_preserved() { // Given let mut builder = ExplainBuilder::new(); - + // When builder .add_section("First", "Content 1") .add_section("Second", "Content 2"); - + // Then assert_eq!(builder.sections().len(), 2); } @@ -521,10 +535,10 @@ mod markdown_output { // Given let mut builder = ExplainBuilder::new(); builder.with_title("My Title"); - + // When let output = builder.build_markdown(); - + // Then assert!(output.contains("# My Title")); } @@ -534,10 +548,10 @@ mod markdown_output { // Given let mut builder = ExplainBuilder::new(); builder.with_summary("Summary text"); - + // When let output = builder.build_markdown(); - + // Then assert!(output.contains("*Summary text*")); } @@ -547,10 +561,10 @@ mod markdown_output { // Given let mut builder = ExplainBuilder::new(); builder.add_bullet("Item 1").add_bullet("Item 2"); - + // When let output = builder.build_markdown(); - + // Then assert!(output.contains("- Item 1")); assert!(output.contains("- Item 2")); @@ -561,10 +575,10 @@ mod markdown_output { // Given let mut builder = ExplainBuilder::new(); builder.add_code_block("fn main() {}", "rust"); - + // When let output = builder.build_markdown(); - + // Then assert!(output.contains("```rust")); assert!(output.contains("fn main() {}")); @@ -576,10 +590,10 @@ mod markdown_output { // Given let mut builder = ExplainBuilder::new(); builder.add_table(&["A", "B"], &[&["1", "2"]]); - + // When let output = builder.build_markdown(); - + // Then assert!(output.contains("| A |")); assert!(output.contains("| 1 |")); @@ -590,10 +604,10 @@ mod markdown_output { // Given let mut builder = ExplainBuilder::new(); builder.add_section("Heading", "Content"); - + // When let output = builder.build_markdown(); - + // Then assert!(output.contains("## Heading")); assert!(output.contains("Content")); @@ -610,10 +624,10 @@ mod markdown_output { .add_bullet("Bullet") .add_code_block("code", "rust") .add_table(&["H"], &[&["D"]]); - + // When let output = builder.build_markdown(); - + // Then assert!(output.contains("# Title")); assert!(output.contains("*Summary*")); @@ -627,10 +641,10 @@ mod markdown_output { fn given_empty_builder_when_build_markdown_then_empty_or_newline() { // Given let builder = ExplainBuilder::new(); - + // When let output = builder.build_markdown(); - + // Then assert!(output.is_empty() || output == "\n"); } @@ -640,11 +654,11 @@ mod markdown_output { // Given let mut builder = ExplainBuilder::new(); builder.with_title("Title"); - + // When let output1 = builder.build_markdown(); let output2 = format_as_markdown(&builder); - + // Then assert_eq!(output1, output2); } @@ -662,10 +676,10 @@ mod plain_text_output { // Given let mut builder = ExplainBuilder::new(); builder.with_title("Title"); - + // When let output = builder.build_plain_text(); - + // Then assert!(output.contains("Title")); assert!(output.contains("=====")); @@ -676,10 +690,10 @@ mod plain_text_output { // Given let mut builder = ExplainBuilder::new(); builder.with_summary("Summary"); - + // When let output = builder.build_plain_text(); - + // Then assert!(output.contains("Summary")); assert!(!output.contains("*Summary*")); @@ -690,10 +704,10 @@ mod plain_text_output { // Given let mut builder = ExplainBuilder::new(); builder.add_bullet("Item"); - + // When let output = builder.build_plain_text(); - + // Then assert!(output.contains("* Item")); assert!(!output.contains("- Item")); @@ -704,10 +718,10 @@ mod plain_text_output { // Given let mut builder = ExplainBuilder::new(); builder.add_code_block("code", "rust"); - + // When let output = builder.build_plain_text(); - + // Then assert!(output.contains("[rust]")); assert!(output.contains("code")); @@ -718,10 +732,10 @@ mod plain_text_output { // Given let mut builder = ExplainBuilder::new(); builder.add_code_block("code", ""); - + // When let output = builder.build_plain_text(); - + // Then assert!(!output.contains("[]")); } @@ -731,10 +745,10 @@ mod plain_text_output { // Given let mut builder = ExplainBuilder::new(); builder.add_table(&["A", "B"], &[&["1", "2"]]); - + // When let output = builder.build_plain_text(); - + // Then assert!(output.contains("A | B")); assert!(output.contains("-+-")); @@ -745,10 +759,10 @@ mod plain_text_output { // Given let mut builder = ExplainBuilder::new(); builder.add_section("Heading", "Content"); - + // When let output = builder.build_plain_text(); - + // Then assert!(output.contains("[Heading]")); assert!(output.contains("Content")); @@ -759,11 +773,11 @@ mod plain_text_output { // Given let mut builder = ExplainBuilder::new(); builder.with_title("Title"); - + // When let output1 = builder.build_plain_text(); let output2 = format_as_plain_text(&builder); - + // Then assert_eq!(output1, output2); } @@ -780,7 +794,7 @@ mod configuration { fn given_default_config_when_created_then_has_defaults() { // Given/When let config = ExplainConfig::default(); - + // Then assert_eq!(config.indent, 0); assert_eq!(config.line_width, 80); @@ -793,10 +807,10 @@ mod configuration { let config = ExplainConfig::new().with_indent(4); let mut builder = ExplainBuilder::with_config(config); builder.add_text("Text"); - + // When let output = builder.build_markdown(); - + // Then assert!(output.contains(" Text")); } @@ -807,10 +821,10 @@ mod configuration { let config = ExplainConfig::new().with_color(true); let mut builder = ExplainBuilder::with_config(config); builder.with_title("Title"); - + // When let output = builder.build_markdown(); - + // Then assert!(output.contains("\x1b[")); } @@ -821,10 +835,10 @@ mod configuration { let config = ExplainConfig::new().with_color(false); let mut builder = ExplainBuilder::with_config(config); builder.with_title("Title"); - + // When let output = builder.build_markdown(); - + // Then assert!(!output.contains("\x1b[")); } @@ -834,10 +848,10 @@ mod configuration { // Given let mut builder = ExplainBuilder::new(); let config = ExplainConfig::new().with_indent(8); - + // When builder.set_config(config); - + // Then assert_eq!(builder.config().indent, 8); } @@ -861,10 +875,10 @@ mod indentation { // Given let section = ExplainSection::text("Hello"); let config = ExplainConfig::new().with_indent(2); - + // When let output = section.to_markdown(&config); - + // Then assert_eq!(output, " Hello"); } @@ -874,10 +888,10 @@ mod indentation { // Given let section = ExplainSection::bullets(vec!["Item".to_string()]); let config = ExplainConfig::new().with_indent(3); - + // When let output = section.to_markdown(&config); - + // Then assert_eq!(output, " - Item"); } @@ -887,10 +901,10 @@ mod indentation { // Given let section = ExplainSection::code("code", "rust"); let config = ExplainConfig::new().with_indent(4); - + // When let output = section.to_markdown(&config); - + // Then assert!(output.contains(" ```rust")); assert!(output.contains(" code")); @@ -901,10 +915,10 @@ mod indentation { // Given let section = ExplainSection::table(vec!["A".to_string()], vec![]); let config = ExplainConfig::new().with_indent(2); - + // When let output = section.to_markdown(&config); - + // Then assert!(output.starts_with(" |")); } @@ -914,10 +928,10 @@ mod indentation { // Given let section = ExplainSection::section("H", "C"); let config = ExplainConfig::new().with_indent(2); - + // When let output = section.to_markdown(&config); - + // Then assert!(output.contains(" ## H")); } @@ -927,10 +941,10 @@ mod indentation { // Given let section = ExplainSection::text("Line1\nLine2\nLine3"); let config = ExplainConfig::new().with_indent(2); - + // When let output = section.to_markdown(&config); - + // Then assert!(output.contains(" Line1")); assert!(output.contains(" Line2")); @@ -949,7 +963,7 @@ mod convenience_functions { fn given_explain_simple_when_called_then_has_title_and_content() { // When let output = explain_simple("Title", "Content"); - + // Then assert!(output.contains("# Title")); assert!(output.contains("Content")); @@ -959,7 +973,7 @@ mod convenience_functions { fn given_explain_simple_empty_content_then_has_title() { // When let output = explain_simple("Title", ""); - + // Then assert!(output.contains("# Title")); } @@ -977,10 +991,10 @@ mod edge_cases { // Given let mut builder = ExplainBuilder::new(); builder.with_title("Title with & \"chars\""); - + // When let output = builder.build(); - + // Then assert!(output.contains("")); assert!(output.contains("&")); @@ -992,10 +1006,10 @@ mod edge_cases { // Given let mut builder = ExplainBuilder::new(); builder.with_title("日本語").add_bullet("項目"); - + // When let output = builder.build(); - + // Then assert!(output.contains("日本語")); assert!(output.contains("項目")); @@ -1007,10 +1021,10 @@ mod edge_cases { let mut builder = ExplainBuilder::new(); let long_title = "A".repeat(1000); builder.with_title(&long_title); - + // When let output = builder.build(); - + // Then assert!(output.contains(&long_title)); } @@ -1021,10 +1035,10 @@ mod edge_cases { let mut builder = ExplainBuilder::new(); let long_bullet = "B".repeat(1000); builder.add_bullet(&long_bullet); - + // When let output = builder.build(); - + // Then assert!(output.contains(&long_bullet)); } @@ -1034,10 +1048,10 @@ mod edge_cases { // Given let section = ExplainSection::table(vec![], vec![]); let config = ExplainConfig::default(); - + // When let output = section.to_markdown(&config); - + // Then assert!(output.is_empty()); } @@ -1047,10 +1061,10 @@ mod edge_cases { // Given let mut builder = ExplainBuilder::new(); builder.add_text("Line1\nLine2\nLine3"); - + // When let output = builder.build(); - + // Then assert!(output.contains("Line1")); assert!(output.contains("Line2")); @@ -1062,11 +1076,11 @@ mod edge_cases { // Given let mut builder = ExplainBuilder::new(); builder.with_title("Old").add_bullet("Old Item"); - + // When builder.clear(); builder.with_title("New").add_bullet("New Item"); - + // Then let output = builder.build(); assert!(output.contains("# New")); @@ -1081,10 +1095,10 @@ mod edge_cases { for i in 0..100 { builder.add_section(&format!("Section {}", i), &format!("Content {}", i)); } - + // When let output = builder.build(); - + // Then assert!(output.contains("Section 0")); assert!(output.contains("Section 99")); @@ -1103,10 +1117,10 @@ mod section_types { // Given let section = ExplainSection::text("Hello"); let config = ExplainConfig::default(); - + // When let output = section.to_markdown(&config); - + // Then assert_eq!(output, "Hello"); } @@ -1116,10 +1130,10 @@ mod section_types { // Given let section = ExplainSection::bullets(vec!["A".to_string(), "B".to_string()]); let config = ExplainConfig::default(); - + // When let output = section.to_markdown(&config); - + // Then assert_eq!(output, "- A\n- B"); } @@ -1129,10 +1143,10 @@ mod section_types { // Given let section = ExplainSection::code("code", "rust"); let config = ExplainConfig::default(); - + // When let output = section.to_markdown(&config); - + // Then assert!(output.starts_with("```rust")); assert!(output.ends_with("```")); @@ -1142,15 +1156,12 @@ mod section_types { #[test] fn given_table_section_when_to_markdown_then_markdown_table() { // Given - let section = ExplainSection::table( - vec!["H".to_string()], - vec![vec!["D".to_string()]], - ); + let section = ExplainSection::table(vec!["H".to_string()], vec![vec!["D".to_string()]]); let config = ExplainConfig::default(); - + // When let output = section.to_markdown(&config); - + // Then assert!(output.contains("| H |")); assert!(output.contains("| D |")); @@ -1161,10 +1172,10 @@ mod section_types { // Given let section = ExplainSection::section("Head", "Body"); let config = ExplainConfig::default(); - + // When let output = section.to_markdown(&config); - + // Then assert!(output.contains("## Head")); assert!(output.contains("Body")); @@ -1175,10 +1186,10 @@ mod section_types { // Given let section = ExplainSection::text("Hello"); let config = ExplainConfig::default(); - + // When let output = section.to_plain_text(&config); - + // Then assert_eq!(output, "Hello"); } @@ -1188,10 +1199,10 @@ mod section_types { // Given let section = ExplainSection::bullets(vec!["A".to_string(), "B".to_string()]); let config = ExplainConfig::default(); - + // When let output = section.to_plain_text(&config); - + // Then assert_eq!(output, "* A\n* B"); } @@ -1201,10 +1212,10 @@ mod section_types { // Given let section = ExplainSection::code("code", "rust"); let config = ExplainConfig::default(); - + // When let output = section.to_plain_text(&config); - + // Then assert!(output.contains("[rust]")); assert!(output.contains(" code")); @@ -1213,15 +1224,12 @@ mod section_types { #[test] fn given_table_section_when_to_plain_text_then_text_table() { // Given - let section = ExplainSection::table( - vec!["H".to_string()], - vec![vec!["D".to_string()]], - ); + let section = ExplainSection::table(vec!["H".to_string()], vec![vec!["D".to_string()]]); let config = ExplainConfig::default(); - + // When let output = section.to_plain_text(&config); - + // Then assert!(output.contains("H")); assert!(output.contains("-")); @@ -1233,10 +1241,10 @@ mod section_types { // Given let section = ExplainSection::section("Head", "Body"); let config = ExplainConfig::default(); - + // When let output = section.to_plain_text(&config); - + // Then assert!(output.contains("[Head]")); assert!(output.contains("Body")); @@ -1262,7 +1270,7 @@ mod builder_chaining { .add_code_block("code", "rust") .add_table(&["H"], &[&["D"]]) .add_text("T"); - + // Then assert_eq!(builder.title(), Some("T")); assert_eq!(builder.summary(), Some("S")); @@ -1277,10 +1285,10 @@ mod builder_chaining { .with_title("Title") .with_summary("Summary") .add_bullet("Bullet"); - + // When let output = builder.build(); - + // Then assert!(output.contains("# Title")); assert!(output.contains("*Summary*")); @@ -1300,10 +1308,10 @@ mod serde_support { fn given_explain_config_when_serialized_then_valid_json() { // Given let config = ExplainConfig::new().with_indent(4).with_color(true); - + // When let json = serde_json::to_string(&config).unwrap(); - + // Then assert!(json.contains("\"indent\":4")); assert!(json.contains("\"color\":true")); @@ -1313,10 +1321,10 @@ mod serde_support { fn given_json_when_deserialized_then_valid_config() { // Given let json = r#"{"indent":2,"line_width":100,"color":true}"#; - + // When let config: ExplainConfig = serde_json::from_str(json).unwrap(); - + // Then assert_eq!(config.indent, 2); assert_eq!(config.line_width, 100); @@ -1327,10 +1335,10 @@ mod serde_support { fn given_explain_section_text_when_serialized_then_valid_json() { // Given let section = ExplainSection::text("Hello"); - + // When let json = serde_json::to_string(§ion).unwrap(); - + // Then assert!(json.contains("\"type\":\"text\"")); assert!(json.contains("Hello")); @@ -1340,10 +1348,10 @@ mod serde_support { fn given_explain_section_bullets_when_serialized_then_valid_json() { // Given let section = ExplainSection::bullets(vec!["A".to_string(), "B".to_string()]); - + // When let json = serde_json::to_string(§ion).unwrap(); - + // Then assert!(json.contains("\"type\":\"bullets\"")); assert!(json.contains("A")); @@ -1354,10 +1362,10 @@ mod serde_support { fn given_explain_section_code_when_serialized_then_valid_json() { // Given let section = ExplainSection::code("fn main() {}", "rust"); - + // When let json = serde_json::to_string(§ion).unwrap(); - + // Then assert!(json.contains("\"type\":\"code\"")); assert!(json.contains("fn main() {}")); @@ -1367,14 +1375,11 @@ mod serde_support { #[test] fn given_explain_section_table_when_serialized_then_valid_json() { // Given - let section = ExplainSection::table( - vec!["A".to_string()], - vec![vec!["1".to_string()]], - ); - + let section = ExplainSection::table(vec!["A".to_string()], vec![vec!["1".to_string()]]); + // When let json = serde_json::to_string(§ion).unwrap(); - + // Then assert!(json.contains("\"type\":\"table\"")); assert!(json.contains("headers")); @@ -1537,10 +1542,7 @@ mod additional_coverage { #[test] fn test_markdown_table_separator() { - let section = ExplainSection::table( - vec!["A".to_string(), "B".to_string()], - vec![], - ); + let section = ExplainSection::table(vec!["A".to_string(), "B".to_string()], vec![]); let config = ExplainConfig::default(); let output = section.to_markdown(&config); // Should have header row and separator @@ -1550,10 +1552,7 @@ mod additional_coverage { #[test] fn test_plain_text_table_separator() { - let section = ExplainSection::table( - vec!["A".to_string(), "B".to_string()], - vec![], - ); + let section = ExplainSection::table(vec!["A".to_string(), "B".to_string()], vec![]); let config = ExplainConfig::default(); let output = section.to_plain_text(&config); assert!(output.contains("-+-")); @@ -1581,10 +1580,7 @@ mod additional_coverage { #[test] fn test_indent_plain_text_table() { - let section = ExplainSection::table( - vec!["A".to_string()], - vec![vec!["1".to_string()]], - ); + let section = ExplainSection::table(vec!["A".to_string()], vec![vec!["1".to_string()]]); let config = ExplainConfig::new().with_indent(2); let output = section.to_plain_text(&config); assert!(output.starts_with(" ")); @@ -1638,14 +1634,14 @@ mod additional_coverage { .add_bullet("B2") .add_code_block("code", "rust") .add_bullet("B3"); - + let output = builder.build(); let b1_pos = output.find("B1").unwrap(); let text_pos = output.find("Text").unwrap(); let b2_pos = output.find("B2").unwrap(); let code_pos = output.find("code").unwrap(); let b3_pos = output.find("B3").unwrap(); - + assert!(b1_pos < text_pos); assert!(text_pos < b2_pos); assert!(b2_pos < code_pos); diff --git a/crates/lintdiff-explain-summary/src/lib.rs b/crates/lintdiff-explain-summary/src/lib.rs index 0a3e44d..3c60143 100644 --- a/crates/lintdiff-explain-summary/src/lib.rs +++ b/crates/lintdiff-explain-summary/src/lib.rs @@ -198,7 +198,10 @@ impl FileSummary { pub fn add_finding(&mut self, severity: &str, disposition: &str, line: Option) { self.finding_count += 1; *self.by_severity.entry(severity.to_string()).or_insert(0) += 1; - *self.by_disposition.entry(disposition.to_string()).or_insert(0) += 1; + *self + .by_disposition + .entry(disposition.to_string()) + .or_insert(0) += 1; if let Some(l) = line { self.lines_affected.insert(l); } @@ -465,10 +468,7 @@ impl SummaryBuilder { for (path, severity, disposition, line) in &self.findings { summary.total_findings += 1; - *summary - .by_severity - .entry(severity.clone()) - .or_insert(0) += 1; + *summary.by_severity.entry(severity.clone()).or_insert(0) += 1; *summary .by_disposition .entry(disposition.clone()) @@ -520,7 +520,9 @@ pub fn aggregate_summaries(summaries: &[ExplainSummary]) -> ExplainSummary { /// Create a map of file paths to file summaries from findings. #[must_use] -pub fn summarize_by_file(findings: &[&F]) -> HashMap { +pub fn summarize_by_file( + findings: &[&F], +) -> HashMap { let mut result: HashMap = HashMap::new(); for finding in findings { @@ -555,19 +557,19 @@ pub fn summarize_by_disposition(summary: &ExplainSummary) -> HashMap String { use std::fmt::Write; let mut output = String::new(); - + let _ = writeln!(output, "# Explain Summary\n"); - + // Timestamp if let Some(ref ts) = summary.timestamp { let _ = writeln!(output, "**Timestamp:** {ts}\n"); } - + // Overview let _ = writeln!(output, "## Overview\n"); let _ = writeln!(output, "- **Total Findings:** {}", summary.total_findings); let _ = writeln!(output, "- **Files Affected:** {}\n", summary.files_affected); - + // By Severity if !summary.by_severity.is_empty() { let _ = writeln!(output, "## By Severity\n"); @@ -577,7 +579,7 @@ pub fn format_summary_markdown(summary: &ExplainSummary) -> String { let _ = writeln!(output, "- **{severity}:** {count}"); } } - + // By Disposition if !summary.by_disposition.is_empty() { let _ = writeln!(output, "\n## By Disposition\n"); @@ -587,7 +589,7 @@ pub fn format_summary_markdown(summary: &ExplainSummary) -> String { let _ = writeln!(output, "- **{disposition}:** {count}"); } } - + // By File if !summary.by_file.is_empty() { let _ = writeln!(output, "\n## By File\n"); @@ -635,10 +637,10 @@ pub fn format_summary_json(_summary: &ExplainSummary) -> String { pub fn format_file_summary_markdown(file_summary: &FileSummary) -> String { use std::fmt::Write; let mut output = String::new(); - + let _ = writeln!(output, "## {}\n", file_summary.path.display()); let _ = writeln!(output, "- **Findings:** {}\n", file_summary.finding_count); - + if !file_summary.by_severity.is_empty() { let _ = writeln!(output, "### By Severity\n"); let mut severities: Vec<_> = file_summary.by_severity.iter().collect(); @@ -647,7 +649,7 @@ pub fn format_file_summary_markdown(file_summary: &FileSummary) -> String { let _ = writeln!(output, "- **{severity}:** {count}\n"); } } - + if !file_summary.by_disposition.is_empty() { let _ = writeln!(output, "### By Disposition\n"); let mut dispositions: Vec<_> = file_summary.by_disposition.iter().collect(); @@ -656,13 +658,13 @@ pub fn format_file_summary_markdown(file_summary: &FileSummary) -> String { let _ = writeln!(output, "- **{disposition}:** {count}\n"); } } - + if !file_summary.lines_affected.is_empty() { let mut lines: Vec<_> = file_summary.lines_affected.iter().copied().collect(); lines.sort_unstable(); let _ = writeln!(output, "\n### Lines Affected\n\n{}\n", lines.len()); } - + output } @@ -714,7 +716,7 @@ pub fn is_info_only(summary: &ExplainSummary) -> bool { pub fn filter_by_disposition(summary: &ExplainSummary, disposition: &str) -> ExplainSummary { let mut result = ExplainSummary::new(); result.timestamp.clone_from(&summary.timestamp); - + for (path, file_summary) in &summary.by_file { let count = file_summary.disposition_count(disposition); if count > 0 { @@ -728,20 +730,22 @@ pub fn filter_by_disposition(summary: &ExplainSummary, disposition: &str) -> Exp new_file_summary .by_disposition .insert(disposition.to_string(), count); - new_file_summary.lines_affected.clone_from(&file_summary.lines_affected); + new_file_summary + .lines_affected + .clone_from(&file_summary.lines_affected); result.by_file.insert(path.clone(), new_file_summary); } } - + result.total_findings = summary.disposition_count(disposition); result .by_disposition .insert(disposition.to_string(), result.total_findings); result.files_affected = result.by_file.len(); - + // Copy severity counts proportionally result.by_severity.clone_from(&summary.by_severity); - + result } diff --git a/crates/lintdiff-explain/src/lib.rs b/crates/lintdiff-explain/src/lib.rs index d839055..8ac42a8 100644 --- a/crates/lintdiff-explain/src/lib.rs +++ b/crates/lintdiff-explain/src/lib.rs @@ -202,7 +202,10 @@ impl Explanation { /// assert!(!explanation.is_included()); /// ``` pub fn outside_diff() -> Self { - Self::new(Disposition::OutsideDiff, "Diagnostic is outside the diff hunks") + Self::new( + Disposition::OutsideDiff, + "Diagnostic is outside the diff hunks", + ) } /// Create a `GeneratedFile` explanation. @@ -216,7 +219,10 @@ impl Explanation { /// assert_eq!(explanation.disposition, Disposition::GeneratedFile); /// ``` pub fn generated_file() -> Self { - Self::new(Disposition::GeneratedFile, "Diagnostic is in a generated file") + Self::new( + Disposition::GeneratedFile, + "Diagnostic is in a generated file", + ) } /// Create a `Suppressed` explanation with the given code. @@ -232,8 +238,11 @@ impl Explanation { /// ``` pub fn suppressed(code: impl Into) -> Self { let code = code.into(); - Self::new(Disposition::Suppressed, format!("Diagnostic '{}' was suppressed by configuration", code)) - .with_code(code) + Self::new( + Disposition::Suppressed, + format!("Diagnostic '{}' was suppressed by configuration", code), + ) + .with_code(code) } /// Create a `NoSpan` explanation. @@ -261,7 +270,10 @@ impl Explanation { /// assert_eq!(explanation.disposition, Disposition::NonWorkspace); /// ``` pub fn non_workspace() -> Self { - Self::new(Disposition::NonWorkspace, "Diagnostic is in a file outside the workspace") + Self::new( + Disposition::NonWorkspace, + "Diagnostic is in a file outside the workspace", + ) } /// Check if this explanation means the diagnostic was included. @@ -358,8 +370,7 @@ mod tests { #[test] fn test_explanation_with_code() { - let explanation = Explanation::new(Disposition::Suppressed, "Test") - .with_code("dead_code"); + let explanation = Explanation::new(Disposition::Suppressed, "Test").with_code("dead_code"); assert_eq!(explanation.code, Some("dead_code".to_string())); } diff --git a/crates/lintdiff-explain/tests/explain_tests.rs b/crates/lintdiff-explain/tests/explain_tests.rs index dfb5e13..b446bd2 100644 --- a/crates/lintdiff-explain/tests/explain_tests.rs +++ b/crates/lintdiff-explain/tests/explain_tests.rs @@ -74,7 +74,7 @@ fn disposition_hash() { set.insert(Disposition::Included); set.insert(Disposition::OutsideDiff); set.insert(Disposition::Included); // Duplicate - + assert_eq!(set.len(), 2); } @@ -99,16 +99,14 @@ fn explanation_new_with_string() { #[test] fn explanation_with_code() { - let explanation = Explanation::new(Disposition::Suppressed, "Test") - .with_code("dead_code"); + let explanation = Explanation::new(Disposition::Suppressed, "Test").with_code("dead_code"); assert_eq!(explanation.code, Some("dead_code".to_string())); } #[test] fn explanation_with_code_string() { let code = String::from("clippy::all"); - let explanation = Explanation::new(Disposition::Suppressed, "Test") - .with_code(code); + let explanation = Explanation::new(Disposition::Suppressed, "Test").with_code(code); assert_eq!(explanation.code, Some("clippy::all".to_string())); } @@ -208,7 +206,7 @@ fn explanation_eq() { let a = Explanation::included("Test"); let b = Explanation::included("Test"); let c = Explanation::included("Different"); - + assert_eq!(a, b); assert_ne!(a, c); } diff --git a/crates/lintdiff-finding-builder/src/lib.rs b/crates/lintdiff-finding-builder/src/lib.rs index 4dd36c0..60568c8 100644 --- a/crates/lintdiff-finding-builder/src/lib.rs +++ b/crates/lintdiff-finding-builder/src/lib.rs @@ -409,18 +409,14 @@ mod tests { #[test] fn test_missing_code() { - let result = FindingBuilder::new() - .with_message("test message") - .build(); + let result = FindingBuilder::new().with_message("test message").build(); assert_eq!(result.unwrap_err(), BuildError::MissingCode); } #[test] fn test_missing_message() { - let result = FindingBuilder::new() - .with_code("test_code") - .build(); + let result = FindingBuilder::new().with_code("test_code").build(); assert_eq!(result.unwrap_err(), BuildError::MissingMessage); } diff --git a/crates/lintdiff-finding-builder/tests/finding_builder_tests.rs b/crates/lintdiff-finding-builder/tests/finding_builder_tests.rs index 599c3e4..1728a05 100644 --- a/crates/lintdiff-finding-builder/tests/finding_builder_tests.rs +++ b/crates/lintdiff-finding-builder/tests/finding_builder_tests.rs @@ -52,7 +52,9 @@ fn fully_configured_finding() { .with_col(15) .with_check_id("clippy::unnecessary_allocation") .with_help("Use `&str` instead of `String`") - .with_url("https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_allocation") + .with_url( + "https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_allocation", + ) .with_fingerprint("a1b2c3d4e5f6") .with_data(json!({ "suggestion": "&str", "complexity": "O(1)" })) .build() @@ -67,8 +69,14 @@ fn fully_configured_finding() { assert_eq!(loc.line, Some(42)); assert_eq!(loc.col, Some(15)); - assert_eq!(finding.check_id, Some("clippy::unnecessary_allocation".to_string())); - assert_eq!(finding.help, Some("Use `&str` instead of `String`".to_string())); + assert_eq!( + finding.check_id, + Some("clippy::unnecessary_allocation".to_string()) + ); + assert_eq!( + finding.help, + Some("Use `&str` instead of `String`".to_string()) + ); assert!(finding.url.is_some()); assert_eq!(finding.fingerprint, Some("a1b2c3d4e5f6".to_string())); assert!(finding.data.is_some()); @@ -80,9 +88,7 @@ fn fully_configured_finding() { #[test] fn missing_code_returns_error() { - let result = FindingBuilder::new() - .with_message("Some message") - .build(); + let result = FindingBuilder::new().with_message("Some message").build(); assert!(result.is_err()); assert_eq!(result.unwrap_err(), BuildError::MissingCode); @@ -90,9 +96,7 @@ fn missing_code_returns_error() { #[test] fn missing_message_returns_error() { - let result = FindingBuilder::new() - .with_code("CODE001") - .build(); + let result = FindingBuilder::new().with_code("CODE001").build(); assert!(result.is_err()); assert_eq!(result.unwrap_err(), BuildError::MissingMessage); @@ -305,7 +309,10 @@ fn url_is_optional() { .build() .unwrap(); - assert_eq!(finding.url, Some("https://docs.example.com/errors/CODE".to_string())); + assert_eq!( + finding.url, + Some("https://docs.example.com/errors/CODE".to_string()) + ); } #[test] diff --git a/crates/lintdiff-finding/src/lib.rs b/crates/lintdiff-finding/src/lib.rs index c55df8c..8edf53e 100644 --- a/crates/lintdiff-finding/src/lib.rs +++ b/crates/lintdiff-finding/src/lib.rs @@ -181,7 +181,8 @@ impl Finding { /// Check if this is a multi-line finding. #[must_use] pub fn is_multiline(&self) -> bool { - self.end_line.is_some_and(|end| end != self.line.unwrap_or(0)) + self.end_line + .is_some_and(|end| end != self.line.unwrap_or(0)) } /// Check if this finding has a span (line and column). diff --git a/crates/lintdiff-finding/tests/finding_tests.rs b/crates/lintdiff-finding/tests/finding_tests.rs index 698049f..87bb175 100644 --- a/crates/lintdiff-finding/tests/finding_tests.rs +++ b/crates/lintdiff-finding/tests/finding_tests.rs @@ -512,7 +512,9 @@ fn test_finding_location_with_line() { #[test] fn test_finding_location_with_line_and_column() { - let finding = Finding::new("src/lib.rs", "msg").with_line(42).with_column(10); + let finding = Finding::new("src/lib.rs", "msg") + .with_line(42) + .with_column(10); assert_eq!(finding.location(), "src/lib.rs:42:10"); } diff --git a/crates/lintdiff-git-info/src/lib.rs b/crates/lintdiff-git-info/src/lib.rs index af9c8eb..f2f71c7 100644 --- a/crates/lintdiff-git-info/src/lib.rs +++ b/crates/lintdiff-git-info/src/lib.rs @@ -392,7 +392,6 @@ impl fmt::Display for GitRef { } } - /// Combined Git information for a repository state. #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -586,26 +585,26 @@ pub fn parse_sha(s: &str) -> Result { #[must_use] pub fn parse_ref(s: &str) -> GitRef { let trimmed = s.trim(); - + if trimmed == "HEAD" { return GitRef::Head; } - + if let Some(name) = trimmed.strip_prefix("refs/heads/") { return GitRef::Branch(name.to_string()); } - + if let Some(name) = trimmed.strip_prefix("refs/tags/") { return GitRef::Tag(name.to_string()); } - + // Try to parse as a commit SHA if is_valid_sha(trimmed) { if let Ok(sha) = GitSha::new(trimmed) { return GitRef::Commit(sha); } } - + GitRef::Unknown } @@ -635,7 +634,7 @@ fn validate_sha(s: &str) -> Result<(), GitInfoError> { actual: s.len(), }); } - + for (i, c) in s.chars().enumerate() { if !c.is_ascii_hexdigit() { return Err(GitInfoError::InvalidHexCharacter { @@ -644,14 +643,14 @@ fn validate_sha(s: &str) -> Result<(), GitInfoError> { }); } } - + Ok(()) } // Internal hex encoding to avoid dependency mod hex { const HEX_CHARS: &[u8; 16] = b"0123456789abcdef"; - + #[allow(unreachable_pub)] pub fn encode(bytes: [u8; 20]) -> String { let mut result = String::with_capacity(40); @@ -695,7 +694,7 @@ mod tests { fn test_git_sha_is_zero() { let zero = GitSha::new("0000000000000000000000000000000000000000").unwrap(); assert!(zero.is_zero()); - + let non_zero = GitSha::new("0123456789abcdef0123456789abcdef01234567").unwrap(); assert!(!non_zero.is_zero()); } diff --git a/crates/lintdiff-git-info/tests/git_info_tests.rs b/crates/lintdiff-git-info/tests/git_info_tests.rs index fde6a9a..192d754 100644 --- a/crates/lintdiff-git-info/tests/git_info_tests.rs +++ b/crates/lintdiff-git-info/tests/git_info_tests.rs @@ -84,7 +84,10 @@ mod git_sha_creation { let result = GitSha::new("0123456789ghijef0123456789abcdef01234567"); assert!(result.is_err()); match result { - Err(GitInfoError::InvalidHexCharacter { position, character }) => { + Err(GitInfoError::InvalidHexCharacter { + position, + character, + }) => { assert_eq!(position, 10); assert_eq!(character, 'g'); } @@ -469,8 +472,14 @@ mod edge_cases { #[test] fn git_ref_display() { - assert_eq!(format!("{}", GitRef::Branch("main".to_string())), "refs/heads/main"); - assert_eq!(format!("{}", GitRef::Tag("v1.0.0".to_string())), "refs/tags/v1.0.0"); + assert_eq!( + format!("{}", GitRef::Branch("main".to_string())), + "refs/heads/main" + ); + assert_eq!( + format!("{}", GitRef::Tag("v1.0.0".to_string())), + "refs/tags/v1.0.0" + ); assert_eq!(format!("{}", GitRef::Head), "HEAD"); assert_eq!(format!("{}", GitRef::Unknown), "(unknown)"); } @@ -491,7 +500,7 @@ mod edge_cases { let sha1 = GitSha::new("0123456789abcdef0123456789abcdef01234567").unwrap(); let sha2 = GitSha::new("0123456789abcdef0123456789abcdef01234567").unwrap(); let sha3 = GitSha::new("ffffffffffffffffffffffffffffffffffffffff").unwrap(); - + assert_eq!(sha1, sha2); assert_ne!(sha1, sha3); } @@ -555,7 +564,7 @@ mod serde_tests { let sha = GitSha::new("0123456789abcdef0123456789abcdef01234567").unwrap(); let json = serde_json::to_string(&sha).unwrap(); assert_eq!(json, "\"0123456789abcdef0123456789abcdef01234567\""); - + let deserialized: GitSha = serde_json::from_str(&json).unwrap(); assert_eq!(sha, deserialized); } @@ -574,7 +583,7 @@ mod serde_tests { let info = GitInfo::new(sha) .with_ref_name("main".to_string()) .with_dirty(false); - + let json = serde_json::to_string(&info).unwrap(); assert!(json.contains("0123456789abcdef0123456789abcdef01234567")); assert!(json.contains("main")); @@ -640,14 +649,14 @@ mod ordering_tests { #[test] fn git_sha_hash_consistency() { use std::collections::HashSet; - + let sha1 = GitSha::new("0123456789abcdef0123456789abcdef01234567").unwrap(); let sha2 = GitSha::new("0123456789abcdef0123456789abcdef01234567").unwrap(); - + let mut set = HashSet::new(); set.insert(sha1.clone()); set.insert(sha2.clone()); - + assert_eq!(set.len(), 1); } @@ -677,17 +686,17 @@ mod integration_tests { // Simulate parsing a SHA from GITHUB_SHA environment variable let env_sha = "0123456789abcdef0123456789abcdef01234567"; let sha = parse_sha(env_sha).unwrap(); - + // Simulate parsing a ref from GITHUB_REF let env_ref = "refs/heads/main"; let git_ref = parse_ref(env_ref); - + // Build GitInfo let info = GitInfo::new(sha) .with_ref_name(git_ref.as_branch().unwrap().to_string()) .with_dirty(false) .with_message("Add feature X".to_string()); - + assert_eq!(info.short_sha(), "0123456"); assert_eq!(info.ref_name, Some("main".to_string())); assert!(info.is_clean()); @@ -697,13 +706,12 @@ mod integration_tests { fn typical_tag_release_workflow() { let env_sha = "0123456789abcdef0123456789abcdef01234567"; let env_ref = "refs/tags/v1.0.0"; - + let sha = parse_sha(env_sha).unwrap(); let git_ref = parse_ref(env_ref); - - let info = GitInfo::new(sha) - .with_ref_name(git_ref.as_tag().unwrap().to_string()); - + + let info = GitInfo::new(sha).with_ref_name(git_ref.as_tag().unwrap().to_string()); + assert_eq!(info.ref_name, Some("v1.0.0".to_string())); } @@ -711,10 +719,10 @@ mod integration_tests { fn detached_head_workflow() { let env_sha = "0123456789abcdef0123456789abcdef01234567"; let sha = parse_sha(env_sha).unwrap(); - + // Detached HEAD - no ref name let info = GitInfo::new(sha); - + assert!(info.ref_name.is_none()); } @@ -722,7 +730,7 @@ mod integration_tests { fn dirty_working_directory() { let sha = GitSha::new("0123456789abcdef0123456789abcdef01234567").unwrap(); let info = GitInfo::new(sha).with_dirty(true); - + assert!(!info.is_clean()); assert!(info.is_dirty); } diff --git a/crates/lintdiff-glob/src/lib.rs b/crates/lintdiff-glob/src/lib.rs index 3be8c62..428a5f2 100644 --- a/crates/lintdiff-glob/src/lib.rs +++ b/crates/lintdiff-glob/src/lib.rs @@ -163,7 +163,7 @@ impl Glob { // Check if this is a globstar (**) if chars.peek() == Some(&'*') { chars.next(); // consume the second * - // Flush any pending literal + // Flush any pending literal if !current_literal.is_empty() { segments.push(PatternSegment::Literal(current_literal.clone())); current_literal.clear(); @@ -214,7 +214,9 @@ impl Glob { } /// Parse a character class starting after the opening `[`. - fn parse_char_class(chars: &mut std::iter::Peekable) -> Result { + fn parse_char_class( + chars: &mut std::iter::Peekable, + ) -> Result { let mut negated = false; let mut entries = Vec::new(); @@ -294,7 +296,11 @@ impl Glob { } /// Match a path against the parsed segments. - fn match_segments(segments: &[PatternSegment], path: &str, path_separator: Option) -> bool { + fn match_segments( + segments: &[PatternSegment], + path: &str, + path_separator: Option, + ) -> bool { if segments.is_empty() { return path.is_empty(); } @@ -356,7 +362,11 @@ impl Glob { // Try matching from each possible position for start_pos in path_idx..=chars.len() { - if Self::match_segments(&segments[next_seg_idx..], &chars[start_pos..].iter().collect::(), path_separator) { + if Self::match_segments( + &segments[next_seg_idx..], + &chars[start_pos..].iter().collect::(), + path_separator, + ) { return true; } } @@ -394,7 +404,11 @@ impl Glob { } /// Find the position after a wildcard that allows the rest to match. - fn match_after_wildcard(remaining_segments: &[PatternSegment], chars: &[char], path_separator: Option) -> Option { + fn match_after_wildcard( + remaining_segments: &[PatternSegment], + chars: &[char], + path_separator: Option, + ) -> Option { for end_pos in 0..=chars.len() { // Check if we hit a path separator (if we have one) if let Some(sep) = path_separator { @@ -402,7 +416,11 @@ impl Glob { break; } } - if Self::match_segments(remaining_segments, &chars[end_pos..].iter().collect::(), path_separator) { + if Self::match_segments( + remaining_segments, + &chars[end_pos..].iter().collect::(), + path_separator, + ) { return Some(end_pos); } } diff --git a/crates/lintdiff-glob/tests/glob_tests.rs b/crates/lintdiff-glob/tests/glob_tests.rs index 102940d..5ab900a 100644 --- a/crates/lintdiff-glob/tests/glob_tests.rs +++ b/crates/lintdiff-glob/tests/glob_tests.rs @@ -640,7 +640,7 @@ fn test_star_at_end() { #[test] fn test_double_star_not_globstar() { - // When ** is not between separators, it should act as two * + // When ** is not between separators, it should act as two * let glob = Glob::new("file**.rs").unwrap(); assert!(glob.is_match("file.rs")); assert!(glob.is_match("file_extra.rs")); @@ -780,7 +780,7 @@ fn test_star_question_combination() { let glob = Glob::new("*?.rs").unwrap(); assert!(glob.is_match("ab.rs")); // * matches a, ? matches b assert!(glob.is_match("abc.rs")); // * matches ab, ? matches c - // * can match empty, so a.rs works: * matches "", ? matches "a" + // * can match empty, so a.rs works: * matches "", ? matches "a" assert!(glob.is_match("a.rs")); assert!(!glob.is_match(".rs")); // ? needs at least one char } diff --git a/crates/lintdiff-host-info/tests/host_info_tests.rs b/crates/lintdiff-host-info/tests/host_info_tests.rs index 0503be6..c24396d 100644 --- a/crates/lintdiff-host-info/tests/host_info_tests.rs +++ b/crates/lintdiff-host-info/tests/host_info_tests.rs @@ -9,8 +9,8 @@ //! - Property-based tests with proptest use lintdiff_host_info::{ - detect_arch, detect_host, detect_os, format_host_info, format_oci_platform, - format_rust_target, get_hostname, ArchType, HostInfo, OsType, + detect_arch, detect_host, detect_os, format_host_info, format_oci_platform, format_rust_target, + get_hostname, ArchType, HostInfo, OsType, }; use proptest::prelude::*; @@ -133,7 +133,7 @@ fn arch_type_detect_returns_valid_variant() { #[test] fn host_info_new_creates_instance_with_all_fields() { let info = HostInfo::new(OsType::Linux, ArchType::X64, Some("testhost".to_string())); - + assert_eq!(info.os, OsType::Linux); assert_eq!(info.arch, ArchType::X64); assert_eq!(info.hostname, Some("testhost".to_string())); @@ -142,7 +142,7 @@ fn host_info_new_creates_instance_with_all_fields() { #[test] fn host_info_new_accepts_none_hostname() { let info = HostInfo::new(OsType::Windows, ArchType::Arm64, None); - + assert_eq!(info.os, OsType::Windows); assert_eq!(info.arch, ArchType::Arm64); assert_eq!(info.hostname, None); @@ -151,7 +151,7 @@ fn host_info_new_accepts_none_hostname() { #[test] fn host_info_without_hostname_creates_instance_with_none_hostname() { let info = HostInfo::without_hostname(OsType::MacOS, ArchType::Arm64); - + assert_eq!(info.os, OsType::MacOS); assert_eq!(info.arch, ArchType::Arm64); assert_eq!(info.hostname, None); @@ -160,21 +160,17 @@ fn host_info_without_hostname_creates_instance_with_none_hostname() { #[test] fn host_info_detect_returns_valid_info() { let info = HostInfo::detect(); - + // OS and arch should be valid detected values - assert!( - ["windows", "linux", "macos", "freebsd", "other"].contains(&info.os.as_str()) - ); - assert!( - ["x86", "x64", "arm", "arm64", "other"].contains(&info.arch.as_str()) - ); + assert!(["windows", "linux", "macos", "freebsd", "other"].contains(&info.os.as_str())); + assert!(["x86", "x64", "arm", "arm64", "other"].contains(&info.arch.as_str())); } #[test] fn host_info_default_returns_detected_info() { let info = HostInfo::default(); let detected = HostInfo::detect(); - + assert_eq!(info.os, detected.os); assert_eq!(info.arch, detected.arch); } @@ -183,7 +179,7 @@ fn host_info_default_returns_detected_info() { fn host_info_is_cloneable() { let info = HostInfo::new(OsType::Linux, ArchType::X64, Some("host".to_string())); let cloned = info.clone(); - + assert_eq!(info, cloned); } @@ -204,7 +200,7 @@ fn detect_arch_function_returns_same_as_type_method() { #[test] fn detect_host_function_returns_complete_info() { let info = detect_host(); - + assert_eq!(info.os, detect_os()); assert_eq!(info.arch, detect_arch()); } @@ -223,21 +219,21 @@ fn get_hostname_function_returns_string_or_none() { #[test] fn format_host_info_with_hostname_includes_hostname() { let info = HostInfo::new(OsType::Linux, ArchType::X64, Some("myhost".to_string())); - + assert_eq!(format_host_info(&info), "myhost (linux/x64)"); } #[test] fn format_host_info_without_hostname_omits_hostname() { let info = HostInfo::without_hostname(OsType::Windows, ArchType::X64); - + assert_eq!(format_host_info(&info), "windows/x64"); } #[test] fn format_host_info_with_empty_hostname_treated_as_none() { let info = HostInfo::new(OsType::Linux, ArchType::X64, Some(String::new())); - + // Empty hostname is still displayed assert_eq!(format_host_info(&info), " (linux/x64)"); } @@ -392,7 +388,7 @@ fn format_oci_platform_all_architectures() { fn host_info_with_very_long_hostname() { let long_hostname = "a".repeat(256); let info = HostInfo::new(OsType::Linux, ArchType::X64, Some(long_hostname.clone())); - + assert_eq!(info.hostname, Some(long_hostname)); } @@ -400,7 +396,7 @@ fn host_info_with_very_long_hostname() { fn host_info_with_unicode_hostname() { let unicode_hostname = "主机名-ホストネーム-🏠".to_string(); let info = HostInfo::new(OsType::Linux, ArchType::X64, Some(unicode_hostname.clone())); - + assert_eq!(info.hostname, Some(unicode_hostname)); } @@ -408,7 +404,7 @@ fn host_info_with_unicode_hostname() { fn format_host_info_preserves_unicode() { let unicode_hostname = "тест".to_string(); let info = HostInfo::new(OsType::Linux, ArchType::X64, Some(unicode_hostname)); - + let formatted = format_host_info(&info); assert!(formatted.contains("тест")); } @@ -437,7 +433,7 @@ fn os_type_can_be_used_in_hashset() { set.insert(OsType::Linux); set.insert(OsType::Windows); set.insert(OsType::Linux); // Duplicate - + assert_eq!(set.len(), 2); assert!(set.contains(&OsType::Linux)); assert!(set.contains(&OsType::Windows)); @@ -449,7 +445,7 @@ fn arch_type_can_be_used_in_hashset() { set.insert(ArchType::X64); set.insert(ArchType::Arm64); set.insert(ArchType::X64); // Duplicate - + assert_eq!(set.len(), 2); assert!(set.contains(&ArchType::X64)); assert!(set.contains(&ArchType::Arm64)); @@ -491,7 +487,7 @@ proptest! { 3 => OsType::FreeBSD, _ => OsType::Other, }; - + let arch_type = match arch % 5 { 0 => ArchType::X86, 1 => ArchType::X64, @@ -499,11 +495,11 @@ proptest! { 3 => ArchType::Arm64, _ => ArchType::Other, }; - + let info = HostInfo::new(os_type, arch_type, hostname); let _formatted = format_host_info(&info); } - + #[test] fn format_rust_target_never_panics( os in 0..5usize, @@ -516,7 +512,7 @@ proptest! { 3 => OsType::FreeBSD, _ => OsType::Other, }; - + let arch_type = match arch % 5 { 0 => ArchType::X86, 1 => ArchType::X64, @@ -524,11 +520,11 @@ proptest! { 3 => ArchType::Arm64, _ => ArchType::Other, }; - + let info = HostInfo::without_hostname(os_type, arch_type); let _target = format_rust_target(&info); } - + #[test] fn format_oci_platform_never_panics( os in 0..5usize, @@ -541,7 +537,7 @@ proptest! { 3 => OsType::FreeBSD, _ => OsType::Other, }; - + let arch_type = match arch % 5 { 0 => ArchType::X86, 1 => ArchType::X64, @@ -549,11 +545,11 @@ proptest! { 3 => ArchType::Arm64, _ => ArchType::Other, }; - + let info = HostInfo::without_hostname(os_type, arch_type); let _platform = format_oci_platform(&info); } - + #[test] fn os_type_as_str_returns_non_empty_string(os in 0..5usize) { let os_type = match os % 5 { @@ -563,11 +559,11 @@ proptest! { 3 => OsType::FreeBSD, _ => OsType::Other, }; - + let s = os_type.as_str(); prop_assert!(!s.is_empty()); } - + #[test] fn arch_type_as_str_returns_non_empty_string(arch in 0..5usize) { let arch_type = match arch % 5 { @@ -577,7 +573,7 @@ proptest! { 3 => ArchType::Arm64, _ => ArchType::Other, }; - + let s = arch_type.as_str(); prop_assert!(!s.is_empty()); } @@ -591,7 +587,7 @@ proptest! { fn format_rust_target_contains_arch_and_os() { let info = HostInfo::without_hostname(OsType::Linux, ArchType::X64); let target = format_rust_target(&info); - + assert!(target.contains("x86_64") || target.contains("x64")); assert!(target.contains("linux")); } @@ -600,7 +596,7 @@ fn format_rust_target_contains_arch_and_os() { fn format_oci_platform_has_correct_format() { let info = HostInfo::without_hostname(OsType::Linux, ArchType::Arm64); let platform = format_oci_platform(&info); - + // Should be in format "os/arch" let parts: Vec<&str> = platform.split('/').collect(); assert_eq!(parts.len(), 2); @@ -612,7 +608,7 @@ fn format_oci_platform_has_correct_format() { fn format_host_info_with_hostname_has_parens() { let info = HostInfo::new(OsType::Linux, ArchType::X64, Some("host".to_string())); let formatted = format_host_info(&info); - + assert!(formatted.contains('(')); assert!(formatted.contains(')')); assert!(formatted.contains('/')); @@ -622,7 +618,7 @@ fn format_host_info_with_hostname_has_parens() { fn format_host_info_without_hostname_has_no_parens() { let info = HostInfo::without_hostname(OsType::Linux, ArchType::X64); let formatted = format_host_info(&info); - + assert!(!formatted.contains('(')); assert!(!formatted.contains(')')); assert!(formatted.contains('/')); diff --git a/crates/lintdiff-hunk-header/src/lib.rs b/crates/lintdiff-hunk-header/src/lib.rs index 9d7e0f9..bb61de9 100644 --- a/crates/lintdiff-hunk-header/src/lib.rs +++ b/crates/lintdiff-hunk-header/src/lib.rs @@ -102,7 +102,12 @@ impl HunkHeader { /// assert_eq!(header.new_count(), 5); /// ``` #[must_use] - pub const fn new(old_start: usize, old_count: usize, new_start: usize, new_count: usize) -> Self { + pub const fn new( + old_start: usize, + old_count: usize, + new_start: usize, + new_count: usize, + ) -> Self { Self { old_start, old_count, @@ -480,7 +485,9 @@ pub fn parse_hunk_header(s: &str) -> Result, HunkHeaderError> let (old_start, old_count) = parse_range(minus_seg, true)?; let (new_start, new_count) = parse_range(plus_seg, false)?; - Ok(Some(HunkHeader::new(old_start, old_count, new_start, new_count))) + Ok(Some(HunkHeader::new( + old_start, old_count, new_start, new_count, + ))) } /// Parse a range segment like "1,4" or "1". diff --git a/crates/lintdiff-hunk-header/tests/hunk_header_tests.rs b/crates/lintdiff-hunk-header/tests/hunk_header_tests.rs index 07ab006..b9a8935 100644 --- a/crates/lintdiff-hunk-header/tests/hunk_header_tests.rs +++ b/crates/lintdiff-hunk-header/tests/hunk_header_tests.rs @@ -12,7 +12,7 @@ //! 9. Display trait round-trip (5 tests) //! 10. Property-based tests with proptest (5 tests) -use lintdiff_hunk_header::{HunkHeader, HunkHeaderError, parse_hunk_header}; +use lintdiff_hunk_header::{parse_hunk_header, HunkHeader, HunkHeaderError}; // ============================================================================= // 1. HunkHeader creation (10 tests) @@ -315,7 +315,9 @@ fn test_parse_standard_hunk_header() { #[test] fn test_parse_with_large_numbers() { - let header = parse_hunk_header("@@ -1000,500 +2000,750 @@").unwrap().unwrap(); + let header = parse_hunk_header("@@ -1000,500 +2000,750 @@") + .unwrap() + .unwrap(); assert_eq!(header.old_start(), 1000); assert_eq!(header.old_count(), 500); assert_eq!(header.new_start(), 2000); @@ -324,7 +326,9 @@ fn test_parse_with_large_numbers() { #[test] fn test_parse_with_context_after() { - let header = parse_hunk_header("@@ -1,4 +1,5 @@ function name()").unwrap().unwrap(); + let header = parse_hunk_header("@@ -1,4 +1,5 @@ function name()") + .unwrap() + .unwrap(); assert_eq!(header.old_start(), 1); assert_eq!(header.old_count(), 4); assert_eq!(header.new_start(), 1); @@ -508,7 +512,9 @@ fn test_line_count_calculation() { #[test] fn test_parse_with_function_context() { // Git sometimes includes function context after the header - let header = parse_hunk_header("@@ -1,4 +1,5 @@ fn main() {").unwrap().unwrap(); + let header = parse_hunk_header("@@ -1,4 +1,5 @@ fn main() {") + .unwrap() + .unwrap(); assert_eq!(header.old_start(), 1); assert_eq!(header.old_count(), 4); assert_eq!(header.new_start(), 1); @@ -702,7 +708,9 @@ proptest! { #[test] fn test_parse_with_tabs() { - let header = parse_hunk_header("@@ -1,4 +1,5 @@\tsome context").unwrap().unwrap(); + let header = parse_hunk_header("@@ -1,4 +1,5 @@\tsome context") + .unwrap() + .unwrap(); assert_eq!(header.old_start(), 1); assert_eq!(header.old_count(), 4); } @@ -766,7 +774,9 @@ fn test_hash_trait() { #[test] fn test_parse_returns_none_for_diff_header() { // A diff --git line should not be parsed as a hunk header - assert!(parse_hunk_header("diff --git a/file.rs b/file.rs").unwrap().is_none()); + assert!(parse_hunk_header("diff --git a/file.rs b/file.rs") + .unwrap() + .is_none()); } #[test] diff --git a/crates/lintdiff-line-merge/tests/line_merge_tests.rs b/crates/lintdiff-line-merge/tests/line_merge_tests.rs index 915b328..905122f 100644 --- a/crates/lintdiff-line-merge/tests/line_merge_tests.rs +++ b/crates/lintdiff-line-merge/tests/line_merge_tests.rs @@ -547,9 +547,8 @@ mod merge_ranges_inplace_feature { #[test] fn it_preserves_capacity_for_large_inputs() { - let mut ranges: Vec<(usize, usize)> = (0..1000) - .map(|i| (i * 20, i * 20 + 10)) - .collect(); + let mut ranges: Vec<(usize, usize)> = + (0..1000).map(|i| (i * 20, i * 20 + 10)).collect(); merge_ranges_inplace(&mut ranges); @@ -561,9 +560,7 @@ mod merge_ranges_inplace_feature { #[test] fn it_dramatically_reduces_size_for_overlapping() { - let mut ranges: Vec<(usize, usize)> = (0..1000) - .map(|i| (1, i + 10)) - .collect(); + let mut ranges: Vec<(usize, usize)> = (0..1000).map(|i| (1, i + 10)).collect(); merge_ranges_inplace(&mut ranges); @@ -986,10 +983,10 @@ mod integration_tests { fn diff_hunk_merging_scenario() { // Simulate diff hunks from a file let hunks = vec![ - (10, 20), // First change - (15, 25), // Overlapping change - (50, 60), // Separate change - (55, 65), // Overlapping with third + (10, 20), // First change + (15, 25), // Overlapping change + (50, 60), // Separate change + (55, 65), // Overlapping with third (100, 110), // Separate change ]; @@ -1057,9 +1054,7 @@ mod integration_tests { #[test] fn worst_case_merge_scenario() { // All ranges overlap - worst case for merge algorithm - let ranges: Vec<(usize, usize)> = (0..100) - .map(|i| (1, 100 + i)) - .collect(); + let ranges: Vec<(usize, usize)> = (0..100).map(|i| (1, 100 + i)).collect(); let merged = merge_ranges(&ranges); diff --git a/crates/lintdiff-locale-detect/src/lib.rs b/crates/lintdiff-locale-detect/src/lib.rs index f6971eb..58e7b60 100644 --- a/crates/lintdiff-locale-detect/src/lib.rs +++ b/crates/lintdiff-locale-detect/src/lib.rs @@ -89,7 +89,11 @@ impl Locale { /// assert_eq!(locale.script, Some("Cyrl".to_string())); /// ``` #[must_use] - pub fn with_script(language: impl Into, region: impl Into, script: impl Into) -> Self { + pub fn with_script( + language: impl Into, + region: impl Into, + script: impl Into, + ) -> Self { Self { language: language.into().to_lowercase(), region: Some(region.into().to_uppercase()), @@ -115,15 +119,15 @@ impl Locale { #[must_use] pub fn to_bcp47(&self) -> String { let mut parts = vec![self.language.clone()]; - + if let Some(script) = &self.script { parts.push(script.clone()); } - + if let Some(region) = &self.region { parts.push(region.clone()); } - + parts.join("-") } @@ -240,26 +244,26 @@ pub fn default_locale() -> Locale { #[must_use] pub fn parse_locale(s: &str) -> Option { let s = s.trim(); - + if s.is_empty() { return None; } - + // Handle encoding suffix (e.g., "en_US.UTF-8") let s = s.split('.').next()?.trim(); - + // Try BCP47 format first (language-Script-Region or language-Region) if s.contains('-') { let parts: Vec<&str> = s.split('-').collect(); return parse_bcp47_parts(&parts); } - + // Try POSIX format (language_Script_Region or language_Region) if s.contains('_') { let parts: Vec<&str> = s.split('_').collect(); return parse_posix_parts(&parts); } - + // Just a language code if is_valid_language_code(s) { Some(Locale::new(s)) @@ -273,12 +277,12 @@ fn parse_bcp47_parts(parts: &[&str]) -> Option { if parts.is_empty() { return None; } - + let language = parts[0]; if !is_valid_language_code(language) { return None; } - + match parts.len() { 1 => Some(Locale::new(language)), 2 => { @@ -299,7 +303,7 @@ fn parse_bcp47_parts(parts: &[&str]) -> Option { 3 => { let second = parts[1]; let third = parts[2]; - + // Format: language-script-region if is_valid_script_code(second) && is_valid_region_code(third) { Some(Locale::with_script(language, third, second)) @@ -316,12 +320,12 @@ fn parse_posix_parts(parts: &[&str]) -> Option { if parts.is_empty() { return None; } - + let language = parts[0]; if !is_valid_language_code(language) { return None; } - + match parts.len() { 1 => Some(Locale::new(language)), 2 => { @@ -342,7 +346,7 @@ fn parse_posix_parts(parts: &[&str]) -> Option { 3 => { let second = parts[1]; let third = parts[2]; - + // Format: language_script_region if is_valid_script_code(second) && is_valid_region_code(third) { Some(Locale::with_script(language, third, second)) @@ -412,7 +416,10 @@ mod tests { fn test_to_bcp47() { assert_eq!(Locale::new("en").to_bcp47(), "en"); assert_eq!(Locale::with_region("en", "US").to_bcp47(), "en-US"); - assert_eq!(Locale::with_script("zh", "CN", "Hans").to_bcp47(), "zh-Hans-CN"); + assert_eq!( + Locale::with_script("zh", "CN", "Hans").to_bcp47(), + "zh-Hans-CN" + ); } #[test] diff --git a/crates/lintdiff-locale-detect/tests/locale_tests.rs b/crates/lintdiff-locale-detect/tests/locale_tests.rs index f7e6141..07809ff 100644 --- a/crates/lintdiff-locale-detect/tests/locale_tests.rs +++ b/crates/lintdiff-locale-detect/tests/locale_tests.rs @@ -1,6 +1,6 @@ //! Comprehensive tests for the lintdiff-locale-detect crate. -use lintdiff_locale_detect::{Locale, default_locale, detect_system_locale, parse_locale}; +use lintdiff_locale_detect::{default_locale, detect_system_locale, parse_locale, Locale}; // ============================================================================ // Locale Creation Tests @@ -18,7 +18,7 @@ fn test_locale_new_creates_language_only_locale() { fn test_locale_new_normalizes_to_lowercase() { let locale = Locale::new("EN"); assert_eq!(locale.language, "en"); - + let locale = Locale::new("En"); assert_eq!(locale.language, "en"); } @@ -138,7 +138,7 @@ fn test_matches_language_returns_false_for_different_language() { fn test_matches_language_ignores_region() { let locale = Locale::with_region("en", "GB"); assert!(locale.matches_language("en")); - + let locale = Locale::with_region("en", "US"); assert!(locale.matches_language("en")); } @@ -263,11 +263,11 @@ fn test_parse_locale_posix_various_locales() { let locale = parse_locale("es_ES").unwrap(); assert_eq!(locale.language, "es"); assert_eq!(locale.region, Some("ES".to_string())); - + let locale = parse_locale("fr_FR").unwrap(); assert_eq!(locale.language, "fr"); assert_eq!(locale.region, Some("FR".to_string())); - + let locale = parse_locale("de_DE").unwrap(); assert_eq!(locale.language, "de"); assert_eq!(locale.region, Some("DE".to_string())); diff --git a/crates/lintdiff-location/src/lib.rs b/crates/lintdiff-location/src/lib.rs index 1d41663..e8a562c 100644 --- a/crates/lintdiff-location/src/lib.rs +++ b/crates/lintdiff-location/src/lib.rs @@ -248,9 +248,7 @@ impl Location { /// ``` #[must_use] pub fn extension(&self) -> Option<&str> { - Path::new(&self.path) - .extension() - .and_then(|s| s.to_str()) + Path::new(&self.path).extension().and_then(|s| s.to_str()) } /// Get the file name (if any). @@ -264,9 +262,7 @@ impl Location { /// ``` #[must_use] pub fn file_name(&self) -> Option<&str> { - Path::new(&self.path) - .file_name() - .and_then(|s| s.to_str()) + Path::new(&self.path).file_name().and_then(|s| s.to_str()) } /// Get the parent directory (if any). @@ -544,11 +540,7 @@ impl LocationRange { /// ``` #[must_use] pub fn start(&self) -> Location { - Location::from_parts( - self.path.clone(), - Some(self.start_line), - self.start_column, - ) + Location::from_parts(self.path.clone(), Some(self.start_line), self.start_column) } /// Get the end location. diff --git a/crates/lintdiff-location/tests/location_tests.rs b/crates/lintdiff-location/tests/location_tests.rs index e973edb..0e65c9e 100644 --- a/crates/lintdiff-location/tests/location_tests.rs +++ b/crates/lintdiff-location/tests/location_tests.rs @@ -11,7 +11,7 @@ //! 8. parse_location function (10 tests) //! 9. Error cases (3 tests) -use lintdiff_location::{Location, LocationParseError, LocationRange, parse_location}; +use lintdiff_location::{parse_location, Location, LocationParseError, LocationRange}; // ============================================================================= // 1. Location creation methods (10 tests) diff --git a/crates/lintdiff-message-norm/src/lib.rs b/crates/lintdiff-message-norm/src/lib.rs index 22951e0..c1c634c 100644 --- a/crates/lintdiff-message-norm/src/lib.rs +++ b/crates/lintdiff-message-norm/src/lib.rs @@ -151,7 +151,8 @@ impl NormalizeConfig { // Step 3: Collapse internal whitespace if self.collapse_whitespace { - let has_multiple_spaces = result.contains(" ") || result.contains("\t ") || result.contains("\t\t"); + let has_multiple_spaces = + result.contains(" ") || result.contains("\t ") || result.contains("\t\t"); if has_multiple_spaces { let mut collapsed = String::with_capacity(result.len()); let mut prev_was_space = false; @@ -501,7 +502,12 @@ fn unescape_html(message: &str) -> Cow<'_, str> { if chars[i] == '&' { // Look for semicolon let mut semicolon_pos = None; - for (j, &ch) in chars.iter().enumerate().take(chars.len().min(i + 12)).skip(i + 1) { + for (j, &ch) in chars + .iter() + .enumerate() + .take(chars.len().min(i + 12)) + .skip(i + 1) + { if ch == ';' { semicolon_pos = Some(j); break; @@ -650,12 +656,23 @@ fn escape_markdown(message: &str) -> Cow<'_, str> { let needs_escape = message.chars().any(|c| { matches!( c, - '\\' | '`' | '*' - | '_' | '{' | '}' - | '[' | ']' | '(' - | ')' | '#' | '+' - | '-' | '.' | '!' - | '|' | '~' | '>' + '\\' | '`' + | '*' + | '_' + | '{' + | '}' + | '[' + | ']' + | '(' + | ')' + | '#' + | '+' + | '-' + | '.' + | '!' + | '|' + | '~' + | '>' ) }); @@ -666,8 +683,8 @@ fn escape_markdown(message: &str) -> Cow<'_, str> { let mut result = String::with_capacity(message.len() + message.len() / 4); for c in message.chars() { match c { - '\\' | '`' | '*' | '_' | '{' | '}' | '[' | ']' | '(' | ')' | '#' | '+' | '-' - | '.' | '!' | '|' | '~' | '>' => { + '\\' | '`' | '*' | '_' | '{' | '}' | '[' | ']' | '(' | ')' | '#' | '+' | '-' | '.' + | '!' | '|' | '~' | '>' => { result.push('\\'); result.push(c); } @@ -691,12 +708,23 @@ fn unescape_markdown(message: &str) -> Cow<'_, str> { // Unescape known markdown characters if matches!( next, - '\\' | '`' | '*' - | '_' | '{' | '}' - | '[' | ']' | '(' - | ')' | '#' | '+' - | '-' | '.' | '!' - | '|' | '~' | '>' + '\\' | '`' + | '*' + | '_' + | '{' + | '}' + | '[' + | ']' + | '(' + | ')' + | '#' + | '+' + | '-' + | '.' + | '!' + | '|' + | '~' + | '>' ) { result.push(next); chars.next(); diff --git a/crates/lintdiff-message-norm/tests/message_norm_tests.rs b/crates/lintdiff-message-norm/tests/message_norm_tests.rs index 01d30ff..2bf6991 100644 --- a/crates/lintdiff-message-norm/tests/message_norm_tests.rs +++ b/crates/lintdiff-message-norm/tests/message_norm_tests.rs @@ -11,8 +11,8 @@ //! Total: 60 tests use lintdiff_message_norm::{ - escape, has_ansi, normalize, normalize_owned, strip_ansi, truncate, truncate_at_word, - unescape, EscapeFormat, NormalizedMessage, NormalizeConfig, + escape, has_ansi, normalize, normalize_owned, strip_ansi, truncate, truncate_at_word, unescape, + EscapeFormat, NormalizeConfig, NormalizedMessage, }; // ============================================================================= @@ -168,7 +168,9 @@ mod normalize_config_tests { #[test] fn config_with_suffix_uses_custom_suffix() { - let config = NormalizeConfig::new().with_max_length(10).with_suffix("..."); + let config = NormalizeConfig::new() + .with_max_length(10) + .with_suffix("..."); assert_eq!(config.truncation_suffix, "..."); let result = config.normalize("hello world this is long"); assert!(result.ends_with("...")); @@ -377,7 +379,10 @@ mod escape_tests { #[test] fn escape_json_escapes_backslash() { - assert_eq!(escape("path\\to\\file", EscapeFormat::Json), "path\\\\to\\\\file"); + assert_eq!( + escape("path\\to\\file", EscapeFormat::Json), + "path\\\\to\\\\file" + ); } #[test] @@ -526,7 +531,10 @@ mod unescape_tests { #[test] fn unescape_json_unescapes_newlines() { - assert_eq!(unescape("hello\\nworld", EscapeFormat::Json), "hello\nworld"); + assert_eq!( + unescape("hello\\nworld", EscapeFormat::Json), + "hello\nworld" + ); } #[test] diff --git a/crates/lintdiff-message-truncate/src/lib.rs b/crates/lintdiff-message-truncate/src/lib.rs index 84a4d38..598ae6f 100644 --- a/crates/lintdiff-message-truncate/src/lib.rs +++ b/crates/lintdiff-message-truncate/src/lib.rs @@ -254,7 +254,11 @@ pub fn truncate_words(s: &str, max_words: usize) -> String { } // Take only max_words words and join them - let result: String = words.into_iter().take(max_words).collect::>().join(" "); + let result: String = words + .into_iter() + .take(max_words) + .collect::>() + .join(" "); if result.is_empty() { return DEFAULT_ELLIPSIS.to_string(); @@ -465,7 +469,10 @@ mod tests { #[test] fn test_truncate_words_basic() { - assert_eq!(truncate_words("Hello beautiful world", 2), "Hello beautiful..."); + assert_eq!( + truncate_words("Hello beautiful world", 2), + "Hello beautiful..." + ); assert_eq!(truncate_words("One two", 5), "One two"); } diff --git a/crates/lintdiff-message-truncate/tests/message_truncate_tests.rs b/crates/lintdiff-message-truncate/tests/message_truncate_tests.rs index b6630f2..cfed83a 100644 --- a/crates/lintdiff-message-truncate/tests/message_truncate_tests.rs +++ b/crates/lintdiff-message-truncate/tests/message_truncate_tests.rs @@ -371,7 +371,10 @@ mod truncate_words_tests { #[test] fn basic_word_truncation() { // Words are normalized with single spaces - assert_eq!(truncate_words("Hello beautiful world", 2), "Hello beautiful..."); + assert_eq!( + truncate_words("Hello beautiful world", 2), + "Hello beautiful..." + ); } #[test] @@ -872,7 +875,8 @@ mod integration_tests { #[test] fn full_workflow_custom_options() { - let message = "Error: Something went wrong. Please try again later. Contact support if needed."; + let message = + "Error: Something went wrong. Please try again later. Contact support if needed."; let options = TruncateOptions::new(50) .with_ellipsis("…") .with_preserve_sentences(true); diff --git a/crates/lintdiff-path-norm/src/lib.rs b/crates/lintdiff-path-norm/src/lib.rs index 91a7794..9fa29b5 100644 --- a/crates/lintdiff-path-norm/src/lib.rs +++ b/crates/lintdiff-path-norm/src/lib.rs @@ -133,7 +133,9 @@ impl NormalizeConfig { // Step 3: Strip diff prefixes (a/ or b/) if self.strip_diff_prefix { - let stripped = result.strip_prefix("a/").or_else(|| result.strip_prefix("b/")); + let stripped = result + .strip_prefix("a/") + .or_else(|| result.strip_prefix("b/")); if let Some(s) = stripped { result = Cow::Owned(s.to_owned()); } @@ -202,15 +204,15 @@ pub fn extension(path: &str) -> Option<&str> { // Handle both forward and backslashes let last_sep = path.rfind(&['/', '\\'][..]).map_or(0, |i| i + 1); let filename = &path[last_sep..]; - + // Find the extension (after last .) let dot_pos = filename.rfind('.')?; - + // Extension must not be the first character (hidden files like .gitignore) if dot_pos == 0 { return None; } - + Some(&filename[dot_pos + 1..]) } @@ -228,22 +230,23 @@ pub fn file_name(path: &str) -> Option<&str> { if path.is_empty() { return None; } - + // If path ends with a slash, it's a directory - no file name if path.ends_with('/') || path.ends_with('\\') { return None; } - + // Find the last separator (forward or backslash) let last_sep = path.rfind(&['/', '\\'][..]); - - last_sep.map_or( - if path.is_empty() { None } else { Some(path) }, - |pos| { - let name = &path[pos + 1..]; - if name.is_empty() { None } else { Some(name) } - }, - ) + + last_sep.map_or(if path.is_empty() { None } else { Some(path) }, |pos| { + let name = &path[pos + 1..]; + if name.is_empty() { + None + } else { + Some(name) + } + }) } /// Extracts the parent directory from a path. @@ -260,17 +263,17 @@ pub fn parent(path: &str) -> Option<&str> { if path.is_empty() { return None; } - + // Strip trailing slashes let path = path.trim_end_matches(&['/', '\\'][..]); - + if path.is_empty() { return None; } - + // Find the last separator (forward or backslash) let last_sep = path.rfind(&['/', '\\'][..])?; - + // Return everything before the last separator Some(&path[..last_sep]) } diff --git a/crates/lintdiff-path-norm/tests/path_norm_tests.rs b/crates/lintdiff-path-norm/tests/path_norm_tests.rs index 016264a..be74a1a 100644 --- a/crates/lintdiff-path-norm/tests/path_norm_tests.rs +++ b/crates/lintdiff-path-norm/tests/path_norm_tests.rs @@ -261,7 +261,10 @@ fn test_paths_cmp_less() { #[test] fn test_paths_cmp_greater() { - assert_eq!(paths_cmp("src/b.rs", "src/a.rs"), std::cmp::Ordering::Greater); + assert_eq!( + paths_cmp("src/b.rs", "src/a.rs"), + std::cmp::Ordering::Greater + ); } // ============================================================================= @@ -354,10 +357,7 @@ fn test_join_empty() { #[test] fn test_join_multiple_components() { - assert_eq!( - join(&["a", "b", "c", "d", "e.rs"]), - "a/b/c/d/e.rs" - ); + assert_eq!(join(&["a", "b", "c", "d", "e.rs"]), "a/b/c/d/e.rs"); } // ============================================================================= diff --git a/crates/lintdiff-range-merge/src/lib.rs b/crates/lintdiff-range-merge/src/lib.rs index 3d8d0b4..ec196d2 100644 --- a/crates/lintdiff-range-merge/src/lib.rs +++ b/crates/lintdiff-range-merge/src/lib.rs @@ -235,7 +235,10 @@ impl LineRange { if !self.overlaps_or_adjacent(other) { return None; } - Some(Self::new(min(self.start, other.start), max(self.end, other.end))) + Some(Self::new( + min(self.start, other.start), + max(self.end, other.end), + )) } /// Get the intersection of this range with another. @@ -257,7 +260,10 @@ impl LineRange { if !self.intersects(other) { return None; } - Some(Self::new(max(self.start, other.start), min(self.end, other.end))) + Some(Self::new( + max(self.start, other.start), + min(self.end, other.end), + )) } } @@ -342,7 +348,7 @@ pub fn merge_lines(lines: &[usize]) -> Vec { } let mut result = Vec::new(); - + // Get the first line to start - safe because we checked is_empty above let (first, rest) = lines.split_first().unwrap_or((&0, &[])); let mut current_start = *first; @@ -363,7 +369,7 @@ pub fn merge_lines(lines: &[usize]) -> Vec { // Don't forget the last range result.push(LineRange::new(current_start, current_end)); - + result } @@ -418,10 +424,7 @@ pub fn merge_overlapping(ranges: &[LineRange]) -> Vec { for next in sorted.iter().skip(1) { if current.overlaps_or_adjacent(next) { // Merge the ranges - current = LineRange::new( - min(current.start, next.start), - max(current.end, next.end), - ); + current = LineRange::new(min(current.start, next.start), max(current.end, next.end)); } else { result.push(current); current = *next; @@ -623,10 +626,7 @@ pub const fn overlaps_or_adjacent(a: &LineRange, b: &LineRange) -> bool { /// ``` #[must_use] pub fn expand_to_include(range: &LineRange, line: usize) -> LineRange { - LineRange::new( - min(range.start, line), - max(range.end, line), - ) + LineRange::new(min(range.start, line), max(range.end, line)) } /// Check if one range fully contains another. @@ -670,7 +670,7 @@ pub const fn gap_between(a: &LineRange, b: &LineRange) -> Option { if a.overlaps_or_adjacent(b) { return None; } - + if a.end < b.start { Some(b.start - a.end - 1) } else { @@ -750,10 +750,7 @@ mod tests { #[test] fn merge_overlapping_overlapping_ranges_merge() { - let ranges = vec![ - LineRange::new(1, 5), - LineRange::new(3, 7), - ]; + let ranges = vec![LineRange::new(1, 5), LineRange::new(3, 7)]; let result = merge_overlapping(&ranges); assert_eq!(result.len(), 1); assert_eq!(result[0], LineRange::new(1, 7)); @@ -761,10 +758,7 @@ mod tests { #[test] fn merge_overlapping_adjacent_ranges_merge() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(11, 20), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(11, 20)]; let result = merge_overlapping(&ranges); assert_eq!(result.len(), 1); assert_eq!(result[0], LineRange::new(1, 20)); diff --git a/crates/lintdiff-range-merge/tests/range_merge_tests.rs b/crates/lintdiff-range-merge/tests/range_merge_tests.rs index 0fc2958..5d13301 100644 --- a/crates/lintdiff-range-merge/tests/range_merge_tests.rs +++ b/crates/lintdiff-range-merge/tests/range_merge_tests.rs @@ -11,8 +11,8 @@ //! 8. Property-based tests with proptest (10 tests) use lintdiff_range_merge::{ - compare_by_end, compare_by_start, expand_to_include, gap_between, is_adjacent, - merge_lines, merge_overlapping, overlaps_or_adjacent, range_contains, range_contains_range, + compare_by_end, compare_by_start, expand_to_include, gap_between, is_adjacent, merge_lines, + merge_overlapping, overlaps_or_adjacent, range_contains, range_contains_range, range_intersection, range_len, range_union, ranges_intersect, LineRange, }; use std::cmp::Ordering; @@ -624,9 +624,9 @@ proptest! { let mut sorted = lines; sorted.sort(); sorted.dedup(); - + let ranges = merge_lines(&sorted); - + // Check that ranges don't overlap for i in 0..ranges.len().saturating_sub(1) { prop_assert!(!ranges[i].overlaps_or_adjacent(&ranges[i + 1])); @@ -638,7 +638,7 @@ proptest! { ranges in prop::collection::vec(arb_range(), 0..50) ) { let merged = merge_overlapping(&ranges); - + // Check that merged ranges don't overlap for i in 0..merged.len().saturating_sub(1) { for j in (i + 1)..merged.len() { @@ -681,7 +681,7 @@ fn line_range_equality_works() { let a = LineRange::new(1, 10); let b = LineRange::new(1, 10); let c = LineRange::new(1, 11); - + assert_eq!(a, b); assert_ne!(a, c); } @@ -691,7 +691,7 @@ fn line_range_ordering_by_start_then_end() { let a = LineRange::new(1, 10); let b = LineRange::new(2, 5); let c = LineRange::new(2, 10); - + assert!(a < b); // Lower start comes first assert!(b < c); // Same start, lower end comes first } @@ -700,14 +700,14 @@ fn line_range_ordering_by_start_then_end() { fn merge_lines_preserves_all_input_lines() { let lines = vec![1, 2, 3, 5, 7, 8, 9, 12]; let ranges = merge_lines(&lines); - + let mut reconstructed = Vec::new(); for range in &ranges { for line in range.start..=range.end { reconstructed.push(line); } } - + assert_eq!(lines, reconstructed); } @@ -718,9 +718,9 @@ fn merge_overlapping_preserves_coverage() { LineRange::new(5, 15), LineRange::new(20, 30), ]; - + let merged = merge_overlapping(&ranges); - + // Every line in original ranges should be in merged ranges for range in &ranges { for line in range.start..=range.end { diff --git a/crates/lintdiff-render-annotations/src/lib.rs b/crates/lintdiff-render-annotations/src/lib.rs index 69a86e9..3030df0 100644 --- a/crates/lintdiff-render-annotations/src/lib.rs +++ b/crates/lintdiff-render-annotations/src/lib.rs @@ -297,10 +297,8 @@ pub fn render_finding_annotation(finding: &Finding) -> String { let message = escape_message(&finding.message); let title = escape_message(&finding.code); - format!( - "::{level} file={file},line={line},title={title}::{message}" - ) - } + format!("::{level} file={file},line={line},title={title}::{message}") + }, ) } @@ -412,7 +410,11 @@ mod tests { #[test] fn test_single_info_finding() { - let findings = vec![create_test_finding(Severity::Info, "I001", "test info message")]; + let findings = vec![create_test_finding( + Severity::Info, + "I001", + "test info message", + )]; let config = AnnotationsConfig::default(); let result = render_annotations(&findings, &config); @@ -423,7 +425,11 @@ mod tests { #[test] fn test_info_finding_included_when_enabled() { - let findings = vec![create_test_finding(Severity::Info, "I001", "test info message")]; + let findings = vec![create_test_finding( + Severity::Info, + "I001", + "test info message", + )]; let config = AnnotationsConfig { include_notes: true, ..Default::default() @@ -507,14 +513,8 @@ mod tests { assert_eq!(escape_message("hello:world"), "hello%3Aworld"); assert_eq!(escape_message("a,b,c"), "a%2Cb%2Cc"); assert_eq!(escape_message("100%"), "100%25"); - assert_eq!( - escape_message("line1\nline2"), - "line1%0Aline2" - ); - assert_eq!( - escape_message("line1\r\nline2"), - "line1%0D%0Aline2" - ); + assert_eq!(escape_message("line1\nline2"), "line1%0Aline2"); + assert_eq!(escape_message("line1\r\nline2"), "line1%0D%0Aline2"); } #[test] diff --git a/crates/lintdiff-render-annotations/tests/annotations_tests.rs b/crates/lintdiff-render-annotations/tests/annotations_tests.rs index b039fed..bdad1fa 100644 --- a/crates/lintdiff-render-annotations/tests/annotations_tests.rs +++ b/crates/lintdiff-render-annotations/tests/annotations_tests.rs @@ -3,7 +3,9 @@ //! These tests verify the GitHub Actions annotation rendering functionality //! including format compliance, severity filtering, and configuration options. -use lintdiff_render_annotations::{render_annotations, render_finding_annotation, AnnotationsConfig}; +use lintdiff_render_annotations::{ + render_annotations, render_finding_annotation, AnnotationsConfig, +}; use lintdiff_types::{Finding, Location, NormPath, Severity}; /// Helper to create a test finding with all fields. @@ -71,7 +73,13 @@ mod single_finding_rendering { #[test] fn renders_error_with_correct_level() { - let finding = create_finding(Severity::Error, "E001", "error message", "src/lib.rs", Some(10)); + let finding = create_finding( + Severity::Error, + "E001", + "error message", + "src/lib.rs", + Some(10), + ); let annotation = render_finding_annotation(&finding); assert!(annotation.starts_with("::error")); @@ -83,7 +91,13 @@ mod single_finding_rendering { #[test] fn renders_warning_with_correct_level() { - let finding = create_finding(Severity::Warn, "W001", "warning message", "src/main.rs", Some(42)); + let finding = create_finding( + Severity::Warn, + "W001", + "warning message", + "src/main.rs", + Some(42), + ); let annotation = render_finding_annotation(&finding); assert!(annotation.starts_with("::warning")); @@ -93,7 +107,13 @@ mod single_finding_rendering { #[test] fn renders_info_as_notice() { - let finding = create_finding(Severity::Info, "I001", "info message", "docs/README.md", Some(1)); + let finding = create_finding( + Severity::Info, + "I001", + "info message", + "docs/README.md", + Some(1), + ); let annotation = render_finding_annotation(&finding); assert!(annotation.starts_with("::notice")); @@ -198,9 +218,13 @@ mod severity_filtering { #[test] fn includes_notes_when_enabled() { - let findings = vec![ - create_finding(Severity::Info, "I001", "info", "src/lib.rs", Some(1)), - ]; + let findings = vec![create_finding( + Severity::Info, + "I001", + "info", + "src/lib.rs", + Some(1), + )]; let config = AnnotationsConfig { include_errors: true, include_warnings: true, @@ -238,7 +262,15 @@ mod max_annotations_limit { #[test] fn limits_output_to_max_annotations() { let findings: Vec = (0..100) - .map(|i| create_finding(Severity::Error, &format!("E{i:03}"), "error", "src/lib.rs", Some(i))) + .map(|i| { + create_finding( + Severity::Error, + &format!("E{i:03}"), + "error", + "src/lib.rs", + Some(i), + ) + }) .collect(); let config = AnnotationsConfig { @@ -253,7 +285,15 @@ mod max_annotations_limit { #[test] fn takes_first_n_findings() { let findings: Vec = (0..5) - .map(|i| create_finding(Severity::Error, &format!("E{i}"), "error", "src/lib.rs", Some(i))) + .map(|i| { + create_finding( + Severity::Error, + &format!("E{i}"), + "error", + "src/lib.rs", + Some(i), + ) + }) .collect(); let config = AnnotationsConfig { @@ -271,7 +311,13 @@ mod max_annotations_limit { #[test] fn zero_max_annotations_produces_empty_output() { - let findings = vec![create_finding(Severity::Error, "E001", "error", "src/lib.rs", Some(1))]; + let findings = vec![create_finding( + Severity::Error, + "E001", + "error", + "src/lib.rs", + Some(1), + )]; let config = AnnotationsConfig { max_annotations: 0, ..Default::default() @@ -287,7 +333,13 @@ mod github_annotation_format { #[test] fn follows_github_workflow_command_format() { - let finding = create_finding(Severity::Error, "clippy::unwrap_used", "used unwrap()", "src/lib.rs", Some(42)); + let finding = create_finding( + Severity::Error, + "clippy::unwrap_used", + "used unwrap()", + "src/lib.rs", + Some(42), + ); let annotation = render_finding_annotation(&finding); // Format: ::{level} file={file},line={line},title={title}::{message} @@ -301,7 +353,13 @@ mod github_annotation_format { #[test] fn escapes_colons_in_code() { - let finding = create_finding(Severity::Error, "clippy::unwrap_used", "message", "src/lib.rs", Some(1)); + let finding = create_finding( + Severity::Error, + "clippy::unwrap_used", + "message", + "src/lib.rs", + Some(1), + ); let annotation = render_finding_annotation(&finding); // The title should have colons escaped @@ -310,7 +368,13 @@ mod github_annotation_format { #[test] fn escapes_colons_in_message() { - let finding = create_finding(Severity::Error, "E001", "error: something went wrong", "src/lib.rs", Some(1)); + let finding = create_finding( + Severity::Error, + "E001", + "error: something went wrong", + "src/lib.rs", + Some(1), + ); let annotation = render_finding_annotation(&finding); assert!(annotation.contains("error%3A something went wrong")); @@ -326,7 +390,13 @@ mod github_annotation_format { #[test] fn escapes_newlines_in_message() { - let finding = create_finding(Severity::Error, "E001", "line1\nline2", "src/lib.rs", Some(1)); + let finding = create_finding( + Severity::Error, + "E001", + "line1\nline2", + "src/lib.rs", + Some(1), + ); let annotation = render_finding_annotation(&finding); assert!(annotation.contains("line1%0Aline2")); @@ -334,7 +404,13 @@ mod github_annotation_format { #[test] fn escapes_carriage_returns_in_message() { - let finding = create_finding(Severity::Error, "E001", "line1\r\nline2", "src/lib.rs", Some(1)); + let finding = create_finding( + Severity::Error, + "E001", + "line1\r\nline2", + "src/lib.rs", + Some(1), + ); let annotation = render_finding_annotation(&finding); assert!(annotation.contains("line1%0D%0Aline2")); @@ -342,7 +418,13 @@ mod github_annotation_format { #[test] fn escapes_percent_in_message() { - let finding = create_finding(Severity::Error, "E001", "100% complete", "src/lib.rs", Some(1)); + let finding = create_finding( + Severity::Error, + "E001", + "100% complete", + "src/lib.rs", + Some(1), + ); let annotation = render_finding_annotation(&finding); assert!(annotation.contains("100%25 complete")); diff --git a/crates/lintdiff-render-markdown/src/lib.rs b/crates/lintdiff-render-markdown/src/lib.rs index 92c3367..457aab4 100644 --- a/crates/lintdiff-render-markdown/src/lib.rs +++ b/crates/lintdiff-render-markdown/src/lib.rs @@ -331,10 +331,7 @@ fn format_location(finding: &Finding) -> String { /// Truncate a message and escape markdown table characters. fn truncate_and_escape(s: &str, max_length: usize) -> String { - let escaped = s - .replace('|', "\\|") - .replace('\r', "") - .replace('\n', " "); + let escaped = s.replace('|', "\\|").replace('\r', "").replace('\n', " "); if escaped.len() > max_length { format!("{}...", &escaped[..max_length.saturating_sub(3)]) @@ -348,7 +345,13 @@ mod tests { use super::*; use lintdiff_types::{Location, NormPath}; - fn test_finding(severity: Severity, path: &str, line: u32, code: &str, message: &str) -> Finding { + fn test_finding( + severity: Severity, + path: &str, + line: u32, + code: &str, + message: &str, + ) -> Finding { Finding { severity, code: code.to_string(), diff --git a/crates/lintdiff-render-markdown/tests/markdown_tests.rs b/crates/lintdiff-render-markdown/tests/markdown_tests.rs index b813b4f..ac8da54 100644 --- a/crates/lintdiff-render-markdown/tests/markdown_tests.rs +++ b/crates/lintdiff-render-markdown/tests/markdown_tests.rs @@ -1,6 +1,8 @@ //! Comprehensive tests for markdown rendering functionality. -use lintdiff_render_markdown::{render_finding_markdown, render_markdown, render_summary, MarkdownConfig}; +use lintdiff_render_markdown::{ + render_finding_markdown, render_markdown, render_summary, MarkdownConfig, +}; use lintdiff_stats::Stats; use lintdiff_types::{Finding, Location, NormPath, Severity}; @@ -153,7 +155,11 @@ fn finding_with_column_in_location() { #[test] fn finding_without_location_shows_dash() { - let findings = vec![create_finding_no_location(Severity::Error, "E001", "No location")]; + let findings = vec![create_finding_no_location( + Severity::Error, + "E001", + "No location", + )]; let md = render_markdown(&findings, &MarkdownConfig::default()); assert!(md.contains("`-`")); @@ -461,9 +467,15 @@ fn summary_codes_sorted_by_count() { let summary = render_summary(&stats, &MarkdownConfig::default()); // HIGH_COUNT should appear before MID_COUNT and LOW_COUNT - let high_pos = summary.find("HIGH_COUNT").expect("HIGH_COUNT should be present"); - let mid_pos = summary.find("MID_COUNT").expect("MID_COUNT should be present"); - let low_pos = summary.find("LOW_COUNT").expect("LOW_COUNT should be present"); + let high_pos = summary + .find("HIGH_COUNT") + .expect("HIGH_COUNT should be present"); + let mid_pos = summary + .find("MID_COUNT") + .expect("MID_COUNT should be present"); + let low_pos = summary + .find("LOW_COUNT") + .expect("LOW_COUNT should be present"); assert!(high_pos < mid_pos); assert!(mid_pos < low_pos); @@ -572,7 +584,13 @@ fn empty_message_renders() { #[test] fn empty_code_renders() { - let findings = vec![create_finding(Severity::Warn, "src/lib.rs", 1, "", "Message")]; + let findings = vec![create_finding( + Severity::Warn, + "src/lib.rs", + 1, + "", + "Message", + )]; let md = render_markdown(&findings, &MarkdownConfig::default()); // Should still render the row diff --git a/crates/lintdiff-render-utils/src/lib.rs b/crates/lintdiff-render-utils/src/lib.rs index 8c0f893..ae61189 100644 --- a/crates/lintdiff-render-utils/src/lib.rs +++ b/crates/lintdiff-render-utils/src/lib.rs @@ -208,7 +208,13 @@ pub fn table(headers: &[&str], rows: &[Vec<&str>]) -> String { let header_row: String = headers .iter() .enumerate() - .map(|(i, h)| format!(" {:width$} ", h, width = widths.get(i).copied().unwrap_or(0))) + .map(|(i, h)| { + format!( + " {:width$} ", + h, + width = widths.get(i).copied().unwrap_or(0) + ) + }) .collect::>() .join("|"); @@ -225,7 +231,11 @@ pub fn table(headers: &[&str], rows: &[Vec<&str>]) -> String { row.iter() .enumerate() .map(|(i, cell)| { - format!(" {:width$} ", cell, width = widths.get(i).copied().unwrap_or(0)) + format!( + " {:width$} ", + cell, + width = widths.get(i).copied().unwrap_or(0) + ) }) .collect::>() .join("|") @@ -395,10 +405,7 @@ mod tests { #[test] fn test_indent_string_multi_line() { let config = IndentConfig::default(); - assert_eq!( - config.indent_string("hello\nworld", 1), - " hello\n world" - ); + assert_eq!(config.indent_string("hello\nworld", 1), " hello\n world"); } #[test] diff --git a/crates/lintdiff-render-utils/tests/render_utils_tests.rs b/crates/lintdiff-render-utils/tests/render_utils_tests.rs index f459eba..1892fd7 100644 --- a/crates/lintdiff-render-utils/tests/render_utils_tests.rs +++ b/crates/lintdiff-render-utils/tests/render_utils_tests.rs @@ -230,7 +230,7 @@ fn test_table_basic() { let headers = vec!["Name", "Age"]; let rows = vec![vec!["Alice", "30"]]; let result = table(&headers, &rows); - + assert!(result.contains("Name")); assert!(result.contains("Age")); assert!(result.contains("Alice")); @@ -242,7 +242,7 @@ fn test_table_multiple_rows() { let headers = vec!["ID", "Value"]; let rows = vec![vec!["1", "a"], vec!["2", "b"], vec!["3", "c"]]; let result = table(&headers, &rows); - + assert!(result.contains("1")); assert!(result.contains("2")); assert!(result.contains("3")); @@ -253,7 +253,7 @@ fn test_table_empty_rows() { let headers = vec!["Col1", "Col2"]; let rows: Vec> = vec![]; let result = table(&headers, &rows); - + // Should still have header and separator assert!(result.contains("Col1")); assert!(result.contains('|')); @@ -264,7 +264,7 @@ fn test_table_column_width_alignment() { let headers = vec!["Short", "Very Long Header"]; let rows = vec![vec!["x", "y"]]; let result = table(&headers, &rows); - + // Check that separator line is properly formed let lines: Vec<&str> = result.lines().collect(); assert!(lines.len() >= 2); @@ -275,7 +275,7 @@ fn test_table_empty_headers() { let headers: Vec<&str> = vec![]; let rows = vec![vec!["a", "b"]]; let result = table(&headers, &rows); - + assert!(result.is_empty()); } @@ -393,7 +393,12 @@ fn test_text_builder_multiple_lines() { #[test] fn test_text_builder_with_indentation() { let mut builder = TextBuilder::new().with_indent(IndentConfig::new(2)); - builder.line("root").indent().line("child").dedent().line("back"); + builder + .line("root") + .indent() + .line("child") + .dedent() + .line("back"); assert_eq!(builder.build(), "root\n child\nback"); } @@ -420,7 +425,7 @@ fn test_indent_config_partial_eq() { let config1 = IndentConfig::new(4); let config2 = IndentConfig::new(4); let config3 = IndentConfig::new(2); - + assert_eq!(config1, config2); assert_ne!(config1, config3); } @@ -437,7 +442,7 @@ fn test_wrap_config_partial_eq() { let config1 = WrapConfig::new(40); let config2 = WrapConfig::new(40); let config3 = WrapConfig::new(80); - + assert_eq!(config1, config2); assert_ne!(config1, config3); } @@ -521,7 +526,15 @@ fn test_indent_config_tab_char() { #[test] fn test_text_builder_nested_indent() { let mut builder = TextBuilder::new().with_indent(IndentConfig::new(2)); - builder.line("0").indent().line("1").indent().line("2").dedent().dedent().line("0"); + builder + .line("0") + .indent() + .line("1") + .indent() + .line("2") + .dedent() + .dedent() + .line("0"); assert_eq!(builder.build(), "0\n 1\n 2\n0"); } @@ -612,7 +625,7 @@ fn test_text_builder_chaining() { #[test] fn test_bullet_list_different_bullets() { let items = vec!["item"]; - + assert_eq!(bullet_list(&items, "-"), "- item"); assert_eq!(bullet_list(&items, "*"), "* item"); assert_eq!(bullet_list(&items, "+"), "+ item"); diff --git a/crates/lintdiff-report-builder/src/lib.rs b/crates/lintdiff-report-builder/src/lib.rs index f0b1a9a..2b1d2ae 100644 --- a/crates/lintdiff-report-builder/src/lib.rs +++ b/crates/lintdiff-report-builder/src/lib.rs @@ -595,11 +595,7 @@ impl ReportBuilder { return Err(ReportBuilderError::MissingToolName); } - if self.tool_version.is_none() - || self.tool_version - .as_ref() - .is_some_and(String::is_empty) - { + if self.tool_version.is_none() || self.tool_version.as_ref().is_some_and(String::is_empty) { return Err(ReportBuilderError::MissingToolVersion); } @@ -635,18 +631,15 @@ impl ReportBuilder { // SAFETY: validate() ensures these are Some and non-empty #[allow(clippy::unwrap_used)] - let tool = ToolInfo::new( - self.tool_name.unwrap(), - self.tool_version.unwrap(), - ); + let tool = ToolInfo::new(self.tool_name.unwrap(), self.tool_version.unwrap()); let mut files: Vec = self.file_results.into_values().collect(); // Sort files by path for deterministic output files.sort_by(|a, b| a.path.cmp(&b.path)); - let summary = self.custom_summary.unwrap_or_else(|| { - ReportSummary::from_file_results(&files) - }); + let summary = self + .custom_summary + .unwrap_or_else(|| ReportSummary::from_file_results(&files)); // SAFETY: validate() ensures timestamp is Some and non-empty #[allow(clippy::unwrap_used)] @@ -761,8 +754,7 @@ mod tests { #[test] fn test_finding_with_location() { - let finding = Finding::warning("test") - .with_location("src/main.rs", 10, 5); + let finding = Finding::warning("test").with_location("src/main.rs", 10, 5); assert_eq!(finding.path, Some("src/main.rs".to_string())); assert_eq!(finding.line, Some(10)); @@ -949,9 +941,8 @@ mod tests { #[test] fn test_report_builder_add_finding() { - let builder = ReportBuilder::new() - .add_finding("src/lib.rs", Finding::error("test error")); - + let builder = ReportBuilder::new().add_finding("src/lib.rs", Finding::error("test error")); + assert_eq!(builder.file_results.len(), 1); let result = builder.file_results.get("src/lib.rs").unwrap(); assert_eq!(result.added.len(), 1); @@ -959,9 +950,9 @@ mod tests { #[test] fn test_report_builder_add_removed_finding() { - let builder = ReportBuilder::new() - .add_removed_finding("src/lib.rs", Finding::warning("fixed")); - + let builder = + ReportBuilder::new().add_removed_finding("src/lib.rs", Finding::warning("fixed")); + let result = builder.file_results.get("src/lib.rs").unwrap(); assert_eq!(result.removed.len(), 1); assert!(result.added.is_empty()); @@ -969,9 +960,9 @@ mod tests { #[test] fn test_report_builder_add_unchanged_finding() { - let builder = ReportBuilder::new() - .add_unchanged_finding("src/lib.rs", Finding::hint("unchanged")); - + let builder = + ReportBuilder::new().add_unchanged_finding("src/lib.rs", Finding::hint("unchanged")); + let result = builder.file_results.get("src/lib.rs").unwrap(); assert_eq!(result.unchanged.len(), 1); } @@ -981,7 +972,7 @@ mod tests { let builder = ReportBuilder::new() .with_tool_info("", "1.0.0") .with_timestamp("2024-01-15T10:30:00Z"); - + let err = builder.validate().unwrap_err(); assert!(err.is_missing_tool_name()); } @@ -991,16 +982,15 @@ mod tests { let builder = ReportBuilder::new() .with_tool_info("lintdiff", "") .with_timestamp("2024-01-15T10:30:00Z"); - + let err = builder.validate().unwrap_err(); assert!(err.is_missing_tool_version()); } #[test] fn test_report_builder_validate_missing_timestamp() { - let builder = ReportBuilder::new() - .with_tool_info("lintdiff", "1.0.0"); - + let builder = ReportBuilder::new().with_tool_info("lintdiff", "1.0.0"); + let err = builder.validate().unwrap_err(); assert!(err.is_missing_timestamp()); } @@ -1010,7 +1000,7 @@ mod tests { let builder = ReportBuilder::new() .with_tool_info("lintdiff", "1.0.0") .with_timestamp("invalid"); - + let err = builder.validate().unwrap_err(); assert!(err.is_invalid_timestamp()); } @@ -1020,7 +1010,7 @@ mod tests { let builder = ReportBuilder::new() .with_tool_info("lintdiff", "1.0.0") .with_timestamp("2024-01-15T10:30:00Z"); - + assert!(builder.validate().is_ok()); } diff --git a/crates/lintdiff-report-builder/tests/report_builder_tests.rs b/crates/lintdiff-report-builder/tests/report_builder_tests.rs index 0b846c1..0e12262 100644 --- a/crates/lintdiff-report-builder/tests/report_builder_tests.rs +++ b/crates/lintdiff-report-builder/tests/report_builder_tests.rs @@ -3,8 +3,8 @@ //! These tests follow the Given-When-Then pattern to describe behavior. use lintdiff_report_builder::{ - FileResult, Finding, GitInfo, ReportBuilder, ReportBuilderError, ReportSummary, - Severity, ToolInfo, quick_report, + quick_report, FileResult, Finding, GitInfo, ReportBuilder, ReportBuilderError, ReportSummary, + Severity, ToolInfo, }; use proptest::prelude::*; @@ -630,8 +630,7 @@ mod validation { #[test] fn given_no_tool_name_when_validate_then_missing_tool_name_error() { // Given - let builder = ReportBuilder::new() - .with_timestamp("2024-01-15T10:30:00Z"); + let builder = ReportBuilder::new().with_timestamp("2024-01-15T10:30:00Z"); // When let err = builder.validate().unwrap_err(); @@ -674,8 +673,7 @@ mod validation { #[test] fn given_no_timestamp_when_validate_then_missing_timestamp_error() { // Given - let builder = ReportBuilder::new() - .with_tool_info("lintdiff", "1.0.0"); + let builder = ReportBuilder::new().with_tool_info("lintdiff", "1.0.0"); // When let err = builder.validate().unwrap_err(); @@ -1182,9 +1180,7 @@ mod serde_tests { #[test] fn test_finding_serde() { - let finding = Finding::error("test error") - .with_code("E001") - .with_line(42); + let finding = Finding::error("test error").with_code("E001").with_line(42); let json = serde_json::to_string(&finding).unwrap(); assert!(json.contains("test error")); diff --git a/crates/lintdiff-report-schema/src/lib.rs b/crates/lintdiff-report-schema/src/lib.rs index b46da47..fd886dd 100644 --- a/crates/lintdiff-report-schema/src/lib.rs +++ b/crates/lintdiff-report-schema/src/lib.rs @@ -15,7 +15,11 @@ impl SchemaVersion { /// Create a new schema version. #[must_use] pub const fn new(major: u32, minor: u32, patch: u32) -> Self { - Self { major, minor, patch } + Self { + major, + minor, + patch, + } } /// Get the current (latest) schema version. @@ -61,7 +65,11 @@ impl SchemaVersion { let patch = parts[2] .parse() .map_err(|_| SchemaVersionParseError::InvalidPatch(parts[2].to_string()))?; - Ok(Self { major, minor, patch }) + Ok(Self { + major, + minor, + patch, + }) } /// Check if this version is compatible with another. diff --git a/crates/lintdiff-report-schema/tests/report_schema_tests.rs b/crates/lintdiff-report-schema/tests/report_schema_tests.rs index e016341..124b5a7 100644 --- a/crates/lintdiff-report-schema/tests/report_schema_tests.rs +++ b/crates/lintdiff-report-schema/tests/report_schema_tests.rs @@ -71,31 +71,46 @@ mod schema_version_creation_and_parsing { #[test] fn test_parse_invalid_format_missing_parts() { let result = SchemaVersion::parse("1.2"); - assert!(matches!(result, Err(SchemaVersionParseError::InvalidFormat(_)))); + assert!(matches!( + result, + Err(SchemaVersionParseError::InvalidFormat(_)) + )); } #[test] fn test_parse_invalid_format_extra_parts() { let result = SchemaVersion::parse("1.2.3.4"); - assert!(matches!(result, Err(SchemaVersionParseError::InvalidFormat(_)))); + assert!(matches!( + result, + Err(SchemaVersionParseError::InvalidFormat(_)) + )); } #[test] fn test_parse_invalid_major_not_a_number() { let result = SchemaVersion::parse("a.2.3"); - assert!(matches!(result, Err(SchemaVersionParseError::InvalidMajor(_)))); + assert!(matches!( + result, + Err(SchemaVersionParseError::InvalidMajor(_)) + )); } #[test] fn test_parse_invalid_minor_not_a_number() { let result = SchemaVersion::parse("1.b.3"); - assert!(matches!(result, Err(SchemaVersionParseError::InvalidMinor(_)))); + assert!(matches!( + result, + Err(SchemaVersionParseError::InvalidMinor(_)) + )); } #[test] fn test_parse_invalid_patch_not_a_number() { let result = SchemaVersion::parse("1.2.c"); - assert!(matches!(result, Err(SchemaVersionParseError::InvalidPatch(_)))); + assert!(matches!( + result, + Err(SchemaVersionParseError::InvalidPatch(_)) + )); } } @@ -132,10 +147,7 @@ mod schema_version_compatibility { fn test_compatibility_is_reflexive() { let v1 = SchemaVersion::new(3, 7, 2); let v2 = SchemaVersion::new(3, 1, 9); - assert_eq!( - v1.is_compatible_with(&v2), - v2.is_compatible_with(&v1) - ); + assert_eq!(v1.is_compatible_with(&v2), v2.is_compatible_with(&v1)); } #[test] @@ -143,7 +155,7 @@ mod schema_version_compatibility { let v0_1_0 = SchemaVersion::new(0, 1, 0); let v0_9_9 = SchemaVersion::new(0, 9, 9); let v1_0_0 = SchemaVersion::new(1, 0, 0); - + assert!(v0_1_0.is_compatible_with(&v0_9_9)); assert!(!v0_1_0.is_compatible_with(&v1_0_0)); } @@ -178,7 +190,8 @@ mod validation_error_variants { #[test] fn test_invalid_value_error_message() { - let error = ValidationError::InvalidValue("count".to_string(), "must be positive".to_string()); + let error = + ValidationError::InvalidValue("count".to_string(), "must be positive".to_string()); let msg = error.to_string(); assert!(msg.contains("count")); assert!(msg.contains("must be positive")); @@ -253,11 +266,12 @@ mod validation_result_methods { #[test] fn test_merge_combines_errors_from_invalid_result() { - let mut result1 = ValidationResult::with_error(ValidationError::MissingField("a".to_string())); + let mut result1 = + ValidationResult::with_error(ValidationError::MissingField("a".to_string())); let result2 = ValidationResult::with_error(ValidationError::MissingField("b".to_string())); - + result1.merge(result2); - + assert!(result1.is_err()); assert_eq!(result1.errors().len(), 2); } @@ -266,20 +280,21 @@ mod validation_result_methods { fn test_merge_with_valid_result_does_not_change_validity() { let mut result1 = ValidationResult::valid(); let result2 = ValidationResult::valid(); - + result1.merge(result2); - + assert!(result1.is_ok()); assert!(result1.errors().is_empty()); } #[test] fn test_merge_valid_into_invalid_preserves_errors() { - let mut result1 = ValidationResult::with_error(ValidationError::Custom("error".to_string())); + let mut result1 = + ValidationResult::with_error(ValidationError::Custom("error".to_string())); let result2 = ValidationResult::valid(); - + result1.merge(result2); - + assert!(result1.is_err()); assert_eq!(result1.errors().len(), 1); } @@ -291,7 +306,7 @@ mod validation_result_methods { ValidationError::MissingField("b".to_string()), ]; let result = ValidationResult::invalid(errors); - + let error_slice = result.errors(); assert_eq!(error_slice.len(), 2); } @@ -341,7 +356,10 @@ mod report_validator_basic_validation { let json = serde_json::json!("not an object"); let result = validator.validate(&json); assert!(result.is_err()); - assert!(result.errors().iter().any(|e| matches!(e, ValidationError::InvalidType(..)))); + assert!(result + .errors() + .iter() + .any(|e| matches!(e, ValidationError::InvalidType(..)))); } #[test] @@ -370,7 +388,10 @@ mod report_validator_basic_validation { }); let result = validator.validate(&json); assert!(result.is_err()); - assert!(result.errors().iter().any(|e| matches!(e, ValidationError::VersionMismatch(..)))); + assert!(result + .errors() + .iter() + .any(|e| matches!(e, ValidationError::VersionMismatch(..)))); } #[test] @@ -383,7 +404,10 @@ mod report_validator_basic_validation { }); let result = validator.validate(&json); assert!(result.is_err()); - assert!(result.errors().iter().any(|e| matches!(e, ValidationError::InvalidValue(..)))); + assert!(result + .errors() + .iter() + .any(|e| matches!(e, ValidationError::InvalidValue(..)))); } #[test] @@ -396,7 +420,10 @@ mod report_validator_basic_validation { }); let result = validator.validate(&json); assert!(result.is_err()); - assert!(result.errors().iter().any(|e| matches!(e, ValidationError::InvalidType(..)))); + assert!(result + .errors() + .iter() + .any(|e| matches!(e, ValidationError::InvalidType(..)))); } #[test] @@ -424,7 +451,10 @@ mod report_validator_required_fields { }); let result = validator.validate(&json); assert!(result.is_err()); - assert!(result.errors().iter().any(|e| matches!(e, ValidationError::MissingField(f) if f == "schema_version"))); + assert!(result + .errors() + .iter() + .any(|e| matches!(e, ValidationError::MissingField(f) if f == "schema_version"))); } #[test] @@ -436,7 +466,10 @@ mod report_validator_required_fields { }); let result = validator.validate(&json); assert!(result.is_err()); - assert!(result.errors().iter().any(|e| matches!(e, ValidationError::MissingField(f) if f == "verdict"))); + assert!(result + .errors() + .iter() + .any(|e| matches!(e, ValidationError::MissingField(f) if f == "verdict"))); } #[test] @@ -448,7 +481,10 @@ mod report_validator_required_fields { }); let result = validator.validate(&json); assert!(result.is_err()); - assert!(result.errors().iter().any(|e| matches!(e, ValidationError::MissingField(f) if f == "findings"))); + assert!(result + .errors() + .iter() + .any(|e| matches!(e, ValidationError::MissingField(f) if f == "findings"))); } #[test] @@ -473,7 +509,10 @@ mod report_validator_required_fields { }); let result = validator.validate(&json); assert!(result.is_err()); - assert!(result.errors().iter().any(|e| matches!(e, ValidationError::MissingField(f) if f == "custom_field"))); + assert!(result + .errors() + .iter() + .any(|e| matches!(e, ValidationError::MissingField(f) if f == "custom_field"))); } #[test] @@ -489,7 +528,10 @@ mod report_validator_required_fields { }); let result = validator.validate(&json); assert!(result.is_err()); - assert!(result.errors().iter().any(|e| matches!(e, ValidationError::MissingField(f) if f == "field2"))); + assert!(result + .errors() + .iter() + .any(|e| matches!(e, ValidationError::MissingField(f) if f == "field2"))); } } @@ -574,7 +616,7 @@ mod additional_tests { let v1 = SchemaVersion::new(1, 0, 0); let v2 = SchemaVersion::new(1, 1, 0); let v3 = SchemaVersion::new(2, 0, 0); - + assert!(v1 < v2); assert!(v2 < v3); assert!(v1 < v3); @@ -585,7 +627,7 @@ mod additional_tests { let v1 = SchemaVersion::new(1, 2, 3); let v2 = SchemaVersion::new(1, 2, 3); let v3 = SchemaVersion::new(1, 2, 4); - + assert_eq!(v1, v2); assert_ne!(v1, v3); } @@ -593,12 +635,12 @@ mod additional_tests { #[test] fn test_version_hash() { use std::collections::HashSet; - + let mut set = HashSet::new(); let v1 = SchemaVersion::new(1, 0, 0); let v2 = SchemaVersion::new(1, 0, 0); let v3 = SchemaVersion::new(2, 0, 0); - + set.insert(v1); assert!(set.contains(&v2)); assert!(!set.contains(&v3)); diff --git a/crates/lintdiff-run-info/src/lib.rs b/crates/lintdiff-run-info/src/lib.rs index 605afe2..d5596d6 100644 --- a/crates/lintdiff-run-info/src/lib.rs +++ b/crates/lintdiff-run-info/src/lib.rs @@ -574,8 +574,7 @@ pub fn is_expired_at(info: &RunInfo, max_age: &Duration, reference_time: OffsetD /// /// Returns [`RunInfoError::InvalidDuration`] if the string cannot be parsed. pub fn parse_timestamp(s: &str) -> Result { - OffsetDateTime::parse(s, &Rfc3339) - .map_err(|e| RunInfoError::invalid_duration(e.to_string())) + OffsetDateTime::parse(s, &Rfc3339).map_err(|e| RunInfoError::invalid_duration(e.to_string())) } /// Create a duration from seconds. @@ -741,20 +740,17 @@ mod tests { #[test] fn test_format_duration_negative() { - assert_eq!( - format_duration(&Duration::milliseconds(-125)), - "-125ms" - ); - assert_eq!( - format_duration(&Duration::seconds(-90)), - "-1m30s" - ); + assert_eq!(format_duration(&Duration::milliseconds(-125)), "-125ms"); + assert_eq!(format_duration(&Duration::seconds(-90)), "-1m30s"); } #[test] fn test_format_duration_short() { assert_eq!(format_duration_short(&Duration::seconds(0)), "0.000s"); - assert_eq!(format_duration_short(&Duration::milliseconds(125)), "0.125s"); + assert_eq!( + format_duration_short(&Duration::milliseconds(125)), + "0.125s" + ); assert_eq!(format_duration_short(&Duration::seconds(90)), "90.000s"); assert_eq!(format_duration_short(&Duration::seconds(4530)), "4530.000s"); } diff --git a/crates/lintdiff-run-info/tests/run_info_tests.rs b/crates/lintdiff-run-info/tests/run_info_tests.rs index cf3f278..10a7a1c 100644 --- a/crates/lintdiff-run-info/tests/run_info_tests.rs +++ b/crates/lintdiff-run-info/tests/run_info_tests.rs @@ -508,9 +508,18 @@ fn format_duration_short_formats_zero_duration() { #[test] fn format_duration_short_formats_milliseconds_as_decimal_seconds() { - assert_eq!(format_duration_short(&Duration::milliseconds(125)), "0.125s"); - assert_eq!(format_duration_short(&Duration::milliseconds(500)), "0.500s"); - assert_eq!(format_duration_short(&Duration::milliseconds(999)), "0.999s"); + assert_eq!( + format_duration_short(&Duration::milliseconds(125)), + "0.125s" + ); + assert_eq!( + format_duration_short(&Duration::milliseconds(500)), + "0.500s" + ); + assert_eq!( + format_duration_short(&Duration::milliseconds(999)), + "0.999s" + ); } #[test] @@ -523,7 +532,10 @@ fn format_duration_short_formats_seconds_with_decimal() { #[test] fn format_duration_short_formats_large_durations_in_seconds() { assert_eq!(format_duration_short(&Duration::seconds(3600)), "3600.000s"); - assert_eq!(format_duration_short(&Duration::seconds(86400)), "86400.000s"); + assert_eq!( + format_duration_short(&Duration::seconds(86400)), + "86400.000s" + ); } #[test] @@ -719,10 +731,7 @@ fn duration_from_secs_creates_duration_from_seconds() { #[test] fn duration_from_millis_creates_duration_from_milliseconds() { - assert_eq!( - duration_from_millis(1000), - Duration::milliseconds(1000) - ); + assert_eq!(duration_from_millis(1000), Duration::milliseconds(1000)); assert_eq!(duration_from_millis(500), Duration::milliseconds(500)); } diff --git a/crates/lintdiff-schema-diff/src/lib.rs b/crates/lintdiff-schema-diff/src/lib.rs index 8357c75..8f9897a 100644 --- a/crates/lintdiff-schema-diff/src/lib.rs +++ b/crates/lintdiff-schema-diff/src/lib.rs @@ -198,12 +198,7 @@ impl JsonDiff { impl fmt::Display for JsonDiff { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}: {}", - self.path_string(), - self.kind - ) + write!(f, "{}: {}", self.path_string(), self.kind) } } @@ -228,14 +223,10 @@ fn diff_json_at_path(a: &Value, b: &Value, path: &JsonPath) -> Vec { } // Both objects - (Value::Object(obj_a), Value::Object(obj_b)) => { - diff_objects(obj_a, obj_b, path) - } + (Value::Object(obj_a), Value::Object(obj_b)) => diff_objects(obj_a, obj_b, path), // Both arrays - (Value::Array(arr_a), Value::Array(arr_b)) => { - diff_arrays(arr_a, arr_b, path) - } + (Value::Array(arr_a), Value::Array(arr_b)) => diff_arrays(arr_a, arr_b, path), // Mixed types (object/array vs primitive) _ => vec![JsonDiff::changed(path.clone(), a.clone(), Value::Null)], @@ -542,7 +533,10 @@ pub fn json_eq_ignore_order(a: &Value, b: &Value) -> bool { if arr_a.len() != arr_b.len() { return false; } - arr_a.iter().zip(arr_b.iter()).all(|(a, b)| json_eq_ignore_order(a, b)) + arr_a + .iter() + .zip(arr_b.iter()) + .all(|(a, b)| json_eq_ignore_order(a, b)) } _ => a == b, } @@ -628,7 +622,11 @@ pub fn get_at_path(value: &Value, path: &[PathSegment]) -> Option { /// # Errors /// /// Returns an error if the path is invalid for the given structure. -pub fn set_at_path(value: &mut Value, path: &[PathSegment], new_value: Value) -> Result<(), String> { +pub fn set_at_path( + value: &mut Value, + path: &[PathSegment], + new_value: Value, +) -> Result<(), String> { if path.is_empty() { *value = new_value; return Ok(()); @@ -644,7 +642,9 @@ pub fn set_at_path(value: &mut Value, path: &[PathSegment], new_value: Value) -> obj.insert(k.clone(), new_value); return Ok(()); } - current = obj.get_mut(k).ok_or_else(|| format!("Key not found: {k}"))?; + current = obj + .get_mut(k) + .ok_or_else(|| format!("Key not found: {k}"))?; } (Value::Array(arr), PathSegment::Index(idx)) => { if is_last { @@ -654,7 +654,9 @@ pub fn set_at_path(value: &mut Value, path: &[PathSegment], new_value: Value) -> } return Err(format!("Index out of bounds: {idx}")); } - current = arr.get_mut(*idx).ok_or_else(|| format!("Index out of bounds: {idx}"))?; + current = arr + .get_mut(*idx) + .ok_or_else(|| format!("Index out of bounds: {idx}"))?; } _ => return Err(format!("Invalid path segment at position {i}")), } @@ -797,9 +799,15 @@ mod tests { assert!(paths.contains(&vec![])); assert!(paths.contains(&vec![PathSegment::key("a".to_string())])); - assert!(paths.contains(&vec![PathSegment::key("a".to_string()), PathSegment::key("b".to_string())])); + assert!(paths.contains(&vec![ + PathSegment::key("a".to_string()), + PathSegment::key("b".to_string()) + ])); assert!(paths.contains(&vec![PathSegment::key("c".to_string())])); - assert!(paths.contains(&vec![PathSegment::key("c".to_string()), PathSegment::index(0)])); + assert!(paths.contains(&vec![ + PathSegment::key("c".to_string()), + PathSegment::index(0) + ])); } #[test] @@ -809,7 +817,14 @@ mod tests { let result = get_at_path(&value, &[PathSegment::key("a".to_string())]); assert_eq!(result, Some(json!({"b": [1, 2, 3]}))); - let result = get_at_path(&value, &[PathSegment::key("a".to_string()), PathSegment::key("b".to_string()), PathSegment::index(1)]); + let result = get_at_path( + &value, + &[ + PathSegment::key("a".to_string()), + PathSegment::key("b".to_string()), + PathSegment::index(1), + ], + ); assert_eq!(result, Some(json!(2))); let result = get_at_path(&value, &[PathSegment::key("x".to_string())]); diff --git a/crates/lintdiff-schema-diff/tests/schema_diff_tests.rs b/crates/lintdiff-schema-diff/tests/schema_diff_tests.rs index 715ba9a..b10d6b8 100644 --- a/crates/lintdiff-schema-diff/tests/schema_diff_tests.rs +++ b/crates/lintdiff-schema-diff/tests/schema_diff_tests.rs @@ -113,7 +113,10 @@ mod diff_kind_tests { #[test] fn display_array_length_changed() { - assert_eq!(DiffKind::ArrayLengthChanged.to_string(), "array length changed"); + assert_eq!( + DiffKind::ArrayLengthChanged.to_string(), + "array length changed" + ); } #[test] @@ -859,9 +862,13 @@ mod set_at_path_tests { let mut value = json!({"a": {"b": 1}}); set_at_path( &mut value, - &[PathSegment::key("a".to_string()), PathSegment::key("b".to_string())], + &[ + PathSegment::key("a".to_string()), + PathSegment::key("b".to_string()), + ], json!(2), - ).unwrap(); + ) + .unwrap(); assert_eq!(value, json!({"a": {"b": 2}})); } diff --git a/crates/lintdiff-severity-map/src/lib.rs b/crates/lintdiff-severity-map/src/lib.rs index afcf2da..940c1b7 100644 --- a/crates/lintdiff-severity-map/src/lib.rs +++ b/crates/lintdiff-severity-map/src/lib.rs @@ -720,12 +720,30 @@ mod tests { #[test] fn canonical_severity_parse_error() { - assert_eq!(CanonicalSeverity::parse("error"), Ok(CanonicalSeverity::Error)); - assert_eq!(CanonicalSeverity::parse("ERROR"), Ok(CanonicalSeverity::Error)); - assert_eq!(CanonicalSeverity::parse("err"), Ok(CanonicalSeverity::Error)); - assert_eq!(CanonicalSeverity::parse("fatal"), Ok(CanonicalSeverity::Error)); - assert_eq!(CanonicalSeverity::parse("critical"), Ok(CanonicalSeverity::Error)); - assert_eq!(CanonicalSeverity::parse("fail"), Ok(CanonicalSeverity::Error)); + assert_eq!( + CanonicalSeverity::parse("error"), + Ok(CanonicalSeverity::Error) + ); + assert_eq!( + CanonicalSeverity::parse("ERROR"), + Ok(CanonicalSeverity::Error) + ); + assert_eq!( + CanonicalSeverity::parse("err"), + Ok(CanonicalSeverity::Error) + ); + assert_eq!( + CanonicalSeverity::parse("fatal"), + Ok(CanonicalSeverity::Error) + ); + assert_eq!( + CanonicalSeverity::parse("critical"), + Ok(CanonicalSeverity::Error) + ); + assert_eq!( + CanonicalSeverity::parse("fail"), + Ok(CanonicalSeverity::Error) + ); assert_eq!(CanonicalSeverity::parse("2"), Ok(CanonicalSeverity::Error)); } @@ -751,7 +769,10 @@ mod tests { #[test] fn canonical_severity_parse_info() { - assert_eq!(CanonicalSeverity::parse("info"), Ok(CanonicalSeverity::Info)); + assert_eq!( + CanonicalSeverity::parse("info"), + Ok(CanonicalSeverity::Info) + ); assert_eq!( CanonicalSeverity::parse("INFO"), Ok(CanonicalSeverity::Info) @@ -760,7 +781,10 @@ mod tests { CanonicalSeverity::parse("information"), Ok(CanonicalSeverity::Info) ); - assert_eq!(CanonicalSeverity::parse("note"), Ok(CanonicalSeverity::Info)); + assert_eq!( + CanonicalSeverity::parse("note"), + Ok(CanonicalSeverity::Info) + ); assert_eq!( CanonicalSeverity::parse("convention"), Ok(CanonicalSeverity::Info) @@ -773,14 +797,26 @@ mod tests { #[test] fn canonical_severity_parse_hint() { - assert_eq!(CanonicalSeverity::parse("hint"), Ok(CanonicalSeverity::Hint)); - assert_eq!(CanonicalSeverity::parse("HINT"), Ok(CanonicalSeverity::Hint)); + assert_eq!( + CanonicalSeverity::parse("hint"), + Ok(CanonicalSeverity::Hint) + ); + assert_eq!( + CanonicalSeverity::parse("HINT"), + Ok(CanonicalSeverity::Hint) + ); assert_eq!( CanonicalSeverity::parse("suggestion"), Ok(CanonicalSeverity::Hint) ); - assert_eq!(CanonicalSeverity::parse("help"), Ok(CanonicalSeverity::Hint)); - assert_eq!(CanonicalSeverity::parse("style"), Ok(CanonicalSeverity::Hint)); + assert_eq!( + CanonicalSeverity::parse("help"), + Ok(CanonicalSeverity::Hint) + ); + assert_eq!( + CanonicalSeverity::parse("style"), + Ok(CanonicalSeverity::Hint) + ); } #[test] @@ -962,10 +998,7 @@ mod tests { mapper1.merge(mapper2); - assert_eq!( - mapper1.map("linter", "error"), - CanonicalSeverity::Warning - ); + assert_eq!(mapper1.map("linter", "error"), CanonicalSeverity::Warning); } // ========================================================================= @@ -1070,10 +1103,13 @@ mod tests { #[test] fn builder_with_linter() { let mapper = SeverityMapBuilder::new() - .with_linter("custom", [ - ("error", CanonicalSeverity::Error), - ("warning", CanonicalSeverity::Warning), - ]) + .with_linter( + "custom", + [ + ("error", CanonicalSeverity::Error), + ("warning", CanonicalSeverity::Warning), + ], + ) .build(); assert_eq!(mapper.map("custom", "error"), CanonicalSeverity::Error); @@ -1193,7 +1229,10 @@ mod tests { fn very_long_severity_string() { let mapper = SeverityMapper::from_defaults(); let long_severity = "error".repeat(100); - assert_eq!(mapper.map("eslint", &long_severity), CanonicalSeverity::Unknown); + assert_eq!( + mapper.map("eslint", &long_severity), + CanonicalSeverity::Unknown + ); } // ========================================================================= @@ -1217,14 +1256,8 @@ mod tests { #[test] fn canonical_severity_debug() { - assert_eq!( - format!("{:?}", CanonicalSeverity::Error), - "Error" - ); - assert_eq!( - format!("{:?}", CanonicalSeverity::Warning), - "Warning" - ); + assert_eq!(format!("{:?}", CanonicalSeverity::Error), "Error"); + assert_eq!(format!("{:?}", CanonicalSeverity::Warning), "Warning"); } #[test] diff --git a/crates/lintdiff-severity-map/tests/severity_map_tests.rs b/crates/lintdiff-severity-map/tests/severity_map_tests.rs index fe82520..a5261de 100644 --- a/crates/lintdiff-severity-map/tests/severity_map_tests.rs +++ b/crates/lintdiff-severity-map/tests/severity_map_tests.rs @@ -9,8 +9,8 @@ //! - Edge cases and property-based tests use lintdiff_severity_map::{ - map_severity, is_error_level, is_warning_level, is_problem_level, - CanonicalSeverity, SeverityMapBuilder, SeverityMapper, SeverityParseError, + is_error_level, is_problem_level, is_warning_level, map_severity, CanonicalSeverity, + SeverityMapBuilder, SeverityMapper, SeverityParseError, }; // ============================================================================= @@ -65,9 +65,8 @@ mod canonical_severity_feature { #[test] fn parse_error_variants() { let error_cases = [ - "error", "ERROR", "Error", "err", "ERR", "Err", - "fatal", "FATAL", "Fatal", "critical", "CRITICAL", - "fail", "FAIL", "Fail", "2", + "error", "ERROR", "Error", "err", "ERR", "Err", "fatal", "FATAL", "Fatal", "critical", + "CRITICAL", "fail", "FAIL", "Fail", "2", ]; for case in error_cases { assert_eq!( @@ -81,9 +80,7 @@ mod canonical_severity_feature { #[test] fn parse_warning_variants() { - let warning_cases = [ - "warning", "WARNING", "Warning", "warn", "WARN", "Warn", "1", - ]; + let warning_cases = ["warning", "WARNING", "Warning", "warn", "WARN", "Warn", "1"]; for case in warning_cases { assert_eq!( CanonicalSeverity::parse(case), @@ -97,9 +94,18 @@ mod canonical_severity_feature { #[test] fn parse_info_variants() { let info_cases = [ - "info", "INFO", "Info", "information", "INFORMATION", - "note", "NOTE", "Note", "convention", "CONVENTION", - "refactor", "REFACTOR", + "info", + "INFO", + "Info", + "information", + "INFORMATION", + "note", + "NOTE", + "Note", + "convention", + "CONVENTION", + "refactor", + "REFACTOR", ]; for case in info_cases { assert_eq!( @@ -114,8 +120,17 @@ mod canonical_severity_feature { #[test] fn parse_hint_variants() { let hint_cases = [ - "hint", "HINT", "Hint", "suggestion", "SUGGESTION", - "help", "HELP", "Help", "style", "STYLE", "Style", + "hint", + "HINT", + "Hint", + "suggestion", + "SUGGESTION", + "help", + "HELP", + "Help", + "style", + "STYLE", + "Style", ]; for case in hint_cases { assert_eq!( @@ -295,7 +310,10 @@ mod severity_mapper_feature { let mut mapper = SeverityMapper::new(); mapper.add_mapping("test-linter", "test-severity", CanonicalSeverity::Error); - assert_eq!(mapper.map("test-linter", "test-severity"), CanonicalSeverity::Error); + assert_eq!( + mapper.map("test-linter", "test-severity"), + CanonicalSeverity::Error + ); assert_eq!(mapper.mapping_count(), 1); } @@ -346,13 +364,19 @@ mod severity_mapper_feature { #[test] fn map_returns_unknown_for_unknown_linter() { let mapper = SeverityMapper::from_defaults(); - assert_eq!(mapper.map("unknown-linter", "error"), CanonicalSeverity::Unknown); + assert_eq!( + mapper.map("unknown-linter", "error"), + CanonicalSeverity::Unknown + ); } #[test] fn map_returns_unknown_for_unknown_severity() { let mapper = SeverityMapper::from_defaults(); - assert_eq!(mapper.map("eslint", "unknown-severity"), CanonicalSeverity::Unknown); + assert_eq!( + mapper.map("eslint", "unknown-severity"), + CanonicalSeverity::Unknown + ); } #[test] @@ -486,7 +510,10 @@ mod severity_mapper_feature { let cloned = mapper.clone(); assert_eq!(mapper.map("eslint", "error"), cloned.map("eslint", "error")); - assert_eq!(mapper.map("rustc", "warning"), cloned.map("rustc", "warning")); + assert_eq!( + mapper.map("rustc", "warning"), + cloned.map("rustc", "warning") + ); } #[test] @@ -687,7 +714,10 @@ mod builtin_linter_mappings_feature { #[test] fn shellcheck_warning_maps_to_warning() { let mapper = create_mapper(); - assert_eq!(mapper.map("shellcheck", "warning"), CanonicalSeverity::Warning); + assert_eq!( + mapper.map("shellcheck", "warning"), + CanonicalSeverity::Warning + ); } #[test] @@ -756,11 +786,14 @@ mod severity_map_builder_feature { #[test] fn with_linter_adds_multiple_mappings() { let mapper = SeverityMapBuilder::new() - .with_linter("custom", [ - ("error", CanonicalSeverity::Error), - ("warning", CanonicalSeverity::Warning), - ("info", CanonicalSeverity::Info), - ]) + .with_linter( + "custom", + [ + ("error", CanonicalSeverity::Error), + ("warning", CanonicalSeverity::Warning), + ("info", CanonicalSeverity::Info), + ], + ) .build(); assert_eq!(mapper.map("custom", "error"), CanonicalSeverity::Error); @@ -854,8 +887,8 @@ mod severity_map_builder_feature { #[test] fn build_returns_mapper() { - let builder = SeverityMapBuilder::new() - .with_mapping("linter", "error", CanonicalSeverity::Error); + let builder = + SeverityMapBuilder::new().with_mapping("linter", "error", CanonicalSeverity::Error); let mapper = builder.build(); assert_eq!(mapper.map("linter", "error"), CanonicalSeverity::Error); @@ -889,7 +922,10 @@ mod convenience_functions_feature { #[test] fn map_severity_returns_unknown_for_unknown_linter() { - assert_eq!(map_severity("unknown-linter", "error"), CanonicalSeverity::Unknown); + assert_eq!( + map_severity("unknown-linter", "error"), + CanonicalSeverity::Unknown + ); } #[test] @@ -1037,14 +1073,20 @@ mod edge_cases_feature { fn very_long_severity_string() { let mapper = SeverityMapper::from_defaults(); let long_severity = "error".repeat(100); - assert_eq!(mapper.map("eslint", &long_severity), CanonicalSeverity::Unknown); + assert_eq!( + mapper.map("eslint", &long_severity), + CanonicalSeverity::Unknown + ); } #[test] fn very_long_linter_name() { let mapper = SeverityMapper::from_defaults(); let long_linter = "linter".repeat(100); - assert_eq!(mapper.map(&long_linter, "error"), CanonicalSeverity::Unknown); + assert_eq!( + mapper.map(&long_linter, "error"), + CanonicalSeverity::Unknown + ); } // ------------------------------------------------------------------------- @@ -1078,15 +1120,24 @@ mod edge_cases_feature { fn special_characters_in_severity() { let mapper = SeverityMapper::from_defaults(); assert_eq!(mapper.map("eslint", "error!"), CanonicalSeverity::Unknown); - assert_eq!(mapper.map("eslint", "error@host"), CanonicalSeverity::Unknown); + assert_eq!( + mapper.map("eslint", "error@host"), + CanonicalSeverity::Unknown + ); assert_eq!(mapper.map("eslint", "error\n"), CanonicalSeverity::Unknown); } #[test] fn special_characters_in_linter() { let mapper = SeverityMapper::from_defaults(); - assert_eq!(mapper.map("eslint-plugin", "error"), CanonicalSeverity::Unknown); - assert_eq!(mapper.map("eslint/plugin", "error"), CanonicalSeverity::Unknown); + assert_eq!( + mapper.map("eslint-plugin", "error"), + CanonicalSeverity::Unknown + ); + assert_eq!( + mapper.map("eslint/plugin", "error"), + CanonicalSeverity::Unknown + ); } } @@ -1303,19 +1354,34 @@ mod integration_tests { fn full_workflow_with_custom_linter() { // Create a mapper for a custom linter let mapper = SeverityMapBuilder::new() - .with_linter("my-custom-linter", [ - ("critical", CanonicalSeverity::Error), - ("major", CanonicalSeverity::Warning), - ("minor", CanonicalSeverity::Info), - ("suggestion", CanonicalSeverity::Hint), - ]) + .with_linter( + "my-custom-linter", + [ + ("critical", CanonicalSeverity::Error), + ("major", CanonicalSeverity::Warning), + ("minor", CanonicalSeverity::Info), + ("suggestion", CanonicalSeverity::Hint), + ], + ) .build(); // Use the mapper - assert_eq!(mapper.map("my-custom-linter", "critical"), CanonicalSeverity::Error); - assert_eq!(mapper.map("my-custom-linter", "major"), CanonicalSeverity::Warning); - assert_eq!(mapper.map("my-custom-linter", "minor"), CanonicalSeverity::Info); - assert_eq!(mapper.map("my-custom-linter", "suggestion"), CanonicalSeverity::Hint); + assert_eq!( + mapper.map("my-custom-linter", "critical"), + CanonicalSeverity::Error + ); + assert_eq!( + mapper.map("my-custom-linter", "major"), + CanonicalSeverity::Warning + ); + assert_eq!( + mapper.map("my-custom-linter", "minor"), + CanonicalSeverity::Info + ); + assert_eq!( + mapper.map("my-custom-linter", "suggestion"), + CanonicalSeverity::Hint + ); // Check problem detection assert!(is_error_level(&mapper.map("my-custom-linter", "critical"))); @@ -1325,10 +1391,13 @@ mod integration_tests { #[test] fn combining_default_and_custom_mappings() { let mapper = SeverityMapBuilder::with_defaults() - .with_linter("custom", [ - ("bad", CanonicalSeverity::Error), - ("not-great", CanonicalSeverity::Warning), - ]) + .with_linter( + "custom", + [ + ("bad", CanonicalSeverity::Error), + ("not-great", CanonicalSeverity::Warning), + ], + ) .build(); // Default mappings work @@ -1337,7 +1406,10 @@ mod integration_tests { // Custom mappings work assert_eq!(mapper.map("custom", "bad"), CanonicalSeverity::Error); - assert_eq!(mapper.map("custom", "not-great"), CanonicalSeverity::Warning); + assert_eq!( + mapper.map("custom", "not-great"), + CanonicalSeverity::Warning + ); } #[test] @@ -1347,10 +1419,13 @@ mod integration_tests { // Create custom mapper for internal tools let internal = SeverityMapBuilder::new() - .with_linter("internal-linter", [ - ("severe", CanonicalSeverity::Error), - ("moderate", CanonicalSeverity::Warning), - ]) + .with_linter( + "internal-linter", + [ + ("severe", CanonicalSeverity::Error), + ("moderate", CanonicalSeverity::Warning), + ], + ) .build(); // Merge internal mappings @@ -1358,7 +1433,10 @@ mod integration_tests { // Both default and internal work assert_eq!(mapper.map("eslint", "error"), CanonicalSeverity::Error); - assert_eq!(mapper.map("internal-linter", "severe"), CanonicalSeverity::Error); + assert_eq!( + mapper.map("internal-linter", "severe"), + CanonicalSeverity::Error + ); } #[test] diff --git a/crates/lintdiff-severity/src/lib.rs b/crates/lintdiff-severity/src/lib.rs index 609a71f..79eb0a7 100644 --- a/crates/lintdiff-severity/src/lib.rs +++ b/crates/lintdiff-severity/src/lib.rs @@ -220,11 +220,11 @@ impl Severity { #[cfg(feature = "colors")] pub fn ansi_color(self) -> &'static str { match self { - Severity::Hint => "\x1b[36m", // Cyan - Severity::Note => "\x1b[34m", // Blue + Severity::Hint => "\x1b[36m", // Cyan + Severity::Note => "\x1b[34m", // Blue Severity::Warning => "\x1b[33m", // Yellow - Severity::Error => "\x1b[31m", // Red - Severity::Fatal => "\x1b[35m", // Magenta + Severity::Error => "\x1b[31m", // Red + Severity::Fatal => "\x1b[35m", // Magenta } } } diff --git a/crates/lintdiff-severity/tests/severity_tests.rs b/crates/lintdiff-severity/tests/severity_tests.rs index 99f8e9d..edbf951 100644 --- a/crates/lintdiff-severity/tests/severity_tests.rs +++ b/crates/lintdiff-severity/tests/severity_tests.rs @@ -498,7 +498,7 @@ mod threshold_functionality { let t1 = SeverityThreshold::minimum(Severity::Warning); let t2 = SeverityThreshold::minimum(Severity::Warning); let t3 = SeverityThreshold::minimum(Severity::Error); - + assert_eq!(t1, t2); assert_ne!(t1, t3); } @@ -571,12 +571,12 @@ mod additional_coverage { #[test] fn test_severity_hash_consistency() { use std::collections::HashSet; - + let mut set = HashSet::new(); set.insert(Severity::Warning); set.insert(Severity::Error); set.insert(Severity::Warning); // Duplicate - + assert_eq!(set.len(), 2); } @@ -585,7 +585,7 @@ mod additional_coverage { let s1 = Severity::Warning; let s2 = s1; // Copy let s3 = s1; // Copy again - + assert_eq!(s1, s2); assert_eq!(s2, s3); } @@ -595,7 +595,7 @@ mod additional_coverage { let t1 = SeverityThreshold::minimum(Severity::Error); let t2 = t1; // Copy let t3 = t1; // Copy again - + assert_eq!(t1, t2); assert_eq!(t2, t3); } @@ -609,7 +609,7 @@ mod additional_coverage { Severity::Error, Severity::Fatal, ]; - + // Verify each is strictly less than the next for i in 0..severities.len() - 1 { assert!(severities[i] < severities[i + 1]); @@ -619,7 +619,7 @@ mod additional_coverage { #[test] fn test_roundtrip_str_to_severity_to_str() { let inputs = ["hint", "note", "warning", "error", "fatal"]; - + for input in inputs { let severity = Severity::from_str(input).unwrap(); assert_eq!(severity.as_str(), input); diff --git a/crates/lintdiff-slugify/src/lib.rs b/crates/lintdiff-slugify/src/lib.rs index dbbafbf..dfc47df 100644 --- a/crates/lintdiff-slugify/src/lib.rs +++ b/crates/lintdiff-slugify/src/lib.rs @@ -534,11 +534,9 @@ fn truncate_at_boundary(s: &mut String, separator: char, max_len: usize) { #[must_use] pub fn slugify_cow(s: &str) -> Cow<'_, str> { // Check if slugification is needed - let needs_conversion = s.chars().any(|c| { - c.is_whitespace() - || (!c.is_alphanumeric() && c != '-') - || c.is_uppercase() - }); + let needs_conversion = s + .chars() + .any(|c| c.is_whitespace() || (!c.is_alphanumeric() && c != '-') || c.is_uppercase()); if !needs_conversion { Cow::Borrowed(s) @@ -580,7 +578,10 @@ mod tests { fn test_preserve_special() { let options = SlugOptions::new().with_preserve_special(true); assert_eq!(slugify_with_options("Test@123", &options), "test@123"); - assert_eq!(slugify_with_options("Special#Char", &options), "special#char"); + assert_eq!( + slugify_with_options("Special#Char", &options), + "special#char" + ); } #[test] @@ -592,7 +593,10 @@ mod tests { #[test] fn test_max_length() { let options = SlugOptions::new().with_max_length(10); - assert_eq!(slugify_with_options("Very Long String", &options), "very-long"); + assert_eq!( + slugify_with_options("Very Long String", &options), + "very-long" + ); } #[test] diff --git a/crates/lintdiff-slugify/tests/slugify_tests.rs b/crates/lintdiff-slugify/tests/slugify_tests.rs index 094eb67..8467c5b 100644 --- a/crates/lintdiff-slugify/tests/slugify_tests.rs +++ b/crates/lintdiff-slugify/tests/slugify_tests.rs @@ -59,10 +59,7 @@ mod basic_slugify_tests { #[test] fn test_multiple_words() { - assert_eq!( - slugify("This is a long title"), - "this-is-a-long-title" - ); + assert_eq!(slugify("This is a long title"), "this-is-a-long-title"); } } @@ -273,7 +270,10 @@ mod preserve_special_tests { #[test] fn test_preserve_at_symbol() { let options = preserve_options(); - assert_eq!(slugify_with_options("test@example", &options), "test@example"); + assert_eq!( + slugify_with_options("test@example", &options), + "test@example" + ); } #[test] @@ -392,9 +392,7 @@ mod separator_tests { #[test] fn test_separator_with_max_length() { - let options = SlugOptions::new() - .with_separator('_') - .with_max_length(15); + let options = SlugOptions::new().with_separator('_').with_max_length(15); assert_eq!( slugify_with_options("One Two Three Four Five", &options), "one_two_three" @@ -424,7 +422,10 @@ mod max_length_tests { #[test] fn test_max_length_truncation() { let options = SlugOptions::new().with_max_length(10); - assert_eq!(slugify_with_options("Very Long String", &options), "very-long"); + assert_eq!( + slugify_with_options("Very Long String", &options), + "very-long" + ); } #[test] @@ -459,10 +460,7 @@ mod max_length_tests { #[test] fn test_max_length_no_truncation_needed() { let options = SlugOptions::new().with_max_length(100); - assert_eq!( - slugify_with_options("Short", &options), - "short" - ); + assert_eq!(slugify_with_options("Short", &options), "short"); } } @@ -563,33 +561,25 @@ mod builder_tests { #[test] fn test_builder_with_lowercase() { - let slugifier = SlugifierBuilder::new() - .with_lowercase(false) - .build(); + let slugifier = SlugifierBuilder::new().with_lowercase(false).build(); assert_eq!(slugifier.slugify("Hello World"), "Hello-World"); } #[test] fn test_builder_with_separator() { - let slugifier = SlugifierBuilder::new() - .with_separator('_') - .build(); + let slugifier = SlugifierBuilder::new().with_separator('_').build(); assert_eq!(slugifier.slugify("Hello World"), "hello_world"); } #[test] fn test_builder_with_max_length() { - let slugifier = SlugifierBuilder::new() - .with_max_length(10) - .build(); + let slugifier = SlugifierBuilder::new().with_max_length(10).build(); assert_eq!(slugifier.slugify("Very Long String"), "very-long"); } #[test] fn test_builder_with_preserve_special() { - let slugifier = SlugifierBuilder::new() - .with_preserve_special(true) - .build(); + let slugifier = SlugifierBuilder::new().with_preserve_special(true).build(); assert_eq!(slugifier.slugify("test@example"), "test@example"); } @@ -600,10 +590,7 @@ mod builder_tests { .with_separator('_') .with_max_length(20) .build(); - assert_eq!( - slugifier.slugify("Hello World Test"), - "Hello_World_Test" - ); + assert_eq!(slugifier.slugify("Hello World Test"), "Hello_World_Test"); } #[test] @@ -788,7 +775,9 @@ mod combination_tests { let input = "This is a COMPLEX Test String!!! With @ Special # Characters $"; let result = slugify_with_options(input, &options); assert!(result.len() <= 50); - assert!(result.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')); + assert!(result + .chars() + .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')); } } @@ -817,10 +806,7 @@ mod real_world_tests { #[test] fn test_url_path() { - assert_eq!( - slugify("/api/v1/users/123"), - "api-v1-users-123" - ); + assert_eq!(slugify("/api/v1/users/123"), "api-v1-users-123"); } #[test] @@ -833,10 +819,7 @@ mod real_world_tests { #[test] fn test_code_identifier() { - assert_eq!( - slugify("myFunctionName"), - "myfunctionname" - ); + assert_eq!(slugify("myFunctionName"), "myfunctionname"); } #[test] @@ -849,18 +832,12 @@ mod real_world_tests { #[test] fn test_markdown_header() { - assert_eq!( - slugify("## Introduction to Rust"), - "introduction-to-rust" - ); + assert_eq!(slugify("## Introduction to Rust"), "introduction-to-rust"); } #[test] fn test_version_string() { - assert_eq!( - slugify("v1.2.3-beta.1"), - "v1-2-3-beta-1" - ); + assert_eq!(slugify("v1.2.3-beta.1"), "v1-2-3-beta-1"); } #[test] @@ -873,10 +850,7 @@ mod real_world_tests { #[test] fn test_package_name() { - assert_eq!( - slugify("@scope/package-name"), - "scope-package-name" - ); + assert_eq!(slugify("@scope/package-name"), "scope-package-name"); } } @@ -1068,7 +1042,10 @@ mod truncate_boundary_tests { #[test] fn test_truncate_preserves_readability() { let options = SlugOptions::new().with_max_length(20); - let result = slugify_with_options("This is a very long sentence that needs truncation", &options); + let result = slugify_with_options( + "This is a very long sentence that needs truncation", + &options, + ); assert!(result.len() <= 20); // Should not end with a separator assert!(!result.ends_with('-')); diff --git a/crates/lintdiff-sort/src/lib.rs b/crates/lintdiff-sort/src/lib.rs index ed45ff2..f7ac6f9 100644 --- a/crates/lintdiff-sort/src/lib.rs +++ b/crates/lintdiff-sort/src/lib.rs @@ -449,10 +449,7 @@ mod tests { }; assert_eq!(compare_by_key(&a, &b, SortKey::Path), Ordering::Less); assert_eq!(compare_by_key(&b, &a, SortKey::Path), Ordering::Greater); - assert_eq!( - compare_by_key(&a, &a, SortKey::Path), - Ordering::Equal - ); + assert_eq!(compare_by_key(&a, &a, SortKey::Path), Ordering::Equal); } #[test] diff --git a/crates/lintdiff-sort/tests/sort_tests.rs b/crates/lintdiff-sort/tests/sort_tests.rs index 7dceb3a..d0618e9 100644 --- a/crates/lintdiff-sort/tests/sort_tests.rs +++ b/crates/lintdiff-sort/tests/sort_tests.rs @@ -293,8 +293,8 @@ mod sort_config_tests { assert_eq!(config.primary, SortKey::Severity); assert_eq!(config.secondary, Some(SortKey::Path)); assert_eq!(config.tertiary, Some(SortKey::Column)); // From default - // Note: by_severity uses ascending direction because compare_by_key for Severity - // already reverses the order (higher severity first) + // Note: by_severity uses ascending direction because compare_by_key for Severity + // already reverses the order (higher severity first) assert_eq!(config.direction, SortDirection::Ascending); } @@ -383,10 +383,7 @@ mod compare_by_key_tests { let low = TestItem::new("test").with_column(5); let high = TestItem::new("test").with_column(15); - assert_eq!( - compare_by_key(&low, &high, SortKey::Column), - Ordering::Less - ); + assert_eq!(compare_by_key(&low, &high, SortKey::Column), Ordering::Less); assert_eq!( compare_by_key(&high, &low, SortKey::Column), Ordering::Greater @@ -407,14 +404,8 @@ mod compare_by_key_tests { let a = TestItem::new("test").with_message("error a"); let b = TestItem::new("test").with_message("error b"); - assert_eq!( - compare_by_key(&a, &b, SortKey::Message), - Ordering::Less - ); - assert_eq!( - compare_by_key(&b, &a, SortKey::Message), - Ordering::Greater - ); + assert_eq!(compare_by_key(&a, &b, SortKey::Message), Ordering::Less); + assert_eq!(compare_by_key(&b, &a, SortKey::Message), Ordering::Greater); } #[test] @@ -422,10 +413,7 @@ mod compare_by_key_tests { let a = TestItem::new("test").with_fingerprint("abc123"); let b = TestItem::new("test").with_fingerprint("def456"); - assert_eq!( - compare_by_key(&a, &b, SortKey::Fingerprint), - Ordering::Less - ); + assert_eq!(compare_by_key(&a, &b, SortKey::Fingerprint), Ordering::Less); assert_eq!( compare_by_key(&b, &a, SortKey::Fingerprint), Ordering::Greater @@ -629,11 +617,11 @@ mod natural_compare_tests { #[test] fn natural_compare_multiple_numbers() { assert_eq!(natural_compare("file1.txt", "file10.txt"), Ordering::Less); - assert_eq!(natural_compare("file10.txt", "file2.txt"), Ordering::Greater); assert_eq!( - natural_compare("file2part1", "file2part10"), - Ordering::Less + natural_compare("file10.txt", "file2.txt"), + Ordering::Greater ); + assert_eq!(natural_compare("file2part1", "file2part10"), Ordering::Less); } #[test] @@ -708,7 +696,11 @@ mod natural_sort_tests { natural_sort_owned(&mut strings); assert_eq!( strings, - vec!["file1".to_string(), "file2".to_string(), "file10".to_string()] + vec![ + "file1".to_string(), + "file2".to_string(), + "file10".to_string() + ] ); } @@ -790,10 +782,7 @@ mod edge_case_tests { let a = TestItem::new("test").with_severity(u8::MAX); let b = TestItem::new("test").with_severity(0); - assert_eq!( - compare_by_key(&a, &b, SortKey::Severity), - Ordering::Less - ); // Higher severity first + assert_eq!(compare_by_key(&a, &b, SortKey::Severity), Ordering::Less); // Higher severity first } #[test] @@ -804,10 +793,7 @@ mod edge_case_tests { let b = TestItem::new("test").with_line(0).with_column(0); assert_eq!(compare_by_key(&a, &b, SortKey::Line), Ordering::Greater); - assert_eq!( - compare_by_key(&a, &b, SortKey::Column), - Ordering::Greater - ); + assert_eq!(compare_by_key(&a, &b, SortKey::Column), Ordering::Greater); } #[test] diff --git a/crates/lintdiff-span-intersect/src/lib.rs b/crates/lintdiff-span-intersect/src/lib.rs index 678d64c..bbfe66c 100644 --- a/crates/lintdiff-span-intersect/src/lib.rs +++ b/crates/lintdiff-span-intersect/src/lib.rs @@ -162,13 +162,7 @@ pub fn find_containing_ranges(line: u32, ranges: &[LineRange]) -> Vec { ranges .iter() .enumerate() - .filter_map(|(i, r)| { - if r.contains(line) { - Some(i) - } else { - None - } - }) + .filter_map(|(i, r)| if r.contains(line) { Some(i) } else { None }) .collect() } @@ -194,9 +188,7 @@ pub fn find_containing_ranges(line: u32, ranges: &[LineRange]) -> Vec { /// ``` #[must_use] pub fn find_first_containing(line: u32, ranges: &[LineRange]) -> Option { - ranges - .iter() - .position(|r| r.contains(line)) + ranges.iter().position(|r| r.contains(line)) } /// Count how many ranges contain a given line number. @@ -474,20 +466,14 @@ mod tests { #[test] fn test_line_in_ranges_found() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; assert!(line_in_ranges(5, &ranges)); assert!(line_in_ranges(25, &ranges)); } #[test] fn test_line_in_ranges_not_found() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; assert!(!line_in_ranges(15, &ranges)); assert!(!line_in_ranges(0, &ranges)); assert!(!line_in_ranges(35, &ranges)); @@ -502,7 +488,7 @@ mod tests { #[test] fn test_line_in_ranges_boundary() { let ranges = vec![LineRange::new(5, 10)]; - assert!(line_in_ranges(5, &ranges)); // Start + assert!(line_in_ranges(5, &ranges)); // Start assert!(line_in_ranges(10, &ranges)); // End assert!(!line_in_ranges(4, &ranges)); // Before assert!(!line_in_ranges(11, &ranges)); // After @@ -521,40 +507,28 @@ mod tests { #[test] fn test_find_containing_ranges_single() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; let result = find_containing_ranges(5, &ranges); assert_eq!(result, vec![0]); } #[test] fn test_find_containing_ranges_none() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; let result = find_containing_ranges(15, &ranges); assert!(result.is_empty()); } #[test] fn test_find_first_containing_found() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(5, 15), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(5, 15)]; assert_eq!(find_first_containing(7, &ranges), Some(0)); assert_eq!(find_first_containing(12, &ranges), Some(1)); } #[test] fn test_find_first_containing_none() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; assert_eq!(find_first_containing(15, &ranges), None); } @@ -572,10 +546,7 @@ mod tests { #[test] fn test_range_intersects_any() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; assert!(range_intersects_any(&LineRange::new(5, 15), &ranges)); assert!(!range_intersects_any(&LineRange::new(12, 18), &ranges)); } @@ -642,28 +613,19 @@ mod tests { #[test] fn test_is_sorted_and_disjoint_true() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; assert!(is_sorted_and_disjoint(&ranges)); } #[test] fn test_is_sorted_and_disjoint_overlapping() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(5, 15), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(5, 15)]; assert!(!is_sorted_and_disjoint(&ranges)); } #[test] fn test_is_sorted_and_disjoint_unsorted() { - let ranges = vec![ - LineRange::new(20, 30), - LineRange::new(1, 10), - ]; + let ranges = vec![LineRange::new(20, 30), LineRange::new(1, 10)]; assert!(!is_sorted_and_disjoint(&ranges)); } } diff --git a/crates/lintdiff-span-intersect/tests/span_intersect_tests.rs b/crates/lintdiff-span-intersect/tests/span_intersect_tests.rs index 498b863..cfafd64 100644 --- a/crates/lintdiff-span-intersect/tests/span_intersect_tests.rs +++ b/crates/lintdiff-span-intersect/tests/span_intersect_tests.rs @@ -2,8 +2,8 @@ //! //! These tests cover all public API functions and edge cases. -use lintdiff_span_intersect::*; use lintdiff_line_range::LineRange; +use lintdiff_span_intersect::*; // ============================================================================ // ranges_intersect Tests @@ -179,10 +179,7 @@ mod line_in_ranges_tests { #[test] fn line_between_ranges() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; assert!(!line_in_ranges(15, &ranges)); } @@ -195,16 +192,13 @@ mod line_in_ranges_tests { #[test] fn boundary_values() { let ranges = vec![LineRange::new(5, 10)]; - assert!(line_in_ranges(5, &ranges)); // Start + assert!(line_in_ranges(5, &ranges)); // Start assert!(line_in_ranges(10, &ranges)); // End } #[test] fn overlapping_ranges() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(5, 15), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(5, 15)]; assert!(line_in_ranges(7, &ranges)); // In both assert!(line_in_ranges(3, &ranges)); // Only in first assert!(line_in_ranges(12, &ranges)); // Only in second @@ -220,10 +214,7 @@ mod find_containing_ranges_tests { #[test] fn finds_single_range() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; let result = find_containing_ranges(5, &ranges); assert_eq!(result, vec![0]); } @@ -241,10 +232,7 @@ mod find_containing_ranges_tests { #[test] fn finds_no_ranges() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; let result = find_containing_ranges(15, &ranges); assert!(result.is_empty()); } @@ -277,28 +265,19 @@ mod find_first_containing_tests { #[test] fn finds_first_match() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(5, 15), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(5, 15)]; assert_eq!(find_first_containing(7, &ranges), Some(0)); } #[test] fn finds_later_match() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; assert_eq!(find_first_containing(25, &ranges), Some(1)); } #[test] fn no_match_returns_none() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; assert_eq!(find_first_containing(15, &ranges), None); } @@ -318,19 +297,13 @@ mod count_containing_tests { #[test] fn counts_zero() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; assert_eq!(count_containing(15, &ranges), 0); } #[test] fn counts_one() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; assert_eq!(count_containing(5, &ranges), 1); } @@ -360,19 +333,13 @@ mod range_intersects_any_tests { #[test] fn intersects_one() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; assert!(range_intersects_any(&LineRange::new(5, 15), &ranges)); } #[test] fn intersects_none() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; assert!(!range_intersects_any(&LineRange::new(12, 18), &ranges)); } @@ -426,10 +393,7 @@ mod find_intersecting_ranges_tests { #[test] fn finds_none() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; let query = LineRange::new(12, 18); let result = find_intersecting_ranges(&query, &ranges); assert!(result.is_empty()); @@ -452,10 +416,7 @@ mod merge_intersecting_ranges_tests { #[test] fn merges_overlapping() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(5, 15), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(5, 15)]; let merged = merge_intersecting_ranges(&ranges); assert_eq!(merged.len(), 1); assert_eq!(merged[0], LineRange::new(1, 15)); @@ -463,10 +424,7 @@ mod merge_intersecting_ranges_tests { #[test] fn merges_adjacent() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(11, 20), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(11, 20)]; let merged = merge_intersecting_ranges(&ranges); assert_eq!(merged.len(), 1); assert_eq!(merged[0], LineRange::new(1, 20)); @@ -474,10 +432,7 @@ mod merge_intersecting_ranges_tests { #[test] fn keeps_disjoint_separate() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(20, 30), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(20, 30)]; let merged = merge_intersecting_ranges(&ranges); assert_eq!(merged.len(), 2); } @@ -542,8 +497,8 @@ mod total_covered_lines_tests { #[test] fn counts_with_overlap() { let ranges = vec![ - LineRange::new(1, 10), // 10 lines - LineRange::new(5, 15), // 5 new lines (11-15) + LineRange::new(1, 10), // 10 lines + LineRange::new(5, 15), // 5 new lines (11-15) ]; assert_eq!(total_covered_lines(&ranges), 15); } @@ -590,28 +545,19 @@ mod is_sorted_and_disjoint_tests { #[test] fn overlapping_fails() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(5, 15), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(5, 15)]; assert!(!is_sorted_and_disjoint(&ranges)); } #[test] fn unsorted_fails() { - let ranges = vec![ - LineRange::new(20, 30), - LineRange::new(1, 10), - ]; + let ranges = vec![LineRange::new(20, 30), LineRange::new(1, 10)]; assert!(!is_sorted_and_disjoint(&ranges)); } #[test] fn adjacent_is_disjoint() { - let ranges = vec![ - LineRange::new(1, 10), - LineRange::new(11, 20), - ]; + let ranges = vec![LineRange::new(1, 10), LineRange::new(11, 20)]; assert!(is_sorted_and_disjoint(&ranges)); } diff --git a/crates/lintdiff-span/src/lib.rs b/crates/lintdiff-span/src/lib.rs index cdb77fe..3b2a078 100644 --- a/crates/lintdiff-span/src/lib.rs +++ b/crates/lintdiff-span/src/lib.rs @@ -556,7 +556,10 @@ mod tests { #[test] fn test_span_line_count() { assert_eq!(Span::single_line(5, 1, 10).line_count(), 1); - assert_eq!(Span::new(Position::new(1, 1), Position::new(5, 10)).line_count(), 5); + assert_eq!( + Span::new(Position::new(1, 1), Position::new(5, 10)).line_count(), + 5 + ); } #[test] diff --git a/crates/lintdiff-stats/src/lib.rs b/crates/lintdiff-stats/src/lib.rs index 4af2fb2..43a81c5 100644 --- a/crates/lintdiff-stats/src/lib.rs +++ b/crates/lintdiff-stats/src/lib.rs @@ -154,7 +154,10 @@ impl Stats { Severity::Warn => "warning", Severity::Info => "info", }; - *stats.by_severity.entry(severity_key.to_string()).or_insert(0) += 1; + *stats + .by_severity + .entry(severity_key.to_string()) + .or_insert(0) += 1; // Count by code *stats.by_code.entry(finding.code.clone()).or_insert(0) += 1; @@ -257,7 +260,6 @@ impl Stats { } } - /// Trait for types that can provide stats. /// /// This trait allows different types to be converted into statistics, diff --git a/crates/lintdiff-stats/tests/stats_tests.rs b/crates/lintdiff-stats/tests/stats_tests.rs index 6c8f917..29962fb 100644 --- a/crates/lintdiff-stats/tests/stats_tests.rs +++ b/crates/lintdiff-stats/tests/stats_tests.rs @@ -150,13 +150,14 @@ mod from_findings { #[test] fn code_is_counted_correctly() { - let findings = vec![create_finding(Severity::Error, "clippy::unwrap_used", "src/lib.rs")]; + let findings = vec![create_finding( + Severity::Error, + "clippy::unwrap_used", + "src/lib.rs", + )]; let stats = Stats::from_findings(&findings); - assert_eq!( - stats.by_code.get("clippy::unwrap_used"), - Some(&1) - ); + assert_eq!(stats.by_code.get("clippy::unwrap_used"), Some(&1)); } #[test] @@ -350,14 +351,8 @@ mod merge { total_diagnostics: 100, matched_diagnostics: 60, filtered_diagnostics: 40, - by_severity: HashMap::from([ - ("error".to_string(), 20), - ("warning".to_string(), 40), - ]), - by_code: HashMap::from([ - ("E001".to_string(), 10), - ("W001".to_string(), 30), - ]), + by_severity: HashMap::from([("error".to_string(), 20), ("warning".to_string(), 40)]), + by_code: HashMap::from([("E001".to_string(), 10), ("W001".to_string(), 30)]), files_affected: 15, }; @@ -365,14 +360,8 @@ mod merge { total_diagnostics: 50, matched_diagnostics: 30, filtered_diagnostics: 20, - by_severity: HashMap::from([ - ("error".to_string(), 10), - ("info".to_string(), 20), - ]), - by_code: HashMap::from([ - ("E001".to_string(), 5), - ("I001".to_string(), 15), - ]), + by_severity: HashMap::from([("error".to_string(), 10), ("info".to_string(), 20)]), + by_code: HashMap::from([("E001".to_string(), 5), ("I001".to_string(), 15)]), files_affected: 20, }; @@ -542,10 +531,7 @@ mod serialization { #[test] fn stats_serializes_severity_map() { let mut stats = Stats::new(); - stats.by_severity = HashMap::from([ - ("error".to_string(), 5), - ("warning".to_string(), 3), - ]); + stats.by_severity = HashMap::from([("error".to_string(), 5), ("warning".to_string(), 3)]); let json = serde_json::to_string(&stats).unwrap(); @@ -557,10 +543,7 @@ mod serialization { #[test] fn stats_serializes_code_map() { let mut stats = Stats::new(); - stats.by_code = HashMap::from([ - ("E001".to_string(), 10), - ("W001".to_string(), 5), - ]); + stats.by_code = HashMap::from([("E001".to_string(), 10), ("W001".to_string(), 5)]); let json = serde_json::to_string(&stats).unwrap(); diff --git a/crates/lintdiff-timestamp/src/lib.rs b/crates/lintdiff-timestamp/src/lib.rs index d3da487..a05fdc0 100644 --- a/crates/lintdiff-timestamp/src/lib.rs +++ b/crates/lintdiff-timestamp/src/lib.rs @@ -301,10 +301,9 @@ impl TimestampFormatter { format_timestamp_millis(dt) } else { // Format without timezone - const FORMAT: &[time::format_description::BorrowedFormatItem<'static>] = - time::macros::format_description!( - "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]" - ); + const FORMAT: &[time::format_description::BorrowedFormatItem<'static>] = time::macros::format_description!( + "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]" + ); dt.format(FORMAT) .unwrap_or_else(|_| "1970-01-01T00:00:00.000".to_string()) } @@ -312,9 +311,7 @@ impl TimestampFormatter { format_timestamp(dt) } else { const FORMAT: &[time::format_description::BorrowedFormatItem<'static>] = - time::macros::format_description!( - "[year]-[month]-[day]T[hour]:[minute]:[second]" - ); + time::macros::format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]"); dt.format(FORMAT) .unwrap_or_else(|_| "1970-01-01T00:00:00".to_string()) } @@ -567,7 +564,11 @@ impl std::fmt::Display for Date { /// assert!(!timestamps_approx_equal(&a, &b, Duration::milliseconds(50))); /// ``` #[must_use] -pub fn timestamps_approx_equal(a: &OffsetDateTime, b: &OffsetDateTime, tolerance: Duration) -> bool { +pub fn timestamps_approx_equal( + a: &OffsetDateTime, + b: &OffsetDateTime, + tolerance: Duration, +) -> bool { let diff = if a > b { *a - *b } else { *b - *a }; diff <= tolerance } diff --git a/crates/lintdiff-timestamp/tests/timestamp_tests.rs b/crates/lintdiff-timestamp/tests/timestamp_tests.rs index fc2d665..f5a7ae3 100644 --- a/crates/lintdiff-timestamp/tests/timestamp_tests.rs +++ b/crates/lintdiff-timestamp/tests/timestamp_tests.rs @@ -1045,7 +1045,14 @@ mod property_tests { use super::*; use time::{Date, Month, Time, UtcOffset}; - fn create_datetime(year: i32, month: u8, day: u8, hour: u8, minute: u8, second: u8) -> Option { + fn create_datetime( + year: i32, + month: u8, + day: u8, + hour: u8, + minute: u8, + second: u8, + ) -> Option { let date = Date::from_calendar_date(year, Month::try_from(month).ok()?, day).ok()?; let time = Time::from_hms(hour, minute, second).ok()?; Some(date.with_time(time).assume_offset(UtcOffset::UTC)) @@ -1189,8 +1196,16 @@ mod now_utc { let parsed = parse_timestamp(&formatted).unwrap(); let after = now_utc(); - assert!(timestamps_approx_equal(&parsed, &before, Duration::seconds(2))); - assert!(timestamps_approx_equal(&parsed, &after, Duration::seconds(2))); + assert!(timestamps_approx_equal( + &parsed, + &before, + Duration::seconds(2) + )); + assert!(timestamps_approx_equal( + &parsed, + &after, + Duration::seconds(2) + )); } } diff --git a/crates/lintdiff-truncate/src/lib.rs b/crates/lintdiff-truncate/src/lib.rs index dbac287..6fb01f1 100644 --- a/crates/lintdiff-truncate/src/lib.rs +++ b/crates/lintdiff-truncate/src/lib.rs @@ -261,7 +261,9 @@ pub fn truncate_lines(lines: &[String], config: &TruncateConfig) -> Vec } // Calculate how much to allocate per line on average - let available = config.max_length.saturating_sub(config.ellipsis.len() * lines.len()); + let available = config + .max_length + .saturating_sub(config.ellipsis.len() * lines.len()); let per_line = available / lines.len().max(1); let per_line = per_line.max(config.ellipsis.len()); @@ -273,7 +275,10 @@ pub fn truncate_lines(lines: &[String], config: &TruncateConfig) -> Vec }; // Truncate each line - lines.iter().map(|line| truncate_owned(line, &line_config)).collect() + lines + .iter() + .map(|line| truncate_owned(line, &line_config)) + .collect() } /// Check if a string would be truncated. @@ -333,7 +338,8 @@ fn find_word_boundary(s: &str, target_bytes: usize) -> usize { // Only use the word boundary if it's not at the very start if last_space > 0 { // Return the position after the whitespace - let after_space = last_space + s[last_space..].chars().next().map_or(0, |c| c.len_utf8()); + let after_space = + last_space + s[last_space..].chars().next().map_or(0, |c| c.len_utf8()); return after_space.min(target); } } diff --git a/crates/lintdiff-verdict-reason/src/lib.rs b/crates/lintdiff-verdict-reason/src/lib.rs index 088527d..b048ab0 100644 --- a/crates/lintdiff-verdict-reason/src/lib.rs +++ b/crates/lintdiff-verdict-reason/src/lib.rs @@ -248,16 +248,36 @@ impl fmt::Display for VerdictReason { match self { Self::NoChanges => write!(f, "No diagnostic changes detected"), Self::AddedWarnings { count } => { - write!(f, "Added {} warning{}", count, if *count == 1 { "" } else { "s" }) + write!( + f, + "Added {} warning{}", + count, + if *count == 1 { "" } else { "s" } + ) } Self::AddedErrors { count } => { - write!(f, "Added {} error{}", count, if *count == 1 { "" } else { "s" }) + write!( + f, + "Added {} error{}", + count, + if *count == 1 { "" } else { "s" } + ) } Self::RemovedWarnings { count } => { - write!(f, "Fixed {} warning{}", count, if *count == 1 { "" } else { "s" }) + write!( + f, + "Fixed {} warning{}", + count, + if *count == 1 { "" } else { "s" } + ) } Self::RemovedErrors { count } => { - write!(f, "Fixed {} error{}", count, if *count == 1 { "" } else { "s" }) + write!( + f, + "Fixed {} error{}", + count, + if *count == 1 { "" } else { "s" } + ) } Self::OnlyUnchanged => write!(f, "Only unchanged diagnostics found"), Self::ThresholdExceeded { limit, actual } => { @@ -729,18 +749,32 @@ pub fn format_reason_short(reason: &VerdictReason) -> String { #[must_use] pub fn format_reason_markdown(reason: &VerdictReason) -> String { match reason { - VerdictReason::NoChanges => "**✅ No Changes** - No diagnostic changes detected".to_string(), + VerdictReason::NoChanges => { + "**✅ No Changes** - No diagnostic changes detected".to_string() + } VerdictReason::AddedWarnings { count } => { - format!("**⚠️ Added Warnings** - {count} new warning{} introduced", if *count == 1 { "" } else { "s" }) + format!( + "**⚠️ Added Warnings** - {count} new warning{} introduced", + if *count == 1 { "" } else { "s" } + ) } VerdictReason::AddedErrors { count } => { - format!("**❌ Added Errors** - {count} new error{} introduced", if *count == 1 { "" } else { "s" }) + format!( + "**❌ Added Errors** - {count} new error{} introduced", + if *count == 1 { "" } else { "s" } + ) } VerdictReason::RemovedWarnings { count } => { - format!("**🩹 Fixed Warnings** - {count} warning{} resolved", if *count == 1 { "" } else { "s" }) + format!( + "**🩹 Fixed Warnings** - {count} warning{} resolved", + if *count == 1 { "" } else { "s" } + ) } VerdictReason::RemovedErrors { count } => { - format!("**🔧 Fixed Errors** - {count} error{} resolved", if *count == 1 { "" } else { "s" }) + format!( + "**🔧 Fixed Errors** - {count} error{} resolved", + if *count == 1 { "" } else { "s" } + ) } VerdictReason::OnlyUnchanged => { "**⏳ Only Unchanged** - Only pre-existing diagnostics found".to_string() @@ -867,8 +901,7 @@ pub fn merge_reasons(reasons: &[VerdictReason]) -> VerdictReason { } VerdictReason::ThresholdExceeded { limit, actual } => { let excess = actual.saturating_sub(*limit); - let current_excess = threshold_exceeded - .map_or(0, |(l, a)| a.saturating_sub(l)); + let current_excess = threshold_exceeded.map_or(0, |(l, a)| a.saturating_sub(l)); if excess > current_excess { threshold_exceeded = Some((*limit, *actual)); } @@ -953,13 +986,14 @@ mod tests { ); assert_eq!(VerdictReason::OnlyUnchanged.as_str(), "only-unchanged"); assert_eq!( - VerdictReason::ThresholdExceeded { limit: 10, actual: 15 }.as_str(), + VerdictReason::ThresholdExceeded { + limit: 10, + actual: 15 + } + .as_str(), "threshold-exceeded" ); - assert_eq!( - VerdictReason::Custom("test".to_string()).as_str(), - "custom" - ); + assert_eq!(VerdictReason::Custom("test".to_string()).as_str(), "custom"); } #[test] @@ -1031,16 +1065,16 @@ mod tests { #[test] fn test_format_reason_short() { - assert_eq!( - format_reason_short(&VerdictReason::NoChanges), - "no-changes" - ); + assert_eq!(format_reason_short(&VerdictReason::NoChanges), "no-changes"); assert_eq!( format_reason_short(&VerdictReason::AddedWarnings { count: 5 }), "added-warnings:5" ); assert_eq!( - format_reason_short(&VerdictReason::ThresholdExceeded { limit: 10, actual: 15 }), + format_reason_short(&VerdictReason::ThresholdExceeded { + limit: 10, + actual: 15 + }), "threshold-exceeded:15/10" ); } @@ -1048,33 +1082,49 @@ mod tests { #[test] fn test_is_failure_reason() { assert!(is_failure_reason(&VerdictReason::AddedErrors { count: 1 })); - assert!(is_failure_reason(&VerdictReason::AddedWarnings { count: 1 })); + assert!(is_failure_reason(&VerdictReason::AddedWarnings { + count: 1 + })); assert!(is_failure_reason(&VerdictReason::ThresholdExceeded { limit: 10, actual: 15 })); - assert!(is_failure_reason(&VerdictReason::Custom("test".to_string()))); + assert!(is_failure_reason(&VerdictReason::Custom( + "test".to_string() + ))); assert!(!is_failure_reason(&VerdictReason::NoChanges)); - assert!(!is_failure_reason(&VerdictReason::RemovedErrors { count: 1 })); - assert!(!is_failure_reason(&VerdictReason::RemovedWarnings { count: 1 })); + assert!(!is_failure_reason(&VerdictReason::RemovedErrors { + count: 1 + })); + assert!(!is_failure_reason(&VerdictReason::RemovedWarnings { + count: 1 + })); assert!(!is_failure_reason(&VerdictReason::OnlyUnchanged)); } #[test] fn test_is_success_reason() { assert!(is_success_reason(&VerdictReason::NoChanges)); - assert!(is_success_reason(&VerdictReason::RemovedErrors { count: 1 })); - assert!(is_success_reason(&VerdictReason::RemovedWarnings { count: 1 })); + assert!(is_success_reason(&VerdictReason::RemovedErrors { + count: 1 + })); + assert!(is_success_reason(&VerdictReason::RemovedWarnings { + count: 1 + })); assert!(is_success_reason(&VerdictReason::OnlyUnchanged)); assert!(!is_success_reason(&VerdictReason::AddedErrors { count: 1 })); - assert!(!is_success_reason(&VerdictReason::AddedWarnings { count: 1 })); + assert!(!is_success_reason(&VerdictReason::AddedWarnings { + count: 1 + })); assert!(!is_success_reason(&VerdictReason::ThresholdExceeded { limit: 10, actual: 15 })); - assert!(!is_success_reason(&VerdictReason::Custom("test".to_string()))); + assert!(!is_success_reason(&VerdictReason::Custom( + "test".to_string() + ))); } #[test] diff --git a/crates/lintdiff-verdict-reason/tests/verdict_reason_tests.rs b/crates/lintdiff-verdict-reason/tests/verdict_reason_tests.rs index 65f41c3..6b5747a 100644 --- a/crates/lintdiff-verdict-reason/tests/verdict_reason_tests.rs +++ b/crates/lintdiff-verdict-reason/tests/verdict_reason_tests.rs @@ -238,7 +238,10 @@ mod verdict_reason_builder { let reason = VerdictReasonBuilder::new() .with_custom("Special handling".to_string()) .build(); - assert_eq!(reason, VerdictReason::Custom("Special handling".to_string())); + assert_eq!( + reason, + VerdictReason::Custom("Special handling".to_string()) + ); } #[test] @@ -419,8 +422,7 @@ mod verdict_summary { #[test] fn test_summary_is_failure() { - let failure_summary = - VerdictSummary::new(VerdictReason::AddedErrors { count: 1 }); + let failure_summary = VerdictSummary::new(VerdictReason::AddedErrors { count: 1 }); assert!(failure_summary.is_failure()); let success_summary = VerdictSummary::new(VerdictReason::NoChanges); @@ -432,8 +434,7 @@ mod verdict_summary { let success_summary = VerdictSummary::new(VerdictReason::RemovedErrors { count: 1 }); assert!(success_summary.is_success()); - let failure_summary = - VerdictSummary::new(VerdictReason::AddedWarnings { count: 1 }); + let failure_summary = VerdictSummary::new(VerdictReason::AddedWarnings { count: 1 }); assert!(!failure_summary.is_success()); } @@ -480,13 +481,19 @@ mod helper_functions { #[test] fn test_is_failure_reason_added_errors() { assert!(is_failure_reason(&VerdictReason::AddedErrors { count: 1 })); - assert!(is_failure_reason(&VerdictReason::AddedErrors { count: 100 })); + assert!(is_failure_reason(&VerdictReason::AddedErrors { + count: 100 + })); } #[test] fn test_is_failure_reason_added_warnings() { - assert!(is_failure_reason(&VerdictReason::AddedWarnings { count: 1 })); - assert!(is_failure_reason(&VerdictReason::AddedWarnings { count: 100 })); + assert!(is_failure_reason(&VerdictReason::AddedWarnings { + count: 1 + })); + assert!(is_failure_reason(&VerdictReason::AddedWarnings { + count: 100 + })); } #[test] @@ -499,7 +506,9 @@ mod helper_functions { #[test] fn test_is_failure_reason_custom() { - assert!(is_failure_reason(&VerdictReason::Custom("Any reason".to_string()))); + assert!(is_failure_reason(&VerdictReason::Custom( + "Any reason".to_string() + ))); } #[test] @@ -509,8 +518,12 @@ mod helper_functions { #[test] fn test_is_success_reason_removed() { - assert!(is_success_reason(&VerdictReason::RemovedErrors { count: 1 })); - assert!(is_success_reason(&VerdictReason::RemovedWarnings { count: 1 })); + assert!(is_success_reason(&VerdictReason::RemovedErrors { + count: 1 + })); + assert!(is_success_reason(&VerdictReason::RemovedWarnings { + count: 1 + })); } #[test] @@ -527,7 +540,10 @@ mod helper_functions { VerdictReason::RemovedWarnings { count: 1 }, VerdictReason::RemovedErrors { count: 1 }, VerdictReason::OnlyUnchanged, - VerdictReason::ThresholdExceeded { limit: 1, actual: 2 }, + VerdictReason::ThresholdExceeded { + limit: 1, + actual: 2, + }, VerdictReason::Custom("test".to_string()), ]; @@ -559,9 +575,7 @@ mod edge_cases { #[test] fn test_large_counts() { - let reason = VerdictReason::AddedErrors { - count: usize::MAX, - }; + let reason = VerdictReason::AddedErrors { count: usize::MAX }; assert_eq!(reason.count(), Some(usize::MAX)); } @@ -616,10 +630,7 @@ mod edge_cases { actual: 10, }; // This is technically "at" the limit, but the variant exists - assert_eq!( - format_reason_short(&reason), - "threshold-exceeded:10/10" - ); + assert_eq!(format_reason_short(&reason), "threshold-exceeded:10/10"); } #[test] @@ -776,7 +787,11 @@ mod additional_coverage { VerdictReason::RemovedWarnings { count: 1 }.icon(), VerdictReason::RemovedErrors { count: 1 }.icon(), VerdictReason::OnlyUnchanged.icon(), - VerdictReason::ThresholdExceeded { limit: 1, actual: 2 }.icon(), + VerdictReason::ThresholdExceeded { + limit: 1, + actual: 2, + } + .icon(), VerdictReason::Custom("".to_string()).icon(), ]; @@ -795,7 +810,11 @@ mod additional_coverage { VerdictReason::RemovedWarnings { count: 1 }.as_str(), VerdictReason::RemovedErrors { count: 1 }.as_str(), VerdictReason::OnlyUnchanged.as_str(), - VerdictReason::ThresholdExceeded { limit: 1, actual: 2 }.as_str(), + VerdictReason::ThresholdExceeded { + limit: 1, + actual: 2, + } + .as_str(), VerdictReason::Custom("".to_string()).as_str(), ]; @@ -819,14 +838,26 @@ mod additional_coverage { #[test] fn test_merge_threshold_takes_highest_excess() { let reasons = vec![ - VerdictReason::ThresholdExceeded { limit: 10, actual: 12 }, // excess 2 - VerdictReason::ThresholdExceeded { limit: 5, actual: 20 }, // excess 15 - VerdictReason::ThresholdExceeded { limit: 3, actual: 5 }, // excess 2 + VerdictReason::ThresholdExceeded { + limit: 10, + actual: 12, + }, // excess 2 + VerdictReason::ThresholdExceeded { + limit: 5, + actual: 20, + }, // excess 15 + VerdictReason::ThresholdExceeded { + limit: 3, + actual: 5, + }, // excess 2 ]; let merged = merge_reasons(&reasons); assert_eq!( merged, - VerdictReason::ThresholdExceeded { limit: 5, actual: 20 } + VerdictReason::ThresholdExceeded { + limit: 5, + actual: 20 + } ); } @@ -866,7 +897,10 @@ mod additional_coverage { VerdictReason::RemovedWarnings { count: 1 }, VerdictReason::RemovedErrors { count: 1 }, VerdictReason::OnlyUnchanged, - VerdictReason::ThresholdExceeded { limit: 1, actual: 2 }, + VerdictReason::ThresholdExceeded { + limit: 1, + actual: 2, + }, VerdictReason::Custom("test".to_string()), ]; diff --git a/crates/lintdiff-verdict/src/lib.rs b/crates/lintdiff-verdict/src/lib.rs index 910438c..cb17213 100644 --- a/crates/lintdiff-verdict/src/lib.rs +++ b/crates/lintdiff-verdict/src/lib.rs @@ -150,7 +150,12 @@ impl FindingCounts { /// Create counts with specific values. #[must_use] - pub const fn from_counts(new_errors: u32, new_warnings: u32, fixed: u32, pre_existing: u32) -> Self { + pub const fn from_counts( + new_errors: u32, + new_warnings: u32, + fixed: u32, + pre_existing: u32, + ) -> Self { Self { new_errors, new_warnings, diff --git a/crates/lintdiff-verdict/tests/verdict_tests.rs b/crates/lintdiff-verdict/tests/verdict_tests.rs index 7c9a86e..fef2908 100644 --- a/crates/lintdiff-verdict/tests/verdict_tests.rs +++ b/crates/lintdiff-verdict/tests/verdict_tests.rs @@ -597,14 +597,18 @@ mod edge_cases { #[test] fn combine_multiple_verdicts() { let verdicts = [Verdict::Pass, Verdict::Warn, Verdict::Pass, Verdict::Fail]; - let combined = verdicts.iter().fold(Verdict::Pass, |acc, &v| acc.combine(v)); + let combined = verdicts + .iter() + .fold(Verdict::Pass, |acc, &v| acc.combine(v)); assert_eq!(combined, Verdict::Fail); } #[test] fn combine_empty_iterator() { let verdicts: [Verdict; 0] = []; - let combined = verdicts.iter().fold(Verdict::Pass, |acc, &v| acc.combine(v)); + let combined = verdicts + .iter() + .fold(Verdict::Pass, |acc, &v| acc.combine(v)); assert_eq!(combined, Verdict::Pass); } From 2aae758c0cd84ba87764b7387e2ac78a9f0567fd Mon Sep 17 00:00:00 2001 From: Steven Zimmerman Date: Sun, 29 Mar 2026 15:50:57 -0400 Subject: [PATCH 5/9] fix: adapt ExplainSection serde payload variants for new serde behavior --- crates/lintdiff-explain-builder/src/lib.rs | 37 +++++++++++++------ .../tests/explain_builder_tests.rs | 6 +-- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/crates/lintdiff-explain-builder/src/lib.rs b/crates/lintdiff-explain-builder/src/lib.rs index ef71edb..0d93783 100644 --- a/crates/lintdiff-explain-builder/src/lib.rs +++ b/crates/lintdiff-explain-builder/src/lib.rs @@ -49,9 +49,15 @@ use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "serde", serde(tag = "type", rename_all = "snake_case"))] pub enum ExplainSection { /// Plain text content. - Text(String), + Text { + /// The plain text content. + content: String, + }, /// Bullet list items. - Bullets(Vec), + Bullets { + /// Items in the bullet list. + items: Vec, + }, /// Code block with optional language. Code { /// The code content. @@ -79,13 +85,15 @@ impl ExplainSection { /// Create a new text section. #[must_use] pub fn text(content: impl Into) -> Self { - Self::Text(content.into()) + Self::Text { + content: content.into(), + } } /// Create a new bullets section. #[must_use] pub const fn bullets(items: Vec) -> Self { - Self::Bullets(items) + Self::Bullets { items } } /// Create a new code section. @@ -116,7 +124,7 @@ impl ExplainSection { #[must_use] pub fn to_markdown(&self, config: &ExplainConfig) -> String { match self { - Self::Text(text) => { + Self::Text { content: text } => { if config.indent > 0 { let indent = " ".repeat(config.indent); text.lines() @@ -127,7 +135,7 @@ impl ExplainSection { text.clone() } } - Self::Bullets(items) => items + Self::Bullets { items } => items .iter() .map(|item| { if config.indent > 0 { @@ -230,7 +238,7 @@ impl ExplainSection { #[must_use] pub fn to_plain_text(&self, config: &ExplainConfig) -> String { match self { - Self::Text(text) => { + Self::Text { content: text } => { if config.indent > 0 { let indent = " ".repeat(config.indent); text.lines() @@ -241,7 +249,7 @@ impl ExplainSection { text.clone() } } - Self::Bullets(items) => items + Self::Bullets { items } => items .iter() .map(|item| { if config.indent > 0 { @@ -470,7 +478,7 @@ impl ExplainBuilder { /// Bullet points are collected and rendered as a list. pub fn add_bullet(&mut self, item: &str) -> &mut Self { // Find or create a Bullets section - if let Some(ExplainSection::Bullets(items)) = self.sections.last_mut() { + if let Some(ExplainSection::Bullets { items }) = self.sections.last_mut() { items.push(item.to_string()); return self; } @@ -711,7 +719,12 @@ mod tests { #[test] fn test_explain_section_text() { let section = ExplainSection::text("Hello, world!"); - assert_eq!(section, ExplainSection::Text("Hello, world!".to_string())); + assert_eq!( + section, + ExplainSection::Text { + content: "Hello, world!".to_string() + } + ); } #[test] @@ -719,7 +732,9 @@ mod tests { let section = ExplainSection::bullets(vec!["a".to_string(), "b".to_string()]); assert_eq!( section, - ExplainSection::Bullets(vec!["a".to_string(), "b".to_string()]) + ExplainSection::Bullets { + items: vec!["a".to_string(), "b".to_string()], + } ); } diff --git a/crates/lintdiff-explain-builder/tests/explain_builder_tests.rs b/crates/lintdiff-explain-builder/tests/explain_builder_tests.rs index be56aab..e47dacb 100644 --- a/crates/lintdiff-explain-builder/tests/explain_builder_tests.rs +++ b/crates/lintdiff-explain-builder/tests/explain_builder_tests.rs @@ -233,7 +233,7 @@ mod bullet_points { // Then assert_eq!(builder.sections().len(), 1); - if let ExplainSection::Bullets(items) = &builder.sections()[0] { + if let ExplainSection::Bullets { items } = &builder.sections()[0] { assert_eq!(items.len(), 2); } else { panic!("Expected Bullets section"); @@ -262,7 +262,7 @@ mod bullet_points { builder.add_bullet(""); // Then - if let ExplainSection::Bullets(items) = &builder.sections()[0] { + if let ExplainSection::Bullets { items } = &builder.sections()[0] { assert_eq!(items[0], ""); } else { panic!("Expected Bullets section"); @@ -280,7 +280,7 @@ mod bullet_points { } // Then - if let ExplainSection::Bullets(items) = &builder.sections()[0] { + if let ExplainSection::Bullets { items } = &builder.sections()[0] { assert_eq!(items.len(), 100); } else { panic!("Expected Bullets section"); From 830f400dfac17709249fb777ab85555543fdab51 Mon Sep 17 00:00:00 2001 From: Steven Zimmerman Date: Sun, 29 Mar 2026 15:56:53 -0400 Subject: [PATCH 6/9] fix: serialize Severity as lowercase strings for serde compatibility --- crates/lintdiff-report-builder/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/lintdiff-report-builder/src/lib.rs b/crates/lintdiff-report-builder/src/lib.rs index 2b1d2ae..5efcbf0 100644 --- a/crates/lintdiff-report-builder/src/lib.rs +++ b/crates/lintdiff-report-builder/src/lib.rs @@ -149,6 +149,7 @@ impl GitInfo { #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] #[repr(u8)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "lowercase")] pub enum Severity { /// Informational hint. Hint = 0, @@ -1263,3 +1264,4 @@ mod tests { assert_eq!(report1, report2); } } + From a9fca6fd9ae0c83b0dd31db7cd631a208fb5caf9 Mon Sep 17 00:00:00 2001 From: Steven Zimmerman Date: Sun, 29 Mar 2026 15:58:30 -0400 Subject: [PATCH 7/9] fix: correct serde cfg_attr syntax for Severity --- crates/lintdiff-report-builder/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/lintdiff-report-builder/src/lib.rs b/crates/lintdiff-report-builder/src/lib.rs index 5efcbf0..b863510 100644 --- a/crates/lintdiff-report-builder/src/lib.rs +++ b/crates/lintdiff-report-builder/src/lib.rs @@ -149,7 +149,7 @@ impl GitInfo { #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] #[repr(u8)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "lowercase")] +#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))] pub enum Severity { /// Informational hint. Hint = 0, From 9c35403a6a5244145000a614aca27e58b18bf9c1 Mon Sep 17 00:00:00 2001 From: Steven Zimmerman Date: Sun, 29 Mar 2026 17:20:25 -0400 Subject: [PATCH 8/9] test: fix severity map builder property invariant --- crates/lintdiff-report-builder/src/lib.rs | 1 - .../tests/severity_map_tests.rs | 12 +++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/lintdiff-report-builder/src/lib.rs b/crates/lintdiff-report-builder/src/lib.rs index b863510..ae2ca63 100644 --- a/crates/lintdiff-report-builder/src/lib.rs +++ b/crates/lintdiff-report-builder/src/lib.rs @@ -1264,4 +1264,3 @@ mod tests { assert_eq!(report1, report2); } } - diff --git a/crates/lintdiff-severity-map/tests/severity_map_tests.rs b/crates/lintdiff-severity-map/tests/severity_map_tests.rs index a5261de..8e99387 100644 --- a/crates/lintdiff-severity-map/tests/severity_map_tests.rs +++ b/crates/lintdiff-severity-map/tests/severity_map_tests.rs @@ -1323,21 +1323,23 @@ mod property_tests { CanonicalSeverity::Warning, CanonicalSeverity::Error, ]; + let mut expected = std::collections::HashMap::new(); for (linter, level) in &mappings { + let canonical = canonical_levels[(*level as usize) % canonical_levels.len()]; builder = builder.with_mapping( linter, "severity", - canonical_levels[(*level as usize) % canonical_levels.len()], + canonical, ); + expected.insert(linter.to_lowercase(), canonical); } let mapper = builder.build(); - // Verify all mappings are present - for (linter, level) in &mappings { - let expected = canonical_levels[(*level as usize) % canonical_levels.len()]; - prop_assert_eq!(mapper.map(linter, "severity"), expected); + // Duplicate keys overwrite earlier entries, so only the last write per linter survives. + for (linter, expected) in expected { + prop_assert_eq!(mapper.map(&linter, "severity"), expected); } } } From 5dc54063bc4f24003d5d277ad9badfb60f9c3fc4 Mon Sep 17 00:00:00 2001 From: Steven Zimmerman Date: Sun, 29 Mar 2026 17:34:14 -0400 Subject: [PATCH 9/9] test: serialize cwd-mutating app-git integration tests --- .../tests/integration_tests.rs | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/crates/lintdiff-app-git/tests/integration_tests.rs b/crates/lintdiff-app-git/tests/integration_tests.rs index ec126f8..64d35b1 100644 --- a/crates/lintdiff-app-git/tests/integration_tests.rs +++ b/crates/lintdiff-app-git/tests/integration_tests.rs @@ -5,6 +5,7 @@ use std::fs; use std::process::Command; +use std::sync::{Mutex, MutexGuard, OnceLock}; use lintdiff_app_git::{acquire_diff, determine_repo_root, gather_git_info, AppGitError}; use tempfile::TempDir; @@ -37,6 +38,32 @@ fn git_run(dir: &std::path::Path, args: &[&str]) -> Result { } } +fn cwd_lock() -> MutexGuard<'static, ()> { + static CWD_LOCK: OnceLock> = OnceLock::new(); + CWD_LOCK + .get_or_init(|| Mutex::new(())) + .lock() + .expect("cwd lock poisoned") +} + +struct CurrentDirGuard { + original_dir: std::path::PathBuf, +} + +impl CurrentDirGuard { + fn change_to(path: &std::path::Path) -> Self { + let original_dir = std::env::current_dir().expect("failed to get current dir"); + std::env::set_current_dir(path).expect("failed to change dir"); + Self { original_dir } + } +} + +impl Drop for CurrentDirGuard { + fn drop(&mut self) { + std::env::set_current_dir(&self.original_dir).expect("failed to restore dir"); + } +} + /// Helper to create a temporary git repository with initial commit fn create_test_repo() -> Result { let temp_dir = TempDir::new().map_err(|e| format!("failed to create temp dir: {e}"))?; @@ -98,6 +125,7 @@ mod repo_root_detection { return; } + let _cwd_lock = cwd_lock(); let temp_dir = create_test_repo().expect("failed to create test repo"); let repo_path = temp_dir.path(); @@ -105,15 +133,11 @@ mod repo_root_detection { let subdir = repo_path.join("src").join("nested").join("deep"); fs::create_dir_all(&subdir).expect("failed to create subdir"); - // Change to subdirectory and find root - let original_dir = std::env::current_dir().expect("failed to get current dir"); - std::env::set_current_dir(&subdir).expect("failed to change dir"); + // Change to subdirectory and find root. + let _cwd_guard = CurrentDirGuard::change_to(&subdir); let result = determine_repo_root(None); - // Restore original directory - std::env::set_current_dir(&original_dir).expect("failed to restore dir"); - assert!(result.is_ok()); let found_root = result.unwrap(); // On Windows, git may return paths with different casing or format @@ -130,6 +154,7 @@ mod repo_root_detection { return; } + let _cwd_lock = cwd_lock(); let outer_repo = create_test_repo().expect("failed to create outer repo"); let outer_path = outer_repo.path(); @@ -146,15 +171,11 @@ mod repo_root_detection { git_run(&inner_path, &["add", "inner.txt"]).expect("failed to add"); git_run(&inner_path, &["commit", "-m", "Inner commit"]).expect("failed to commit"); - // From inner repo, should find inner repo root - let original_dir = std::env::current_dir().expect("failed to get current dir"); - std::env::set_current_dir(&inner_path).expect("failed to change dir"); + // From inner repo, should find inner repo root. + let _cwd_guard = CurrentDirGuard::change_to(&inner_path); let result = determine_repo_root(None); - // Restore original directory - std::env::set_current_dir(&original_dir).expect("failed to restore dir"); - assert!(result.is_ok()); let found_root = result.unwrap(); let found_canonical = found_root.canonicalize().unwrap_or(found_root); @@ -171,19 +192,16 @@ mod repo_root_detection { return; } + let _cwd_lock = cwd_lock(); // Create a temporary directory without git let temp_dir = TempDir::new().expect("failed to create temp dir"); let non_git_path = temp_dir.path(); - let original_dir = std::env::current_dir().expect("failed to get current dir"); - std::env::set_current_dir(non_git_path).expect("failed to change dir"); + let _cwd_guard = CurrentDirGuard::change_to(non_git_path); // determine_repo_root should fall back to current_dir when git command fails let result = determine_repo_root(None); - // Restore original directory - std::env::set_current_dir(&original_dir).expect("failed to restore dir"); - // Should return current directory as fallback assert!(result.is_ok()); }