SusSourceSusContext

module Context

Represents a test context that can contain nested tests and other contexts.

Definitions

attr_accessor :identity

Signature

attribute Identity, nil

The identity of this context.

attr_accessor :description

Signature

attribute String, nil

The description of this context.

attr_accessor :children

Signature

attribute Hash

The child contexts and tests.

def self.extended(base)

Called when this module is extended.

Signature

parameter base Class

The class being extended.

Implementation

def self.extended(base)
	base.children = Hash.new
end

def add(child)

Add a child context or test to this context.

Signature

parameter child Object

The child to add.

Implementation

def add(child)
	@children[child.identity] = child
end

def empty?

Signature

returns Boolean

Whether this context has no children.

Implementation

def empty?
	@children.nil? || @children.empty?
end

def leaf?

Signature

returns Boolean

Always returns false, as contexts are not leaf nodes.

Implementation

def leaf?
	false
end

def print(output)

Print a representation of this context.

Signature

parameter output Output

The output target.

Implementation

def print(output)
	output.write("context ", :context, self.description, :reset)
end

def full_name

Signature

returns String

The full name of this context.

Implementation

def full_name
	output = Output::Buffered.new
	print(output)
	return output.string
end

def call(assertions)

Execute all child contexts and tests.

Signature

parameter assertions Assertions

The assertions instance to use.

Implementation

def call(assertions)
	return if self.empty?
	
	assertions.nested(self) do |assertions|
		self.children.each do |identity, child|
			child.call(assertions)
		end
	end
end

def each(&block)

Iterate over all leaf nodes (test cases) in this context.

Signature

yields {|test| ...}

Each test case.

Implementation

def each(&block)
	self.children.each do |identity, child|
		if child.leaf?
			yield child
		else
			child.each(&block)
		end
	end
end

def before(&hook)

Include a before hook to the context class, that invokes the given block before running each test.

Before hooks are usually invoked in the order they are defined, i.e. the first defined hook is invoked first.

Signature

yields {...}

The block to execute before each test.

Implementation

def before(&hook)
	wrapper = Module.new
	
	wrapper.define_method(:before) do
		super()
		
		instance_exec(&hook)
	end
	
	self.include(wrapper)
end

def after(&hook)

Include an after hook to the context class, that invokes the given block after running each test.

After hooks are usually invoked in the reverse order they are defined, i.e. the last defined hook is invoked first.

Signature

yields {|error| ...}

The block to execute after each test. An error argument is passed if the test failed with an exception.

Implementation

def after(&hook)
	wrapper = Module.new
	
	wrapper.define_method(:after) do |error|
		instance_exec(error, &hook)
	rescue => error
		raise
	ensure
		super(error)
	end
	
	self.include(wrapper)
end

def around(&block)

Add an around hook to the context class.

Around hooks are called in the reverse order they are defined.

The top level around implementation invokes before and after hooks.

Signature

yields {|&block| ...}

The block to execute around each test.

Implementation

def around(&block)
	wrapper = Module.new
	
	wrapper.define_method(:around, &block)
	
	self.include(wrapper)
end

def describe(subject, **options, &block)

Define a new test group describing a subject.

Signature

parameter subject Object

The subject to describe (class, module, or feature).

parameter options Hash

Additional options.

yields {...}

Optional block containing nested tests.

Implementation

def describe(subject, **options, &block)
	add Describe.build(self, subject, **options, &block)
end

def file(path)

Load a test file as a child context.

Signature

parameter path String

The path to the test file.

Implementation

def file(path)
	add File.build(self, path)
end

def include_context(shared, *arguments, **options)

Include a shared context into the current context, along with any arguments or options.

Signature

parameter shared Sus::Shared

The shared context to include.

parameter arguments Array

The arguments to pass to the shared context.

parameter options Hash

The options to pass to the shared context.

Implementation

def include_context(shared, *arguments, **options)
	self.class_exec(*arguments, **options, &shared.block)
end

def it(...)

Define a new test case.

Signature

parameter description String

The description of the test.

parameter options Hash

Additional options.

yields {...}

The test code.

Implementation

def it(...)
	add It.build(self, ...)
end

def it_behaves_like(shared, *arguments, **options, &block)

Define a test context that behaves like a shared context.

Signature

parameter shared Shared

The shared context to use.

parameter arguments Array

Optional arguments to pass to the shared context.

parameter options Hash

Additional options.

yields {...}

Optional block to execute before the shared context.

Implementation

def it_behaves_like(shared, *arguments, **options, &block)
	add ItBehavesLike.build(self, shared, arguments, **options, &block)
end

def let(name, &block)

Define a lazy variable that is evaluated when first accessed.

Signature

parameter name Symbol

The name of the variable.

yields {...}

The block that computes the variable value.

Implementation

def let(name, &block)
	instance_variable = :"@#{name}"
	
	self.define_method(name) do
		if self.instance_variable_defined?(instance_variable)
			return self.instance_variable_get(instance_variable)
		else
			self.instance_variable_set(instance_variable, self.instance_exec(&block))
		end
	end
end

def with(subject = nil, unique: true, **variables, &block)

Define a new test context with specific conditions or variables.

Signature

parameter subject String | Nil

Optional subject description. If nil, uses variables.inspect.

parameter unique Boolean

Whether the identity should be unique.

parameter variables Hash

Variables to make available in the context.

yields {...}

Optional block containing nested tests.

Implementation

def with(subject = nil, unique: true, **variables, &block)
	subject ||= variables.inspect
	
	add With.build(self, subject, variables, unique: unique, &block)
end