Skip to main content

Crate ferrotype

Crate ferrotype 

Source
Expand description

§Ferrotype

A tintype, also known as a melainotype or ferrotype, is a photograph made by creating a direct positive on a thin sheet of metal, colloquially called ‘tin’, coated with a dark lacquer or enamel and used as the support for the photographic emulsion.

Ferrotype is an opinionated wrapper around insta.rs that makes it easy to create and maintain structured snapshot tests with multiple named sections.

§Features

  • Multi-section snapshots with automatically formatted titles
  • Rich content support for various data types:
    • Debug output (add_debug)
    • Token streams (add_token_stream) with pretty formatting
    • Bluegum tree structures
    • Hex dumps of binary data with hex crate
    • ANSI color code stripping
  • Deterministic output with automatic filtering of memory addresses and non-deterministic data
  • Flexible organization with configurable snapshot directory structure
  • Debugging support with backtraces and error handling
  • Seamless integration with existing insta.rs workflows

§Installation

Add this to your Cargo.toml:

[dev-dependencies]
ferrotype = "0.1"

§Quick Start

Here’s the minimum required code to create a ferrotype snapshot:

use ferrotype::Ferrotype;

// 1. Create a new snapshot
let mut snapshot = Ferrotype::new();

// 2. Add content to sections
snapshot.add("Input", "Hello, world!".to_string());

// 3. Assert the snapshot
ferrotype::assert!(snapshot);

§Comprehensive Example

use ferrotype::Ferrotype;

#[derive(Debug)]
struct TestData {
    name: String,
    count: u32,
    items: Vec<String>,
}

let mut snapshot = Ferrotype::new();

// Configure snapshot behavior
snapshot.set_filter_memory_addresses(true);  // Default: true
snapshot.set_expect_errors(false);           // Default: false

// Add different types of content
snapshot.add("Description", "Testing my awesome feature".to_string());

let test_data = TestData {
    name: "test".to_string(),
    count: 42,
    items: vec!["a".to_string(), "b".to_string()],
};
snapshot.add_debug("Test Data", &test_data);

// Add hex dump of binary data
#[cfg(feature = "hex")]
snapshot.add_hex("Binary Data", &[0xDE, 0xAD, 0xBE, 0xEF]);

// Add formatted Rust code
#[cfg(feature = "tokenstream")]
{
    let tokens: proc_macro2::TokenStream =
        "fn hello() { println!(\"Hello!\"); }".parse().unwrap();
    snapshot.add_token_stream("Generated Code", &tokens);
}

// Assert the snapshot
ferrotype::assert!(snapshot);

§Examples

The crate includes several example programs demonstrating different aspects of ferrotype:

  • basic - Core functionality and simple usage patterns
  • filtering - Demonstrates all filtering options for non-deterministic data
  • features - Shows feature-specific functionality (hex dumps, token streams, etc.)
  • testing - Real-world testing scenarios with an API client

Run examples with:

# Basic example
cargo run --example basic

# Filtering demonstration
cargo run --example filtering

# All features (requires all features enabled)
cargo run --example features --all-features

# Testing example
cargo run --example testing

§Snapshot Output Format

The above example would create a snapshot file like this:

---
source: src/lib.rs
expression: "use my_crate::comprehensive_example"
---
Description: >
  Testing my awesome feature

TestData: >
  TestData {
      name: "test",
      count: 42,
      items: [
          "a",
          "b",
      ],
  }

BinaryData: >
  Length: 4 (0x4) bytes
  0000:   de ad be ef                                       ....

GeneratedCode: >
  fn hello() {
      println!("Hello!");
  }

Backtrace: >
  0: my_crate::comprehensive_example
             at src/lib.rs:42:5
  1: my_crate::comprehensive_example::{{closure}}
             at src/lib.rs:41:1
  ...

§Available Methods

