forked from rubinius/rubinius
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Brian Ford
committed
Aug 20, 2008
1 parent
d6f1b5f
commit bfa449f
Showing
178 changed files
with
12,247 additions
and
1,901 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
Copyright (c) 2008 Engine Yard, Inc. All rights reserved. | ||
|
||
Permission is hereby granted, free of charge, to any person | ||
obtaining a copy of this software and associated documentation | ||
files (the "Software"), to deal in the Software without | ||
restriction, including without limitation the rights to use, | ||
copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the | ||
Software is furnished to do so, subject to the following | ||
conditions: | ||
|
||
The above copyright notice and this permission notice shall be | ||
included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,194 @@ | ||
mSpec and mMock are simplistic apes of RSpec. | ||
= Overview | ||
|
||
The primary design rationale for mSpec is simplicity to allow nascent Ruby | ||
implementations to run the Ruby specs. So, for example, there is not great | ||
concern given to constant clashes. Namespacing (or module scoping) is not used | ||
because implementing this correctly took a significant amount of work in | ||
Rubinius and it is likely that other implementations would also face | ||
MSpec is a specialized framework that is syntax-compatible with RSpec for | ||
basic things like +describe+, +it+ blocks and +before+, +after+ actions. MSpec | ||
contains additional features that assist in writing the RubySpecs used by | ||
multiple Ruby implementations. | ||
|
||
MSpec attempts to use the simplest Ruby language features so that beginning | ||
Ruby implementations can run the Ruby specs. So, for example, there is not | ||
great concern given to constant clashes. Namespacing (or module scoping) is | ||
not used because implementing this correctly took a significant amount of work | ||
in Rubinius and it is likely that other implementations would also face | ||
difficulties. | ||
|
||
mSpec is not intended as a replacement for RSpec. mSpec attempts to provide a | ||
subset of RSpec syntax. It does not provide all the matchers, for instance. | ||
MSpec is not intended as a replacement for RSpec. MSpec attempts to provide a | ||
subset of RSpec's features in some cases and a superset in others. It does not | ||
provide all the matchers, for instance. However, MSpec provides several | ||
extensions to facilitate writing the Ruby specs in a manner compatible with | ||
multiple Ruby implementations. | ||
|
||
mSpec also provides several extensions to facilitate writing the Ruby specs in | ||
a manner compatible with multiple Ruby implementations. First, mSpec offers a | ||
set of guards to control execution of the specs. These guards not only enable | ||
or disable execution but also annotate the specs with additional information | ||
about why they are run or not run. Second, mSpec provides a different shared | ||
spec implementation specifically designed to ease writing specs for the | ||
numerous aliased methods in Ruby. The mSpec shared spec implementation should | ||
not conflict with RSpec's own shared behavior facility. | ||
First, MSpec offers a set of guards to control execution of the specs. These | ||
guards not only enable or disable execution but also annotate the specs with | ||
additional information about why they are run or not run. Second, MSpec | ||
provides a different shared spec implementation specifically designed to ease | ||
writing specs for the numerous aliased methods in Ruby. The MSpec shared spec | ||
implementation should not conflict with RSpec's own shared behavior facility. | ||
Third, MSpec provides various helper methods to simplify some specs, for | ||
example, creating temporary file names. Finally, MSpec has several specialized | ||
runner scripts that includes a configuration facility with a default project | ||
file and user-specific overrides. | ||
|
||
Caveats: | ||
* Use RSpec to run the mSpec specs. There are no plans currently to make | ||
the mSpec specs runnable by mSpec. | ||
* Don't mock the #hash method as mMock uses Hash internally. This can be | ||
replaced if necessary, but at this point it's not worth it. | ||
|
||
* Use RSpec to run the MSpec specs. There are no plans currently to make | ||
the MSpec specs runnable by MSpec. | ||
* Don't mock the #hash method as MSpec's Mock implementation uses Hash | ||
internally. This can be replaced if necessary, but at this point there is no | ||
compelling need to do so. | ||
|
||
|
||
== Architecture | ||
|
||
|
||
== Matchers | ||
|
||
Matchers are additional aids for the verification process. The default | ||
is of course to #should or #should_not using the #== operator and its | ||
friends but the matchers add a new set of 'operators' to help in the | ||
task. They reside in `mspec/matchers/`. There are two broad categories, | ||
those that apply to an individual object and those that apply to a | ||
block: | ||
|
||
=== Object | ||
|
||
- `base` implements the standard #==, #< #<= #>= #> and #=~ with their | ||
normal semantics for the objects that you invoke them on. | ||
|
||
- `be_ancestor_of` is equivalent to checking `obj.ancestors.include?`. | ||
|
||
- `be_close` is a "delta" for floating-point math. Due to the very | ||
nature of it, floating-point comparisons should never be treated as | ||
exact. By default the tolerance is 0.00003 but it can be altered if | ||
so desired. So `0.23154.should be_close(0.23157)` would succeed | ||
(which is usually close enough for floating point unless you are | ||
doing some scientific computing.) | ||
|
||
- `be_empty` checks `obj.empty?` | ||
|
||
- `be_kind_of` is equivalent to `obj.kind_of?` | ||
|
||
- `include` is `obj.include?` | ||
|
||
=== Block | ||
|
||
All of these should be applied to a block created with `lambda` or `proc`: | ||
|
||
- `complain` is probably clearer stated as `lambda {...}.should complain`; | ||
it checks that the block issues a warning. The message can be checked | ||
against either a String or a Regexp. | ||
|
||
- `output` checks that the block produces the given output (stdout as well | ||
as stderr, in that order) matched either to a String or a Regexp. This one | ||
uses overrides so if that is a problem (for e.g. speccing Readline or | ||
something) see below. | ||
|
||
- `output_to_fd` is a lower-level version and actually verifies that output | ||
to a certain file descriptor is correct whether from an in-/output stream | ||
or an actual file. Also can check with either a String or a Regexp. | ||
|
||
- `raise_error` verifies the exception type (if any) raised by the block it | ||
is associated with. The exception class can be given for finer-grained | ||
control (inheritance works normally so Exception would catch everything.) | ||
|
||
== Nested 'describe' blocks | ||
|
||
MSpec supports nesting one 'describe' block inside another. The examples in | ||
the nested block are evaluated with all the before/after blocks of all the | ||
containing 'describe' blocks. The following example illustrates this: | ||
|
||
describe "Some#method" do | ||
before :each do | ||
@obj = 1 | ||
end | ||
|
||
describe "when passed String" do | ||
before :each do | ||
@meth = :to_s | ||
end | ||
|
||
it "returns false" do | ||
# when this example is evaluated, @obj = 1 and @meth = :to_s | ||
end | ||
end | ||
end | ||
|
||
The output when using the SpecdocFormatter (selected with -fs to the runners) | ||
will be as follows: | ||
|
||
Some#method when passed String | ||
- returns false | ||
|
||
|
||
== Shared 'describe' blocks | ||
|
||
MSpec supports RSpec-style shared 'describe' blocks. MSpec also provides a | ||
convenience method to assist in writing specs for the numerous aliased methods | ||
that Ruby provides. The following example illustrates shared blocks: | ||
|
||
describe :someclass_some_method, :shared => true do | ||
it "does something" do | ||
end | ||
end | ||
|
||
describe "SomeClass#some_method" do | ||
it_should_behave_like "someclass_some_method" | ||
end | ||
|
||
The first argument to 'describe' for a shared block is an object that | ||
duck-types as a String. The representation of the object must be unique. This | ||
example uses a symbol. This was the convention for the previous facility that | ||
MSpec provided for aliased method (#it_behaves_like). However, this convention | ||
is not set in stone (but the uniqueness requirement is). Note that the | ||
argument to the #it_should_behave_like is a String because at this time RSpec | ||
will not find the shared block by the symbol. | ||
|
||
MSpec continues to support the #it_behaves_like convenience method for | ||
specifying aliased methods. The syntax is as follows: | ||
|
||
it_behaves_like :symbol_matching_shared_describe, :method [, :object] | ||
|
||
describe :someclass_some_method, :shared => true do | ||
it "returns true" do | ||
obj.send(@method).should be_true | ||
end | ||
|
||
it "returns something else" do | ||
@object.send(@method).should be_something_else | ||
end | ||
end | ||
|
||
# example #1 | ||
describe "SomeClass#some_method" do | ||
it_behaves_like :someclass_some_method, :other_method | ||
end | ||
|
||
# example #2 | ||
describe "SomeOtherClass#some_method" do | ||
it_behaves_like :someclass_some_method, :some_method, OtherClass | ||
end | ||
|
||
The first form above (#1) is used for typical aliases. That is, methods with | ||
different names on the same class that behave identically. The | ||
#it_behaves_like helper creates a before(:all) block that sets @method to | ||
:other_method. The form of the first example block in the shared block | ||
illustrates the typical form of a spec for an aliased method. | ||
|
||
The second form above (#2) is used for methods on different classes that are | ||
essentially aliases, even though Ruby does not provide a syntax for specifying | ||
such methods as aliases. Examples are the methods on File, FileTest, and | ||
File::Stat. In this case, the #it_behaves_like helper sets both @method and | ||
@object in the before(:all) block (@method = :some_method, @object = | ||
OtherClass in this example). | ||
|
||
For shared specs that fall outside of either of these two narrow categories, | ||
use nested or shared 'describe' blocks as appropriate and use the | ||
#it_should_behave_like method directly. | ||
|
||
== Guards | ||
|
||
|
||
== Helpers | ||
|
||
|
||
== Runners |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
require 'rubygems' | ||
require 'spec/rake/spectask' | ||
require 'rake/gempackagetask' | ||
require 'lib/mspec/version' | ||
|
||
Spec::Rake::SpecTask.new | ||
|
||
task :default => :spec | ||
|
||
|
||
spec = Gem::Specification.new do |s| | ||
s.name = %q{mspec} | ||
s.version = MSpec::VERSION | ||
|
||
s.specification_version = 2 if s.respond_to? :specification_version= | ||
|
||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= | ||
s.authors = ["Brian Ford"] | ||
s.date = %q{2008-05-21} | ||
s.email = %q{[email protected]} | ||
s.has_rdoc = true | ||
s.extra_rdoc_files = %w[ README LICENSE ] | ||
s.executables = ["mkspec", "mspec", "mspec-ci", "mspec-run", "mspec-tag"] | ||
s.files = FileList[ '{bin,lib,spec}/**/*.{yaml,txt,rb}', 'Rakefile', *s.extra_rdoc_files ] | ||
s.homepage = %q{http://rubyspec.org} | ||
s.rubyforge_project = 'http://rubyforge.org/projects/mspec' | ||
s.require_paths = ["lib"] | ||
s.rubygems_version = %q{1.1.1} | ||
s.summary = <<EOS | ||
MSpec is a specialized framework that is syntax-compatible | ||
with RSpec for basic things like describe, it blocks and | ||
before, after actions. | ||
MSpec contains additional features that assist in writing | ||
the RubySpecs used by multiple Ruby implementations. Also, | ||
MSpec attempts to use the simplest Ruby language features | ||
so that beginning Ruby implementations can run it. | ||
EOS | ||
|
||
s.rdoc_options << '--title' << 'MSpec Gem' << | ||
'--main' << 'README' << | ||
'--line-numbers' | ||
end | ||
|
||
Rake::GemPackageTask.new(spec){ |pkg| pkg.gem_spec = spec } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#!/usr/bin/env ruby | ||
|
||
$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') | ||
|
||
require 'mspec/commands/mkspec' | ||
|
||
MkSpec.main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,100 +1,7 @@ | ||
#!/usr/bin/env ruby | ||
|
||
require 'optparse' | ||
require 'mspec/version' | ||
require 'mspec/bin/options' | ||
$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') | ||
|
||
includes = [] | ||
requires = [] | ||
name = nil | ||
target = 'shotgun/rubinius' | ||
flags = [] | ||
command = nil | ||
options = [] | ||
require 'mspec/commands/mspec' | ||
|
||
if ["ci", "run", "tag"].include? ARGV[0] | ||
command = ARGV.shift | ||
options << "-h" if ARGV.delete("-h") || ARGV.delete("--help") | ||
end | ||
|
||
opts = OptionParser.new("", 24, ' ') do |opts| | ||
opts.banner = "mspec [COMMAND] [options] (FILE|DIRECTORY|GLOB)+" | ||
opts.separator "" | ||
|
||
opts.on("-t", "--target TARGET", String, | ||
"Implementation to run the specs: r:ruby|r19:ruby19|x:rbx|j:jruby") do |t| | ||
case t | ||
when 'r', 'ruby' | ||
target = 'ruby' | ||
when 'r19', 'ruby19' | ||
target = 'ruby19' | ||
when 'x', 'rbx', 'rubinius' | ||
target = 'shotgun/rubinius' | ||
when 'X' | ||
target = "rbx" | ||
when 'j', 'jruby' | ||
target = 'jruby' | ||
else | ||
target = t | ||
end | ||
end | ||
opts.on("-T", "--target-opt OPT", String, | ||
"Pass OPT as a flag to the target implementation") do |t| | ||
flags << t | ||
end | ||
opts.on("-I", "--include DIR", String, | ||
"Pass DIR through as the -I option to the target") do |d| | ||
includes << "-I#{d}" | ||
end | ||
opts.on("-r", "--require LIBRARY", String, | ||
"Pass LIBRARY through as the -r option to the target") do |f| | ||
requires << "-r#{f}" | ||
end | ||
opts.on("-n", "--name RUBY_NAME", String, | ||
"Override the name used to determine the implementation") do |n| | ||
name = "RUBY_NAME = \"#{n}\";" | ||
end | ||
opts.on("-X", "--tags-dir DIR", String, | ||
"Use DIR as the path prefix for locating spec tag files") do |d| | ||
ENV['TAGS_DIR'] = d | ||
end | ||
opts.on("-D", "--gdb", "Run under gdb") do | ||
flags << '--gdb' | ||
end | ||
opts.on("-A", "--valgrind", "Run under valgrind") do | ||
flags << '--valgrind' | ||
end | ||
opts.on("-w", "--warnings", "Don't supress warnings") do | ||
flags << '-w' | ||
ENV['OUTPUT_WARNINGS'] = '1' | ||
end | ||
opts.on("-v", "--version", "Show version") do | ||
puts "MSpec #{MSpec::VERSION}" | ||
exit | ||
end | ||
opts.on("-h", "--help", "Show this message") do | ||
puts opts | ||
puts %[ | ||
where COMMAND is one of: | ||
run - Run the specified specs (default) | ||
ci - Run the known good specs | ||
tag - Add or remove tags | ||
mspec COMMAND -h for more options | ||
] | ||
exit | ||
end | ||
end | ||
|
||
options += opts.filter! ARGV | ||
opts.parse ARGV | ||
|
||
ENV['MSPEC_RUNNER'] = '1' | ||
ENV['MSPEC_OPTIONS'] = options.join("\n") | ||
exec %[#{target} \ | ||
#{flags.join(" ")} \ | ||
#{includes.join(" ")} \ | ||
#{requires.join(" ")} \ | ||
mspec/bin/mspec-#{command || "run"} | ||
] | ||
MSpecMain.main |
Oops, something went wrong.