Module: Oselvar::Var::Runner

Defined in:
lib/oselvar/var/runner.rb,
lib/oselvar/var/runner/cli.rb,
lib/oselvar/var/runner/run.rb,
lib/oselvar/var/runner/steps.rb,
lib/oselvar/var/runner/render.rb,
lib/oselvar/var/runner/discovery.rb,
lib/oselvar/var/runner/baseline_store.rb

Overview

The imperative shell: discovery, step loading, planning, failure rendering, and the filesystem drift baseline store. Depends on the facade and config; never on a test framework. Port of var-runner.

Defined Under Namespace

Modules: CLI Classes: FileBaselineStore, LoadedSteps, RecordingReporter

Constant Summary collapse

VERSION =
'0.3.2'

Class Method Summary collapse

Class Method Details

.create_file_baseline_store(root) ⇒ Object



25
26
27
# File 'lib/oselvar/var/runner/baseline_store.rb', line 25

def create_file_baseline_store(root)
  FileBaselineStore.new(root)
end

.examples_with_runs(execution_plan, create_context, reporter) ⇒ Object

Pair each PlannedExample with its lazy run closure, in plan order.



28
29
30
31
32
# File 'lib/oselvar/var/runner/run.rb', line 28

def examples_with_runs(execution_plan, create_context, reporter)
  reporter_cb = ->(d) { reporter.diagnostic(d) }
  queue = Core::Execute.collect_examples(execution_plan, create_context: create_context, reporter: reporter_cb)
  execution_plan.examples.zip(queue).map { |example, queued| [example, queued.run] }
end

.find_specs(include, exclude, root) ⇒ Object

Existing files under root matching any include glob, minus excludes; sorted.



63
64
65
66
67
68
69
70
# File 'lib/oselvar/var/runner/discovery.rb', line 63

def find_specs(include, exclude, root)
  out = []
  include.each do |g|
    out.concat(Dir.glob(g, base: root).map { |rel| File.join(root, rel) })
  end
  out = out.select { |p| File.file?(p) }.uniq
  out.reject { |p| matches_any?(rel_posix(p, root), exclude) }.sort
end

.glob_to_regex(pattern) ⇒ Object

Translate a glob with **, *, ? to an anchored regex (PEP 428 / pathlib full_match semantics), matching the other ports' hand-rolled compiler rather than Ruby's Dir glob. Port of _glob_to_regex.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/oselvar/var/runner/discovery.rb', line 13

def glob_to_regex(pattern)
  result = +''
  i = 0
  n = pattern.length
  while i < n
    c = pattern[i]
    if c == '/' && pattern[i, 4] == '/**/'
      result << '/(?:.+/)?'
      i += 4
    elsif c == '/' && pattern[i, 3] == '/**' && i + 3 == n
      result << '(?:/.*)?'
      i += 3
    elsif c == '*' && pattern[i, 3] == '**/'
      result << '(?:.*/)?'
      i += 3
    elsif c == '*' && pattern[i, 2] == '**'
      result << '.*'
      i += 2
    elsif c == '*'
      result << '[^/]*'
      i += 1
    elsif c == '?'
      result << '[^/]'
      i += 1
    else
      result << Regexp.escape(c)
      i += 1
    end
  end
  /\A#{result}\z/
end

.load_steps(step_globs, root) ⇒ Object

Reset the accumulator, load (execute) every step file matching step_globs under root, and build the registry + context factory.



16
17
18
19
20
21
22
23
24
# File 'lib/oselvar/var/runner/steps.rb', line 16

def load_steps(step_globs, root)
  RegistryGlue.reset_builder
  files = []
  step_globs.each do |g|
    files.concat(Dir.glob(g, base: root).map { |rel| File.join(root, rel) })
  end
  files.select { |p| File.file?(p) }.uniq.sort.each { |path| load path }
  LoadedSteps.new(registry: RegistryGlue.build_registry, create_context: RegistryGlue.context_factory)
end

.match_spec?(path, include, exclude, root) ⇒ Boolean

True iff path matches an include glob and no exclude glob.

Returns:

  • (Boolean)


57
58
59
60
# File 'lib/oselvar/var/runner/discovery.rb', line 57

def match_spec?(path, include, exclude, root)
  rel = rel_posix(path, root)
  matches_any?(rel, include) && !matches_any?(rel, exclude)
end

.matches_any?(rel, globs) ⇒ Boolean

Returns:

  • (Boolean)


52
53
54
# File 'lib/oselvar/var/runner/discovery.rb', line 52

def matches_any?(rel, globs)
  globs.any? { |g| glob_to_regex(g).match?(rel) }
end

.plan_spec(path, source, registry) ⇒ Object



23
24
25
# File 'lib/oselvar/var/runner/run.rb', line 23

def plan_spec(path, source, registry)
  Core::Plan.plan(Core::Parse.parse(path, source), registry)
end

.rel_posix(path, root) ⇒ Object

Relative POSIX path of path within root, without dereferencing symlinks; yields a ../ prefix when path is outside root.



47
48
49
50
# File 'lib/oselvar/var/runner/discovery.rb', line 47

def rel_posix(path, root)
  Pathname.new(File.expand_path(path))
          .relative_path_from(Pathname.new(File.expand_path(root))).to_s
end

.render_failure(error, _source, path) ⇒ Object

Render a step failure as a human-readable, markdown-anchored string, dispatching on the concrete error type. Port of render.py.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/oselvar/var/runner/render.rb', line 12

def render_failure(error, _source, path)
  case error
  when Core::CellMismatchError
    lines = ["Cell mismatch in #{path}:"]
    failing = error.cells.reject(&:ok)
    lines << '  (no failing cells)' if failing.empty?
    failing.each do |cell|
      lines << "  line #{cell.span.start_line} | column '#{cell.column}' — " \
               "expected: #{cell.expected.inspect}, actual: #{cell.actual.inspect}"
    end
    lines.join("\n")
  when Core::DocStringMismatchError
    diff = error.diff
    "Doc string mismatch at line #{diff.span.start_line}:\n  " \
      "expected: #{diff.expected.inspect}\n  actual:   #{diff.actual.inspect}"
  when Core::ReturnShapeError
    error.message
  else
    "#{error.class}: #{error.message}"
  end
end