Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mitsuhiko/insta
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1.2.0
Choose a base ref
...
head repository: mitsuhiko/insta
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1.3.0
Choose a head ref
  • 3 commits
  • 10 files changed
  • 1 contributor

Commits on Nov 15, 2020

  1. Verified

    This commit was signed with the committer’s verified signature.
    xuezhaojun xuezhao
    Copy the full SHA
    3062169 View commit details

Commits on Nov 19, 2020

  1. Copy the full SHA
    07c1df8 View commit details
  2. 1.3.0

    mitsuhiko committed Nov 19, 2020
    Copy the full SHA
    e23b3a1 View commit details
Showing with 164 additions and 58 deletions.
  1. +5 −0 CHANGELOG.md
  2. +2 −2 Cargo.toml
  3. +1 −1 Makefile
  4. +24 −25 README.md
  5. +4 −4 cargo-insta/Cargo.lock
  6. +2 −2 cargo-insta/Cargo.toml
  7. +109 −6 src/content.rs
  8. +8 −9 src/lib.rs
  9. +7 −7 src/macros.rs
  10. +2 −2 src/redaction.rs
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 1.3.0

* Expose more useful methods from `Content`.
* Fixes for latest rustc version.

## 1.2.0

* Fix invalid offset calculation for inline snapshot (#137)
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "insta"
version = "1.2.0"
version = "1.3.0"
license = "Apache-2.0"
authors = ["Armin Ronacher <armin.ronacher@active-4.com>"]
description = "A snapshot testing library for Rust"
@@ -36,7 +36,7 @@ serialization = []
csv = { version = "1.1.3", optional = true }
difference = "2.0.0"
serde = { version = "1.0.85", features = ["derive"] }
serde_yaml = "0.8.8"
serde_yaml = "0.8.14"
console = { version = "0.12.0", optional = true, default-features = false }
serde_json = "1.0.36"
lazy_static = "1.4.0"
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ lint:
@cargo clippy

update-readme:
@cargo readme > README.md
@cargo readme | perl -pe 's/\[`(.*?)`]/`$$1`/g' | perl -pe 's/\[(.*?)\](?![(])/$$1/g' > README.md
@cd cargo-insta; cargo readme > README.md

.PHONY: all doc test cargotest format format-check lint update-readme
49 changes: 24 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -19,9 +19,9 @@ large or change often.
## What it looks like:

```rust
#[test]
#test
fn test_hello_world() {
insta::assert_debug_snapshot!(vec![1, 2, 3]);
insta::assert_debug_snapshot!(vec!1, 2, 3);
}
```

@@ -51,9 +51,9 @@ $ cargo install cargo-insta
```rust
use insta::assert_debug_snapshot;

#[test]
#test
fn test_snapshots() {
assert_debug_snapshot!(vec![1, 2, 3]);
assert_debug_snapshot!(vec!1, 2, 3);
}
```

@@ -68,9 +68,9 @@ $ cargo test
$ cargo insta review
```

For more information on updating see [Snapshot Updating].
For more information on updating see Snapshot Updating.

[Snapshot Updating]: #snapshot-updating
Snapshot Updating: #snapshot-updating

## How it operates

@@ -96,7 +96,7 @@ the `name` of the snapshot. Snapshots can either be explicitly named or the
name is derived from the test name.

Additionally snapshots can also be stored inline. In that case the
[`cargo-insta`](https://crates.io/crates/cargo-insta) tool is necessary.
`cargo-insta`(https://crates.io/crates/cargo-insta) tool is necessary.
See [inline snapshots](#inline-snapshots) for more information.

For macros that work with `serde::Serialize` this crate also permits
@@ -110,7 +110,7 @@ that can make debugging easier and the snapshot:

```
---
expression: "vec![1, 2, 3]"
expression: "vec!1, 2, 3"
source: tests/test_basic.rs
---
[
@@ -190,7 +190,7 @@ To provide an explicit name provide the name of the snapshot as first
argument to the macro:

```rust
#[test]
#test
fn test_something() {
assert_snapshot!("first_snapshot", "first value");
assert_snapshot!("second_snapshot", "second value");
@@ -228,20 +228,20 @@ the syntax `{ selector => replacement_value }`.
The following selectors exist:

- `.key`: selects the given key
- `["key"]`: alternative syntax for keys
- `[index]`: selects the given index in an array
- `[]`: selects all items on an array
- `[:end]`: selects all items up to `end` (excluding, supports negative indexing)
- `[start:]`: selects all items starting with `start`
- `[start:end]`: selects all items from `start` to `end` (end excluding,
- `"key"`: alternative syntax for keys
- `index`: selects the given index in an array
- ``: selects all items on an array
- `:end`: selects all items up to `end` (excluding, supports negative indexing)
- `start:`: selects all items starting with `start`
- `start:end`: selects all items from `start` to `end` (end excluding,
supports negative indexing).
- `.*`: selects all keys on that depth
- `.**`: performs a deep match (zero or more items). Can only be used once.

Example usage:

```rust
#[derive(Serialize)]
#derive(Serialize)
pub struct User {
id: Uuid,
username: String,
@@ -257,14 +257,14 @@ assert_yaml_snapshot!(&User {
map
},
}, {
".id" => "[uuid]",
".extra.ssn" => "[ssn]"
".id" => "uuid",
".extra.ssn" => "ssn"
});
```

It's also possible to execute a callback that can produce a new value
instead of hardcoding a replacement value by using the
[`dynamic_redaction`](fn.dynamic_redaction.html) function:
`dynamic_redaction` function:

```rust
assert_yaml_snapshot!(&User {
@@ -273,7 +273,7 @@ assert_yaml_snapshot!(&User {
}, {
".id" => dynamic_redaction(|value, _| {
// assert that the value looks like a uuid here
"[uuid]"
"uuid"
}),
});
```
@@ -300,8 +300,7 @@ glob!("inputs/*.txt", |path| {
```

The path to the glob macro is relative to the location of the test
file. It uses the [`globwalk`](https://crates.io/crates/globwalk) crate
for actual glob operations.
file. It uses the `globwalk` crate for actual glob operations.

## Inline Snapshots

@@ -314,7 +313,7 @@ value on review.
Example:

```rust
#[derive(Serialize)]
#derive(Serialize)
pub struct User {
username: String,
}
@@ -341,7 +340,7 @@ The following features exist:
## Settings

There are some settings that can be changed on a per-thread (and thus
per-test) basis. For more information see [settings](struct.Settings.html).
per-test) basis. For more information see Settings.

## Legacy Snapshot Formats

@@ -362,7 +361,7 @@ cannot spot which files are actually unreferenced. However you can use
the `INSTA_SNAPSHOT_REFERENCES_FILE` environment variable to
instruct insta to append all referenced files into a list. This can then
be used to delete all files not referenced. For instance one could use
[`ripgrep`](https://github.com/BurntSushi/ripgrep) like this:
[ripgrep](https://github.com/BurntSushi/ripgrep) like this:

```
export INSTA_SNAPSHOT_REFERENCES_FILE="$(mktemp)"
8 changes: 4 additions & 4 deletions cargo-insta/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions cargo-insta/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cargo-insta"
version = "1.2.0"
version = "1.3.0"
license = "Apache-2.0"
authors = ["Armin Ronacher <armin.ronacher@active-4.com>"]
description = "A review tool for the insta snapshot testing library for Rust"
@@ -11,7 +11,7 @@ edition = "2018"
readme = "README.md"

[dependencies]
insta = { version = "1.2.0", path = "..", features = ["redactions"] }
insta = { version = "1.3.0", path = "..", features = ["redactions"] }
console = "0.12.0"
clap = "2.33.0"
difference = "2.0.0"
115 changes: 109 additions & 6 deletions src/content.rs
Original file line number Diff line number Diff line change
@@ -4,8 +4,26 @@ use std::marker::PhantomData;

/// Represents variable typed content.
///
/// This is used internally for the serialization system to
/// represent values before the actual snapshots are written.
/// This is used for the serialization system to represent values
/// before the actual snapshots are written and is also exposed to
/// dynamic redaction functions.
///
/// Some enum variants are intentionally not exposed to user code.
/// It's generally recommended to construct content objects by
/// using the [`From`](std::convert::From) trait and by using the
/// accessor methods to assert on it.
///
/// While matching on the content is possible in theory it is
/// recommended against. The reason for this is that the content
/// enum holds variants that can "wrap" values where it's not
/// expected. For instance if a field holds an `Option<String>`
/// you cannot use pattern matching to extract the string as it
/// will be contained in an internal `Some` variant that is not
/// exposed. On the other hand the `as_str` method will
/// automatically resolve such internal wrappers.
///
/// If you do need to pattern match you should use the
/// `resolve_inner` method to resolve such internal wrappers.
#[derive(Debug, Clone)]
pub enum Content {
Bool(bool),
@@ -125,16 +143,63 @@ impl<'a> From<&'a [u8]> for Content {
}

impl Content {
/// This resolves the innermost content in a chain of
/// wrapped content.
///
/// For instance if you encounter an `Option<Option<String>>`
/// field the content will be wrapped twice in an internal
/// option wrapper. If you need to pattern match you will
/// need in some situations to first resolve the inner value
/// before such matching can take place as there is no exposed
/// way to match on these wrappers.
///
/// This method does not need to be called for the `as_`
/// methods which resolve automatically.
pub fn resolve_inner(&self) -> &Content {
match *self {
Content::Some(ref v)
| Content::NewtypeStruct(_, ref v)
| Content::NewtypeVariant(_, _, _, ref v) => v.resolve_inner(),
ref other => other,
}
}

/// Returns the value as string
pub fn as_str(&self) -> Option<&str> {
match *self {
match self.resolve_inner() {
Content::String(ref s) => Some(s.as_str()),
_ => None,
}
}

/// Returns the value as bytes
pub fn as_bytes(&self) -> Option<&[u8]> {
match self.resolve_inner() {
Content::Bytes(ref b) => Some(&*b),
_ => None,
}
}

/// Returns the value as slice of content values.
pub fn as_slice(&self) -> Option<&[Content]> {
match self.resolve_inner() {
Content::Seq(ref v) | Content::Tuple(ref v) | Content::TupleVariant(_, _, _, ref v) => {
Some(&v[..])
}
_ => None,
}
}

/// Returns true if the value is nil.
pub fn is_nil(&self) -> bool {
match self.resolve_inner() {
Content::None | Content::Unit => true,
_ => false,
}
}

pub(crate) fn as_key(&self) -> Key<'_> {
match *self {
match *self.resolve_inner() {
Content::Bool(val) => Key::Bool(val),
Content::Char(val) => Key::U64(val as u64),
Content::U16(val) => Key::U64(val.into()),
@@ -147,14 +212,21 @@ impl Content {
Content::F64(val) => Key::F64(val),
Content::String(ref val) => Key::Str(&val.as_str()),
Content::Bytes(ref val) => Key::Bytes(&val[..]),
Content::Some(ref val) => val.as_key(),
_ => Key::Other,
}
}

/// Returns the value as bool
pub fn as_bool(&self) -> Option<bool> {
match *self.resolve_inner() {
Content::Bool(val) => Some(val),
_ => None,
}
}

/// Returns the value as u64
pub fn as_u64(&self) -> Option<u64> {
match *self {
match *self.resolve_inner() {
Content::U8(v) => Some(u64::from(v)),
Content::U16(v) => Some(u64::from(v)),
Content::U32(v) => Some(u64::from(v)),
@@ -167,6 +239,37 @@ impl Content {
}
}

/// Returns the value as i64
pub fn as_i64(&self) -> Option<i64> {
match *self.resolve_inner() {
Content::U8(v) => Some(i64::from(v)),
Content::U16(v) => Some(i64::from(v)),
Content::U32(v) => Some(i64::from(v)),
Content::U64(v) => {
let rv = v as i64;
if rv as u64 == v {
Some(rv)
} else {
None
}
}
Content::I8(v) => Some(i64::from(v)),
Content::I16(v) => Some(i64::from(v)),
Content::I32(v) => Some(i64::from(v)),
Content::I64(v) => Some(v),
_ => None,
}
}

/// Returns the value as f64
pub fn as_f64(&self) -> Option<f64> {
match *self.resolve_inner() {
Content::F32(v) => Some(f64::from(v)),
Content::F64(v) => Some(v),
_ => None,
}
}

pub(crate) fn sort_maps(&mut self) {
self.walk(&mut |content| {
if let Content::Map(ref mut items) = content {
17 changes: 8 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -266,7 +266,7 @@
//!
//! It's also possible to execute a callback that can produce a new value
//! instead of hardcoding a replacement value by using the
//! [`dynamic_redaction`](fn.dynamic_redaction.html) function:
//! [`dynamic_redaction`] function:
//!
//! ```no_run
//! # #[cfg(feature = "redactions")] {
@@ -311,8 +311,7 @@
//! ```
//!
//! The path to the glob macro is relative to the location of the test
//! file. It uses the [`globwalk`](https://crates.io/crates/globwalk) crate
//! for actual glob operations.
//! file. It uses the [`globwalk`] crate for actual glob operations.
//!
//! # Inline Snapshots
//!
@@ -343,17 +342,17 @@
//!
//! The following features exist:
//!
//! * `csv`: enables CSV support (`assert_csv_snapshot!`)
//! * `ron`: enables RON support (`assert_ron_snapshot!`)
//! * `toml`: enables TOML support (`assert_toml_snapshot!`)
//! * `csv`: enables CSV support ([`assert_csv_snapshot!`])
//! * `ron`: enables RON support ([`assert_ron_snapshot!`])
//! * `toml`: enables TOML support ([`assert_toml_snapshot!`])
//! * `redactions`: enables support for redactions
//! * `glob`: enables support for globbing (`glob!`)
//! * `glob`: enables support for globbing ([`glob!`])
//! * `colors`: enables color output (enabled by default)
//!
//! # Settings
//!
//! There are some settings that can be changed on a per-thread (and thus
//! per-test) basis. For more information see [settings](struct.Settings.html).
//! per-test) basis. For more information see [Settings].
//!
//! # Legacy Snapshot Formats
//!
@@ -374,7 +373,7 @@
//! the `INSTA_SNAPSHOT_REFERENCES_FILE` environment variable to
//! instruct insta to append all referenced files into a list. This can then
//! be used to delete all files not referenced. For instance one could use
//! [`ripgrep`](https://github.com/BurntSushi/ripgrep) like this:
//! [ripgrep](https://github.com/BurntSushi/ripgrep) like this:
//!
//! ```text
//! export INSTA_SNAPSHOT_REFERENCES_FILE="$(mktemp)"
14 changes: 7 additions & 7 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
///
/// **Feature:** `csv` (disabled by default)
///
/// This works exactly like [`assert_yaml_snapshot`](macro.assert_yaml_snapshot.html)
/// This works exactly like [`assert_yaml_snapshot!`]
/// but serializes in [CSV](https://github.com/burntsushi/rust-csv) format instead of
/// YAML.
///
@@ -45,7 +45,7 @@ macro_rules! assert_csv_snapshot {
///
/// **Feature:** `toml` (disabled by default)
///
/// This works exactly like [`assert_toml_snapshot`](macro.assert_toml_snapshot.html)
/// This works exactly like [`assert_toml_snapshot!`]
/// but serializes in [TOML](https://github.com/alexcrichton/toml-rs) format instead of
/// YAML. Note that TOML cannot represent all values due to limitations in the
/// format.
@@ -101,7 +101,7 @@ macro_rules! assert_toml_snapshot {
/// assert_yaml_snapshot!(vec![1, 2, 3]);
/// ```
///
/// Unlike the [`assert_debug_snapshot`](macros.assert_debug_snapshot.html)
/// Unlike the [`assert_debug_snapshot!`]
/// macro, this one has a secondary mode where redactions can be defined.
///
/// The third argument to the macro can be an object expression for redaction.
@@ -155,7 +155,7 @@ macro_rules! assert_yaml_snapshot {
///
/// **Feature:** `ron` (disabled by default)
///
/// This works exactly like [`assert_yaml_snapshot`](macro.assert_yaml_snapshot.html)
/// This works exactly like [`assert_yaml_snapshot!`]
/// but serializes in [RON](https://github.com/ron-rs/ron/) format instead of
/// YAML which retains some type information for more accurate comparisions.
///
@@ -197,9 +197,9 @@ macro_rules! assert_ron_snapshot {

/// Asserts a `Serialize` snapshot in JSON format.
///
/// This works exactly like [`assert_yaml_snapshot`](macro.assert_yaml_snapshot.html)
/// but serializes in JSON format. This is normally not recommended because it
/// makes diffs less reliable, but it can be useful for certain specialized situations.
/// This works exactly like [`assert_yaml_snapshot!`] but serializes in JSON format.
/// This is normally not recommended because it makes diffs less reliable, but it can
/// be useful for certain specialized situations.
///
/// Example:
///
4 changes: 2 additions & 2 deletions src/redaction.rs
Original file line number Diff line number Diff line change
@@ -99,8 +99,8 @@ impl<'a> From<&'a [u8]> for Redaction {
/// statically declaring it a dynamic value can be computed. This can also
/// be used to perform assertions before replacing the value.
///
/// The closure is passed two arguments: the value as [`Content`](internals/enum.Content.html)
/// and the path that was selected (as [`ContentPath`](internals/struct.ContentPath.html)).
/// The closure is passed two arguments: the value as [`Content`]
/// and the path that was selected (as [`ContentPath`])
///
/// Example:
///