diff

Diff Output

When an expectation fails, BDD::Behave produces a structured, colorized diff between the actual and expected values whenever both are of a "diffable" shape. The diff is shape-aware: strings are compared character-by-character (single line) or line-by-line (multi line). Arrays, hashes, sets, bags, and mixes are rendered as multi-line JSON-style structures and compared with a longest-common-subsequence algorithm.

Conventions

  • Lines marked with red - are values that were expected but not present in the actual.

  • Lines marked with green + are values that were received but not in the expected.

  • Unmarked lines are unchanged context.

This matches the --Expected / ++Received convention used by Jest and similar runners.

When a diff is produced

A diff is rendered when both values share one of these shapes:

ShapeTrigger
Strboth values are Str
Arrayboth do Positional
Hashboth do Associative
Setboth are Set or SetHash
Bagboth are Bag or BagHash
Mixboth are Mix or MixHash
Junctionexpected is any Junction (any/all/one/none)

Plain scalars (Int, Bool, Rat, etc.) keep the existing Expected: / to be: lines without a diff section, since the two .raku representations already make the difference obvious.

String diffs

For single-line strings, the differing region is highlighted in place using common prefix/suffix detection:

- 'hello earth'
+ 'hello world'

The non-matching characters (earth and world) are colorized red and green respectively.

For multi-line strings, the diff drops to line-level:

  foo
- QUX
+ bar
  baz

Structural diffs

Hashes, arrays, sets, bags, and mixes are pretty-printed in JSON-style and then compared line-by-line:

  {
    "name" => "alice",
-   "age" => 31,
+   "age" => 30,
    "city" => "paris",
  }

Hash keys are sorted alphabetically for stable, reviewable output. Nested structures recurse and preserve indentation:

  {
    "tags" => [
      "x",
-     "z",
+     "y",
    ],
    "user" => {
      "age" => 30,
-     "name" => "bob",
+     "name" => "alice",
    },
  }

Junction diffs

When the expected value is a Junction, the diff collapses it to its constituent eigenstates and marks each one with āœ“ (smartmatched the given value) or āœ— (didn't), so the reader sees exactly which alternatives didn't line up:

- any(1, 2, 3)
+ 5
  Alternatives (none of 3 matched; expected at least one):
    āœ— 1
    āœ— 2
    āœ— 3

The summary line is tailored per junction kind (any / all / one / none) and reflects the negation state when .not is in play. Type-object alternatives (Int | Rat) render by name. Values render via .raku. See Junctions for the full set of summaries and an example under each kind.

Junction diffs are emitted even under negation (unlike scalar diffs), because the failed-negation case for a junction is still informative: the reader wants to see which alternative the given value collided with.

Negated expectations

expect(...).not.to.be(...) failures don't render a diff: when the comparison was supposed to fail and didn't, both values match exactly, so a diff would be empty. The standard Expected: / not to be: lines are sufficient. The exception is junction expectations under negation (see Junction diffs above).

Module surface

The diff machinery lives in BDD::Behave::Diff. The exported functions are:

  • diff-shape($value --> Str): 'Str', 'Array', 'Hash', 'Set', 'Bag', 'Mix', 'Scalar', or 'Undef'.

  • diffable($given, $expected --> Bool): True when both values share a structural shape worth diffing or $expected is a Junction.

  • render-diff($given, $expected, Bool :$negated --> Str): produces the colorized diff string. Always returns a single string (multi-line for structural and junction diffs). :negated only affects junction summaries.

  • pretty-lines($value, :$indent --> List): exposes the underlying pretty-printer for advanced use.

  • is-junction($value --> Bool): True for any Junction (uses a typed multi to avoid autothreading).

  • junction-kind(Junction:D --> Str): 'any', 'all', 'one', or 'none'.

  • junction-eigenstates(Junction:D --> List): the alternatives the junction was built from.

You normally don't need to call these directly. Failure output uses them automatically.

BDD::Behave v0.9.4

Behavior driven development framework

Authors

  • Greg Donald

License

Artistic-2.0

Dependencies

Provides

  • BDD::Behave
  • BDD::Behave::Benchmark
  • BDD::Behave::Benchmark::Baseline
  • BDD::Behave::Benchmark::Format
  • BDD::Behave::Bisect
  • BDD::Behave::Colors
  • BDD::Behave::Configuration
  • BDD::Behave::Coverage
  • BDD::Behave::DSL
  • BDD::Behave::Diff
  • BDD::Behave::DocExtractor
  • BDD::Behave::DryRun
  • BDD::Behave::Expectation
  • BDD::Behave::Failure
  • BDD::Behave::FailureStore
  • BDD::Behave::Failures
  • BDD::Behave::Files
  • BDD::Behave::Formatter
  • BDD::Behave::Formatter::Documentation
  • BDD::Behave::Formatter::HTML
  • BDD::Behave::Formatter::JSON
  • BDD::Behave::Formatter::JUnit
  • BDD::Behave::Formatter::JsonEvents
  • BDD::Behave::Formatter::Progress
  • BDD::Behave::Formatter::Registry
  • BDD::Behave::Formatter::TAP
  • BDD::Behave::Formatter::Tree
  • BDD::Behave::LetRuntime
  • BDD::Behave::Matcher
  • BDD::Behave::Matcher::Async
  • BDD::Behave::Matcher::Boolean
  • BDD::Behave::Matcher::Change
  • BDD::Behave::Matcher::Collection
  • BDD::Behave::Matcher::Core
  • BDD::Behave::Matcher::Custom
  • BDD::Behave::Matcher::Exception
  • BDD::Behave::Matcher::Numeric
  • BDD::Behave::Matcher::String
  • BDD::Behave::Matcher::Type
  • BDD::Behave::Mock::Allow
  • BDD::Behave::Mock::ArgMatcher
  • BDD::Behave::Mock::Double
  • BDD::Behave::Mock::HaveReceived
  • BDD::Behave::Mock::Spy
  • BDD::Behave::Mock::Stub
  • BDD::Behave::Parallel
  • BDD::Behave::Parallel::Distribution
  • BDD::Behave::Parallel::EventStream
  • BDD::Behave::Parallel::Manifest
  • BDD::Behave::Parallel::Queue
  • BDD::Behave::Parallel::WorkerPool
  • BDD::Behave::Runner
  • BDD::Behave::SharedContexts
  • BDD::Behave::SharedExamples
  • BDD::Behave::Slang
  • BDD::Behave::SpecLoader
  • BDD::Behave::SpecRegistry
  • BDD::Behave::SpecTree
  • BDD::Behave::SpecTree::Core
  • BDD::Behave::SpecTree::Example
  • BDD::Behave::SpecTree::ExampleGroup
  • BDD::Behave::SpecTree::Suite
  • BDD::Behave::Time
  • BDD::Behave::TypeName
  • BDD::Behave::Version
  • BDD::Behave::Watch
  • BDD::Behave::Watch::Session
  • BDD::Behave::Watch::SmartSelector
  • BDD::Behave::Watch::UI
  • BDD::Behave::Watch::Watcher
  • BDD::Behave::Worker

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.