Module: Hecks::Behaviors

Defined in:
lib/hecks/behaviors/ir.rb,
lib/hecks/behaviors/dsl.rb,
lib/hecks/behaviors/rspec.rb,
lib/hecks/behaviors/runner.rb,
lib/hecks/behaviors/expectations.rb

Defined Under Namespace

Modules: Expectations, RSpec Classes: BehaviorsBuilder, BehaviorsSuite, FileResult, LoadOutsideRunner, Malformed, ParseResult, SweepResult, TestCase, TestCaseBuilder, TestSetup

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.last_suiteObject

The suite the most recent Hecks.behaviors call built — read once, right after Kernel.load, by run below, which resets it to nil before every load so a file that loads without calling Hecks.behaviors at all is never confused for a stale previous suite (a real bug in a prior port of this idea: compared only against nil, so after the first successful file in a sweep it stayed non-nil forever).



31
32
33
# File 'lib/hecks/behaviors/runner.rb', line 31

def last_suite
  @last_suite
end

.loading_pathObject

The .behaviors file currently being Kernel.loaded, if any — bound only for the duration of that load (run's own ensure), never left set. Hecks.behaviors (lib/hecks/behaviors.rb) reads this to resolve its own loads line relative to the right file, and to refuse a .behaviors file loaded any other way.



22
23
24
# File 'lib/hecks/behaviors/runner.rb', line 22

def loading_path
  @loading_path
end

Class Method Details

.parse(path) ⇒ Object

Kernel.loads one .behaviors file and returns its suite, with NO test actually executed yet — the cheap half, split out so a caller that only needs to know what tests exist (the rspec shim, naming its its at collection time) doesn't pay for running them until it actually wants to. Behaviors.loading_path is bound only for the duration of the load, and last_suite is reset to nil BEFORE it — a file that loads without ever calling Hecks.behaviors is unambiguously a parse error, never a stale suite from whatever loaded before it in a sweep (a real bug in a prior port of this idea: compared only against nil, so after the first successful file in a sweep it stayed non-nil forever).



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/hecks/behaviors/runner.rb', line 44

def parse(path)
  path = File.expand_path(path)
  previous_path = loading_path
  self.loading_path = path
  self.last_suite = nil

  begin
    Kernel.load(path)
  rescue StandardError, ScriptError => e
    return ParseResult.new(path: path, suite: nil, parse_error: "#{e.class}: #{e.message}")
  ensure
    self.loading_path = previous_path
  end

  suite = last_suite
  return ParseResult.new(path: path, suite: nil, parse_error: "file loaded but called no Hecks.behaviors") unless suite

  ParseResult.new(path: path, suite: suite, parse_error: nil)
end

.run(path) ⇒ Object

One .behaviors file → FileResult, every test actually run.



65
66
67
68
69
70
71
# File 'lib/hecks/behaviors/runner.rb', line 65

def run(path)
  parsed = parse(path)
  return FileResult.new(path: parsed.path, parse_error: parsed.parse_error, runs: []) if parsed.parse_error

  runs = parsed.suite.tests.map { |test| Expectations.run_one(test, parsed.suite) }
  FileResult.new(path: parsed.path, parse_error: nil, runs: runs)
end

.run_all(dir) ⇒ Object

Sweeps every .behaviors file under dir. Reports the file count it actually found — a sweep that goes green without saying how much it looked at is indistinguishable from one that found nothing to look at.



77
78
79
80
81
# File 'lib/hecks/behaviors/runner.rb', line 77

def run_all(dir)
  files = Dir.glob(File.join(dir, "**", "*.behaviors"))
  results = files.map { |path| run(path) }
  SweepResult.new(root: dir, files_swept: files.size, files: results, summary: summarize(results))
end

.summarize(results) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
# File 'lib/hecks/behaviors/runner.rb', line 83

def summarize(results)
  runs = results.flat_map(&:runs)
  {
    files:        results.size,
    parse_errors: results.count(&:parse_error),
    total:        runs.size,
    passed:       runs.count { |r| r.status == :pass },
    failed:       runs.count { |r| r.status == :fail },
    errored:      runs.count { |r| r.status == :error }
  }
end