Skip to content

Enforce starting newlines#563

Merged
max-sixty merged 38 commits intomitsuhiko:masterfrom
max-sixty:trimming
Sep 10, 2025
Merged

Enforce starting newlines#563
max-sixty merged 38 commits intomitsuhiko:masterfrom
max-sixty:trimming

Conversation

@max-sixty
Copy link
Copy Markdown
Collaborator

@max-sixty max-sixty commented Aug 11, 2024

This is an example of what I've been suggesting at #506 (+ some linked issues):

  • Stacked on Unify handling of file & inline snapshots (compat) #528 so that would need to merge first
  • Enforces the correct number of newlines at the start of snapshots. The start is easier because we don't need to worry about editor issues in trailing newlines (and don't need to worry about how Lines deals ambiguously with trailing new lines)
  • Works for both inline & file snapshots
  • Adds a matches_legacy method on snapshot contents — this encapsulates the older formats we still support and warns about them

It's not ready to merge yet, because we don't seem to actually support --force-update-snapshots on inline values, which is somewhat required. But I'm publishing for feedback & to put some weight on #528 in case we don't want to pursue.

max-sixty added a commit to max-sixty/insta that referenced this pull request Aug 12, 2024
This will make diffs in mitsuhiko#563 more reasonable

(Though it was good to have some snapshots that _weren't_ updated, as meta-tests that un-updated snapshots still worked -- possibly we try and add an integration test in that direction...)
max-sixty added a commit that referenced this pull request Aug 12, 2024
This will make diffs in #563 more reasonable

(Though it was good to have some snapshots that _weren't_ updated, as
meta-tests that un-updated snapshots still worked -- possibly we try and
add an integration test in that direction...)
Comment thread insta/src/serialization.rs Outdated
max-sixty added a commit to max-sixty/insta that referenced this pull request Aug 17, 2024
We previously excluded these. But it's somewhat required for mitsuhiko#563, and I don't think there's a big downside -- we only generate pending files when a snapshot doesn't match of `--force-update-snapshots` is passed.
max-sixty added a commit to max-sixty/insta that referenced this pull request Sep 17, 2024
Moving some unambiguous code from mitsuhiko#563 into a new PR so we can keep moving
max-sixty added a commit to max-sixty/insta that referenced this pull request Sep 17, 2024
max-sixty added a commit that referenced this pull request Sep 17, 2024
Moving some unambiguous code from #563 into a new PR so we can keep
moving
max-sixty added a commit that referenced this pull request Sep 17, 2024
Another PR taking some unambiguous code from #563
max-sixty added a commit that referenced this pull request Sep 19, 2024
#581)

This solves the issue in #573 for the moment:
- When `--force-update-snapshots` in passed, we only update inline
snapshots when there's some difference _within_ the string, such as an
additional linebreak at the start or the end
- We no longer update the surrounding hashes. In the existing code, this
happened because we were writing too many inline snapshots, not because
we were actually checking the number of hashes
- Checking the number of hashes isn't easy to do — reason outlined at
#573 (comment)
- The main change in the code is that we store the unnormalized snapshot
and then normalize when we need to. The existing code stored the
normalized version, which meant we couldn't evaluate whether the
unnormalized versions were different

It's a decent number of changes, but will integrate nicely with
#563.

~(FYI we currently don't look at the indentation, but we could adjust
this)~ Now indentation works too
@max-sixty
Copy link
Copy Markdown
Collaborator Author

One downside (but balanced against lots of upsides!) is that because we insert a newline at the start of a multiline string, a literal string can look a bit odd:

assert_snapshot!("
foo
bar
", @r"

foo
bar
");

Notice that because the original literal has a newline after its ", and we always add a newline to the original value, there are then two newlines after the opening quote of the result.

This is mostly only noticeable in examples: very few generated values start with a newline!

@max-sixty max-sixty mentioned this pull request Oct 6, 2024
@max-sixty
Copy link
Copy Markdown
Collaborator Author

max-sixty commented Sep 10, 2025

I'm tempted to merge this as there's no downside to enforce starting newlines; and it simplifies the code overall

lmk any objections...

max-sixty and others added 17 commits September 10, 2025 00:34
- Test common indentation removal with 4 and 8 spaces
- Test relative indentation preservation
- Test tab indentation handling
- Test edge cases with empty lines and whitespace
- Test single line trimming behavior
- Test force-update aggressive trimming
- Replace problematic trimming_indentation.rs with test_trimming_behavior.rs
- New tests create snapshots with excess indentation and verify trimming works
- Tests now correctly assert the expected trimmed output
- All tests passing locally
- Fix module ordering in main.rs
- Fix line breaks in assertions
- Remove trailing whitespace
- Remove redundant test_trimming_behavior.rs test file
- Keep comprehensive trimming.rs with precise diff assertions
- All trimming tests now in one well-structured file
- Tests cover: basic trimming, force-update, file snapshots, complex indentation
Based on code review feedback:
- Add test_edge_cases covering mixed tabs/spaces, no common indent, whitespace-only
- Improve file snapshot test assertions to verify structure
- Tests now cover all important edge cases identified in review
- Test that old format snapshots still pass (backwards compat)
- Test that --accept migrates old format to new trimmed format
- Test multiline warning behavior
- Test that properly formatted snapshots remain unchanged
- Test force-update on old format snapshots

These tests ensure:
1. No breaking changes for existing users
2. Clean migration path via --accept
3. Proper warning messages
4. Correct behavior preservation
- Merged trimming.rs and backwards_compat.rs into inline_snapshot_trimming.rs
- 9 comprehensive tests covering:
  - Basic trimming functionality (4 tests)
  - Backwards compatibility (5 tests)
- Tests cover all critical scenarios:
  - Old format compatibility
  - Migration path via --accept
  - Force-update aggressive trimming
  - Warning behavior
  - File snapshots
- Single file is easier to maintain and understand
Co-authored-by: Claude <no-reply@anthropic.com>
- Simpler, clearer description
- Focuses on what users care about: readable snapshots
- Avoids implementation details
The feature was announced in 1.41.0 but this PR implements it properly
Copy the existing 1.41.0 entry about --force-update-snapshots updating
inline snapshots' delimiters and indentation to Unreleased section,
since this PR properly implements that feature
The changelog now reflects that leading newlines are no longer trimmed during assertions.

Co-authored-by: Claude <no-reply@anthropic.com>
Move the indentation trimming entry from 1.41.0 (where it was incorrectly
announced but not implemented) to Unreleased (where it's actually being
implemented in this PR)
The indentation trimming functionality already existed in master.
The actual NEW feature is the leading newline requirement for multiline
snapshots and the associated warning.

Changes:
- Reduced from 12 tests (777 lines) to 6 focused tests (344 lines)
- Tests now specifically verify the leading newline requirement
- Each test case is properly isolated (no test munging)
- Removed redundant tests for pre-existing trimming functionality
- Fixed test assertions to check exact behavior (no || conditions)
- Improved test documentation to clarify NEW vs existing features
- Remove empty line between doc comment and function
- Fix format string to use inline variables per clippy suggestion
@max-sixty
Copy link
Copy Markdown
Collaborator Author

merging but one click to revert if anyone disagrees

@max-sixty max-sixty merged commit 16363f4 into mitsuhiko:master Sep 10, 2025
15 checks passed
@max-sixty max-sixty deleted the trimming branch September 10, 2025 21:49
@max-sixty max-sixty mentioned this pull request Nov 20, 2025
max-sixty added a commit that referenced this pull request Nov 20, 2025
## Summary

Prepare for the 1.44.0 release:

- Bump version to 1.44.0 in `insta/Cargo.toml` and
`cargo-insta/Cargo.toml`
- Update CHANGELOG.md with all changes since 1.43.2

## Changes in 1.44.0

- Added non-interactive snapshot review and reject modes for use in
non-TTY environments (LLMs, CI pipelines, scripts) #815
- Add `--disable-nextest-doctest` flag with deprecation warning #803
- Add ergonomic `--test-runner-fallback` / `--no-test-runner-fallback`
flags #811
- Apply redactions to snapshot metadata #813
- Remove confusing 'previously unseen snapshot' message #812
- Speed up JSON float rendering #806 (@nyurik)
- Allow globset version up to 0.4.16 #810 (@g0hl1n)
- Improve documentation #814 (@tshepang)
- Enforce starting newlines in assertions #563

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
max-sixty added a commit to max-sixty/insta that referenced this pull request Nov 27, 2025
This fixes a regression introduced in 1.44.0 where existing inline
snapshots using the legacy multiline format would fail to match.

The problem: In 1.44.0, we changed how inline snapshots handle leading
newlines (PR mitsuhiko#563). This caused snapshots like:

    insta::assert_snapshot!(value, @r"
    Unconflicted Mode(FILE) 0839b2e9412b
    ");

to fail when the actual value is "Unconflicted Mode(FILE) 0839b2e9412b".
The legacy format stored single-line content in a multiline raw string
with source code indentation, which after processing becomes
"    Unconflicted...\n    " - the leading spaces from indentation
weren't being stripped in the comparison.

The fix: In `matches_legacy`, detect the legacy single-line-in-multiline
pattern by checking if the raw contents contain a newline but collapse
to a single line after trimming. When this pattern is detected, apply
`trim_start()` to strip the source code indentation artifacts.

This ensures:
- Legacy snapshots continue to pass (with a warning to update)
- Modern single-line snapshots with intentional spaces are preserved
- True multiline snapshots are unaffected

We take backward compatibility seriously - upgrading insta should not
cause existing valid tests to fail.

Reported-by: jj-vcs/jj
See: mitsuhiko#819 (comment)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
max-sixty added a commit that referenced this pull request Nov 27, 2025
## Summary

This fixes a regression introduced in 1.44.0 where existing inline
snapshots using the legacy multiline format would fail to match.

**The problem:** PR #563 changed how inline snapshots handle leading
newlines. This caused snapshots like:

```rust
insta::assert_snapshot!(value, @r"
    Unconflicted Mode(FILE) 0839b2e9412b
    ");
```

to fail when the actual value is `"Unconflicted Mode(FILE)
0839b2e9412b"`.

The legacy format stored single-line content in a multiline raw string
with source code indentation. After `from_inline_literal` processing,
this becomes `" Unconflicted...\n "` — the leading spaces from code
indentation weren't being stripped in the legacy comparison path.

**The fix:** In `matches_legacy`, detect the legacy
single-line-in-multiline pattern:

```rust
let is_legacy_single_line_in_multiline =
    sc.contents.contains('\n') && sc.contents.trim_end().lines().count() <= 1;
```

When this pattern is detected, apply `trim_start()` to strip the source
code indentation artifacts.

This ensures:
- ✅ Legacy snapshots continue to pass (with a warning to update)
- ✅ Modern single-line snapshots with intentional leading spaces are
preserved
- ✅ True multiline snapshots are unaffected

## Test plan

- [x] Added 8 comprehensive functional tests covering:
  - Single-line content in multiline format (the jj bug)
  - Raw string multiline variant
  - Force update reformatting works
  - True multiline content unaffected
  - Multiline with relative indentation preserved
  - Intentional leading spaces correctly fail (no false positives)
  - Trailing whitespace line edge case
  - Empty snapshot edge case
- [x] All 72 functional tests pass
- [x] Full test suite passes

Reported-by: jj-vcs/jj  
See: #819 (comment)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
max-sixty added a commit to max-sixty/insta that referenced this pull request Nov 27, 2025
…ko#830)

## Summary

This fixes a regression introduced in 1.44.0 where existing inline
snapshots using the legacy multiline format would fail to match.

**The problem:** PR mitsuhiko#563 changed how inline snapshots handle leading
newlines. This caused snapshots like:

```rust
insta::assert_snapshot!(value, @r"
    Unconflicted Mode(FILE) 0839b2e9412b
    ");
```

to fail when the actual value is `"Unconflicted Mode(FILE)
0839b2e9412b"`.

The legacy format stored single-line content in a multiline raw string
with source code indentation. After `from_inline_literal` processing,
this becomes `" Unconflicted...\n "` — the leading spaces from code
indentation weren't being stripped in the legacy comparison path.

**The fix:** In `matches_legacy`, detect the legacy
single-line-in-multiline pattern:

```rust
let is_legacy_single_line_in_multiline =
    sc.contents.contains('\n') && sc.contents.trim_end().lines().count() <= 1;
```

When this pattern is detected, apply `trim_start()` to strip the source
code indentation artifacts.

This ensures:
- ✅ Legacy snapshots continue to pass (with a warning to update)
- ✅ Modern single-line snapshots with intentional leading spaces are
preserved
- ✅ True multiline snapshots are unaffected

## Test plan

- [x] Added 8 comprehensive functional tests covering:
  - Single-line content in multiline format (the jj bug)
  - Raw string multiline variant
  - Force update reformatting works
  - True multiline content unaffected
  - Multiline with relative indentation preserved
  - Intentional leading spaces correctly fail (no false positives)
  - Trailing whitespace line edge case
  - Empty snapshot edge case
- [x] All 72 functional tests pass
- [x] Full test suite passes

Reported-by: jj-vcs/jj  
See: mitsuhiko#819 (comment)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant