Sha256: c410fd40924153ab0568d40d1ab6f49a7e71c6882a4478b03f247fe8845a189d

Contents?: true

Size: 1.96 KB

Versions: 1

Compression:

Stored size: 1.96 KB

Contents

module Contracts
  class Testable
    # Given an array-of-arrays of arguments,
    # gives you the product of those arguments so that
    # each possible combination is tried.
    # Example: <tt>[[1, 2], [3, 4]]</tt> would give you:
    #
    #   [[1, 3], [1, 4], [2, 3], [2, 4]]
    def self.product(arrays)
      arrays.inject do |acc, x|
        acc.product(x)
      end.flatten(arrays.size - 2)
    end

    # Given a contract, tells if you it's testable
    def self.testable?(contract)
      if contract.respond_to?(:testable?)
        contract.testable?
      else
        contract.respond_to?(:new) && contract.method(:new).arity == 0
      end
    end

    # Given a contract, returns the test data associated with that contract
    def self.test_data(contract)
      if contract.respond_to?(:testable?)
        contract.test_data
      else
        contract.new
      end
    end

    # TODO: Should work on whatever class it was invoked on, no?
    def self.check_all
      o = Object.new
      Object.decorated_methods.each do |name, _contracts|
        check(o.method(name))
      end
    end

    def self.check(meth)
      contracts = meth.owner.decorated_methods[meth.name.to_sym][0].contracts
      arg_contracts = contracts[0, contracts.size - 1]
      return_val = contracts[-1]
      checkable = arg_contracts.all? do |arg_contract|
        Testable.testable?(arg_contract)
      end

      if checkable
        print "Checking #{meth.name}..."
        _test_data = arg_contracts.map do |arg_contract|
          data = Testable.test_data(arg_contract)
          data.is_a?(Array) ? data : [data]
        end
        test_data = Testable.product _test_data
        test_data.each do |args|
          if args.is_a? Hash
            # because *hash destroys the hash
            res = meth.call(args)
          else
            res = meth.call(*args)
          end
          Contract.valid?(res, return_val)
        end
        puts "#{test_data.size} tests run."
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
contracts-0.8 lib/contracts/testable.rb