Fixrb

fix-command

The fix command: a process per specification file, and the count of those met.

The fix command runs each specification file of fix in a process of its own, lets their results through, and tells how many files were met. A file is met when its process exits with 0, which is what exit(Fix[:Name].test { … }) gives at the end of a file: the status is the one thing a subject cannot forge, so the command reads nothing else.

Version
1.0.0
Ruby
3.3 or later, with fork
Dependencies
fix
License
MIT

Install

Add gem "fix-command" to your Gemfile, or run gem install fix-command. It brings fix with it.

Usage

Without an argument, fix runs the *_fix.rb files of the fix directory, at any depth: fix/ is to Fix what test/ is to minitest. With arguments, it runs the files given, whatever their names, and the *_fix.rb files of the directories given, in the order of the arguments, those of a directory in the order of their names. Two such files:

require "fix"

Fix :Account do
  on :balance do
    it MUST eq 100
    it SHOULD eq 200
  end
end

Account = Struct.new(:balance)

exit(Fix[:Account].test { Account.new(100) })
require "fix"

Fix :Duck do
  on :quack do
    it MUST eq "Quack!"
  end

  on :swim do
    it MAY eq "Splash!"
  end
end

class Duck
  def quack = "Quack!"
end

exit(Fix[:Duck].test { Duck.new })

Each runs in a new process, with the Ruby that runs fix, and writes where fix writes; the count comes last:

fix examples/fix-command
examples/fix-command/account_fix.rb:5: Success: expected 100 to eq 100
examples/fix-command/account_fix.rb:6: Warning: expected 100 to eq 200
examples/fix-command/duck_fix.rb:5: Success: expected "Quack!" to eq "Quack!"
examples/fix-command/duck_fix.rb:9: Info: NoMethodError: undefined method 'swim' for an instance of Duck
2 files met

A file not met, a file that raises when loaded or a process that dies give 2 files, 1 not met: fix/account_fix.rb and the status 1. The processes inherit the environment of the command: bundle exec fix gives every file the gems of the Gemfile, and RUBYOPT=-Ilib fix adds lib to their load path.

Random order

The order of the files cannot change a result, as far as the process goes: each file is a process, and each context a child of it. What a subject does outside the process can depend on it, though, a database or a file that one specification leaves changed for the next. --random runs the files in a random order, and writes first the command that runs them in the same order again, --random=SEED:

fix --random examples/fix-command
fix --random=2 examples/fix-command
examples/fix-command/duck_fix.rb:5: Success: expected "Quack!" to eq "Quack!"
examples/fix-command/duck_fix.rb:9: Info: NoMethodError: undefined method 'swim' for an instance of Duck
examples/fix-command/account_fix.rb:5: Success: expected 100 to eq 100
examples/fix-command/account_fix.rb:6: Warning: expected 100 to eq 200
2 files met

Status

0 when every file was met, 1 when one was not, 2 for a usage error, written on the standard error with the usage: an unknown option, a path that does not exist, or no file to run. --help writes the usage, --version the version. The command reads nothing in the results, so there is no count of expectations, no colour and no letter per expectation; it has no timeout, and runs the files one at a time.

Documentation