Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: opal/opal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: f2226a670a3e^
Choose a base ref
...
head repository: opal/opal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: af1ca0ce8941
Choose a head ref

Commits on Jan 24, 2015

  1. Add a cruby checkout

    elia committed Jan 24, 2015
    Copy the full SHA
    f2226a6 View commit details
  2. Add opal-minitest to dev deps

    elia committed Jan 24, 2015
    Copy the full SHA
    c63eff3 View commit details
  3. Add test/unit from CRuby

    elia committed Jan 24, 2015
    Copy the full SHA
    4b055cb View commit details
  4. Add minitest/unit

    elia committed Jan 24, 2015
    Copy the full SHA
    1bf7d06 View commit details
  5. Copy the full SHA
    581f334 View commit details
  6. Copy the full SHA
    a1f86a1 View commit details
  7. [remove] test/unit fixes

    elia committed Jan 24, 2015
    Copy the full SHA
    de903fa View commit details
  8. Add a WIP cruby_tests task

    elia committed Jan 24, 2015
    Copy the full SHA
    eebdc11 View commit details
  9. Embed minitest

    elia committed Jan 24, 2015
    Copy the full SHA
    67d5084 View commit details
  10. Copy the full SHA
    86c4ce8 View commit details
  11. [remove] test/unit fixes

    elia committed Jan 24, 2015
    Copy the full SHA
    50dde90 View commit details
  12. Copy the full SHA
    1eb2ecc View commit details
  13. Typo

    elia committed Jan 24, 2015
    Copy the full SHA
    823fa42 View commit details
  14. Copy the full SHA
    98afd17 View commit details
  15. Copy the full SHA
    610957e View commit details
  16. Copy the full SHA
    9ac8e00 View commit details
  17. Copy the full SHA
    fe62a7e View commit details
  18. Just use the simplest possible Test::Unit impl.

    Which is exactly:
    
        require 'minitest/autorun'
        Test::Unit::TestCase = Minitest::Test
    elia committed Jan 24, 2015
    Copy the full SHA
    f895359 View commit details
  19. Copy the full SHA
    e4292e7 View commit details
  20. Add a simple test case for cruby_test task

    More to come.
    elia committed Jan 24, 2015
    Copy the full SHA
    21b2c04 View commit details
  21. Copy the full SHA
    183c158 View commit details
  22. Split Rakefile

    elia committed Jan 24, 2015
    Copy the full SHA
    af1ca0c View commit details
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -25,3 +25,7 @@
[submodule "spec/stdlib/rubysl-date"]
path = spec/stdlib/rubysl-date
url = https://github.com/rubysl/rubysl-date
[submodule "test/cruby"]
path = test/cruby
url = https://github.com/ruby/ruby.git
branch = ruby_2_2
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
@@ -10,4 +10,4 @@ import 'tasks/documenting.rake'
import 'tasks/testing.rake'
import 'tasks/building.rake'

task :default => [:rspec, :mspec_node]
task :default => [:rspec, :mspec_node, :cruby_tests]
1 change: 1 addition & 0 deletions opal.gemspec
Original file line number Diff line number Diff line change
@@ -33,4 +33,5 @@ Gem::Specification.new do |s|
s.add_development_dependency 'bundler', '~> 1.5'
s.add_development_dependency 'yard', '~> 0.8.7'
s.add_development_dependency 'rack-test'
s.add_development_dependency 'opal-minitest'
end
4 changes: 3 additions & 1 deletion opal/corelib/enumerable.rb
Original file line number Diff line number Diff line change
@@ -1079,7 +1079,9 @@ def slice_before(pattern = undefined, &block)
end

def sort(&block)
raise NotImplementedError
ary = to_a
block = -> a,b {a <=> b} unless block_given?
return `ary.sort(block)`
end

def sort_by(&block)
2 changes: 1 addition & 1 deletion opal/corelib/string.rb
Original file line number Diff line number Diff line change
@@ -71,7 +71,7 @@ def <=>(other)
end

def <<(other)
raise NotImplementedError, 'Mutable String methods are not supported in Opal.'
raise NotImplementedError, '#<< not supported. Mutable String methods are not supported in Opal.'
end

def ==(other)
780 changes: 780 additions & 0 deletions stdlib/minitest.rb

Large diffs are not rendered by default.

662 changes: 662 additions & 0 deletions stdlib/minitest/assertions.rb

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions stdlib/minitest/autorun.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# begin
# require "rubygems"
# gem "minitest"
# rescue Gem::LoadError
# # do nothing
# end

require "minitest"
require "minitest/spec"
require "minitest/mock"

Minitest.autorun
426 changes: 426 additions & 0 deletions stdlib/minitest/benchmark.rb

Large diffs are not rendered by default.