§Core Methods

  • Ferrotype::new() - Create a new snapshot builder
  • add(title, content) - Add a section with string content
  • add_debug(title, item) - Add a section with debug-formatted content
  • as_string() - Get the formatted snapshot content
  • print() - Print to stdout

§Configuration

  • set_expect_errors(bool) - Configure whether errors are expected
  • set_filter_memory_addresses(bool) - Toggle memory address filtering
  • add_backtrace() - Add current call stack to snapshot

§Feature-specific Methods

These methods are available when the corresponding features are enabled:

§bluegum feature
  • add_bluegum(title, tree) - Add a rendered bluegum tree
  • add_bluegum_builder(title, builder) - Add a pre-built bluegum structure
  • add_bluegum_builder_with(title, closure) - Build bluegum structure with closure
  • add_bluegum_with(title, tree, styles) - Add bluegum tree with custom styles
§tokenstream feature
  • add_token_stream(title, tokens) - Add formatted Rust code from TokenStream
§anstream feature
  • add_strip_str(title, content) - Add content with ANSI codes stripped
§hex feature
  • add_hex(title, bytes) - Add hex dump of binary data

§Configuration Options

§Snapshot Directory

Control where snapshots are stored:

// Use custom folder structure
#[use_folder(parser, tests)]
ferrotype::assert!(snapshot);

// Results in snapshots stored in: snapshots/parser/tests/

§Feature Flags

[dev-dependencies]
ferrotype = { version = "0.1", features = ["hex", "bluegum"] }

# Or disable default features and pick specific ones
ferrotype = { version = "0.1", default-features = false, features = ["tokenstream"] }

Available features:

  • dot_snapshots - Store snapshots in .snapshots/ instead of snapshots/
  • tokenstream - Enable add_token_stream() for formatting Rust code
  • bluegum - Enable bluegum tree rendering methods
  • anstream - Enable add_strip_str() for ANSI code removal
  • hex - Enable add_hex() for binary data hex dumps

All features are enabled by default.

§Error Handling

use ferrotype::Ferrotype;

let mut snapshot = Ferrotype::new();
snapshot.set_expect_errors(true);  // Don't fail test on errors
snapshot.add("Error Case", "Some error output".to_string());
ferrotype::assert!(snapshot);

§Memory Address Filtering

use ferrotype::Ferrotype;

#[derive(Debug)]
struct SomeStruct {
    value: i32,
}

let some_struct = SomeStruct { value: 42 };
let mut snapshot = Ferrotype::new();
snapshot.set_filter_memory_addresses(false);  // Preserve memory addresses
snapshot.add_debug("Raw Debug", &some_struct);
ferrotype::assert!(snapshot);

§Integration with Existing Tests

Ferrotype works alongside existing insta.rs tests:

use ferrotype::Ferrotype;

// Existing insta test
fn existing_test() {
    let my_data = vec![1, 2, 3];
    insta::assert_debug_snapshot!(my_data);
}

// New ferrotype test
fn enhanced_test() {
    let input_data = "test input";
    let output_data = vec!["result1", "result2"];
    let analysis_results = "analysis complete";

    let mut snapshot = Ferrotype::new();
    snapshot.add("Input", input_data.to_string());
    snapshot.add_debug("Output", &output_data);
    snapshot.add("Analysis", analysis_results.to_string());
    ferrotype::assert!(snapshot);
}

§Best Practices

  1. Use descriptive section titles: They become the headings in your snapshots
  2. Group related data: Put related information in the same test
  3. Enable memory filtering: Keeps snapshots deterministic across runs
  4. Use appropriate content methods: add_debug for structs, add_hex for binary data, etc.
  5. Review snapshots: Use cargo insta review to accept/reject changes

§License

Licensed under the Blue Oak Model License 1.0.0 - see the LICENSE file for details.

Macros§

assert
Assert a snapshot using insta with ferrotype-specific configuration.

Structs§

Ferrotype
A snapshot builder for creating structured test snapshots with insta.

Functions§

get_output_dir
Get the output directory for snapshots based on the configured feature.