class Mutest::Isolation::Fork

Isolation via the fork(2) systemcall.

We do inject so many globals and common patterns to make this unit specifiable without mocking the globals and more important: Not having mutations that bypass mocks into a real world side effect.

Public Instance Methods

call(&block) click to toggle source

Call block in isolation

@return [Object]

returns block execution result

@raise [Error]

if block terminates abnormal
# File lib/mutest/isolation/fork.rb, line 21
def call(&block)
  io.pipe(binmode: true) do |pipes|
    parent(*pipes, &block)
  end
rescue StandardError => exception
  raise Error, exception
end
child(reader, writer, &block) click to toggle source

Handle child process

@param [IO] reader @param [IO] writer

@return [undefined]

# File lib/mutest/isolation/fork.rb, line 53
def child(reader, writer, &block)
  reader.close
  writer.binmode
  writer.syswrite(marshal.dump(result(&block)))
  writer.close
end
parent(reader, writer, &block) click to toggle source

Handle parent process

@param [IO] reader @param [IO] writer

@return [undefined]

# File lib/mutest/isolation/fork.rb, line 35
def parent(reader, writer, &block)
  pid =
    process.fork do
      child(reader, writer, &block)
    end

  writer.close
  marshal.load(reader)
ensure
  process.waitpid(pid) if pid
end
result() { || ... } click to toggle source

The block result computed under silencing

@return [Object]

# File lib/mutest/isolation/fork.rb, line 63
def result
  devnull.call do |null|
    stderr.reopen(null)
    stdout.reopen(null)
    yield
  end
end