281 changes: 281 additions & 0 deletions stdlib/minitest/expectations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
##
# It's where you hide your "assertions".
#
# Please note, because of the way that expectations are implemented,
# all expectations (eg must_equal) are dependent upon a thread local
# variable +:current_spec+. If your specs rely on mixing threads into
# the specs themselves, you're better off using assertions. For
# example:
#
# it "should still work in threads" do
# my_threaded_thingy do
# (1+1).must_equal 2 # bad
# assert_equal 2, 1+1 # good
# end
# end

module Minitest::Expectations
##
# See Minitest::Assertions#assert_empty.
#
# collection.must_be_empty
#
# :method: must_be_empty

infect_an_assertion :assert_empty, :must_be_empty, :unary

##
# See Minitest::Assertions#assert_equal
#
# a.must_equal b
#
# :method: must_equal

infect_an_assertion :assert_equal, :must_equal

##
# See Minitest::Assertions#assert_in_delta
#
# n.must_be_close_to m [, delta]
#
# :method: must_be_close_to

infect_an_assertion :assert_in_delta, :must_be_close_to

alias :must_be_within_delta :must_be_close_to # :nodoc:

##
# See Minitest::Assertions#assert_in_epsilon
#
# n.must_be_within_epsilon m [, epsilon]
#
# :method: must_be_within_epsilon

infect_an_assertion :assert_in_epsilon, :must_be_within_epsilon

##
# See Minitest::Assertions#assert_includes
#
# collection.must_include obj
#
# :method: must_include

infect_an_assertion :assert_includes, :must_include, :reverse

##
# See Minitest::Assertions#assert_instance_of
#
# obj.must_be_instance_of klass
#
# :method: must_be_instance_of

infect_an_assertion :assert_instance_of, :must_be_instance_of

##
# See Minitest::Assertions#assert_kind_of
#
# obj.must_be_kind_of mod
#
# :method: must_be_kind_of

infect_an_assertion :assert_kind_of, :must_be_kind_of

##
# See Minitest::Assertions#assert_match
#
# a.must_match b
#
# :method: must_match

infect_an_assertion :assert_match, :must_match

##
# See Minitest::Assertions#assert_nil
#
# obj.must_be_nil
#
# :method: must_be_nil

infect_an_assertion :assert_nil, :must_be_nil, :unary

##
# See Minitest::Assertions#assert_operator
#
# n.must_be :<=, 42
#
# This can also do predicates:
#
# str.must_be :empty?
#
# :method: must_be

infect_an_assertion :assert_operator, :must_be, :reverse

##
# See Minitest::Assertions#assert_output
#
# proc { ... }.must_output out_or_nil [, err]
#
# :method: must_output

infect_an_assertion :assert_output, :must_output

##
# See Minitest::Assertions#assert_raises
#
# proc { ... }.must_raise exception
#
# :method: must_raise

infect_an_assertion :assert_raises, :must_raise

##
# See Minitest::Assertions#assert_respond_to
#
# obj.must_respond_to msg
#
# :method: must_respond_to

infect_an_assertion :assert_respond_to, :must_respond_to, :reverse

##
# See Minitest::Assertions#assert_same
#
# a.must_be_same_as b
#
# :method: must_be_same_as

infect_an_assertion :assert_same, :must_be_same_as

##
# See Minitest::Assertions#assert_silent
#
# proc { ... }.must_be_silent
#
# :method: must_be_silent

infect_an_assertion :assert_silent, :must_be_silent

##
# See Minitest::Assertions#assert_throws
#
# proc { ... }.must_throw sym
#
# :method: must_throw

infect_an_assertion :assert_throws, :must_throw

##
# See Minitest::Assertions#refute_empty
#
# collection.wont_be_empty
#
# :method: wont_be_empty

infect_an_assertion :refute_empty, :wont_be_empty, :unary

##
# See Minitest::Assertions#refute_equal
#
# a.wont_equal b
#
# :method: wont_equal

infect_an_assertion :refute_equal, :wont_equal

##
# See Minitest::Assertions#refute_in_delta
#
# n.wont_be_close_to m [, delta]
#
# :method: wont_be_close_to

infect_an_assertion :refute_in_delta, :wont_be_close_to

alias :wont_be_within_delta :wont_be_close_to # :nodoc:

##
# See Minitest::Assertions#refute_in_epsilon
#
# n.wont_be_within_epsilon m [, epsilon]
#
# :method: wont_be_within_epsilon

infect_an_assertion :refute_in_epsilon, :wont_be_within_epsilon

##
# See Minitest::Assertions#refute_includes
#
# collection.wont_include obj
#
# :method: wont_include

infect_an_assertion :refute_includes, :wont_include, :reverse

##
# See Minitest::Assertions#refute_instance_of
#
# obj.wont_be_instance_of klass
#
# :method: wont_be_instance_of

infect_an_assertion :refute_instance_of, :wont_be_instance_of

##
# See Minitest::Assertions#refute_kind_of
#
# obj.wont_be_kind_of mod
#
# :method: wont_be_kind_of

infect_an_assertion :refute_kind_of, :wont_be_kind_of

##
# See Minitest::Assertions#refute_match
#
# a.wont_match b
#
# :method: wont_match

infect_an_assertion :refute_match, :wont_match

##
# See Minitest::Assertions#refute_nil
#
# obj.wont_be_nil
#
# :method: wont_be_nil

infect_an_assertion :refute_nil, :wont_be_nil, :unary

##
# See Minitest::Assertions#refute_operator
#
# n.wont_be :<=, 42
#
# This can also do predicates:
#
# str.wont_be :empty?
#
# :method: wont_be

infect_an_assertion :refute_operator, :wont_be, :reverse

##
# See Minitest::Assertions#refute_respond_to
#
# obj.wont_respond_to msg
#
# :method: wont_respond_to

infect_an_assertion :refute_respond_to, :wont_respond_to, :reverse

##
# See Minitest::Assertions#refute_same
#
# a.wont_be_same_as b
#
# :method: wont_be_same_as

infect_an_assertion :refute_same, :wont_be_same_as
end
11 changes: 11 additions & 0 deletions stdlib/minitest/hell.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require "minitest/parallel"

class Minitest::Test
class << self
alias :old_test_order :test_order # :nodoc:

def test_order # :nodoc:
:parallel
end
end
end
220 changes: 220 additions & 0 deletions stdlib/minitest/mock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
class MockExpectationError < StandardError; end # :nodoc:

module Minitest # :nodoc:

##
# A simple and clean mock object framework.
#
# All mock objects are an instance of Mock

class Mock
alias :__respond_to? :respond_to?

overridden_methods = %w(
===
inspect
object_id
public_send
respond_to_missing?
send
to_s
)

instance_methods.each do |m|
undef_method m unless overridden_methods.include?(m.to_s) || m =~ /^__/
end

overridden_methods.map(&:to_sym).each do |method_id|
define_method method_id do |*args, &b|
if @expected_calls.has_key? method_id then
method_missing(method_id, *args, &b)
else
super(*args, &b)
end
end
end

def initialize # :nodoc:
@expected_calls = Hash.new { |calls, name| calls[name] = [] }
@actual_calls = Hash.new { |calls, name| calls[name] = [] }
end

##
# Expect that method +name+ is called, optionally with +args+ or a
# +blk+, and returns +retval+.
#
# @mock.expect(:meaning_of_life, 42)
# @mock.meaning_of_life # => 42
#
# @mock.expect(:do_something_with, true, [some_obj, true])
# @mock.do_something_with(some_obj, true) # => true
#
# @mock.expect(:do_something_else, true) do |a1, a2|
# a1 == "buggs" && a2 == :bunny
# end
#
# +args+ is compared to the expected args using case equality (ie, the
# '===' operator), allowing for less specific expectations.
#
# @mock.expect(:uses_any_string, true, [String])
# @mock.uses_any_string("foo") # => true
# @mock.verify # => true
#
# @mock.expect(:uses_one_string, true, ["foo"])
# @mock.uses_one_string("bar") # => true
# @mock.verify # => raises MockExpectationError

def expect(name, retval, args=[], &blk)
name = name.to_sym

if block_given?
raise ArgumentError, "args ignored when block given" unless args.empty?
@expected_calls[name] << { :retval => retval, :block => blk }
else
raise ArgumentError, "args must be an array" unless Array === args
@expected_calls[name] << { :retval => retval, :args => args }
end
self
end

def __call name, data # :nodoc:
case data
when Hash then
"#{name}(#{data[:args].inspect[1..-2]}) => #{data[:retval].inspect}"
else
data.map { |d| __call name, d }.join ", "
end
end

##
# Verify that all methods were called as expected. Raises
# +MockExpectationError+ if the mock object was not called as
# expected.

def verify
@expected_calls.each do |name, calls|
calls.each do |expected|
msg1 = "expected #{__call name, expected}"
msg2 = "#{msg1}, got [#{__call name, @actual_calls[name]}]"

raise MockExpectationError, msg2 if
@actual_calls.has_key?(name) and
not @actual_calls[name].include?(expected)

raise MockExpectationError, msg1 unless
@actual_calls.has_key?(name) and
@actual_calls[name].include?(expected)
end
end
true
end

def method_missing(sym, *args, &block) # :nodoc:
unless @expected_calls.has_key?(sym) then
raise NoMethodError, "unmocked method %p, expected one of %p" %
[sym, @expected_calls.keys.sort_by(&:to_s)]
end

index = @actual_calls[sym].length
expected_call = @expected_calls[sym][index]

unless expected_call then
raise MockExpectationError, "No more expects available for %p: %p" %
[sym, args]
end

expected_args, retval, val_block =
expected_call.values_at(:args, :retval, :block)

if val_block then
raise MockExpectationError, "mocked method %p failed block w/ %p" %
[sym, args] unless val_block.call(*args, &block)

# keep "verify" happy
@actual_calls[sym] << expected_call
return retval
end

if expected_args.size != args.size then
raise ArgumentError, "mocked method %p expects %d arguments, got %d" %
[sym, expected_args.size, args.size]
end

fully_matched = expected_args.zip(args).all? { |mod, a|
mod === a or mod == a
}

unless fully_matched then
raise MockExpectationError, "mocked method %p called with unexpected arguments %p" %
[sym, args]
end

@actual_calls[sym] << {
:retval => retval,
:args => expected_args.zip(args).map { |mod, a| mod === a ? mod : a }
}

retval
end

def respond_to?(sym, include_private = false) # :nodoc:
return true if @expected_calls.has_key? sym.to_sym
return __respond_to?(sym, include_private)
end
end
end

class Object # :nodoc:

##
# Add a temporary stubbed method replacing +name+ for the duration
# of the +block+. If +val_or_callable+ responds to #call, then it
# returns the result of calling it, otherwise returns the value
# as-is. If stubbed method yields a block, +block_args+ will be
# passed along. Cleans up the stub at the end of the +block+. The
# method +name+ must exist before stubbing.
#
# def test_stale_eh
# obj_under_test = Something.new
# refute obj_under_test.stale?
#
# Time.stub :now, Time.at(0) do
# assert obj_under_test.stale?
# end
# end
#

def stub name, val_or_callable, *block_args, &block
new_name = "__minitest_stub__#{name}"

metaclass = class << self; self; end

if respond_to? name and not methods.map(&:to_s).include? name.to_s then
metaclass.send :define_method, name do |*args|
super(*args)
end
end

metaclass.send :alias_method, new_name, name

metaclass.send :define_method, name do |*args, &blk|

ret = if val_or_callable.respond_to? :call then
val_or_callable.call(*args)
else
val_or_callable
end

blk.call(*block_args) if blk

ret
end

yield self
ensure
metaclass.send :undef_method, name
metaclass.send :alias_method, name, new_name
metaclass.send :undef_method, new_name
end

end
65 changes: 65 additions & 0 deletions stdlib/minitest/parallel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
module Minitest
module Parallel

##
# The engine used to run multiple tests in parallel.

class Executor

##
# The size of the pool of workers.

attr_reader :size

##
# Create a parallel test executor of with +size+ workers.

def initialize size
@size = size
@queue = Queue.new
# @pool = size.times.map {
# Thread.new(@queue) do |queue|
# Thread.current.abort_on_exception = true
# while job = queue.pop
# klass, method, reporter = job
# result = Minitest.run_one_method klass, method
# reporter.synchronize { reporter.record result }
# end
# end
# }
end

##
# Add a job to the queue

def << work; @queue << work; end

##
# Shuts down the pool of workers by signalling them to quit and
# waiting for them all to finish what they're currently working
# on.

def shutdown
# size.times { @queue << nil }
# @pool.each(&:join)
@queue.each do |job|
klass, method, reporter = job
result = Minitest.run_one_method klass, method
reporter.record result
# reporter.synchronize { reporter.record result }
end
end
end

module Test
def _synchronize; Test.io_lock.synchronize { yield }; end # :nodoc:

module ClassMethods
def run_one_method klass, method_name, reporter # :nodoc:
Minitest.parallel_executor << [klass, method_name, reporter]
end
def test_order; :parallel; end # :nodoc:
end
end
end
end
4 changes: 4 additions & 0 deletions stdlib/minitest/pride.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
require "minitest"

Minitest.load_plugins
Minitest::PrideIO.pride!
142 changes: 142 additions & 0 deletions stdlib/minitest/pride_plugin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
require "minitest"

module Minitest
def self.plugin_pride_options opts, options # :nodoc:
opts.on "-p", "--pride", "Pride. Show your testing pride!" do
PrideIO.pride!
end
end

def self.plugin_pride_init options # :nodoc:
if PrideIO.pride? then
klass = ENV["TERM"] =~ /^xterm|-256color$/ ? PrideLOL : PrideIO
io = klass.new options[:io]

self.reporter.reporters.grep(Minitest::Reporter).each do |rep|
rep.io = io
end
end
end

##
# Show your testing pride!

class PrideIO
##
# Activate the pride plugin. Called from both -p option and minitest/pride

def self.pride!
@pride = true
end

##
# Are we showing our testing pride?

def self.pride?
@pride ||= false
end

# Start an escape sequence
ESC = "\e["

# End the escape sequence
NND = "#{ESC}0m"

# The IO we're going to pipe through.
attr_reader :io

def initialize io # :nodoc:
@io = io
# stolen from /System/Library/Perl/5.10.0/Term/ANSIColor.pm
# also reference http://en.wikipedia.org/wiki/ANSI_escape_code
@colors ||= (31..36).to_a
@size = @colors.size
@index = 0
end

##
# Wrap print to colorize the output.

def print o
case o
when "." then
io.print pride o
when "E", "F" then
io.print "#{ESC}41m#{ESC}37m#{o}#{NND}"
when "S" then
io.print pride o
else
io.print o
end
end

def puts(*o) # :nodoc:
o.map! { |s|
s.to_s.sub(/Finished/) {
@index = 0
'Fabulous run'.split(//).map { |c|
pride(c)
}.join
}
}

io.puts(*o)
end

##
# Color a string.

def pride string
string = "*" if string == "."
c = @colors[@index % @size]
@index += 1
"#{ESC}#{c}m#{string}#{NND}"
end

def method_missing msg, *args # :nodoc:
io.send(msg, *args)
end
end

##
# If you thought the PrideIO was colorful...
#
# (Inspired by lolcat, but with clean math)

class PrideLOL < PrideIO
PI_3 = Math::PI / 3 # :nodoc:

def initialize io # :nodoc:
# walk red, green, and blue around a circle separated by equal thirds.
#
# To visualize, type this into wolfram-alpha:
#
# plot (3*sin(x)+3), (3*sin(x+2*pi/3)+3), (3*sin(x+4*pi/3)+3)

# 6 has wide pretty gradients. 3 == lolcat, about half the width
@colors = (0...(6 * 7)).map { |n|
n *= 1.0 / 6
r = (3 * Math.sin(n ) + 3).to_i
g = (3 * Math.sin(n + 2 * PI_3) + 3).to_i
b = (3 * Math.sin(n + 4 * PI_3) + 3).to_i

# Then we take rgb and encode them in a single number using base 6.
# For some mysterious reason, we add 16... to clear the bottom 4 bits?
# Yes... they're ugly.

36 * r + 6 * g + b + 16
}

super
end

##
# Make the string even more colorful. Damnit.

def pride string
c = @colors[@index % @size]
@index += 1
"#{ESC}38;5;#{c}m#{string}#{NND}"
end
end
end
310 changes: 310 additions & 0 deletions stdlib/minitest/spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,310 @@
require "minitest/test"

class Module # :nodoc:
def infect_an_assertion meth, new_name, dont_flip = false # :nodoc:
# warn "%-22p -> %p %p" % [meth, new_name, dont_flip]
dont_flip = !!dont_flip
self.class_eval do
define_method(new_name) do |*args|
case
when dont_flip
Minitest::Spec.current.send(meth, self, *args)
when Proc === self
Minitest::Spec.current.send(meth, *args, &self)
else
Minitest::Spec.current.send(meth, args.first, self, *args[1..-1])
end
end
end

# <<-EOM
# def #{new_name} *args
# case
# when #{dont_flip} then
# Minitest::Spec.current.#{meth}(self, *args)
# when Proc === self then
# Minitest::Spec.current.#{meth}(*args, &self)
# else
# Minitest::Spec.current.#{meth}(args.first, self, *args[1..-1])
# end
# end
# EOM
end
end

module Kernel # :nodoc:
##
# Describe a series of expectations for a given target +desc+.
#
# Defines a test class subclassing from either Minitest::Spec or
# from the surrounding describe's class. The surrounding class may
# subclass Minitest::Spec manually in order to easily share code:
#
# class MySpec < Minitest::Spec
# # ... shared code ...
# end
#
# class TestStuff < MySpec
# it "does stuff" do
# # shared code available here
# end
# describe "inner stuff" do
# it "still does stuff" do
# # ...and here
# end
# end
# end
#
# For more information on getting started with writing specs, see:
#
# http://www.rubyinside.com/a-minitestspec-tutorial-elegant-spec-style-testing-that-comes-with-ruby-5354.html
#
# For some suggestions on how to improve your specs, try:
#
# http://betterspecs.org
#
# but do note that several items there are debatable or specific to
# rspec.
#
# For more information about expectations, see Minitest::Expectations.

def describe desc, *additional_desc, &block # :doc:
stack = Minitest::Spec.describe_stack
name = [stack.last, desc, *additional_desc].compact.join("::")
sclas = stack.last || if Class === self && is_a?(Minitest::Spec::DSL) then
self
else
Minitest::Spec.spec_type desc, *additional_desc
end

cls = sclas.create name, desc

stack.push cls
cls.class_eval(&block)
stack.pop
cls
end
private :describe
end

##
# Minitest::Spec -- The faster, better, less-magical spec framework!
#
# For a list of expectations, see Minitest::Expectations.

class Minitest::Spec < Minitest::Test

def self.current # :nodoc:
Thread.current[:current_spec]
end

def initialize name # :nodoc:
super
Thread.current[:current_spec] = self
end

##
# Oh look! A Minitest::Spec::DSL module! Eat your heart out DHH.

module DSL
##
# Contains pairs of matchers and Spec classes to be used to
# calculate the superclass of a top-level describe. This allows for
# automatically customizable spec types.
#
# See: register_spec_type and spec_type

TYPES = [[//, Minitest::Spec]]

##
# Register a new type of spec that matches the spec's description.
# This method can take either a Regexp and a spec class or a spec
# class and a block that takes the description and returns true if
# it matches.
#
# Eg:
#
# register_spec_type(/Controller$/, Minitest::Spec::Rails)
#
# or:
#
# register_spec_type(Minitest::Spec::RailsModel) do |desc|
# desc.superclass == ActiveRecord::Base
# end

def register_spec_type(*args, &block)
if block then
matcher, klass = block, args.first
else
matcher, klass = *args
end
TYPES.unshift [matcher, klass]
end

##
# Figure out the spec class to use based on a spec's description. Eg:
#
# spec_type("BlahController") # => Minitest::Spec::Rails

def spec_type desc, *additional
TYPES.find { |matcher, klass|
if matcher.respond_to? :call then
matcher.call desc, *additional
else
matcher === desc.to_s
end
}.last
end

def describe_stack # :nodoc:
Thread.current[:describe_stack] ||= []
end

##
# Returns the children of this spec.

def children
@children ||= []
end

def nuke_test_methods! # :nodoc:
self.public_instance_methods.grep(/^test_/).each do |name|
self.send :undef_method, name
end
end

##
# Define a 'before' action. Inherits the way normal methods should.
#
# NOTE: +type+ is ignored and is only there to make porting easier.
#
# Equivalent to Minitest::Test#setup.

def before type = nil, &block
define_method :setup do
super()
self.instance_eval(&block)
end
end

##
# Define an 'after' action. Inherits the way normal methods should.
#
# NOTE: +type+ is ignored and is only there to make porting easier.
#
# Equivalent to Minitest::Test#teardown.

def after type = nil, &block
define_method :teardown do
self.instance_eval(&block)
super()
end
end

##
# Define an expectation with name +desc+. Name gets morphed to a
# proper test method name. For some freakish reason, people who
# write specs don't like class inheritance, so this goes way out of
# its way to make sure that expectations aren't inherited.
#
# This is also aliased to #specify and doesn't require a +desc+ arg.
#
# Hint: If you _do_ want inheritance, use minitest/test. You can mix
# and match between assertions and expectations as much as you want.

def it desc = "anonymous", &block
block ||= proc { skip "(no tests defined)" }

@specs ||= 0
@specs += 1

name = "test_%04d_%s" % [ @specs, desc ]

undef_klasses = self.children.reject { |c| c.public_method_defined? name }

define_method name, &block

undef_klasses.each do |undef_klass|
undef_klass.send :undef_method, name
end

name
end

##
# Essentially, define an accessor for +name+ with +block+.
#
# Why use let instead of def? I honestly don't know.

def let name, &block
name = name.to_s
pre, post = "let '#{name}' cannot ", ". Please use another name."
methods = Minitest::Spec.instance_methods.map(&:to_s) - %w[subject]
raise ArgumentError, "#{pre}begin with 'test'#{post}" if
name =~ /\Atest/
raise ArgumentError, "#{pre}override a method in Minitest::Spec#{post}" if
methods.include? name

define_method name do
@_memoized ||= {}
@_memoized.fetch(name) { |k| @_memoized[k] = instance_eval(&block) }
end
end

##
# Another lazy man's accessor generator. Made even more lazy by
# setting the name for you to +subject+.

def subject &block
let :subject, &block
end

def create name, desc # :nodoc:
cls = Class.new(self) do
@name = name
@desc = desc

nuke_test_methods!
end

children << cls

cls
end

def name # :nodoc:
defined?(@name) ? @name : super
end

def to_s # :nodoc:
name # Can't alias due to 1.8.7, not sure why
end

# :stopdoc:
attr_reader :desc
alias :specify :it

module InstanceMethods
def before_setup
super
Thread.current[:current_spec] = self
end
end

def self.extended obj
obj.send :include, InstanceMethods
end

# :startdoc:
end

extend DSL

TYPES = DSL::TYPES # :nodoc:
end

require "minitest/expectations"

class Object # :nodoc:
include Minitest::Expectations unless ENV["MT_NO_EXPECTATIONS"]
end
293 changes: 293 additions & 0 deletions stdlib/minitest/test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
require "minitest" unless defined? Minitest::Runnable

module Minitest
##
# Subclass Test to create your own tests. Typically you'll want a
# Test subclass per implementation class.
#
# See Minitest::Assertions

class Test < Runnable
require "minitest/assertions"
include Minitest::Assertions

PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, # :nodoc:
Interrupt, SystemExit]

class << self; attr_accessor :io_lock; end # :nodoc:
self.io_lock = Mutex.new

##
# Call this at the top of your tests when you absolutely
# positively need to have ordered tests. In doing so, you're
# admitting that you suck and your tests are weak.

def self.i_suck_and_my_tests_are_order_dependent!
class << self
undef_method :test_order if method_defined? :test_order
define_method :test_order do :alpha end
end
end

##
# Make diffs for this Test use #pretty_inspect so that diff
# in assert_equal can have more details. NOTE: this is much slower
# than the regular inspect but much more usable for complex
# objects.

def self.make_my_diffs_pretty!
require "pp"

define_method :mu_pp do |o|
o.pretty_inspect
end
end

##
# Call this at the top of your tests when you want to run your
# tests in parallel. In doing so, you're admitting that you rule
# and your tests are awesome.

def self.parallelize_me!
include Minitest::Parallel::Test
extend Minitest::Parallel::Test::ClassMethods
end

##
# Returns all instance methods starting with "test_". Based on
# #test_order, the methods are either sorted, randomized
# (default), or run in parallel.

def self.runnable_methods
methods = methods_matching(/^test_/)

case self.test_order
when :random, :parallel then
max = methods.size
methods.sort.sort_by { rand max }
when :alpha, :sorted then
methods.sort
else
raise "Unknown test_order: #{self.test_order.inspect}"
end
end

##
# Defines the order to run tests (:random by default). Override
# this or use a convenience method to change it for your tests.

def self.test_order
:random
end

##
# The time it took to run this test.

attr_accessor :time

def marshal_dump # :nodoc:
super << self.time
end

def marshal_load ary # :nodoc:
self.time = ary.pop
super
end

TEARDOWN_METHODS = %w{ before_teardown teardown after_teardown } # :nodoc:

##
# Runs a single test with setup/teardown hooks.

def run
with_info_handler do
time_it do
capture_exceptions do
before_setup; setup; after_setup

self.send self.name
end

TEARDOWN_METHODS.each do |hook|
capture_exceptions do
self.send hook
end
end
end
end

self # per contract
end

##
# Provides before/after hooks for setup and teardown. These are
# meant for library writers, NOT for regular test authors. See
# #before_setup for an example.

module LifecycleHooks

##
# Runs before every test, before setup. This hook is meant for
# libraries to extend minitest. It is not meant to be used by
# test developers.
#
# As a simplistic example:
#
# module MyMinitestPlugin
# def before_setup
# super
# # ... stuff to do before setup is run
# end
#
# def after_setup
# # ... stuff to do after setup is run
# super
# end
#
# def before_teardown
# super
# # ... stuff to do before teardown is run
# end
#
# def after_teardown
# # ... stuff to do after teardown is run
# super
# end
# end
#
# class MiniTest::Test
# include MyMinitestPlugin
# end

def before_setup; end

##
# Runs before every test. Use this to set up before each test
# run.

def setup; end

##
# Runs before every test, after setup. This hook is meant for
# libraries to extend minitest. It is not meant to be used by
# test developers.
#
# See #before_setup for an example.

def after_setup; end

##
# Runs after every test, before teardown. This hook is meant for
# libraries to extend minitest. It is not meant to be used by
# test developers.
#
# See #before_setup for an example.

def before_teardown; end

##
# Runs after every test. Use this to clean up after each test
# run.

def teardown; end

##
# Runs after every test, after teardown. This hook is meant for
# libraries to extend minitest. It is not meant to be used by
# test developers.
#
# See #before_setup for an example.

def after_teardown; end
end # LifecycleHooks

def capture_exceptions # :nodoc:
begin
yield
# rescue *PASSTHROUGH_EXCEPTIONS
# raise
# rescue Assertion => e
# self.failures << e
# rescue Exception => e
# self.failures << UnexpectedError.new(e)
rescue => e
case e
when *PASSTHROUGH_EXCEPTIONS
when Assertion then self.failures << e
when Exception then self.failures << UnexpectedError.new(e)
end
end
end

##
# Did this run error?

def error?
self.failures.any? { |f| UnexpectedError === f }
end

##
# The location identifier of this test.

def location
loc = " [#{self.failure.location}]" unless passed? or error?
"#{self.class}##{self.name}#{loc}"
end

##
# Did this run pass?
#
# Note: skipped runs are not considered passing, but they don't
# cause the process to exit non-zero.

def passed?
not self.failure
end

##
# Returns ".", "F", or "E" based on the result of the run.

def result_code
self.failure and self.failure.result_code or "."
end

##
# Was this run skipped?

def skipped?
self.failure and Skip === self.failure
end

def time_it # :nodoc:
t0 = Time.now

yield
ensure
self.time = Time.now - t0
end

def to_s # :nodoc:
return location if passed? and not skipped?

failures.map { |failure|
"#{failure.result_label}:\n#{self.location}:\n#{failure.message}\n"
}.join "\n"
end

def with_info_handler &block # :nodoc:
t0 = Time.now

handler = lambda do
warn "\nCurrent: %s#%s %.2fs" % [self.class, self.name, Time.now - t0]
end

self.class.on_signal "INFO", handler, &block
end

include LifecycleHooks
include Guard
extend Guard
end # Test
end

require "minitest/unit" unless defined?(MiniTest) # compatibility layer only
45 changes: 45 additions & 0 deletions stdlib/minitest/unit.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# :stopdoc:

unless defined?(Minitest) then
# all of this crap is just to avoid circular requires and is only
# needed if a user requires "minitest/unit" directly instead of
# "minitest/autorun", so we also warn

from = caller.reject { |s| s =~ /rubygems/ }.join("\n ")
warn "Warning: you should require 'minitest/autorun' instead."
warn %(Warning: or add 'gem "minitest"' before 'require "minitest/autorun"')
warn "From:\n #{from}"

module Minitest; end
MiniTest = Minitest # prevents minitest.rb from requiring back to us
require "minitest"
end

MiniTest = Minitest unless defined?(MiniTest)

module Minitest
class Unit
VERSION = Minitest::VERSION
class TestCase < Minitest::Test
def self.inherited klass # :nodoc:
from = caller.first
warn "MiniTest::Unit::TestCase is now Minitest::Test. From #{from}"
super
end
end

def self.autorun # :nodoc:
from = caller.first
warn "MiniTest::Unit.autorun is now Minitest.autorun. From #{from}"
Minitest.autorun
end

def self.after_tests(&b)
from = caller.first
warn "MiniTest::Unit.after_tests is now Minitest.after_run. From #{from}"
Minitest.after_run(&b)
end
end
end

# :startdoc:
10 changes: 10 additions & 0 deletions stdlib/test/unit.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# test/unit compatibility layer using minitest.

require 'minitest/autorun'
module Test
module Unit
class TestCase < Minitest::Test
alias assert_raise assert_raises
end
end
end
2 changes: 1 addition & 1 deletion stdlib/thread.rb
Original file line number Diff line number Diff line change
@@ -108,7 +108,7 @@ def push(value)
alias enq push

def each(&block)
@storage.each(&:block)
@storage.each(&block)
end
end

38 changes: 38 additions & 0 deletions tasks/documentation.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace :doc do
doc_repo = Pathname(ENV['DOC_REPO'] || 'gh-pages')
doc_base = doc_repo.join('doc')
current_git_release = -> { `git rev-parse --abbrev-ref HEAD`.chomp }
template_option = "--template opal --template-path #{doc_repo.join('yard-templates')}"

directory doc_repo.to_s do
remote = ENV['DOC_REPO_REMOTE'] || '.'
sh 'git', 'clone', '-b', 'gh-pages', '--', remote, doc_repo.to_s
end

task :corelib => doc_repo.to_s do
git = current_git_release.call
name = 'corelib'
glob = 'opal/**/*.rb'

command = "doxx --template #{doc_repo.join('doxx-templates/opal.jade')} "\
"--source opal/corelib --target #{doc_base}/#{git}/#{name} "\
"--title \"Opal runtime.js Documentation\" --readme opal/README.md"
puts command; system command or $stderr.puts "Please install doxx with: npm install"

command = "yard doc #{glob} #{template_option} "\
"--readme opal/README.md -o #{doc_base}/#{git}/#{name}"
puts command; system command
end

task :stdlib => doc_repo do
git = current_git_release.call
name = 'stdlib'
glob = '{stdlib/**/*,opal/compiler,opal/erb,opal/version}.rb'
command = "yard doc #{glob} #{template_option} "\
"--readme stdlib/README.md -o gh-pages/doc/#{git}/#{name}"
puts command; system command
end
end

task :doc => ['doc:corelib', 'doc:stdlib']

41 changes: 39 additions & 2 deletions tasks/testing.rake
Original file line number Diff line number Diff line change
@@ -60,6 +60,43 @@ task :mspec_node do
"bin/opal -Ispec -Ilib -gmspec #{stubs} -rnodejs -Dwarning -A #{filename}"
end

task :mspec => [:mspec_node, :mspec_phantom]
task :test_all => [:rspec, :mspec]
task :cruby_tests do
if ENV.key? 'FILES'
files = Dir[ENV['FILES'] || 'test/test_*.rb']
include_paths = '-Itest -I. -Itmp -Ilib'
else
include_paths = '-Itest/cruby/test'
test_dir = Pathname("#{__dir__}/test/cruby/test")
files = %w[
ruby/test_call.rb
].flat_map do |path|
if path.end_with?('.rb')
path
else
glob = test_dir.join(path+"/test_*.rb").to_s
size = test_dir.to_s.size
Dir[glob].map { |file| file[size+1..-1] }
end
end
end

requires = files.map{|f| "require '#{f}'"}
filename = 'tmp/cruby_tests.rb'
mkdir_p File.dirname(filename)
File.write filename, <<-RUBY
#{requires.join(" \n")}
exit
RUBY

stubs = "-soptparse -sio/console -stimeout -smutex_m -srubygems -stempfile -smonitor"

puts "== Running: #{files.join ", "}"

sh 'RUBYOPT="-rbundler/setup" '\
"bin/opal #{include_paths} #{stubs} -rnodejs -Dwarning -A #{filename} -c > tmp/cruby_tests.js"
sh 'node tmp/cruby_tests.js'
end

task :mspec => [:mspec_node, :mspec_phantom]
task :minitest => [:cruby_tests]
task :test_all => [:rspec, :mspec, :minitest]
1 change: 1 addition & 0 deletions test/cruby
Submodule cruby added at 8f0c3f