Module: Shifty::Testing

Defined in:
lib/shifty/testing.rb

Overview

Test harness: runs a worker through the framework so unit tests exercise the same handoff policy the production pipeline will. Deliberately not loaded by require "shifty" — opt in with require "shifty/testing".

Class Method Summary collapse

Class Method Details

.mutates_input?(worker, input) ⇒ Boolean

The mutation detector (§6.4): hands the task a private mutable deep copy and reports whether the task changed it — surfacing mutation even when the current policy permits or hides it.

Returns:

  • (Boolean)


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/shifty/testing.rb', line 35

def mutates_input?(worker, input)
  copy = begin
    Marshal.load(Marshal.dump(input))
  rescue TypeError => e
    raise Error, "Shifty::Testing.mutates_input? needs a deep-copyable " \
      "(Marshal-dumpable) input, but got an instance of #{input.class} " \
      "(#{e.message})."
  end
  baseline = Marshal.dump(copy)
  harness(worker, :shared) do |subject|
    subject.supply = source_for([copy])
    subject.shift
  end
  Marshal.dump(copy) != baseline
end

.run(worker, inputs:, policy: nil, max_shifts: 10_000) ⇒ Object

Feeds the inputs to the worker via a source and collects its outputs until the end-of-stream sentinel (nil). The worker's declared/effective policy governs each handoff, exactly as in production; pass policy: to override it for policy-matrix tests.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/shifty/testing.rb', line 14

def run(worker, inputs:, policy: nil, max_shifts: 10_000)
  harness(worker, policy) do |subject|
    subject.supply = source_for(inputs)
    outputs = []
    shifts = 0
    until (value = subject.shift).nil?
      outputs << value
      if (shifts += 1) > max_shifts
        raise Error, "Shifty::Testing.run exceeded #{max_shifts} shifts " \
          "without seeing the nil end-of-stream sentinel. The worker's " \
          "task probably converts nil into a non-nil value; let nil " \
          "pass through (e.g. `value && ...`), or raise max_shifts:."
      end
    end
    outputs
  end
end