lib/on/test_helper.rb

Summary

Maintainability
A
0 mins
Test Coverage
class On
  # Helper for testing On callbacks.
  #
  # == Example
  #
  #   require 'minitest/autorun'
  #   require 'on'
  #   require 'on/test_helper'
  #
  #   class SomeTest < MiniTest::Spec
  #     include On::TestHelper
  #
  #     let(:recorder) { On::TestHelper::Recorder.new }
  #
  #     it "records everything" do
  #       on = On.new(:success, :failure, &recorder)
  #       on.call :success, :some, :args
  #       assert_callback recorder, :success, :some, :args
  #     end
  #
  #     it "calls nothing" do
  #       on = On.new(:success, :failure, &recorder)
  #       # nothing called
  #       refute_callbacks recorder
  #     end
  #
  #     it "records everything manually" do
  #       on = On.new(:success, :failure) do |result|
  #         recorder.record_block
  #         recorder.record_callback(result, :success, :failure)
  #       end
  #       on.call :success, :some, :args
  #       assert_callback recorder, :success, :some, :args
  #     end
  #
  #     it "checks record args in a block" do
  #       on = On.new(:success, :failure) do |result|
  #         recorder.record_block
  #         recorder.record_callback(result, :success, :failure)
  #       end
  #       on.call :success, :some, :args
  #       assert_callback recorder, :success do |some, args|
  #         assert_equal :some, some
  #         assert_equal :args, args
  #       end
  #     end
  #   end
  module TestHelper
    # Asserts that a certain callbacks has been recorded by +recorder+.
    #
    # == Example
    #
    #   assert_callback recorder, :success, "some", "args"
    #
    def assert_callback(recorder, name, *args)
      raise ArgumentError, "Provide args or block but not both" if block_given? && !args.empty?

      callback = recorder.last_record
      assertion_message = proc { "Callback was #{callback}" }
      assert callback, "No callbacks found"
      assert_equal name, callback.name, assertion_message
      if block_given?
        yield *callback.args
      else
        assert_equal args, callback.args, assertion_message
      end
    end

    # Asserts that *no* callbacks has been recorder by +recorder+.
    def refute_callbacks(recorder)
      assert recorder.empty?, "Something has been recorded #{recorder.inspect}"
    end

    # Record callbacks.
    class Recorder
      Callback = Struct.new(:name, :args)

      def initialize
        @block      = false
        @callbacks  = []
      end

      def block_called?
        @block
      end

      def empty?
        @callbacks.empty?
      end

      # Pops the last recorded recorded.
      def last_record
        @callbacks.pop
      end

      # Records block and all defined callbacks.
      def record_all
        proc do |on|
          record_block
          record_callback(on, *on.callbacks)
        end
      end

      # Records a block.
      #
      #   recorder = Recorder.new
      #   On.new(:success) do |callback|
      #     recorder.record_block
      #     callback.on :success do
      #       # assert...
      #     end
      #   end
      #
      #   assert recorder.block_called?
      def record_block
        @block = true
      end

      # Records a single callback.
      def record_callback(on, *names)
        names.each do |name|
          on.on name do |*args|
            callback_recorded(name, args)
          end
        end
      end

      def callback_recorded(name, args=[])
        callback = Callback === name ? name : Callback.new(name, args)
        @callbacks << callback
      end

      # Short-hand for &+recorder.record_all+.
      def to_proc
        record_all
      end
    end
  end
end