lib/sus/context.rb
# frozen_string_literal: true # Released under the MIT License. # Copyright, 2021-2024, by Samuel Williams. require_relative "assertions" require_relative "identity" module Sus module Context attr_accessor :identity attr_accessor :description attr_accessor :children def self.extended(base) base.children = Hash.new end unless respond_to?(:set_temporary_name) def set_temporary_name(name) # No-op. end def to_s (self.description || self.name).to_s end def inspect if description = self.description "\#<#{self.name || "Context"} #{self.description}>" else self.name end end end def add(child) @children[child.identity] = child end def empty? @children.nil? || @children.empty? end def leaf? false end def print(output) output.write("context ", :context, self.description, :reset) end def full_name output = Output::Buffered.new print(output) return output.string end 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) self.children.each do |identity, child| if child.leaf? yield child else child.each(&block) end end end # Include an around method to the context class, that invokes the given block before running the test. # # Before hooks are usually invoked in the order they are defined, i.e. the first defined hook is invoked first. # # @parameter hook [Proc] The block to execute before each test. def before(&hook) wrapper = Module.new wrapper.define_method(:before) do super() instance_exec(&hook) end self.include(wrapper) end # Include an around method to the context class, that invokes the given block after running the test. # # After hooks are usually invoked in the reverse order they are defined, i.e. the last defined hook is invoked first. # # @parameter hook [Proc] The block to execute after each test. An `error` argument is passed if the test failed with an exception. 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 # 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. # # @paremeter block [Proc] The block to execute around each test. def around(&block) wrapper = Module.new wrapper.define_method(:around, &block) self.include(wrapper) end end end