[macruby-changes] [876] MacRuby/branches/experimental
source_changes at macosforge.org
source_changes at macosforge.org
Wed Mar 11 16:10:17 PDT 2009
Revision: 876
http://trac.macosforge.org/projects/ruby/changeset/876
Author: eloy.de.enige at gmail.com
Date: 2009-03-11 16:10:17 -0700 (Wed, 11 Mar 2009)
Log Message:
-----------
Imported mpspec 65a5dbf1063759eafc42947f697329c638b9a2ce. See http://github.com/rubyspec/mspec/tree/master
Added Paths:
-----------
MacRuby/branches/experimental/mspec/
MacRuby/branches/experimental/mspec/LICENSE
MacRuby/branches/experimental/mspec/README
MacRuby/branches/experimental/mspec/Rakefile
MacRuby/branches/experimental/mspec/bin/
MacRuby/branches/experimental/mspec/bin/mkspec
MacRuby/branches/experimental/mspec/bin/mkspec.bat
MacRuby/branches/experimental/mspec/bin/mspec
MacRuby/branches/experimental/mspec/bin/mspec-ci
MacRuby/branches/experimental/mspec/bin/mspec-ci.bat
MacRuby/branches/experimental/mspec/bin/mspec-run
MacRuby/branches/experimental/mspec/bin/mspec-run.bat
MacRuby/branches/experimental/mspec/bin/mspec-tag
MacRuby/branches/experimental/mspec/bin/mspec-tag.bat
MacRuby/branches/experimental/mspec/bin/mspec.bat
MacRuby/branches/experimental/mspec/lib/
MacRuby/branches/experimental/mspec/lib/mspec/
MacRuby/branches/experimental/mspec/lib/mspec/commands/
MacRuby/branches/experimental/mspec/lib/mspec/commands/mkspec.rb
MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec-ci.rb
MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec-run.rb
MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec-tag.rb
MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec.rb
MacRuby/branches/experimental/mspec/lib/mspec/expectations/
MacRuby/branches/experimental/mspec/lib/mspec/expectations/expectations.rb
MacRuby/branches/experimental/mspec/lib/mspec/expectations/should.rb
MacRuby/branches/experimental/mspec/lib/mspec/expectations.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/
MacRuby/branches/experimental/mspec/lib/mspec/guards/background.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/bug.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/compliance.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/conflict.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/endian.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/extensions.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/guard.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/noncompliance.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/platform.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/quarantine.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/runner.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/superuser.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/support.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/tty.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards/version.rb
MacRuby/branches/experimental/mspec/lib/mspec/guards.rb
MacRuby/branches/experimental/mspec/lib/mspec/helpers/
MacRuby/branches/experimental/mspec/lib/mspec/helpers/argv.rb
MacRuby/branches/experimental/mspec/lib/mspec/helpers/bignum.rb
MacRuby/branches/experimental/mspec/lib/mspec/helpers/const_lookup.rb
MacRuby/branches/experimental/mspec/lib/mspec/helpers/environment.rb
MacRuby/branches/experimental/mspec/lib/mspec/helpers/fixture.rb
MacRuby/branches/experimental/mspec/lib/mspec/helpers/flunk.rb
MacRuby/branches/experimental/mspec/lib/mspec/helpers/io.rb
MacRuby/branches/experimental/mspec/lib/mspec/helpers/language_version.rb
MacRuby/branches/experimental/mspec/lib/mspec/helpers/ruby_exe.rb
MacRuby/branches/experimental/mspec/lib/mspec/helpers/scratch.rb
MacRuby/branches/experimental/mspec/lib/mspec/helpers/tmp.rb
MacRuby/branches/experimental/mspec/lib/mspec/helpers.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/
MacRuby/branches/experimental/mspec/lib/mspec/matchers/base.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_an_instance_of.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_ancestor_of.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_close.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_empty.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_false.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_kind_of.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_nil.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_true.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/complain.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/eql.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/equal.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/equal_element.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/equal_utf16.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_constant.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_instance_method.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_method.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_private_instance_method.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/include.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/match_yaml.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/method.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/output.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/output_to_fd.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/raise_error.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/respond_to.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers/stringsymboladapter.rb
MacRuby/branches/experimental/mspec/lib/mspec/matchers.rb
MacRuby/branches/experimental/mspec/lib/mspec/mocks/
MacRuby/branches/experimental/mspec/lib/mspec/mocks/mock.rb
MacRuby/branches/experimental/mspec/lib/mspec/mocks/object.rb
MacRuby/branches/experimental/mspec/lib/mspec/mocks/proxy.rb
MacRuby/branches/experimental/mspec/lib/mspec/mocks.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/
MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/
MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/debug.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/filter.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/gdb.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/tag.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/taglist.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/tagpurge.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/tally.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/timer.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/actions.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/context.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/example.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/exception.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/
MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/match.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/profile.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/regexp.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/tag.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/filters.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/
MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/describe.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/dotted.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/file.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/html.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/method.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/specdoc.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/spinner.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/summary.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/unit.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/yaml.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/mspec.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/object.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/shared.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner/tag.rb
MacRuby/branches/experimental/mspec/lib/mspec/runner.rb
MacRuby/branches/experimental/mspec/lib/mspec/utils/
MacRuby/branches/experimental/mspec/lib/mspec/utils/name_map.rb
MacRuby/branches/experimental/mspec/lib/mspec/utils/options.rb
MacRuby/branches/experimental/mspec/lib/mspec/utils/ruby_name.rb
MacRuby/branches/experimental/mspec/lib/mspec/utils/script.rb
MacRuby/branches/experimental/mspec/lib/mspec/utils/version.rb
MacRuby/branches/experimental/mspec/lib/mspec/version.rb
MacRuby/branches/experimental/mspec/lib/mspec.rb
MacRuby/branches/experimental/mspec/mspec.gemspec
MacRuby/branches/experimental/mspec/spec/
MacRuby/branches/experimental/mspec/spec/commands/
MacRuby/branches/experimental/mspec/spec/commands/fixtures/
MacRuby/branches/experimental/mspec/spec/commands/fixtures/four.txt
MacRuby/branches/experimental/mspec/spec/commands/fixtures/level2/
MacRuby/branches/experimental/mspec/spec/commands/fixtures/level2/three_spec.rb
MacRuby/branches/experimental/mspec/spec/commands/fixtures/one_spec.rb
MacRuby/branches/experimental/mspec/spec/commands/fixtures/three.rb
MacRuby/branches/experimental/mspec/spec/commands/fixtures/two_spec.rb
MacRuby/branches/experimental/mspec/spec/commands/mkspec_spec.rb
MacRuby/branches/experimental/mspec/spec/commands/mspec_ci_spec.rb
MacRuby/branches/experimental/mspec/spec/commands/mspec_run_spec.rb
MacRuby/branches/experimental/mspec/spec/commands/mspec_spec.rb
MacRuby/branches/experimental/mspec/spec/commands/mspec_tag_spec.rb
MacRuby/branches/experimental/mspec/spec/expectations/
MacRuby/branches/experimental/mspec/spec/expectations/expectations_spec.rb
MacRuby/branches/experimental/mspec/spec/expectations/should_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/
MacRuby/branches/experimental/mspec/spec/guards/background_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/bug_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/compliance_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/conflict_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/endian_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/extensions_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/guard_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/noncompliance_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/platform_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/quarantine_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/runner_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/superuser_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/support_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/tty_spec.rb
MacRuby/branches/experimental/mspec/spec/guards/version_spec.rb
MacRuby/branches/experimental/mspec/spec/helpers/
MacRuby/branches/experimental/mspec/spec/helpers/argv_spec.rb
MacRuby/branches/experimental/mspec/spec/helpers/bignum_spec.rb
MacRuby/branches/experimental/mspec/spec/helpers/const_lookup_spec.rb
MacRuby/branches/experimental/mspec/spec/helpers/environment_spec.rb
MacRuby/branches/experimental/mspec/spec/helpers/fixture_spec.rb
MacRuby/branches/experimental/mspec/spec/helpers/flunk_spec.rb
MacRuby/branches/experimental/mspec/spec/helpers/io_spec.rb
MacRuby/branches/experimental/mspec/spec/helpers/language_version_spec.rb
MacRuby/branches/experimental/mspec/spec/helpers/ruby_exe_spec.rb
MacRuby/branches/experimental/mspec/spec/helpers/scratch_spec.rb
MacRuby/branches/experimental/mspec/spec/helpers/tmp_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/
MacRuby/branches/experimental/mspec/spec/matchers/base_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/be_an_instance_of_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/be_ancestor_of_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/be_close_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/be_empty_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/be_false_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/be_kind_of_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/be_nil_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/be_true_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/complain_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/eql_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/equal_element_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/equal_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/equal_utf16_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/have_constant_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/have_instance_method_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/have_method_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/have_private_instance_method_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/include_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/match_yaml_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/output_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/output_to_fd_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/raise_error_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/respond_to_spec.rb
MacRuby/branches/experimental/mspec/spec/matchers/stringsymboladapter_spec.rb
MacRuby/branches/experimental/mspec/spec/mocks/
MacRuby/branches/experimental/mspec/spec/mocks/mock_spec.rb
MacRuby/branches/experimental/mspec/spec/mocks/proxy_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/
MacRuby/branches/experimental/mspec/spec/runner/actions/
MacRuby/branches/experimental/mspec/spec/runner/actions/debug_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/actions/filter_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/actions/gdb_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/actions/tag_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/actions/taglist_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/actions/tagpurge_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/actions/tally_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/actions/timer_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/context_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/example_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/exception_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/filters/
MacRuby/branches/experimental/mspec/spec/runner/filters/a.yaml
MacRuby/branches/experimental/mspec/spec/runner/filters/b.yaml
MacRuby/branches/experimental/mspec/spec/runner/filters/match_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/filters/profile_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/filters/regexp_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/filters/tag_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/formatters/
MacRuby/branches/experimental/mspec/spec/runner/formatters/describe_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/formatters/dotted_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/formatters/file_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/formatters/html_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/formatters/method_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/formatters/specdoc_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/formatters/spinner_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/formatters/summary_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/formatters/unit_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/formatters/yaml_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/mspec_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/shared_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/tag_spec.rb
MacRuby/branches/experimental/mspec/spec/runner/tags.txt
MacRuby/branches/experimental/mspec/spec/spec_helper.rb
MacRuby/branches/experimental/mspec/spec/utils/
MacRuby/branches/experimental/mspec/spec/utils/name_map_spec.rb
MacRuby/branches/experimental/mspec/spec/utils/options_spec.rb
MacRuby/branches/experimental/mspec/spec/utils/script_spec.rb
MacRuby/branches/experimental/mspec/spec/utils/version_spec.rb
Added: MacRuby/branches/experimental/mspec/LICENSE
===================================================================
--- MacRuby/branches/experimental/mspec/LICENSE (rev 0)
+++ MacRuby/branches/experimental/mspec/LICENSE 2009-03-11 23:10:17 UTC (rev 876)
@@ -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.
Added: MacRuby/branches/experimental/mspec/README
===================================================================
--- MacRuby/branches/experimental/mspec/README (rev 0)
+++ MacRuby/branches/experimental/mspec/README 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,197 @@
+= Overview
+
+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'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.
+
+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 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
+ at 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
+
+Since Ruby is not completely isolated from its platform or execution environment, the spec files may contain guards: conditions placed around a spec or a set of specs to enable or disable them.
+
+You can find an overview of the current guards and their usage in: http://rubyspec.org/wiki/mspec/Guards .
+
+== Helpers
+
+
+== Runners
Added: MacRuby/branches/experimental/mspec/Rakefile
===================================================================
--- MacRuby/branches/experimental/mspec/Rakefile (rev 0)
+++ MacRuby/branches/experimental/mspec/Rakefile 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,47 @@
+require 'rubygems'
+require 'spec/rake/spectask'
+require 'rake/gempackagetask'
+
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/lib')
+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.to_s
+
+ 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{2009-3-1}
+ s.email = %q{bford at engineyard.com}
+ 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 }
Added: MacRuby/branches/experimental/mspec/bin/mkspec
===================================================================
--- MacRuby/branches/experimental/mspec/bin/mkspec (rev 0)
+++ MacRuby/branches/experimental/mspec/bin/mkspec 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
+
+require 'mspec/commands/mkspec'
+
+MkSpec.main
Property changes on: MacRuby/branches/experimental/mspec/bin/mkspec
___________________________________________________________________
Added: svn:executable
+ *
Added: MacRuby/branches/experimental/mspec/bin/mkspec.bat
===================================================================
--- MacRuby/branches/experimental/mspec/bin/mkspec.bat (rev 0)
+++ MacRuby/branches/experimental/mspec/bin/mkspec.bat 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1 @@
+@"ruby.exe" "%~dpn0" %*
Added: MacRuby/branches/experimental/mspec/bin/mspec
===================================================================
--- MacRuby/branches/experimental/mspec/bin/mspec (rev 0)
+++ MacRuby/branches/experimental/mspec/bin/mspec 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
+
+require 'mspec/commands/mspec'
+
+MSpecMain.main
Property changes on: MacRuby/branches/experimental/mspec/bin/mspec
___________________________________________________________________
Added: svn:executable
+ *
Added: MacRuby/branches/experimental/mspec/bin/mspec-ci
===================================================================
--- MacRuby/branches/experimental/mspec/bin/mspec-ci (rev 0)
+++ MacRuby/branches/experimental/mspec/bin/mspec-ci 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,8 @@
+#!/usr/bin/env ruby
+
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
+
+require 'mspec/commands/mspec-ci'
+require 'mspec'
+
+MSpecCI.main
Property changes on: MacRuby/branches/experimental/mspec/bin/mspec-ci
___________________________________________________________________
Added: svn:executable
+ *
Added: MacRuby/branches/experimental/mspec/bin/mspec-ci.bat
===================================================================
--- MacRuby/branches/experimental/mspec/bin/mspec-ci.bat (rev 0)
+++ MacRuby/branches/experimental/mspec/bin/mspec-ci.bat 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1 @@
+@"ruby.exe" "%~dpn0" %*
Added: MacRuby/branches/experimental/mspec/bin/mspec-run
===================================================================
--- MacRuby/branches/experimental/mspec/bin/mspec-run (rev 0)
+++ MacRuby/branches/experimental/mspec/bin/mspec-run 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,8 @@
+#!/usr/bin/env ruby
+
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
+
+require 'mspec/commands/mspec-run'
+require 'mspec'
+
+MSpecRun.main
Property changes on: MacRuby/branches/experimental/mspec/bin/mspec-run
___________________________________________________________________
Added: svn:executable
+ *
Added: MacRuby/branches/experimental/mspec/bin/mspec-run.bat
===================================================================
--- MacRuby/branches/experimental/mspec/bin/mspec-run.bat (rev 0)
+++ MacRuby/branches/experimental/mspec/bin/mspec-run.bat 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1 @@
+@"ruby.exe" "%~dpn0" %*
Added: MacRuby/branches/experimental/mspec/bin/mspec-tag
===================================================================
--- MacRuby/branches/experimental/mspec/bin/mspec-tag (rev 0)
+++ MacRuby/branches/experimental/mspec/bin/mspec-tag 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,8 @@
+#!/usr/bin/env ruby
+
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
+
+require 'mspec/commands/mspec-tag'
+require 'mspec'
+
+MSpecTag.main
Property changes on: MacRuby/branches/experimental/mspec/bin/mspec-tag
___________________________________________________________________
Added: svn:executable
+ *
Added: MacRuby/branches/experimental/mspec/bin/mspec-tag.bat
===================================================================
--- MacRuby/branches/experimental/mspec/bin/mspec-tag.bat (rev 0)
+++ MacRuby/branches/experimental/mspec/bin/mspec-tag.bat 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1 @@
+@"ruby.exe" "%~dpn0" %*
Added: MacRuby/branches/experimental/mspec/bin/mspec.bat
===================================================================
--- MacRuby/branches/experimental/mspec/bin/mspec.bat (rev 0)
+++ MacRuby/branches/experimental/mspec/bin/mspec.bat 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1 @@
+@"ruby.exe" "%~dpn0" %*
Added: MacRuby/branches/experimental/mspec/lib/mspec/commands/mkspec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/commands/mkspec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/commands/mkspec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,140 @@
+#! /usr/bin/env ruby
+
+MSPEC_HOME = File.expand_path(File.dirname(__FILE__) + '/../../..')
+
+require 'fileutils'
+require 'rbconfig'
+require 'mspec/version'
+require 'mspec/utils/options'
+require 'mspec/utils/name_map'
+
+
+class MkSpec
+ attr_reader :config
+
+ def initialize
+ @config = {
+ :constants => [],
+ :requires => [],
+ :base => "spec/ruby/1.8/core"
+ }
+ @map = NameMap.new
+ end
+
+ def options(argv=ARGV)
+ options = MSpecOptions.new "mkspec [options]"
+
+ options.on("-c", "--constant", "CONSTANT",
+ "Class or Module to generate spec stubs for") do |name|
+ config[:constants] << name
+ end
+ options.on("-b", "--base", "DIR",
+ "Directory to generate specs into") do |directory|
+ config[:base] = File.expand_path directory
+ end
+ options.on("-r", "--require", "LIBRARY",
+ "A library to require") do |file|
+ config[:requires] << file
+ end
+ options.version MSpec::VERSION
+ options.help
+
+ options.doc "\n How might this work in the real world?\n"
+ options.doc " 1. To create spec stubs for every class or module in Object\n"
+ options.doc " $ mkspec\n"
+ options.doc " 2. To create spec stubs for Fixnum\n"
+ options.doc " $ mkspec -c Fixnum\n"
+ options.doc " 3. To create spec stubs for Complex in 'superspec/complex'\n"
+ options.doc " $ mkspec -c Complex -rcomplex -b superspec"
+ options.doc ""
+
+ options.parse argv
+ end
+
+ def create_directory(mod)
+ subdir = @map.dir_name mod, config[:base]
+
+ if File.exist? subdir
+ unless File.directory? subdir
+ puts "#{subdir} already exists and is not a directory."
+ return nil
+ end
+ else
+ FileUtils.mkdir_p subdir
+ end
+
+ subdir
+ end
+
+ def write_requires(dir, file)
+ /\A#{Regexp.escape config[:base]}\/?(.*)/ =~ dir
+ parents = '../' * ($1.split('/').length + 1)
+
+ File.open file, 'w' do |f|
+ f.puts "require File.dirname(__FILE__) + '/#{parents}spec_helper'"
+ config[:requires].each do |lib|
+ f.puts "require '#{lib}'"
+ end
+ end
+ end
+
+ def write_spec(file, meth, exists)
+ if exists
+ out = `#{ruby} #{MSPEC_HOME}/bin/mspec-run --dry-run -fs -e '#{meth}' #{file}`
+ return if out =~ /#{Regexp.escape meth}/
+ end
+
+ File.open file, 'a' do |f|
+ f.puts <<-EOS
+
+describe "#{meth}" do
+ it "needs to be reviewed for spec completeness"
+end
+EOS
+ end
+
+ puts file
+ end
+
+ def create_file(dir, mod, meth, name)
+ file = File.join dir, @map.file_name(meth, mod)
+ exists = File.exist? file
+
+ write_requires dir, file unless exists
+ write_spec file, name, exists
+ end
+
+ def run
+ config[:requires].each { |lib| require lib }
+ constants = config[:constants]
+ constants = @map.filter(Object.constants) if constants.empty?
+
+ @map.map({}, constants).each do |mod, methods|
+ name = mod.chop
+ next unless dir = create_directory(name)
+
+ methods.each { |method| create_file dir, name, method, mod + method }
+ end
+ end
+
+ ##
+ # Determine and return the path of the ruby executable.
+
+ def ruby
+ ruby = File.join(Config::CONFIG['bindir'],
+ Config::CONFIG['ruby_install_name'])
+
+ ruby.gsub! File::SEPARATOR, File::ALT_SEPARATOR if File::ALT_SEPARATOR
+
+ return ruby
+ end
+
+ def self.main
+ ENV['MSPEC_RUNNER'] = '1'
+
+ script = new
+ script.options
+ script.run
+ end
+end
+
Added: MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec-ci.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec-ci.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec-ci.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,75 @@
+#!/usr/bin/env ruby
+
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
+
+require 'mspec/version'
+require 'mspec/utils/options'
+require 'mspec/utils/script'
+
+
+class MSpecCI < MSpecScript
+ def options(argv=ARGV)
+ options = MSpecOptions.new "mspec ci [options] (FILE|DIRECTORY|GLOB)+", 30, config
+
+ options.doc " Ask yourself:"
+ options.doc " 1. How to run the specs?"
+ options.doc " 2. How to modify the guard behavior?"
+ options.doc " 2. How to display the output?"
+ options.doc " 3. What action to perform?"
+ options.doc " 4. When to perform it?"
+
+ options.doc "\n How to run the specs"
+ options.chdir
+ options.prefix
+ options.configure { |f| load f }
+ options.name
+ options.pretend
+ options.background
+ options.interrupt
+
+ options.doc "\n How to modify the guard behavior"
+ options.unguarded
+ options.verify
+
+ options.doc "\n How to display their output"
+ options.formatters
+ options.verbose
+
+ options.doc "\n What action to perform"
+ options.actions
+
+ options.doc "\n When to perform it"
+ options.action_filters
+
+ options.doc "\n Help!"
+ options.version MSpec::VERSION
+ options.help
+
+ options.doc "\n Custom options"
+ custom_options options
+
+ options.doc "\n How might this work in the real world?"
+ options.doc "\n 1. To simply run the known good specs"
+ options.doc "\n $ mspec ci"
+ options.doc "\n 2. To run a subset of the known good specs"
+ options.doc "\n $ mspec ci path/to/specs"
+ options.doc "\n 3. To start the debugger before the spec matching 'this crashes'"
+ options.doc "\n $ mspec ci --spec-debug -S 'this crashes'"
+ options.doc ""
+
+ patterns = options.parse argv
+ patterns = config[:ci_files] if patterns.empty?
+ @files = files patterns
+ end
+
+ def run
+ MSpec.register_tags_patterns config[:tags_patterns]
+ MSpec.register_files @files
+ filter = TagFilter.new(:exclude,
+ "fails", "critical", "unstable", "incomplete", "unsupported")
+ filter.register
+
+ MSpec.process
+ exit MSpec.exit_code
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec-run.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec-run.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec-run.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,90 @@
+#!/usr/bin/env ruby
+
+$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
+
+require 'mspec/version'
+require 'mspec/utils/options'
+require 'mspec/utils/script'
+
+
+class MSpecRun < MSpecScript
+ def initialize
+ super
+
+ config[:files] = []
+ end
+
+ def options(argv=ARGV)
+ options = MSpecOptions.new "mspec run [options] (FILE|DIRECTORY|GLOB)+", 30, config
+
+ options.doc " Ask yourself:"
+ options.doc " 1. What specs to run?"
+ options.doc " 2. How to modify the execution?"
+ options.doc " 3. How to modify the guard behavior?"
+ options.doc " 4. How to display the output?"
+ options.doc " 5. What action to perform?"
+ options.doc " 6. When to perform it?"
+
+ options.doc "\n What specs to run"
+ options.filters
+
+ options.doc "\n How to modify the execution"
+ options.chdir
+ options.prefix
+ options.configure { |f| load f }
+ options.name
+ options.randomize
+ options.pretend
+ options.background
+ options.interrupt
+
+ options.doc "\n How to modify the guard behavior"
+ options.unguarded
+ options.verify
+
+ options.doc "\n How to display their output"
+ options.formatters
+ options.verbose
+
+ options.doc "\n What action to perform"
+ options.actions
+
+ options.doc "\n When to perform it"
+ options.action_filters
+
+ options.doc "\n Help!"
+ options.version MSpec::VERSION
+ options.help
+
+ options.doc "\n Custom options"
+ custom_options options
+
+ options.doc "\n How might this work in the real world?"
+ options.doc "\n 1. To simply run some specs"
+ options.doc "\n $ mspec path/to/the/specs"
+ options.doc " mspec path/to/the_file_spec.rb"
+ options.doc "\n 2. To run specs tagged with 'fails'"
+ options.doc "\n $ mspec -g fails path/to/the_file_spec.rb"
+ options.doc "\n 3. To start the debugger before the spec matching 'this crashes'"
+ options.doc "\n $ mspec --spec-debug -S 'this crashes' path/to/the_file_spec.rb"
+ options.doc ""
+
+ patterns = options.parse argv
+ patterns = config[:files] if patterns.empty?
+ if patterns.empty?
+ puts options
+ puts "No files specified."
+ exit 1
+ end
+ @files = files patterns
+ end
+
+ def run
+ MSpec.register_tags_patterns config[:tags_patterns]
+ MSpec.register_files @files
+
+ MSpec.process
+ exit MSpec.exit_code
+ end
+end
+
Added: MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec-tag.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec-tag.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec-tag.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,130 @@
+#!/usr/bin/env ruby
+
+require 'mspec/version'
+require 'mspec/utils/options'
+require 'mspec/utils/script'
+
+
+class MSpecTag < MSpecScript
+ def initialize
+ super
+
+ config[:tagger] = :add
+ config[:tag] = 'fails:'
+ config[:outcome] = :fail
+ config[:ltags] = []
+ end
+
+ def options(argv=ARGV)
+ options = MSpecOptions.new "mspec tag [options] (FILE|DIRECTORY|GLOB)+", 30, config
+
+ options.doc " Ask yourself:"
+ options.doc " 1. What specs to run?"
+ options.doc " 2. How to modify the execution?"
+ options.doc " 3. How to display the output?"
+ options.doc " 4. What tag action to perform?"
+ options.doc " 5. When to perform it?"
+
+ options.doc "\n What specs to run"
+ options.filters
+
+ options.doc "\n How to modify the execution"
+ options.configure { |f| load f }
+ options.name
+ options.pretend
+ options.unguarded
+ options.interrupt
+
+ options.doc "\n How to display their output"
+ options.formatters
+ options.verbose
+
+ options.doc "\n What action to perform and when to perform it"
+ options.on("-N", "--add", "TAG",
+ "Add TAG with format 'tag' or 'tag(comment)' (see -Q, -F, -L)") do |o|
+ config[:tagger] = :add
+ config[:tag] = "#{o}:"
+ end
+ options.on("-R", "--del", "TAG",
+ "Delete TAG (see -Q, -F, -L)") do |o|
+ config[:tagger] = :del
+ config[:tag] = "#{o}:"
+ config[:outcome] = :pass
+ end
+ options.on("-Q", "--pass", "Apply action to specs that pass (default for --del)") do
+ config[:outcome] = :pass
+ end
+ options.on("-F", "--fail", "Apply action to specs that fail (default for --add)") do
+ config[:outcome] = :fail
+ end
+ options.on("-L", "--all", "Apply action to all specs") do
+ config[:outcome] = :all
+ end
+ options.on("--list", "TAG", "Display descriptions of any specs tagged with TAG") do |t|
+ config[:tagger] = :list
+ config[:ltags] << t
+ end
+ options.on("--list-all", "Display descriptions of any tagged specs") do
+ config[:tagger] = :list_all
+ end
+ options.on("--purge", "Remove all tags not matching any specs") do
+ config[:tagger] = :purge
+ end
+
+ options.doc "\n Help!"
+ options.version MSpec::VERSION
+ options.help
+
+ options.doc "\n Custom options"
+ custom_options options
+
+ options.doc "\n How might this work in the real world?"
+ options.doc "\n 1. To add the 'fails' tag to failing specs"
+ options.doc "\n $ mspec tag path/to/the_file_spec.rb"
+ options.doc "\n 2. To remove the 'fails' tag from passing specs"
+ options.doc "\n $ mspec tag --del fails path/to/the_file_spec.rb"
+ options.doc "\n 3. To display the descriptions for all specs tagged with 'fails'"
+ options.doc "\n $ mspec tag --list fails path/to/the/specs"
+ options.doc ""
+
+ patterns = options.parse argv
+ if patterns.empty?
+ puts options
+ puts "No files specified."
+ exit 1
+ end
+ @files = files patterns
+ end
+
+ def register
+ case config[:tagger]
+ when :add, :del
+ tag = SpecTag.new config[:tag]
+ tagger = TagAction.new(config[:tagger], config[:outcome], tag.tag, tag.comment,
+ config[:atags], config[:astrings])
+ when :list, :list_all
+ tagger = TagListAction.new config[:tagger] == :list_all ? nil : config[:ltags]
+ MSpec.register_mode :pretend
+ config[:formatter] = false
+ when :purge
+ tagger = TagPurgeAction.new
+ MSpec.register_mode :pretend
+ MSpec.register_mode :unguarded
+ config[:formatter] = false
+ else
+ raise ArgumentError, "No recognized action given"
+ end
+ tagger.register
+
+ super
+ end
+
+ def run
+ MSpec.register_tags_patterns config[:tags_patterns]
+ MSpec.register_files @files
+
+ MSpec.process
+ exit MSpec.exit_code
+ end
+end
+
Added: MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/commands/mspec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,157 @@
+#!/usr/bin/env ruby
+
+MSPEC_HOME = File.expand_path(File.dirname(__FILE__) + '/../../..')
+
+require 'mspec/version'
+require 'mspec/utils/options'
+require 'mspec/utils/script'
+require 'mspec/helpers/tmp'
+require 'mspec/runner/actions/timer'
+
+
+class MSpecMain < MSpecScript
+ def initialize
+ config[:includes] = []
+ config[:requires] = []
+ config[:target] = ENV['RUBY'] || 'ruby'
+ config[:flags] = []
+ config[:command] = nil
+ config[:options] = []
+ end
+
+ def options(argv=ARGV)
+ config[:command] = argv.shift if ["ci", "run", "tag"].include?(argv[0])
+
+ options = MSpecOptions.new "mspec [COMMAND] [options] (FILE|DIRECTORY|GLOB)+", 30, config
+
+ options.doc " The mspec command sets up and invokes the sub-commands"
+ options.doc " (see below) to enable, for instance, running the specs"
+ options.doc " with different implementations like ruby, jruby, rbx, etc.\n"
+
+ options.configure do |f|
+ load f
+ config[:options] << '-B' << f
+ end
+
+ options.targets
+
+ options.on("-D", "--gdb", "Run under gdb") do
+ config[:flags] << '--gdb'
+ end
+ options.on("-A", "--valgrind", "Run under valgrind") do
+ config[:flags] << '--valgrind'
+ end
+ options.on("--warnings", "Don't supress warnings") do
+ config[:flags] << '-w'
+ ENV['OUTPUT_WARNINGS'] = '1'
+ end
+ options.on("-j", "--multi", "Run multiple (possibly parallel) subprocesses") do
+ config[:multi] = true
+ config[:options] << "-fy"
+ end
+ options.version MSpec::VERSION do
+ if config[:command]
+ config[:options] << "-v"
+ else
+ puts "#{File.basename $0} #{MSpec::VERSION}"
+ exit
+ end
+ end
+ options.help do
+ if config[:command]
+ config[:options] << "-h"
+ else
+ puts options
+ exit 1
+ end
+ end
+
+ options.doc "\n Custom options"
+ custom_options options
+
+ # The rest of the help output
+ options.doc "\n where COMMAND is one of:\n"
+ options.doc " run - Run the specified specs (default)"
+ options.doc " ci - Run the known good specs"
+ options.doc " tag - Add or remove tags\n"
+ options.doc " mspec COMMAND -h for more options\n"
+
+ options.on_extra { |o| config[:options] << o }
+ config[:options].concat options.parse(argv)
+ end
+
+ def register; end
+
+ def parallel
+ @parallel ||= !(Object.const_defined?(:JRUBY_VERSION) ||
+ /(mswin|mingw)/ =~ RUBY_PLATFORM)
+ end
+
+ def fork(&block)
+ parallel ? Kernel.fork(&block) : block.call
+ end
+
+ def report(files, timer)
+ require 'yaml'
+
+ exceptions = []
+ tally = Tally.new
+
+ files.each do |file|
+ d = File.open(file, "r") { |f| YAML.load f }
+ File.delete file
+
+ exceptions += Array(d['exceptions'])
+ tally.files! d['files']
+ tally.examples! d['examples']
+ tally.expectations! d['expectations']
+ tally.errors! d['errors']
+ tally.failures! d['failures']
+ end
+
+ print "\n"
+ exceptions.each_with_index do |exc, index|
+ print "\n#{index+1})\n", exc, "\n"
+ end
+ print "\n#{timer.format}\n\n#{tally.format}\n"
+ end
+
+ def multi_exec(argv)
+ timer = TimerAction.new
+ timer.start
+
+ files = config[:ci_files].inject([]) do |list, item|
+ name = tmp "mspec-ci-multi-#{list.size}"
+
+ rest = argv + ["-o", name, item]
+ fork { system [config[:target], *rest].join(" ") }
+
+ list << name
+ end
+
+ Process.waitall
+ timer.finish
+ report files, timer
+ end
+
+ def run
+ ENV['MSPEC_RUNNER'] = '1'
+ ENV['RUBY_EXE'] = config[:target]
+ ENV['RUBY_FLAGS'] = config[:flags].join " "
+
+ argv = []
+ argv.concat config[:flags]
+ argv.concat config[:includes]
+ argv.concat config[:requires]
+ argv << "-v"
+ argv << "#{MSPEC_HOME}/bin/mspec-#{ config[:command] || "run" }"
+ argv.concat config[:options]
+
+ if config[:multi] and config[:command] == "ci"
+ multi_exec argv
+ else
+ exec config[:target], *argv
+ end
+ end
+end
+
Added: MacRuby/branches/experimental/mspec/lib/mspec/expectations/expectations.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/expectations/expectations.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/expectations/expectations.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,17 @@
+class ExpectationNotMetError < StandardError; end
+class ExpectationNotFoundError < StandardError
+ def message
+ "No behavior expectation was found in the example"
+ end
+end
+
+class Expectation
+ def self.fail_with(expected, actual)
+ if expected.to_s.size + actual.to_s.size > 80
+ message = expected.to_s.chomp + "\n" + actual.to_s
+ else
+ message = expected.to_s + " " + actual.to_s
+ end
+ Kernel.raise ExpectationNotMetError, message
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/expectations/should.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/expectations/should.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/expectations/should.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,25 @@
+class Object
+ def should(matcher=nil)
+ MSpec.expectation
+ MSpec.actions :expectation, MSpec.current.state
+ if matcher
+ unless matcher.matches?(self)
+ Expectation.fail_with(*matcher.failure_message)
+ end
+ else
+ PositiveOperatorMatcher.new(self)
+ end
+ end
+
+ def should_not(matcher=nil)
+ MSpec.expectation
+ MSpec.actions :expectation, MSpec.current.state
+ if matcher
+ if matcher.matches?(self)
+ Expectation.fail_with(*matcher.negative_failure_message)
+ end
+ else
+ NegativeOperatorMatcher.new(self)
+ end
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/expectations.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/expectations.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/expectations.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,2 @@
+require 'mspec/expectations/expectations'
+require 'mspec/expectations/should'
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/background.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/background.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/background.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,21 @@
+require 'mspec/guards/guard'
+
+# Some specs, notably those for Readline, will block under certain
+# circumstances when run as background or subprocesses. Use this guard for
+# such specs.
+
+class BackgroundGuard < SpecGuard
+ def match?
+ MSpec.mode? :background
+ end
+end
+
+class Object
+ def process_is_foreground
+ g = BackgroundGuard.new
+ g.name = :process_is_foreground
+ yield if g.yield? true
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/bug.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/bug.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/bug.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,24 @@
+require 'mspec/guards/version'
+
+class BugGuard < VersionGuard
+ def initialize(bug, version)
+ @bug = bug
+ @version = SpecVersion.new version, true
+ self.parameters = [@bug, @version]
+ end
+
+ def match?
+ return false if MSpec.mode? :no_ruby_bug
+ standard? && ruby_version <= @version
+ end
+end
+
+class Object
+ def ruby_bug(bug, version)
+ g = BugGuard.new bug, version
+ g.name = :ruby_bug
+ yield if g.yield? true
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/compliance.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/compliance.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/compliance.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,37 @@
+require 'mspec/guards/guard'
+
+class CompliantOnGuard < SpecGuard
+ def match?
+ if @args.include? :ruby
+ raise Exception, "improper use of compliant_on guard"
+ end
+ standard? or implementation?(*@args)
+ end
+end
+
+class NotCompliantOnGuard < SpecGuard
+ def match?
+ if @args.include? :ruby
+ raise Exception, "improper use of not_compliant_on guard"
+ end
+ standard? or !implementation?(*@args)
+ end
+end
+
+class Object
+ def compliant_on(*args)
+ g = CompliantOnGuard.new(*args)
+ g.name = :compliant_on
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+
+ def not_compliant_on(*args)
+ g = NotCompliantOnGuard.new(*args)
+ g.name = :not_compliant_on
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/conflict.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/conflict.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/conflict.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,18 @@
+require 'mspec/guards/guard'
+
+class ConflictsGuard < SpecGuard
+ def match?
+ constants = Object.constants
+ @args.any? { |mod| constants.include? mod.to_s }
+ end
+end
+
+class Object
+ def conflicts_with(*modules)
+ g = ConflictsGuard.new(*modules)
+ g.name = :conflicts_with
+ yield if g.yield? true
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/endian.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/endian.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/endian.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,44 @@
+require 'mspec/guards/guard'
+
+# Despite that these are inverses, the two classes are
+# used to simplify MSpec guard reporting modes
+
+class BigEndianGuard < SpecGuard
+ def pattern
+ [1].pack('L')
+ end
+ private :pattern
+
+ def match?
+ pattern[-1] == ?\001
+ end
+end
+
+class LittleEndianGuard < SpecGuard
+ def pattern
+ [1].pack('L')
+ end
+ private :pattern
+
+ def match?
+ pattern[-1] == ?\000
+ end
+end
+
+class Object
+ def big_endian
+ g = BigEndianGuard.new
+ g.name = :big_endian
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+
+ def little_endian
+ g = LittleEndianGuard.new
+ g.name = :little_endian
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/extensions.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/extensions.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/extensions.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,20 @@
+require 'mspec/guards/guard'
+
+class ExtensionsGuard < SpecGuard
+ def match?
+ if @args.include? :ruby
+ raise Exception, "improper use of extended_on guard"
+ end
+ !standard? and implementation?(*@args)
+ end
+end
+
+class Object
+ def extended_on(*args)
+ g = ExtensionsGuard.new(*args)
+ g.name = :extended_on
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/guard.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/guard.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/guard.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,166 @@
+require 'mspec/runner/mspec'
+require 'mspec/runner/actions/tally'
+
+class SpecGuard
+ def self.report
+ @report ||= Hash.new { |h,k| h[k] = [] }
+ end
+
+ def self.clear
+ @report = nil
+ end
+
+ def self.finish
+ report.keys.sort.each do |key|
+ desc = report[key]
+ size = desc.size
+ spec = size == 1 ? "spec" : "specs"
+ print "\n\n#{size} #{spec} omitted by guard: #{key}:\n"
+ desc.each { |description| print "\n", description; }
+ end
+
+ print "\n\n"
+ end
+
+ def self.guards
+ @guards ||= []
+ end
+
+ def self.clear_guards
+ @guards = []
+ end
+
+ # Returns a partial Ruby version string based on +which+. For example,
+ # if RUBY_VERSION = 8.2.3 and RUBY_PATCHLEVEL = 71:
+ #
+ # :major => "8"
+ # :minor => "8.2"
+ # :tiny => "8.2.3"
+ # :teeny => "8.2.3"
+ # :full => "8.2.3.71"
+ def self.ruby_version(which = :minor)
+ case which
+ when :major
+ n = 1
+ when :minor
+ n = 2
+ when :tiny, :teeny
+ n = 3
+ else
+ n = 4
+ end
+
+ patch = RUBY_PATCHLEVEL.to_i
+ patch = 0 if patch < 0
+ version = "#{RUBY_VERSION}.#{patch}"
+ version.split('.')[0,n].join('.')
+ end
+
+ def self.windows?(key = RUBY_PLATFORM)
+ !!key.match(/(mswin|mingw)/)
+ end
+
+ attr_accessor :name, :parameters
+
+ def initialize(*args)
+ self.parameters = @args = args
+ end
+
+ def yield?(invert=false)
+ return true if MSpec.mode? :unguarded
+
+ allow = match? ^ invert
+
+ if not allow and reporting?
+ MSpec.guard
+ MSpec.register :finish, SpecGuard
+ MSpec.register :add, self
+ return true
+ elsif MSpec.mode? :verify
+ return true
+ end
+
+ allow
+ end
+
+ def ===(other)
+ true
+ end
+
+ def reporting?
+ MSpec.mode?(:report) or
+ (MSpec.mode?(:report_on) and SpecGuard.guards.include?(name))
+ end
+
+ def report_key
+ "#{name} #{parameters.join(", ")}"
+ end
+
+ def record(description)
+ SpecGuard.report[report_key] << description
+ end
+
+ def add(example)
+ record example.description
+ MSpec.retrieve(:formatter).tally.counter.guards!
+ end
+
+ def unregister
+ MSpec.unguard
+ MSpec.unregister :add, self
+ end
+
+ def implementation?(*args)
+ args.any? do |name|
+ !!case name
+ when :rubinius
+ RUBY_NAME =~ /^rbx/
+ when :ruby
+ RUBY_NAME =~ /^ruby/
+ when :jruby
+ RUBY_NAME =~ /^jruby/
+ when :ironruby
+ RUBY_NAME =~ /^ironruby/
+ when :macruby
+ RUBY_NAME =~ /^macruby/
+ else
+ false
+ end
+ end
+ end
+
+ def standard?
+ implementation? :ruby
+ end
+
+ def windows?(sym, key)
+ sym == :windows && SpecGuard.windows?(key)
+ end
+
+ def platform?(*args)
+ args.any? do |platform|
+ if platform != :java && RUBY_PLATFORM.match('java') && os?(platform)
+ true
+ else
+ RUBY_PLATFORM.match(platform.to_s) || windows?(platform, RUBY_PLATFORM)
+ end
+ end
+ end
+
+ def wordsize?(size)
+ size == 8 * 1.size
+ end
+
+ def os?(*oses)
+ require 'rbconfig'
+ oses.any? do |os|
+ host_os = Config::CONFIG['host_os'] || RUBY_PLATFORM
+ host_os.downcase!
+ host_os.match(os.to_s) || windows?(os, host_os)
+ end
+ end
+
+ def match?
+ implementation?(*@args) or platform?(*@args)
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/noncompliance.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/noncompliance.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/noncompliance.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,20 @@
+require 'mspec/guards/guard'
+
+class NonComplianceGuard < SpecGuard
+ def match?
+ if @args.include? :ruby
+ raise Exception, "improper use of deviates_on guard"
+ end
+ !standard? and implementation?(*@args)
+ end
+end
+
+class Object
+ def deviates_on(*args)
+ g = NonComplianceGuard.new(*args)
+ g.name = :deviates_on
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/platform.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/platform.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/platform.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,43 @@
+require 'mspec/guards/guard'
+
+class PlatformGuard < SpecGuard
+ def initialize(*args)
+ if args.last.is_a?(Hash)
+ @options, @platforms = args.last, args[0..-2]
+ else
+ @options, @platforms = {}, args
+ end
+ self.parameters = args
+ end
+
+ def match?
+ match = @platforms.empty? ? true : platform?(*@platforms)
+ @options.each do |key, value|
+ case key
+ when :os
+ match &&= os?(*value)
+ when :wordsize
+ match &&= wordsize? value
+ end
+ end
+ match
+ end
+end
+
+class Object
+ def platform_is(*args)
+ g = PlatformGuard.new(*args)
+ g.name = :platform_is
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+
+ def platform_is_not(*args)
+ g = PlatformGuard.new(*args)
+ g.name = :platform_is_not
+ yield if g.yield? true
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/quarantine.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/quarantine.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/quarantine.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,17 @@
+require 'mspec/guards/guard'
+
+class QuarantineGuard < SpecGuard
+ def match?
+ false
+ end
+end
+
+class Object
+ def quarantine!
+ g = QuarantineGuard.new
+ g.name = :quarantine!
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/runner.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/runner.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/runner.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,34 @@
+require 'mspec/guards/guard'
+
+class RunnerGuard < SpecGuard
+ def match?
+ @args.any? do |runner|
+ case runner
+ when :mspec
+ ENV['MSPEC_RUNNER'] == '1'
+ when :rspec
+ ENV['RSPEC_RUNNER'] == '1' or Object.const_defined?(:Spec)
+ else
+ false
+ end
+ end
+ end
+end
+
+class Object
+ def runner_is(*args)
+ g = RunnerGuard.new(*args)
+ g.name = :runner_is
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+
+ def runner_is_not(*args)
+ g = RunnerGuard.new(*args)
+ g.name = :runner_is_not
+ yield if g.yield? true
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/superuser.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/superuser.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/superuser.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,17 @@
+require 'mspec/guards/guard'
+
+class SuperUserGuard < SpecGuard
+ def match?
+ Process.euid == 0
+ end
+end
+
+class Object
+ def as_superuser
+ g = SuperUserGuard.new
+ g.name = :as_superuser
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/support.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/support.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/support.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,20 @@
+require 'mspec/guards/guard'
+
+class SupportedGuard < SpecGuard
+ def match?
+ if @args.include? :ruby
+ raise Exception, "improper use of not_supported_on guard"
+ end
+ standard? or !implementation?(*@args)
+ end
+end
+
+class Object
+ def not_supported_on(*args)
+ g = SupportedGuard.new(*args)
+ g.name = :not_supported_on
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/tty.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/tty.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/tty.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,20 @@
+require 'mspec/guards/guard'
+
+# If a spec depends on STDOUT being a tty, use this guard. For specs that may
+# block if run as a background process, see BackgroundGuard.
+
+class TTYGuard < SpecGuard
+ def match?
+ STDOUT.tty?
+ end
+end
+
+class Object
+ def with_tty
+ g = TTYGuard.new
+ g.name = :with_tty
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards/version.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards/version.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards/version.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,38 @@
+require 'mspec/utils/version'
+require 'mspec/guards/guard'
+
+class VersionGuard < SpecGuard
+ def initialize(version)
+ case version
+ when String
+ @version = SpecVersion.new version
+ when Range
+ a = SpecVersion.new version.first
+ b = SpecVersion.new version.last
+ @version = version.exclude_end? ? a...b : a..b
+ end
+ self.parameters = [version]
+ end
+
+ def ruby_version
+ @ruby_version ||= SpecVersion.new self.class.ruby_version(:full)
+ end
+
+ def match?
+ if Range === @version
+ @version.include? ruby_version
+ else
+ ruby_version >= @version
+ end
+ end
+end
+
+class Object
+ def ruby_version_is(*args)
+ g = VersionGuard.new(*args)
+ g.name = :ruby_version_is
+ yield if g.yield?
+ ensure
+ g.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/guards.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/guards.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/guards.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,16 @@
+require 'mspec/utils/ruby_name'
+require 'mspec/guards/background'
+require 'mspec/guards/bug'
+require 'mspec/guards/compliance'
+require 'mspec/guards/conflict'
+require 'mspec/guards/endian'
+require 'mspec/guards/extensions'
+require 'mspec/guards/guard'
+require 'mspec/guards/noncompliance'
+require 'mspec/guards/platform'
+require 'mspec/guards/quarantine'
+require 'mspec/guards/runner'
+require 'mspec/guards/support'
+require 'mspec/guards/superuser'
+require 'mspec/guards/tty'
+require 'mspec/guards/version'
Added: MacRuby/branches/experimental/mspec/lib/mspec/helpers/argv.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/helpers/argv.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/helpers/argv.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,43 @@
+class Object
+ # Convenience helper for altering ARGV. Saves the
+ # value of ARGV and sets it to +args+. If a block
+ # is given, yields to the block and then restores
+ # the value of ARGV. The previously saved value of
+ # ARGV can be restored by passing +:restore+. The
+ # former is useful in a single spec. The latter is
+ # useful in before/after actions. For example:
+ #
+ # describe "This" do
+ # before do
+ # argv ['a', 'b']
+ # end
+ #
+ # after do
+ # argv :restore
+ # end
+ #
+ # it "does something" do
+ # # do something
+ # end
+ # end
+ #
+ # describe "That" do
+ # it "does something" do
+ # argv ['a', 'b'] do
+ # # do something
+ # end
+ # end
+ # end
+ def argv(args)
+ if args == :restore
+ ARGV.replace(@__mspec_saved_argv__ || [])
+ else
+ @__mspec_saved_argv__ = ARGV
+ ARGV.replace args
+ if block_given?
+ yield
+ argv :restore
+ end
+ end
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/helpers/bignum.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/helpers/bignum.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/helpers/bignum.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,5 @@
+class Object
+ def bignum_value(plus=0)
+ 0x8000_0000_0000_0000 + plus
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/helpers/const_lookup.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/helpers/const_lookup.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/helpers/const_lookup.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,9 @@
+module Kernel
+ def const_lookup(c)
+ names = c.split '::'
+ names.shift if names.first.empty?
+ names.inject(Object) do |m, n|
+ m.const_defined?(n) ? m.const_get(n) : m.const_missing(n)
+ end
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/helpers/environment.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/helpers/environment.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/helpers/environment.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,23 @@
+require 'mspec/guards/guard'
+
+class Object
+ def env
+ env = ""
+ if SpecGuard.windows?
+ env = Hash[*`cmd.exe /C set`.split("\n").map { |e| e.split("=", 2) }.flatten]
+ else
+ env = Hash[*`env`.split("\n").map { |e| e.split("=", 2) }.flatten]
+ end
+ env
+ end
+
+ def username
+ user = ""
+ if SpecGuard.windows?
+ user = `cmd.exe /C ECHO %USERNAME%`.strip
+ else
+ user = `whoami`.strip
+ end
+ user
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/helpers/fixture.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/helpers/fixture.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/helpers/fixture.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,20 @@
+class Object
+ # Returns the name of a fixture file by adjoining the directory
+ # of the +dir+ argument with "fixtures" and the contents of the
+ # +args+ array. For example,
+ #
+ # +dir+ == "some/path"
+ #
+ # and
+ #
+ # +args+ == ["dir", "file.txt"]
+ #
+ # then the result is the expanded path of
+ #
+ # "some/fixtures/dir/file.txt".
+ def fixture(dir, *args)
+ path = File.dirname(dir)
+ path = path[0..-7] if path[-7..-1] == "/shared"
+ File.expand_path(File.join(path, "fixtures", args))
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/helpers/flunk.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/helpers/flunk.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/helpers/flunk.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,5 @@
+class Object
+ def flunk(msg="This example is a failure")
+ Expectation.fail_with "Failed:", msg
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/helpers/io.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/helpers/io.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/helpers/io.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,17 @@
+class IOStub < String
+ def write(*str)
+ self << str.to_s
+ end
+
+ def print(*str)
+ write(str.to_s + $\.to_s)
+ end
+
+ def puts(*str)
+ write(str.collect { |s| s.to_s.chomp }.concat([nil]).join("\n"))
+ end
+
+ def flush
+ self
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/helpers/language_version.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/helpers/language_version.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/helpers/language_version.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,20 @@
+require 'mspec/guards/guard'
+
+class Object
+ # Helper for syntax-sensitive specs. The specs should be placed in a file in
+ # the +versions+ subdirectory. For example, suppose language/method_spec.rb
+ # contains specs whose syntax depends on the Ruby version. In the
+ # language/method_spec.rb use the helper as follows:
+ #
+ # language_version __FILE__, "method"
+ #
+ # Then add a file "language/versions/method_1.8.rb" for the specs that are
+ # syntax-compatible with Ruby 1.8.x.
+ def language_version(dir, name)
+ path = File.dirname(File.expand_path(dir))
+ name = "#{name}_#{SpecGuard.ruby_version}.rb"
+ file = File.join path, "versions", name
+
+ require file if File.exists? file
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/helpers/ruby_exe.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/helpers/ruby_exe.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/helpers/ruby_exe.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,123 @@
+require 'mspec/utils/ruby_name'
+require 'mspec/guards/guard'
+
+# The ruby_exe helper provides a wrapper for invoking the
+# same Ruby interpreter as the one running the specs and
+# getting the output from running the code. If +code+ is a
+# file that exists, it will be run. Otherwise, +code+ should
+# be Ruby code that will be run with the -e command line
+# option. For example:
+#
+# ruby_exe('path/to/some/file.rb')
+#
+# will be executed as
+#
+# `#{RUBY_EXE} #{'path/to/some/file.rb'}`
+#
+# while
+#
+# ruby_exe('puts "hello, world."')
+#
+# will be executed as
+#
+# `#{RUBY_EXE} -e #{'puts "hello, world."'}`
+#
+# The ruby_exe helper also accepts an options hash with two
+# keys: :options and :args. For example:
+#
+# ruby_exe('file.rb', :options => "-w", :args => "> file.txt")
+#
+# will be executed as
+#
+# `#{RUBY_EXE} -w #{'file.rb'} > file.txt`
+#
+# If +nil+ is passed for the first argument, the command line
+# will be built only from the options hash.
+#
+# The RUBY_EXE constant can be set explicitly since the value
+# is used each time ruby_exe is invoked. The mspec runner script
+# will set ENV['RUBY_EXE'] to the name of the executable used
+# to invoke the mspec-run script. The value of RUBY_EXE will be
+# constructed as follows:
+#
+# 1. the value of ENV['RUBY_EXE']
+# 2. an explicit value based on RUBY_NAME
+# 3. cwd/(RUBY_NAME + $(EXEEXT) || $(exeext) || '')
+# 4. $(bindir)/$(RUBY_INSTALL_NAME)
+#
+# The value will only be used if the file exists and is executable.
+#
+# These 4 ways correspond to the following scenarios:
+#
+# 1. Using the MSpec runner scripts, the name of the
+# executable is explicitly passed by ENV['RUBY_EXE']
+# so there is no ambiguity.
+#
+# Otherwise, if using RSpec (or something else)
+#
+# 2. Running the specs while developing an alternative
+# Ruby implementation. This explicitly names the
+# executable in the development directory based on
+# the value of RUBY_NAME, which is probably initialized
+# from the value of RUBY_ENGINE.
+# 3. Running the specs within the source directory for
+# some implementation. (E.g. a local build directory.)
+# 4. Running the specs against some installed Ruby
+# implementation.
+
+class Object
+ def ruby_exe_options(option)
+ case option
+ when :env
+ ENV['RUBY_EXE']
+ when :engine
+ case RUBY_NAME
+ when 'rbx'
+ "bin/rbx"
+ when 'jruby'
+ "bin/jruby"
+ when 'ironruby'
+ "ir"
+ end
+ when :name
+ bin = RUBY_NAME + (Config::CONFIG['EXEEXT'] || Config::CONFIG['exeext'] || '')
+ File.join(".", bin)
+ when :install_name
+ bin = Config::CONFIG["RUBY_INSTALL_NAME"] || Config::CONFIG["ruby_install_name"]
+ bin << (Config::CONFIG['EXEEXT'] || Config::CONFIG['exeext'] || '')
+ File.join(Config::CONFIG['bindir'], bin)
+ end
+ end
+
+ def resolve_ruby_exe
+ [:env, :engine, :name, :install_name].each do |option|
+ next unless cmd = ruby_exe_options(option)
+ exe = cmd.split.first
+
+ # It has been reported that File.executable is not reliable
+ # on Windows platforms (see commit 56bc555c). So, we check the
+ # platform.
+ if File.exists?(exe) and (SpecGuard.windows? or File.executable?(exe))
+ return cmd
+ end
+ end
+ nil
+ end
+
+ def ruby_exe(code, opts = {})
+ body = code
+ working_dir = opts[:dir] || "."
+ Dir.chdir(working_dir) do
+ body = "-e #{code.inspect}" if code and not File.exists?(code)
+ cmd = [RUBY_EXE, ENV['RUBY_FLAGS'], opts[:options], body, opts[:args]]
+ `#{cmd.compact.join(' ')}`
+ end
+ end
+
+ unless Object.const_defined?(:RUBY_EXE) and RUBY_EXE
+ require 'rbconfig'
+
+ RUBY_EXE = resolve_ruby_exe or
+ raise Exception, "Unable to find a suitable ruby executable."
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/helpers/scratch.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/helpers/scratch.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/helpers/scratch.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,17 @@
+module ScratchPad
+ def self.clear
+ @record = nil
+ end
+
+ def self.record(arg)
+ @record = arg
+ end
+
+ def self.<<(arg)
+ @record << arg
+ end
+
+ def self.recorded
+ @record
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/helpers/tmp.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/helpers/tmp.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/helpers/tmp.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,32 @@
+# The #tmp method provides a similar functionality
+# to that of Dir.tmpdir. This helper can be overridden
+# by different implementations to provide a more useful
+# behavior if needed.
+#
+# Usage in a spec:
+#
+# File.open(tmp("tags.txt"), "w") { |f| f.puts "" }
+#
+# The order of directories below with "/private/tmp"
+# preceding "/tmp" is significant. On OS X, the directory
+# "/tmp" is a symlink to "private/tmp" with no leading
+# "/". Rather than futzing with what constitutes an
+# absolute path, we just look for "/private/tmp" first.
+
+class Object
+ def tmp(name)
+ unless @spec_temp_directory
+ [ "/private/tmp", "/tmp", "/var/tmp", ENV["TMPDIR"], ENV["TMP"],
+ ENV["TEMP"], ENV["USERPROFILE"] ].each do |dir|
+ if dir and File.directory?(dir) and File.writable?(dir)
+ temp = File.expand_path dir
+ temp = File.readlink temp if File.symlink? temp
+ @spec_temp_directory = temp
+ break
+ end
+ end
+ end
+
+ File.join @spec_temp_directory, name
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/helpers.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/helpers.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/helpers.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,11 @@
+require 'mspec/helpers/argv'
+require 'mspec/helpers/bignum'
+require 'mspec/helpers/const_lookup'
+require 'mspec/helpers/environment'
+require 'mspec/helpers/fixture'
+require 'mspec/helpers/flunk'
+require 'mspec/helpers/io'
+require 'mspec/helpers/language_version'
+require 'mspec/helpers/ruby_exe'
+require 'mspec/helpers/scratch'
+require 'mspec/helpers/tmp'
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/base.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/base.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/base.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,95 @@
+class PositiveOperatorMatcher
+ def initialize(actual)
+ @actual = actual
+ end
+
+ def ==(expected)
+ unless @actual == expected
+ Expectation.fail_with("Expected #{@actual.pretty_inspect}",
+ "to equal #{expected.pretty_inspect}")
+ end
+ end
+
+ def <(expected)
+ unless @actual < expected
+ Expectation.fail_with("Expected #{@actual.pretty_inspect}",
+ "to be less than #{expected.pretty_inspect}")
+ end
+ end
+
+ def <=(expected)
+ unless @actual <= expected
+ Expectation.fail_with("Expected #{@actual.pretty_inspect}",
+ "to be less than or equal to #{expected.pretty_inspect}")
+ end
+ end
+
+ def >(expected)
+ unless @actual > expected
+ Expectation.fail_with("Expected #{@actual.pretty_inspect}",
+ "to be greater than #{expected.pretty_inspect}")
+ end
+ end
+
+ def >=(expected)
+ unless @actual >= expected
+ Expectation.fail_with("Expected #{@actual.pretty_inspect}",
+ "to be greater than or equal to #{expected.pretty_inspect}")
+ end
+ end
+
+ def =~(expected)
+ unless @actual =~ expected
+ Expectation.fail_with("Expected #{@actual.pretty_inspect}",
+ "to match #{expected.pretty_inspect}")
+ end
+ end
+end
+
+class NegativeOperatorMatcher
+ def initialize(actual)
+ @actual = actual
+ end
+
+ def ==(expected)
+ if @actual == expected
+ Expectation.fail_with("Expected #{@actual.pretty_inspect}",
+ "not to equal #{expected.pretty_inspect}")
+ end
+ end
+
+ def <(expected)
+ if @actual < expected
+ Expectation.fail_with("Expected #{@actual.pretty_inspect}",
+ "not to be less than #{expected.pretty_inspect}")
+ end
+ end
+
+ def <=(expected)
+ if @actual <= expected
+ Expectation.fail_with("Expected #{@actual.pretty_inspect}",
+ "not to be less than or equal to #{expected.pretty_inspect}")
+ end
+ end
+
+ def >(expected)
+ if @actual > expected
+ Expectation.fail_with("Expected #{@actual.pretty_inspect}",
+ "not to be greater than #{expected.pretty_inspect}")
+ end
+ end
+
+ def >=(expected)
+ if @actual >= expected
+ Expectation.fail_with("Expected #{@actual.pretty_inspect}",
+ "not to be greater than or equal to #{expected.pretty_inspect}")
+ end
+ end
+
+ def =~(expected)
+ if @actual =~ expected
+ Expectation.fail_with("Expected #{@actual.pretty_inspect}",
+ "not to match #{expected.pretty_inspect}")
+ end
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_an_instance_of.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_an_instance_of.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_an_instance_of.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,26 @@
+class BeAnInstanceOfMatcher
+ def initialize(expected)
+ @expected = expected
+ end
+
+ def matches?(actual)
+ @actual = actual
+ @actual.instance_of?(@expected)
+ end
+
+ def failure_message
+ ["Expected #{@actual.inspect} (#{@actual.class})",
+ "to be an instance of #{@expected}"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.inspect} (#{@actual.class})",
+ "not to be an instance of #{@expected}"]
+ end
+end
+
+class Object
+ def be_an_instance_of(expected)
+ BeAnInstanceOfMatcher.new(expected)
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_ancestor_of.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_ancestor_of.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_ancestor_of.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,24 @@
+class BeAncestorOfMatcher
+ def initialize(expected)
+ @expected = expected
+ end
+
+ def matches?(actual)
+ @actual = actual
+ @expected.ancestors.include? @actual
+ end
+
+ def failure_message
+ ["Expected #{@actual}", "to be an ancestor of #{@expected}"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual}", "not to be an ancestor of #{@expected}"]
+ end
+end
+
+class Object
+ def be_ancestor_of(expected)
+ BeAncestorOfMatcher.new(expected)
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_close.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_close.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_close.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,27 @@
+TOLERANCE = 0.00003 unless Object.const_defined?(:TOLERANCE)
+
+class BeCloseMatcher
+ def initialize(expected, tolerance)
+ @expected = expected
+ @tolerance = tolerance
+ end
+
+ def matches?(actual)
+ @actual = actual
+ (@actual - @expected).abs < @tolerance
+ end
+
+ def failure_message
+ ["Expected #{@expected}", "to be within +/- #{@tolerance} of #{@actual}"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@expected}", "not to be within +/- #{@tolerance} of #{@actual}"]
+ end
+end
+
+class Object
+ def be_close(expected, tolerance)
+ BeCloseMatcher.new(expected, tolerance)
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_empty.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_empty.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_empty.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,20 @@
+class BeEmptyMatcher
+ def matches?(actual)
+ @actual = actual
+ @actual.empty?
+ end
+
+ def failure_message
+ ["Expected #{@actual.inspect}", "to be empty"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.inspect}", "not to be empty"]
+ end
+end
+
+class Object
+ def be_empty
+ BeEmptyMatcher.new
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_false.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_false.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_false.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,20 @@
+class BeFalseMatcher
+ def matches?(actual)
+ @actual = actual
+ @actual == false
+ end
+
+ def failure_message
+ ["Expected #{@actual.inspect}", "to be false"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.inspect}", "not to be false"]
+ end
+end
+
+class Object
+ def be_false
+ BeFalseMatcher.new
+ end
+end
\ No newline at end of file
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_kind_of.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_kind_of.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_kind_of.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,24 @@
+class BeKindOfMatcher
+ def initialize(expected)
+ @expected = expected
+ end
+
+ def matches?(actual)
+ @actual = actual
+ @actual.is_a?(@expected)
+ end
+
+ def failure_message
+ ["Expected #{@actual.inspect} (#{@actual.class})", "to be kind of #{@expected}"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.inspect} (#{@actual.class})", "not to be kind of #{@expected}"]
+ end
+end
+
+class Object
+ def be_kind_of(expected)
+ BeKindOfMatcher.new(expected)
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_nil.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_nil.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_nil.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,20 @@
+class BeNilMatcher
+ def matches?(actual)
+ @actual = actual
+ @actual.nil?
+ end
+
+ def failure_message
+ ["Expected #{@actual.inspect}", "to be nil"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.inspect}", "not to be nil"]
+ end
+end
+
+class Object
+ def be_nil
+ BeNilMatcher.new
+ end
+end
\ No newline at end of file
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_true.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_true.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/be_true.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,20 @@
+class BeTrueMatcher
+ def matches?(actual)
+ @actual = actual
+ @actual == true
+ end
+
+ def failure_message
+ ["Expected #{@actual.inspect}", "to be true"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.inspect}", "not to be true"]
+ end
+end
+
+class Object
+ def be_true
+ BeTrueMatcher.new
+ end
+end
\ No newline at end of file
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/complain.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/complain.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/complain.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,56 @@
+require 'mspec/helpers/io'
+
+class ComplainMatcher
+ def initialize(complaint)
+ @complaint = complaint
+ end
+
+ def matches?(proc)
+ @saved_err = $stderr
+ @stderr = $stderr = IOStub.new
+ @verbose = $VERBOSE
+ $VERBOSE = false
+
+ proc.call
+
+ unless @complaint.nil?
+ case @complaint
+ when Regexp
+ return false unless $stderr =~ @complaint
+ else
+ return false unless $stderr == @complaint
+ end
+ end
+
+ return $stderr.empty? ? false : true
+ ensure
+ $VERBOSE = @verbose
+ $stderr = @saved_err
+ end
+
+ def failure_message
+ if @complaint.nil?
+ ["Expected a warning", "but received none"]
+ elsif @complaint.kind_of? Regexp
+ ["Expected warning to match:", @complaint.inspect]
+ else
+ ["Expected warning: #{@complaint.inspect}", "but got: #{@stderr.chomp.inspect}"]
+ end
+ end
+
+ def negative_failure_message
+ if @complaint.nil?
+ ["Unexpected warning: ", @stderr.chomp.inspect]
+ elsif @complaint.kind_of? Regexp
+ ["Expected warning not to match:", @complaint.inspect]
+ else
+ ["Expected warning: #{@complaint.inspect}", "but got: #{@stderr.chomp.inspect}"]
+ end
+ end
+end
+
+class Object
+ def complain(complaint=nil)
+ ComplainMatcher.new(complaint)
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/eql.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/eql.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/eql.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,26 @@
+class EqlMatcher
+ def initialize(expected)
+ @expected = expected
+ end
+
+ def matches?(actual)
+ @actual = actual
+ @actual.eql?(@expected)
+ end
+
+ def failure_message
+ ["Expected #{@actual.pretty_inspect}",
+ "to have same value and type as #{@expected.pretty_inspect}"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.pretty_inspect}",
+ "not to have same value or type as #{@expected.pretty_inspect}"]
+ end
+end
+
+class Object
+ def eql(expected)
+ EqlMatcher.new(expected)
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/equal.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/equal.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/equal.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,26 @@
+class EqualMatcher
+ def initialize(expected)
+ @expected = expected
+ end
+
+ def matches?(actual)
+ @actual = actual
+ @actual.equal?(@expected)
+ end
+
+ def failure_message
+ ["Expected #{@actual.pretty_inspect}",
+ "to be identical to #{@expected.pretty_inspect}"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.pretty_inspect}",
+ "not to be identical to #{@expected.pretty_inspect}"]
+ end
+end
+
+class Object
+ def equal(expected)
+ EqualMatcher.new(expected)
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/equal_element.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/equal_element.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/equal_element.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,78 @@
+class EqualElementMatcher
+ def initialize(element, attributes = nil, content = nil, options = {})
+ @element = element
+ @attributes = attributes
+ @content = content
+ @options = options
+ end
+
+ def matches?(actual)
+ @actual = actual
+
+ matched = true
+
+ if @options[:not_closed]
+ matched &&= actual =~ /^#{Regexp.quote("<" + @element)}.*#{Regexp.quote(">" + (@content || ''))}$/
+ else
+ matched &&= actual =~ /^#{Regexp.quote("<" + @element)}/
+ matched &&= actual =~ /#{Regexp.quote("</" + @element + ">")}$/
+ matched &&= actual =~ /#{Regexp.quote(">" + @content + "</")}/ if @content
+ end
+
+ if @attributes
+ if @attributes.empty?
+ matched &&= actual.scan(/\w+\=\"(.*)\"/).size == 0
+ else
+ @attributes.each do |key, value|
+ if value == true
+ matched &&= (actual.scan(/#{Regexp.quote(key)}(\s|>)/).size == 1)
+ else
+ matched &&= (actual.scan(%Q{ #{key}="#{value}"}).size == 1)
+ end
+ end
+ end
+ end
+
+ !!matched
+ end
+
+ def failure_message
+ ["Expected #{@actual.pretty_inspect}",
+ "to be a '#{@element}' element with #{attributes_for_failure_message} and #{content_for_failure_message}"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.pretty_inspect}",
+ "not to be a '#{@element}' element with #{attributes_for_failure_message} and #{content_for_failure_message}"]
+ end
+
+ def attributes_for_failure_message
+ if @attributes
+ if @attributes.empty?
+ "no attributes"
+ else
+ @attributes.inject([]) { |memo, n| memo << %Q{#{n[0]}="#{n[1]}"} }.join(" ")
+ end
+ else
+ "any attributes"
+ end
+ end
+
+ def content_for_failure_message
+ if @content
+ if @content.empty?
+ "no content"
+ else
+ "#{@content.inspect} as content"
+ end
+ else
+ "any content"
+ end
+ end
+end
+
+class Object
+ def equal_element(*args)
+ EqualElementMatcher.new(*args)
+ end
+end
\ No newline at end of file
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/equal_utf16.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/equal_utf16.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/equal_utf16.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,34 @@
+class EqualUtf16Matcher
+ def initialize(expected)
+ @expected = expected
+ end
+
+ def matches?(actual)
+ @actual = actual
+ @actual == @expected || @actual == expected_swapped
+ end
+
+ def expected_swapped
+ if @expected.respond_to?(:to_str)
+ @expected_swapped ||= @expected.to_str.gsub(/(.)(.)/, '\2\1')
+ else
+ @expected_swapped ||= @expected.collect { |s| s.to_str.gsub(/(.)(.)/, '\2\1') }
+ end
+ end
+
+ def failure_message
+ ["Expected #{@actual.pretty_inspect}",
+ "to equal #{@expected.pretty_inspect} or #{expected_swapped.pretty_inspect}"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.pretty_inspect}",
+ "not to equal #{@expected.pretty_inspect} nor #{expected_swapped.pretty_inspect}"]
+ end
+end
+
+class Object
+ def equal_utf16(expected)
+ EqualUtf16Matcher.new(expected)
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_constant.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_constant.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_constant.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,30 @@
+require 'mspec/matchers/stringsymboladapter'
+
+class HaveConstantMatcher
+ include StringSymbolAdapter
+
+ def initialize(name)
+ @name = convert_name name
+ end
+
+ def matches?(mod)
+ @mod = mod
+ @mod.constants.include? @name
+ end
+
+ def failure_message
+ ["Expected #{@mod} to have constant '#{@name.to_s}'",
+ "but it does not"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@mod} NOT to have constant '#{@name.to_s}'",
+ "but it does"]
+ end
+end
+
+class Object
+ def have_constant(name)
+ HaveConstantMatcher.new name
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_instance_method.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_instance_method.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_instance_method.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,24 @@
+require 'mspec/matchers/method'
+
+class HaveInstanceMethodMatcher < MethodMatcher
+ def matches?(mod)
+ @mod = mod
+ mod.instance_methods(@include_super).include? @method
+ end
+
+ def failure_message
+ ["Expected #{@mod} to have instance method '#{@method.to_s}'",
+ "but it does not"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@mod} NOT to have instance method '#{@method.to_s}'",
+ "but it does"]
+ end
+end
+
+class Object
+ def have_instance_method(method, include_super=true)
+ HaveInstanceMethodMatcher.new method, include_super
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_method.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_method.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_method.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,24 @@
+require 'mspec/matchers/method'
+
+class HaveMethodMatcher < MethodMatcher
+ def matches?(mod)
+ @mod = mod
+ @mod.methods(@include_super).include? @method
+ end
+
+ def failure_message
+ ["Expected #{@mod} to have method '#{@method.to_s}'",
+ "but it does not"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@mod} NOT to have method '#{@method.to_s}'",
+ "but it does"]
+ end
+end
+
+class Object
+ def have_method(method, include_super=true)
+ HaveMethodMatcher.new method, include_super
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_private_instance_method.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_private_instance_method.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/have_private_instance_method.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,24 @@
+require 'mspec/matchers/method'
+
+class HavePrivateInstanceMethodMatcher < MethodMatcher
+ def matches?(mod)
+ @mod = mod
+ mod.private_instance_methods(@include_super).include? @method
+ end
+
+ def failure_message
+ ["Expected #{@mod} to have private instance method '#{@method.to_s}'",
+ "but it does not"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@mod} NOT to have private instance method '#{@method.to_s}'",
+ "but it does"]
+ end
+end
+
+class Object
+ def have_private_instance_method(method, include_super=true)
+ HavePrivateInstanceMethodMatcher.new method, include_super
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/include.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/include.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/include.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,32 @@
+class IncludeMatcher
+ def initialize(*expected)
+ @expected = expected
+ end
+
+ def matches?(actual)
+ @actual = actual
+ @expected.each do |e|
+ @element = e
+ unless @actual.include?(e)
+ return false
+ end
+ end
+ return true
+ end
+
+ def failure_message
+ ["Expected #{@actual.inspect}", "to include #{@element.inspect}"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.inspect}", "not to include #{@element.inspect}"]
+ end
+end
+
+# Cannot override #include at the toplevel in MRI
+module MSpec
+ def include(*expected)
+ IncludeMatcher.new(*expected)
+ end
+ module_function :include
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/match_yaml.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/match_yaml.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/match_yaml.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,47 @@
+class MatchYAMLMatcher
+
+ def initialize(expected)
+ if valid_yaml?(expected)
+ @expected = expected
+ else
+ @expected = expected.to_yaml
+ end
+ end
+
+ def matches?(actual)
+ @actual = actual
+ clean_yaml(@actual) == @expected
+ end
+
+ def failure_message
+ ["Expected #{@actual.inspect}", " to match #{@expected.inspect}"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.inspect}", " to match #{@expected.inspect}"]
+ end
+
+ protected
+
+ def clean_yaml(yaml)
+ yaml.gsub(/([^-])\s+\n/, "\\1\n")
+ end
+
+ def valid_yaml?(obj)
+ require 'yaml'
+ begin
+ YAML.load(obj)
+ rescue
+ false
+ else
+ true
+ end
+ end
+end
+
+class Object
+ def match_yaml(expected)
+ MatchYAMLMatcher.new(expected)
+ end
+end
+
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/method.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/method.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/method.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,14 @@
+require 'mspec/matchers/stringsymboladapter'
+
+class MethodMatcher
+ include StringSymbolAdapter
+
+ def initialize(method, include_super=true)
+ @include_super = include_super
+ @method = convert_name method
+ end
+
+ def matches?(mod)
+ raise Exception, "define #matches? in the subclass"
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/output.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/output.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/output.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,67 @@
+require 'mspec/helpers/io'
+
+class OutputMatcher
+ def initialize(stdout, stderr)
+ @out = stdout
+ @err = stderr
+ end
+
+ def matches?(proc)
+ @saved_out = $stdout
+ @saved_err = $stderr
+ @stdout = $stdout = IOStub.new
+ @stderr = $stderr = IOStub.new
+
+ proc.call
+
+ unless @out.nil?
+ case @out
+ when Regexp
+ return false unless $stdout =~ @out
+ else
+ return false unless $stdout == @out
+ end
+ end
+
+ unless @err.nil?
+ case @err
+ when Regexp
+ return false unless $stderr =~ @err
+ else
+ return false unless $stderr == @err
+ end
+ end
+
+ return true
+ ensure
+ $stdout = @saved_out
+ $stderr = @saved_err
+ end
+
+ def failure_message
+ expected_out = "\n"
+ actual_out = "\n"
+ unless @out.nil?
+ expected_out << " $stdout: #{@out.inspect}\n"
+ actual_out << " $stdout: #{@stdout.chomp.inspect}\n"
+ end
+ unless @err.nil?
+ expected_out << " $stderr: #{@err.inspect}\n"
+ actual_out << " $stderr: #{@stderr.chomp.inspect}\n"
+ end
+ ["Expected:#{expected_out}", " got:#{actual_out}"]
+ end
+
+ def negative_failure_message
+ out = ""
+ out << " $stdout: #{@stdout.chomp.dump}\n" unless @out.nil?
+ out << " $stderr: #{@stderr.chomp.dump}\n" unless @err.nil?
+ ["Expected output not to be:\n", out]
+ end
+end
+
+class Object
+ def output(stdout=nil, stderr=nil)
+ OutputMatcher.new(stdout, stderr)
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/output_to_fd.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/output_to_fd.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/output_to_fd.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,71 @@
+require 'mspec/helpers/tmp'
+require 'fileutils'
+
+# Lower-level output speccing mechanism for a single
+# output stream. Unlike OutputMatcher which provides
+# methods to capture the output, we actually replace
+# the FD itself so that there is no reliance on a
+# certain method being used.
+class OutputToFDMatcher
+ def initialize(expected, to)
+ @to, @expected = to, expected
+
+ case @to
+ when STDOUT
+ @to_name = "STDOUT"
+ when STDERR
+ @to_name = "STDERR"
+ when IO
+ @to_name = @to.object_id.to_s
+ else
+ raise ArgumentError, "#{@to.inspect} is not a supported output target"
+ end
+ end
+
+ def matches?(block)
+ old_to = @to.dup
+ out = File.open(tmp("mspec_output_to_#{$$}_#{Time.now.to_i}"), 'w+')
+
+ # Replacing with a file handle so that Readline etc. work
+ @to.reopen out
+
+ block.call
+
+ ensure
+ begin
+ @to.reopen old_to
+
+ out.rewind
+ @actual = out.read
+
+ case @expected
+ when Regexp
+ return !(@actual =~ @expected).nil?
+ else
+ return @actual == @expected
+ end
+
+ # Clean up
+ ensure
+ out.close unless out.closed?
+ FileUtils.rm out.path
+ end
+
+ return true
+ end
+
+ def failure_message()
+ ["Expected (#{@to_name}): #{@expected.inspect}\n",
+ "#{'but got'.rjust(@to_name.length + 10)}: #{@actual.inspect}\nBacktrace"]
+ end
+
+ def negative_failure_message()
+ ["Expected output (#{@to_name}) to NOT be:\n", @actual.inspect]
+ end
+end
+
+class Object
+ def output_to_fd(what, where = STDOUT)
+ OutputToFDMatcher.new what, where
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/raise_error.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/raise_error.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/raise_error.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,48 @@
+class RaiseErrorMatcher
+ def initialize(exception, message, &block)
+ @exception = exception
+ @message = message
+ @block = block
+ end
+
+ def matches?(proc)
+ proc.call
+ return false
+ rescue Exception => @actual
+ return false unless @exception === @actual
+ if @message then
+ case @message
+ when String then
+ return false if @message != @actual.message
+ when Regexp then
+ return false if @message !~ @actual.message
+ end
+ end
+
+ @block[@actual] if @block
+
+ return true
+ end
+
+ def failure_message
+ message = ["Expected #{@exception}#{%[ (#{@message})] if @message}"]
+
+ if @actual then
+ message << "but got #{@actual.class}#{%[ (#{@actual.message})] if @actual.message}"
+ else
+ message << "but no exception was raised"
+ end
+
+ message
+ end
+
+ def negative_failure_message
+ ["Expected to not get #{@exception}#{%[ (#{@message})] if @message}", ""]
+ end
+end
+
+class Object
+ def raise_error(exception=Exception, message=nil, &block)
+ RaiseErrorMatcher.new(exception, message, &block)
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/respond_to.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/respond_to.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/respond_to.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,24 @@
+class RespondToMatcher
+ def initialize(expected)
+ @expected = expected
+ end
+
+ def matches?(actual)
+ @actual = actual
+ @actual.respond_to?(@expected)
+ end
+
+ def failure_message
+ ["Expected #{@actual.inspect} (#{@actual.class})", "to respond to #{@expected}"]
+ end
+
+ def negative_failure_message
+ ["Expected #{@actual.inspect} (#{@actual.class})", "not to respond to #{@expected}"]
+ end
+end
+
+class Object
+ def respond_to(expected)
+ RespondToMatcher.new(expected)
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers/stringsymboladapter.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers/stringsymboladapter.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers/stringsymboladapter.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,8 @@
+require 'mspec/utils/version'
+
+module StringSymbolAdapter
+ def convert_name(name)
+ version = SpecVersion.new(RUBY_VERSION) <=> "1.9"
+ version < 0 ? name.to_s : name
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/matchers.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/matchers.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/matchers.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,23 @@
+require 'mspec/matchers/base'
+require 'mspec/matchers/be_ancestor_of'
+require 'mspec/matchers/be_close'
+require 'mspec/matchers/be_empty'
+require 'mspec/matchers/be_false'
+require 'mspec/matchers/be_kind_of'
+require 'mspec/matchers/be_nil'
+require 'mspec/matchers/be_true'
+require 'mspec/matchers/complain'
+require 'mspec/matchers/eql'
+require 'mspec/matchers/equal'
+require 'mspec/matchers/equal_element'
+require 'mspec/matchers/equal_utf16'
+require 'mspec/matchers/have_constant'
+require 'mspec/matchers/have_instance_method'
+require 'mspec/matchers/have_method'
+require 'mspec/matchers/have_private_instance_method'
+require 'mspec/matchers/include'
+require 'mspec/matchers/match_yaml'
+require 'mspec/matchers/raise_error'
+require 'mspec/matchers/output'
+require 'mspec/matchers/output_to_fd'
+require 'mspec/matchers/respond_to'
Added: MacRuby/branches/experimental/mspec/lib/mspec/mocks/mock.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/mocks/mock.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/mocks/mock.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,155 @@
+require 'mspec/expectations/expectations'
+
+module Mock
+ def self.reset
+ @mocks = @stubs = nil
+ end
+
+ def self.mocks
+ @mocks ||= Hash.new { |h,k| h[k] = [] }
+ end
+
+ def self.stubs
+ @stubs ||= Hash.new { |h,k| h[k] = [] }
+ end
+
+ def self.replaced_name(obj, sym)
+ :"__ms_#{obj.__id__}_#{sym}__"
+ end
+
+ def self.replaced_key(obj, sym)
+ [replaced_name(obj, sym), obj, sym]
+ end
+
+ def self.replaced?(key)
+ !!(mocks.keys + stubs.keys).find { |k| k.first == key.first }
+ end
+
+ def self.install_method(obj, sym, type=nil)
+ meta = class << obj; self; end
+
+ key = replaced_key obj, sym
+ if (sym.to_sym == :respond_to? or obj.respond_to?(sym)) and !replaced?(key)
+ meta.__send__ :alias_method, key.first, sym.to_sym
+ end
+
+ meta.class_eval <<-END
+ def #{sym}(*args, &block)
+ Mock.verify_call self, :#{sym}, *args, &block
+ end
+ END
+
+ proxy = MockProxy.new type
+
+ if proxy.mock?
+ MSpec.expectation
+ MSpec.actions :expectation, MSpec.current.state
+ end
+
+ if proxy.stub?
+ stubs[key].unshift proxy
+ else
+ mocks[key] << proxy
+ end
+
+ proxy
+ end
+
+ def self.name_or_inspect(obj)
+ obj.instance_variable_get(:@name) || obj.inspect
+ end
+
+ def self.verify_count
+ mocks.each do |key, proxies|
+ replaced, obj, sym = *key
+ proxies.each do |proxy|
+ qualifier, count = proxy.count
+ pass = case qualifier
+ when :at_least
+ proxy.calls >= count
+ when :at_most
+ proxy.calls <= count
+ when :exactly
+ proxy.calls == count
+ when :any_number_of_times
+ true
+ else
+ false
+ end
+ unless pass
+ Expectation.fail_with(
+ "Mock '#{name_or_inspect obj}' expected to receive '#{sym}' " \
+ "#{qualifier.to_s.sub('_', ' ')} #{count} times",
+ "but received it #{proxy.calls} times")
+ end
+ end
+ end
+ end
+
+ def self.verify_call(obj, sym, *args, &block)
+ compare = *args
+ if RUBY_VERSION >= '1.9'
+ compare = compare.first if compare.length <= 1
+ end
+
+ key = replaced_key obj, sym
+ proxies = mocks[key] + stubs[key]
+ proxies.each do |proxy|
+ pass = case proxy.arguments
+ when :any_args
+ true
+ when :no_args
+ compare.nil?
+ else
+ proxy.arguments == compare
+ end
+
+ if proxy.yielding?
+ if block
+ proxy.yielding.each do |args_to_yield|
+ if block.arity == -1 || block.arity == args_to_yield.size
+ block.call(*args_to_yield)
+ else
+ Expectation.fail_with(
+ "Mock '#{name_or_inspect obj}' asked to yield " \
+ "|#{proxy.yielding.join(', ')}| on #{sym}\n",
+ "but a block with arity #{block.arity} was passed")
+ end
+ end
+ else
+ Expectation.fail_with(
+ "Mock '#{name_or_inspect obj}' asked to yield " \
+ "|[#{proxy.yielding.join('], [')}]| on #{sym}\n",
+ "but no block was passed")
+ end
+ end
+
+ if pass
+ proxy.called
+ return proxy.returning
+ end
+ end
+
+ if sym.to_sym == :respond_to?
+ return obj.__send__(replaced_name(obj, sym), compare)
+ else
+ Expectation.fail_with("Mock '#{name_or_inspect obj}': method #{sym}\n",
+ "called with unexpected arguments (#{Array(compare).join(' ')})")
+ end
+ end
+
+ def self.cleanup
+ symbols = mocks.keys + stubs.keys
+ symbols.uniq.each do |replaced, obj, sym|
+ meta = class << obj; self; end
+
+ if meta.instance_methods.include?(replaced.to_s)
+ meta.__send__ :alias_method, sym.to_sym, replaced
+ meta.__send__ :remove_method, replaced
+ else
+ meta.__send__ :remove_method, sym.to_sym
+ end
+ end
+ reset
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/mocks/object.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/mocks/object.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/mocks/object.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,20 @@
+require 'mspec/mocks/proxy'
+
+class Object
+ def stub!(sym)
+ Mock.install_method self, sym, :stub
+ end
+
+ def should_receive(sym)
+ Mock.install_method self, sym
+ end
+
+ def should_not_receive(sym)
+ proxy = Mock.install_method self, sym
+ proxy.exactly(0).times
+ end
+
+ def mock(name, options={})
+ MockObject.new name, options
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/mocks/proxy.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/mocks/proxy.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/mocks/proxy.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,136 @@
+class MockObject
+ def initialize(name, options={})
+ @name = name
+ @null = options[:null_object]
+ end
+
+ def method_missing(sym, *args, &block)
+ @null ? self : super
+ end
+end
+
+class MockProxy
+ def initialize(type=nil)
+ @multiple_returns = nil
+ @returning = nil
+ @yielding = []
+ @arguments = :any_args
+ @type = type || :mock
+ end
+
+ def mock?
+ @type == :mock
+ end
+
+ def stub?
+ @type == :stub
+ end
+
+ def count
+ @count ||= mock? ? [:exactly, 1] : [:any_number_of_times, 0]
+ end
+
+ def arguments
+ @arguments
+ end
+
+ def returning
+ if @multiple_returns
+ if @returning.size == 1
+ @multiple_returns = false
+ return @returning = @returning.shift
+ end
+ return @returning.shift
+ end
+ @returning
+ end
+
+ def times
+ self
+ end
+
+ def calls
+ @calls ||= 0
+ end
+
+ def called
+ @calls = calls + 1
+ end
+
+ def exactly(n)
+ @count = [:exactly, n_times(n)]
+ self
+ end
+
+ def at_least(n)
+ @count = [:at_least, n_times(n)]
+ self
+ end
+
+ def at_most(n)
+ @count = [:at_most, n_times(n)]
+ self
+ end
+
+ def once
+ exactly 1
+ end
+
+ def twice
+ exactly 2
+ end
+
+ def any_number_of_times
+ @count = [:any_number_of_times, 0]
+ self
+ end
+
+ def with(*args)
+ raise ArgumentError, "you must specify the expected arguments" if args.empty?
+ @arguments = *args
+ if RUBY_VERSION >= '1.9'
+ @arguments = @arguments.first if @arguments.length <= 1
+ end
+ self
+ end
+
+ def and_return(*args)
+ case args.size
+ when 0
+ @returning = nil
+ when 1
+ @returning = args[0]
+ else
+ @multiple_returns = true
+ @returning = args
+ count[1] = args.size if count[1] < args.size
+ end
+ self
+ end
+
+ def and_yield(*args)
+ @yielding << args
+ self
+ end
+
+ def yielding
+ @yielding
+ end
+
+ def yielding?
+ !@yielding.empty?
+ end
+
+ private
+
+ def n_times(n)
+ case n
+ when :once
+ 1
+ when :twice
+ 2
+ else
+ Integer n
+ end
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/mocks.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/mocks.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/mocks.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,3 @@
+require 'mspec/mocks/mock'
+require 'mspec/mocks/proxy'
+require 'mspec/mocks/object'
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/debug.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/debug.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/debug.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,17 @@
+require 'mspec/runner/actions/filter'
+
+class DebugAction < ActionFilter
+ def before(state)
+ Kernel.debugger if self === state.description
+ end
+
+ def register
+ super
+ MSpec.register :before, self
+ end
+
+ def unregister
+ super
+ MSpec.unregister :before, self
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/filter.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/filter.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/filter.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,40 @@
+require 'mspec/runner/filters/match'
+
+# ActionFilter is a base class for actions that are triggered by
+# specs that match the filter. The filter may be specified by
+# strings that match spec descriptions or by tags for strings
+# that match spec descriptions.
+#
+# Unlike TagFilter and RegexpFilter, ActionFilter instances do
+# not affect the specs that are run. The filter is only used to
+# trigger the action.
+
+class ActionFilter
+ def initialize(tags=nil, descs=nil)
+ @tags = Array(tags)
+ descs = Array(descs)
+ @sfilter = MatchFilter.new(nil, *descs) unless descs.empty?
+ end
+
+ def ===(string)
+ @sfilter === string or @tfilter === string
+ end
+
+ def load
+ @tfilter = nil
+ return if @tags.empty?
+
+ desc = MSpec.read_tags(@tags).map { |t| t.description }
+ return if desc.empty?
+
+ @tfilter = MatchFilter.new(nil, *desc)
+ end
+
+ def register
+ MSpec.register :load, self
+ end
+
+ def unregister
+ MSpec.unregister :load, self
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/gdb.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/gdb.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/gdb.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,17 @@
+require 'mspec/runner/actions/filter'
+
+class GdbAction < ActionFilter
+ def before(state)
+ Kernel.yield_gdb(true) if self === state.description
+ end
+
+ def register
+ super
+ MSpec.register :before, self
+ end
+
+ def unregister
+ super
+ MSpec.unregister :before, self
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/tag.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/tag.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/tag.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,133 @@
+require 'mspec/runner/actions/filter'
+
+# TagAction - Write tagged spec description string to a
+# tag file associated with each spec file.
+#
+# The action is triggered by specs whose descriptions
+# match the filter created with 'tags' and/or 'desc'
+#
+# The action fires in the :after event, after the spec
+# had been run. The action fires if the outcome of
+# running the spec matches 'outcome'.
+#
+# The arguments are:
+#
+# action: :add, :del
+# outcome: :pass, :fail, :all
+# tag: the tag to create/delete
+# comment: the comment to create
+# tags: zero or more tags to get matching
+# spec description strings from
+# desc: zero or more strings to match the
+# spec description strings
+
+class TagAction < ActionFilter
+ def initialize(action, outcome, tag, comment, tags=nil, descs=nil)
+ super tags, descs
+ @action = action
+ @outcome = outcome
+ @tag = tag
+ @comment = comment
+ @report = []
+ @exception = false
+ end
+
+ # Returns true if there are no _tag_ or _description_ filters. This
+ # means that a TagAction matches any example by default. Otherwise,
+ # returns true if either the _tag_ or the _description_ filter
+ # matches +string+.
+ def ===(string)
+ return true unless @sfilter or @tfilter
+ @sfilter === string or @tfilter === string
+ end
+
+ # Callback for the MSpec :before event. Resets the +#exception?+
+ # flag to false.
+ def before(state)
+ @exception = false
+ end
+
+ # Callback for the MSpec :exception event. Sets the +#exception?+
+ # flag to true.
+ def exception(exception)
+ @exception = true
+ end
+
+ # Callback for the MSpec :after event. Performs the tag action
+ # depending on the type of action and the outcome of evaluating
+ # the example. See +TagAction+ for a description of the actions.
+ def after(state)
+ if self === state.description and outcome?
+ tag = SpecTag.new
+ tag.tag = @tag
+ tag.comment = @comment
+ tag.description = state.description
+
+ case @action
+ when :add
+ changed = MSpec.write_tag tag
+ when :del
+ changed = MSpec.delete_tag tag
+ end
+
+ @report << state.description if changed
+ end
+ end
+
+ # Returns true if the result of evaluating the example matches
+ # the _outcome_ registered for this tag action. See +TagAction+
+ # for a description of the _outcome_ types.
+ def outcome?
+ @outcome == :all or
+ (@outcome == :pass and not exception?) or
+ (@outcome == :fail and exception?)
+ end
+
+ # Returns true if an exception was raised while evaluating the
+ # current example.
+ def exception?
+ @exception
+ end
+
+ def report
+ @report.join("\n") + "\n"
+ end
+ private :report
+
+ # Callback for the MSpec :finish event. Prints the actions
+ # performed while evaluating the examples.
+ def finish
+ case @action
+ when :add
+ if @report.empty?
+ print "\nTagAction: no specs were tagged with '#{@tag}'\n"
+ else
+ print "\nTagAction: specs tagged with '#{@tag}':\n\n"
+ print report
+ end
+ when :del
+ if @report.empty?
+ print "\nTagAction: no tags '#{@tag}' were deleted\n"
+ else
+ print "\nTagAction: tag '#{@tag}' deleted for specs:\n\n"
+ print report
+ end
+ end
+ end
+
+ def register
+ super
+ MSpec.register :before, self
+ MSpec.register :exception, self
+ MSpec.register :after, self
+ MSpec.register :finish, self
+ end
+
+ def unregister
+ super
+ MSpec.unregister :before, self
+ MSpec.unregister :exception, self
+ MSpec.unregister :after, self
+ MSpec.unregister :finish, self
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/taglist.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/taglist.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/taglist.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,56 @@
+require 'mspec/runner/actions/filter'
+
+# TagListAction - prints out the descriptions for any specs
+# tagged with +tags+. If +tags+ is an empty list, prints out
+# descriptions for any specs that are tagged.
+class TagListAction
+ def initialize(tags=nil)
+ @tags = tags.nil? || tags.empty? ? nil : Array(tags)
+ @filter = nil
+ end
+
+ # Returns true. This enables us to match any tag when loading
+ # tags from the file.
+ def include?(arg)
+ true
+ end
+
+ # Returns true if any tagged descriptions matches +string+.
+ def ===(string)
+ @filter === string
+ end
+
+ # Prints a banner about matching tagged specs.
+ def start
+ if @tags
+ print "\nListing specs tagged with #{@tags.map { |t| "'#{t}'" }.join(", ") }\n\n"
+ else
+ print "\nListing all tagged specs\n\n"
+ end
+ end
+
+ # Creates a MatchFilter for specific tags or for all tags.
+ def load
+ @filter = nil
+ desc = MSpec.read_tags(@tags || self).map { |t| t.description }
+ @filter = MatchFilter.new(nil, *desc) unless desc.empty?
+ end
+
+ # Prints the spec description if it matches the filter.
+ def after(state)
+ return unless self === state.description
+ print state.description, "\n"
+ end
+
+ def register
+ MSpec.register :start, self
+ MSpec.register :load, self
+ MSpec.register :after, self
+ end
+
+ def unregister
+ MSpec.unregister :start, self
+ MSpec.unregister :load, self
+ MSpec.unregister :after, self
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/tagpurge.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/tagpurge.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/tagpurge.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,56 @@
+require 'mspec/runner/actions/filter'
+require 'mspec/runner/actions/taglist'
+
+# TagPurgeAction - removes all tags not matching any spec
+# descriptions.
+class TagPurgeAction < TagListAction
+ attr_reader :matching
+
+ def initialize
+ @matching = []
+ @filter = nil
+ @tags = nil
+ end
+
+ # Prints a banner about purging tags.
+ def start
+ print "\nRemoving tags not matching any specs\n\n"
+ end
+
+ # Creates a MatchFilter for all tags.
+ def load
+ @filter = nil
+ @tags = MSpec.read_tags self
+ desc = @tags.map { |t| t.description }
+ @filter = MatchFilter.new(nil, *desc) unless desc.empty?
+ end
+
+ # Saves any matching tags
+ def after(state)
+ @matching << state.description if self === state.description
+ end
+
+ # Rewrites any matching tags. Prints non-matching tags.
+ # Deletes the tag file if there were no tags (this cleans
+ # up empty or malformed tag files).
+ def unload
+ if @filter
+ matched = @tags.select { |t| @matching.any? { |s| s == t.description } }
+ MSpec.write_tags matched
+
+ (@tags - matched).each { |t| print t.description, "\n" }
+ else
+ MSpec.delete_tags
+ end
+ end
+
+ def register
+ super
+ MSpec.register :unload, self
+ end
+
+ def unregister
+ super
+ MSpec.unregister :unload, self
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/tally.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/tally.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/tally.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,116 @@
+class Tally
+ attr_accessor :files, :examples, :expectations, :failures, :errors, :guards
+
+ def initialize
+ @files = @examples = @expectations = @failures = @errors = @guards = 0
+ end
+
+ def files!(add=1)
+ @files += add
+ end
+
+ def examples!(add=1)
+ @examples += add
+ end
+
+ def expectations!(add=1)
+ @expectations += add
+ end
+
+ def failures!(add=1)
+ @failures += add
+ end
+
+ def errors!(add=1)
+ @errors += add
+ end
+
+ def guards!(add=1)
+ @guards += add
+ end
+
+ def file
+ pluralize files, "file"
+ end
+
+ def example
+ pluralize examples, "example"
+ end
+
+ def expectation
+ pluralize expectations, "expectation"
+ end
+
+ def failure
+ pluralize failures, "failure"
+ end
+
+ def error
+ pluralize errors, "error"
+ end
+
+ def guard
+ pluralize guards, "guard"
+ end
+
+ def format
+ results = [ file, example, expectation, failure, error ]
+ results << guard if [:report, :report_on, :verify].any? { |m| MSpec.mode? m }
+ results.join(", ")
+ end
+
+ alias_method :to_s, :format
+
+ def pluralize(count, singular)
+ "#{count} #{singular}#{'s' unless count == 1}"
+ end
+ private :pluralize
+end
+
+class TallyAction
+ attr_reader :counter
+
+ def initialize
+ @counter = Tally.new
+ end
+
+ def register
+ MSpec.register :load, self
+ MSpec.register :exception, self
+ MSpec.register :example, self
+ MSpec.register :expectation, self
+ end
+
+ def unregister
+ MSpec.unregister :load, self
+ MSpec.unregister :exception, self
+ MSpec.unregister :example, self
+ MSpec.unregister :expectation, self
+ end
+
+ def load
+ @counter.files!
+ end
+
+ # Callback for the MSpec :expectation event. Increments the
+ # tally of expectations (e.g. #should, #should_receive, etc.).
+ def expectation(state)
+ @counter.expectations!
+ end
+
+ # Callback for the MSpec :exception event. Increments the
+ # tally of errors and failures.
+ def exception(exception)
+ exception.failure? ? @counter.failures! : @counter.errors!
+ end
+
+ # Callback for the MSpec :example event. Increments the tally
+ # of examples.
+ def example(state, block)
+ @counter.examples!
+ end
+
+ def format
+ @counter.format
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/timer.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/timer.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/actions/timer.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,22 @@
+class TimerAction
+ def register
+ MSpec.register :start, self
+ MSpec.register :finish, self
+ end
+
+ def start
+ @start = Time.now
+ end
+
+ def finish
+ @stop = Time.now
+ end
+
+ def elapsed
+ @stop - @start
+ end
+
+ def format
+ "Finished in %f seconds" % elapsed
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/actions.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/actions.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/actions.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,8 @@
+require 'mspec/runner/actions/tally'
+require 'mspec/runner/actions/timer'
+require 'mspec/runner/actions/filter'
+require 'mspec/runner/actions/tag'
+require 'mspec/runner/actions/taglist'
+require 'mspec/runner/actions/tagpurge'
+require 'mspec/runner/actions/debug'
+require 'mspec/runner/actions/gdb'
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/context.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/context.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/context.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,186 @@
+# Holds the state of the +describe+ block that is being
+# evaluated. Every example (i.e. +it+ block) is evaluated
+# in a context, which may include state set up in <tt>before
+# :each</tt> or <tt>before :all</tt> blocks.
+#
+#--
+# A note on naming: this is named _ContextState_ rather
+# than _DescribeState_ because +describe+ is the keyword
+# in the DSL for refering to the context in which an example
+# is evaluated, just as +it+ refers to the example itself.
+#++
+class ContextState
+ attr_reader :state, :parent, :parents, :children, :examples, :to_s
+
+ def initialize(mod, options=nil)
+ @to_s = mod.to_s
+ if options.is_a? Hash
+ @options = options
+ else
+ @to_s += "#{".:#".include?(options[0,1]) ? "" : " "}#{options}" if options
+ @options = { }
+ end
+ @options[:shared] ||= false
+
+ @parsed = false
+ @before = { :all => [], :each => [] }
+ @after = { :all => [], :each => [] }
+ @pre = {}
+ @post = {}
+ @examples = []
+ @parent = nil
+ @parents = [self]
+ @children = []
+
+ @mock_verify = lambda { Mock.verify_count }
+ @mock_cleanup = lambda { Mock.cleanup }
+ @expectation_missing = lambda { raise ExpectationNotFoundError }
+ end
+
+ # Returns true if this is a shared +ContextState+. Essentially, when
+ # created with: describe "Something", :shared => true { ... }
+ def shared?
+ return @options[:shared]
+ end
+
+ # Set the parent (enclosing) +ContextState+ for this state. Creates
+ # the +parents+ list.
+ def parent=(parent)
+ @description = nil
+ @parent = parent
+ parent.child self if parent and not shared?
+
+ state = parent
+ while state
+ parents.unshift state
+ state = state.parent
+ end
+ end
+
+ # Add the ContextState instance +child+ to the list of nested
+ # describe blocks.
+ def child(child)
+ @children << child
+ end
+
+ # Returns a list of all before(+what+) blocks from self and any parents.
+ def pre(what)
+ @pre[what] ||= parents.inject([]) { |l, s| l.push(*s.before(what)) }
+ end
+
+ # Returns a list of all after(+what+) blocks from self and any parents.
+ # The list is in reverse order. In other words, the blocks defined in
+ # inner describes are in the list before those defined in outer describes,
+ # and in a particular describe block those defined later are in the list
+ # before those defined earlier.
+ def post(what)
+ @post[what] ||= parents.inject([]) { |l, s| l.unshift(*s.after(what)) }
+ end
+
+ # Records before(:each) and before(:all) blocks.
+ def before(what, &block)
+ return if MSpec.guarded?
+ block ? @before[what].push(block) : @before[what]
+ end
+
+ # Records after(:each) and after(:all) blocks.
+ def after(what, &block)
+ return if MSpec.guarded?
+ block ? @after[what].unshift(block) : @after[what]
+ end
+
+ # Creates an ExampleState instance for the block and stores it
+ # in a list of examples to evaluate unless the example is filtered.
+ def it(desc, &block)
+ example = ExampleState.new(self, desc, block)
+ MSpec.actions :add, example
+ return if MSpec.guarded?
+ @examples << example
+ end
+
+ # Evaluates the block and resets the toplevel +ContextState+ to #parent.
+ def describe(&block)
+ @parsed = protect @to_s, block, false
+ MSpec.register_current parent
+ MSpec.register_shared self if shared?
+ end
+
+ # Returns a description string generated from self and all parents
+ def description
+ @description ||= parents.map { |p| p.to_s }.join(" ")
+ end
+
+ # Injects the before/after blocks and examples from the shared
+ # describe block into this +ContextState+ instance.
+ def it_should_behave_like(desc)
+ return if MSpec.guarded?
+
+ unless state = MSpec.retrieve_shared(desc)
+ raise Exception, "Unable to find shared 'describe' for #{desc}"
+ end
+
+ state.examples.each { |ex| ex.context = self; @examples << ex }
+ state.before(:all).each { |b| before :all, &b }
+ state.before(:each).each { |b| before :each, &b }
+ state.after(:each).each { |b| after :each, &b }
+ state.after(:all).each { |b| after :all, &b }
+ end
+
+ # Evaluates each block in +blocks+ using the +MSpec.protect+ method
+ # so that exceptions are handled and tallied. Returns true and does
+ # NOT evaluate any blocks if +check+ is true and
+ # <tt>MSpec.mode?(:pretend)</tt> is true.
+ def protect(what, blocks, check=true)
+ return true if check and MSpec.mode? :pretend
+ Array(blocks).all? { |block| MSpec.protect what, &block }
+ end
+
+ # Removes filtered examples. Returns true if there are examples
+ # left to evaluate.
+ def filter_examples
+ @examples.reject! { |ex| ex.filtered? }
+ not @examples.empty?
+ end
+
+ # Evaluates the examples in a +ContextState+. Invokes the MSpec events
+ # for :enter, :before, :after, :leave.
+ def process
+ MSpec.register_current self
+
+ if @parsed and filter_examples
+ MSpec.shuffle @examples if MSpec.randomize?
+ MSpec.actions :enter, description
+
+ if protect "before :all", pre(:all)
+ @examples.each do |state|
+ @state = state
+ example = state.example
+ MSpec.actions :before, state
+
+ if protect "before :each", pre(:each)
+ MSpec.clear_expectations
+ if example
+ passed = protect nil, example
+ MSpec.actions :example, state, example
+ protect nil, @expectation_missing unless MSpec.expectation? or not passed
+ end
+ protect "after :each", post(:each)
+ protect "Mock.verify_count", @mock_verify
+ end
+
+ protect "Mock.cleanup", @mock_cleanup
+ MSpec.actions :after, state
+ @state = nil
+ end
+ protect "after :all", post(:all)
+ else
+ protect "Mock.cleanup", @mock_cleanup
+ end
+
+ MSpec.actions :leave
+ end
+
+ MSpec.register_current nil
+ children.each { |child| child.process }
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/example.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/example.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/example.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,34 @@
+require 'mspec/runner/mspec'
+
+# Holds some of the state of the example (i.e. +it+ block) that is
+# being evaluated. See also +ContextState+.
+class ExampleState
+ attr_reader :context, :it, :example
+
+ def initialize(context, it, example=nil)
+ @context = context
+ @it = it
+ @example = example
+ end
+
+ def context=(context)
+ @description = nil
+ @context = context
+ end
+
+ def describe
+ @context.description
+ end
+
+ def description
+ @description ||= "#{describe} #{@it}"
+ end
+
+ def filtered?
+ incl = MSpec.retrieve(:include) || []
+ excl = MSpec.retrieve(:exclude) || []
+ included = incl.empty? || incl.any? { |f| f === description }
+ included &&= excl.empty? || !excl.any? { |f| f === description }
+ not included
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/exception.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/exception.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/exception.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,43 @@
+class ExceptionState
+ attr_reader :description, :describe, :it, :exception
+
+ PATH = /#{File.expand_path(File.dirname(__FILE__) + '/../../..')}/
+
+ def initialize(state, location, exception)
+ @exception = exception
+
+ @description = location ? "An exception occurred during: #{location}" : ""
+ if state
+ @description << "\n" unless @description.empty?
+ @description << state.description
+ @describe = state.describe
+ @it = state.it
+ else
+ @describe = @it = ""
+ end
+ end
+
+ def failure?
+ [ExpectationNotMetError, ExpectationNotFoundError].any? { |e| @exception.is_a? e }
+ end
+
+ def message
+ if @exception.message.empty?
+ "<No message>"
+ elsif @exception.class == ExpectationNotMetError ||
+ @exception.class == ExpectationNotFoundError
+ @exception.message
+ else
+ "#{@exception.class}: #{@exception.message}"
+ end
+ end
+
+ def backtrace
+ begin
+ bt = @exception.awesome_backtrace.show.split "\n"
+ rescue Exception
+ bt = @exception.backtrace || []
+ end
+ bt.reject { |line| PATH =~ line }.join("\n")
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/match.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/match.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/match.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,22 @@
+class MatchFilter
+ def initialize(what, *strings)
+ @what = what
+ @descriptions = to_regexp(*strings)
+ end
+
+ def to_regexp(*strings)
+ strings.map { |str| Regexp.new Regexp.escape(str) }
+ end
+
+ def ===(string)
+ @descriptions.any? { |d| d === string }
+ end
+
+ def register
+ MSpec.register @what, self
+ end
+
+ def unregister
+ MSpec.unregister @what, self
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/profile.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/profile.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/profile.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,54 @@
+class ProfileFilter
+ def initialize(what, *files)
+ @what = what
+ @methods = load(*files)
+ @pattern = /([^ .#]+[.#])([^ ]+)/
+ end
+
+ def find(name)
+ return name if File.exist?(File.expand_path(name))
+
+ ["spec/profiles", "spec", "profiles", "."].each do |dir|
+ file = File.join dir, name
+ return file if File.exist? file
+ end
+ end
+
+ def parse(file)
+ pattern = /(\S+):\s*/
+ key = ""
+ file.inject(Hash.new { |h,k| h[k] = [] }) do |hash, line|
+ line.chomp!
+ if line[0,2] == "- "
+ hash[key] << line[2..-1].gsub(/[ '"]/, "")
+ elsif m = pattern.match(line)
+ key = m[1]
+ end
+ hash
+ end
+ end
+
+ def load(*files)
+ files.inject({}) do |hash, file|
+ next hash unless name = find(file)
+
+ File.open name, "r" do |f|
+ hash.merge parse(f)
+ end
+ end
+ end
+
+ def ===(string)
+ return false unless m = @pattern.match(string)
+ return false unless l = @methods[m[1]]
+ l.include? m[2]
+ end
+
+ def register
+ MSpec.register @what, self
+ end
+
+ def unregister
+ MSpec.unregister @what, self
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/regexp.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/regexp.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/regexp.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,7 @@
+require 'mspec/runner/filters/match'
+
+class RegexpFilter < MatchFilter
+ def to_regexp(*strings)
+ strings.map { |str| Regexp.new str }
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/tag.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/tag.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/filters/tag.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,29 @@
+require 'mspec/runner/filters/match'
+
+class TagFilter
+ def initialize(what, *tags)
+ @what = what
+ @tags = tags
+ end
+
+ def load
+ desc = MSpec.read_tags(@tags).map { |t| t.description }
+
+ @filter = MatchFilter.new(@what, *desc)
+ @filter.register
+ end
+
+ def unload
+ @filter.unregister if @filter
+ end
+
+ def register
+ MSpec.register :load, self
+ MSpec.register :unload, self
+ end
+
+ def unregister
+ MSpec.unregister :load, self
+ MSpec.unregister :unload, self
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/filters.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/filters.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/filters.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,4 @@
+require 'mspec/runner/filters/match'
+require 'mspec/runner/filters/regexp'
+require 'mspec/runner/filters/tag'
+require 'mspec/runner/filters/profile'
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/describe.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/describe.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/describe.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,24 @@
+require 'mspec/runner/formatters/dotted'
+require 'mspec/runner/actions/tally'
+
+class DescribeFormatter < DottedFormatter
+ # Callback for the MSpec :finish event. Prints a summary of
+ # the number of errors and failures for each +describe+ block.
+ def finish
+ describes = Hash.new { |h,k| h[k] = Tally.new }
+
+ @exceptions.each do |exc|
+ desc = describes[exc.describe]
+ exc.failure? ? desc.failures! : desc.errors!
+ end
+
+ print "\n"
+ describes.each do |d, t|
+ text = d.size > 40 ? "#{d[0,37]}..." : d.ljust(40)
+ print "\n#{text} #{t.failure}, #{t.error}"
+ end
+ print "\n" unless describes.empty?
+
+ print "\n#{@timer.format}\n\n#{@tally.format}\n"
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/dotted.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/dotted.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/dotted.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,98 @@
+require 'mspec/expectations/expectations'
+require 'mspec/runner/actions/timer'
+require 'mspec/runner/actions/tally'
+
+class DottedFormatter
+ attr_reader :exceptions, :timer, :tally
+
+ def initialize(out=nil)
+ @exception = @failure = false
+ @exceptions = []
+ @count = 0
+ if out.nil?
+ @out = $stdout
+ else
+ @out = File.open out, "w"
+ end
+ end
+
+ # Creates the +TimerAction+ and +TallyAction+ instances and
+ # registers them. Registers +self+ for the +:exception+,
+ # +:before+, +:after+, and +:finish+ actions.
+ def register
+ (@timer = TimerAction.new).register
+ (@tally = TallyAction.new).register
+ @counter = @tally.counter
+
+ MSpec.register :exception, self
+ MSpec.register :before, self
+ MSpec.register :after, self
+ MSpec.register :finish, self
+ end
+
+ # Returns true if any exception is raised while running
+ # an example. This flag is reset before each example
+ # is evaluated.
+ def exception?
+ @exception
+ end
+
+ # Returns true if all exceptions during the evaluation
+ # of an example are failures rather than errors. See
+ # <tt>ExceptionState#failure</tt>. This flag is reset
+ # before each example is evaluated.
+ def failure?
+ @failure
+ end
+
+ # Callback for the MSpec :before event. Resets the
+ # +#exception?+ and +#failure+ flags.
+ def before(state = nil)
+ @failure = @exception = false
+ end
+
+ # Callback for the MSpec :exception event. Stores the
+ # +ExceptionState+ object to generate the list of backtraces
+ # after all the specs are run. Also updates the internal
+ # +#exception?+ and +#failure?+ flags.
+ def exception(exception)
+ @count += 1
+ @failure = @exception ? @failure && exception.failure? : exception.failure?
+ @exception = true
+ @exceptions << exception
+ end
+
+ # Callback for the MSpec :after event. Prints an indicator
+ # for the result of evaluating this example as follows:
+ # . = No failure or error
+ # F = An ExpectationNotMetError was raised
+ # E = Any exception other than ExpectationNotMetError
+ def after(state = nil)
+ unless exception?
+ print "."
+ else
+ print failure? ? "F" : "E"
+ end
+ end
+
+ # Callback for the MSpec :finish event. Prints a description
+ # and backtrace for every exception that occurred while
+ # evaluating the examples.
+ def finish
+ print "\n"
+ count = 0
+ @exceptions.each do |exc|
+ outcome = exc.failure? ? "FAILED" : "ERROR"
+ print "\n#{count += 1})\n#{exc.description} #{outcome}\n"
+ print exc.message, "\n"
+ print exc.backtrace, "\n"
+ end
+ print "\n#{@timer.format}\n\n#{@tally.format}\n"
+ end
+
+ # A convenience method to allow printing to different outputs.
+ def print(*args)
+ @out.print(*args)
+ @out.flush rescue nil #IronRuby throws a .NET exception on IO.flush
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/file.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/file.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/file.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,19 @@
+require 'mspec/runner/formatters/dotted'
+
+class FileFormatter < DottedFormatter
+ # Unregisters DottedFormatter#before, #after methods and
+ # registers #load, #unload, which perform the same duties
+ # as #before, #after in DottedFormatter.
+ def register
+ super
+
+ MSpec.unregister :before, self
+ MSpec.unregister :after, self
+
+ MSpec.register :load, self
+ MSpec.register :unload, self
+ end
+
+ alias_method :load, :before
+ alias_method :unload, :after
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/html.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/html.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/html.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,81 @@
+require 'mspec/expectations/expectations'
+require 'mspec/runner/formatters/dotted'
+
+class HtmlFormatter < DottedFormatter
+ def register
+ super
+ MSpec.register :start, self
+ MSpec.register :enter, self
+ MSpec.register :leave, self
+ end
+
+ def start
+ print <<-EOH
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Spec Output For #{RUBY_NAME} (#{RUBY_VERSION})</title>
+<style type="text/css">
+ul {
+ list-style: none;
+}
+.fail {
+ color: red;
+}
+.pass {
+ color: green;
+}
+#details :target {
+ background-color: #ffffe0;
+}
+</style>
+</head>
+<body>
+EOH
+ end
+
+ def enter(describe)
+ print "<div><p>#{describe}</p>\n<ul>\n"
+ end
+
+ def leave
+ print "</ul>\n</div>\n"
+ end
+
+ def exception(exception)
+ super
+ outcome = exception.failure? ? "FAILED" : "ERROR"
+ print %[<li class="fail">- #{exception.it} (<a href="#details-#{@count}">]
+ print %[#{outcome} - #{@count}</a>)</li>\n]
+ end
+
+ def after(state)
+ print %[<li class="pass">- #{state.it}</li>\n] unless exception?
+ end
+
+ def finish
+ success = @exceptions.empty?
+ unless success
+ print "<hr>\n"
+ print %[<ol id="details">]
+ count = 0
+ @exceptions.each do |exc|
+ outcome = exc.failure? ? "FAILED" : "ERROR"
+ print %[\n<li id="details-#{count += 1}"><p>#{escape(exc.description)} #{outcome}</p>\n<p>]
+ print escape(exc.message)
+ print "</p>\n<pre>\n"
+ print escape(exc.backtrace)
+ print "</pre>\n</li>\n"
+ end
+ print "</ol>\n"
+ end
+ print %[<p>#{@timer.format}</p>\n]
+ print %[<p class="#{success ? "pass" : "fail"}">#{@tally.format}</p>\n]
+ print "</body>\n</html>\n"
+ end
+
+ def escape(string)
+ string.gsub("&", " ").gsub("<", "<").gsub(">", ">")
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/method.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/method.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/method.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,93 @@
+require 'mspec/runner/formatters/dotted'
+
+class MethodFormatter < DottedFormatter
+ attr_accessor :methods
+
+ def initialize(out=nil)
+ super
+ @methods = Hash.new do |h, k|
+ hash = {}
+ hash[:examples] = 0
+ hash[:expectations] = 0
+ hash[:failures] = 0
+ hash[:errors] = 0
+ hash[:exceptions] = []
+ h[k] = hash
+ end
+ end
+
+ # Returns the type of method as a "class", "instance",
+ # or "unknown".
+ def method_type(sep)
+ case sep
+ when '.', '::'
+ "class"
+ when '#'
+ "instance"
+ else
+ "unknown"
+ end
+ end
+
+ # Callback for the MSpec :before event. Parses the
+ # describe string into class and method if possible.
+ # Resets the tallies so the counts are only for this
+ # example.
+ def before(state)
+ super
+
+ # The pattern for a method name is not correctly
+ # restrictive but it is simplistic and useful
+ # for our purpose.
+ /^([A-Za-z_]+\w*)(\.|#|::)([^ ]+)/ =~ state.describe
+ @key = $1 && $2 && $3 ? "#{$1}#{$2}#{$3}" : state.describe
+
+ unless methods.key? @key
+ h = methods[@key]
+ h[:class] = "#{$1}"
+ h[:method] = "#{$3}"
+ h[:type] = method_type $2
+ h[:description] = state.description
+ end
+
+ tally.counter.examples = 0
+ tally.counter.expectations = 0
+ tally.counter.failures = 0
+ tally.counter.errors = 0
+
+ @exceptions = []
+ end
+
+ # Callback for the MSpec :after event. Sets or adds to
+ # tallies for the example block.
+ def after(state)
+ h = methods[@key]
+ h[:examples] += tally.counter.examples
+ h[:expectations] += tally.counter.expectations
+ h[:failures] += tally.counter.failures
+ h[:errors] += tally.counter.errors
+ @exceptions.each do |exc|
+ h[:exceptions] << "#{exc.message}\n#{exc.backtrace}\n"
+ end
+ end
+
+ # Callback for the MSpec :finish event. Prints out the
+ # summary information in YAML format for all the methods.
+ def finish
+ print "---\n"
+
+ methods.each do |key, hash|
+ print key.inspect, ":\n"
+ print " class: ", hash[:class].inspect, "\n"
+ print " method: ", hash[:method].inspect, "\n"
+ print " type: ", hash[:type], "\n"
+ print " description: ", hash[:description].inspect, "\n"
+ print " examples: ", hash[:examples], "\n"
+ print " expectations: ", hash[:expectations], "\n"
+ print " failures: ", hash[:failures], "\n"
+ print " errors: ", hash[:errors], "\n"
+ print " exceptions:\n"
+ hash[:exceptions].each { |exc| print " - ", exc.inspect, "\n" }
+ end
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/specdoc.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/specdoc.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/specdoc.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,41 @@
+require 'mspec/expectations/expectations'
+require 'mspec/runner/formatters/dotted'
+
+class SpecdocFormatter < DottedFormatter
+ def register
+ super
+ MSpec.register :enter, self
+ end
+
+ # Callback for the MSpec :enter event. Prints the
+ # +describe+ block string.
+ def enter(describe)
+ print "\n#{describe}\n"
+ end
+
+ # Callback for the MSpec :before event. Prints the
+ # +it+ block string.
+ def before(state)
+ super
+ print "- #{state.it}"
+ end
+
+ # Callback for the MSpec :exception event. Prints
+ # either 'ERROR - X' or 'FAILED - X' where _X_ is
+ # the sequential number of the exception raised. If
+ # there has already been an exception raised while
+ # evaluating this example, it prints another +it+
+ # block description string so that each discription
+ # string has an associated 'ERROR' or 'FAILED'
+ def exception(exception)
+ print "\n- #{exception.it}" if exception?
+ super
+ print " (#{exception.failure? ? 'FAILED' : 'ERROR'} - #{@count})"
+ end
+
+ # Callback for the MSpec :after event. Prints a
+ # newline to finish the description string output.
+ def after(state)
+ print "\n"
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/spinner.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/spinner.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/spinner.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,99 @@
+require 'mspec/expectations/expectations'
+require 'mspec/runner/formatters/dotted'
+
+class SpinnerFormatter < DottedFormatter
+ attr_reader :length
+
+ Spins = %w!| / - \\!
+ HOUR = 3600
+ MIN = 60
+
+ def initialize(out=nil)
+ @exception = @failure = false
+ @exceptions = []
+ @count = 0
+ @out = $stdout
+
+ @which = 0
+ @loaded = 0
+ self.length = 40
+ @percent = 0
+ @start = Time.now
+
+ term = ENV['TERM']
+ @color = (term != "dumb")
+ @fail_color = "32"
+ @error_color = "32"
+ end
+
+ def register
+ super
+
+ MSpec.register :start, self
+ MSpec.register :load, self
+ end
+
+ def length=(length)
+ @length = length
+ @ratio = 100.0 / length
+ @position = length / 2 - 2
+ end
+
+ def etr
+ return "00:00:00" if @percent == 0
+ elapsed = Time.now - @start
+ remain = (100 * elapsed / @percent) - elapsed
+
+ hour = remain >= HOUR ? (remain / HOUR).to_i : 0
+ remain -= hour * HOUR
+ min = remain >= MIN ? (remain / MIN).to_i : 0
+ sec = remain - min * MIN
+
+ "%02d:%02d:%02d" % [hour, min, sec]
+ end
+
+ def percentage
+ @percent = @loaded * 100 / @total
+ bar = ("=" * (@percent / @ratio)).ljust @length
+ label = "%d%%" % @percent
+ bar[@position, label.size] = label
+ bar
+ end
+
+ def spin
+ @which = (@which + 1) % Spins.size
+ if @color
+ print "\r[%s | %s | %s] \033[0;#{@fail_color}m%6dF \033[0;#{@error_color}m%6dE\033[0m" %
+ [Spins[@which], percentage, etr, @counter.failures, @counter.errors]
+ else
+ print "\r[%s | %s | %s] %6dF %6dE" %
+ [Spins[@which], percentage, etr, @counter.failures, @counter.errors]
+ end
+ end
+
+ # Callback for the MSpec :start event. Stores the total
+ # number of files that will be processed.
+ def start
+ @total = MSpec.retrieve(:files).size
+ end
+
+ # Callback for the MSpec :load event. Increments the number
+ # of files that have been loaded.
+ def load
+ @loaded += 1
+ end
+
+ # Callback for the MSpec :exception event. Changes the color
+ # used to display the tally of errors and failures
+ def exception(exception)
+ super
+ @fail_color = "31" if exception.failure?
+ @error_color = "33" unless exception.failure?
+ end
+
+ # Callback for the MSpec :after event. Updates the spinner
+ # and progress bar.
+ def after(state)
+ spin
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/summary.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/summary.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/summary.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,11 @@
+require 'mspec/expectations/expectations'
+require 'mspec/runner/formatters/dotted'
+
+class SummaryFormatter < DottedFormatter
+ # Callback for the MSpec :after event. Overrides the
+ # callback provided by +DottedFormatter+ and does not
+ # print any output for each example evaluated.
+ def after(state)
+ # do nothing
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/unit.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/unit.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/unit.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,21 @@
+require 'mspec/expectations/expectations'
+require 'mspec/runner/formatters/dotted'
+
+class UnitdiffFormatter < DottedFormatter
+ def finish
+ print "\n\n#{@timer.format}\n"
+ count = 0
+ @exceptions.each do |exc|
+ outcome = exc.failure? ? "FAILED" : "ERROR"
+ print "\n#{count += 1})\n#{exc.description} #{outcome}\n"
+ print exc.message, ": \n"
+ print exc.backtrace, "\n"
+ end
+ print "\n#{@tally.format}\n"
+ end
+
+ def backtrace(exc)
+ exc.backtrace && exc.backtrace.join("\n")
+ end
+ private :backtrace
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/yaml.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/yaml.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters/yaml.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,44 @@
+require 'mspec/expectations/expectations'
+require 'mspec/runner/formatters/dotted'
+
+class YamlFormatter < DottedFormatter
+ def initialize(out=nil)
+ @exception = @failure = false
+ @exceptions = []
+ @count = 0
+ @out = $stdout
+
+ if out.nil?
+ @finish = $stdout
+ else
+ @finish = File.open out, "w"
+ end
+ end
+
+ def switch
+ @out = @finish
+ end
+
+ def after(state)
+ end
+
+ def finish
+ switch
+
+ print "---\n"
+ print "exceptions:\n"
+ @exceptions.each do |exc|
+ outcome = exc.failure? ? "FAILED" : "ERROR"
+ str = "#{exc.description} #{outcome}\n"
+ str << exc.message << "\n" << exc.backtrace
+ print "- ", str.inspect, "\n"
+ end
+
+ print "time: ", @timer.elapsed, "\n"
+ print "files: ", @tally.counter.files, "\n"
+ print "examples: ", @tally.counter.examples, "\n"
+ print "expectations: ", @tally.counter.expectations, "\n"
+ print "failures: ", @tally.counter.failures, "\n"
+ print "errors: ", @tally.counter.errors, "\n"
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/formatters.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,10 @@
+require 'mspec/runner/formatters/describe'
+require 'mspec/runner/formatters/dotted'
+require 'mspec/runner/formatters/file'
+require 'mspec/runner/formatters/specdoc'
+require 'mspec/runner/formatters/html'
+require 'mspec/runner/formatters/summary'
+require 'mspec/runner/formatters/unit'
+require 'mspec/runner/formatters/spinner'
+require 'mspec/runner/formatters/method'
+require 'mspec/runner/formatters/yaml'
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/mspec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/mspec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/mspec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,335 @@
+require 'mspec/runner/context'
+require 'mspec/runner/exception'
+require 'mspec/runner/tag'
+require 'fileutils'
+
+module MSpec
+
+ @exit = nil
+ @start = nil
+ @enter = nil
+ @before = nil
+ @after = nil
+ @leave = nil
+ @finish = nil
+ @exclude = nil
+ @include = nil
+ @leave = nil
+ @load = nil
+ @unload = nil
+ @current = nil
+ @modes = []
+ @shared = {}
+ @guarded = []
+ @exception = nil
+ @randomize = nil
+ @expectation = nil
+ @expectations = false
+
+ def self.describe(mod, options=nil, &block)
+ state = ContextState.new mod, options
+ state.parent = current
+
+ MSpec.register_current state
+ state.describe(&block)
+
+ state.process unless state.shared? or current
+ end
+
+ def self.process
+ actions :start
+ files
+ actions :finish
+ end
+
+ def self.files
+ return unless files = retrieve(:files)
+
+ shuffle files if randomize?
+ files.each do |file|
+ @env = Object.new
+ @env.extend MSpec
+
+ store :file, file
+ actions :load
+ protect("loading #{file}") { Kernel.load file }
+ actions :unload
+ end
+ end
+
+ def self.actions(action, *args)
+ actions = retrieve(action)
+ actions.each { |obj| obj.send action, *args } if actions
+ end
+
+ def self.protect(location, &block)
+ begin
+ @env.instance_eval(&block)
+ return true
+ rescue SystemExit
+ raise
+ rescue Exception => exc
+ register_exit 1
+ actions :exception, ExceptionState.new(current && current.state, location, exc)
+ return false
+ end
+ end
+
+ # Guards can be nested, so a stack is necessary to know when we have
+ # exited the toplevel guard.
+ def self.guard
+ @guarded << true
+ end
+
+ def self.unguard
+ @guarded.pop
+ end
+
+ def self.guarded?
+ not @guarded.empty?
+ end
+
+ # Sets the toplevel ContextState to +state+.
+ def self.register_current(state)
+ store :current, state
+ end
+
+ # Sets the toplevel ContextState to +nil+.
+ def self.clear_current
+ store :current, nil
+ end
+
+ # Returns the toplevel ContextState.
+ def self.current
+ retrieve :current
+ end
+
+ # Stores the shared ContextState keyed by description.
+ def self.register_shared(state)
+ @shared[state.to_s] = state
+ end
+
+ # Returns the shared ContextState matching description.
+ def self.retrieve_shared(desc)
+ @shared[desc.to_s]
+ end
+
+ # Stores the exit code used by the runner scripts.
+ def self.register_exit(code)
+ store :exit, code
+ end
+
+ # Retrieves the stored exit code.
+ def self.exit_code
+ retrieve(:exit).to_i
+ end
+
+ # Stores the list of files to be evaluated.
+ def self.register_files(files)
+ store :files, files
+ end
+
+ # Stores one or more substitution patterns for transforming
+ # a spec filename into a tags filename, where each pattern
+ # has the form:
+ #
+ # [Regexp, String]
+ #
+ # See also +tags_file+.
+ def self.register_tags_patterns(patterns)
+ store :tags_patterns, patterns
+ end
+
+ # Registers an operating mode. Modes recognized by MSpec:
+ #
+ # :pretend - actions execute but specs are not run
+ # :verify - specs are run despite guards and the result is
+ # verified to match the expectation of the guard
+ # :report - specs that are guarded are reported
+ # :unguarded - all guards are forced off
+ def self.register_mode(mode)
+ modes = retrieve :modes
+ modes << mode unless modes.include? mode
+ end
+
+ # Clears all registered modes.
+ def self.clear_modes
+ store :modes, []
+ end
+
+ # Returns +true+ if +mode+ is registered.
+ def self.mode?(mode)
+ retrieve(:modes).include? mode
+ end
+
+ def self.retrieve(symbol)
+ instance_variable_get :"@#{symbol}"
+ end
+
+ def self.store(symbol, value)
+ instance_variable_set :"@#{symbol}", value
+ end
+
+ # This method is used for registering actions that are
+ # run at particular points in the spec cycle:
+ # :start before any specs are run
+ # :load before a spec file is loaded
+ # :enter before a describe block is run
+ # :before before a single spec is run
+ # :add while a describe block is adding examples to run later
+ # :expectation before a 'should', 'should_receive', etc.
+ # :example after an example block is run, passed the block
+ # :exception after an exception is rescued
+ # :after after a single spec is run
+ # :leave after a describe block is run
+ # :unload after a spec file is run
+ # :finish after all specs are run
+ #
+ # Objects registered as actions above should respond to
+ # a method of the same name. For example, if an object
+ # is registered as a :start action, it should respond to
+ # a #start method call.
+ #
+ # Additionally, there are two "action" lists for
+ # filtering specs:
+ # :include return true if the spec should be run
+ # :exclude return true if the spec should NOT be run
+ #
+ def self.register(symbol, action)
+ unless value = retrieve(symbol)
+ value = store symbol, []
+ end
+ value << action unless value.include? action
+ end
+
+ def self.unregister(symbol, action)
+ if value = retrieve(symbol)
+ value.delete action
+ end
+ end
+
+ def self.randomize(flag=true)
+ @randomize = flag
+ end
+
+ def self.randomize?
+ @randomize == true
+ end
+
+ def self.shuffle(ary)
+ return if ary.empty?
+
+ size = ary.size
+ size.times do |i|
+ r = rand(size - i - 1)
+ ary[i], ary[r] = ary[r], ary[i]
+ end
+ end
+
+ # Records that an expectation has been encountered in an example.
+ def self.expectation
+ store :expectations, true
+ end
+
+ # Returns true if an expectation has been encountered
+ def self.expectation?
+ retrieve :expectations
+ end
+
+ # Resets the flag that an expectation has been encountered in an example.
+ def self.clear_expectations
+ store :expectations, false
+ end
+
+ # Transforms a spec filename into a tags filename by applying each
+ # substitution pattern in :tags_pattern. The default patterns are:
+ #
+ # [%r(/spec/), '/spec/tags/'], [/_spec.rb$/, '_tags.txt']
+ #
+ # which will perform the following transformation:
+ #
+ # path/to/spec/class/method_spec.rb => path/to/spec/tags/class/method_tags.txt
+ #
+ # See also +register_tags_patterns+.
+ def self.tags_file
+ patterns = retrieve(:tags_patterns) ||
+ [[%r(spec/), 'spec/tags/'], [/_spec.rb$/, '_tags.txt']]
+ patterns.inject(retrieve(:file).dup) do |file, pattern|
+ file.gsub(*pattern)
+ end
+ end
+
+ # Returns a list of tags matching any tag string in +keys+ based
+ # on the return value of <tt>keys.include?("tag_name")</tt>
+ def self.read_tags(keys)
+ tags = []
+ file = tags_file
+ if File.exist? file
+ File.open(file, "r") do |f|
+ f.each_line do |line|
+ line.chomp!
+ next if line.empty?
+ tag = SpecTag.new line.chomp
+ tags << tag if keys.include? tag.tag
+ end
+ end
+ end
+ tags
+ end
+
+ # Writes each tag in +tags+ to the tag file. Overwrites the
+ # tag file if it exists.
+ def self.write_tags(tags)
+ file = tags_file
+ path = File.dirname file
+ FileUtils.mkdir_p path unless File.exist? path
+ File.open(file, "w") do |f|
+ tags.each { |t| f.puts t }
+ end
+ end
+
+ # Writes +tag+ to the tag file if it does not already exist.
+ # Returns +true+ if the tag is written, +false+ otherwise.
+ def self.write_tag(tag)
+ string = tag.to_s
+ file = tags_file
+ path = File.dirname file
+ FileUtils.mkdir_p path unless File.exist? path
+ if File.exist? file
+ File.open(file, "r") do |f|
+ f.each_line { |line| return false if line.chomp == string }
+ end
+ end
+ File.open(file, "a") { |f| f.puts string }
+ return true
+ end
+
+ # Deletes +tag+ from the tag file if it exists. Returns +true+
+ # if the tag is deleted, +false+ otherwise. Deletes the tag
+ # file if it is empty.
+ def self.delete_tag(tag)
+ deleted = false
+ pattern = /#{tag.tag}.*#{Regexp.escape(tag.escape(tag.description))}/
+ file = tags_file
+ if File.exist? file
+ lines = IO.readlines(file)
+ File.open(file, "w") do |f|
+ lines.each do |line|
+ unless pattern =~ line.chomp
+ f.puts line unless line.empty?
+ else
+ deleted = true
+ end
+ end
+ end
+ File.delete file unless File.size? file
+ end
+ return deleted
+ end
+
+ # Removes the tag file associated with a spec file.
+ def self.delete_tags
+ file = tags_file
+ File.delete file if File.exists? file
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/object.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/object.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/object.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,24 @@
+class Object
+ def before(at=:each, &block)
+ MSpec.current.before at, &block
+ end
+
+ def after(at=:each, &block)
+ MSpec.current.after at, &block
+ end
+
+ def describe(mod, msg=nil, options=nil, &block)
+ MSpec.describe mod, msg, &block
+ end
+
+ def it(msg, &block)
+ MSpec.current.it msg, &block
+ end
+
+ def it_should_behave_like(desc)
+ MSpec.current.it_should_behave_like desc
+ end
+
+ alias_method :context, :describe
+ alias_method :specify, :it
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/shared.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/shared.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/shared.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,12 @@
+require 'mspec/runner/mspec'
+
+class Object
+ def it_behaves_like(desc, meth, obj=nil)
+ send :before, :all do
+ @method = meth
+ @object = obj if obj
+ end
+
+ send :it_should_behave_like, desc.to_s
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner/tag.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner/tag.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner/tag.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,32 @@
+class SpecTag
+ attr_accessor :tag, :comment, :description
+
+ def initialize(string=nil)
+ parse(string) if string
+ end
+
+ def parse(string)
+ m = /^([^()#:]+)(\(([^)]+)?\))?:(.*)$/.match string
+ @tag, @comment, description = m.values_at(1, 3, 4) if m
+ @description = unescape description
+ end
+
+ def unescape(str)
+ return unless str
+ str = str[1..-2] if str[0] == ?" and str[-1] == ?"
+ str.gsub(/\\n/, "\n")
+ end
+
+ def escape(str)
+ str = %["#{str.gsub(/\n/, '\n')}"] if /\n/ =~ str
+ str
+ end
+
+ def to_s
+ "#{@tag}#{ "(#{@comment})" if @comment }:#{escape @description}"
+ end
+
+ def ==(o)
+ @tag == o.tag and @comment == o.comment and @description == o.description
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/runner.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/runner.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/runner.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,15 @@
+require 'mspec/mocks'
+require 'mspec/runner/mspec'
+require 'mspec/runner/context'
+require 'mspec/runner/example'
+require 'mspec/runner/object'
+require 'mspec/runner/formatters'
+require 'mspec/runner/actions'
+require 'mspec/runner/filters'
+require 'mspec/runner/shared'
+require 'mspec/runner/tag'
+
+def $stderr.write(str)
+ # The 'useless use of' warnings are a crime against OO.
+ str =~ /useless use of/ ? nil : super
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/utils/name_map.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/utils/name_map.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/utils/name_map.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,129 @@
+require 'mspec/helpers/const_lookup'
+
+class NameMap
+ MAP = {
+ '`' => 'backtick',
+ '+' => 'plus',
+ '-' => 'minus',
+ '+@' => 'uplus',
+ '-@' => 'uminus',
+ '*' => 'multiply',
+ '/' => 'divide',
+ '%' => 'modulo',
+ '<<' => {'Bignum' => 'left_shift',
+ 'Fixnum' => 'left_shift',
+ 'IO' => 'output',
+ :default => 'append' },
+ '>>' => 'right_shift',
+ '<' => 'lt',
+ '<=' => 'lte',
+ '>' => 'gt',
+ '>=' => 'gte',
+ '=' => 'assignment',
+ '==' => 'equal_value',
+ '===' => 'case_compare',
+ '<=>' => 'comparison',
+ '[]' => 'element_reference',
+ '[]=' => 'element_set',
+ '**' => 'exponent',
+ '!' => 'not',
+ '~' => {'Bignum' => 'complement',
+ 'Fixnum' => 'complement',
+ 'Regexp' => 'match',
+ 'String' => 'match' },
+ '!=' => 'not_equal',
+ '!~' => 'not_match',
+ '=~' => 'match',
+ '&' => {'Bignum' => 'bit_and',
+ 'Fixnum' => 'bit_and',
+ 'Array' => 'intersection',
+ 'TrueClass' => 'and',
+ 'FalseClass' => 'and',
+ 'NilClass' => 'and',
+ 'Set' => 'intersection' },
+ '|' => {'Bignum' => 'bit_or',
+ 'Fixnum' => 'bit_or',
+ 'Array' => 'union',
+ 'TrueClass' => 'or',
+ 'FalseClass' => 'or',
+ 'NilClass' => 'or',
+ 'Set' => 'union' },
+ '^' => {'Bignum' => 'bit_xor',
+ 'Fixnum' => 'bit_xor',
+ 'TrueClass' => 'xor',
+ 'FalseClass' => 'xor',
+ 'NilClass' => 'xor',
+ 'Set' => 'exclusion'},
+ }
+
+ EXCLUDED = %w[
+ MSpecScript
+ MkSpec
+ DTracer
+ NameMap
+ OptionParser
+ YAML
+ ]
+
+ def initialize(filter=false)
+ @seen = {}
+ @filter = filter
+ end
+
+ def exception?(name)
+ return false unless c = class_or_module(name)
+ c == Errno or c.ancestors.include? Exception
+ end
+
+ def class_or_module(c)
+ const = const_lookup(c)
+ filtered = @filter && EXCLUDED.include?(const.name)
+ return const if Module === const and not filtered
+ rescue NameError
+ end
+
+ def namespace(mod, const)
+ return const.to_s if mod.nil? or %w[Object Class Module].include? mod
+ "#{mod}::#{const}"
+ end
+
+ def map(hash, constants, mod=nil)
+ @seen = {} unless mod
+
+ constants.each do |const|
+ name = namespace mod, const
+ m = class_or_module name
+ next unless m and not @seen[m]
+ @seen[m] = true
+
+ ms = m.methods false
+ hash["#{name}."] = ms.sort unless ms.empty?
+
+ ms = m.public_instance_methods(false) +
+ m.protected_instance_methods(false)
+ hash["#{name}#"] = ms.sort unless ms.empty?
+
+ map hash, m.constants, name
+ end
+
+ hash
+ end
+
+ def dir_name(c, base)
+ return File.join(base, 'exception') if exception? c
+
+ c.split('::').inject(base) do |dir, name|
+ name.gsub!(/Class/, '') unless name == 'Class'
+ File.join dir, name.downcase
+ end
+ end
+
+ def file_name(m, c)
+ if MAP.key?(m)
+ name = MAP[m].is_a?(Hash) ? MAP[m][c.split('::').last] || MAP[m][:default] : MAP[m]
+ else
+ name = m.gsub(/[?!=]/, '')
+ end
+ "#{name}_spec.rb"
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/utils/options.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/utils/options.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/utils/options.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,441 @@
+require 'mspec/version'
+
+class MSpecOption
+ attr_reader :short, :long, :arg, :description, :block
+
+ def initialize(short, long, arg, description, block)
+ @short = short
+ @long = long
+ @arg = arg
+ @description = description
+ @block = block
+ end
+
+ def arg?
+ @arg != nil
+ end
+
+ def match?(opt)
+ opt == @short or opt == @long
+ end
+end
+
+# MSpecOptions provides a parser for command line options. It also
+# provides a composable set of options from which the runner scripts
+# can select for their particular functionality.
+class MSpecOptions
+ # Raised if incorrect or incomplete formats are passed to #on.
+ class OptionError < Exception; end
+
+ # Raised if an unrecognized option is encountered.
+ class ParseError < Exception; end
+
+ attr_accessor :config, :banner, :width, :options
+
+ def initialize(banner="", width=30, config=nil)
+ @banner = banner
+ @config = config
+ @width = width
+ @options = []
+ @doc = []
+ @extra = []
+ @on_extra = lambda { |x|
+ raise ParseError, "Unrecognized option: #{x}" if x[0] == ?-
+ @extra << x
+ }
+
+ yield self if block_given?
+ end
+
+ # Registers an option. Acceptable formats for arguments are:
+ #
+ # on "-a", "description"
+ # on "-a", "--abdc", "description"
+ # on "-a", "ARG", "description"
+ # on "--abdc", "ARG", "description"
+ # on "-a", "--abdc", "ARG", "description"
+ #
+ # If an block is passed, it will be invoked when the option is
+ # matched. Not passing a block is permitted, but nonsensical.
+ def on(*args, &block)
+ raise OptionError, "option and description are required" if args.size < 2
+
+ description = args.pop
+ short, long, argument = nil
+ args.each do |arg|
+ if arg[0] == ?-
+ if arg[1] == ?-
+ long = arg
+ else
+ short = arg
+ end
+ else
+ argument = arg
+ end
+ end
+
+ add short, long, argument, description, block
+ end
+
+ # Adds documentation text for an option and adds an +MSpecOption+
+ # instance to the list of registered options.
+ def add(short, long, arg, description, block)
+ s = short ? short.dup : " "
+ s << (short ? ", " : " ") if long
+ doc " #{s}#{long} #{arg}".ljust(@width-1) + " #{description}"
+ @options << MSpecOption.new(short, long, arg, description, block)
+ end
+
+ # Searches all registered options to find a match for +opt+. Returns
+ # +nil+ if no registered options match.
+ def match?(opt)
+ @options.find { |o| o.match? opt }
+ end
+
+ # Processes an option. Calles the #on_extra block (or default) for
+ # unrecognized options. For registered options, possibly fetches an
+ # argument and invokes the option's block if it is not nil.
+ def process(argv, entry, opt, arg)
+ unless option = match?(opt)
+ @on_extra[entry]
+ else
+ if option.arg?
+ arg = argv.shift if arg.nil?
+ raise ParseError, "No argument provided for #{opt}" unless arg
+ end
+ option.block[arg] if option.block
+ end
+ option
+ end
+
+ # Splits a string at +n+ characters into the +opt+ and the +rest+.
+ # The +arg+ is set to +nil+ if +rest+ is an empty string.
+ def split(str, n)
+ opt = str[0, n]
+ rest = str[n, str.size]
+ arg = rest == "" ? nil : rest
+ return opt, arg, rest
+ end
+
+ # Parses an array of command line entries, calling blocks for
+ # registered options.
+ def parse(argv=ARGV)
+ argv = Array(argv).dup
+
+ while entry = argv.shift
+ # collect everything that is not an option
+ if entry[0] != ?- or entry.size < 2
+ @on_extra[entry]
+ next
+ end
+
+ # this is a long option
+ if entry[1] == ?-
+ opt, arg = entry.split "="
+ process argv, entry, opt, arg
+ next
+ end
+
+ # disambiguate short option group from short option with argument
+ opt, arg, rest = split entry, 2
+
+ # process first option
+ option = process argv, entry, opt, arg
+ next unless option and not option.arg?
+
+ # process the rest of the options
+ while rest.size > 0
+ opt, arg, rest = split rest, 1
+ opt = "-" + opt
+ option = process argv, opt, opt, arg
+ break if option.arg?
+ end
+ end
+
+ @extra
+ rescue ParseError => e
+ puts self
+ puts e
+ exit 1
+ end
+
+ # Adds a string of documentation text inline in the text generated
+ # from the options. See #on and #add.
+ def doc(str)
+ @doc << str
+ end
+
+ # Convenience method for providing -v, --version options.
+ def version(version, &block)
+ show = block || lambda { puts "#{File.basename $0} #{version}"; exit }
+ on "-v", "--version", "Show version", &show
+ end
+
+ # Convenience method for providing -h, --help options.
+ def help(&block)
+ help = block || lambda { puts self; exit 1 }
+ on "-h", "--help", "Show this message", &help
+ end
+
+ # Stores a block that will be called with unrecognized options
+ def on_extra(&block)
+ @on_extra = block
+ end
+
+ # Returns a string representation of the options and doc strings.
+ def to_s
+ @banner + "\n\n" + @doc.join("\n") + "\n"
+ end
+
+ # The methods below provide groups of options that
+ # are composed by the particular runners to provide
+ # their functionality
+
+ def configure(&block)
+ on("-B", "--config", "FILE",
+ "Load FILE containing configuration options", &block)
+ end
+
+ def name
+ on("-n", "--name", "RUBY_NAME",
+ "Set the value of RUBY_NAME (used to determine the implementation)") do |n|
+ Object.const_set :RUBY_NAME, n
+ end
+ end
+
+ def targets
+ on("-t", "--target", "TARGET",
+ "Implementation to run the specs, where:") do |t|
+ case t
+ when 'r', 'ruby'
+ config[:target] = 'ruby'
+ when 'r19', 'ruby19'
+ config[:target] = 'ruby1.9'
+ when 'x', 'rubinius'
+ config[:target] = './bin/rbx'
+ when 'X', 'rbx'
+ config[:target] = 'rbx'
+ when 'j', 'jruby'
+ config[:target] = 'jruby'
+ when 'i','ironruby'
+ config[:target] = 'ir'
+ else
+ config[:target] = t
+ end
+ end
+
+ doc ""
+ doc " r or ruby invokes ruby in PATH"
+ doc " r19, ruby19 or ruby1.9 invokes ruby1.9 in PATH"
+ doc " x or rubinius invokes ./bin/rbx"
+ doc " X or rbx invokes rbx in PATH"
+ doc " j or jruby invokes jruby in PATH"
+ doc " i or ironruby invokes ir in PATH\n"
+
+ on("-T", "--target-opt", "OPT",
+ "Pass OPT as a flag to the target implementation") do |t|
+ config[:flags] << t
+ end
+ on("-I", "--include", "DIR",
+ "Pass DIR through as the -I option to the target") do |d|
+ config[:includes] << "-I#{d}"
+ end
+ on("-r", "--require", "LIBRARY",
+ "Pass LIBRARY through as the -r option to the target") do |f|
+ config[:requires] << "-r#{f}"
+ end
+ end
+
+ def formatters
+ on("-f", "--format", "FORMAT",
+ "Formatter for reporting, where FORMAT is one of:") do |o|
+ case o
+ when 's', 'spec', 'specdoc'
+ config[:formatter] = SpecdocFormatter
+ when 'h', 'html'
+ config[:formatter] = HtmlFormatter
+ when 'd', 'dot', 'dotted'
+ config[:formatter] = DottedFormatter
+ when 'b', 'describe'
+ config[:formatter] = DescribeFormatter
+ when 'f', 'file'
+ config[:formatter] = FileFormatter
+ when 'u', 'unit', 'unitdiff'
+ config[:formatter] = UnitdiffFormatter
+ when 'm', 'summary'
+ config[:formatter] = SummaryFormatter
+ when 'a', '*', 'spin'
+ config[:formatter] = SpinnerFormatter
+ when 't', 'method'
+ config[:formatter] = MethodFormatter
+ when 'y', 'yaml'
+ config[:formatter] = YamlFormatter
+ else
+ puts "Unknown format: #{o}"
+ puts @parser
+ exit
+ end
+ end
+
+ doc ""
+ doc " s, spec, specdoc SpecdocFormatter"
+ doc " h, html, HtmlFormatter"
+ doc " d, dot, dotted DottedFormatter"
+ doc " f, file FileFormatter"
+ doc " u, unit, unitdiff UnitdiffFormatter"
+ doc " m, summary SummaryFormatter"
+ doc " a, *, spin SpinnerFormatter"
+ doc " t, method MethodFormatter"
+ doc " y, yaml YamlFormatter\n"
+
+ on("-o", "--output", "FILE",
+ "Write formatter output to FILE") do |f|
+ config[:output] = f
+ end
+ end
+
+ def filters
+ on("-e", "--example", "STR",
+ "Run examples with descriptions matching STR") do |o|
+ config[:includes] << o
+ end
+ on("-E", "--exclude", "STR",
+ "Exclude examples with descriptions matching STR") do |o|
+ config[:excludes] << o
+ end
+ on("-p", "--pattern", "PATTERN",
+ "Run examples with descriptions matching PATTERN") do |o|
+ config[:patterns] << Regexp.new(o)
+ end
+ on("-P", "--excl-pattern", "PATTERN",
+ "Exclude examples with descriptions matching PATTERN") do |o|
+ config[:xpatterns] << Regexp.new(o)
+ end
+ on("-g", "--tag", "TAG",
+ "Run examples with descriptions matching ones tagged with TAG") do |o|
+ config[:tags] << o
+ end
+ on("-G", "--excl-tag", "TAG",
+ "Exclude examples with descriptions matching ones tagged with TAG") do |o|
+ config[:xtags] << o
+ end
+ on("-w", "--profile", "FILE",
+ "Run examples for methods listed in the profile FILE") do |f|
+ config[:profiles] << f
+ end
+ on("-W", "--excl-profile", "FILE",
+ "Exclude examples for methods listed in the profile FILE") do |f|
+ config[:xprofiles] << f
+ end
+ end
+
+ def chdir
+ on("-C", "--chdir", "DIR",
+ "Change the working directory to DIR before running specs") do |d|
+ Dir.chdir d
+ end
+ end
+
+ def prefix
+ on("--prefix", "STR", "Prepend STR when resolving spec file names") do |p|
+ config[:prefix] = p
+ end
+ end
+
+ def pretend
+ on("-Z", "--dry-run",
+ "Invoke formatters and other actions, but don't execute the specs") do
+ MSpec.register_mode :pretend
+ end
+ end
+
+ def background
+ on("--background",
+ "Enable guard for specs that may hang in background processes") do
+ MSpec.register_mode :background
+ end
+ end
+
+ def unguarded
+ on("--unguarded", "Turn off all guards") do
+ MSpec.register_mode :unguarded
+ end
+ on("--no-ruby_bug", "Turn off the ruby_bug guard") do
+ MSpec.register_mode :no_ruby_bug
+ end
+ end
+
+ def randomize
+ on("-H", "--random",
+ "Randomize the list of spec files") do
+ MSpec.randomize
+ end
+ end
+
+ def verbose
+ on("-V", "--verbose", "Output the name of each file processed") do
+ obj = Object.new
+ def obj.start
+ @width = MSpec.retrieve(:files).inject(0) { |max, f| f.size > max ? f.size : max }
+ end
+ def obj.load
+ file = MSpec.retrieve :file
+ print "\n#{file.ljust(@width)}"
+ end
+ MSpec.register :start, obj
+ MSpec.register :load, obj
+ end
+
+ on("-m", "--marker", "MARKER",
+ "Output MARKER for each file processed") do |o|
+ obj = Object.new
+ obj.instance_variable_set :@marker, o
+ def obj.load
+ print @marker
+ end
+ MSpec.register :load, obj
+ end
+ end
+
+ def interrupt
+ on("--int-spec", "Control-C interupts the current spec only") do
+ config[:abort] = false
+ end
+ end
+
+ def verify
+ on("--report-on", "GUARD", "Report specs guarded by GUARD") do |g|
+ MSpec.register_mode :report_on
+ SpecGuard.guards << g.to_sym
+ end
+ on("-O", "--report", "Report guarded specs") do
+ MSpec.register_mode :report
+ end
+ on("-Y", "--verify",
+ "Verify that guarded specs pass and fail as expected") do
+ MSpec.register_mode :verify
+ end
+ end
+
+ def action_filters
+ on("-K", "--action-tag", "TAG",
+ "Spec descriptions marked with TAG will trigger the specified action") do |o|
+ config[:atags] << o
+ end
+ on("-S", "--action-string", "STR",
+ "Spec descriptions matching STR will trigger the specified action") do |o|
+ config[:astrings] << o
+ end
+ end
+
+ def actions
+ on("--spec-debug",
+ "Invoke the debugger when a spec description matches (see -K, -S)") do
+ config[:debugger] = true
+ end
+ on("--spec-gdb",
+ "Invoke Gdb when a spec description matches (see -K, -S)") do
+ config[:gdb] = true
+ end
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/utils/ruby_name.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/utils/ruby_name.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/utils/ruby_name.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,8 @@
+unless Object.const_defined?(:RUBY_NAME) and RUBY_NAME
+ if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE
+ RUBY_NAME = RUBY_ENGINE
+ else
+ require 'rbconfig'
+ RUBY_NAME = Config::CONFIG["RUBY_INSTALL_NAME"] || Config::CONFIG["ruby_install_name"]
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/utils/script.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/utils/script.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/utils/script.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,219 @@
+require 'mspec/guards/guard'
+require 'mspec/runner/formatters/dotted'
+
+# MSpecScript provides a skeleton for all the MSpec runner scripts.
+
+class MSpecScript
+ # Returns the config object. Maintained at the class
+ # level to easily enable simple config files. See the
+ # class method +set+.
+ def self.config
+ @config ||= {
+ :path => ['.', 'spec'],
+ :config_ext => '.mspec'
+ }
+ end
+
+ # Associates +value+ with +key+ in the config object. Enables
+ # simple config files of the form:
+ #
+ # class MSpecScript
+ # set :target, "ruby"
+ # set :files, ["one_spec.rb", "two_spec.rb"]
+ # end
+ def self.set(key, value)
+ config[key] = value
+ end
+
+ # Gets the value of +key+ from the config object. Simplifies
+ # getting values in a config file:
+ #
+ # class MSpecScript
+ # set :a, 1
+ # set :b, 2
+ # set :c, get(:a) + get(:b)
+ # end
+ def self.get(key)
+ config[key]
+ end
+
+ def initialize
+ config[:formatter] = nil
+ config[:includes] = []
+ config[:excludes] = []
+ config[:patterns] = []
+ config[:xpatterns] = []
+ config[:tags] = []
+ config[:xtags] = []
+ config[:profiles] = []
+ config[:xprofiles] = []
+ config[:atags] = []
+ config[:astrings] = []
+ config[:ltags] = []
+ config[:abort] = true
+ end
+
+ # Returns the config object maintained by the instance's class.
+ # See the class methods +set+ and +config+.
+ def config
+ MSpecScript.config
+ end
+
+ # Returns +true+ if the file was located in +config[:path]+,
+ # possibly appending +config[:config_ext]. Returns +false+
+ # otherwise.
+ def load(target)
+ names = [target]
+ unless target[-6..-1] == config[:config_ext]
+ names << target + config[:config_ext]
+ end
+
+ names.each do |name|
+ return Kernel.load(name) if File.exist?(File.expand_path(name))
+
+ config[:path].each do |dir|
+ file = File.join dir, name
+ return Kernel.load(file) if File.exist? file
+ end
+ end
+
+ false
+ end
+
+ # Attempts to load a default config file. First tries to load
+ # 'default.mspec'. If that fails, attempts to load a config
+ # file name constructed from the value of RUBY_ENGINE and the
+ # first two numbers in RUBY_VERSION. For example, on MRI 1.8.6,
+ # the file name would be 'ruby.1.8.mspec'.
+ def load_default
+ return if load 'default.mspec'
+
+ if Object.const_defined?(:RUBY_ENGINE)
+ engine = RUBY_ENGINE
+ else
+ engine = 'ruby'
+ end
+ load "#{engine}.#{SpecGuard.ruby_version}.mspec"
+ end
+
+ # Callback for enabling custom options. This version is a no-op.
+ # Provide an implementation specific version in a config file.
+ # Called by #options after the MSpec-provided options are added.
+ def custom_options(options)
+ options.doc " No custom options registered"
+ end
+
+ # Registers all filters and actions.
+ def register
+ if config[:formatter].nil?
+ config[:formatter] = @files.size < 50 ? DottedFormatter : FileFormatter
+ end
+
+ if config[:formatter]
+ formatter = config[:formatter].new(config[:output])
+ formatter.register
+ MSpec.store :formatter, formatter
+ end
+
+ MatchFilter.new(:include, *config[:includes]).register unless config[:includes].empty?
+ MatchFilter.new(:exclude, *config[:excludes]).register unless config[:excludes].empty?
+ RegexpFilter.new(:include, *config[:patterns]).register unless config[:patterns].empty?
+ RegexpFilter.new(:exclude, *config[:xpatterns]).register unless config[:xpatterns].empty?
+ TagFilter.new(:include, *config[:tags]).register unless config[:tags].empty?
+ TagFilter.new(:exclude, *config[:xtags]).register unless config[:xtags].empty?
+ ProfileFilter.new(:include, *config[:profiles]).register unless config[:profiles].empty?
+ ProfileFilter.new(:exclude, *config[:xprofiles]).register unless config[:xprofiles].empty?
+
+ DebugAction.new(config[:atags], config[:astrings]).register if config[:debugger]
+ GdbAction.new(config[:atags], config[:astrings]).register if config[:gdb]
+
+ custom_register
+ end
+
+ # Callback for enabling custom actions, etc. This version is a
+ # no-op. Provide an implementation specific version in a config
+ # file. Called by #register.
+ def custom_register
+ end
+
+ # Sets up signal handlers. Only a handler for SIGINT is
+ # registered currently.
+ def signals
+ if config[:abort]
+ Signal.trap "INT" do
+ puts "\nProcess aborted!"
+ exit! 1
+ end
+ end
+ end
+
+ # Attempts to resolve +partial+ as a file or directory name in the
+ # following order:
+ #
+ # 1. +partial+
+ # 2. +partial+ + "_spec.rb"
+ # 3. <tt>File.join(config[:prefix], partial)</tt>
+ # 4. <tt>File.join(config[:prefix], partial + "_spec.rb")</tt>
+ #
+ # If it is a file name, returns the name as an entry in an array.
+ # If it is a directory, returns all *_spec.rb files in the
+ # directory and subdirectories.
+ #
+ # If unable to resolve +partial+, returns <tt>Dir[partial]</tt>.
+ def entries(partial)
+ file = partial + "_spec.rb"
+ patterns = [partial]
+ patterns << file
+ if config[:prefix]
+ patterns << File.join(config[:prefix], partial)
+ patterns << File.join(config[:prefix], file)
+ end
+
+ patterns.each do |pattern|
+ expanded = File.expand_path(pattern)
+ return [pattern] if File.file?(expanded)
+
+ specs = File.join(pattern, "/**/*_spec.rb")
+ specs = File.expand_path(specs) rescue specs
+ return Dir[specs].sort if File.directory?(expanded)
+ end
+
+ Dir[partial]
+ end
+
+ # Resolves each entry in +list+ to a set of files.
+ #
+ # If the entry has a leading '^' character, the list of files
+ # is subtracted from the list of files accumulated to that point.
+ #
+ # If the entry has a leading ':' character, the corresponding
+ # key is looked up in the config object and the entries in the
+ # value retrieved are processed through #entries.
+ def files(list)
+ list.inject([]) do |files, item|
+ case item[0]
+ when ?^
+ files -= entries(item[1..-1])
+ when ?:
+ key = item[1..-1].to_sym
+ files += files(Array(config[key]))
+ else
+ files += entries(item)
+ end
+ files
+ end
+ end
+
+ # Instantiates an instance and calls the series of methods to
+ # invoke the script.
+ def self.main
+ $VERBOSE = nil unless ENV['OUTPUT_WARNINGS']
+ script = new
+ script.load_default
+ script.load '~/.mspecrc'
+ script.options
+ script.signals
+ script.register
+ script.run
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/utils/version.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/utils/version.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/utils/version.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,53 @@
+class SpecVersion
+ # If beginning implementations have a problem with this include, we can
+ # manually implement the relational operators that are needed.
+ include Comparable
+
+ # SpecVersion handles comparison correctly for the context by filling in
+ # missing version parts according to the value of +ceil+. If +ceil+ is
+ # +false+, 0 digits fill in missing version parts. If +ceil+ is +true+, 9
+ # digits fill in missing parts. (See e.g. VersionGuard and BugGuard.)
+ def initialize(version, ceil = false)
+ @version = version
+ @ceil = ceil
+ @integer = nil
+ end
+
+ def to_s
+ @version
+ end
+
+ def to_str
+ to_s
+ end
+
+ # Converts a string representation of a version major.minor.tiny.patchlevel
+ # to an integer representation so that comparisons can be made. For example,
+ # "1.8.6.77" < "1.8.6.123" would be false if compared as strings.
+ def to_i
+ unless @integer
+ major, minor, tiny, patch = @version.split "."
+ if @ceil
+ tiny = 99 unless tiny
+ patch = 9999 unless patch
+ end
+ parts = [major, minor, tiny, patch].map { |x| x.to_i }
+ @integer = ("1%02d%02d%02d%04d" % parts).to_i
+ end
+ @integer
+ end
+
+ def to_int
+ to_i
+ end
+
+ def <=>(other)
+ if other.respond_to? :to_int
+ other = Integer other
+ else
+ other = SpecVersion.new(String(other)).to_i
+ end
+
+ self.to_i <=> other
+ end
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec/version.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec/version.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec/version.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,5 @@
+require 'mspec/utils/version'
+
+module MSpec
+ VERSION = SpecVersion.new "1.5.10"
+end
Added: MacRuby/branches/experimental/mspec/lib/mspec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/lib/mspec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/lib/mspec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,11 @@
+require 'mspec/matchers'
+require 'mspec/expectations'
+require 'mspec/mocks'
+require 'mspec/runner'
+require 'mspec/guards'
+require 'mspec/helpers'
+
+# If the implementation on which the specs are run cannot
+# load pp from the standard library, add a pp.rb file that
+# defines the #pretty_inspect method on Object or Kernel.
+require 'pp'
\ No newline at end of file
Added: MacRuby/branches/experimental/mspec/mspec.gemspec
===================================================================
--- MacRuby/branches/experimental/mspec/mspec.gemspec (rev 0)
+++ MacRuby/branches/experimental/mspec/mspec.gemspec 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,33 @@
+Gem::Specification.new do |s|
+ s.name = %q{mspec}
+ s.version = "1.5.10"
+
+ 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{2009-3-1}
+ s.email = %q{bford at engineyard.com}
+ 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
Added: MacRuby/branches/experimental/mspec/spec/commands/mkspec_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/commands/mkspec_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/commands/mkspec_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,332 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/commands/mkspec'
+
+
+describe "The -c, --constant CONSTANT option" do
+ before :each do
+ @options = MSpecOptions.new
+ MSpecOptions.stub!(:new).and_return(@options)
+ @script = MkSpec.new
+ @config = @script.config
+ end
+
+ it "is enabled by #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-c", "--constant", "CONSTANT",
+ an_instance_of(String))
+ @script.options
+ end
+
+ it "adds CONSTANT to the list of constants" do
+ ["-c", "--constant"].each do |opt|
+ @config[:constants] = []
+ @script.options [opt, "Object"]
+ @config[:constants].should include("Object")
+ end
+ end
+end
+
+describe "The -b, --base DIR option" do
+ before :each do
+ @options = MSpecOptions.new
+ MSpecOptions.stub!(:new).and_return(@options)
+ @script = MkSpec.new
+ @config = @script.config
+ end
+
+ it "is enabled by #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-b", "--base", "DIR",
+ an_instance_of(String))
+ @script.options
+ end
+
+ it "sets the base directory relative to which the spec directories are created" do
+ ["-b", "--base"].each do |opt|
+ @config[:base] = nil
+ @script.options [opt, "superspec"]
+ @config[:base].should == File.expand_path("superspec")
+ end
+ end
+end
+
+describe "The -r, --require LIBRARY option" do
+ before :each do
+ @options = MSpecOptions.new
+ MSpecOptions.stub!(:new).and_return(@options)
+ @script = MkSpec.new
+ @config = @script.config
+ end
+
+ it "is enabled by #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-r", "--require", "LIBRARY",
+ an_instance_of(String))
+ @script.options
+ end
+
+ it "adds CONSTANT to the list of constants" do
+ ["-r", "--require"].each do |opt|
+ @config[:requires] = []
+ @script.options [opt, "libspec"]
+ @config[:requires].should include("libspec")
+ end
+ end
+end
+
+describe MkSpec, "#options" do
+ before :each do
+ @options = MSpecOptions.new
+ MSpecOptions.stub!(:new).and_return(@options)
+ @script = MkSpec.new
+ end
+
+ it "parses the command line options" do
+ @options.should_receive(:parse).with(["--this", "and", "--that"])
+ @script.options ["--this", "and", "--that"]
+ end
+
+ it "parses ARGV unless passed other options" do
+ @options.should_receive(:parse).with(ARGV)
+ @script.options
+ end
+
+ it "prints help and exits if passed an unrecognized option" do
+ @options.should_receive(:raise).with(MSpecOptions::ParseError, an_instance_of(String))
+ @options.stub!(:puts)
+ @options.stub!(:exit)
+ @script.options "--iunknown"
+ end
+end
+
+describe MkSpec, "#create_directory" do
+ before :each do
+ @script = MkSpec.new
+ @script.config[:base] = "spec"
+ end
+
+ it "prints a warning if a file with the directory name exists" do
+ File.should_receive(:exist?).and_return(true)
+ File.should_receive(:directory?).and_return(false)
+ FileUtils.should_not_receive(:mkdir_p)
+ @script.should_receive(:puts).with("spec/class already exists and is not a directory.")
+ @script.create_directory("Class").should == nil
+ end
+
+ it "does nothing if the directory already exists" do
+ File.should_receive(:exist?).and_return(true)
+ File.should_receive(:directory?).and_return(true)
+ FileUtils.should_not_receive(:mkdir_p)
+ @script.create_directory("Class").should == "spec/class"
+ end
+
+ it "creates the directory if it does not exist" do
+ File.should_receive(:exist?).and_return(false)
+ FileUtils.should_receive(:mkdir_p).with("spec/class")
+ @script.create_directory("Class").should == "spec/class"
+ end
+
+ it "creates the directory for a namespaced module if it does not exist" do
+ File.should_receive(:exist?).and_return(false)
+ FileUtils.should_receive(:mkdir_p).with("spec/struct/tms")
+ @script.create_directory("Struct::Tms").should == "spec/struct/tms"
+ end
+end
+
+describe MkSpec, "#write_requires" do
+ before :each do
+ @script = MkSpec.new
+ @script.config[:base] = "spec"
+
+ @file = mock("file")
+ File.stub!(:open).and_yield(@file)
+ end
+
+ it "writes the spec_helper require line" do
+ @file.should_receive(:puts).with("require File.dirname(__FILE__) + '/../../../spec_helper'")
+ @script.write_requires("spec/core/tcejbo", "spec/core/tcejbo/inspect_spec.rb")
+ end
+
+ it "writes require lines for each library specified on the command line" do
+ @file.stub!(:puts)
+ @file.should_receive(:puts).with("require File.dirname(__FILE__) + '/../../../spec_helper'")
+ @file.should_receive(:puts).with("require 'complex'")
+ @script.config[:requires] << 'complex'
+ @script.write_requires("spec/core/tcejbo", "spec/core/tcejbo/inspect_spec.rb")
+ end
+end
+
+describe MkSpec, "#write_spec" do
+ before :each do
+ @file = mock("file")
+ @file.stub!(:puts)
+ File.stub!(:open).and_yield(@file)
+
+ @script = MkSpec.new
+ @script.stub!(:puts)
+
+ @response = mock("system command response")
+ @response.stub!(:=~).and_return(false)
+ @script.stub!(:`).and_return(@response)
+ end
+
+ it "checks if specs exist for the method if the spec file exists" do
+ @script.should_receive(:`).with(
+ /mspec\/bin\/mspec-run --dry-run -fs -e 'Object#inspect' spec\/core\/tcejbo\/inspect_spec.rb/)
+ @script.write_spec("spec/core/tcejbo/inspect_spec.rb", "Object#inspect", true)
+ end
+
+ it "escapes the Regexp when checking for method name in the spec file output" do
+ Regexp.should_receive(:escape).with("Array#[]=")
+ @script.write_spec("spec/core/yarra/element_set_spec.rb", "Array#[]=", true)
+ end
+
+ it "returns nil if the spec file exists and contains a spec for the method" do
+ @response.stub!(:=~).and_return(true)
+ @script.write_spec("spec/core/tcejbo/inspect_spec.rb", "Object#inspect", true).should == nil
+ end
+
+ it "does not print the spec file name if it exists and contains a spec for the method" do
+ @response.stub!(:=~).and_return(true)
+ @script.should_not_receive(:puts)
+ @script.write_spec("spec/core/tcejbo/inspect_spec.rb", "Object#inspect", true)
+ end
+
+ it "prints the spec file name if a template spec is written" do
+ @script.should_receive(:puts).with("spec/core/tcejbo/inspect_spec.rb")
+ @script.write_spec("spec/core/tcejbo/inspect_spec.rb", "Object#inspect", true)
+ end
+
+ it "writes a template spec to the file if the spec file does not exist" do
+ @file.should_receive(:puts)
+ @script.should_receive(:puts).with("spec/core/tcejbo/inspect_spec.rb")
+ @script.write_spec("spec/core/tcejbo/inspect_spec.rb", "Object#inspect", false)
+ end
+
+ it "writes a template spec to the file if it exists but contains no spec for the method" do
+ @response.should_receive(:=~).and_return(false)
+ @file.should_receive(:puts)
+ @script.should_receive(:puts).with("spec/core/tcejbo/inspect_spec.rb")
+ @script.write_spec("spec/core/tcejbo/inspect_spec.rb", "Object#inspect", true)
+ end
+
+ it "writes a template spec" do
+ @file.should_receive(:puts).with(<<EOS)
+
+describe "Object#inspect" do
+ it "needs to be reviewed for spec completeness"
+end
+EOS
+ @script.write_spec("spec/core/tcejbo/inspect_spec.rb", "Object#inspect", true)
+ end
+end
+
+describe MkSpec, "#create_file" do
+ before :each do
+ @script = MkSpec.new
+ @script.stub!(:write_requires)
+ @script.stub!(:write_spec)
+
+ File.stub!(:exist?).and_return(false)
+ end
+
+ it "generates a file name based on the directory, class/module, and method" do
+ File.should_receive(:join).with("spec/tcejbo", "inspect_spec.rb"
+ ).and_return("spec/tcejbo/inspect_spec.rb")
+ @script.create_file("spec/tcejbo", "Object", "inspect", "Object#inspect")
+ end
+
+ it "does not call #write_requires if the spec file already exists" do
+ File.should_receive(:exist?).and_return(true)
+ @script.should_not_receive(:write_requires)
+ @script.create_file("spec/tcejbo", "Object", "inspect", "Object#inspect")
+ end
+
+ it "calls #write_requires if the spec file does not exist" do
+ File.should_receive(:exist?).and_return(false)
+ @script.should_receive(:write_requires).with(
+ "spec/tcejbo", "spec/tcejbo/inspect_spec.rb")
+ @script.create_file("spec/tcejbo", "Object", "inspect", "Object#inspect")
+ end
+
+ it "calls #write_spec with the file, method name" do
+ @script.should_receive(:write_spec).with(
+ "spec/tcejbo/inspect_spec.rb", "Object#inspect", false)
+ @script.create_file("spec/tcejbo", "Object", "inspect", "Object#inspect")
+ end
+end
+
+describe MkSpec, "#run" do
+ before :each do
+ @options = MSpecOptions.new
+ MSpecOptions.stub!(:new).and_return(@options)
+
+ @map = NameMap.new
+ NameMap.stub!(:new).and_return(@map)
+
+ @script = MkSpec.new
+ @script.stub!(:create_directory).and_return("spec/mkspec")
+ @script.stub!(:create_file)
+ @script.config[:constants] = [MkSpec]
+ end
+
+ it "loads files in the requires list" do
+ @script.stub!(:require)
+ @script.should_receive(:require).with("alib")
+ @script.should_receive(:require).with("blib")
+ @script.config[:requires] = ["alib", "blib"]
+ @script.run
+ end
+
+ it "creates a map of constants to methods" do
+ @map.should_receive(:map).with({}, @script.config[:constants]).and_return({})
+ @script.run
+ end
+
+ it "creates a map of Object.constants if not constants are specified" do
+ @script.config[:constants] = []
+ Object.stub!(:constants).and_return(["Object"])
+ @map.should_receive(:filter).with(["Object"]).and_return(["Object"])
+ @map.should_receive(:map).with({}, ["Object"]).and_return({})
+ @script.run
+ end
+
+ it "calls #create_directory for each class/module in the map" do
+ @script.should_receive(:create_directory).with("MkSpec").twice
+ @script.run
+ end
+
+ it "calls #create_file for each method on each class/module in the map" do
+ @map.should_receive(:map).with({}, @script.config[:constants]).and_return({"MkSpec#" => "run"})
+ @script.should_receive(:create_file).with("spec/mkspec", "MkSpec", "run", "MkSpec#run")
+ @script.run
+ end
+end
+
+describe MkSpec, ".main" do
+ before :each do
+ @script = mock("MkSpec", :null_object => true)
+ MkSpec.stub!(:new).and_return(@script)
+ end
+
+ it "sets MSPEC_RUNNER = '1' in the environment" do
+ ENV["MSPEC_RUNNER"] = "0"
+ MkSpec.main
+ ENV["MSPEC_RUNNER"].should == "1"
+ end
+
+ it "creates an instance of MSpecScript" do
+ MkSpec.should_receive(:new).and_return(@script)
+ MkSpec.main
+ end
+
+ it "calls the #options method on the script" do
+ @script.should_receive(:options)
+ MkSpec.main
+ end
+
+ it "calls the #run method on the script" do
+ @script.should_receive(:run)
+ MkSpec.main
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/commands/mspec_ci_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/commands/mspec_ci_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/commands/mspec_ci_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,142 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/runner/mspec'
+require 'mspec/runner/filters/tag'
+require 'mspec/commands/mspec-ci'
+
+describe MSpecCI, "#options" do
+ before :each do
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+
+ @script = MSpecCI.new
+ @script.stub!(:config).and_return(@config)
+ @script.stub!(:files).and_return([])
+ end
+
+ it "enables the chdir option" do
+ @options.should_receive(:chdir)
+ @script.options
+ end
+
+ it "enables the prefix option" do
+ @options.should_receive(:prefix)
+ @script.options
+ end
+
+ it "enables the config option" do
+ @options.should_receive(:configure)
+ @script.options
+ end
+
+ it "provides a custom action (block) to the config option" do
+ @script.should_receive(:load).with("cfg.mspec")
+ @script.options ["-B", "cfg.mspec"]
+ end
+
+ it "enables the name option" do
+ @options.should_receive(:name)
+ @script.options
+ end
+
+ it "enables the dry run option" do
+ @options.should_receive(:pretend)
+ @script.options
+ end
+
+ it "enables the background option" do
+ @options.should_receive(:background)
+ @script.options
+ end
+
+ it "enables the unguarded option" do
+ @options.should_receive(:unguarded)
+ @script.options
+ end
+
+ it "enables the interrupt single specs option" do
+ @options.should_receive(:interrupt)
+ @script.options
+ end
+
+ it "enables the formatter options" do
+ @options.should_receive(:formatters)
+ @script.options
+ end
+
+ it "enables the verbose option" do
+ @options.should_receive(:verbose)
+ @script.options
+ end
+
+ it "enables the action options" do
+ @options.should_receive(:actions)
+ @script.options
+ end
+
+ it "enables the action filter options" do
+ @options.should_receive(:action_filters)
+ @script.options
+ end
+
+ it "enables the version option" do
+ @options.should_receive(:version)
+ @script.options
+ end
+
+ it "enables the help option" do
+ @options.should_receive(:help)
+ @script.options
+ end
+
+ it "calls #custom_options" do
+ @script.should_receive(:custom_options).with(@options)
+ @script.options
+ end
+end
+
+describe MSpecCI, "#run" do
+ before :each do
+ MSpec.stub!(:process)
+
+ @filter = mock("TagFilter")
+ TagFilter.stub!(:new).and_return(@filter)
+ @filter.stub!(:register)
+
+ @config = { :ci_files => ["one", "two"] }
+ @script = MSpecCI.new
+ @script.stub!(:exit)
+ @script.stub!(:config).and_return(@config)
+ @script.stub!(:files).and_return(["one", "two"])
+ @script.options
+ end
+
+ it "registers the tags patterns" do
+ @config[:tags_patterns] = [/spec/, "tags"]
+ MSpec.should_receive(:register_tags_patterns).with([/spec/, "tags"])
+ @script.run
+ end
+
+ it "registers the files to process" do
+ MSpec.should_receive(:register_files).with(["one", "two"])
+ @script.run
+ end
+
+ it "registers a tag filter for 'fails', 'unstable', 'incomplete', 'critical', 'unsupported'" do
+ filter = mock("fails filter")
+ TagFilter.should_receive(:new).with(:exclude,
+ "fails", "critical", "unstable", "incomplete", "unsupported").and_return(filter)
+ filter.should_receive(:register)
+ @script.run
+ end
+
+ it "processes the files" do
+ MSpec.should_receive(:process)
+ @script.run
+ end
+
+ it "exits with the exit code registered with MSpec" do
+ MSpec.stub!(:exit_code).and_return(7)
+ @script.should_receive(:exit).with(7)
+ @script.run
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/commands/mspec_run_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/commands/mspec_run_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/commands/mspec_run_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,178 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/runner/mspec'
+require 'mspec/commands/mspec-run'
+
+describe MSpecRun, ".new" do
+ before :each do
+ @script = MSpecRun.new
+ end
+
+ it "sets config[:files] to an empty list" do
+ @script.config[:files].should == []
+ end
+end
+
+describe MSpecRun, "#options" do
+ before :each do
+ @stdout, $stdout = $stdout, IOStub.new
+
+ @argv = ["a", "b"]
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+
+ @script = MSpecRun.new
+ @script.stub!(:config).and_return(@config)
+ end
+
+ after :each do
+ $stdout = @stdout
+ end
+
+ it "enables the filter options" do
+ @options.should_receive(:filters)
+ @script.options @argv
+ end
+
+ it "enables the chdir option" do
+ @options.should_receive(:chdir)
+ @script.options @argv
+ end
+
+ it "enables the prefix option" do
+ @options.should_receive(:prefix)
+ @script.options @argv
+ end
+
+ it "enables the configure option" do
+ @options.should_receive(:configure)
+ @script.options @argv
+ end
+
+ it "provides a custom action (block) to the config option" do
+ @script.should_receive(:load).with("cfg.mspec")
+ @script.options ["-B", "cfg.mspec", "a"]
+ end
+
+ it "enables the name option" do
+ @options.should_receive(:name)
+ @script.options @argv
+ end
+
+ it "enables the randomize option to runs specs in random order" do
+ @options.should_receive(:randomize)
+ @script.options @argv
+ end
+
+ it "enables the dry run option" do
+ @options.should_receive(:pretend)
+ @script.options @argv
+ end
+
+ it "enables the background option" do
+ @options.should_receive(:background)
+ @script.options @argv
+ end
+
+ it "enables the unguarded option" do
+ @options.should_receive(:unguarded)
+ @script.options @argv
+ end
+
+ it "enables the interrupt single specs option" do
+ @options.should_receive(:interrupt)
+ @script.options @argv
+ end
+
+ it "enables the formatter options" do
+ @options.should_receive(:formatters)
+ @script.options @argv
+ end
+
+ it "enables the verbose option" do
+ @options.should_receive(:verbose)
+ @script.options @argv
+ end
+
+ it "enables the verify options" do
+ @options.should_receive(:verify)
+ @script.options @argv
+ end
+
+ it "enables the action options" do
+ @options.should_receive(:actions)
+ @script.options @argv
+ end
+
+ it "enables the action filter options" do
+ @options.should_receive(:action_filters)
+ @script.options @argv
+ end
+
+ it "enables the version option" do
+ @options.should_receive(:version)
+ @script.options @argv
+ end
+
+ it "enables the help option" do
+ @options.should_receive(:help)
+ @script.options @argv
+ end
+
+ it "exits if there are no files to process" do
+ @options.should_receive(:parse).and_return([])
+ @script.should_receive(:exit)
+ @script.options
+ $stdout.should =~ /No files specified/
+ end
+
+ it "calls #custom_options" do
+ @script.should_receive(:custom_options).with(@options)
+ @script.options @argv
+ end
+end
+
+describe MSpecRun, "#run" do
+ before :each do
+ @script = MSpecRun.new
+ @script.stub!(:exit)
+ @spec_dir = File.expand_path(File.dirname(__FILE__)+"/fixtures")
+ @file_patterns = [
+ @spec_dir+"/level2",
+ @spec_dir+"/one_spec.rb",
+ @spec_dir+"/two_spec.rb"]
+ @files = [
+ @spec_dir+"/level2/three_spec.rb",
+ @spec_dir+"/one_spec.rb",
+ @spec_dir+"/two_spec.rb"]
+ @script.options @file_patterns
+ end
+
+ it "registers the tags patterns" do
+ @script.config[:tags_patterns] = [/spec/, "tags"]
+ MSpec.should_receive(:register_tags_patterns).with([/spec/, "tags"])
+ @script.run
+ end
+
+ it "registers the files to process" do
+ MSpec.should_receive(:register_files).with(@files)
+ @script.run
+ end
+
+ it "uses config[:files] if no files are given on the command line" do
+ @script.config[:files] = @file_patterns
+ MSpec.should_receive(:register_files).with(@files)
+ @script.options []
+ @script.run
+ end
+
+ it "processes the files" do
+ MSpec.should_receive(:process)
+ @script.run
+ end
+
+ it "exits with the exit code registered with MSpec" do
+ MSpec.stub!(:exit_code).and_return(7)
+ @script.should_receive(:exit).with(7)
+ @script.run
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/commands/mspec_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/commands/mspec_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/commands/mspec_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,425 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'yaml'
+require 'mspec/commands/mspec'
+
+describe MSpecMain, "#options" do
+ before :each do
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+
+ @script = MSpecMain.new
+ @script.stub!(:config).and_return(@config)
+ @script.stub!(:load)
+ end
+
+ it "enables the configure option" do
+ @options.should_receive(:configure)
+ @script.options
+ end
+
+ it "provides a custom action (block) to the config option" do
+ @script.options ["-B", "config"]
+ @config[:options].should include("-B", "config")
+ end
+
+ it "loads the file specified by the config option" do
+ @script.should_receive(:load).with("config")
+ @script.options ["-B", "config"]
+ end
+
+ it "enables the target options" do
+ @options.should_receive(:targets)
+ @script.options
+ end
+
+ it "sets config[:options] to all argv entries that are not registered options" do
+ @options.on "-X", "--exclude", "ARG", "description"
+ @script.options [".", "-G", "fail", "-X", "ARG", "--list", "unstable", "some/file.rb"]
+ @config[:options].should == [".", "-G", "fail", "--list", "unstable", "some/file.rb"]
+ end
+
+ it "calls #custom_options" do
+ @script.should_receive(:custom_options).with(@options)
+ @script.options
+ end
+end
+
+describe MSpecMain, "#parallel" do
+ before :all do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ end
+
+ before :each do
+ @script = MSpecMain.new
+ @ruby_platform = Object.const_get :RUBY_PLATFORM
+ end
+
+ after :each do
+ Object.const_set :RUBY_PLATFORM, @ruby_platform
+ end
+
+ it "returns false if JRUBY_VERSION is defined" do
+ Object.should_receive(:const_defined?).with(:JRUBY_VERSION).and_return(true)
+ @script.parallel.should == false
+ end
+
+ it "returns false if RUBY_PLATFORM matches mswin" do
+ Object.const_set :RUBY_PLATFORM, "i386-mswin32"
+ @script.parallel.should == false
+ end
+
+ it "returns false if RUBY_PLATFORM matches mingw" do
+ Object.const_set :RUBY_PLATFORM, "i386-mingw32"
+ @script.parallel.should == false
+ end
+
+ it "returns true unless JRUBY_VERSION is set or RUBY_PLATFORM matches mswin or mingw" do
+ Object.should_receive(:const_defined?).with(:JRUBY_VERSION).and_return(false)
+ Object.const_set :RUBY_PLATFORM, "i686-linux"
+ @script.parallel.should == true
+ end
+end
+
+describe MSpecMain, "#fork" do
+ before :each do
+ @script = MSpecMain.new
+ ScratchPad.clear
+ end
+
+ it "calls Kernel.fork if #parallel returns true" do
+ @script.should_receive(:parallel).and_return(true)
+ Kernel.should_receive(:fork)
+ @script.fork
+ end
+
+ it "calls the block if #parallel returns false" do
+ @script.should_receive(:parallel).and_return(false)
+ Kernel.should_not_receive(:fork)
+ @script.fork { ScratchPad.record :called }
+ ScratchPad.recorded.should == :called
+ end
+end
+
+describe MSpecMain, "#report" do
+ before :each do
+ @stdout, $stdout = $stdout, IOStub.new
+
+ @timer = mock("timer", :null_object => true)
+ @timer.stub!(:format).and_return("Finished in 42 seconds")
+ @file = mock("file", :null_object => true)
+
+ File.stub!(:delete)
+ YAML.stub!(:load)
+
+ @hash = { "files"=>1, "examples"=>1, "expectations"=>2, "failures"=>0, "errors"=>0 }
+ File.stub!(:open).and_yield(@file).and_return(@hash)
+
+ @script = MSpecMain.new
+ end
+
+ after :each do
+ $stdout = @stdout
+ end
+
+ it "calls YAML.load for each element in the passed array" do
+ YAML.should_receive(:load).with(@file).twice
+ @script.report(["a", "b"], @timer)
+ end
+
+ it "calls File.delete for each element in the passed array" do
+ File.should_receive(:delete).with("a")
+ File.should_receive(:delete).with("b")
+ @script.report(["a", "b"], @timer)
+ end
+
+ it "outputs a summary without errors" do
+ @script.report(["a", "b"], @timer)
+ $stdout.should ==
+%[
+
+Finished in 42 seconds
+
+2 files, 2 examples, 4 expectations, 0 failures, 0 errors
+]
+ end
+
+ it "outputs a summary with errors" do
+ @hash["exceptions"] = [
+ "Some#method works real good FAILED\nExpected real good\n to equal fail\n\nfoo.rb:1\nfoo.rb:2",
+ "Some#method never fails ERROR\nExpected 5\n to equal 3\n\nfoo.rb:1\nfoo.rb:2"
+ ]
+ @script.report(["a"], @timer)
+ $stdout.should ==
+%[
+
+1)
+Some#method works real good FAILED
+Expected real good
+ to equal fail
+
+foo.rb:1
+foo.rb:2
+
+2)
+Some#method never fails ERROR
+Expected 5
+ to equal 3
+
+foo.rb:1
+foo.rb:2
+
+Finished in 42 seconds
+
+1 file, 1 example, 2 expectations, 0 failures, 0 errors
+]
+ end
+end
+
+describe MSpecMain, "#multi_exec" do
+ before :each do
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+
+ @config[:target] = "target"
+ @config[:ci_files] = ["a", "b"]
+
+ @script = MSpecMain.new
+ @script.stub!(:config).and_return(@config)
+ @script.stub!(:fork)
+ @script.stub!(:report)
+ Process.stub!(:waitall)
+ end
+
+ it "calls #fork for each entry in config[:ci_files]" do
+ @script.should_receive(:fork).twice
+ @script.multi_exec []
+ end
+
+ it "calls Process.waitall" do
+ Process.should_receive(:waitall)
+ @script.multi_exec []
+ end
+
+ it "calls #report" do
+ @script.should_receive(:report)
+ @script.multi_exec []
+ end
+end
+
+describe MSpecMain, "#run" do
+ before :each do
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+ @script = MSpecMain.new
+ @script.stub!(:config).and_return(@config)
+ @script.stub!(:exec)
+ end
+
+ it "sets MSPEC_RUNNER = '1' in the environment" do
+ ENV["MSPEC_RUNNER"] = "0"
+ @script.run
+ ENV["MSPEC_RUNNER"].should == "1"
+ end
+
+ it "sets RUBY_EXE = config[:target] in the environment" do
+ ENV["RUBY_EXE"] = nil
+ @script.run
+ ENV["RUBY_EXE"].should == @config[:target]
+ end
+
+ it "sets RUBY_FLAGS = config[:flags] in the environment" do
+ ENV["RUBY_FLAGS"] = nil
+ @config[:flags] = ["-w", "-Q"]
+ @script.run
+ ENV["RUBY_FLAGS"].should == "-w -Q"
+ end
+
+ it "uses exec to invoke the runner script" do
+ @script.should_receive(:exec).with("ruby", "-v", %r"mspec/bin/mspec-run$")
+ @script.options []
+ @script.run
+ end
+
+ it "calls #multi_exec if the command is 'ci' and the multi option is passed" do
+ @script.should_receive(:multi_exec).and_return do |arg|
+ arg.length.should == 3
+ arg[0].should == "-v"
+ arg[1].should =~ %r"mspec/bin/mspec-ci$"
+ arg[2].should == "-fy"
+ end
+ @script.options ["ci", "-j"]
+ @script.run
+ end
+end
+
+describe "The -D, --gdb option" do
+ before :each do
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+ @script = MSpecMain.new
+ @script.stub!(:config).and_return(@config)
+ end
+
+ it "is enabled by #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-D", "--gdb", an_instance_of(String))
+ @script.options
+ end
+
+ it "sets flags to --gdb" do
+ ["-D", "--gdb"].each do |opt|
+ @config[:flags] = []
+ @script.options [opt]
+ @config[:flags].should include("--gdb")
+ end
+ end
+end
+
+describe "The -A, --valgrind option" do
+ before :each do
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+ @script = MSpecMain.new
+ @script.stub!(:config).and_return(@config)
+ end
+
+ it "is enabled by #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-A", "--valgrind", an_instance_of(String))
+ @script.options
+ end
+
+ it "sets flags to --valgrind" do
+ ["-A", "--valgrind"].each do |opt|
+ @config[:flags] = []
+ @script.options [opt]
+ @config[:flags].should include("--valgrind")
+ end
+ end
+end
+
+describe "The --warnings option" do
+ before :each do
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+ @script = MSpecMain.new
+ @script.stub!(:config).and_return(@config)
+ end
+
+ it "is enabled by #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("--warnings", an_instance_of(String))
+ @script.options
+ end
+
+ it "sets flags to -w" do
+ @config[:flags] = []
+ @script.options ["--warnings"]
+ @config[:flags].should include("-w")
+ end
+
+ it "set OUTPUT_WARNINGS = '1' in the environment" do
+ ENV['OUTPUT_WARNINGS'] = '0'
+ @script.options ["--warnings"]
+ ENV['OUTPUT_WARNINGS'].should == '1'
+ end
+end
+
+describe "The -j, --multi option" do
+ before :each do
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+ @script = MSpecMain.new
+ @script.stub!(:config).and_return(@config)
+ end
+
+ it "is enabled by #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-j", "--multi", an_instance_of(String))
+ @script.options
+ end
+
+ it "sets the multiple process option" do
+ ["-j", "--multi"].each do |opt|
+ @config[:multi] = nil
+ @script.options [opt]
+ @config[:multi].should == true
+ end
+ end
+
+ it "sets the formatter to YamlFormatter" do
+ ["-j", "--multi"].each do |opt|
+ @config[:options] = []
+ @script.options [opt]
+ @config[:options].should include("-fy")
+ end
+ end
+end
+
+describe "The -h, --help option" do
+ before :each do
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+ @script = MSpecMain.new
+ @script.stub!(:config).and_return(@config)
+ end
+
+ it "is enabled by #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-h", "--help", an_instance_of(String))
+ @script.options
+ end
+
+ it "passes the option to the subscript" do
+ ["-h", "--help"].each do |opt|
+ @config[:options] = []
+ @script.options ["ci", opt]
+ @config[:options].sort.should == ["-h"]
+ end
+ end
+
+ it "prints help and exits" do
+ @script.should_receive(:puts).twice
+ @script.should_receive(:exit).twice
+ ["-h", "--help"].each do |opt|
+ @script.options [opt]
+ end
+ end
+end
+
+describe "The -v, --version option" do
+ before :each do
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+ @script = MSpecMain.new
+ @script.stub!(:config).and_return(@config)
+ end
+
+ it "is enabled by #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-v", "--version", an_instance_of(String))
+ @script.options
+ end
+
+ it "passes the option to the subscripts" do
+ ["-v", "--version"].each do |opt|
+ @config[:options] = []
+ @script.options ["ci", opt]
+ @config[:options].sort.should == ["-v"]
+ end
+ end
+
+ it "prints the version and exits if no subscript is invoked" do
+ @config[:command] = nil
+ File.stub!(:basename).and_return("mspec")
+ @script.should_receive(:puts).twice.with("mspec #{MSpec::VERSION}")
+ @script.should_receive(:exit).twice
+ ["-v", "--version"].each do |opt|
+ @script.options [opt]
+ end
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/commands/mspec_tag_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/commands/mspec_tag_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/commands/mspec_tag_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,410 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/runner/mspec'
+require 'mspec/commands/mspec-tag'
+require 'mspec/runner/actions/tag'
+require 'mspec/runner/actions/taglist'
+require 'mspec/runner/actions/tagpurge'
+
+describe MSpecTag, ".new" do
+ before :each do
+ @script = MSpecTag.new
+ end
+
+ it "sets config[:ltags] to an empty list" do
+ @script.config[:ltags].should == []
+ end
+
+ it "sets config[:tagger] to :add" do
+ @script.config[:tagger] = :add
+ end
+
+ it "sets config[:tag] to 'fails:'" do
+ @script.config[:tag] = 'fails:'
+ end
+
+ it "sets config[:outcome] to :fail" do
+ @script.config[:outcome] = :fail
+ end
+end
+
+describe MSpecTag, "#options" do
+ before :each do
+ @stdout, $stdout = $stdout, IOStub.new
+
+ @argv = ["a", "b"]
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+
+ @script = MSpecTag.new
+ @script.stub!(:config).and_return(@config)
+ end
+
+ after :each do
+ $stdout = @stdout
+ end
+
+ it "enables the filter options" do
+ @options.should_receive(:filters)
+ @script.options @argv
+ end
+
+ it "enables the configure option" do
+ @options.should_receive(:configure)
+ @script.options @argv
+ end
+
+ it "provides a custom action (block) to the config option" do
+ @script.should_receive(:load).with("cfg.mspec")
+ @script.options ["-B", "cfg.mspec", "a"]
+ end
+
+ it "enables the name option" do
+ @options.should_receive(:name)
+ @script.options @argv
+ end
+
+ it "enables the dry run option" do
+ @options.should_receive(:pretend)
+ @script.options @argv
+ end
+
+ it "enables the unguarded option" do
+ @options.should_receive(:unguarded)
+ @script.options @argv
+ end
+
+ it "enables the interrupt single specs option" do
+ @options.should_receive(:interrupt)
+ @script.options @argv
+ end
+
+ it "enables the formatter options" do
+ @options.should_receive(:formatters)
+ @script.options @argv
+ end
+
+ it "enables the verbose option" do
+ @options.should_receive(:verbose)
+ @script.options @argv
+ end
+
+ it "enables the version option" do
+ @options.should_receive(:version)
+ @script.options @argv
+ end
+
+ it "enables the help option" do
+ @options.should_receive(:help)
+ @script.options @argv
+ end
+
+ it "calls #custom_options" do
+ @script.should_receive(:custom_options).with(@options)
+ @script.options @argv
+ end
+
+ it "exits if there are no files to process" do
+ @options.should_receive(:parse).and_return([])
+ @script.should_receive(:exit)
+ @script.options
+ $stdout.should =~ /No files specified/
+ end
+end
+
+describe MSpecTag, "options" do
+ before :each do
+ @options, @config = new_option
+ MSpecOptions.stub!(:new).and_return(@options)
+ @script = MSpecTag.new
+ @script.stub!(:config).and_return(@config)
+ end
+
+ describe "-N, --add TAG" do
+ it "is enabled with #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-N", "--add", "TAG", an_instance_of(String))
+ @script.options ["file.rb"]
+ end
+
+ it "sets the mode to :add and sets the tag to TAG" do
+ ["-N", "--add"].each do |opt|
+ @config[:tagger] = nil
+ @config[:tag] = nil
+ @script.options [opt, "taggit", "file.rb"]
+ @config[:tagger].should == :add
+ @config[:tag].should == "taggit:"
+ end
+ end
+ end
+
+ describe "-R, --del TAG" do
+ it "is enabled with #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-R", "--del", "TAG",
+ an_instance_of(String))
+ @script.options ["file.rb"]
+ end
+
+ it "it sets the mode to :del, the tag to TAG, and the outcome to :pass" do
+ ["-R", "--del"].each do |opt|
+ @config[:tagger] = nil
+ @config[:tag] = nil
+ @config[:outcome] = nil
+ @script.options [opt, "taggit", "file.rb"]
+ @config[:tagger].should == :del
+ @config[:tag].should == "taggit:"
+ @config[:outcome].should == :pass
+ end
+ end
+ end
+
+ describe "-Q, --pass" do
+ it "is enabled with #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-Q", "--pass", an_instance_of(String))
+ @script.options ["file.rb"]
+ end
+
+ it "sets the outcome to :pass" do
+ ["-Q", "--pass"].each do |opt|
+ @config[:outcome] = nil
+ @script.options [opt, "file.rb"]
+ @config[:outcome].should == :pass
+ end
+ end
+ end
+
+ describe "-F, --fail" do
+ it "is enabled with #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-F", "--fail", an_instance_of(String))
+ @script.options ["file.rb"]
+ end
+
+ it "sets the outcome to :fail" do
+ ["-F", "--fail"].each do |opt|
+ @config[:outcome] = nil
+ @script.options [opt, "file.rb"]
+ @config[:outcome].should == :fail
+ end
+ end
+ end
+
+ describe "-L, --all" do
+ it "is enabled with #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-L", "--all", an_instance_of(String))
+ @script.options ["file.rb"]
+ end
+
+ it "sets the outcome to :all" do
+ ["-L", "--all"].each do |opt|
+ @config[:outcome] = nil
+ @script.options [opt, "file.rb"]
+ @config[:outcome].should == :all
+ end
+ end
+ end
+
+ describe "--list TAG" do
+ it "is enabled with #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("--list", "TAG", an_instance_of(String))
+ @script.options ["file.rb"]
+ end
+
+ it "sets the mode to :list" do
+ @config[:tagger] = nil
+ @script.options ["--list", "TAG", "file.rb"]
+ @config[:tagger].should == :list
+ end
+
+ it "sets ltags to include TAG" do
+ @config[:tag] = nil
+ @script.options ["--list", "TAG", "file.rb"]
+ @config[:ltags].should == ["TAG"]
+ end
+ end
+
+ describe "--list-all" do
+ it "is enabled with #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("--list-all", an_instance_of(String))
+ @script.options ["file.rb"]
+ end
+
+ it "sets the mode to :list_all" do
+ @config[:tagger] = nil
+ @script.options ["--list-all", "file.rb"]
+ @config[:tagger].should == :list_all
+ end
+ end
+
+ describe "--purge" do
+ it "is enabled with #options" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("--purge", an_instance_of(String))
+ @script.options ["file.rb"]
+ end
+
+ it "sets the mode to :purge" do
+ @config[:tagger] = nil
+ @script.options ["--purge", "file.rb"]
+ @config[:tagger].should == :purge
+ end
+ end
+end
+
+describe MSpecTag, "#run" do
+ before :each do
+ MSpec.stub!(:process)
+
+ options = mock("MSpecOptions", :null_object => true)
+ options.stub!(:parse).and_return(["one", "two"])
+ MSpecOptions.stub!(:new).and_return(options)
+
+ @config = { }
+ @script = MSpecTag.new
+ @script.stub!(:exit)
+ @script.stub!(:config).and_return(@config)
+ @script.stub!(:files).and_return(["one", "two"])
+ @script.options
+ end
+
+ it "registers the tags patterns" do
+ @config[:tags_patterns] = [/spec/, "tags"]
+ MSpec.should_receive(:register_tags_patterns).with([/spec/, "tags"])
+ @script.run
+ end
+
+ it "registers the files to process" do
+ MSpec.should_receive(:register_files).with(["one", "two"])
+ @script.run
+ end
+
+ it "processes the files" do
+ MSpec.should_receive(:process)
+ @script.run
+ end
+
+ it "exits with the exit code registered with MSpec" do
+ MSpec.stub!(:exit_code).and_return(7)
+ @script.should_receive(:exit).with(7)
+ @script.run
+ end
+end
+
+describe MSpecTag, "#register" do
+ before :each do
+ @script = MSpecTag.new
+ @config = @script.config
+ @config[:tag] = "fake:"
+ @config[:atags] = []
+ @config[:astrings] = []
+ @config[:ltags] = ["fails", "unstable"]
+
+ @script.stub!(:files).and_return([])
+ @script.options "fake"
+
+ @t = mock("TagAction")
+ @t.stub!(:register)
+
+ @tl = mock("TagListAction")
+ @tl.stub!(:register)
+ end
+
+ it "creates a TagAction if config[:tagger] is :add" do
+ TagAction.should_receive(:new).with(:add, :fail, "fake", nil, [], []).and_return(@t)
+ @script.register
+ end
+
+ it "creates a TagAction if config[:tagger] is :del" do
+ @config[:tagger] = :del
+ @config[:outcome] = :pass
+ TagAction.should_receive(:new).with(:del, :pass, "fake", nil, [], []).and_return(@t)
+ @script.register
+ end
+
+ it "calls #register on the TagAction instance" do
+ TagAction.should_receive(:new).and_return(@t)
+ @t.should_receive(:register)
+ @script.register
+ end
+
+ it "raises an ArgumentError if no recognized action is given" do
+ @config[:tagger] = :totally_whack
+ lambda { @script.register }.should raise_error(ArgumentError)
+ end
+
+ describe "when config[:tagger] is :list" do
+ before :each do
+ @config[:tagger] = :list
+ end
+
+ it "creates a TagListAction" do
+ TagListAction.should_receive(:new).with(@config[:ltags]).and_return(@tl)
+ @tl.should_receive(:register)
+ @script.register
+ end
+
+ it "registers MSpec pretend mode" do
+ MSpec.should_receive(:register_mode).with(:pretend)
+ @script.register
+ end
+
+ it "sets config[:formatter] to false" do
+ @script.register
+ @config[:formatter].should be_false
+ end
+ end
+
+ describe "when config[:tagger] is :list_all" do
+ before :each do
+ @config[:tagger] = :list_all
+ end
+
+ it "creates a TagListAction" do
+ TagListAction.should_receive(:new).with(nil).and_return(@tl)
+ @tl.should_receive(:register)
+ @script.register
+ end
+
+ it "registers MSpec pretend mode" do
+ MSpec.should_receive(:register_mode).with(:pretend)
+ @script.register
+ end
+
+ it "sets config[:formatter] to false" do
+ @script.register
+ @config[:formatter].should be_false
+ end
+ end
+
+ describe "when config[:tagger] is :purge" do
+ before :each do
+ MSpec.stub!(:register_mode)
+ @config[:tagger] = :purge
+ end
+
+ it "creates a TagPurgeAction" do
+ TagPurgeAction.should_receive(:new).and_return(@tl)
+ @tl.should_receive(:register)
+ @script.register
+ end
+
+ it "registers MSpec in pretend mode" do
+ MSpec.should_receive(:register_mode).with(:pretend)
+ @script.register
+ end
+
+ it "registers MSpec in unguarded mode" do
+ MSpec.should_receive(:register_mode).with(:unguarded)
+ @script.register
+ end
+
+ it "sets config[:formatter] to false" do
+ @script.register
+ @config[:formatter].should be_false
+ end
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/expectations/expectations_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/expectations/expectations_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/expectations/expectations_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,29 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+
+describe ExpectationNotMetError do
+ it "is a subclass of StandardError" do
+ ExpectationNotMetError.ancestors.should include(StandardError)
+ end
+end
+
+describe ExpectationNotFoundError do
+ it "is a subclass of StandardError" do
+ ExpectationNotFoundError.ancestors.should include(StandardError)
+ end
+end
+
+describe ExpectationNotFoundError, "#message" do
+ it "returns 'No behavior expectation was found in the example'" do
+ m = ExpectationNotFoundError.new.message
+ m.should == "No behavior expectation was found in the example"
+ end
+end
+
+describe Expectation, "#fail_with" do
+ it "raises an ExpectationNotMetError" do
+ lambda {
+ Expectation.fail_with "expected this", "to equal that"
+ }.should raise_error(ExpectationNotMetError, "expected this to equal that")
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/expectations/should_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/expectations/should_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/expectations/should_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,129 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/base'
+require 'mspec/runner/mspec'
+
+class Object
+ alias_method :rspec_should, :should
+ alias_method :rspec_should_not, :should_not
+end
+require 'mspec/expectations/should'
+class Object
+ alias_method :mspec_should, :should
+ alias_method :mspec_should_not, :should_not
+ alias_method :should, :rspec_should
+ alias_method :should_not, :rspec_should_not
+end
+
+# Adapted from RSpec 1.0.8
+describe Object, "#should" do
+ before :each do
+ class Object; alias_method :should, :mspec_should; end
+
+ @state = mock("example state", :null_object => true)
+ context = mock("context state", :null_object => true)
+ context.stub!(:state).and_return(@state)
+ MSpec.stub!(:current).and_return(context)
+ MSpec.stub!(:actions)
+
+ @target = "target"
+ @matcher = mock("matcher", :null_object => true)
+ end
+
+ after :each do
+ class Object; alias_method :should, :rspec_should; end
+ end
+
+ it "accepts and interacts with a matcher" do
+ @matcher.should_receive(:matches?).with(@target).and_return(true)
+ @target.should @matcher
+ end
+
+ it "calls #failure_message when matcher #matches? returns false" do
+ @matcher.should_receive(:matches?).with(@target).and_return(false)
+ @matcher.should_receive(:failure_message).and_return(["expected", "actual"])
+ @target.should @matcher rescue nil
+ end
+
+ it "raises an ExpectationNotMetError when matcher #matches? returns false" do
+ @matcher.should_receive(:matches?).with(@target).and_return(false)
+ @matcher.should_receive(:failure_message).and_return(["expected", "actual"])
+ lambda {
+ @target.should @matcher
+ }.should raise_error(ExpectationNotMetError, "expected actual")
+ end
+
+ it "returns a PostiveOperatorMatcher instance when not passed a matcher" do
+ matcher = should
+ class Object; alias_method :should, :rspec_should; end
+ matcher.should be_instance_of(PositiveOperatorMatcher)
+ end
+
+ it "invokes the MSpec :expectation actions" do
+ MSpec.should_receive(:actions).with(:expectation, @state)
+ @target.should @matcher
+ end
+
+ it "registers that an expectation has been encountered" do
+ MSpec.should_receive(:expectation)
+ @target.should @matcher
+ end
+end
+
+describe Object, "#should_not" do
+ before :each do
+ class Object; alias_method :should, :mspec_should; end
+ class Object; alias_method :should_not, :mspec_should_not; end
+
+ @state = mock("example state", :null_object => true)
+ context = mock("context state", :null_object => true)
+ context.stub!(:state).and_return(@state)
+ MSpec.stub!(:current).and_return(context)
+ MSpec.stub!(:actions)
+
+ @target = "target"
+ @matcher = mock("matcher", :null_object => true)
+ end
+
+ after :each do
+ class Object; alias_method :should, :rspec_should; end
+ class Object; alias_method :should_not, :rspec_should_not; end
+ end
+
+ it "accepts and interacts with a matcher" do
+ @matcher.should_receive(:matches?).with(@target).and_return(false)
+ @target.should_not @matcher
+ end
+
+ it "calls #negative_failure_message when matcher.matches? returns true" do
+ @matcher.should_receive(:matches?).with(@target).and_return(true)
+ @matcher.should_receive(:negative_failure_message).and_return(["expected", "actual"])
+ @target.should_not @matcher rescue nil
+ end
+
+ it "raises an ExpectationNotMetError when matcher.matches? returns true" do
+ @matcher.should_receive(:matches?).with(@target).and_return(true)
+ @matcher.should_receive(:negative_failure_message).and_return(["expected", "actual"])
+ lambda {
+ @target.should_not @matcher
+ }.should raise_error(ExpectationNotMetError, "expected actual")
+ end
+
+ it "returns a NegativeOperatorMatcher instance when not passed a matcher" do
+ matcher = should_not nil
+ class Object; alias_method :should, :rspec_should; end
+ matcher.should be_instance_of(NegativeOperatorMatcher)
+ end
+
+ it "invokes the MSpec :expectation actions" do
+ MSpec.should_receive(:actions).with(:expectation, @state)
+ @matcher.should_receive(:negative_failure_message).and_return(["expected", "actual"])
+ @target.should_not @matcher rescue nil
+ end
+
+ it "registers that an expectation has been encountered" do
+ MSpec.should_receive(:expectation)
+ @matcher.should_receive(:negative_failure_message).and_return(["expected", "actual"])
+ @target.should_not @matcher rescue nil
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/background_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/background_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/background_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,36 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/background'
+
+describe Object, "#process_is_foreground" do
+ before :each do
+ MSpec.clear_modes
+ ScratchPad.clear
+
+ @guard = BackgroundGuard.new
+ BackgroundGuard.stub!(:new).and_return(@guard)
+ end
+
+ it "yields if MSpec.mode?(:background) is false" do
+ MSpec.mode?(:background).should be_false
+ process_is_foreground { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "does not yield if MSpec.mode?(:background) is true" do
+ MSpec.register_mode :background
+ process_is_foreground { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "sets the name of the guard to :process_is_foreground" do
+ process_is_foreground { ScratchPad.record :yield }
+ @guard.name.should == :process_is_foreground
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:unregister)
+ lambda do
+ process_is_foreground { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/bug_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/bug_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/bug_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,140 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/utils/ruby_name'
+require 'mspec/guards/bug'
+
+describe BugGuard, "#match? when #implementation? is 'ruby'" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ end
+
+ before :each do
+ @ruby_version = Object.const_get :RUBY_VERSION
+ @ruby_patch = Object.const_get :RUBY_PATCHLEVEL
+ @ruby_name = Object.const_get :RUBY_NAME
+
+ Object.const_set :RUBY_VERSION, '1.8.6'
+ Object.const_set :RUBY_PATCHLEVEL, 114
+ Object.const_set :RUBY_NAME, 'ruby'
+ end
+
+ after :each do
+ Object.const_set :RUBY_VERSION, @ruby_version
+ Object.const_set :RUBY_PATCHLEVEL, @ruby_patch
+ Object.const_set :RUBY_NAME, @ruby_name
+ end
+
+ it "returns false when version argument is less than RUBY_VERSION and RUBY_PATCHLEVEL" do
+ BugGuard.new("#1", "1.8.5").match?.should == false
+ BugGuard.new("#1", "1.8.6.113").match?.should == false
+ end
+
+ it "returns true when version argument is equal to RUBY_VERSION and RUBY_PATCHLEVEL" do
+ BugGuard.new("#1", "1.8.6.114").match?.should == true
+ end
+
+ it "returns true when version argument is greater than RUBY_VERSION and RUBY_PATCHLEVEL" do
+ BugGuard.new("#1", "1.8.7").match?.should == true
+ BugGuard.new("#1", "1.8.6.115").match?.should == true
+ end
+
+ it "returns true when version argument implicitly includes RUBY_VERSION and RUBY_PATCHLEVEL" do
+ BugGuard.new("#1", "1.8").match?.should == true
+ BugGuard.new("#1", "1.8.6").match?.should == true
+ end
+
+ it "returns false when MSpec.mode?(:no_ruby_bug) is true" do
+ MSpec.should_receive(:mode?).with(:no_ruby_bug).twice.and_return(:true)
+ BugGuard.new("#1", "1.8.5").match?.should == false
+ BugGuard.new("#1", "1.8").match?.should == false
+ end
+end
+
+describe BugGuard, "#match? when #implementation? is not 'ruby'" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ end
+
+ before :each do
+ @ruby_version = Object.const_get :RUBY_VERSION
+ @ruby_patch = Object.const_get :RUBY_PATCHLEVEL
+ @ruby_name = Object.const_get :RUBY_NAME
+
+ Object.const_set :RUBY_VERSION, '1.8.6'
+ Object.const_set :RUBY_PATCHLEVEL, 114
+ Object.const_set :RUBY_NAME, 'jruby'
+ end
+
+ after :each do
+ Object.const_set :RUBY_VERSION, @ruby_version
+ Object.const_set :RUBY_PATCHLEVEL, @ruby_patch
+ Object.const_set :RUBY_NAME, @ruby_name
+ end
+
+ it "returns false when version argument is less than RUBY_VERSION and RUBY_PATCHLEVEL" do
+ BugGuard.new("#1", "1.8").match?.should == false
+ BugGuard.new("#1", "1.8.6").match?.should == false
+ end
+
+ it "returns false when version argument is equal to RUBY_VERSION and RUBY_PATCHLEVEL" do
+ BugGuard.new("#1", "1.8.6.114").match?.should == false
+ end
+
+ it "returns false when version argument is greater than RUBY_VERSION and RUBY_PATCHLEVEL" do
+ BugGuard.new("#1", "1.8.7").match?.should == false
+ BugGuard.new("#1", "1.8.6.115").match?.should == false
+ end
+
+ it "returns false when MSpec.mode?(:no_ruby_bug) is true" do
+ MSpec.should_receive(:mode?).with(:no_ruby_bug).any_number_of_times.and_return(:true)
+ BugGuard.new("#1", "1.8.6").match?.should == false
+ BugGuard.new("#1", "1.8.6.114").match?.should == false
+ BugGuard.new("#1", "1.8.6.115").match?.should == false
+ end
+end
+
+describe Object, "#ruby_bug" do
+ before :each do
+ @guard = BugGuard.new "#1234", "x.x.x.x"
+ BugGuard.stub!(:new).and_return(@guard)
+ ScratchPad.clear
+ end
+
+ it "yields when #match? returns false" do
+ @guard.stub!(:match?).and_return(false)
+ ruby_bug("#1234", "1.8.6") { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "does not yield when #match? returns true" do
+ @guard.stub!(:match?).and_return(true)
+ ruby_bug("#1234", "1.8.6") { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "requires a bug tracker number and a version number" do
+ lambda { ruby_bug { } }.should raise_error(ArgumentError)
+ lambda { ruby_bug("#1234") { } }.should raise_error(ArgumentError)
+ end
+
+ it "sets the name of the guard to :ruby_bug" do
+ ruby_bug("#1234", "1.8.6") { }
+ @guard.name.should == :ruby_bug
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:unregister)
+ lambda do
+ ruby_bug("", "") { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/compliance_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/compliance_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/compliance_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,140 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/compliance'
+
+describe Object, "#compliant_on" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ @ruby_name = Object.const_get :RUBY_NAME if Object.const_defined? :RUBY_NAME
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ if @ruby_name
+ Object.const_set :RUBY_NAME, @ruby_name
+ else
+ Object.send :remove_const, :RUBY_NAME
+ end
+ end
+
+ before :each do
+ ScratchPad.clear
+ end
+
+ it "raises an Exception when passed :ruby" do
+ Object.const_set :RUBY_NAME, "jruby"
+ lambda {
+ compliant_on(:ruby) { ScratchPad.record :yield }
+ }.should raise_error(Exception)
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "does not yield when #standard? and #implementation? return false" do
+ Object.const_set :RUBY_NAME, "jruby"
+ compliant_on(:rubinius, :ironruby) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "yields when #standard? returns true" do
+ Object.const_set :RUBY_NAME, "ruby"
+ compliant_on(:rubinius) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "yields when #implementation? returns true" do
+ Object.const_set :RUBY_NAME, "jruby"
+ compliant_on(:jruby) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "does not yield when #implementation? returns false" do
+ Object.const_set :RUBY_NAME, "jruby"
+ compliant_on(:rubinius) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+end
+
+describe Object, "#compliant_on" do
+ before :each do
+ @guard = CompliantOnGuard.new :any
+ CompliantOnGuard.stub!(:new).and_return(@guard)
+ end
+
+ it "sets the name of the guard to :compliant_on" do
+ compliant_on(:rubinius) { }
+ @guard.name.should == :compliant_on
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:unregister)
+ lambda do
+ compliant_on(:rubinius) { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
+
+describe Object, "#not_compliant_on" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ @ruby_name = Object.const_get :RUBY_NAME if Object.const_defined? :RUBY_NAME
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ if @ruby_name
+ Object.const_set :RUBY_NAME, @ruby_name
+ else
+ Object.send :remove_const, :RUBY_NAME
+ end
+ end
+
+ before :each do
+ ScratchPad.clear
+ end
+
+ it "raises an Exception when passed :ruby" do
+ Object.const_set :RUBY_NAME, "jruby"
+ lambda {
+ not_compliant_on(:ruby) { ScratchPad.record :yield }
+ }.should raise_error(Exception)
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "yields when #standard? returns true" do
+ Object.const_set :RUBY_NAME, "ruby"
+ not_compliant_on(:rubinius) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "does not yield when #implementation? returns true" do
+ Object.const_set :RUBY_NAME, "jruby "
+ not_compliant_on(:jruby) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "yields when #implementation? returns false" do
+ Object.const_set :RUBY_NAME, "jruby "
+ not_compliant_on(:rubinius) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+end
+
+describe Object, "#not_compliant_on" do
+ before :each do
+ @guard = NotCompliantOnGuard.new :any
+ NotCompliantOnGuard.stub!(:new).and_return(@guard)
+ end
+
+ it "sets the name of the guard to :not_compliant_on" do
+ not_compliant_on(:rubinius) { }
+ @guard.name.should == :not_compliant_on
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:unregister)
+ lambda do
+ not_compliant_on(:rubinius) { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/conflict_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/conflict_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/conflict_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,39 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/conflict'
+
+describe Object, "#conflicts_with" do
+ before :each do
+ ScratchPad.clear
+ end
+
+ it "does not yield if Object.constants includes any of the arguments" do
+ Object.stub!(:constants).and_return(["SomeClass", "OtherClass"])
+ conflicts_with(:SomeClass, :AClass, :BClass) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "yields if Object.constants does not include any of the arguments" do
+ Object.stub!(:constants).and_return(["SomeClass", "OtherClass"])
+ conflicts_with(:AClass, :BClass) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+end
+
+describe Object, "#conflicts_with" do
+ before :each do
+ @guard = ConflictsGuard.new
+ ConflictsGuard.stub!(:new).and_return(@guard)
+ end
+
+ it "sets the name of the guard to :conflicts_with" do
+ conflicts_with(:AClass, :BClass) { }
+ @guard.name.should == :conflicts_with
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:unregister)
+ lambda do
+ conflicts_with(:AClass, :BClass) { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/endian_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/endian_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/endian_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,68 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/endian'
+
+describe Object, "#big_endian" do
+ before :each do
+ @guard = BigEndianGuard.new
+ BigEndianGuard.stub!(:new).and_return(@guard)
+ ScratchPad.clear
+ end
+
+ it "yields on big-endian platforms" do
+ @guard.stub!(:pattern).and_return([1])
+ big_endian { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "does not yield on little-endian platforms" do
+ @guard.stub!(:pattern).and_return([0])
+ big_endian { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "sets the name of the guard to :big_endian" do
+ big_endian { }
+ @guard.name.should == :big_endian
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.stub!(:pattern).and_return([1])
+ @guard.should_receive(:unregister)
+ lambda do
+ big_endian { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
+
+describe Object, "#little_endian" do
+ before :each do
+ @guard = LittleEndianGuard.new
+ LittleEndianGuard.stub!(:new).and_return(@guard)
+ ScratchPad.clear
+ end
+
+ it "yields on little-endian platforms" do
+ @guard.stub!(:pattern).and_return([0])
+ little_endian { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "does not yield on big-endian platforms" do
+ @guard.stub!(:pattern).and_return([1])
+ little_endian { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "sets the name of the guard to :little_endian" do
+ little_endian { }
+ @guard.name.should == :little_endian
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.stub!(:pattern).and_return([0])
+ @guard.should_receive(:unregister)
+ lambda do
+ little_endian { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/extensions_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/extensions_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/extensions_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,69 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/extensions'
+
+describe Object, "#extended_on" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ @ruby_name = Object.const_get :RUBY_NAME if Object.const_defined? :RUBY_NAME
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ if @ruby_name
+ Object.const_set :RUBY_NAME, @ruby_name
+ else
+ Object.send :remove_const, :RUBY_NAME
+ end
+ end
+
+ before :each do
+ ScratchPad.clear
+ end
+
+ it "raises an Exception when passed :ruby" do
+ Object.const_set :RUBY_NAME, "jruby"
+ lambda {
+ extended_on(:ruby) { ScratchPad.record :yield }
+ }.should raise_error(Exception)
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "does not yield when #standard? returns true" do
+ Object.const_set :RUBY_NAME, "ruby"
+ extended_on(:rubinius) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "does not yield when #implementation? returns false" do
+ Object.const_set :RUBY_NAME, "jruby"
+ extended_on(:rubinius) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "yields when #implementation? returns true" do
+ Object.const_set :RUBY_NAME, "rbx"
+ extended_on(:rubinius) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+end
+
+describe Object, "#extended_on" do
+ before :each do
+ @guard = ExtensionsGuard.new
+ ExtensionsGuard.stub!(:new).and_return(@guard)
+ end
+
+ it "sets the name of the guard to :extended_on" do
+ extended_on(:rubinius) { }
+ @guard.name.should == :extended_on
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:match?).and_return(true)
+ @guard.should_receive(:unregister)
+ lambda do
+ extended_on(:rubinius) { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/guard_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/guard_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/guard_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,476 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/utils/ruby_name'
+require 'mspec/guards/guard'
+require 'rbconfig'
+
+describe SpecGuard, ".ruby_version" do
+ before :all do
+ @ruby_version = Object.const_get :RUBY_VERSION
+ @ruby_patchlevel = Object.const_get :RUBY_PATCHLEVEL
+
+ Object.const_set :RUBY_VERSION, "8.2.3"
+ Object.const_set :RUBY_PATCHLEVEL, 71
+ end
+
+ after :all do
+ Object.const_set :RUBY_VERSION, @ruby_version
+ Object.const_set :RUBY_PATCHLEVEL, @ruby_patchlevel
+ end
+
+ it "returns the version and patchlevel for :full" do
+ SpecGuard.ruby_version(:full).should == "8.2.3.71"
+ end
+
+ it "returns 0 for negative RUBY_PATCHLEVEL values" do
+ Object.const_set :RUBY_PATCHLEVEL, -1
+ SpecGuard.ruby_version(:full).should == "8.2.3.0"
+ end
+
+ it "returns major.minor.tiny for :tiny" do
+ SpecGuard.ruby_version(:tiny).should == "8.2.3"
+ end
+
+ it "returns major.minor.tiny for :teeny" do
+ SpecGuard.ruby_version(:tiny).should == "8.2.3"
+ end
+
+ it "returns major.minor for :minor" do
+ SpecGuard.ruby_version(:minor).should == "8.2"
+ end
+
+ it "defaults to :minor" do
+ SpecGuard.ruby_version.should == "8.2"
+ end
+
+ it "returns major for :major" do
+ SpecGuard.ruby_version(:major).should == "8"
+ end
+end
+
+describe SpecGuard, ".windows?" do
+ before :all do
+ @ruby_platform = Object.const_get :RUBY_PLATFORM
+ end
+
+ after :all do
+ Object.const_set :RUBY_PLATFORM, @ruby_platform
+ end
+
+ it "returns true if key is mswin32" do
+ SpecGuard.windows?("mswin32").should be_true
+ end
+
+ it "returns true if key is mingw" do
+ SpecGuard.windows?("mingw").should be_true
+ end
+
+ it "returns false for non-windows" do
+ SpecGuard.windows?("notwindows").should be_false
+ end
+
+ it "uses RUBY_PLATFORM by default" do
+ Object.const_set :RUBY_PLATFORM, "mswin32"
+ SpecGuard.windows?.should be_true
+ end
+end
+
+describe SpecGuard, "#yield?" do
+ before :each do
+ MSpec.clear_modes
+ @guard = SpecGuard.new
+ end
+
+ after :each do
+ MSpec.unregister :add, @guard
+ MSpec.clear_modes
+ SpecGuard.clear_guards
+ end
+
+ it "returns true if MSpec.mode?(:unguarded) is true" do
+ MSpec.register_mode :unguarded
+ @guard.yield?.should == true
+ end
+
+ it "returns true if MSpec.mode?(:verify) is true" do
+ MSpec.register_mode :verify
+ @guard.yield?.should == true
+ end
+
+ it "returns true if MSpec.mode?(:verify) is true regardless of invert being true" do
+ MSpec.register_mode :verify
+ @guard.yield?(true).should == true
+ end
+
+ it "returns true if MSpec.mode?(:report) is true" do
+ MSpec.register_mode :report
+ @guard.yield?.should == true
+ end
+
+ it "returns true if MSpec.mode?(:report) is true regardless of invert being true" do
+ MSpec.register_mode :report
+ @guard.yield?(true).should == true
+ end
+
+ it "returns true if MSpec.mode?(:report_on) is true and SpecGuards.guards contains the named guard" do
+ MSpec.register_mode :report_on
+ SpecGuard.guards << :guard_name
+ @guard.yield?.should == false
+ @guard.name = :guard_name
+ @guard.yield?.should == true
+ end
+
+ it "returns #match? if neither report nor verify mode are true" do
+ @guard.stub!(:match?).and_return(false)
+ @guard.yield?.should == false
+ @guard.stub!(:match?).and_return(true)
+ @guard.yield?.should == true
+ end
+
+ it "returns #match? if invert is true and neither report nor verify mode are true" do
+ @guard.stub!(:match?).and_return(false)
+ @guard.yield?(true).should == true
+ @guard.stub!(:match?).and_return(true)
+ @guard.yield?(true).should == false
+ end
+end
+
+describe SpecGuard, "#===" do
+ it "returns true" do
+ anything = mock("anything")
+ SpecGuard.new.===(anything).should == true
+ end
+end
+
+describe SpecGuard, "#implementation?" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ end
+
+ before :each do
+ @ruby_name = Object.const_get :RUBY_NAME
+ @guard = SpecGuard.new
+ end
+
+ after :each do
+ Object.const_set :RUBY_NAME, @ruby_name
+ end
+
+ it "returns true if passed :ruby and RUBY_NAME == 'ruby'" do
+ Object.const_set :RUBY_NAME, 'ruby'
+ @guard.implementation?(:ruby).should == true
+ end
+
+ it "returns true if passed :rubinius and RUBY_NAME == 'rbx'" do
+ Object.const_set :RUBY_NAME, 'rbx'
+ @guard.implementation?(:rubinius).should == true
+ end
+
+ it "returns true if passed :jruby and RUBY_NAME == 'jruby'" do
+ Object.const_set :RUBY_NAME, 'jruby'
+ @guard.implementation?(:jruby).should == true
+ end
+
+ it "returns true if passed :ironruby and RUBY_NAME == 'ironruby'" do
+ Object.const_set :RUBY_NAME, 'ironruby'
+ @guard.implementation?(:ironruby).should == true
+ end
+
+ it "returns true if passed :ruby and RUBY_NAME matches /^ruby/" do
+ Object.const_set :RUBY_NAME, 'ruby'
+ @guard.implementation?(:ruby).should == true
+
+ Object.const_set :RUBY_NAME, 'ruby1.8'
+ @guard.implementation?(:ruby).should == true
+
+ Object.const_set :RUBY_NAME, 'ruby1.9'
+ @guard.implementation?(:ruby).should == true
+ end
+
+ it "returns false when passed an unrecognized name" do
+ Object.const_set :RUBY_NAME, 'ruby'
+ @guard.implementation?(:python).should == false
+ end
+end
+
+describe SpecGuard, "#standard?" do
+ before :each do
+ @guard = SpecGuard.new
+ end
+
+ it "returns true if #implementation? returns true" do
+ @guard.should_receive(:implementation?).with(:ruby).and_return(true)
+ @guard.standard?.should be_true
+ end
+
+ it "returns false if #implementation? returns false" do
+ @guard.should_receive(:implementation?).with(:ruby).and_return(false)
+ @guard.standard?.should be_false
+ end
+end
+
+describe SpecGuard, "#platform?" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ end
+
+ before :each do
+ @ruby_platform = Object.const_get :RUBY_PLATFORM
+ Object.const_set :RUBY_PLATFORM, 'solarce'
+ @guard = SpecGuard.new
+ end
+
+ after :each do
+ Object.const_set :RUBY_PLATFORM, @ruby_platform
+ end
+
+ it "returns false when arg does not match RUBY_PLATFORM" do
+ @guard.platform?(:ruby).should == false
+ end
+
+ it "returns false when no arg matches RUBY_PLATFORM" do
+ @guard.platform?(:ruby, :jruby, :rubinius).should == false
+ end
+
+ it "returns true when arg matches RUBY_PLATFORM" do
+ @guard.platform?(:solarce).should == true
+ end
+
+ it "returns true when any arg matches RUBY_PLATFORM" do
+ @guard.platform?(:ruby, :jruby, :solarce, :rubinius).should == true
+ end
+
+ it "returns true when arg is :windows and RUBY_PLATFORM contains 'mswin'" do
+ Object.const_set :RUBY_PLATFORM, 'i386-mswin32'
+ @guard.platform?(:windows).should == true
+ end
+
+ it "returns true when arg is :windows and RUBY_PLATFORM contains 'mingw'" do
+ Object.const_set :RUBY_PLATFORM, 'i386-mingw32'
+ @guard.platform?(:windows).should == true
+ end
+
+ it "returns false when arg is not :windows and Config::CONFIG['host_os'] contains 'mswin'" do
+ Object.const_set :RUBY_PLATFORM, 'i386-mswin32'
+ @guard.platform?(:linux).should == false
+ end
+
+ it "returns false when arg is not :windows and Config::CONFIG['host_os'] contains 'mingw'" do
+ Object.const_set :RUBY_PLATFORM, 'i386-mingw32'
+ @guard.platform?(:linux).should == false
+ end
+end
+
+describe SpecGuard, "#platform? on JRuby" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ end
+
+ before :each do
+ @ruby_platform = Object.const_get :RUBY_PLATFORM
+ Object.const_set :RUBY_PLATFORM, 'java'
+ @guard = SpecGuard.new
+ end
+
+ after :each do
+ Object.const_set :RUBY_PLATFORM, @ruby_platform
+ end
+
+ it "returns true when arg is :java and RUBY_PLATFORM contains 'java'" do
+ @guard.platform?(:java).should == true
+ end
+
+ it "returns true when arg is :windows and RUBY_PLATFORM contains 'java' and os?(:windows) is true" do
+ Config::CONFIG.stub!(:[]).and_return('mswin32')
+ @guard.platform?(:windows).should == true
+ end
+
+ it "returns true when RUBY_PLATFORM contains 'java' and os?(argument) is true" do
+ Config::CONFIG.stub!(:[]).and_return('amiga')
+ @guard.platform?(:amiga).should == true
+ end
+end
+
+describe SpecGuard, "#wordsize?" do
+ before :each do
+ @guard = SpecGuard.new
+ end
+
+ it "returns true when arg is 32 and 1.size is 4" do
+ @guard.wordsize?(32).should == (1.size == 4)
+ end
+
+ it "returns true when arg is 64 and 1.size is 8" do
+ @guard.wordsize?(64).should == (1.size == 8)
+ end
+end
+
+describe SpecGuard, "#os?" do
+ before :each do
+ @guard = SpecGuard.new
+ Config::CONFIG.stub!(:[]).and_return('unreal')
+ end
+
+ it "returns true if argument matches Config::CONFIG['host_os']" do
+ @guard.os?(:unreal).should == true
+ end
+
+ it "returns true if any argument matches Config::CONFIG['host_os']" do
+ @guard.os?(:bsd, :unreal, :amiga).should == true
+ end
+
+ it "returns false if no argument matches Config::CONFIG['host_os']" do
+ @guard.os?(:bsd, :netbsd, :amiga, :msdos).should == false
+ end
+
+ it "returns false if argument does not match Config::CONFIG['host_os']" do
+ @guard.os?(:amiga).should == false
+ end
+
+ it "returns true when arg is :windows and Config::CONFIG['host_os'] contains 'mswin'" do
+ Config::CONFIG.stub!(:[]).and_return('i386-mswin32')
+ @guard.os?(:windows).should == true
+ end
+
+ it "returns true when arg is :windows and Config::CONFIG['host_os'] contains 'mingw'" do
+ Config::CONFIG.stub!(:[]).and_return('i386-mingw32')
+ @guard.os?(:windows).should == true
+ end
+
+ it "returns false when arg is not :windows and Config::CONFIG['host_os'] contains 'mswin'" do
+ Config::CONFIG.stub!(:[]).and_return('i386-mingw32')
+ @guard.os?(:linux).should == false
+ end
+
+ it "returns false when arg is not :windows and Config::CONFIG['host_os'] contains 'mingw'" do
+ Config::CONFIG.stub!(:[]).and_return('i386-mingw32')
+ @guard.os?(:linux).should == false
+ end
+end
+
+describe SpecGuard, "windows?" do
+ before :each do
+ @guard = SpecGuard.new
+ end
+
+ it "returns false if not passed :windows" do
+ @guard.windows?(:linux, 'mswin32').should == false
+ @guard.windows?(:linux, 'i386-mingw32').should == false
+ end
+
+ it "returns true if passed :windows and the key matches 'mswin' or 'mingw'" do
+ @guard.windows?(:windows, 'mswin32').should == true
+ @guard.windows?(:windows, 'i386-mingw32').should == true
+ end
+
+ it "returns false if passed :windows and the key matches neither 'mswin' nor 'mingw'" do
+ @guard.windows?(:windows, 'darwin9.0').should == false
+ @guard.windows?(:windows, 'linux').should == false
+ end
+end
+
+describe SpecGuard, "#match?" do
+ before :each do
+ @guard = SpecGuard.new
+ SpecGuard.stub!(:new).and_return(@guard)
+ end
+
+ it "returns true if #platform? or #implementation? return true" do
+ @guard.stub!(:implementation?).and_return(true)
+ @guard.stub!(:platform?).and_return(false)
+ @guard.match?.should == true
+
+ @guard.stub!(:implementation?).and_return(false)
+ @guard.stub!(:platform?).and_return(true)
+ @guard.match?.should == true
+ end
+
+ it "returns false if #platform? and #implementation? return false" do
+ @guard.stub!(:implementation?).and_return(false)
+ @guard.stub!(:platform?).and_return(false)
+ @guard.match?.should == false
+ end
+end
+
+describe SpecGuard, "#unregister" do
+ before :each do
+ MSpec.stub!(:unregister)
+ @guard = SpecGuard.new
+ end
+
+ it "unregisters from MSpec :add actions" do
+ MSpec.should_receive(:unregister).with(:add, @guard)
+ @guard.unregister
+ end
+end
+
+describe SpecGuard, "#record" do
+ after :each do
+ SpecGuard.clear
+ end
+
+ it "saves the name of the guarded spec under the name of the guard" do
+ guard = SpecGuard.new "a", "1.8"..."1.9"
+ guard.name = :named_guard
+ guard.record "SomeClass#action returns true"
+ SpecGuard.report.should == {
+ 'named_guard a, 1.8...1.9' => ["SomeClass#action returns true"]
+ }
+ end
+end
+
+describe SpecGuard, ".guards" do
+ it "returns an Array" do
+ SpecGuard.guards.should be_kind_of(Array)
+ end
+end
+
+describe SpecGuard, ".clear_guards" do
+ it "resets the array to empty" do
+ SpecGuard.guards << :guard
+ SpecGuard.guards.should == [:guard]
+ SpecGuard.clear_guards
+ SpecGuard.guards.should == []
+ end
+end
+
+describe SpecGuard, ".finish" do
+ before :each do
+ $stdout = @out = IOStub.new
+ end
+
+ after :each do
+ $stdout = STDOUT
+ SpecGuard.clear
+ end
+
+ it "prints the descriptions of the guarded specs" do
+ guard = SpecGuard.new "a", "1.8"..."1.9"
+ guard.name = :named_guard
+ guard.record "SomeClass#action returns true"
+ guard.record "SomeClass#reverse returns false"
+ SpecGuard.finish
+ $stdout.should == %[
+
+2 specs omitted by guard: named_guard a, 1.8...1.9:
+
+SomeClass#action returns true
+SomeClass#reverse returns false
+
+]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/noncompliance_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/noncompliance_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/noncompliance_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,69 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/noncompliance'
+
+describe Object, "#deviates_on" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ @ruby_name = Object.const_get :RUBY_NAME if Object.const_defined? :RUBY_NAME
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ if @ruby_name
+ Object.const_set :RUBY_NAME, @ruby_name
+ else
+ Object.send :remove_const, :RUBY_NAME
+ end
+ end
+
+ before :each do
+ ScratchPad.clear
+ end
+
+ it "raises an Exception when passed :ruby" do
+ Object.const_set :RUBY_NAME, "jruby"
+ lambda {
+ deviates_on(:ruby) { ScratchPad.record :yield }
+ }.should raise_error(Exception)
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "does not yield when #standard? returns true" do
+ Object.const_set :RUBY_NAME, "ruby"
+ deviates_on(:rubinius) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "does not yield when #implementation? returns false" do
+ Object.const_set :RUBY_NAME, "jruby"
+ deviates_on(:rubinius) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "yields when #implementation? returns true" do
+ Object.const_set :RUBY_NAME, "jruby"
+ deviates_on(:jruby) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+end
+
+describe Object, "#deviates_on" do
+ before :each do
+ @guard = NonComplianceGuard.new
+ NonComplianceGuard.stub!(:new).and_return(@guard)
+ end
+
+ it "sets the name of the guard to :deviates_on" do
+ deviates_on(:jruby) { }
+ @guard.name.should == :deviates_on
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:match?).and_return(true)
+ @guard.should_receive(:unregister)
+ lambda do
+ deviates_on(:rubinius) { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/platform_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/platform_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/platform_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,110 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/platform'
+
+describe Object, "#platform_is" do
+ before :each do
+ @guard = PlatformGuard.new :dummy
+ PlatformGuard.stub!(:new).and_return(@guard)
+ ScratchPad.clear
+ end
+
+ it "does not yield when #platform? returns false" do
+ @guard.stub!(:platform?).and_return(false)
+ platform_is(:ruby) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "yields when #platform? returns true" do
+ @guard.stub!(:platform?).and_return(true)
+ platform_is(:solarce) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "sets the name of the guard to :platform_is" do
+ platform_is(:solarce) { }
+ @guard.name.should == :platform_is
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:match?).and_return(true)
+ @guard.should_receive(:unregister)
+ lambda do
+ platform_is(:solarce) { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
+
+describe Object, "#platform_is_not" do
+ before :each do
+ @guard = PlatformGuard.new :dummy
+ PlatformGuard.stub!(:new).and_return(@guard)
+ ScratchPad.clear
+ end
+
+ it "does not yield when #platform? returns true" do
+ @guard.stub!(:platform?).and_return(true)
+ platform_is_not(:ruby) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "yields when #platform? returns false" do
+ @guard.stub!(:platform?).and_return(false)
+ platform_is_not(:solarce) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "sets the name of the guard to :platform_is_not" do
+ platform_is_not(:solarce) { }
+ @guard.name.should == :platform_is_not
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:match?).and_return(false)
+ @guard.should_receive(:unregister)
+ lambda do
+ platform_is_not(:solarce) { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
+
+describe Object, "#platform_is :wordsize => SIZE_SPEC" do
+ before :each do
+ @guard = PlatformGuard.new :darwin, :wordsize => 32
+ @guard.stub!(:platform?).and_return(true)
+ PlatformGuard.stub!(:new).and_return(@guard)
+ ScratchPad.clear
+ end
+
+ it "yields when #wordsize? returns true" do
+ @guard.stub!(:wordsize?).and_return(true)
+ platform_is(:wordsize => 32) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "doesn not yield when #wordsize? returns false" do
+ @guard.stub!(:wordsize?).and_return(false)
+ platform_is(:wordsize => 32) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+end
+
+describe Object, "#platform_is_not :wordsize => SIZE_SPEC" do
+ before :each do
+ @guard = PlatformGuard.new :darwin, :wordsize => 32
+ @guard.stub!(:platform?).and_return(true)
+ PlatformGuard.stub!(:new).and_return(@guard)
+ ScratchPad.clear
+ end
+
+ it "yields when #wordsize? returns false" do
+ @guard.stub!(:wordsize?).and_return(false)
+ platform_is_not(:wordsize => 32) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "doesn not yield when #wordsize? returns true" do
+ @guard.stub!(:wordsize?).and_return(true)
+ platform_is_not(:wordsize => 32) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/quarantine_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/quarantine_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/quarantine_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,35 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/quarantine'
+
+describe QuarantineGuard, "#match?" do
+ it "returns false" do
+ QuarantineGuard.new.match?.should == false
+ end
+end
+
+describe Object, "#quarantine!" do
+ before :each do
+ ScratchPad.clear
+
+ @guard = QuarantineGuard.new
+ QuarantineGuard.stub!(:new).and_return(@guard)
+ end
+
+ it "does not yield" do
+ quarantine! { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "sets the name of the guard to :quarantine!" do
+ quarantine! { }
+ @guard.name.should == :quarantine!
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:match?).and_return(true)
+ @guard.should_receive(:unregister)
+ lambda do
+ quarantine! { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/runner_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/runner_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/runner_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,101 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/runner'
+
+describe RunnerGuard, "#match?" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ end
+
+ it "returns true when passed :mspec and ENV['MSPEC_RUNNER'] is true" do
+ ENV['MSPEC_RUNNER'] = '1'
+ RunnerGuard.new(:mspec).match?.should == true
+ end
+
+ it "returns false when passed :mspec and ENV['MSPEC_RUNNER'] is false" do
+ ENV.delete 'MSPEC_RUNNER'
+ RunnerGuard.new(:mspec).match?.should == false
+ end
+
+ it "returns true when passed :rspec and ENV['RSPEC_RUNNER'] is false but the constant Spec exists" do
+ ENV.delete 'RSPEC_RUNNER'
+ Object.const_set(:Spec, 1) unless Object.const_defined?(:Spec)
+ RunnerGuard.new(:rspec).match?.should == true
+ end
+
+ it "returns true when passed :rspec and ENV['RSPEC_RUNNER'] is true but the constant Spec does not exist" do
+ ENV['RSPEC_RUNNER'] = '1'
+ Object.should_receive(:const_defined?).with(:Spec).any_number_of_times.and_return(false)
+ RunnerGuard.new(:rspec).match?.should == true
+ end
+end
+
+describe Object, "#runner_is" do
+ before :each do
+ @guard = RunnerGuard.new
+ RunnerGuard.stub!(:new).and_return(@guard)
+ ScratchPad.clear
+ end
+
+ it "yields when #match? returns true" do
+ @guard.stub!(:match?).and_return(true)
+ runner_is(:mspec) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "does not yield when #match? returns false" do
+ @guard.stub!(:match?).and_return(false)
+ runner_is(:mspec) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "sets the name of the guard to :runner_is" do
+ runner_is(:mspec) { }
+ @guard.name.should == :runner_is
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:match?).and_return(true)
+ @guard.should_receive(:unregister)
+ lambda do
+ runner_is(:mspec) { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
+
+describe Object, "#runner_is_not" do
+ before :each do
+ @guard = RunnerGuard.new
+ RunnerGuard.stub!(:new).and_return(@guard)
+ ScratchPad.clear
+ end
+
+ it "does not yield when #match? returns true" do
+ @guard.stub!(:match?).and_return(true)
+ runner_is_not(:mspec) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "yields when #match? returns false" do
+ @guard.stub!(:match?).and_return(false)
+ runner_is_not(:mspec) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "sets the name of the guard to :runner_is_not" do
+ runner_is_not(:mspec) { }
+ @guard.name.should == :runner_is_not
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:match?).and_return(false)
+ @guard.should_receive(:unregister)
+ lambda do
+ runner_is_not(:mspec) { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/superuser_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/superuser_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/superuser_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,35 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/superuser'
+
+describe Object, "#as_superuser" do
+ before :each do
+ @guard = SuperUserGuard.new
+ SuperUserGuard.stub!(:new).and_return(@guard)
+ ScratchPad.clear
+ end
+
+ it "does not yield when Process.euid is not 0" do
+ Process.stub!(:euid).and_return(501)
+ as_superuser { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "yields when Process.euid is 0" do
+ Process.stub!(:euid).and_return(0)
+ as_superuser { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "sets the name of the guard to :as_superuser" do
+ as_superuser { }
+ @guard.name.should == :as_superuser
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:match?).and_return(true)
+ @guard.should_receive(:unregister)
+ lambda do
+ as_superuser { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/support_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/support_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/support_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,69 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/support'
+
+describe Object, "#not_supported_on" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ @ruby_name = Object.const_get :RUBY_NAME if Object.const_defined? :RUBY_NAME
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ if @ruby_name
+ Object.const_set :RUBY_NAME, @ruby_name
+ else
+ Object.send :remove_const, :RUBY_NAME
+ end
+ end
+
+ before :each do
+ ScratchPad.clear
+ end
+
+ it "raises an Exception when passed :ruby" do
+ Object.const_set :RUBY_NAME, "jruby"
+ lambda {
+ not_supported_on(:ruby) { ScratchPad.record :yield }
+ }.should raise_error(Exception)
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "does not yield when #implementation? returns true" do
+ Object.const_set :RUBY_NAME, "jruby"
+ not_supported_on(:jruby) { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "yields when #standard? returns true" do
+ Object.const_set :RUBY_NAME, "ruby"
+ not_supported_on(:rubinius) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "yields when #implementation? returns false" do
+ Object.const_set :RUBY_NAME, "jruby"
+ not_supported_on(:rubinius) { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+end
+
+describe Object, "#not_supported_on" do
+ before :each do
+ @guard = SupportedGuard.new
+ SupportedGuard.stub!(:new).and_return(@guard)
+ end
+
+ it "sets the name of the guard to :not_supported_on" do
+ not_supported_on(:rubinius) { }
+ @guard.name.should == :not_supported_on
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:match?).and_return(true)
+ @guard.should_receive(:unregister)
+ lambda do
+ not_supported_on(:rubinius) { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/tty_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/tty_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/tty_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,36 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/tty'
+
+describe Object, "#with_tty" do
+ before :each do
+ ScratchPad.clear
+
+ @guard = TTYGuard.new
+ TTYGuard.stub!(:new).and_return(@guard)
+ end
+
+ it "yields if STDOUT is a TTY" do
+ STDOUT.should_receive(:tty?).and_return(true)
+ with_tty { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "does not yield if STDOUT is not a TTY" do
+ STDOUT.should_receive(:tty?).and_return(false)
+ with_tty { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "sets the name of the guard to :with_tty" do
+ with_tty { }
+ @guard.name.should == :with_tty
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:match?).and_return(true)
+ @guard.should_receive(:unregister)
+ lambda do
+ with_tty { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/guards/version_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/guards/version_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/guards/version_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,130 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/guards/version'
+
+# The VersionGuard specifies a version of Ruby with a String of
+# the form: v = 'major.minor.tiny.patchlevel'.
+#
+# A VersionGuard instance can be created with a single String,
+# which means any version >= each component of v.
+# Or, the guard can be created with a Range, a..b, or a...b,
+# where a, b are of the same form as v. The meaning of the Range
+# is as typically understood: a..b means v >= a and v <= b;
+# a...b means v >= a and v < b.
+
+describe VersionGuard, "#ruby_version" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ end
+
+ before :each do
+ @ruby_version = Object.const_get :RUBY_VERSION
+ @ruby_patch = Object.const_get :RUBY_PATCHLEVEL
+
+ Object.const_set :RUBY_VERSION, '1.8.6'
+ Object.const_set :RUBY_PATCHLEVEL, 114
+
+ @guard = VersionGuard.new 'x.x.x.x'
+ end
+
+ after :each do
+ Object.const_set :RUBY_VERSION, @ruby_version
+ Object.const_set :RUBY_PATCHLEVEL, @ruby_patch
+ end
+
+ it "returns 'RUBY_VERSION.RUBY_PATCHLEVEL'" do
+ @guard.ruby_version.should == 10108060114
+ end
+end
+
+describe VersionGuard, "#match?" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ end
+
+ before :each do
+ @ruby_version = Object.const_get :RUBY_VERSION
+ @ruby_patch = Object.const_get :RUBY_PATCHLEVEL
+
+ Object.const_set :RUBY_VERSION, '1.8.6'
+ Object.const_set :RUBY_PATCHLEVEL, 114
+ end
+
+ after :each do
+ Object.const_set :RUBY_VERSION, @ruby_version
+ Object.const_set :RUBY_PATCHLEVEL, @ruby_patch
+ end
+
+ it "returns true when the argument is equal to RUBY_VERSION and RUBY_PATCHLEVEL" do
+ VersionGuard.new('1.8.6.114').match?.should == true
+ end
+
+ it "returns true when the argument is less than RUBY_VERSION and RUBY_PATCHLEVEL" do
+ VersionGuard.new('1.8').match?.should == true
+ VersionGuard.new('1.8.5').match?.should == true
+ end
+
+ it "returns false when the argument is greater than RUBY_VERSION and RUBY_PATCHLEVEL" do
+ VersionGuard.new('1.8.7').match?.should == false
+ VersionGuard.new('1.8.7.000').match?.should == false
+ VersionGuard.new('1.8.7.10').match?.should == false
+ end
+
+ it "returns true when the argument range includes RUBY_VERSION and RUBY_PATCHLEVEL" do
+ VersionGuard.new('1.8.5'..'1.8.7.111').match?.should == true
+ VersionGuard.new('1.8'..'1.9').match?.should == true
+ VersionGuard.new('1.8'...'1.9').match?.should == true
+ VersionGuard.new('1.8'..'1.8.6.114').match?.should == true
+ VersionGuard.new('1.8'...'1.8.6.115').match?.should == true
+ end
+
+ it "returns false when the argument range does not include RUBY_VERSION and RUBY_PATCHLEVEL" do
+ VersionGuard.new('1.8.7'..'1.8.9').match?.should == false
+ VersionGuard.new('1.8.4'..'1.8.5').match?.should == false
+ VersionGuard.new('1.8.5'..'1.8.6.113').match?.should == false
+ VersionGuard.new('1.8.4'...'1.8.6').match?.should == false
+ VersionGuard.new('1.8.5'...'1.8.6.114').match?.should == false
+ end
+end
+
+describe Object, "#ruby_version_is" do
+ before :each do
+ @guard = VersionGuard.new 'x.x.x.x'
+ VersionGuard.stub!(:new).and_return(@guard)
+ ScratchPad.clear
+ end
+
+ it "yields when #match? returns true" do
+ @guard.stub!(:match?).and_return(true)
+ ruby_version_is('x.x.x.x') { ScratchPad.record :yield }
+ ScratchPad.recorded.should == :yield
+ end
+
+ it "does not yield when #match? returns false" do
+ @guard.stub!(:match?).and_return(false)
+ ruby_version_is('x.x.x.x') { ScratchPad.record :yield }
+ ScratchPad.recorded.should_not == :yield
+ end
+
+ it "sets the name of the guard to :ruby_version_is" do
+ ruby_version_is("") { }
+ @guard.name.should == :ruby_version_is
+ end
+
+ it "calls #unregister even when an exception is raised in the guard block" do
+ @guard.should_receive(:match?).and_return(true)
+ @guard.should_receive(:unregister)
+ lambda do
+ ruby_version_is("") { raise Exception }
+ end.should raise_error(Exception)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/helpers/argv_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/helpers/argv_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/helpers/argv_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,26 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/helpers/argv'
+
+describe Object, "#argv" do
+ before :each do
+ ScratchPad.clear
+
+ @saved_argv = ARGV
+ @argv = ["a", "b"]
+ end
+
+ it "replaces and restores the value of ARGV" do
+ argv @argv
+ ARGV.should == @argv
+ argv :restore
+ ARGV.should == @saved_argv
+ end
+
+ it "yields to the block after setting ARGV" do
+ argv @argv do
+ ScratchPad.record ARGV
+ end
+ ScratchPad.recorded.should == @argv
+ ARGV.should == @saved_argv
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/helpers/bignum_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/helpers/bignum_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/helpers/bignum_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,11 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/helpers/bignum'
+
+describe Object, "#bignum_value" do
+ it "returns a value that is an instance of Bignum on any platform" do
+ bignum_value.should == 0x8000_0000_0000_0000
+ end
+
+ it "returns the default value incremented by the argument" do
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/helpers/const_lookup_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/helpers/const_lookup_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/helpers/const_lookup_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,48 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/helpers/const_lookup'
+
+CONST = 2
+
+module ConstLookupSpecs
+ class A
+ class B
+ CONST = 1
+ end
+
+ class C; end
+
+ class D
+ def self.const_missing(const)
+ A::B::CONST
+ end
+ end
+ end
+end
+
+describe Kernel, "#const_lookup" do
+ it "returns the constant specified by 'A::B'" do
+ const_lookup("ConstLookupSpecs::A::B").should == ConstLookupSpecs::A::B
+ end
+
+ it "returns a regular constant specified without scoping" do
+ const_lookup("ConstLookupSpecs").should == ConstLookupSpecs
+ end
+
+ it "returns an explicit toplevel constant" do
+ const_lookup("::ConstLookupSpecs").should == ConstLookupSpecs
+ end
+
+ it "returns the constant from the proper scope" do
+ const_lookup("ConstLookupSpecs::A::B::CONST").should == 1
+ end
+
+ it "raises NameError if the constant is not contained within the module's scope" do
+ lambda {
+ const_lookup("ConstLookupSpecs::A::C::CONST")
+ }.should raise_error(NameError)
+ end
+
+ it "returns the value of #const_missing" do
+ const_lookup("ConstLookupSpecs::A::D::CONST").should == 1
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/helpers/environment_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/helpers/environment_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/helpers/environment_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,82 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/helpers/environment'
+
+describe "#env" do
+ before(:all) do
+ @ruby_platform = Object.const_get :RUBY_PLATFORM
+ end
+
+ after(:all) do
+ Object.const_set :RUBY_PLATFORM, @ruby_platform
+ end
+
+ it "returns a hash of variables" do
+ env.class.should == Hash
+ end
+
+ it "calls `env` on non-Windows" do
+ Object.const_set :RUBY_PLATFORM, "notwindows"
+ should_receive(:`).with("env").and_return("one=two\nthree=four")
+ env
+ end
+
+ it "calls `cmd.exe /C set` on Windows (mswin32)" do
+ Object.const_set :RUBY_PLATFORM, "mswin32"
+ should_receive(:`).with("cmd.exe /C set").and_return("one=two\nthree=four")
+ env
+ end
+
+ it "calls `cmd.exe /C set` on Windows (mingw)" do
+ Object.const_set :RUBY_PLATFORM, "mingw"
+ should_receive(:`).with("cmd.exe /C set").and_return("one=two\nthree=four")
+ env
+ end
+
+ it "returns the current user's environment variables" do
+ Object.const_set :RUBY_PLATFORM, "notwindows"
+ should_receive(:`).with("env").and_return("one=two\nthree=four")
+ env.should == {"one" => "two", "three" => "four"}
+
+ Object.const_set :RUBY_PLATFORM, "mswin32"
+ should_receive(:`).with("cmd.exe /C set").and_return("five=six\nseven=eight")
+ env.should == {"five" => "six", "seven" => "eight"}
+ end
+end
+
+describe "#username" do
+ before(:all) do
+ @ruby_platform = Object.const_get :RUBY_PLATFORM
+ end
+
+ after(:all) do
+ Object.const_set :RUBY_PLATFORM, @ruby_platform
+ end
+
+ it "calls `cmd.exe /C ECHO %USERNAME%` on Windows (mswin32)" do
+ Object.const_set :RUBY_PLATFORM, "mswin32"
+ should_receive(:`).with("cmd.exe /C ECHO %USERNAME%").and_return("john")
+ username
+ end
+
+ it "calls `cmd.exe /C ECHO %USERNAME%` on Windows (mingw)" do
+ Object.const_set :RUBY_PLATFORM, "mingw"
+ should_receive(:`).with("cmd.exe /C ECHO %USERNAME%").and_return("john")
+ username
+ end
+
+ it "calls `env` on non-Windows" do
+ Object.const_set :RUBY_PLATFORM, "notwindows"
+ should_receive(:`).with("whoami").and_return("john")
+ username
+ end
+
+ it "returns the user's username" do
+ Object.const_set :RUBY_PLATFORM, "mswin32"
+ should_receive(:`).with("cmd.exe /C ECHO %USERNAME%").and_return("johnonwin")
+ username.should == "johnonwin"
+
+ Object.const_set :RUBY_PLATFORM, "notwindows"
+ should_receive(:`).with("whoami").and_return("john")
+ username.should == "john"
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/helpers/fixture_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/helpers/fixture_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/helpers/fixture_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,18 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/helpers/fixture'
+
+describe Object, "#fixture" do
+ before :each do
+ @dir = File.expand_path(Dir.pwd)
+ end
+
+ it "returns the expanded path to a fixture file" do
+ name = fixture("some/path/file.rb", "dir", "file.txt")
+ name.should == "#{@dir}/some/path/fixtures/dir/file.txt"
+ end
+
+ it "omits '/shared' if it is the suffix of the directory string" do
+ name = fixture("some/path/shared/file.rb", "dir", "file.txt")
+ name.should == "#{@dir}/some/path/fixtures/dir/file.txt"
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/helpers/flunk_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/helpers/flunk_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/helpers/flunk_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,19 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/helpers/flunk'
+require 'mspec/runner/mspec'
+
+describe Object, "#flunk" do
+ before :each do
+ MSpec.stub!(:actions)
+ MSpec.stub!(:current).and_return(mock("spec state", :null_object => true))
+ end
+
+ it "raises an ExpectationNotMetError unconditionally" do
+ lambda { flunk }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "accepts on argument for an optional message" do
+ lambda {flunk "test"}.should raise_error(ExpectationNotMetError)
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/helpers/io_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/helpers/io_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/helpers/io_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,38 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe IOStub do
+ before :each do
+ @out = IOStub.new
+ @sep = $\
+ end
+
+ after :each do
+ $\ = @sep
+ end
+
+ it "provides a write method" do
+ @out.write "this"
+ @out.should == "this"
+ end
+
+ it "concatenates the arguments sent to write" do
+ @out.write "flim ", "flam"
+ @out.should == "flim flam"
+ end
+
+ it "provides a print method that appends the default separator" do
+ $\ = " [newline] "
+ @out.print "hello"
+ @out.print "world"
+ @out.should == "hello [newline] world [newline] "
+ end
+
+ it "provides a puts method that appends the default separator" do
+ @out.puts "hello", 1, 2, 3
+ @out.should == "hello\n1\n2\n3\n"
+ end
+
+ it "provides a flush method that does nothing and returns self" do
+ @out.flush.should == @out
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/helpers/language_version_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/helpers/language_version_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/helpers/language_version_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,29 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/helpers/language_version'
+
+describe Object, "#language_version" do
+ before :all do
+ @ruby_version = Object.const_get :RUBY_VERSION
+
+ Object.const_set :RUBY_VERSION, "8.2.3"
+
+ dir = File.dirname(File.expand_path(__FILE__))
+ @name = "#{dir}/versions/method_8.2.rb"
+ end
+
+ after :all do
+ Object.const_set :RUBY_VERSION, @ruby_version
+ end
+
+ it "loads files conditionally based on name and RUBY_VERSION if it exists" do
+ File.should_receive(:exists?).with(@name).and_return(true)
+ should_receive(:require).with(@name)
+ language_version __FILE__, "method"
+ end
+
+ it "does not load the file if it does not exist" do
+ File.should_receive(:exists?).with(@name).and_return(false)
+ should_not_receive(:require).with(@name)
+ language_version __FILE__, "method"
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/helpers/ruby_exe_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/helpers/ruby_exe_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/helpers/ruby_exe_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,160 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/helpers/ruby_exe'
+require 'rbconfig'
+
+class RubyExeSpecs
+end
+
+describe "#ruby_exe_options" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+
+ @ruby_name = Object.const_get :RUBY_NAME
+ @ruby_exe_env = ENV['RUBY_EXE']
+
+ @script = RubyExeSpecs.new
+ end
+
+ after :all do
+ Object.const_set :RUBY_NAME, @ruby_name
+ ENV['RUBY_EXE'] = @ruby_exe_env
+ $VERBOSE = @verbose
+ end
+
+ before :each do
+ @script = RubyExeSpecs.new
+ end
+
+ it "returns ENV['RUBY_EXE'] when passed :env" do
+ ENV['RUBY_EXE'] = "kowabunga"
+ @script.ruby_exe_options(:env).should == "kowabunga"
+ end
+
+ it "returns 'bin/rbx' when passed :engine and RUBY_NAME is 'rbx'" do
+ Object.const_set :RUBY_NAME, 'rbx'
+ @script.ruby_exe_options(:engine).should == 'bin/rbx'
+ end
+
+ it "returns 'bin/jruby' when passed :engine and RUBY_NAME is 'jruby'" do
+ Object.const_set :RUBY_NAME, 'jruby'
+ @script.ruby_exe_options(:engine).should == 'bin/jruby'
+ end
+
+ it "returns 'ir' when passed :engine and RUBY_NAME is 'ironruby'" do
+ Object.const_set :RUBY_NAME, 'ironruby'
+ @script.ruby_exe_options(:engine).should == 'ir'
+ end
+
+ it "returns RUBY_NAME + $(EXEEXT) when passed :name" do
+ bin = RUBY_NAME + (Config::CONFIG['EXEEXT'] || Config::CONFIG['exeext'] || '')
+ name = File.join ".", bin
+ @script.ruby_exe_options(:name).should == name
+ end
+
+ it "returns $(bindir)/$(RUBY_INSTALL_NAME) + $(EXEEXT) when passed :install_name" do
+ bin = Config::CONFIG['RUBY_INSTALL_NAME'] + (Config::CONFIG['EXEEXT'] || Config::CONFIG['exeext'] || '')
+ name = File.join Config::CONFIG['bindir'], bin
+ @script.ruby_exe_options(:install_name).should == name
+ end
+end
+
+describe "#resolve_ruby_exe" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+
+ @name = "ruby_spec_exe"
+ end
+
+ before :each do
+ @ruby_platform = Object.const_get :RUBY_PLATFORM
+
+ @script = RubyExeSpecs.new
+ end
+
+ after :each do
+ Object.const_set :RUBY_PLATFORM, @ruby_platform
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ end
+
+ it "returns the value returned by #ruby_exe_options if it exists and is executable" do
+ Object.const_set :RUBY_PLATFORM, "notwindows"
+ @script.should_receive(:ruby_exe_options).and_return(@name)
+ File.should_receive(:exists?).with(@name).and_return(true)
+ File.should_receive(:executable?).with(@name).and_return(true)
+ @script.resolve_ruby_exe.should == @name
+ end
+
+ it "returns the value returned by #ruby_exe_options if it exists on Windows platforms" do
+ Object.const_set :RUBY_PLATFORM, "mswin"
+ @script.should_receive(:ruby_exe_options).and_return(@name)
+ File.should_receive(:exists?).with(@name).and_return(true)
+ File.should_not_receive(:executable?)
+ @script.resolve_ruby_exe.should == @name
+ end
+
+ it "returns nil if no exe is found" do
+ File.should_receive(:exists?).at_least(:once).and_return(false)
+ @script.resolve_ruby_exe.should be_nil
+ end
+end
+
+describe Object, "#ruby_exe" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+
+ @ruby_flags = ENV["RUBY_FLAGS"]
+ ENV["RUBY_FLAGS"] = "-w -Q"
+
+ @ruby_exe = Object.const_get :RUBY_EXE
+ Object.const_set :RUBY_EXE, 'ruby_spec_exe'
+
+ @file = "some/ruby/file.rb"
+ @code = %(some "real" 'ruby' code)
+
+ @script = RubyExeSpecs.new
+ end
+
+ after :all do
+ Object.const_set :RUBY_EXE, @ruby_exe
+ ENV["RUBY_FLAGS"] = @ruby_flags
+ $VERBOSE = @verbose
+ end
+
+ it "executes the argument if it is a file that exists" do
+ File.should_receive(:exists?).with(@file).and_return(true)
+ @script.should_receive(:`).with("ruby_spec_exe -w -Q some/ruby/file.rb")
+ @script.ruby_exe @file
+ end
+
+ it "executes the file with options and arguments" do
+ File.should_receive(:exists?).with(@file).and_return(true)
+ @script.should_receive(:`).with(
+ "ruby_spec_exe -w -Q -w -Cdir some/ruby/file.rb < file.txt")
+ @script.ruby_exe @file, :options => "-w -Cdir", :args => "< file.txt"
+ end
+
+ it "executes the argument with -e" do
+ File.should_receive(:exists?).with(@code).and_return(false)
+ @script.should_receive(:`).with(
+ %(ruby_spec_exe -w -Q -e "some \\"real\\" 'ruby' code"))
+ @script.ruby_exe @code
+ end
+
+ it "executes the code with options and arguments" do
+ File.should_receive(:exists?).with(@code).and_return(false)
+ @script.should_receive(:`).with(
+ %(ruby_spec_exe -w -Q -W0 -Cdir -e "some \\"real\\" 'ruby' code" < file.txt))
+ @script.ruby_exe @code, :options => "-W0 -Cdir", :args => "< file.txt"
+ end
+
+ it "executes with options and arguments but without code or file" do
+ @script.should_receive(:`).with("ruby_spec_exe -w -Q -c > file.txt")
+ @script.ruby_exe nil, :options => "-c", :args => "> file.txt"
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/helpers/scratch_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/helpers/scratch_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/helpers/scratch_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,22 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe ScratchPad do
+ it "records an object and returns a previously recorded object" do
+ ScratchPad.record :this
+ ScratchPad.recorded.should == :this
+ end
+
+ it "clears the recorded object" do
+ ScratchPad.record :that
+ ScratchPad.recorded.should == :that
+ ScratchPad.clear
+ ScratchPad.recorded.should == nil
+ end
+
+ it "provides a convenience shortcut to append to a previously recorded object" do
+ ScratchPad.record []
+ ScratchPad << :new
+ ScratchPad << :another
+ ScratchPad.recorded.should == [:new, :another]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/helpers/tmp_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/helpers/tmp_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/helpers/tmp_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,72 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/helpers/tmp'
+
+describe Object, "#tmp" do
+ before :each do
+ File.stub!(:directory?).and_return(false)
+ File.stub!(:symlink?).and_return(false)
+ ENV.stub!(:[]).and_return(nil)
+ end
+
+ it "returns /tmp/<name> if /tmp is a writable directory" do
+ dir = "/tmp"
+ File.should_receive(:directory?).with(dir).and_return(true)
+ File.should_receive(:writable?).with(dir).and_return(true)
+ File.should_receive(:expand_path).with(dir).and_return(dir)
+ tmp("test.txt").should == dir + "/test.txt"
+ end
+
+ it "returns /var/tmp/<name> if /var/tmp is a writable directory" do
+ dir = "/var/tmp"
+ File.should_receive(:directory?).with(dir).and_return(true)
+ File.should_receive(:writable?).with(dir).and_return(true)
+ File.should_receive(:expand_path).with(dir).and_return(dir)
+ tmp("test.txt").should == dir + "/test.txt"
+ end
+
+ it "returns ENV['TMPDIR']/<name> if ENV['TMPDIR'] is a writable directory" do
+ dir = "/tmpdir"
+ ENV.should_receive(:[]).with("TMPDIR").and_return(dir)
+ File.should_receive(:directory?).with(dir).and_return(true)
+ File.should_receive(:writable?).with(dir).and_return(true)
+ File.should_receive(:expand_path).with(dir).and_return(dir)
+ tmp("test.txt").should == dir + "/test.txt"
+ end
+
+ it "returns ENV['TMP']/<name> if ENV['TMP'] is a writable directory" do
+ dir = "/tmp/tmp"
+ ENV.should_receive(:[]).with("TMP").and_return(dir)
+ File.should_receive(:directory?).with(dir).and_return(true)
+ File.should_receive(:writable?).with(dir).and_return(true)
+ File.should_receive(:expand_path).with(dir).and_return(dir)
+ tmp("test.txt").should == dir + "/test.txt"
+ end
+
+ it "returns ENV['TEMP']/<name> if ENV['TEMP'] is a writable directory" do
+ dir = "/tmp/temp"
+ ENV.should_receive(:[]).with("TEMP").and_return(dir)
+ File.should_receive(:directory?).with(dir).and_return(true)
+ File.should_receive(:writable?).with(dir).and_return(true)
+ File.should_receive(:expand_path).with(dir).and_return(dir)
+ tmp("test.txt").should == dir + "/test.txt"
+ end
+
+ it "returns ENV['USERPROFILE']/<name> if ENV['USERPROFILE'] is a writable directory" do
+ dir = "/tmp/temp"
+ ENV.should_receive(:[]).with("TEMP").and_return(dir)
+ File.should_receive(:directory?).with(dir).and_return(true)
+ File.should_receive(:writable?).with(dir).and_return(true)
+ File.should_receive(:expand_path).with(dir).and_return(dir)
+ tmp("test.txt").should == dir + "/test.txt"
+ end
+
+ it "returns the actual file name if the file is a symlink" do
+ dir = "/tmp"
+ File.should_receive(:directory?).with(dir).and_return(true)
+ File.should_receive(:writable?).with(dir).and_return(true)
+ File.should_receive(:expand_path).with(dir).and_return(dir)
+ File.should_receive(:symlink?).with(dir).and_return(true)
+ File.should_receive(:readlink).with(dir).and_return("/ponies"+dir)
+ tmp("test.txt").should == "/ponies" + dir + "/test.txt"
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/base_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/base_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/base_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,216 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/base'
+require 'time'
+
+describe PositiveOperatorMatcher, "== operator" do
+ it "raises an ExpectationNotMetError when expected == actual returns false" do
+ lambda {
+ PositiveOperatorMatcher.new(1) == 2
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "provides a failure message that 'Expected x to equal y'" do
+ Expectation.should_receive(:fail_with).with("Expected 1\n", "to equal 2\n")
+ PositiveOperatorMatcher.new(1) == 2
+ end
+
+ it "does not raise an exception when expected == actual returns true" do
+ PositiveOperatorMatcher.new(1) == 1
+ end
+end
+
+describe PositiveOperatorMatcher, "=~ operator" do
+ it "raises an ExpectationNotMetError when expected =~ actual returns false" do
+ lambda {
+ PositiveOperatorMatcher.new('real') =~ /fake/
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "provides a failure message that 'Expected \"x\" to match y'" do
+ Expectation.should_receive(:fail_with).with("Expected \"real\"\n", "to match /fake/\n")
+ PositiveOperatorMatcher.new('real') =~ /fake/
+ end
+
+ it "does not raise an exception when expected =~ actual returns true" do
+ PositiveOperatorMatcher.new('real') =~ /real/
+ end
+end
+
+describe PositiveOperatorMatcher, "> operator" do
+ it "raises an ExpectationNotMetError when expected > actual returns false" do
+ lambda {
+ PositiveOperatorMatcher.new(4) > 5
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "provides a failure message that 'Expected x to be greater than y'" do
+ Expectation.should_receive(:fail_with).with("Expected 4\n", "to be greater than 5\n")
+ PositiveOperatorMatcher.new(4) > 5
+ end
+
+ it "does not raise an exception when expected > actual returns true" do
+ PositiveOperatorMatcher.new(5) > 4
+ end
+end
+
+describe PositiveOperatorMatcher, ">= operator" do
+ it "raises an ExpectationNotMetError when expected >= actual returns false" do
+ lambda {
+ PositiveOperatorMatcher.new(4) >= 5
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "provides a failure message that 'Expected x to be greater than or equal to y'" do
+ Expectation.should_receive(:fail_with).with("Expected 4\n", "to be greater than or equal to 5\n")
+ PositiveOperatorMatcher.new(4) >= 5
+ end
+
+ it "does not raise an exception when expected > actual returns true" do
+ PositiveOperatorMatcher.new(5) >= 4
+ PositiveOperatorMatcher.new(5) >= 5
+ end
+end
+
+describe PositiveOperatorMatcher, "< operater" do
+ it "raises an ExpectationNotMetError when expected < actual returns false" do
+ lambda {
+ PositiveOperatorMatcher.new(5) < 4
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "provides a failure message that 'Expected x to be less than y'" do
+ Expectation.should_receive(:fail_with).with("Expected 5\n", "to be less than 4\n")
+ PositiveOperatorMatcher.new(5) < 4
+ end
+
+ it "does not raise an exception when expected < actual returns true" do
+ PositiveOperatorMatcher.new(4) < 5
+ end
+end
+
+describe PositiveOperatorMatcher, "<= operater" do
+ it "raises an ExpectationNotMetError when expected < actual returns false" do
+ lambda {
+ PositiveOperatorMatcher.new(5) <= 4
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "provides a failure message that 'Expected x to be less than or equal to y'" do
+ Expectation.should_receive(:fail_with).with("Expected 5\n", "to be less than or equal to 4\n")
+ PositiveOperatorMatcher.new(5) <= 4
+ end
+
+ it "does not raise an exception when expected < actual returns true" do
+ PositiveOperatorMatcher.new(4) <= 5
+ PositiveOperatorMatcher.new(4) <= 4
+ end
+end
+
+describe NegativeOperatorMatcher, "== operator" do
+ it "raises an ExpectationNotMetError when expected == actual returns true" do
+ lambda {
+ NegativeOperatorMatcher.new(1) == 1
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "provides a failure message that 'Expected x not to equal y'" do
+ Expectation.should_receive(:fail_with).with("Expected 1\n", "not to equal 1\n")
+ NegativeOperatorMatcher.new(1) == 1
+ end
+
+ it "does not raise an exception when expected == actual returns false" do
+ NegativeOperatorMatcher.new(1) == 2
+ end
+end
+
+describe NegativeOperatorMatcher, "=~ operator" do
+ it "raises an ExpectationNotMetError when expected =~ actual returns true" do
+ lambda {
+ NegativeOperatorMatcher.new('real') =~ /real/
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "provides a failure message that 'Expected \"x\" not to match /y/'" do
+ Expectation.should_receive(:fail_with).with("Expected \"real\"\n", "not to match /real/\n")
+ NegativeOperatorMatcher.new('real') =~ /real/
+ end
+
+ it "does not raise an exception when expected =~ actual returns false" do
+ NegativeOperatorMatcher.new('real') =~ /fake/
+ end
+end
+
+describe NegativeOperatorMatcher, "< operator" do
+ it "raises an ExpectationNotMetError when expected < actual returns true" do
+ lambda {
+ NegativeOperatorMatcher.new(4) < 5
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "provides a failure message that 'Expected x not to be less than y'" do
+ Expectation.should_receive(:fail_with).with("Expected 4\n", "not to be less than 5\n")
+ NegativeOperatorMatcher.new(4) < 5
+ end
+
+ it "does not raise an exception when expected < actual returns false" do
+ NegativeOperatorMatcher.new(5) < 4
+ end
+end
+
+describe NegativeOperatorMatcher, "<= operator" do
+ it "raises an ExpectationNotMetError when expected <= actual returns true" do
+ lambda {
+ NegativeOperatorMatcher.new(4) <= 5
+ }.should raise_error(ExpectationNotMetError)
+ lambda {
+ NegativeOperatorMatcher.new(5) <= 5
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "provides a failure message that 'Expected x not to be less than or equal to y'" do
+ Expectation.should_receive(:fail_with).with("Expected 4\n", "not to be less than or equal to 5\n")
+ NegativeOperatorMatcher.new(4) <= 5
+ end
+
+ it "does not raise an exception when expected <= actual returns false" do
+ NegativeOperatorMatcher.new(5) <= 4
+ end
+end
+
+describe NegativeOperatorMatcher, "> operator" do
+ it "raises an ExpectationNotMetError when expected > actual returns true" do
+ lambda {
+ NegativeOperatorMatcher.new(5) > 4
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "provides a failure message that 'Expected x not to be greater than y'" do
+ Expectation.should_receive(:fail_with).with("Expected 5\n", "not to be greater than 4\n")
+ NegativeOperatorMatcher.new(5) > 4
+ end
+
+ it "does not raise an exception when expected > actual returns false" do
+ NegativeOperatorMatcher.new(4) > 5
+ end
+end
+
+describe NegativeOperatorMatcher, ">= operator" do
+ it "raises an ExpectationNotMetError when expected >= actual returns true" do
+ lambda {
+ NegativeOperatorMatcher.new(5) >= 4
+ }.should raise_error(ExpectationNotMetError)
+ lambda {
+ NegativeOperatorMatcher.new(5) >= 5
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "provides a failure message that 'Expected x not to be greater than or equal to y'" do
+ Expectation.should_receive(:fail_with).with("Expected 5\n", "not to be greater than or equal to 4\n")
+ NegativeOperatorMatcher.new(5) >= 4
+ end
+
+ it "does not raise an exception when expected >= actual returns false" do
+ NegativeOperatorMatcher.new(4) >= 5
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/be_an_instance_of_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/be_an_instance_of_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/be_an_instance_of_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,50 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/be_an_instance_of'
+
+module BeAnInOfSpecs
+ class A
+ end
+
+ class B < A
+ end
+
+ class C < B
+ end
+end
+
+describe BeAnInstanceOfMatcher do
+ it "matches when actual is an instance_of? expected" do
+ a = BeAnInOfSpecs::A.new
+ BeAnInstanceOfMatcher.new(BeAnInOfSpecs::A).matches?(a).should be_true
+
+ b = BeAnInOfSpecs::B.new
+ BeAnInstanceOfMatcher.new(BeAnInOfSpecs::B).matches?(b).should be_true
+ end
+
+ it "does not match when actual is not an instance_of? expected" do
+ a = BeAnInOfSpecs::A.new
+ BeAnInstanceOfMatcher.new(BeAnInOfSpecs::B).matches?(a).should be_false
+
+ b = BeAnInOfSpecs::B.new
+ BeAnInstanceOfMatcher.new(BeAnInOfSpecs::A).matches?(b).should be_false
+
+ c = BeAnInOfSpecs::C.new
+ BeAnInstanceOfMatcher.new(BeAnInOfSpecs::A).matches?(c).should be_false
+ BeAnInstanceOfMatcher.new(BeAnInOfSpecs::B).matches?(c).should be_false
+ end
+
+ it "provides a useful failure message" do
+ matcher = BeAnInstanceOfMatcher.new(Numeric)
+ matcher.matches?("string")
+ matcher.failure_message.should == [
+ "Expected \"string\" (String)", "to be an instance of Numeric"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = BeAnInstanceOfMatcher.new(Numeric)
+ matcher.matches?(4.2)
+ matcher.negative_failure_message.should == [
+ "Expected 4.2 (Float)", "not to be an instance of Numeric"]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/be_ancestor_of_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/be_ancestor_of_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/be_ancestor_of_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,28 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/be_ancestor_of'
+
+class Parent; end
+class Child < Parent; end
+
+describe BeAncestorOfMatcher do
+ it "matches when actual is an ancestor of expected" do
+ BeAncestorOfMatcher.new(Child).matches?(Parent).should == true
+ end
+
+ it "does not match when actual is not an ancestor of expected" do
+ BeAncestorOfMatcher.new(Parent).matches?(Child).should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = BeAncestorOfMatcher.new(Parent)
+ matcher.matches?(Child)
+ matcher.failure_message.should == ["Expected Child", "to be an ancestor of Parent"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = BeAncestorOfMatcher.new(Child)
+ matcher.matches?(Parent)
+ matcher.negative_failure_message.should == ["Expected Parent", "not to be an ancestor of Child"]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/be_close_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/be_close_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/be_close_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,46 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/be_close'
+
+# Adapted from RSpec 1.0.8
+describe BeCloseMatcher do
+ it "matches when actual == expected" do
+ BeCloseMatcher.new(5.0, 0.5).matches?(5.0).should == true
+ end
+
+ it "matches when actual < (expected + tolerance)" do
+ BeCloseMatcher.new(5.0, 0.5).matches?(5.49).should == true
+ end
+
+ it "matches when actual > (expected - tolerance)" do
+ BeCloseMatcher.new(5.0, 0.5).matches?(4.51).should == true
+ end
+
+ it "does not match when actual == (expected + tolerance)" do
+ BeCloseMatcher.new(5.0, 0.5).matches?(5.5).should == false
+ end
+
+ it "does not match when actual == (expected - tolerance)" do
+ BeCloseMatcher.new(5.0, 0.5).matches?(4.5).should == false
+ end
+
+ it "does not match when actual < (expected - tolerance)" do
+ BeCloseMatcher.new(5.0, 0.5).matches?(4.49).should == false
+ end
+
+ it "does not match when actual > (expected + tolerance)" do
+ BeCloseMatcher.new(5.0, 0.5).matches?(5.51).should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = BeCloseMatcher.new(5.0, 0.5)
+ matcher.matches?(5.51)
+ matcher.failure_message.should == ["Expected 5.0", "to be within +/- 0.5 of 5.51"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = BeCloseMatcher.new(5.0, 0.5)
+ matcher.matches?(5.0)
+ matcher.negative_failure_message.should == ["Expected 5.0", "not to be within +/- 0.5 of 5.0"]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/be_empty_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/be_empty_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/be_empty_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,26 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/be_empty'
+
+describe BeEmptyMatcher do
+ it "matches when actual is empty" do
+ BeEmptyMatcher.new.matches?("").should == true
+ end
+
+ it "does not match when actual is not empty" do
+ BeEmptyMatcher.new.matches?([10]).should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = BeEmptyMatcher.new
+ matcher.matches?("not empty string")
+ matcher.failure_message.should == ["Expected \"not empty string\"", "to be empty"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = BeEmptyMatcher.new
+ matcher.matches?("")
+ matcher.negative_failure_message.should == ["Expected \"\"", "not to be empty"]
+ end
+end
+
Added: MacRuby/branches/experimental/mspec/spec/matchers/be_false_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/be_false_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/be_false_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,28 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/be_false'
+
+describe BeFalseMatcher do
+ it "matches when actual is false" do
+ BeFalseMatcher.new.matches?(false).should == true
+ end
+
+ it "does not match when actual is not false" do
+ BeFalseMatcher.new.matches?("").should == false
+ BeFalseMatcher.new.matches?(true).should == false
+ BeFalseMatcher.new.matches?(nil).should == false
+ BeFalseMatcher.new.matches?(0).should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = BeFalseMatcher.new
+ matcher.matches?("some string")
+ matcher.failure_message.should == ["Expected \"some string\"", "to be false"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = BeFalseMatcher.new
+ matcher.matches?(false)
+ matcher.negative_failure_message.should == ["Expected false", "not to be false"]
+ end
+end
\ No newline at end of file
Added: MacRuby/branches/experimental/mspec/spec/matchers/be_kind_of_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/be_kind_of_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/be_kind_of_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,31 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/be_kind_of'
+
+describe BeKindOfMatcher do
+ it "matches when actual is a kind_of? expected" do
+ BeKindOfMatcher.new(Integer).matches?(1).should == true
+ BeKindOfMatcher.new(Fixnum).matches?(2).should == true
+ BeKindOfMatcher.new(Regexp).matches?(/m/).should == true
+ end
+
+ it "does not match when actual is not a kind_of? expected" do
+ BeKindOfMatcher.new(Integer).matches?(1.5).should == false
+ BeKindOfMatcher.new(String).matches?(:a).should == false
+ BeKindOfMatcher.new(Hash).matches?([]).should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = BeKindOfMatcher.new(Numeric)
+ matcher.matches?('string')
+ matcher.failure_message.should == [
+ "Expected \"string\" (String)", "to be kind of Numeric"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = BeKindOfMatcher.new(Numeric)
+ matcher.matches?(4.2)
+ matcher.negative_failure_message.should == [
+ "Expected 4.2 (Float)", "not to be kind of Numeric"]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/be_nil_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/be_nil_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/be_nil_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,27 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/be_nil'
+
+describe BeNilMatcher do
+ it "matches when actual is nil" do
+ BeNilMatcher.new.matches?(nil).should == true
+ end
+
+ it "does not match when actual is not nil" do
+ BeNilMatcher.new.matches?("").should == false
+ BeNilMatcher.new.matches?(false).should == false
+ BeNilMatcher.new.matches?(0).should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = BeNilMatcher.new
+ matcher.matches?("some string")
+ matcher.failure_message.should == ["Expected \"some string\"", "to be nil"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = BeNilMatcher.new
+ matcher.matches?(nil)
+ matcher.negative_failure_message.should == ["Expected nil", "not to be nil"]
+ end
+end
\ No newline at end of file
Added: MacRuby/branches/experimental/mspec/spec/matchers/be_true_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/be_true_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/be_true_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,28 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/be_true'
+
+describe BeTrueMatcher do
+ it "matches when actual is true" do
+ BeTrueMatcher.new.matches?(true).should == true
+ end
+
+ it "does not match when actual is not true" do
+ BeTrueMatcher.new.matches?("").should == false
+ BeTrueMatcher.new.matches?(false).should == false
+ BeTrueMatcher.new.matches?(nil).should == false
+ BeTrueMatcher.new.matches?(0).should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = BeTrueMatcher.new
+ matcher.matches?("some string")
+ matcher.failure_message.should == ["Expected \"some string\"", "to be true"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = BeTrueMatcher.new
+ matcher.matches?(true)
+ matcher.negative_failure_message.should == ["Expected true", "not to be true"]
+ end
+end
\ No newline at end of file
Added: MacRuby/branches/experimental/mspec/spec/matchers/complain_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/complain_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/complain_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,52 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/complain'
+
+describe ComplainMatcher do
+ it "matches when executing the proc results in output to $stderr" do
+ proc = lambda { warn "I'm gonna tell yo mama" }
+ ComplainMatcher.new(nil).matches?(proc).should == true
+ end
+
+ it "maches when executing the proc results in the expected output to $stderr" do
+ proc = lambda { warn "Que haces?" }
+ ComplainMatcher.new("Que haces?\n").matches?(proc).should == true
+ ComplainMatcher.new("Que pasa?\n").matches?(proc).should == false
+ ComplainMatcher.new(/Que/).matches?(proc).should == true
+ ComplainMatcher.new(/Quoi/).matches?(proc).should == false
+ end
+
+ it "does not match when there is no output to $stderr" do
+ ComplainMatcher.new(nil).matches?(lambda {}).should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = ComplainMatcher.new(nil)
+ matcher.matches?(lambda { })
+ matcher.failure_message.should == ["Expected a warning", "but received none"]
+ matcher = ComplainMatcher.new("listen here")
+ matcher.matches?(lambda { warn "look out" })
+ matcher.failure_message.should ==
+ ["Expected warning: \"listen here\"", "but got: \"look out\""]
+ matcher = ComplainMatcher.new(/talk/)
+ matcher.matches?(lambda { warn "listen up" })
+ matcher.failure_message.should ==
+ ["Expected warning to match:", "/talk/"]
+ end
+
+ it "provides a useful negative failure message" do
+ proc = lambda { warn "ouch" }
+ matcher = ComplainMatcher.new(nil)
+ matcher.matches?(proc)
+ matcher.negative_failure_message.should ==
+ ["Unexpected warning: ", "\"ouch\""]
+ matcher = ComplainMatcher.new("ouchy")
+ matcher.matches?(proc)
+ matcher.negative_failure_message.should ==
+ ["Expected warning: \"ouchy\"", "but got: \"ouch\""]
+ matcher = ComplainMatcher.new(/ou/)
+ matcher.matches?(proc)
+ matcher.negative_failure_message.should ==
+ ["Expected warning not to match:", "/ou/"]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/eql_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/eql_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/eql_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,33 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/eql'
+
+describe EqlMatcher do
+ it "matches when actual is eql? to expected" do
+ EqlMatcher.new(1).matches?(1).should == true
+ EqlMatcher.new(1.5).matches?(1.5).should == true
+ EqlMatcher.new("red").matches?("red").should == true
+ EqlMatcher.new(:blue).matches?(:blue).should == true
+ EqlMatcher.new(Object).matches?(Object).should == true
+
+ o = Object.new
+ EqlMatcher.new(o).matches?(o).should == true
+ end
+
+ it "does not match when actual is not eql? to expected" do
+ EqlMatcher.new(1).matches?(1.0).should == false
+ EqlMatcher.new(Hash).matches?(Object).should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = EqlMatcher.new("red")
+ matcher.matches?("red")
+ matcher.failure_message.should == ["Expected \"red\"\n", "to have same value and type as \"red\"\n"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = EqlMatcher.new(1)
+ matcher.matches?(1.0)
+ matcher.negative_failure_message.should == ["Expected 1.0\n", "not to have same value or type as 1\n"]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/equal_element_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/equal_element_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/equal_element_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,75 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/equal_element'
+
+describe EqualElementMatcher do
+ it "matches if it finds an element with the passed name, no matter what attributes/content" do
+ EqualElementMatcher.new("A").matches?('<A></A>').should be_true
+ EqualElementMatcher.new("A").matches?('<A HREF="http://example.com"></A>').should be_true
+ EqualElementMatcher.new("A").matches?('<A HREF="http://example.com"></A>').should be_true
+
+ EqualElementMatcher.new("BASE").matches?('<BASE></A>').should be_false
+ EqualElementMatcher.new("BASE").matches?('<A></BASE>').should be_false
+ EqualElementMatcher.new("BASE").matches?('<A></A>').should be_false
+ EqualElementMatcher.new("BASE").matches?('<A HREF="http://example.com"></A>').should be_false
+ EqualElementMatcher.new("BASE").matches?('<A HREF="http://example.com"></A>').should be_false
+ end
+
+ it "matches if it finds an element with the passed name and the passed attributes" do
+ EqualElementMatcher.new("A", {}).matches?('<A></A>').should be_true
+ EqualElementMatcher.new("A", nil).matches?('<A HREF="http://example.com"></A>').should be_true
+ EqualElementMatcher.new("A", "HREF" => "http://example.com").matches?('<A HREF="http://example.com"></A>').should be_true
+
+ EqualElementMatcher.new("A", {}).matches?('<A HREF="http://example.com"></A>').should be_false
+ EqualElementMatcher.new("A", "HREF" => "http://example.com").matches?('<A></A>').should be_false
+ EqualElementMatcher.new("A", "HREF" => "http://example.com").matches?('<A HREF="http://test.com"></A>').should be_false
+ EqualElementMatcher.new("A", "HREF" => "http://example.com").matches?('<A HREF="http://example.com" HREF="http://example.com"></A>').should be_false
+ end
+
+ it "matches if it finds an element with the passed name, the passed attributes and the passed content" do
+ EqualElementMatcher.new("A", {}, "").matches?('<A></A>').should be_true
+ EqualElementMatcher.new("A", {"HREF" => "http://example.com"}, "Example").matches?('<A HREF="http://example.com">Example</A>').should be_true
+
+ EqualElementMatcher.new("A", {}, "Test").matches?('<A></A>').should be_false
+ EqualElementMatcher.new("A", {"HREF" => "http://example.com"}, "Example").matches?('<A HREF="http://example.com"></A>').should be_false
+ EqualElementMatcher.new("A", {"HREF" => "http://example.com"}, "Example").matches?('<A HREF="http://example.com">Test</A>').should be_false
+ end
+
+ it "can match unclosed elements" do
+ EqualElementMatcher.new("BASE", nil, nil, :not_closed => true).matches?('<BASE>').should be_true
+ EqualElementMatcher.new("BASE", {"HREF" => "http://example.com"}, nil, :not_closed => true).matches?('<BASE HREF="http://example.com">').should be_true
+ EqualElementMatcher.new("BASE", {"HREF" => "http://example.com"}, "Example", :not_closed => true).matches?('<BASE HREF="http://example.com">Example').should be_true
+
+ EqualElementMatcher.new("BASE", {}, nil, :not_closed => true).matches?('<BASE HREF="http://example.com">').should be_false
+ EqualElementMatcher.new("BASE", {"HREF" => "http://example.com"}, "", :not_closed => true).matches?('<BASE HREF="http://example.com">Example').should be_false
+ EqualElementMatcher.new("BASE", {"HREF" => "http://example.com"}, "Test", :not_closed => true).matches?('<BASE HREF="http://example.com">Example').should be_false
+ end
+
+ it "provides a useful failure message" do
+ equal_element = EqualElementMatcher.new("A", {}, "Test")
+ equal_element.matches?('<A></A>').should be_false
+ equal_element.failure_message.should == [%{Expected "<A></A>"\n}, %{to be a 'A' element with no attributes and "Test" as content}]
+
+ equal_element = EqualElementMatcher.new("A", {}, "")
+ equal_element.matches?('<A>Test</A>').should be_false
+ equal_element.failure_message.should == [%{Expected "<A>Test</A>"\n}, %{to be a 'A' element with no attributes and no content}]
+
+ equal_element = EqualElementMatcher.new("A", "HREF" => "http://www.example.com")
+ equal_element.matches?('<A>Test</A>').should be_false
+ equal_element.failure_message.should == [%{Expected "<A>Test</A>"\n}, %{to be a 'A' element with HREF="http://www.example.com" and any content}]
+ end
+
+ it "provides a useful negative failure message" do
+ equal_element = EqualElementMatcher.new("A", {}, "Test")
+ equal_element.matches?('<A></A>').should be_false
+ equal_element.negative_failure_message.should == [%{Expected "<A></A>"\n}, %{not to be a 'A' element with no attributes and "Test" as content}]
+
+ equal_element = EqualElementMatcher.new("A", {}, "")
+ equal_element.matches?('<A>Test</A>').should be_false
+ equal_element.negative_failure_message.should == [%{Expected "<A>Test</A>"\n}, %{not to be a 'A' element with no attributes and no content}]
+
+ equal_element = EqualElementMatcher.new("A", "HREF" => "http://www.example.com")
+ equal_element.matches?('<A>Test</A>').should be_false
+ equal_element.negative_failure_message.should == [%{Expected "<A>Test</A>"\n}, %{not to be a 'A' element with HREF="http://www.example.com" and any content}]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/equal_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/equal_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/equal_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,33 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/equal'
+
+describe EqualMatcher do
+ it "matches when actual is equal? to expected" do
+ EqualMatcher.new(1).matches?(1).should == true
+ EqualMatcher.new(:blue).matches?(:blue).should == true
+ EqualMatcher.new(Object).matches?(Object).should == true
+
+ o = Object.new
+ EqualMatcher.new(o).matches?(o).should == true
+ end
+
+ it "does not match when actual is not a equal? to expected" do
+ EqualMatcher.new(1).matches?(1.0).should == false
+ EqualMatcher.new(1.5).matches?(1.5).should == false
+ EqualMatcher.new("blue").matches?("blue").should == false
+ EqualMatcher.new(Hash).matches?(Object).should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = EqualMatcher.new("red")
+ matcher.matches?("red")
+ matcher.failure_message.should == ["Expected \"red\"\n", "to be identical to \"red\"\n"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = EqualMatcher.new(1)
+ matcher.matches?(1)
+ matcher.negative_failure_message.should == ["Expected 1\n", "not to be identical to 1\n"]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/equal_utf16_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/equal_utf16_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/equal_utf16_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,47 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/equal_utf16'
+
+describe EqualUtf16Matcher do
+ it "when given strings, matches when actual == expected" do
+ EqualUtf16Matcher.new("abcd").matches?("abcd").should == true
+ end
+
+ it "when given strings, matches when actual == expected, with byte order reversed" do
+ EqualUtf16Matcher.new("abcd").matches?("badc").should == true
+ end
+
+ it "when given arrays, matches when actual == expected" do
+ EqualUtf16Matcher.new(["abcd"]).matches?(["abcd"]).should == true
+ EqualUtf16Matcher.new(["abcd", "efgh"]).matches?(["abcd", "efgh"]).should == true
+ end
+
+ it "when given arrays, matches when actual == a version of expected with byte order reversed for all strings contained" do
+ EqualUtf16Matcher.new(["abcd"]).matches?(["badc"]).should == true
+ EqualUtf16Matcher.new(["abcd", "efgh"]).matches?(["badc", "fehg"]).should == true
+ end
+
+ it "when given strings, does not match when actual != expected AND != expected with byte order reversed" do
+ EqualUtf16Matcher.new("abcd").matches?("").should == false
+ EqualUtf16Matcher.new("abcd").matches?(nil).should == false
+ EqualUtf16Matcher.new("abcd").matches?("acbd").should == false
+ end
+
+ it "when given arrays, does not match when actual is not == expected or == a version of expected with byte order reversed for all strings contained simultaneously" do
+ EqualUtf16Matcher.new(["abcd"]).matches?([]).should == false
+ EqualUtf16Matcher.new(["abcd"]).matches?(["dcba"]).should == false
+ EqualUtf16Matcher.new(["abcd", "efgh"]).matches?(["abcd", "fehg"]).should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = EqualUtf16Matcher.new("a\0b\0")
+ matcher.matches?("a\0b\0c\0")
+ matcher.failure_message.should == ["Expected \"a\\000b\\000c\\000\"\n", "to equal \"a\\000b\\000\"\n or \"\\000a\\000b\"\n"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = EqualUtf16Matcher.new("a\0b\0")
+ matcher.matches?("\0a\0b")
+ matcher.negative_failure_message.should == ["Expected \"\\000a\\000b\"\n", "not to equal \"a\\000b\\000\"\n nor \"\\000a\\000b\"\n"]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/have_constant_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/have_constant_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/have_constant_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,37 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/have_constant'
+
+class HCMSpecs
+ X = :x
+end
+
+describe HaveConstantMatcher do
+ it "matches when mod has the constant" do
+ matcher = HaveConstantMatcher.new :X
+ matcher.matches?(HCMSpecs).should be_true
+ end
+
+ it "does not match when mod does not have the constant" do
+ matcher = HaveConstantMatcher.new :A
+ matcher.matches?(HCMSpecs).should be_false
+ end
+
+ it "provides a failure message for #should" do
+ matcher = HaveConstantMatcher.new :A
+ matcher.matches?(HCMSpecs)
+ matcher.failure_message.should == [
+ "Expected HCMSpecs to have constant 'A'",
+ "but it does not"
+ ]
+ end
+
+ it "provides a failure messoge for #should_not" do
+ matcher = HaveConstantMatcher.new :X
+ matcher.matches?(HCMSpecs)
+ matcher.negative_failure_message.should == [
+ "Expected HCMSpecs NOT to have constant 'X'",
+ "but it does"
+ ]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/have_instance_method_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/have_instance_method_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/have_instance_method_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,53 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/have_instance_method'
+
+class HIMMSpecs
+ def instance_method
+ end
+
+ class Subclass < HIMMSpecs
+ def instance_sub_method
+ end
+ end
+end
+
+describe HaveInstanceMethodMatcher do
+ it "inherits from MethodMatcher" do
+ HaveInstanceMethodMatcher.new(:m).should be_kind_of(MethodMatcher)
+ end
+
+ it "matches when mod has the instance method" do
+ matcher = HaveInstanceMethodMatcher.new :instance_method
+ matcher.matches?(HIMMSpecs).should be_true
+ matcher.matches?(HIMMSpecs::Subclass).should be_true
+ end
+
+ it "does not match when mod does not have the instance method" do
+ matcher = HaveInstanceMethodMatcher.new :another_method
+ matcher.matches?(HIMMSpecs).should be_false
+ end
+
+ it "does not match if the method is in a superclass and include_super is false" do
+ matcher = HaveInstanceMethodMatcher.new :instance_method, false
+ matcher.matches?(HIMMSpecs::Subclass).should be_false
+ end
+
+ it "provides a failure message for #should" do
+ matcher = HaveInstanceMethodMatcher.new :some_method
+ matcher.matches?(HIMMSpecs)
+ matcher.failure_message.should == [
+ "Expected HIMMSpecs to have instance method 'some_method'",
+ "but it does not"
+ ]
+ end
+
+ it "provides a failure messoge for #should_not" do
+ matcher = HaveInstanceMethodMatcher.new :some_method
+ matcher.matches?(HIMMSpecs)
+ matcher.negative_failure_message.should == [
+ "Expected HIMMSpecs NOT to have instance method 'some_method'",
+ "but it does"
+ ]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/have_method_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/have_method_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/have_method_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,55 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/have_method'
+
+class HMMSpecs
+ def instance_method
+ end
+
+ class Subclass < HMMSpecs
+ def instance_sub_method
+ end
+ end
+end
+
+describe HaveMethodMatcher do
+ it "inherits from MethodMatcher" do
+ HaveMethodMatcher.new(:m).should be_kind_of(MethodMatcher)
+ end
+
+ it "matches when mod has the method" do
+ matcher = HaveMethodMatcher.new :instance_method
+ matcher.matches?(HMMSpecs).should be_true
+ matcher.matches?(HMMSpecs.new).should be_true
+ matcher.matches?(HMMSpecs::Subclass).should be_true
+ matcher.matches?(HMMSpecs::Subclass.new).should be_true
+ end
+
+ it "does not match when mod does not have the method" do
+ matcher = HaveMethodMatcher.new :another_method
+ matcher.matches?(HMMSpecs).should be_false
+ end
+
+ it "does not match if the method is in a superclass and include_super is false" do
+ matcher = HaveMethodMatcher.new :instance_method, false
+ matcher.matches?(HMMSpecs::Subclass).should be_false
+ end
+
+ it "provides a failure message for #should" do
+ matcher = HaveMethodMatcher.new :some_method
+ matcher.matches?(HMMSpecs)
+ matcher.failure_message.should == [
+ "Expected HMMSpecs to have method 'some_method'",
+ "but it does not"
+ ]
+ end
+
+ it "provides a failure messoge for #should_not" do
+ matcher = HaveMethodMatcher.new :some_method
+ matcher.matches?(HMMSpecs)
+ matcher.negative_failure_message.should == [
+ "Expected HMMSpecs NOT to have method 'some_method'",
+ "but it does"
+ ]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/have_private_instance_method_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/have_private_instance_method_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/have_private_instance_method_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,57 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/have_private_instance_method'
+
+class HPIMMSpecs
+ private
+
+ def private_method
+ end
+
+ class Subclass < HPIMMSpecs
+ private
+
+ def private_sub_method
+ end
+ end
+end
+
+describe HavePrivateInstanceMethodMatcher do
+ it "inherits from MethodMatcher" do
+ HavePrivateInstanceMethodMatcher.new(:m).should be_kind_of(MethodMatcher)
+ end
+
+ it "matches when mod has the private instance method" do
+ matcher = HavePrivateInstanceMethodMatcher.new :private_method
+ matcher.matches?(HPIMMSpecs).should be_true
+ matcher.matches?(HPIMMSpecs::Subclass).should be_true
+ end
+
+ it "does not match when mod does not have the private instance method" do
+ matcher = HavePrivateInstanceMethodMatcher.new :another_method
+ matcher.matches?(HPIMMSpecs).should be_false
+ end
+
+ it "does not match if the method is in a superclass and include_super is false" do
+ matcher = HavePrivateInstanceMethodMatcher.new :private_method, false
+ matcher.matches?(HPIMMSpecs::Subclass).should be_false
+ end
+
+ it "provides a failure message for #should" do
+ matcher = HavePrivateInstanceMethodMatcher.new :some_method
+ matcher.matches?(HPIMMSpecs)
+ matcher.failure_message.should == [
+ "Expected HPIMMSpecs to have private instance method 'some_method'",
+ "but it does not"
+ ]
+ end
+
+ it "provides a failure messoge for #should_not" do
+ matcher = HavePrivateInstanceMethodMatcher.new :some_method
+ matcher.matches?(HPIMMSpecs)
+ matcher.negative_failure_message.should == [
+ "Expected HPIMMSpecs NOT to have private instance method 'some_method'",
+ "but it does"
+ ]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/include_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/include_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/include_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,37 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/include'
+
+describe IncludeMatcher do
+ it "matches when actual includes expected" do
+ IncludeMatcher.new(2).matches?([1,2,3]).should == true
+ IncludeMatcher.new("b").matches?("abc").should == true
+ end
+
+ it "does not match when actual does not include expected" do
+ IncludeMatcher.new(4).matches?([1,2,3]).should == false
+ IncludeMatcher.new("d").matches?("abc").should == false
+ end
+
+ it "matches when actual includes all expected" do
+ IncludeMatcher.new(3, 2, 1).matches?([1,2,3]).should == true
+ IncludeMatcher.new("a", "b", "c").matches?("abc").should == true
+ end
+
+ it "does not match when actual does not include all expected" do
+ IncludeMatcher.new(3, 2, 4).matches?([1,2,3]).should == false
+ IncludeMatcher.new("a", "b", "c", "d").matches?("abc").should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = IncludeMatcher.new(5, 2)
+ matcher.matches?([1,2,3])
+ matcher.failure_message.should == ["Expected [1, 2, 3]", "to include 5"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = IncludeMatcher.new(1, 2, 3)
+ matcher.matches?([1,2,3])
+ matcher.negative_failure_message.should == ["Expected [1, 2, 3]", "not to include 3"]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/match_yaml_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/match_yaml_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/match_yaml_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,39 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/match_yaml'
+
+describe MatchYAMLMatcher do
+ before :each do
+ @matcher = MatchYAMLMatcher.new("--- \nfoo: bar\n")
+ end
+
+ it "compares YAML documents and matches if they're equivalent" do
+ @matcher.matches?("--- \nfoo: bar\n").should == true
+ end
+
+ it "compares YAML documents and does not match if they're not equivalent" do
+ @matcher.matches?("--- \nbar: foo\n").should == false
+ @matcher.matches?("--- \nfoo: \nbar\n").should == false
+ end
+
+ it "also receives objects that respond_to to_yaml" do
+ matcher = MatchYAMLMatcher.new("some string")
+ matcher.matches?("some string").should == true
+
+ matcher = MatchYAMLMatcher.new(['a', 'b'])
+ matcher.matches?("--- \n- a\n- b\n").should == true
+
+ matcher = MatchYAMLMatcher.new("foo" => "bar")
+ matcher.matches?("--- \nfoo: bar\n").should == true
+ end
+
+ it "matches documents with trailing whitespace" do
+ @matcher.matches?("--- \nfoo: bar \n").should == true
+ @matcher.matches?("--- \nfoo: bar \n").should == true
+ end
+
+ it "fails with a descriptive error message" do
+ @matcher.matches?("foo").should == false
+ @matcher.failure_message.should == ["Expected \"foo\"", " to match \"--- \\nfoo: bar\\n\""]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/output_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/output_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/output_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,74 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/output'
+
+describe OutputMatcher do
+ it "matches when executing the proc results in the expected output to $stdout" do
+ proc = Proc.new { puts "bang!" }
+ OutputMatcher.new("bang!\n", nil).matches?(proc).should == true
+ OutputMatcher.new("pop", nil).matches?(proc).should == false
+ OutputMatcher.new(/bang/, nil).matches?(proc).should == true
+ OutputMatcher.new(/po/, nil).matches?(proc).should == false
+ end
+
+ it "matches when executing the proc results in the expected output to $stderr" do
+ proc = Proc.new { $stderr.write "boom!" }
+ OutputMatcher.new(nil, "boom!").matches?(proc).should == true
+ OutputMatcher.new(nil, "fizzle").matches?(proc).should == false
+ OutputMatcher.new(nil, /boom/).matches?(proc).should == true
+ OutputMatcher.new(nil, /fizzl/).matches?(proc).should == false
+ end
+
+ it "provides a useful failure message" do
+ proc = Proc.new { puts "unexpected"; $stderr.puts "unerror" }
+ matcher = OutputMatcher.new("expected", "error")
+ matcher.matches?(proc)
+ matcher.failure_message.should ==
+ ["Expected:\n $stdout: \"expected\"\n $stderr: \"error\"\n",
+ " got:\n $stdout: \"unexpected\"\n $stderr: \"unerror\"\n"]
+ matcher = OutputMatcher.new("expected", nil)
+ matcher.matches?(proc)
+ matcher.failure_message.should ==
+ ["Expected:\n $stdout: \"expected\"\n",
+ " got:\n $stdout: \"unexpected\"\n"]
+ matcher = OutputMatcher.new(nil, "error")
+ matcher.matches?(proc)
+ matcher.failure_message.should ==
+ ["Expected:\n $stderr: \"error\"\n",
+ " got:\n $stderr: \"unerror\"\n"]
+ matcher = OutputMatcher.new(/base/, nil)
+ matcher.matches?(proc)
+ matcher.failure_message.should ==
+ ["Expected:\n $stdout: /base/\n",
+ " got:\n $stdout: \"unexpected\"\n"]
+ matcher = OutputMatcher.new(nil, /octave/)
+ matcher.matches?(proc)
+ matcher.failure_message.should ==
+ ["Expected:\n $stderr: /octave/\n",
+ " got:\n $stderr: \"unerror\"\n"]
+ end
+
+ it "provides a useful negative failure message" do
+ proc = Proc.new { puts "expected"; $stderr.puts "error" }
+ matcher = OutputMatcher.new("expected", "error")
+ matcher.matches?(proc)
+ matcher.negative_failure_message.should ==
+ ["Expected output not to be:\n", " $stdout: \"expected\"\n $stderr: \"error\"\n"]
+ matcher = OutputMatcher.new("expected", nil)
+ matcher.matches?(proc)
+ matcher.negative_failure_message.should ==
+ ["Expected output not to be:\n", " $stdout: \"expected\"\n"]
+ matcher = OutputMatcher.new(nil, "error")
+ matcher.matches?(proc)
+ matcher.negative_failure_message.should ==
+ ["Expected output not to be:\n", " $stderr: \"error\"\n"]
+ matcher = OutputMatcher.new(/expect/, nil)
+ matcher.matches?(proc)
+ matcher.negative_failure_message.should ==
+ ["Expected output not to be:\n", " $stdout: \"expected\"\n"]
+ matcher = OutputMatcher.new(nil, /err/)
+ matcher.matches?(proc)
+ matcher.negative_failure_message.should ==
+ ["Expected output not to be:\n", " $stderr: \"error\"\n"]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/output_to_fd_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/output_to_fd_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/output_to_fd_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,33 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/output_to_fd'
+
+describe OutputToFDMatcher do
+ # Figure out how in the hell to achieve this
+ it "matches when running the block produces the expected output to the given FD" do
+ output_to_fd("Hi\n", STDERR).matches?(lambda { $stderr.print "Hi\n" }).should == true
+ end
+
+ it "does not match if running the block does not produce the expected output to the FD" do
+ output_to_fd("Hi\n", STDERR).matches?(lambda { $stderr.puts("Hello\n") }).should == false
+ end
+
+ it "defaults to matching against STDOUT" do
+ output_to_fd("Hi\n").matches?(lambda { $stdout.print "Hi\n" }).should == true
+ end
+
+ it "accepts any IO instance" do
+ io = IO.new STDOUT.fileno
+ output_to_fd("Hi\n", io).matches?(lambda { io.print "Hi\n" }).should == true
+ end
+
+ it "allows matching with a Regexp" do
+ s = "Hi there\n"
+ output_to_fd(/Hi/, STDERR).matches?(lambda { $stderr.print s }).should == true
+ output_to_fd(/Hi?/, STDERR).matches?(lambda { $stderr.print s }).should == true
+ output_to_fd(/[hH]i?/, STDERR).matches?(lambda { $stderr.print s }).should == true
+ output_to_fd(/.*/, STDERR).matches?(lambda { $stderr.print s }).should == true
+ output_to_fd(/H.*?here/, STDERR).matches?(lambda { $stderr.print s }).should == true
+ output_to_fd(/Ahoy/, STDERR).matches?(lambda { $stderr.print s }).should == false
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/raise_error_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/raise_error_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/raise_error_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,56 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/raise_error'
+
+class ExpectedException < Exception; end
+class UnexpectedException < Exception; end
+
+describe RaiseErrorMatcher do
+ it "matches when the proc raises the expected exception" do
+ proc = Proc.new { raise ExpectedException }
+ RaiseErrorMatcher.new(ExpectedException, nil).matches?(proc).should == true
+ end
+
+ it "executes it's optional block if matched" do
+ run = false
+ proc = Proc.new { raise ExpectedException }
+ matcher = RaiseErrorMatcher.new(ExpectedException, nil) { |error|
+ run = true
+ error.class.should == ExpectedException
+ }
+
+ matcher.matches?(proc).should == true
+ run.should == true
+ end
+
+ it "matches when the proc raises the expected exception with the expected message" do
+ proc = Proc.new { raise ExpectedException, "message" }
+ RaiseErrorMatcher.new(ExpectedException, "message").matches?(proc).should == true
+ end
+
+ it "does not match when the proc does not raise the expected exception" do
+ proc = Proc.new { raise UnexpectedException }
+ RaiseErrorMatcher.new(ExpectedException, nil).matches?(proc).should == false
+ end
+
+ it "does not match when the proc raises the expected exception with an unexpected message" do
+ proc = Proc.new { raise UnexpectedException, "unexpected" }
+ RaiseErrorMatcher.new(ExpectedException, "expected").matches?(proc).should == false
+ end
+
+ it "provides a useful failure message" do
+ proc = Proc.new { raise UnexpectedException, "unexpected" }
+ matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
+ matcher.matches?(proc)
+ matcher.failure_message.should ==
+ ["Expected ExpectedException (expected)", "but got UnexpectedException (unexpected)"]
+ end
+
+ it "provides a useful negative failure message" do
+ proc = Proc.new { raise ExpectedException, "expected" }
+ matcher = RaiseErrorMatcher.new(ExpectedException, "expected")
+ matcher.matches?(proc)
+ matcher.negative_failure_message.should ==
+ ["Expected to not get ExpectedException (expected)", ""]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/respond_to_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/respond_to_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/respond_to_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,31 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/respond_to'
+
+describe RespondToMatcher do
+ it "matches when actual does respond_to? expected" do
+ RespondToMatcher.new(:to_s).matches?(Object.new).should == true
+ RespondToMatcher.new(:inject).matches?([]).should == true
+ RespondToMatcher.new(:[]).matches?(1).should == true
+ RespondToMatcher.new(:[]=).matches?("string").should == true
+ end
+
+ it "does not match when actual does not respond_to? expected" do
+ RespondToMatcher.new(:to_i).matches?(Object.new).should == false
+ RespondToMatcher.new(:inject).matches?(1).should == false
+ RespondToMatcher.new(:non_existent_method).matches?([]).should == false
+ RespondToMatcher.new(:[]=).matches?(1).should == false
+ end
+
+ it "provides a useful failure message" do
+ matcher = RespondToMatcher.new(:non_existent_method)
+ matcher.matches?('string')
+ matcher.failure_message.should == ["Expected \"string\" (String)", "to respond to non_existent_method"]
+ end
+
+ it "provides a useful negative failure message" do
+ matcher = RespondToMatcher.new(:to_i)
+ matcher.matches?(4.2)
+ matcher.negative_failure_message.should == ["Expected 4.2 (Float)", "not to respond to to_i"]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/matchers/stringsymboladapter_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/matchers/stringsymboladapter_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/matchers/stringsymboladapter_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,40 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/stringsymboladapter'
+
+class StringSymbolSpecs
+ include StringSymbolAdapter
+end
+
+describe StringSymbolAdapter, "#convert_name" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ end
+
+ before :each do
+ @ruby_version = Object.const_get :RUBY_VERSION
+
+ @name = mock("name")
+ end
+
+ after :each do
+ Object.const_set :RUBY_VERSION, @ruby_version
+ end
+
+ it "converts the name to a string if RUBY_VERSION < 1.9" do
+ Object.const_set :RUBY_VERSION, "1.8.6"
+ @name.should_receive(:to_s).and_return("method_name")
+ StringSymbolSpecs.new.convert_name @name
+ end
+
+ it "does not convert the name to a string if RUBY_VERSION >= 1.9" do
+ Object.const_set :RUBY_VERSION, "1.9.0"
+ @name.should_not_receive(:to_s)
+ StringSymbolSpecs.new.convert_name @name
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/mocks/mock_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/mocks/mock_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/mocks/mock_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,448 @@
+# This is a bit awkward. Currently the way to verify that the
+# opposites are true (for example a failure when the specified
+# arguments are NOT provided) is to simply alter the particular
+# spec to a failure condition.
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/runner/mspec'
+require 'mspec/mocks/mock'
+require 'mspec/mocks/proxy'
+
+describe Mock, ".mocks" do
+ it "returns a Hash" do
+ Mock.mocks.should be_kind_of(Hash)
+ end
+end
+
+describe Mock, ".stubs" do
+ it "returns a Hash" do
+ Mock.stubs.should be_kind_of(Hash)
+ end
+end
+
+describe Mock, ".replaced_name" do
+ it "returns the name for a method that is being replaced by a mock method" do
+ m = mock('a fake id')
+ m.stub!(:__id__).and_return(42)
+ Mock.replaced_name(m, :method_call).should == :__ms_42_method_call__
+ end
+end
+
+describe Mock, ".replaced_key" do
+ it "returns a key used internally by Mock" do
+ m = mock('a fake id')
+ m.stub!(:__id__).and_return(42)
+ Mock.replaced_key(m, :method_call).should == [:__ms_42_method_call__, m, :method_call]
+ end
+end
+
+describe Mock, ".replaced?" do
+ before :each do
+ @mock = mock('install_method')
+ MSpec.stub!(:actions)
+ MSpec.stub!(:current).and_return(mock("spec state", :null_object => true))
+ end
+
+ it "returns true if a method has been stubbed on an object" do
+ Mock.install_method @mock, :method_call
+ Mock.replaced?(Mock.replaced_key(@mock, :method_call)).should be_true
+ end
+
+ it "returns true if a method has been mocked on an object" do
+ Mock.install_method @mock, :method_call, :stub
+ Mock.replaced?(Mock.replaced_key(@mock, :method_call)).should be_true
+ end
+
+ it "returns false if a method has not been stubbed or mocked" do
+ Mock.replaced?(Mock.replaced_key(@mock, :method_call)).should be_false
+ end
+end
+
+describe Mock, ".name_or_inspect" do
+ before :each do
+ @mock = mock("I have a #name")
+ end
+
+ it "returns the value of @name if set" do
+ @mock.instance_variable_set(:@name, "Myself")
+ Mock.name_or_inspect(@mock).should == "Myself"
+ end
+end
+
+describe Mock, ".install_method for mocks" do
+ before :each do
+ @mock = mock('install_method')
+ MSpec.stub!(:actions)
+ MSpec.stub!(:current).and_return(mock("spec state", :null_object => true))
+ end
+
+ after :each do
+ Mock.cleanup
+ end
+
+ it "returns a MockProxy instance" do
+ Mock.install_method(@mock, :method_call).should be_an_instance_of(MockProxy)
+ end
+
+ it "does not override a previously mocked method with the same name" do
+ Mock.install_method(@mock, :method_call).with(:a, :b).and_return(1)
+ Mock.install_method(@mock, :method_call).with(:c).and_return(2)
+ @mock.method_call(:a, :b)
+ @mock.method_call(:c)
+ lambda { @mock.method_call(:d) }.should raise_error(ExpectationNotMetError)
+ end
+
+ # This illustrates RSpec's behavior. This spec fails in mock call count verification
+ # on RSpec (i.e. Mock 'foo' expected :foo with (any args) once, but received it 0 times)
+ # and we mimic the behavior of RSpec.
+ #
+ # describe "A mock receiving multiple calls to #should_receive" do
+ # it "returns the first value mocked" do
+ # m = mock 'multiple #should_receive'
+ # m.should_receive(:foo).and_return(true)
+ # m.foo.should == true
+ # m.should_receive(:foo).and_return(false)
+ # m.foo.should == true
+ # end
+ # end
+ #
+ it "does not override a previously mocked method having the same arguments" do
+ Mock.install_method(@mock, :method_call).with(:a).and_return(true)
+ @mock.method_call(:a).should == true
+ Mock.install_method(@mock, :method_call).with(:a).and_return(false)
+ @mock.method_call(:a).should == true
+ lambda { Mock.verify_count }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "properly sends #respond_to? calls to the aliased respond_to? method when not matching mock expectations" do
+ Mock.install_method(@mock, :respond_to?).with(:to_str).and_return('mock to_str')
+ Mock.install_method(@mock, :respond_to?).with(:to_int).and_return('mock to_int')
+ @mock.respond_to?(:to_str).should == 'mock to_str'
+ @mock.respond_to?(:to_int).should == 'mock to_int'
+ @mock.respond_to?(:to_s).should == true
+ @mock.respond_to?(:not_really_a_real_method_seriously).should == false
+ end
+
+ it "adds to the expectation tally" do
+ state = mock("run state", :null_object => true)
+ state.stub!(:state).and_return(mock("spec state"))
+ MSpec.should_receive(:current).and_return(state)
+ MSpec.should_receive(:actions).with(:expectation, state.state)
+ Mock.install_method(@mock, :method_call).and_return(1)
+ @mock.method_call.should == 1
+ end
+
+ it "registers that an expectation has been encountered" do
+ state = mock("run state", :null_object => true)
+ state.stub!(:state).and_return(mock("spec state"))
+ MSpec.should_receive(:expectation)
+ Mock.install_method(@mock, :method_call).and_return(1)
+ @mock.method_call.should == 1
+ end
+end
+
+describe Mock, ".install_method for stubs" do
+ before :each do
+ @mock = mock('install_method')
+ MSpec.stub!(:actions)
+ MSpec.stub!(:current).and_return(mock("spec state", :null_object => true))
+ end
+
+ after :each do
+ Mock.cleanup
+ end
+
+ it "returns a MockProxy instance" do
+ Mock.install_method(@mock, :method_call, :stub).should be_an_instance_of(MockProxy)
+ end
+
+ # This illustrates RSpec's behavior. This spec passes on RSpec and we mimic it
+ #
+ # describe "A mock receiving multiple calls to #stub!" do
+ # it "returns the last value stubbed" do
+ # m = mock 'multiple #stub!'
+ # m.stub!(:foo).and_return(true)
+ # m.foo.should == true
+ # m.stub!(:foo).and_return(false)
+ # m.foo.should == false
+ # end
+ # end
+ it "inserts new stubs before old stubs" do
+ Mock.install_method(@mock, :method_call, :stub).with(:a).and_return(true)
+ @mock.method_call(:a).should == true
+ Mock.install_method(@mock, :method_call, :stub).with(:a).and_return(false)
+ @mock.method_call(:a).should == false
+ Mock.verify_count
+ end
+
+ it "does not add to the expectation tally" do
+ state = mock("run state", :null_object => true)
+ state.stub!(:state).and_return(mock("spec state"))
+ MSpec.should_not_receive(:actions)
+ Mock.install_method(@mock, :method_call, :stub).and_return(1)
+ @mock.method_call.should == 1
+ end
+end
+
+describe Mock, ".install_method" do
+ before :each do
+ @mock = mock('install_method')
+ MSpec.stub!(:actions)
+ MSpec.stub!(:current).and_return(mock("spec state", :null_object => true))
+ end
+
+ after :each do
+ Mock.cleanup
+ end
+
+ it "does not alias a mocked or stubbed method when installing a new mock or stub" do
+ @mock.should_not respond_to(:method_call)
+
+ Mock.install_method @mock, :method_call
+ @mock.should respond_to(:method_call)
+ @mock.should_not respond_to(Mock.replaced_name(@mock, :method_call))
+
+ Mock.install_method @mock, :method_call, :stub
+ @mock.should respond_to(:method_call)
+ @mock.should_not respond_to(Mock.replaced_name(@mock, :method_call))
+ end
+end
+
+describe Mock, ".verify_call" do
+ before :each do
+ MSpec.stub!(:actions)
+ MSpec.stub!(:current).and_return(mock("spec state", :null_object => true))
+
+ @mock = mock('verify_call')
+ @proxy = Mock.install_method @mock, :method_call
+ end
+
+ after :each do
+ ScratchPad.clear
+ Mock.cleanup
+ end
+
+ it "does not raise an exception when the mock method receives the expected arguments" do
+ @proxy.with(1, 'two', :three)
+ Mock.verify_call @mock, :method_call, 1, 'two', :three
+ end
+
+ it "raises an ExpectationNotMetError when the mock method does not receive the expected arguments" do
+ @proxy.with(4, 2)
+ lambda {
+ Mock.verify_call @mock, :method_call, 42
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "raises an ExpectationNotMetError when the mock method is called with arguments but expects none" do
+ lambda {
+ @proxy.with(:no_args)
+ Mock.verify_call @mock, :method_call, "hello"
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "raises an ExpectationNotMetError when the mock method is called with no arguments but expects some" do
+ @proxy.with("hello", "beautiful", "world")
+ lambda {
+ Mock.verify_call @mock, :method_call
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "does not raise an exception when the mock method is called with arguments and is expecting :any_args" do
+ @proxy.with(:any_args)
+ Mock.verify_call @mock, :method_call, 1, 2, 3
+ end
+
+ it "yields a passed block when it is expected to" do
+ @proxy.and_yield()
+ Mock.verify_call @mock, :method_call do
+ ScratchPad.record true
+ end
+ ScratchPad.recorded.should == true
+ end
+
+ it "does not yield a passed block when it is not expected to" do
+ Mock.verify_call @mock, :method_call do
+ ScratchPad.record true
+ end
+ ScratchPad.recorded.should == nil
+ end
+
+ it "can yield subsequently" do
+ @proxy.and_yield(1).and_yield(2).and_yield(3)
+
+ ScratchPad.record []
+ Mock.verify_call @mock, :method_call do |arg|
+ ScratchPad << arg
+ end
+ ScratchPad.recorded.should == [1, 2, 3]
+ end
+
+ it "can yield and return an expected value" do
+ @proxy.and_yield(1).and_return(3)
+
+ Mock.verify_call(@mock, :method_call) { |arg| ScratchPad.record arg }.should == 3
+ ScratchPad.recorded.should == 1
+ end
+
+ it "raises an expection when it is expected to yield but no block is given" do
+ @proxy.and_yield(1, 2, 3)
+ lambda {
+ Mock.verify_call(@mock, :method_call)
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "raises an expection when it is expected to yield more arguments than the block can take" do
+ @proxy.and_yield(1, 2, 3)
+ lambda {
+ Mock.verify_call(@mock, :method_call) {|a, b|}
+ }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "does not raise an expection when it is expected to yield to a block that can take any number of arguments" do
+ @proxy.and_yield(1, 2, 3)
+ lambda {
+ Mock.verify_call(@mock, :method_call) {|*a|}
+ }.should_not raise_error(ExpectationNotMetError)
+ end
+end
+
+describe Mock, ".verify_count" do
+ before :each do
+ MSpec.stub!(:actions)
+ MSpec.stub!(:current).and_return(mock("spec state", :null_object => true))
+
+ @mock = mock('verify_count')
+ @proxy = Mock.install_method @mock, :method_call
+ end
+
+ after :each do
+ Mock.cleanup
+ end
+
+ it "does not raise an exception when the mock receives at least the expected number of calls" do
+ @proxy.at_least(2)
+ @mock.method_call
+ @mock.method_call
+ Mock.verify_count
+ end
+
+ it "raises an ExpectationNotMetError when the mock receives less than at least the expected number of calls" do
+ @proxy.at_least(2)
+ @mock.method_call
+ lambda { Mock.verify_count }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "does not raise an exception when the mock receives at most the expected number of calls" do
+ @proxy.at_most(2)
+ @mock.method_call
+ @mock.method_call
+ Mock.verify_count
+ end
+
+ it "raises an ExpectationNotMetError when the mock receives more than at most the expected number of calls" do
+ @proxy.at_most(2)
+ @mock.method_call
+ @mock.method_call
+ @mock.method_call
+ lambda { Mock.verify_count }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "does not raise an exception when the mock receives exactly the expected number of calls" do
+ @proxy.exactly(2)
+ @mock.method_call
+ @mock.method_call
+ Mock.verify_count
+ end
+
+ it "raises an ExpectationNotMetError when the mock receives less than exactly the expected number of calls" do
+ @proxy.exactly(2)
+ @mock.method_call
+ lambda { Mock.verify_count }.should raise_error(ExpectationNotMetError)
+ end
+
+ it "raises an ExpectationNotMetError when the mock receives more than exactly the expected number of calls" do
+ @proxy.exactly(2)
+ @mock.method_call
+ @mock.method_call
+ @mock.method_call
+ lambda { Mock.verify_count }.should raise_error(ExpectationNotMetError)
+ end
+end
+
+describe Mock, ".verify_count mixing mocks and stubs" do
+ before :each do
+ MSpec.stub!(:actions)
+ MSpec.stub!(:current).and_return(mock("spec state", :null_object => true))
+
+ @mock = mock('verify_count')
+ end
+
+ after :each do
+ Mock.cleanup
+ end
+
+ it "does not raise an exception for a stubbed method that is never called" do
+ Mock.install_method @mock, :method_call, :stub
+ Mock.verify_count
+ end
+
+ it "verifies the calls to the mocked method when a mock is defined after a stub" do
+ Mock.install_method @mock, :method_call, :stub
+ Mock.install_method @mock, :method_call, :mock
+ @mock.method_call
+ Mock.verify_count
+ end
+
+ it "verifies the calls to the mocked method when a mock is defined before a stub" do
+ Mock.install_method @mock, :method_call, :mock
+ Mock.install_method @mock, :method_call, :stub
+ @mock.method_call
+ Mock.verify_count
+ end
+end
+
+describe Mock, ".cleanup" do
+ before :each do
+ MSpec.stub!(:actions)
+ MSpec.stub!(:current).and_return(mock("spec state", :null_object => true))
+
+ @mock = mock('cleanup')
+ @proxy = Mock.install_method @mock, :method_call
+ @stub = Mock.install_method @mock, :method_call, :stub
+ end
+
+ after :each do
+ Mock.cleanup
+ end
+
+ it "removes the mock method call if it did not override an existing method" do
+ @mock.should respond_to(:method_call)
+
+ Mock.cleanup
+ @mock.should_not respond_to(:method_call)
+ end
+
+ it "removes the replaced method if the mock method overrides an existing method" do
+ def @mock.already_here() :hey end
+ @mock.should respond_to(:already_here)
+ Mock.install_method @mock, :already_here
+ @mock.should respond_to(Mock.replaced_name(@mock, :already_here))
+
+ Mock.cleanup
+ @mock.should_not respond_to(Mock.replaced_name(@mock, :already_here))
+ @mock.should respond_to(:already_here)
+ @mock.already_here.should == :hey
+ end
+
+ it "removes all mock expectations" do
+ Mock.mocks.should == { Mock.replaced_key(@mock, :method_call) => [@proxy] }
+ Mock.cleanup
+ Mock.mocks.should == {}
+ end
+
+ it "removes all stubs" do
+ Mock.stubs.should == { Mock.replaced_key(@mock, :method_call) => [@stub] }
+ Mock.cleanup
+ Mock.stubs.should == {}
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/mocks/proxy_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/mocks/proxy_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/mocks/proxy_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,366 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/mocks/proxy'
+
+describe MockObject, ".new" do
+ it "creates a new mock object" do
+ m = MockObject.new('not a null object')
+ lambda { m.not_a_method }.should raise_error(NoMethodError)
+ end
+
+ it "creates a new mock object that follows the NullObject pattern" do
+ m = MockObject.new('null object', :null_object => true)
+ m.not_really_a_method.should equal(m)
+ end
+end
+
+describe MockProxy, ".new" do
+ it "creates a mock proxy by default" do
+ MockProxy.new.mock?.should be_true
+ end
+
+ it "creates a stub proxy by request" do
+ MockProxy.new(:stub).stub?.should be_true
+ end
+
+ it "sets the call expectation to 1 call for a mock" do
+ MockProxy.new.count.should == [:exactly, 1]
+ end
+
+ it "sets the call expectation to any number of times for a stub" do
+ MockProxy.new(:stub).count.should == [:any_number_of_times, 0]
+ end
+end
+
+describe MockProxy, "#count" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns the expected number of calls the mock should receive" do
+ @proxy.count.should == [:exactly, 1]
+ @proxy.at_least(3).count.should == [:at_least, 3]
+ end
+end
+
+describe MockProxy, "#arguments" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns the expected arguments" do
+ @proxy.arguments.should == :any_args
+ end
+end
+
+describe MockProxy, "#with" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns self" do
+ @proxy.with(:a).should be_equal(@proxy)
+ end
+
+ it "raises an ArgumentError if no arguments are given" do
+ lambda { @proxy.with }.should raise_error(ArgumentError)
+ end
+
+ it "accepts any number of arguments" do
+ @proxy.with(1, 2, 3).should be_an_instance_of(MockProxy)
+ @proxy.arguments.should == [1,2,3]
+ end
+end
+
+describe MockProxy, "#once" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns self" do
+ @proxy.once.should be_equal(@proxy)
+ end
+
+ it "sets the expected calls to 1" do
+ @proxy.once
+ @proxy.count.should == [:exactly, 1]
+ end
+
+ it "accepts no arguments" do
+ lambda { @proxy.once(:a) }.should raise_error
+ end
+end
+
+describe MockProxy, "#twice" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns self" do
+ @proxy.twice.should be_equal(@proxy)
+ end
+
+ it "sets the expected calls to 2" do
+ @proxy.twice
+ @proxy.count.should == [:exactly, 2]
+ end
+
+ it "accepts no arguments" do
+ lambda { @proxy.twice(:b) }.should raise_error
+ end
+end
+
+describe MockProxy, "#exactly" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns self" do
+ @proxy.exactly(2).should be_equal(@proxy)
+ end
+
+ it "sets the expected calls to exactly n" do
+ @proxy.exactly(5)
+ @proxy.count.should == [:exactly, 5]
+ end
+
+ it "does not accept an argument that Integer() cannot convert" do
+ lambda { @proxy.exactly('x') }.should raise_error
+ end
+end
+
+describe MockProxy, "#at_least" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns self" do
+ @proxy.at_least(3).should be_equal(@proxy)
+ end
+
+ it "sets the expected calls to at least n" do
+ @proxy.at_least(3)
+ @proxy.count.should == [:at_least, 3]
+ end
+
+ it "accepts :once :twice" do
+ @proxy.at_least(:once)
+ @proxy.count.should == [:at_least, 1]
+ @proxy.at_least(:twice)
+ @proxy.count.should == [:at_least, 2]
+ end
+
+ it "does not accept an argument that Integer() cannot convert" do
+ lambda { @proxy.at_least('x') }.should raise_error
+ end
+end
+
+describe MockProxy, "#at_most" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns self" do
+ @proxy.at_most(2).should be_equal(@proxy)
+ end
+
+ it "sets the expected calls to at most n" do
+ @proxy.at_most(2)
+ @proxy.count.should == [:at_most, 2]
+ end
+
+ it "accepts :once, :twice" do
+ @proxy.at_most(:once)
+ @proxy.count.should == [:at_most, 1]
+ @proxy.at_most(:twice)
+ @proxy.count.should == [:at_most, 2]
+ end
+
+ it "does not accept an argument that Integer() cannot convert" do
+ lambda { @proxy.at_most('x') }.should raise_error
+ end
+end
+
+describe MockProxy, "#any_number_of_times" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns self" do
+ @proxy.any_number_of_times.should be_equal(@proxy)
+ end
+
+ it "sets the expected calls to any number of times" do
+ @proxy.any_number_of_times
+ @proxy.count.should == [:any_number_of_times, 0]
+ end
+
+ it "does not accept an argument" do
+ lambda { @proxy.any_number_of_times(2) }.should raise_error
+ end
+end
+
+describe MockProxy, "#and_return" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns self" do
+ @proxy.and_return(false).should equal(@proxy)
+ end
+
+ it "sets the expected return value" do
+ @proxy.and_return(false)
+ @proxy.returning.should == false
+ end
+
+ it "accepts any number of return values" do
+ @proxy.and_return(1, 2, 3)
+ @proxy.returning.should == 1
+ @proxy.returning.should == 2
+ @proxy.returning.should == 3
+ end
+
+ it "implicitly sets the expected number of calls" do
+ @proxy.and_return(1, 2, 3)
+ @proxy.count.should == [:exactly, 3]
+ end
+
+ it "only sets the expected number of calls if it is higher than what is already set" do
+ @proxy.at_least(5).times.and_return(1, 2, 3)
+ @proxy.count.should == [:at_least, 5]
+
+ @proxy.at_least(2).times.and_return(1, 2, 3)
+ @proxy.count.should == [:at_least, 3]
+ end
+end
+
+describe MockProxy, "#returning" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns nil by default" do
+ @proxy.returning.should be_nil
+ end
+
+ it "returns the value set by #and_return" do
+ @proxy.and_return(2)
+ @proxy.returning.should == 2
+ @proxy.returning.should == 2
+ end
+
+ it "returns a sequence of values set by #and_return" do
+ @proxy.and_return(1,2,3,4)
+ @proxy.returning.should == 1
+ @proxy.returning.should == 2
+ @proxy.returning.should == 3
+ @proxy.returning.should == 4
+ @proxy.returning.should == 4
+ @proxy.returning.should == 4
+ end
+end
+
+describe MockProxy, "#calls" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns the number of times the proxy is called" do
+ @proxy.calls.should == 0
+ end
+end
+
+describe MockProxy, "#called" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "increments the number of times the proxy is called" do
+ @proxy.called
+ @proxy.called
+ @proxy.calls.should == 2
+ end
+end
+
+describe MockProxy, "#times" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "is a no-op" do
+ @proxy.times.should == @proxy
+ end
+end
+
+describe MockProxy, "#stub?" do
+ it "returns true if the proxy is created as a stub" do
+ MockProxy.new(:stub).stub?.should be_true
+ end
+
+ it "returns false if the proxy is created as a mock" do
+ MockProxy.new(:mock).stub?.should be_false
+ end
+end
+
+describe MockProxy, "#mock?" do
+ it "returns true if the proxy is created as a mock" do
+ MockProxy.new(:mock).mock?.should be_true
+ end
+
+ it "returns false if the proxy is created as a stub" do
+ MockProxy.new(:stub).mock?.should be_false
+ end
+end
+
+describe MockProxy, "#and_yield" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns self" do
+ @proxy.and_yield(false).should equal(@proxy)
+ end
+
+ it "sets the expected values to yield" do
+ @proxy.and_yield(1).yielding.should == [[1]]
+ end
+
+ it "accepts multiple values to yield" do
+ @proxy.and_yield(1, 2, 3).yielding.should == [[1, 2, 3]]
+ end
+end
+
+describe MockProxy, "#yielding" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns an empty array by default" do
+ @proxy.yielding.should == []
+ end
+
+ it "returns an array of arrays of values the proxy should yield" do
+ @proxy.and_yield(3)
+ @proxy.yielding.should == [[3]]
+ end
+
+ it "returns an accumulation of arrays of values the proxy should yield" do
+ @proxy.and_yield(1).and_yield(2, 3)
+ @proxy.yielding.should == [[1], [2, 3]]
+ end
+end
+
+describe MockProxy, "#yielding?" do
+ before :each do
+ @proxy = MockProxy.new
+ end
+
+ it "returns false if the proxy is not yielding" do
+ @proxy.yielding?.should be_false
+ end
+
+ it "returns true if the proxy is yielding" do
+ @proxy.and_yield(1)
+ @proxy.yielding?.should be_true
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/actions/debug_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/actions/debug_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/actions/debug_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,62 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/actions/debug'
+require 'mspec/runner/mspec'
+require 'mspec/runner/context'
+require 'mspec/runner/example'
+
+describe DebugAction do
+ before :each do
+ MSpec.stub!(:read_tags).and_return([])
+ end
+
+ it "creates an MatchFilter with its tag and desc arguments" do
+ filter = mock('action filter', :null_object => true)
+ MatchFilter.should_receive(:new).with(nil, "some", "thing").and_return(filter)
+ DebugAction.new ["tag", "key"], ["some", "thing"]
+ end
+end
+
+describe DebugAction, "#before" do
+ before :each do
+ MSpec.stub!(:read_tags).and_return([])
+ @state = ExampleState.new ContextState.new("Catch#me"), "if you can"
+ end
+
+ it "does not invoke the debugger if the description does not match" do
+ Kernel.should_not_receive(:debugger)
+ action = DebugAction.new nil, "match"
+ action.before @state
+ end
+
+ it "invokes the debugger if the description matches" do
+ Kernel.should_receive(:debugger)
+ action = DebugAction.new nil, "can"
+ action.before @state
+ end
+end
+
+describe DebugAction, "#register" do
+ before :each do
+ MSpec.stub!(:read_tags).and_return([])
+ MSpec.stub!(:register)
+ @action = DebugAction.new nil, nil
+ end
+
+ it "registers itself with MSpec for the :before action" do
+ MSpec.should_receive(:register).with(:before, @action)
+ @action.register
+ end
+end
+
+describe DebugAction, "#unregister" do
+ before :each do
+ MSpec.stub!(:read_tags).and_return([])
+ MSpec.stub!(:unregister)
+ @action = DebugAction.new nil, nil
+ end
+
+ it "unregisters itself with MSpec for the :before action" do
+ MSpec.should_receive(:unregister).with(:before, @action)
+ @action.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/actions/filter_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/actions/filter_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/actions/filter_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,84 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/actions/filter'
+require 'mspec/runner/mspec'
+require 'mspec/runner/tag'
+
+describe ActionFilter do
+ it "creates a filter when not passed a description" do
+ MatchFilter.should_not_receive(:new)
+ ActionFilter.new(nil, nil)
+ end
+
+ it "creates a filter from a single description" do
+ MatchFilter.should_receive(:new).with(nil, "match me")
+ ActionFilter.new(nil, "match me")
+ end
+
+ it "creates a filter from an array of descriptions" do
+ MatchFilter.should_receive(:new).with(nil, "match me", "again")
+ ActionFilter.new(nil, ["match me", "again"])
+ end
+end
+
+describe ActionFilter, "#===" do
+ before :each do
+ MSpec.stub!(:read_tags).and_return(["match"])
+ @action = ActionFilter.new(nil, ["catch", "if you"])
+ end
+
+ it "returns false if there are no filters" do
+ action = ActionFilter.new
+ action.===("anything").should == false
+ end
+
+ it "returns true if the argument matches any of the descriptions" do
+ @action.===("catch").should == true
+ @action.===("if you can").should == true
+ end
+
+ it "returns false if the argument does not match any of the descriptions" do
+ @action.===("patch me").should == false
+ @action.===("if I can").should == false
+ end
+end
+
+describe ActionFilter, "#load" do
+ before :each do
+ @tag = SpecTag.new "tag(comment):description"
+ end
+
+ it "creates a filter from a single tag" do
+ MSpec.should_receive(:read_tags).with(["tag"]).and_return([@tag])
+ MatchFilter.should_receive(:new).with(nil, "description")
+ ActionFilter.new("tag", nil).load
+ end
+
+ it "creates a filter from an array of tags" do
+ MSpec.should_receive(:read_tags).with(["tag", "key"]).and_return([@tag])
+ MatchFilter.should_receive(:new).with(nil, "description")
+ ActionFilter.new(["tag", "key"], nil).load
+ end
+
+ it "creates a filter from both tags and descriptions" do
+ MSpec.should_receive(:read_tags).and_return([@tag])
+ filter = ActionFilter.new("tag", ["match me", "again"])
+ MatchFilter.should_receive(:new).with(nil, "description")
+ filter.load
+ end
+end
+
+describe ActionFilter, "#register" do
+ it "registers itself with MSpec for the :load actions" do
+ filter = ActionFilter.new
+ MSpec.should_receive(:register).with(:load, filter)
+ filter.register
+ end
+end
+
+describe ActionFilter, "#unregister" do
+ it "unregisters itself with MSpec for the :load actions" do
+ filter = ActionFilter.new
+ MSpec.should_receive(:unregister).with(:load, filter)
+ filter.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/actions/gdb_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/actions/gdb_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/actions/gdb_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,61 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/actions/gdb'
+require 'mspec/runner/mspec'
+require 'mspec/runner/example'
+
+describe GdbAction do
+ before :each do
+ MSpec.stub!(:read_tags).and_return([])
+ end
+
+ it "creates an MatchFilter with its tag and desc arguments" do
+ filter = mock('action filter', :null_object => true)
+ MatchFilter.should_receive(:new).with(nil, "some", "thing").and_return(filter)
+ GdbAction.new ["tag", "key"], ["some", "thing"]
+ end
+end
+
+describe GdbAction, "#before" do
+ before :each do
+ MSpec.stub!(:read_tags).and_return([])
+ @state = ExampleState.new ContextState.new("Catch#me"), "if you can"
+ end
+
+ it "does not invoke the debugger if the description does not match" do
+ Kernel.should_not_receive(:yield_gdb)
+ action = GdbAction.new nil, "match"
+ action.before @state
+ end
+
+ it "invokes the debugger if the description matches" do
+ Kernel.should_receive(:yield_gdb).with(true)
+ action = GdbAction.new nil, "can"
+ action.before @state
+ end
+end
+
+describe GdbAction, "#register" do
+ before :each do
+ MSpec.stub!(:read_tags).and_return([])
+ MSpec.stub!(:register)
+ @action = GdbAction.new nil, nil
+ end
+
+ it "registers itself with MSpec for the :before action" do
+ MSpec.should_receive(:register).with(:before, @action)
+ @action.register
+ end
+end
+
+describe GdbAction, "#unregister" do
+ before :each do
+ MSpec.stub!(:read_tags).and_return([])
+ MSpec.stub!(:unregister)
+ @action = GdbAction.new nil, nil
+ end
+
+ it "unregisters itself with MSpec for the :before action" do
+ MSpec.should_receive(:unregister).with(:before, @action)
+ @action.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/actions/tag_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/actions/tag_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/actions/tag_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,315 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/actions/tag'
+require 'mspec/runner/mspec'
+require 'mspec/runner/example'
+require 'mspec/runner/tag'
+
+describe TagAction, ".new" do
+ it "creates an MatchFilter with its tag and desc arguments" do
+ filter = mock('action filter', :null_object => true)
+ MatchFilter.should_receive(:new).with(nil, "some", "thing").and_return(filter)
+ TagAction.new :add, :all, nil, nil, ["tag", "key"], ["some", "thing"]
+ end
+end
+
+describe TagAction, "#===" do
+ before :each do
+ MSpec.stub!(:read_tags).and_return(["match"])
+ @action = TagAction.new :add, :fail, nil, nil, nil, ["catch", "if you"]
+ end
+
+ it "returns true if there are no filters" do
+ action = TagAction.new :add, :all, nil, nil
+ action.===("anything").should == true
+ end
+
+ it "returns true if the argument matches any of the descriptions" do
+ @action.===("catch").should == true
+ @action.===("if you can").should == true
+ end
+
+ it "returns false if the argument does not match any of the descriptions" do
+ @action.===("patch me").should == false
+ @action.===("if I can").should == false
+ end
+end
+
+describe TagAction, "#exception?" do
+ before :each do
+ @action = TagAction.new :add, :fail, nil, nil, nil, nil
+ end
+
+ it "returns false if no exception has been raised while evaluating an example" do
+ @action.exception?.should be_false
+ end
+
+ it "returns true if an exception was raised while evaluating an example" do
+ @action.exception ExceptionState.new nil, nil, Exception.new("failed")
+ @action.exception?.should be_true
+ end
+end
+
+describe TagAction, "#outcome?" do
+ before :each do
+ MSpec.stub!(:read_tags).and_return([])
+ @exception = ExceptionState.new nil, nil, Exception.new("failed")
+ end
+
+ it "returns true if outcome is :fail and the spec fails" do
+ action = TagAction.new :add, :fail, nil, nil, nil, nil
+ action.exception @exception
+ action.outcome?.should == true
+ end
+
+ it "returns false if the outcome is :fail and the spec passes" do
+ action = TagAction.new :add, :fail, nil, nil, nil, nil
+ action.outcome?.should == false
+ end
+
+ it "returns true if the outcome is :pass and the spec passes" do
+ action = TagAction.new :del, :pass, nil, nil, nil, nil
+ action.outcome?.should == true
+ end
+
+ it "returns false if the outcome is :pass and the spec fails" do
+ action = TagAction.new :del, :pass, nil, nil, nil, nil
+ action.exception @exception
+ action.outcome?.should == false
+ end
+
+ it "returns true if the outcome is :all" do
+ action = TagAction.new :add, :all, nil, nil, nil, nil
+ action.exception @exception
+ action.outcome?.should == true
+ end
+end
+
+describe TagAction, "#before" do
+ it "resets the #exception? flag to false" do
+ action = TagAction.new :add, :fail, nil, nil, nil, nil
+ action.exception?.should be_false
+ action.exception ExceptionState.new(nil, nil, Exception.new("Fail!"))
+ action.exception?.should be_true
+ action.before(ExampleState.new(ContextState.new("describe"), "it"))
+ action.exception?.should be_false
+ end
+end
+
+describe TagAction, "#exception" do
+ it "sets the #exception? flag" do
+ action = TagAction.new :add, :fail, nil, nil, nil, nil
+ action.exception?.should be_false
+ action.exception ExceptionState.new(nil, nil, Exception.new("Fail!"))
+ action.exception?.should be_true
+ end
+end
+
+describe TagAction, "#after when action is :add" do
+ before :each do
+ MSpec.stub!(:read_tags).and_return([])
+ context = ContextState.new "Catch#me"
+ @state = ExampleState.new context, "if you can"
+ @tag = SpecTag.new "tag(comment):Catch#me if you can"
+ SpecTag.stub!(:new).and_return(@tag)
+ @exception = ExceptionState.new nil, nil, Exception.new("failed")
+ end
+
+ it "does not write a tag if the description does not match" do
+ MSpec.should_not_receive(:write_tag)
+ action = TagAction.new :add, :all, "tag", "comment", nil, "match"
+ action.after @state
+ end
+
+ it "does not write a tag if outcome is :fail and the spec passed" do
+ MSpec.should_not_receive(:write_tag)
+ action = TagAction.new :add, :fail, "tag", "comment", nil, "can"
+ action.after @state
+ end
+
+ it "writes a tag if the outcome is :fail and the spec failed" do
+ MSpec.should_receive(:write_tag).with(@tag)
+ action = TagAction.new :add, :fail, "tag", "comment", nil, "can"
+ action.exception @exception
+ action.after @state
+ end
+
+ it "does not write a tag if outcome is :pass and the spec failed" do
+ MSpec.should_not_receive(:write_tag)
+ action = TagAction.new :add, :pass, "tag", "comment", nil, "can"
+ action.exception @exception
+ action.after @state
+ end
+
+ it "writes a tag if the outcome is :pass and the spec passed" do
+ MSpec.should_receive(:write_tag).with(@tag)
+ action = TagAction.new :add, :pass, "tag", "comment", nil, "can"
+ action.after @state
+ end
+
+ it "writes a tag if the outcome is :all" do
+ MSpec.should_receive(:write_tag).with(@tag)
+ action = TagAction.new :add, :all, "tag", "comment", nil, "can"
+ action.after @state
+ end
+end
+
+describe TagAction, "#after when action is :del" do
+ before :each do
+ MSpec.stub!(:read_tags).and_return([])
+ context = ContextState.new "Catch#me"
+ @state = ExampleState.new context, "if you can"
+ @tag = SpecTag.new "tag(comment):Catch#me if you can"
+ SpecTag.stub!(:new).and_return(@tag)
+ @exception = ExceptionState.new nil, nil, Exception.new("failed")
+ end
+
+ it "does not delete a tag if the description does not match" do
+ MSpec.should_not_receive(:delete_tag)
+ action = TagAction.new :del, :all, "tag", "comment", nil, "match"
+ action.after @state
+ end
+
+ it "does not delete a tag if outcome is :fail and the spec passed" do
+ MSpec.should_not_receive(:delete_tag)
+ action = TagAction.new :del, :fail, "tag", "comment", nil, "can"
+ action.after @state
+ end
+
+ it "deletes a tag if the outcome is :fail and the spec failed" do
+ MSpec.should_receive(:delete_tag).with(@tag)
+ action = TagAction.new :del, :fail, "tag", "comment", nil, "can"
+ action.exception @exception
+ action.after @state
+ end
+
+ it "does not delete a tag if outcome is :pass and the spec failed" do
+ MSpec.should_not_receive(:delete_tag)
+ action = TagAction.new :del, :pass, "tag", "comment", nil, "can"
+ action.exception @exception
+ action.after @state
+ end
+
+ it "deletes a tag if the outcome is :pass and the spec passed" do
+ MSpec.should_receive(:delete_tag).with(@tag)
+ action = TagAction.new :del, :pass, "tag", "comment", nil, "can"
+ action.after @state
+ end
+
+ it "deletes a tag if the outcome is :all" do
+ MSpec.should_receive(:delete_tag).with(@tag)
+ action = TagAction.new :del, :all, "tag", "comment", nil, "can"
+ action.after @state
+ end
+end
+
+describe TagAction, "#finish" do
+ before :each do
+ $stdout = @out = IOStub.new
+ context = ContextState.new "Catch#me"
+ @state = ExampleState.new context, "if you can"
+ MSpec.stub!(:write_tag).and_return(true)
+ MSpec.stub!(:delete_tag).and_return(true)
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "reports no specs tagged if none where tagged" do
+ action = TagAction.new :add, :fail, "tag", "comment", nil, "can"
+ action.stub!(:outcome?).and_return(false)
+ action.after @state
+ action.finish
+ @out.should == "\nTagAction: no specs were tagged with 'tag'\n"
+ end
+
+ it "reports no specs tagged if none where tagged" do
+ action = TagAction.new :del, :fail, "tag", "comment", nil, "can"
+ action.stub!(:outcome?).and_return(false)
+ action.after @state
+ action.finish
+ @out.should == "\nTagAction: no tags 'tag' were deleted\n"
+ end
+
+ it "reports the spec descriptions that were tagged" do
+ action = TagAction.new :add, :fail, "tag", "comment", nil, "can"
+ action.stub!(:outcome?).and_return(true)
+ action.after @state
+ action.finish
+ @out.should ==
+%[
+TagAction: specs tagged with 'tag':
+
+Catch#me if you can
+]
+ end
+
+ it "reports the spec descriptions for the tags that were deleted" do
+ action = TagAction.new :del, :fail, "tag", "comment", nil, "can"
+ action.stub!(:outcome?).and_return(true)
+ action.after @state
+ action.finish
+ @out.should ==
+%[
+TagAction: tag 'tag' deleted for specs:
+
+Catch#me if you can
+]
+ end
+end
+
+describe TagAction, "#register" do
+ before :each do
+ MSpec.stub!(:register)
+ MSpec.stub!(:read_tags).and_return([])
+ @action = TagAction.new :add, :all, nil, nil, nil, nil
+ end
+
+ it "registers itself with MSpec for the :before event" do
+ MSpec.should_receive(:register).with(:before, @action)
+ @action.register
+ end
+
+ it "registers itself with MSpec for the :after event" do
+ MSpec.should_receive(:register).with(:after, @action)
+ @action.register
+ end
+
+ it "registers itself with MSpec for the :exception event" do
+ MSpec.should_receive(:register).with(:exception, @action)
+ @action.register
+ end
+
+ it "registers itself with MSpec for the :finish event" do
+ MSpec.should_receive(:register).with(:finish, @action)
+ @action.register
+ end
+end
+
+describe TagAction, "#unregister" do
+ before :each do
+ MSpec.stub!(:unregister)
+ MSpec.stub!(:read_tags).and_return([])
+ @action = TagAction.new :add, :all, nil, nil, nil, nil
+ end
+
+ it "unregisters itself with MSpec for the :before event" do
+ MSpec.should_receive(:unregister).with(:before, @action)
+ @action.unregister
+ end
+
+ it "unregisters itself with MSpec for the :after event" do
+ MSpec.should_receive(:unregister).with(:after, @action)
+ @action.unregister
+ end
+
+ it "unregisters itself with MSpec for the :exception event" do
+ MSpec.should_receive(:unregister).with(:exception, @action)
+ @action.unregister
+ end
+
+ it "unregisters itself with MSpec for the :finish event" do
+ MSpec.should_receive(:unregister).with(:finish, @action)
+ @action.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/actions/taglist_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/actions/taglist_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/actions/taglist_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,152 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/actions/taglist'
+require 'mspec/runner/mspec'
+require 'mspec/runner/example'
+require 'mspec/runner/tag'
+
+describe TagListAction, "#include?" do
+ it "returns true" do
+ TagListAction.new.include?(:anything).should be_true
+ end
+end
+
+describe TagListAction, "#===" do
+ before :each do
+ tag = SpecTag.new "fails:description"
+ MSpec.stub!(:read_tags).and_return([tag])
+ @filter = mock("MatchFilter", :null_object => true)
+ MatchFilter.stub!(:new).and_return(@filter)
+ @action = TagListAction.new
+ @action.load
+ end
+
+ it "returns true if filter === string returns true" do
+ @filter.should_receive(:===).with("str").and_return(true)
+ @action.===("str").should be_true
+ end
+
+ it "returns false if filter === string returns false" do
+ @filter.should_receive(:===).with("str").and_return(false)
+ @action.===("str").should be_false
+ end
+end
+
+describe TagListAction, "#start" do
+ before :each do
+ @stdout = $stdout
+ $stdout = IOStub.new
+ end
+
+ after :each do
+ $stdout = @stdout
+ end
+
+ it "prints a banner for specific tags" do
+ action = TagListAction.new ["fails", "unstable"]
+ action.start
+ $stdout.should == "\nListing specs tagged with 'fails', 'unstable'\n\n"
+ end
+
+ it "prints a banner for all tags" do
+ action = TagListAction.new
+ action.start
+ $stdout.should == "\nListing all tagged specs\n\n"
+ end
+end
+
+describe TagListAction, "#load" do
+ before :each do
+ @t1 = SpecTag.new "fails:I fail"
+ @t2 = SpecTag.new "unstable:I'm unstable"
+ end
+
+ it "creates a MatchFilter for matching tags" do
+ MSpec.should_receive(:read_tags).with(["fails"]).and_return([@t1])
+ MatchFilter.should_receive(:new).with(nil, "I fail")
+ TagListAction.new(["fails"]).load
+ end
+
+ it "creates a MatchFilter for all tags" do
+ MSpec.should_receive(:read_tags).and_return([@t1, @t2])
+ MatchFilter.should_receive(:new).with(nil, "I fail", "I'm unstable")
+ TagListAction.new.load
+ end
+
+ it "does not create a MatchFilter if there are no matching tags" do
+ MSpec.stub!(:read_tags).and_return([])
+ MatchFilter.should_not_receive(:new)
+ TagListAction.new(["fails"]).load
+ end
+end
+
+describe TagListAction, "#after" do
+ before :each do
+ @stdout = $stdout
+ $stdout = IOStub.new
+
+ @state = mock("ExampleState")
+ @state.stub!(:description).and_return("str")
+
+ @action = TagListAction.new
+ end
+
+ after :each do
+ $stdout = @stdout
+ end
+
+ it "prints nothing if the filter does not match" do
+ @action.should_receive(:===).with("str").and_return(false)
+ @action.after(@state)
+ $stdout.should == ""
+ end
+
+ it "prints the example description if the filter matches" do
+ @action.should_receive(:===).with("str").and_return(true)
+ @action.after(@state)
+ $stdout.should == "str\n"
+ end
+end
+
+describe TagListAction, "#register" do
+ before :each do
+ MSpec.stub!(:register)
+ @action = TagListAction.new
+ end
+
+ it "registers itself with MSpec for the :start event" do
+ MSpec.should_receive(:register).with(:start, @action)
+ @action.register
+ end
+
+ it "registers itself with MSpec for the :load event" do
+ MSpec.should_receive(:register).with(:load, @action)
+ @action.register
+ end
+
+ it "registers itself with MSpec for the :after event" do
+ MSpec.should_receive(:register).with(:after, @action)
+ @action.register
+ end
+end
+
+describe TagListAction, "#unregister" do
+ before :each do
+ MSpec.stub!(:unregister)
+ @action = TagListAction.new
+ end
+
+ it "unregisters itself with MSpec for the :start event" do
+ MSpec.should_receive(:unregister).with(:start, @action)
+ @action.unregister
+ end
+
+ it "unregisters itself with MSpec for the :load event" do
+ MSpec.should_receive(:unregister).with(:load, @action)
+ @action.unregister
+ end
+
+ it "unregisters itself with MSpec for the :after event" do
+ MSpec.should_receive(:unregister).with(:after, @action)
+ @action.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/actions/tagpurge_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/actions/tagpurge_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/actions/tagpurge_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,154 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/actions/tagpurge'
+require 'mspec/runner/mspec'
+require 'mspec/runner/example'
+require 'mspec/runner/tag'
+
+describe TagPurgeAction, "#start" do
+ before :each do
+ @stdout = $stdout
+ $stdout = IOStub.new
+ end
+
+ after :each do
+ $stdout = @stdout
+ end
+
+ it "prints a banner" do
+ action = TagPurgeAction.new
+ action.start
+ $stdout.should == "\nRemoving tags not matching any specs\n\n"
+ end
+end
+
+describe TagPurgeAction, "#load" do
+ before :each do
+ @t1 = SpecTag.new "fails:I fail"
+ @t2 = SpecTag.new "unstable:I'm unstable"
+ end
+
+ it "creates a MatchFilter for all tags" do
+ MSpec.should_receive(:read_tags).and_return([@t1, @t2])
+ MatchFilter.should_receive(:new).with(nil, "I fail", "I'm unstable")
+ TagPurgeAction.new.load
+ end
+end
+
+describe TagPurgeAction, "#after" do
+ before :each do
+ @state = mock("ExampleState")
+ @state.stub!(:description).and_return("str")
+
+ @action = TagPurgeAction.new
+ end
+
+ it "does not save the description if the filter does not match" do
+ @action.should_receive(:===).with("str").and_return(false)
+ @action.after @state
+ @action.matching.should == []
+ end
+
+ it "saves the description if the filter matches" do
+ @action.should_receive(:===).with("str").and_return(true)
+ @action.after @state
+ @action.matching.should == ["str"]
+ end
+end
+
+describe TagPurgeAction, "#unload" do
+ before :each do
+ @stdout = $stdout
+ $stdout = IOStub.new
+
+ @t1 = SpecTag.new "fails:I fail"
+ @t2 = SpecTag.new "unstable:I'm unstable"
+ @t3 = SpecTag.new "fails:I'm unstable"
+
+ MSpec.stub!(:read_tags).and_return([@t1, @t2, @t3])
+ MSpec.stub!(:write_tags)
+
+ @state = mock("ExampleState")
+ @state.stub!(:description).and_return("I'm unstable")
+
+ @action = TagPurgeAction.new
+ @action.load
+ @action.after @state
+ end
+
+ after :each do
+ $stdout = @stdout
+ end
+
+ it "does not rewrite any tags if there were no tags for the specs" do
+ MSpec.should_receive(:read_tags).and_return([])
+ MSpec.should_receive(:delete_tags)
+ MSpec.should_not_receive(:write_tags)
+
+ @action.load
+ @action.after @state
+ @action.unload
+
+ $stdout.should == ""
+ end
+
+ it "rewrites tags that were matched" do
+ MSpec.should_receive(:write_tags).with([@t2, @t3])
+ @action.unload
+ end
+
+ it "prints tags that were not matched" do
+ @action.unload
+ $stdout.should == "I fail\n"
+ end
+end
+
+describe TagPurgeAction, "#unload" do
+ before :each do
+ @stdout = $stdout
+ $stdout = IOStub.new
+
+ MSpec.stub!(:read_tags).and_return([])
+
+ @state = mock("ExampleState")
+ @state.stub!(:description).and_return("I'm unstable")
+
+ @action = TagPurgeAction.new
+ @action.load
+ @action.after @state
+ end
+
+ after :each do
+ $stdout = @stdout
+ end
+
+ it "deletes the tag file if no tags were found" do
+ MSpec.should_not_receive(:write_tags)
+ MSpec.should_receive(:delete_tags)
+ @action.unload
+ $stdout.should == ""
+ end
+end
+
+describe TagPurgeAction, "#register" do
+ before :each do
+ MSpec.stub!(:register)
+ @action = TagPurgeAction.new
+ end
+
+ it "registers itself with MSpec for the :unload event" do
+ MSpec.should_receive(:register).with(:unload, @action)
+ @action.register
+ end
+end
+
+describe TagPurgeAction, "#unregister" do
+ before :each do
+ MSpec.stub!(:unregister)
+ @action = TagPurgeAction.new
+ end
+
+ it "unregisters itself with MSpec for the :unload event" do
+ MSpec.should_receive(:unregister).with(:unload, @action)
+ @action.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/actions/tally_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/actions/tally_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/actions/tally_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,347 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/runner/actions/tally'
+require 'mspec/runner/mspec'
+require 'mspec/runner/example'
+
+describe Tally, "#files!" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ it "increments the count returned by #files" do
+ @tally.files! 3
+ @tally.files.should == 3
+ @tally.files!
+ @tally.files.should == 4
+ end
+end
+
+describe Tally, "#examples!" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ it "increments the count returned by #examples" do
+ @tally.examples! 2
+ @tally.examples.should == 2
+ @tally.examples! 2
+ @tally.examples.should == 4
+ end
+end
+
+describe Tally, "#expectations!" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ it "increments the count returned by #expectations" do
+ @tally.expectations!
+ @tally.expectations.should == 1
+ @tally.expectations! 3
+ @tally.expectations.should == 4
+ end
+end
+
+describe Tally, "#failures!" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ it "increments the count returned by #failures" do
+ @tally.failures! 1
+ @tally.failures.should == 1
+ @tally.failures!
+ @tally.failures.should == 2
+ end
+end
+
+describe Tally, "#errors!" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ it "increments the count returned by #errors" do
+ @tally.errors!
+ @tally.errors.should == 1
+ @tally.errors! 2
+ @tally.errors.should == 3
+ end
+end
+
+describe Tally, "#guards!" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ it "increments the count returned by #guards" do
+ @tally.guards!
+ @tally.guards.should == 1
+ @tally.guards! 2
+ @tally.guards.should == 3
+ end
+end
+
+describe Tally, "#file" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ it "returns a formatted string of the number of #files" do
+ @tally.file.should == "0 files"
+ @tally.files!
+ @tally.file.should == "1 file"
+ @tally.files!
+ @tally.file.should == "2 files"
+ end
+end
+
+describe Tally, "#example" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ it "returns a formatted string of the number of #examples" do
+ @tally.example.should == "0 examples"
+ @tally.examples!
+ @tally.example.should == "1 example"
+ @tally.examples!
+ @tally.example.should == "2 examples"
+ end
+end
+
+describe Tally, "#expectation" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ it "returns a formatted string of the number of #expectations" do
+ @tally.expectation.should == "0 expectations"
+ @tally.expectations!
+ @tally.expectation.should == "1 expectation"
+ @tally.expectations!
+ @tally.expectation.should == "2 expectations"
+ end
+end
+
+describe Tally, "#failure" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ it "returns a formatted string of the number of #failures" do
+ @tally.failure.should == "0 failures"
+ @tally.failures!
+ @tally.failure.should == "1 failure"
+ @tally.failures!
+ @tally.failure.should == "2 failures"
+ end
+end
+
+describe Tally, "#error" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ it "returns a formatted string of the number of #errors" do
+ @tally.error.should == "0 errors"
+ @tally.errors!
+ @tally.error.should == "1 error"
+ @tally.errors!
+ @tally.error.should == "2 errors"
+ end
+end
+
+describe Tally, "#guard" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ it "returns a formatted string of the number of #guards" do
+ @tally.guard.should == "0 guards"
+ @tally.guards!
+ @tally.guard.should == "1 guard"
+ @tally.guards!
+ @tally.guard.should == "2 guards"
+ end
+end
+
+describe Tally, "#format" do
+ before :each do
+ @tally = Tally.new
+ end
+
+ after :each do
+ MSpec.clear_modes
+ end
+
+ it "returns a formatted string of counts" do
+ @tally.files!
+ @tally.examples! 2
+ @tally.expectations! 4
+ @tally.errors!
+ @tally.format.should == "1 file, 2 examples, 4 expectations, 0 failures, 1 error"
+ end
+
+ it "includes guards if MSpec is in verify mode" do
+ MSpec.register_mode :verify
+ @tally.files!
+ @tally.examples! 2
+ @tally.expectations! 4
+ @tally.errors!
+ @tally.guards!
+ @tally.format.should ==
+ "1 file, 2 examples, 4 expectations, 0 failures, 1 error, 1 guard"
+ end
+
+ it "includes guards if MSpec is in report mode" do
+ MSpec.register_mode :report
+ @tally.files!
+ @tally.examples! 2
+ @tally.expectations! 4
+ @tally.errors!
+ @tally.guards! 2
+ @tally.format.should ==
+ "1 file, 2 examples, 4 expectations, 0 failures, 1 error, 2 guards"
+ end
+
+ it "includes guards if MSpec is in report_on mode" do
+ MSpec.register_mode :report_on
+ @tally.files!
+ @tally.examples! 2
+ @tally.expectations! 4
+ @tally.errors!
+ @tally.guards! 2
+ @tally.format.should ==
+ "1 file, 2 examples, 4 expectations, 0 failures, 1 error, 2 guards"
+ end
+end
+
+describe TallyAction, "#counter" do
+ before :each do
+ @tally = TallyAction.new
+ @state = ExampleState.new("describe", "it")
+ end
+
+ it "returns the Tally object" do
+ @tally.counter.should be_kind_of(Tally)
+ end
+end
+
+describe TallyAction, "#load" do
+ before :each do
+ @tally = TallyAction.new
+ @state = ExampleState.new("describe", "it")
+ end
+
+ it "increments the count returned by Tally#files" do
+ @tally.load
+ @tally.counter.files.should == 1
+ end
+end
+
+describe TallyAction, "#expectation" do
+ before :each do
+ @tally = TallyAction.new
+ @state = ExampleState.new("describe", "it")
+ end
+
+ it "increments the count returned by Tally#expectations" do
+ @tally.expectation @state
+ @tally.counter.expectations.should == 1
+ end
+end
+
+describe TallyAction, "#example" do
+ before :each do
+ @tally = TallyAction.new
+ @state = ExampleState.new("describe", "it")
+ end
+
+ it "increments counts returned by Tally#examples" do
+ @tally.example @state, nil
+ @tally.counter.examples.should == 1
+ @tally.counter.expectations.should == 0
+ @tally.counter.failures.should == 0
+ @tally.counter.errors.should == 0
+ end
+end
+
+describe TallyAction, "#exception" do
+ before :each do
+ @tally = TallyAction.new
+ @state = ExampleState.new("describe", "it")
+ end
+
+ it "increments counts returned by Tally#failures" do
+ exc = ExceptionState.new nil, nil, ExpectationNotMetError.new("Failed!")
+ @tally.exception exc
+ @tally.counter.examples.should == 0
+ @tally.counter.expectations.should == 0
+ @tally.counter.failures.should == 1
+ @tally.counter.errors.should == 0
+ end
+end
+
+describe TallyAction, "#exception" do
+ before :each do
+ @tally = TallyAction.new
+ @state = ExampleState.new("describe", "it")
+ end
+
+ it "increments counts returned by Tally#errors" do
+ exc = ExceptionState.new nil, nil, Exception.new("Error!")
+ @tally.exception exc
+ @tally.counter.examples.should == 0
+ @tally.counter.expectations.should == 0
+ @tally.counter.failures.should == 0
+ @tally.counter.errors.should == 1
+ end
+end
+
+describe TallyAction, "#format" do
+ before :each do
+ @tally = TallyAction.new
+ @state = ExampleState.new("describe", "it")
+ end
+
+ it "returns a readable string of counts" do
+ @tally.load
+ @tally.example @state, nil
+ @tally.expectation @state
+ @tally.expectation @state
+ exc = ExceptionState.new nil, nil, ExpectationNotMetError.new("Failed!")
+ @tally.exception exc
+ @tally.format.should == "1 file, 1 example, 2 expectations, 1 failure, 0 errors"
+ end
+end
+
+describe TallyAction, "#register" do
+ before :each do
+ @tally = TallyAction.new
+ @state = ExampleState.new("describe", "it")
+ end
+
+ it "registers itself with MSpec for appropriate actions" do
+ MSpec.should_receive(:register).with(:load, @tally)
+ MSpec.should_receive(:register).with(:example, @tally)
+ MSpec.should_receive(:register).with(:exception, @tally)
+ MSpec.should_receive(:register).with(:expectation, @tally)
+ @tally.register
+ end
+end
+
+describe TallyAction, "#unregister" do
+ before :each do
+ @tally = TallyAction.new
+ @state = ExampleState.new("describe", "it")
+ end
+
+ it "unregisters itself with MSpec for appropriate actions" do
+ MSpec.should_receive(:unregister).with(:load, @tally)
+ MSpec.should_receive(:unregister).with(:exception, @tally)
+ MSpec.should_receive(:unregister).with(:example, @tally)
+ MSpec.should_receive(:unregister).with(:expectation, @tally)
+ @tally.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/actions/timer_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/actions/timer_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/actions/timer_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,42 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/actions/timer'
+require 'mspec/runner/mspec'
+require 'time'
+
+describe TimerAction do
+ before :each do
+ @timer = TimerAction.new
+ end
+
+ it "responds to #start by recording the current time" do
+ Time.should_receive(:now)
+ @timer.start
+ end
+
+ it "responds to #finish by recording the current time" do
+ Time.should_receive(:now)
+ @timer.finish
+ end
+
+ it "responds to #elapsed by returning the difference between stop and start" do
+ Time.stub!(:now).and_return(Time.parse('10/18/2007 5:43:18'))
+ @timer.start
+ Time.stub!(:now).and_return(Time.parse('10/18/2007 5:43:51'))
+ @timer.finish
+ @timer.elapsed.should == 33
+ end
+
+ it "responds to #format by returning a readable string of elapsed time" do
+ Time.stub!(:now).and_return(Time.parse('10/18/2007 5:43:18'))
+ @timer.start
+ Time.stub!(:now).and_return(Time.parse('10/18/2007 5:43:51'))
+ @timer.finish
+ @timer.format.should == "Finished in 33.000000 seconds"
+ end
+
+ it "responds to #register by registering itself with MSpec for appropriate actions" do
+ MSpec.should_receive(:register).with(:start, @timer)
+ MSpec.should_receive(:register).with(:finish, @timer)
+ @timer.register
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/context_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/context_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/context_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,993 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/matchers/base'
+require 'mspec/runner/mspec'
+require 'mspec/mocks/mock'
+require 'mspec/runner/context'
+require 'mspec/runner/example'
+
+describe ContextState, "#describe" do
+ before :each do
+ @state = ContextState.new "C#m"
+ @proc = lambda { ScratchPad.record :a }
+ ScratchPad.clear
+ end
+
+ it "evaluates the passed block" do
+ @state.describe(&@proc)
+ ScratchPad.recorded.should == :a
+ end
+
+ it "evaluates the passed block via #protect" do
+ @state.should_receive(:protect).with("C#m", @proc, false)
+ @state.describe(&@proc)
+ end
+
+ it "registers #parent as the current MSpec ContextState" do
+ parent = ContextState.new ""
+ @state.parent = parent
+ MSpec.should_receive(:register_current).with(parent)
+ @state.describe { }
+ end
+
+ it "registers self with MSpec when #shared? is true" do
+ state = ContextState.new "something shared", :shared => true
+ MSpec.should_receive(:register_shared).with(state)
+ state.describe { }
+ end
+end
+
+describe ContextState, "#shared?" do
+ it "returns false when the ContextState is not shared" do
+ ContextState.new("").shared?.should be_false
+ end
+
+ it "returns true when the ContextState is shared" do
+ ContextState.new("", {:shared => true}).shared?.should be_true
+ end
+end
+
+describe ContextState, "#to_s" do
+ it "returns a description string for self when passed a Module" do
+ ContextState.new(Object).to_s.should == "Object"
+ end
+
+ it "returns a description string for self when passed a String" do
+ ContextState.new("SomeClass").to_s.should == "SomeClass"
+ end
+
+ it "returns a description string for self when passed a Module, String" do
+ ContextState.new(Object, "when empty").to_s.should == "Object when empty"
+ end
+
+ it "returns a description string for self when passed a Module and String beginning with '#'" do
+ ContextState.new(Object, "#to_s").to_s.should == "Object#to_s"
+ end
+
+ it "returns a description string for self when passed a Module and String beginning with '.'" do
+ ContextState.new(Object, ".to_s").to_s.should == "Object.to_s"
+ end
+
+ it "returns a description string for self when passed a Module and String beginning with '::'" do
+ ContextState.new(Object, "::to_s").to_s.should == "Object::to_s"
+ end
+end
+
+describe ContextState, "#description" do
+ before :each do
+ @state = ContextState.new "when empty"
+ @parent = ContextState.new "Toplevel"
+ end
+
+ it "returns a composite description string from self and all parents" do
+ @parent.description.should == "Toplevel"
+ @state.description.should == "when empty"
+ @state.parent = @parent
+ @state.description.should == "Toplevel when empty"
+ end
+end
+
+describe ContextState, "#it" do
+ before :each do
+ @state = ContextState.new ""
+ @proc = lambda { }
+
+ @ex = ExampleState.new("", "", &@proc)
+ end
+
+ it "creates an ExampleState instance for the block" do
+ ExampleState.should_receive(:new).with(@state, "it", @proc).and_return(@ex)
+ @state.describe(&@proc)
+ @state.it("it", &@proc)
+ end
+
+ it "calls registered :add actions" do
+ ExampleState.should_receive(:new).with(@state, "it", @proc).and_return(@ex)
+
+ add_action = mock("add")
+ add_action.should_receive(:add).with(@ex).and_return { ScratchPad.record :add }
+ MSpec.register :add, add_action
+
+ @state.it("it", &@proc)
+ ScratchPad.recorded.should == :add
+ MSpec.unregister :add, add_action
+ end
+end
+
+describe ContextState, "#examples" do
+ before :each do
+ @state = ContextState.new ""
+ end
+
+ it "returns a list of all examples in this ContextState" do
+ @state.it("first") { }
+ @state.it("second") { }
+ @state.examples.size.should == 2
+ end
+end
+
+describe ContextState, "#before" do
+ before :each do
+ @state = ContextState.new ""
+ @proc = lambda { }
+ end
+
+ it "records the block for :each" do
+ @state.before(:each, &@proc)
+ @state.before(:each).should == [@proc]
+ end
+
+ it "records the block for :all" do
+ @state.before(:all, &@proc)
+ @state.before(:all).should == [@proc]
+ end
+end
+
+describe ContextState, "#after" do
+ before :each do
+ @state = ContextState.new ""
+ @proc = lambda { }
+ end
+
+ it "records the block for :each" do
+ @state.after(:each, &@proc)
+ @state.after(:each).should == [@proc]
+ end
+
+ it "records the block for :all" do
+ @state.after(:all, &@proc)
+ @state.after(:all).should == [@proc]
+ end
+end
+
+describe ContextState, "#pre" do
+ before :each do
+ @a = lambda { }
+ @b = lambda { }
+ @c = lambda { }
+
+ parent = ContextState.new ""
+ parent.before(:each, &@c)
+ parent.before(:all, &@c)
+
+ @state = ContextState.new ""
+ @state.parent = parent
+ end
+
+ it "returns before(:each) actions in the order they were defined" do
+ @state.before(:each, &@a)
+ @state.before(:each, &@b)
+ @state.pre(:each).should == [@c, @a, @b]
+ end
+
+ it "returns before(:all) actions in the order they were defined" do
+ @state.before(:all, &@a)
+ @state.before(:all, &@b)
+ @state.pre(:all).should == [@c, @a, @b]
+ end
+end
+
+describe ContextState, "#post" do
+ before :each do
+ @a = lambda { }
+ @b = lambda { }
+ @c = lambda { }
+
+ parent = ContextState.new ""
+ parent.after(:each, &@c)
+ parent.after(:all, &@c)
+
+ @state = ContextState.new ""
+ @state.parent = parent
+ end
+
+ it "returns after(:each) actions in the reverse order they were defined" do
+ @state.after(:each, &@a)
+ @state.after(:each, &@b)
+ @state.post(:each).should == [@b, @a, @c]
+ end
+
+ it "returns after(:all) actions in the reverse order they were defined" do
+ @state.after(:all, &@a)
+ @state.after(:all, &@b)
+ @state.post(:all).should == [@b, @a, @c]
+ end
+end
+
+describe ContextState, "#protect" do
+ before :each do
+ ScratchPad.record []
+ @a = lambda { ScratchPad << :a }
+ @b = lambda { ScratchPad << :b }
+ @c = lambda { raise Exception, "Fail!" }
+ end
+
+ it "returns true and does execute any blocks if check and MSpec.mode?(:pretend) are true" do
+ MSpec.should_receive(:mode?).with(:pretend).and_return(true)
+ ContextState.new("").protect("message", [@a, @b]).should be_true
+ ScratchPad.recorded.should == []
+ end
+
+ it "executes the blocks if MSpec.mode?(:pretend) is false" do
+ MSpec.should_receive(:mode?).with(:pretend).and_return(false)
+ ContextState.new("").protect("message", [@a, @b])
+ ScratchPad.recorded.should == [:a, :b]
+ end
+
+ it "executes the blocks if check is false" do
+ ContextState.new("").protect("message", [@a, @b], false)
+ ScratchPad.recorded.should == [:a, :b]
+ end
+
+ it "returns true if none of the blocks raise an exception" do
+ ContextState.new("").protect("message", [@a, @b]).should be_true
+ end
+
+ it "returns false if any of the blocks raise an exception" do
+ ContextState.new("").protect("message", [@a, @c, @b]).should be_false
+ end
+end
+
+describe ContextState, "#parent=" do
+ before :each do
+ @state = ContextState.new ""
+ @parent = mock("describe")
+ @parent.stub!(:parent).and_return(nil)
+ @parent.stub!(:child)
+ end
+
+ it "does not set self as a child of parent if shared" do
+ @parent.should_not_receive(:child)
+ state = ContextState.new "", :shared => true
+ state.parent = @parent
+ end
+
+ it "sets self as a child of parent" do
+ @parent.should_receive(:child).with(@state)
+ @state.parent = @parent
+ end
+
+ it "creates the list of parents" do
+ @state.parent = @parent
+ @state.parents.should == [@parent, @state]
+ end
+end
+
+describe ContextState, "#parent" do
+ before :each do
+ @state = ContextState.new ""
+ @parent = mock("describe")
+ @parent.stub!(:parent).and_return(nil)
+ @parent.stub!(:child)
+ end
+
+ it "returns nil if parent has not been set" do
+ @state.parent.should be_nil
+ end
+
+ it "returns the parent" do
+ @state.parent = @parent
+ @state.parent.should == @parent
+ end
+end
+
+describe ContextState, "#parents" do
+ before :each do
+ @first = ContextState.new ""
+ @second = ContextState.new ""
+ @parent = mock("describe")
+ @parent.stub!(:parent).and_return(nil)
+ @parent.stub!(:child)
+ end
+
+ it "returns a list of all enclosing ContextState instances" do
+ @first.parent = @parent
+ @second.parent = @first
+ @second.parents.should == [@parent, @first, @second]
+ end
+end
+
+describe ContextState, "#child" do
+ before :each do
+ @first = ContextState.new ""
+ @second = ContextState.new ""
+ @parent = mock("describe")
+ @parent.stub!(:parent).and_return(nil)
+ @parent.stub!(:child)
+ end
+
+ it "adds the ContextState to the list of contained ContextStates" do
+ @first.child @second
+ @first.children.should == [@second]
+ end
+end
+
+describe ContextState, "#children" do
+ before :each do
+ @parent = ContextState.new ""
+ @first = ContextState.new ""
+ @second = ContextState.new ""
+ end
+
+ it "returns the list of directly contained ContextStates" do
+ @first.parent = @parent
+ @second.parent = @first
+ @parent.children.should == [@first]
+ @first.children.should == [@second]
+ end
+end
+
+describe ContextState, "#state" do
+ before :each do
+ MSpec.store :before, []
+ MSpec.store :after, []
+
+ @state = ContextState.new ""
+ end
+
+ it "returns nil if no spec is being executed" do
+ @state.state.should == nil
+ end
+
+ it "returns a ExampleState instance if an example is being executed" do
+ ScratchPad.record @state
+ @state.describe { }
+ @state.it("") { ScratchPad.record ScratchPad.recorded.state }
+ @state.process
+ @state.state.should == nil
+ ScratchPad.recorded.should be_kind_of(ExampleState)
+ end
+end
+
+describe ContextState, "#process" do
+ before :each do
+ MSpec.store :before, []
+ MSpec.store :after, []
+ MSpec.stub!(:register_current)
+
+ @state = ContextState.new ""
+ @state.describe { }
+
+ @a = lambda { ScratchPad << :a }
+ @b = lambda { ScratchPad << :b }
+ ScratchPad.record []
+ end
+
+ it "calls each before(:all) block" do
+ @state.before(:all, &@a)
+ @state.before(:all, &@b)
+ @state.it("") { }
+ @state.process
+ ScratchPad.recorded.should == [:a, :b]
+ end
+
+ it "calls each after(:all) block" do
+ @state.after(:all, &@a)
+ @state.after(:all, &@b)
+ @state.it("") { }
+ @state.process
+ ScratchPad.recorded.should == [:b, :a]
+ end
+
+ it "calls each it block" do
+ @state.it("one", &@a)
+ @state.it("two", &@b)
+ @state.process
+ ScratchPad.recorded.should == [:a, :b]
+ end
+
+ it "does not call the #it block if #filtered? returns true" do
+ @state.it("one", &@a)
+ @state.it("two", &@b)
+ @state.examples.first.stub!(:filtered?).and_return(true)
+ @state.process
+ ScratchPad.recorded.should == [:b]
+ end
+
+ it "calls each before(:each) block" do
+ @state.before(:each, &@a)
+ @state.before(:each, &@b)
+ @state.it("") { }
+ @state.process
+ ScratchPad.recorded.should == [:a, :b]
+ end
+
+ it "calls each after(:each) block" do
+ @state.after(:each, &@a)
+ @state.after(:each, &@b)
+ @state.it("") { }
+ @state.process
+ ScratchPad.recorded.should == [:b, :a]
+ end
+
+ it "calls Mock.cleanup for each it block" do
+ @state.it("") { }
+ @state.it("") { }
+ Mock.should_receive(:cleanup).twice
+ @state.process
+ end
+
+ it "calls Mock.verify_count for each it block" do
+ @state.it("") { }
+ @state.it("") { }
+ Mock.should_receive(:verify_count).twice
+ @state.process
+ end
+
+ it "calls the describe block" do
+ ScratchPad.record []
+ @state.describe { ScratchPad << :a }
+ @state.process
+ ScratchPad.recorded.should == [:a]
+ end
+
+ it "creates a new ExampleState instance for each example" do
+ ScratchPad.record @state
+ @state.describe { }
+ @state.it("it") { ScratchPad.record ScratchPad.recorded.state }
+ @state.process
+ ScratchPad.recorded.should be_kind_of(ExampleState)
+ end
+
+ it "clears the expectations flag before evaluating the #it block" do
+ MSpec.clear_expectations
+ MSpec.should_receive(:clear_expectations)
+ @state.it("it") { ScratchPad.record MSpec.expectation? }
+ @state.process
+ ScratchPad.recorded.should be_false
+ end
+
+ it "shuffles the spec list if MSpec.randomize? is true" do
+ MSpec.randomize
+ MSpec.should_receive(:shuffle)
+ @state.it("") { }
+ @state.process
+ MSpec.randomize false
+ end
+
+ it "sets the current MSpec ContextState" do
+ MSpec.should_receive(:register_current).with(@state)
+ @state.process
+ end
+
+ it "resets the current MSpec ContextState to nil when there are examples" do
+ MSpec.should_receive(:register_current).with(nil)
+ @state.it("") { }
+ @state.process
+ end
+
+ it "resets the current MSpec ContextState to nil when there are no examples" do
+ MSpec.should_receive(:register_current).with(nil)
+ @state.process
+ end
+
+ it "call #process on children when there are examples" do
+ child = ContextState.new ""
+ child.should_receive(:process)
+ @state.child child
+ @state.it("") { }
+ @state.process
+ end
+
+ it "call #process on children when there are no examples" do
+ child = ContextState.new ""
+ child.should_receive(:process)
+ @state.child child
+ @state.process
+ end
+end
+
+describe ContextState, "#process" do
+ before :each do
+ MSpec.store :exception, []
+
+ @state = ContextState.new ""
+ @state.describe { }
+
+ action = mock("action")
+ def action.exception(exc)
+ ScratchPad.record :exception if exc.exception.is_a? ExpectationNotFoundError
+ end
+ MSpec.register :exception, action
+
+ MSpec.clear_expectations
+ ScratchPad.clear
+ end
+
+ after :each do
+ MSpec.store :exception, nil
+ end
+
+ it "raises an ExpectationNotFoundError if an #it block does not contain an expectation" do
+ @state.it("it") { }
+ @state.process
+ ScratchPad.recorded.should == :exception
+ end
+
+ it "does not raise an ExpectationNotFoundError if an #it block does contain an expectation" do
+ @state.it("it") { MSpec.expectation }
+ @state.process
+ ScratchPad.recorded.should be_nil
+ end
+
+ it "does not raise an ExpectationNotFoundError if the #it block causes a failure" do
+ @state.it("it") { raise Exception, "Failed!" }
+ @state.process
+ ScratchPad.recorded.should be_nil
+ end
+end
+
+describe ContextState, "#process" do
+ before :each do
+ MSpec.store :example, []
+
+ @state = ContextState.new ""
+ @state.describe { }
+
+ example = mock("example")
+ def example.example(state, spec)
+ ScratchPad << state << spec
+ end
+ MSpec.register :example, example
+
+ ScratchPad.record []
+ end
+
+ after :each do
+ MSpec.store :example, nil
+ end
+
+ it "calls registered :example actions with the current ExampleState and block" do
+ @state.it("") { MSpec.expectation }
+ @state.process
+
+ ScratchPad.recorded.first.should be_kind_of(ExampleState)
+ ScratchPad.recorded.last.should be_kind_of(Proc)
+ end
+
+ it "does not call registered example actions if the example has no block" do
+ @state.it("empty example")
+ @state.process
+ ScratchPad.recorded.should == []
+ end
+end
+
+describe ContextState, "#process" do
+ before :each do
+ MSpec.store :before, []
+ MSpec.store :after, []
+
+ @state = ContextState.new ""
+ @state.describe { }
+ @state.it("") { MSpec.expectation }
+ end
+
+ after :each do
+ MSpec.store :before, nil
+ MSpec.store :after, nil
+ end
+
+ it "calls registered :before actions with the current ExampleState instance" do
+ before = mock("before")
+ before.should_receive(:before).and_return {
+ ScratchPad.record :before
+ @spec_state = @state.state
+ }
+ MSpec.register :before, before
+ @state.process
+ ScratchPad.recorded.should == :before
+ @spec_state.should be_kind_of(ExampleState)
+ end
+
+ it "calls registered :after actions with the current ExampleState instance" do
+ after = mock("after")
+ after.should_receive(:after).and_return {
+ ScratchPad.record :after
+ @spec_state = @state.state
+ }
+ MSpec.register :after, after
+ @state.process
+ ScratchPad.recorded.should == :after
+ @spec_state.should be_kind_of(ExampleState)
+ end
+end
+
+describe ContextState, "#process" do
+ before :each do
+ MSpec.store :enter, []
+ MSpec.store :leave, []
+
+ @state = ContextState.new "C#m"
+ @state.describe { }
+ @state.it("") { MSpec.expectation }
+ end
+
+ after :each do
+ MSpec.store :enter, nil
+ MSpec.store :leave, nil
+ end
+
+ it "calls registered :enter actions with the current #describe string" do
+ enter = mock("enter")
+ enter.should_receive(:enter).with("C#m").and_return { ScratchPad.record :enter }
+ MSpec.register :enter, enter
+ @state.process
+ ScratchPad.recorded.should == :enter
+ end
+
+ it "calls registered :leave actions" do
+ leave = mock("leave")
+ leave.should_receive(:leave).and_return { ScratchPad.record :leave }
+ MSpec.register :leave, leave
+ @state.process
+ ScratchPad.recorded.should == :leave
+ end
+end
+
+describe ContextState, "#process when an exception is raised in before(:all)" do
+ before :each do
+ MSpec.store :before, []
+ MSpec.store :after, []
+
+ @state = ContextState.new ""
+ @state.describe { }
+
+ @a = lambda { ScratchPad << :a }
+ @b = lambda { ScratchPad << :b }
+ ScratchPad.record []
+
+ @state.before(:all) { raise Exception, "Fail!" }
+ end
+
+ after :each do
+ MSpec.store :before, nil
+ MSpec.store :after, nil
+ end
+
+ it "does not call before(:each)" do
+ @state.before(:each, &@a)
+ @state.it("") { }
+ @state.process
+ ScratchPad.recorded.should == []
+ end
+
+ it "does not call the it block" do
+ @state.it("one", &@a)
+ @state.process
+ ScratchPad.recorded.should == []
+ end
+
+ it "does not call after(:each)" do
+ @state.after(:each, &@a)
+ @state.it("") { }
+ @state.process
+ ScratchPad.recorded.should == []
+ end
+
+ it "does not call after(:each)" do
+ @state.after(:all, &@a)
+ @state.it("") { }
+ @state.process
+ ScratchPad.recorded.should == []
+ end
+
+ it "does not call Mock.verify_count" do
+ @state.it("") { }
+ Mock.should_not_receive(:verify_count)
+ @state.process
+ end
+
+ it "calls Mock.cleanup" do
+ @state.it("") { }
+ Mock.should_receive(:cleanup)
+ @state.process
+ end
+end
+
+describe ContextState, "#process when an exception is raised in before(:each)" do
+ before :each do
+ MSpec.store :before, []
+ MSpec.store :after, []
+
+ @state = ContextState.new ""
+ @state.describe { }
+
+ @a = lambda { ScratchPad << :a }
+ @b = lambda { ScratchPad << :b }
+ ScratchPad.record []
+
+ @state.before(:each) { raise Exception, "Fail!" }
+ end
+
+ after :each do
+ MSpec.store :before, nil
+ MSpec.store :after, nil
+ end
+
+ it "does not call the it block" do
+ @state.it("one", &@a)
+ @state.process
+ ScratchPad.recorded.should == []
+ end
+
+ it "does not call after(:each)" do
+ @state.after(:each, &@a)
+ @state.it("") { }
+ @state.process
+ ScratchPad.recorded.should == []
+ end
+
+ it "does not call Mock.verify_count" do
+ @state.it("") { }
+ Mock.should_not_receive(:verify_count)
+ @state.process
+ end
+end
+
+describe ContextState, "#process in pretend mode" do
+ before :all do
+ MSpec.register_mode :pretend
+ end
+
+ after :all do
+ MSpec.register_mode nil
+ end
+
+ before :each do
+ ScratchPad.clear
+ MSpec.store :before, []
+ MSpec.store :after, []
+
+ @state = ContextState.new ""
+ @state.describe { }
+ @state.it("") { }
+ end
+
+ after :each do
+ MSpec.store :before, nil
+ MSpec.store :after, nil
+ end
+
+ it "calls registered :before actions with the current ExampleState instance" do
+ before = mock("before")
+ before.should_receive(:before).and_return {
+ ScratchPad.record :before
+ @spec_state = @state.state
+ }
+ MSpec.register :before, before
+ @state.process
+ ScratchPad.recorded.should == :before
+ @spec_state.should be_kind_of(ExampleState)
+ end
+
+ it "calls registered :after actions with the current ExampleState instance" do
+ after = mock("after")
+ after.should_receive(:after).and_return {
+ ScratchPad.record :after
+ @spec_state = @state.state
+ }
+ MSpec.register :after, after
+ @state.process
+ ScratchPad.recorded.should == :after
+ @spec_state.should be_kind_of(ExampleState)
+ end
+end
+
+describe ContextState, "#process in pretend mode" do
+ before :all do
+ MSpec.register_mode :pretend
+ end
+
+ after :all do
+ MSpec.register_mode nil
+ end
+
+ before :each do
+ MSpec.store :before, []
+ MSpec.store :after, []
+
+ @state = ContextState.new ""
+ @state.describe { }
+
+ @a = lambda { ScratchPad << :a }
+ @b = lambda { ScratchPad << :b }
+ ScratchPad.record []
+ end
+
+ it "calls the describe block" do
+ ScratchPad.record []
+ @state.describe { ScratchPad << :a }
+ @state.process
+ ScratchPad.recorded.should == [:a]
+ end
+
+ it "does not call any before(:all) block" do
+ @state.before(:all, &@a)
+ @state.before(:all, &@b)
+ @state.it("") { }
+ @state.process
+ ScratchPad.recorded.should == []
+ end
+
+ it "does not call any after(:all) block" do
+ @state.after(:all, &@a)
+ @state.after(:all, &@b)
+ @state.it("") { }
+ @state.process
+ ScratchPad.recorded.should == []
+ end
+
+ it "does not call any it block" do
+ @state.it("one", &@a)
+ @state.it("two", &@b)
+ @state.process
+ ScratchPad.recorded.should == []
+ end
+
+ it "does not call any before(:each) block" do
+ @state.before(:each, &@a)
+ @state.before(:each, &@b)
+ @state.it("") { }
+ @state.process
+ ScratchPad.recorded.should == []
+ end
+
+ it "does not call any after(:each) block" do
+ @state.after(:each, &@a)
+ @state.after(:each, &@b)
+ @state.it("") { }
+ @state.process
+ ScratchPad.recorded.should == []
+ end
+
+ it "does not call Mock.cleanup" do
+ @state.it("") { }
+ @state.it("") { }
+ Mock.should_not_receive(:cleanup)
+ @state.process
+ end
+end
+
+describe ContextState, "#process in pretend mode" do
+ before :all do
+ MSpec.register_mode :pretend
+ end
+
+ after :all do
+ MSpec.register_mode nil
+ end
+
+ before :each do
+ MSpec.store :enter, []
+ MSpec.store :leave, []
+
+ @state = ContextState.new ""
+ @state.describe { }
+ @state.it("") { }
+ end
+
+ after :each do
+ MSpec.store :enter, nil
+ MSpec.store :leave, nil
+ end
+
+ it "calls registered :enter actions with the current #describe string" do
+ enter = mock("enter")
+ enter.should_receive(:enter).and_return { ScratchPad.record :enter }
+ MSpec.register :enter, enter
+ @state.process
+ ScratchPad.recorded.should == :enter
+ end
+
+ it "calls registered :leave actions" do
+ leave = mock("leave")
+ leave.should_receive(:leave).and_return { ScratchPad.record :leave }
+ MSpec.register :leave, leave
+ @state.process
+ ScratchPad.recorded.should == :leave
+ end
+end
+
+describe ContextState, "#it_should_behave_like" do
+ before :each do
+ @shared = ContextState.new("", :shared => true)
+ MSpec.stub!(:retrieve_shared).and_return(@shared)
+
+ @state = ContextState.new ""
+ @a = lambda { }
+ @b = lambda { }
+ end
+
+ it "raises an Exception if unable to find the shared ContextState" do
+ MSpec.should_receive(:retrieve_shared).and_return(nil)
+ lambda { @state.it_should_behave_like "this" }.should raise_error(Exception)
+ end
+
+ it "adds examples from the shared ContextState" do
+ @shared.it "some", &@a
+ @shared.it "thing", &@b
+ @state.it_should_behave_like ""
+ @state.examples.should include(*@shared.examples)
+ end
+
+ it "sets the containing ContextState for the examples" do
+ @shared.it "some", &@a
+ @shared.it "thing", &@b
+ @shared.examples.each { |ex| ex.should_receive(:context=).with(@state) }
+ @state.it_should_behave_like ""
+ end
+
+ it "adds before(:all) blocks from the shared ContextState" do
+ @shared.before :all, &@a
+ @shared.before :all, &@b
+ @state.it_should_behave_like ""
+ @state.before(:all).should include(*@shared.before(:all))
+ end
+
+ it "adds before(:each) blocks from the shared ContextState" do
+ @shared.before :each, &@a
+ @shared.before :each, &@b
+ @state.it_should_behave_like ""
+ @state.before(:each).should include(*@shared.before(:each))
+ end
+
+ it "adds after(:each) blocks from the shared ContextState" do
+ @shared.after :each, &@a
+ @shared.after :each, &@b
+ @state.it_should_behave_like ""
+ @state.after(:each).should include(*@shared.after(:each))
+ end
+
+ it "adds after(:all) blocks from the shared ContextState" do
+ @shared.after :all, &@a
+ @shared.after :all, &@b
+ @state.it_should_behave_like ""
+ @state.after(:all).should include(*@shared.after(:all))
+ end
+end
+
+describe ContextState, "#filter_examples" do
+ before :each do
+ @state = ContextState.new ""
+ @state.it("one") { }
+ @state.it("two") { }
+ end
+
+ it "removes examples that are filtered" do
+ @state.examples.first.stub!(:filtered?).and_return(true)
+ @state.examples.size.should == 2
+ @state.filter_examples
+ @state.examples.size.should == 1
+ end
+
+ it "returns true if there are remaining examples to evaluate" do
+ @state.examples.first.stub!(:filtered?).and_return(true)
+ @state.filter_examples.should be_true
+ end
+
+ it "returns false if there are no remaining examples to evaluate" do
+ @state.examples.first.stub!(:filtered?).and_return(true)
+ @state.examples.last.stub!(:filtered?).and_return(true)
+ @state.filter_examples.should be_false
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/example_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/example_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/example_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,112 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/matchers/base'
+require 'mspec/runner/mspec'
+require 'mspec/mocks/mock'
+require 'mspec/runner/example'
+
+describe ExampleState do
+ it "is initialized with the ContextState, #it string, and #it block" do
+ prc = lambda { }
+ context = ContextState.new ""
+ ExampleState.new(context, "does", prc).should be_kind_of(ExampleState)
+ end
+end
+
+describe ExampleState, "#describe" do
+ before :each do
+ @context = ContextState.new Object, "#to_s"
+ @state = ExampleState.new @context, "it"
+ end
+
+ it "returns the ContextState#description" do
+ @state.describe.should == @context.description
+ end
+end
+
+describe ExampleState, "#it" do
+ before :each do
+ @state = ExampleState.new ContextState.new("describe"), "it"
+ end
+
+ it "returns the argument to the #it block" do
+ @state.it.should == "it"
+ end
+end
+
+describe ExampleState, "#context=" do
+ before :each do
+ @state = ExampleState.new ContextState.new("describe"), "it"
+ @context = ContextState.new "New#context"
+ end
+
+ it "sets the containing ContextState" do
+ @state.context = @context
+ @state.context.should == @context
+ end
+
+ it "resets the description" do
+ @state.description.should == "describe it"
+ @state.context = @context
+ @state.description.should == "New#context it"
+ end
+end
+
+describe ExampleState, "#example" do
+ before :each do
+ @proc = lambda { }
+ @state = ExampleState.new ContextState.new("describe"), "it", @proc
+ end
+
+ it "returns the #it block" do
+ @state.example.should == @proc
+ end
+end
+
+describe ExampleState, "#filtered?" do
+ before :each do
+ MSpec.store :include, nil
+ MSpec.store :exclude, nil
+
+ @state = ExampleState.new ContextState.new("describe"), "it"
+ @filter = mock("filter")
+ end
+
+ it "returns false if MSpec include filters list is empty" do
+ @state.filtered?.should == false
+ end
+
+ it "returns false if MSpec include filters match this spec" do
+ @filter.should_receive(:===).and_return(true)
+ MSpec.register :include, @filter
+ @state.filtered?.should == false
+ end
+
+ it "returns true if MSpec include filters do not match this spec" do
+ @filter.should_receive(:===).and_return(false)
+ MSpec.register :include, @filter
+ @state.filtered?.should == true
+ end
+
+ it "returns false if MSpec exclude filters list is empty" do
+ @state.filtered?.should == false
+ end
+
+ it "returns false if MSpec exclude filters do not match this spec" do
+ @filter.should_receive(:===).and_return(false)
+ MSpec.register :exclude, @filter
+ @state.filtered?.should == false
+ end
+
+ it "returns true if MSpec exclude filters match this spec" do
+ @filter.should_receive(:===).and_return(true)
+ MSpec.register :exclude, @filter
+ @state.filtered?.should == true
+ end
+
+ it "returns true if MSpec include and exclude filters match this spec" do
+ @filter.should_receive(:===).twice.and_return(true)
+ MSpec.register :include, @filter
+ MSpec.register :exclude, @filter
+ @state.filtered?.should == true
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/exception_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/exception_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/exception_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,134 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/expectations/expectations'
+require 'mspec/runner/example'
+require 'mspec/runner/exception'
+
+describe ExceptionState, "#initialize" do
+ it "takes a state, location (e.g. before :each), and exception" do
+ context = ContextState.new "Class#method"
+ state = ExampleState.new context, "does something"
+ exc = Exception.new "Fail!"
+ ExceptionState.new(state, "location", exc).should be_kind_of(ExceptionState)
+ end
+end
+
+describe ExceptionState, "#description" do
+ before :each do
+ context = ContextState.new "Class#method"
+ @state = ExampleState.new context, "does something"
+ end
+
+ it "returns the state description if state was not nil" do
+ exc = ExceptionState.new(@state, nil, nil)
+ exc.description.should == "Class#method does something"
+ end
+
+ it "returns the location if it is not nil and description is nil" do
+ exc = ExceptionState.new(nil, "location", nil)
+ exc.description.should == "An exception occurred during: location"
+ end
+
+ it "returns both description and location if neither are nil" do
+ exc = ExceptionState.new(@state, "location", nil)
+ exc.description.should == "An exception occurred during: location\nClass#method does something"
+ end
+end
+
+describe ExceptionState, "#describe" do
+ before :each do
+ context = ContextState.new "Class#method"
+ @state = ExampleState.new context, "does something"
+ end
+
+ it "returns the ExampleState#describe string if created with a non-nil state" do
+ ExceptionState.new(@state, nil, nil).describe.should == @state.describe
+ end
+
+ it "returns an empty string if created with a nil state" do
+ ExceptionState.new(nil, nil, nil).describe.should == ""
+ end
+end
+
+describe ExceptionState, "#it" do
+ before :each do
+ context = ContextState.new "Class#method"
+ @state = ExampleState.new context, "does something"
+ end
+
+ it "returns the ExampleState#it string if created with a non-nil state" do
+ ExceptionState.new(@state, nil, nil).it.should == @state.it
+ end
+
+ it "returns an empty string if created with a nil state" do
+ ExceptionState.new(nil, nil, nil).it.should == ""
+ end
+end
+
+describe ExceptionState, "#failure?" do
+ before :each do
+ @state = ExampleState.new ContextState.new("C#m"), "works"
+ end
+
+ it "returns true if the exception is an ExpectationNotMetError" do
+ exc = ExceptionState.new @state, "", ExpectationNotMetError.new("Fail!")
+ exc.failure?.should be_true
+ end
+
+ it "returns true if the exception is an ExpectationNotFoundError" do
+ exc = ExceptionState.new @state, "", ExpectationNotFoundError.new("Fail!")
+ exc.failure?.should be_true
+ end
+
+ it "returns false if the exception is not an ExpectationNotMetError or an ExpectationNotFoundError" do
+ exc = ExceptionState.new @state, "", Exception.new("Fail!")
+ exc.failure?.should be_false
+ end
+end
+
+describe ExceptionState, "#message" do
+ it "returns <No message> if the exception message is empty" do
+ exc = ExceptionState.new @state, "", Exception.new("")
+ exc.message.should == "<No message>"
+ end
+
+ it "returns the message without exception class when the exception is an ExpectationNotMetError" do
+ exc = ExceptionState.new @state, "", ExpectationNotMetError.new("Fail!")
+ exc.message.should == "Fail!"
+ end
+
+ it "returns ExpectationNotFoundError#message when the exception is an ExpectationNotFoundError" do
+ e = ExpectationNotFoundError.new
+ exc = ExceptionState.new @state, "", e
+ exc.message.should == e.message
+ end
+
+ it "returns the message with exception class when the exception is not an ExpectationNotMetError or an ExpectationNotFoundError" do
+ exc = ExceptionState.new @state, "", Exception.new("Fail!")
+ exc.message.should == "Exception: Fail!"
+ end
+end
+
+describe ExceptionState, "#backtrace" do
+ before :each do
+ @action = mock("action")
+ def @action.exception(exc)
+ ScratchPad.record exc.exception
+ end
+ MSpec.register :exception, @action
+
+ ScratchPad.clear
+ MSpec.protect("") { raise Exception }
+
+ @exc = ExceptionState.new @state, "", ScratchPad.recorded
+ end
+
+ it "returns a string representation of the exception backtrace" do
+ @exc.backtrace.should be_kind_of(String)
+ end
+
+ it "strips MSpec files from the backtrace" do
+ @exc.backtrace.split("\n").each do |line|
+ line.should_not =~ ExceptionState::PATH
+ end
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/filters/a.yaml
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/filters/a.yaml (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/filters/a.yaml 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,4 @@
+---
+A#:
+- a
+- aa
Added: MacRuby/branches/experimental/mspec/spec/runner/filters/b.yaml
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/filters/b.yaml (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/filters/b.yaml 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,11 @@
+---
+B.:
+- b
+- bb
+B::C#:
+- b!
+- b=
+- b?
+- "-"
+- "[]"
+- "[]="
Added: MacRuby/branches/experimental/mspec/spec/runner/filters/match_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/filters/match_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/filters/match_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,44 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/mspec'
+require 'mspec/runner/filters/match'
+
+describe MatchFilter, "#to_regexp" do
+ before :each do
+ @filter = MatchFilter.new nil
+ end
+
+ it "converts its arguments to Regexp instances" do
+ @filter.to_regexp('a', 'b', 'c').should == [/a/, /b/, /c/]
+ end
+end
+
+describe MatchFilter, "#===" do
+ before :each do
+ @filter = MatchFilter.new nil, 'a', 'b', 'c'
+ end
+
+ it "returns true if the argument matches any of the #initialize strings" do
+ @filter.===('aaa').should == true
+ @filter.===('bccb').should == true
+ end
+
+ it "returns false if the argument matches none of the #initialize strings" do
+ @filter.===('d').should == false
+ end
+end
+
+describe MatchFilter, "#register" do
+ it "registers itself with MSpec for the designated action list" do
+ filter = MatchFilter.new :include
+ MSpec.should_receive(:register).with(:include, filter)
+ filter.register
+ end
+end
+
+describe MatchFilter, "#unregister" do
+ it "unregisters itself with MSpec for the designated action list" do
+ filter = MatchFilter.new :exclude
+ MSpec.should_receive(:unregister).with(:exclude, filter)
+ filter.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/filters/profile_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/filters/profile_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/filters/profile_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,117 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/mspec'
+require 'mspec/runner/filters/profile'
+
+describe ProfileFilter, "#find" do
+ before :each do
+ @filter = ProfileFilter.new nil
+ File.stub!(:exist?).and_return(false)
+ @file = "rails.yaml"
+ end
+
+ it "attempts to locate the file through the expanded path name" do
+ File.should_receive(:expand_path).with(@file).and_return(@file)
+ File.should_receive(:exist?).with(@file).and_return(true)
+ @filter.find(@file).should == @file
+ end
+
+ it "attemps to locate the file in 'spec/profiles'" do
+ path = File.join "spec/profiles", @file
+ File.should_receive(:exist?).with(path).and_return(true)
+ @filter.find(@file).should == path
+ end
+
+ it "attemps to locate the file in 'spec'" do
+ path = File.join "spec", @file
+ File.should_receive(:exist?).with(path).and_return(true)
+ @filter.find(@file).should == path
+ end
+
+ it "attemps to locate the file in 'profiles'" do
+ path = File.join "profiles", @file
+ File.should_receive(:exist?).with(path).and_return(true)
+ @filter.find(@file).should == path
+ end
+
+ it "attemps to locate the file in '.'" do
+ path = File.join ".", @file
+ File.should_receive(:exist?).with(path).and_return(true)
+ @filter.find(@file).should == path
+ end
+end
+
+describe ProfileFilter, "#parse" do
+ before :each do
+ @filter = ProfileFilter.new nil
+ @file = File.open(File.dirname(__FILE__) + "/b.yaml", "r")
+ end
+
+ after :each do
+ @file.close
+ end
+
+ it "creates a Hash of the contents of the YAML file" do
+ @filter.parse(@file).should == {
+ "B." => ["b", "bb"],
+ "B::C#" => ["b!", "b=", "b?", "-", "[]", "[]="]
+ }
+ end
+end
+
+describe ProfileFilter, "#load" do
+ before :each do
+ @filter = ProfileFilter.new nil
+ @files = [
+ File.dirname(__FILE__) + "/a.yaml",
+ File.dirname(__FILE__) + "/b.yaml"
+ ]
+ end
+
+ it "generates a composite hash from multiple YAML files" do
+ @filter.load(*@files).should == {
+ "A#" => ["a", "aa"],
+ "B." => ["b", "bb"],
+ "B::C#" => ["b!", "b=", "b?", "-", "[]", "[]="]
+ }
+ end
+end
+
+describe ProfileFilter, "#===" do
+ before :each do
+ @filter = ProfileFilter.new nil
+ @filter.stub!(:load).and_return({ "A#" => ["[]=", "a", "a!", "a?", "aa="]})
+ @filter.send :initialize, nil
+ end
+
+ it "returns true if the spec description is for a method in the profile" do
+ @filter.===("The A#[]= method").should == true
+ @filter.===("A#a returns").should == true
+ @filter.===("A#a! replaces").should == true
+ @filter.===("A#a? returns").should == true
+ @filter.===("A#aa= raises").should == true
+ end
+
+ it "returns false if the spec description is for a method not in the profile" do
+ @filter.===("The A#[] method").should == false
+ @filter.===("B#a returns").should == false
+ @filter.===("A.a! replaces").should == false
+ @filter.===("AA#a? returns").should == false
+ @filter.===("A#aa raises").should == false
+ end
+end
+
+describe ProfileFilter, "#register" do
+ it "registers itself with MSpec for the designated action list" do
+ filter = ProfileFilter.new :include
+ MSpec.should_receive(:register).with(:include, filter)
+ filter.register
+ end
+end
+
+describe ProfileFilter, "#unregister" do
+ it "unregisters itself with MSpec for the designated action list" do
+ filter = ProfileFilter.new :exclude
+ MSpec.should_receive(:unregister).with(:exclude, filter)
+ filter.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/filters/regexp_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/filters/regexp_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/filters/regexp_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,13 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/mspec'
+require 'mspec/runner/filters/regexp'
+
+describe RegexpFilter, "#to_regexp" do
+ before :each do
+ @filter = RegexpFilter.new nil
+ end
+
+ it "converts its arguments to Regexp instances" do
+ @filter.to_regexp('a(b|c)', 'b[^ab]', 'cc?').should == [/a(b|c)/, /b[^ab]/, /cc?/]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/filters/tag_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/filters/tag_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/filters/tag_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,77 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/mspec'
+require 'mspec/runner/filters/match'
+require 'mspec/runner/filters/tag'
+
+describe TagFilter, "#load" do
+ before :each do
+ @match = mock("match filter", :null_object => true)
+ @filter = TagFilter.new :include, "tag", "key"
+ @tag = SpecTag.new "tag(comment):description"
+ MSpec.stub!(:read_tags).and_return([@tag])
+ MSpec.stub!(:register)
+ end
+
+ it "loads tags from the tag file" do
+ MSpec.should_receive(:read_tags).with(["tag", "key"]).and_return([])
+ @filter.load
+ end
+
+ it "creates a MatchFilter from the descriptions matching the tags" do
+ MatchFilter.should_receive(:new).with(:include, "description").and_return(@match)
+ @filter.load
+ end
+
+ it "creates an empty MatchFilter if no tags were found" do
+ MSpec.should_receive(:read_tags).and_return([])
+ MatchFilter.should_receive(:new).with(:include).and_return(@match)
+ @filter.load
+ end
+
+ it "registers the MatchFilter if there were tags found in the tag file" do
+ @match.should_receive(:register)
+ MatchFilter.should_receive(:new).with(:include, "description").and_return(@match)
+ @filter.load
+ end
+
+ it "registers the empty MatchFilter if no tags were found" do
+ @match.should_receive(:register)
+ MSpec.should_receive(:read_tags).and_return([])
+ MatchFilter.should_receive(:new).with(:include).and_return(@match)
+ @filter.load
+ end
+end
+
+describe TagFilter, "#unload" do
+ before :each do
+ @filter = TagFilter.new :include, "tag", "key"
+ @tag = SpecTag.new "tag(comment):description"
+ MSpec.stub!(:read_tags).and_return([@tag])
+ end
+
+ it "unregisters the MatchFilter if one was registered" do
+ match = mock("match filter", :null_object => true)
+ match.should_receive(:unregister)
+ MatchFilter.stub!(:new).with(:include, "description").and_return(match)
+ @filter.load
+ @filter.unload
+ end
+end
+
+describe TagFilter, "#register" do
+ it "registers itself with MSpec for the :load, :unload actions" do
+ filter = TagFilter.new(nil)
+ MSpec.should_receive(:register).with(:load, filter)
+ MSpec.should_receive(:register).with(:unload, filter)
+ filter.register
+ end
+end
+
+describe TagFilter, "#unregister" do
+ it "unregisters itself with MSpec for the :load, :unload actions" do
+ filter = TagFilter.new(nil)
+ MSpec.should_receive(:unregister).with(:load, filter)
+ MSpec.should_receive(:unregister).with(:unload, filter)
+ filter.unregister
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/formatters/describe_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/formatters/describe_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/formatters/describe_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,67 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/formatters/describe'
+require 'mspec/runner/example'
+
+describe DescribeFormatter, "#finish" do
+ before :each do
+ MSpec.stub!(:register)
+ MSpec.stub!(:unregister)
+
+ @timer = mock("timer", :null_object => true)
+ TimerAction.stub!(:new).and_return(@timer)
+ @timer.stub!(:format).and_return("Finished in 2.0 seconds")
+
+ $stdout = @out = IOStub.new
+ context = ContextState.new "Class#method"
+ @state = ExampleState.new(context, "runs")
+
+ @formatter = DescribeFormatter.new
+ @formatter.register
+
+ @tally = @formatter.tally
+ @counter = @tally.counter
+
+ @counter.files!
+ @counter.examples!
+ @counter.expectations! 2
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints a summary of elapsed time" do
+ @formatter.finish
+ @out.should =~ /^Finished in 2.0 seconds$/
+ end
+
+ it "prints a tally of counts" do
+ @formatter.finish
+ @out.should =~ /^1 file, 1 example, 2 expectations, 0 failures, 0 errors$/
+ end
+
+ it "does not print exceptions" do
+ @formatter.finish
+ @out.should == %[
+
+Finished in 2.0 seconds
+
+1 file, 1 example, 2 expectations, 0 failures, 0 errors
+]
+ end
+
+ it "prints a summary of failures and errors for each describe block" do
+ exc = ExceptionState.new @state, nil, MSpecExampleError.new("broken")
+ exc.stub!(:backtrace).and_return("path/to/some/file.rb:35:in method")
+ @formatter.exception exc
+ @formatter.finish
+ @out.should == %[
+
+Class#method 0 failures, 1 error
+
+Finished in 2.0 seconds
+
+1 file, 1 example, 2 expectations, 0 failures, 0 errors
+]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/formatters/dotted_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/formatters/dotted_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/formatters/dotted_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,290 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/formatters/dotted'
+require 'mspec/runner/mspec'
+require 'mspec/runner/example'
+
+describe DottedFormatter, "#initialize" do
+ it "permits zero arguments" do
+ DottedFormatter.new
+ end
+
+ it "accepts one argument" do
+ DottedFormatter.new nil
+ end
+end
+
+describe DottedFormatter, "#register" do
+ before :each do
+ @formatter = DottedFormatter.new
+ end
+
+ it "registers self with MSpec for appropriate actions" do
+ MSpec.stub!(:register)
+ MSpec.should_receive(:register).with(:exception, @formatter)
+ MSpec.should_receive(:register).with(:before, @formatter)
+ MSpec.should_receive(:register).with(:after, @formatter)
+ MSpec.should_receive(:register).with(:finish, @formatter)
+ @formatter.register
+ end
+
+ it "creates TimerAction and TallyAction" do
+ timer = mock("timer")
+ tally = mock("tally")
+ timer.should_receive(:register)
+ tally.should_receive(:register)
+ tally.should_receive(:counter)
+ TimerAction.should_receive(:new).and_return(timer)
+ TallyAction.should_receive(:new).and_return(tally)
+ @formatter.register
+ end
+end
+
+describe DottedFormatter, "#print" do
+ before :each do
+ $stdout = IOStub.new
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "writes to $stdout by default" do
+ formatter = DottedFormatter.new
+ formatter.print "begonias"
+ $stdout.should == "begonias"
+ end
+
+ it "writes to the file specified when the formatter was created" do
+ out = IOStub.new
+ File.should_receive(:open).with("some/file", "w").and_return(out)
+ formatter = DottedFormatter.new "some/file"
+ formatter.print "begonias"
+ out.should == "begonias"
+ end
+
+ it "flushes the IO output" do
+ $stdout.should_receive(:flush)
+ formatter = DottedFormatter.new
+ formatter.print "begonias"
+ end
+
+ it "rescues errors from flush" do
+ $stdout.should_receive(:flush).and_raise(RuntimeError.new)
+ formatter = DottedFormatter.new
+ formatter.print("begonias").should == nil
+ end
+end
+
+describe DottedFormatter, "#exception" do
+ before :each do
+ @formatter = DottedFormatter.new
+ @failure = ExceptionState.new nil, nil, ExpectationNotMetError.new("failed")
+ @error = ExceptionState.new nil, nil, MSpecExampleError.new("boom!")
+ end
+
+ it "sets the #failure? flag" do
+ @formatter.exception @failure
+ @formatter.failure?.should be_true
+ @formatter.exception @error
+ @formatter.failure?.should be_false
+ end
+
+ it "sets the #exception? flag" do
+ @formatter.exception @error
+ @formatter.exception?.should be_true
+ @formatter.exception @failure
+ @formatter.exception?.should be_true
+ end
+
+ it "addes the exception to the list of exceptions" do
+ @formatter.exceptions.should == []
+ @formatter.exception @error
+ @formatter.exception @failure
+ @formatter.exceptions.should == [@error, @failure]
+ end
+end
+
+describe DottedFormatter, "#exception?" do
+ before :each do
+ @formatter = DottedFormatter.new
+ @failure = ExceptionState.new nil, nil, ExpectationNotMetError.new("failed")
+ @error = ExceptionState.new nil, nil, MSpecExampleError.new("boom!")
+ end
+
+ it "returns false if there have been no exceptions" do
+ @formatter.exception?.should be_false
+ end
+
+ it "returns true if any exceptions are errors" do
+ @formatter.exception @failure
+ @formatter.exception @error
+ @formatter.exception?.should be_true
+ end
+
+ it "returns true if all exceptions are failures" do
+ @formatter.exception @failure
+ @formatter.exception @failure
+ @formatter.exception?.should be_true
+ end
+
+ it "returns true if all exceptions are errors" do
+ @formatter.exception @error
+ @formatter.exception @error
+ @formatter.exception?.should be_true
+ end
+end
+
+describe DottedFormatter, "#failure?" do
+ before :each do
+ @formatter = DottedFormatter.new
+ @failure = ExceptionState.new nil, nil, ExpectationNotMetError.new("failed")
+ @error = ExceptionState.new nil, nil, MSpecExampleError.new("boom!")
+ end
+
+ it "returns false if there have been no exceptions" do
+ @formatter.failure?.should be_false
+ end
+
+ it "returns false if any exceptions are errors" do
+ @formatter.exception @failure
+ @formatter.exception @error
+ @formatter.failure?.should be_false
+ end
+
+ it "returns true if all exceptions are failures" do
+ @formatter.exception @failure
+ @formatter.exception @failure
+ @formatter.failure?.should be_true
+ end
+end
+
+describe DottedFormatter, "#before" do
+ before :each do
+ @state = ExampleState.new ContextState.new("describe"), "it"
+ @formatter = DottedFormatter.new
+ @formatter.exception ExceptionState.new(nil, nil, ExpectationNotMetError.new("Failed!"))
+ end
+
+ it "resets the #failure? flag to false" do
+ @formatter.failure?.should be_true
+ @formatter.before @state
+ @formatter.failure?.should be_false
+ end
+
+ it "resets the #exception? flag to false" do
+ @formatter.exception?.should be_true
+ @formatter.before @state
+ @formatter.exception?.should be_false
+ end
+end
+
+describe DottedFormatter, "#after" do
+ before :each do
+ $stdout = @out = IOStub.new
+ @formatter = DottedFormatter.new
+ @state = ExampleState.new ContextState.new("describe"), "it"
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints a '.' if there was no exception raised" do
+ @formatter.after(@state)
+ @out.should == "."
+ end
+
+ it "prints an 'F' if there was an expectation failure" do
+ exc = ExpectationNotMetError.new "failed"
+ @formatter.exception ExceptionState.new(@state, nil, exc)
+ @formatter.after(@state)
+ @out.should == "F"
+ end
+
+ it "prints an 'E' if there was an exception other than expectation failure" do
+ exc = MSpecExampleError.new("boom!")
+ @formatter.exception ExceptionState.new(@state, nil, exc)
+ @formatter.after(@state)
+ @out.should == "E"
+ end
+
+ it "prints an 'E' if there are mixed exceptions and exepctation failures" do
+ exc = ExpectationNotMetError.new "failed"
+ @formatter.exception ExceptionState.new(@state, nil, exc)
+ exc = MSpecExampleError.new("boom!")
+ @formatter.exception ExceptionState.new(@state, nil, exc)
+ @formatter.after(@state)
+ @out.should == "E"
+ end
+end
+
+describe DottedFormatter, "#finish" do
+ before :each do
+ @tally = mock("tally", :null_object => true)
+ TallyAction.stub!(:new).and_return(@tally)
+ @timer = mock("timer", :null_object => true)
+ TimerAction.stub!(:new).and_return(@timer)
+
+ $stdout = @out = IOStub.new
+ context = ContextState.new "Class#method"
+ @state = ExampleState.new(context, "runs")
+ MSpec.stub!(:register)
+ @formatter = DottedFormatter.new
+ @formatter.register
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints a failure message for an exception" do
+ exc = ExceptionState.new @state, nil, MSpecExampleError.new("broken")
+ @formatter.exception exc
+ @formatter.after @state
+ @formatter.finish
+ @out.should =~ /^1\)\nClass#method runs ERROR$/
+ end
+
+ it "prints a backtrace for an exception" do
+ exc = ExceptionState.new @state, nil, MSpecExampleError.new("broken")
+ exc.stub!(:backtrace).and_return("path/to/some/file.rb:35:in method")
+ @formatter.exception exc
+ @formatter.after @state
+ @formatter.finish
+ @out.should =~ %r[path/to/some/file.rb:35:in method$]
+ end
+
+ it "prints a summary of elapsed time" do
+ @timer.should_receive(:format).and_return("Finished in 2.0 seconds")
+ @formatter.finish
+ @out.should =~ /^Finished in 2.0 seconds$/
+ end
+
+ it "prints a tally of counts" do
+ @tally.should_receive(:format).and_return("1 example, 0 failures")
+ @formatter.finish
+ @out.should =~ /^1 example, 0 failures$/
+ end
+
+ it "prints errors, backtraces, elapsed time, and tallies" do
+ exc = ExceptionState.new @state, nil, MSpecExampleError.new("broken")
+ exc.stub!(:backtrace).and_return("path/to/some/file.rb:35:in method")
+ @formatter.exception exc
+ @timer.should_receive(:format).and_return("Finished in 2.0 seconds")
+ @tally.should_receive(:format).and_return("1 example, 1 failure")
+ @formatter.after @state
+ @formatter.finish
+ @out.should ==
+%[E
+
+1)
+Class#method runs ERROR
+MSpecExampleError: broken
+path/to/some/file.rb:35:in method
+
+Finished in 2.0 seconds
+
+1 example, 1 failure
+]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/formatters/file_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/formatters/file_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/formatters/file_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,84 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/formatters/file'
+require 'mspec/runner/mspec'
+require 'mspec/runner/example'
+
+describe FileFormatter, "#register" do
+ before :each do
+ @formatter = FileFormatter.new
+ end
+
+ it "registers self with MSpec for :load, :unload actions" do
+ MSpec.stub!(:register)
+ MSpec.should_receive(:register).with(:load, @formatter)
+ MSpec.should_receive(:register).with(:unload, @formatter)
+ @formatter.register
+ end
+
+ it "unregisters self with MSpec for :before, :after actions" do
+ MSpec.stub!(:unregister)
+ MSpec.should_receive(:unregister).with(:before, @formatter)
+ MSpec.should_receive(:unregister).with(:after, @formatter)
+ @formatter.register
+ end
+end
+
+describe FileFormatter, "#load" do
+ before :each do
+ @state = ExampleState.new ContextState.new("describe"), "it"
+ @formatter = FileFormatter.new
+ @formatter.exception ExceptionState.new(nil, nil, ExpectationNotMetError.new("Failed!"))
+ end
+
+ it "resets the #failure? flag to false" do
+ @formatter.failure?.should be_true
+ @formatter.load @state
+ @formatter.failure?.should be_false
+ end
+
+ it "resets the #exception? flag to false" do
+ @formatter.exception?.should be_true
+ @formatter.load @state
+ @formatter.exception?.should be_false
+ end
+end
+
+describe FileFormatter, "#unload" do
+ before :each do
+ $stdout = @out = IOStub.new
+ @formatter = FileFormatter.new
+ @state = ExampleState.new ContextState.new("describe"), "it"
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints a '.' if there was no exception raised" do
+ @formatter.unload(@state)
+ @out.should == "."
+ end
+
+ it "prints an 'F' if there was an expectation failure" do
+ exc = ExpectationNotMetError.new "failed"
+ @formatter.exception ExceptionState.new(@state, nil, exc)
+ @formatter.unload(@state)
+ @out.should == "F"
+ end
+
+ it "prints an 'E' if there was an exception other than expectation failure" do
+ exc = MSpecExampleError.new("boom!")
+ @formatter.exception ExceptionState.new(@state, nil, exc)
+ @formatter.unload(@state)
+ @out.should == "E"
+ end
+
+ it "prints an 'E' if there are mixed exceptions and exepctation failures" do
+ exc = ExpectationNotMetError.new "failed"
+ @formatter.exception ExceptionState.new(@state, nil, exc)
+ exc = MSpecExampleError.new("boom!")
+ @formatter.exception ExceptionState.new(@state, nil, exc)
+ @formatter.unload(@state)
+ @out.should == "E"
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/formatters/html_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/formatters/html_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/formatters/html_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,216 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/utils/ruby_name'
+require 'mspec/guards/guard'
+require 'mspec/runner/formatters/html'
+require 'mspec/runner/mspec'
+require 'mspec/runner/example'
+
+describe HtmlFormatter do
+ before :each do
+ @formatter = HtmlFormatter.new
+ end
+
+ it "responds to #register by registering itself with MSpec for appropriate actions" do
+ MSpec.stub!(:register)
+ MSpec.should_receive(:register).with(:start, @formatter)
+ MSpec.should_receive(:register).with(:enter, @formatter)
+ MSpec.should_receive(:register).with(:leave, @formatter)
+ @formatter.register
+ end
+end
+
+describe HtmlFormatter, "#start" do
+ before :each do
+ $stdout = @out = IOStub.new
+ @formatter = HtmlFormatter.new
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints the HTML head" do
+ @formatter.start
+ ruby_name = RUBY_NAME
+ ruby_name.should =~ /^ruby/
+ @out.should ==
+%[<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Spec Output For #{ruby_name} (#{RUBY_VERSION})</title>
+<style type="text/css">
+ul {
+ list-style: none;
+}
+.fail {
+ color: red;
+}
+.pass {
+ color: green;
+}
+#details :target {
+ background-color: #ffffe0;
+}
+</style>
+</head>
+<body>
+]
+ end
+end
+
+describe HtmlFormatter, "#enter" do
+ before :each do
+ $stdout = @out = IOStub.new
+ @formatter = HtmlFormatter.new
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints the #describe string" do
+ @formatter.enter "describe"
+ @out.should == "<div><p>describe</p>\n<ul>\n"
+ end
+end
+
+describe HtmlFormatter, "#leave" do
+ before :each do
+ $stdout = @out = IOStub.new
+ @formatter = HtmlFormatter.new
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints the closing tags for the #describe string" do
+ @formatter.leave
+ @out.should == "</ul>\n</div>\n"
+ end
+end
+
+describe HtmlFormatter, "#exception" do
+ before :each do
+ $stdout = @out = IOStub.new
+ @formatter = HtmlFormatter.new
+ @formatter.register
+ @state = ExampleState.new ContextState.new("describe"), "it"
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints the #it string once for each exception raised" do
+ exc = ExceptionState.new @state, nil, ExpectationNotMetError.new("disappointing")
+ @formatter.exception exc
+ exc = ExceptionState.new @state, nil, MSpecExampleError.new("painful")
+ @formatter.exception exc
+ @out.should ==
+%[<li class="fail">- it (<a href="#details-1">FAILED - 1</a>)</li>
+<li class="fail">- it (<a href="#details-2">ERROR - 2</a>)</li>
+]
+ end
+end
+
+describe HtmlFormatter, "#after" do
+ before :each do
+ $stdout = @out = IOStub.new
+ @formatter = HtmlFormatter.new
+ @formatter.register
+ @state = ExampleState.new ContextState.new("describe"), "it"
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints the #it once when there are no exceptions raised" do
+ @formatter.after @state
+ @out.should == %[<li class="pass">- it</li>\n]
+ end
+
+ it "does not print any output if an exception is raised" do
+ exc = ExceptionState.new @state, nil, ExpectationNotMetError.new("disappointing")
+ @formatter.exception exc
+ out = @out.dup
+ @formatter.after @state
+ @out.should == out
+ end
+end
+
+describe HtmlFormatter, "#finish" do
+ before :each do
+ @tally = mock("tally", :null_object => true)
+ TallyAction.stub!(:new).and_return(@tally)
+ @timer = mock("timer", :null_object => true)
+ TimerAction.stub!(:new).and_return(@timer)
+
+ $stdout = @out = IOStub.new
+ context = ContextState.new "describe"
+ @state = ExampleState.new(context, "it")
+ MSpec.stub!(:register)
+ @formatter = HtmlFormatter.new
+ @formatter.register
+ @exception = MSpecExampleError.new("broken")
+ @exception.stub!(:backtrace).and_return(["file.rb:1", "file.rb:2"])
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints a failure message for an exception" do
+ exc = ExceptionState.new @state, nil, @exception
+ @formatter.exception exc
+ @formatter.finish
+ @out.should =~ %r[<p>describe it ERROR</p>]
+ end
+
+ it "prints a backtrace for an exception" do
+ exc = ExceptionState.new @state, nil, @exception
+ exc.stub!(:backtrace).and_return("path/to/some/file.rb:35:in method")
+ @formatter.exception exc
+ @formatter.finish
+ @out.should =~ %r[<pre>.*path/to/some/file.rb:35:in method.*</pre>]m
+ end
+
+ it "prints a summary of elapsed time" do
+ @timer.should_receive(:format).and_return("Finished in 2.0 seconds")
+ @formatter.finish
+ @out.should =~ %r[<p>Finished in 2.0 seconds</p>\n]
+ end
+
+ it "prints a tally of counts" do
+ @tally.should_receive(:format).and_return("1 example, 0 failures")
+ @formatter.finish
+ @out.should =~ %r[<p class="pass">1 example, 0 failures</p>]
+ end
+
+ it "prints errors, backtraces, elapsed time, and tallies" do
+ exc = ExceptionState.new @state, nil, @exception
+ exc.stub!(:backtrace).and_return("path/to/some/file.rb:35:in method")
+ @formatter.exception exc
+
+ @timer.should_receive(:format).and_return("Finished in 2.0 seconds")
+ @tally.should_receive(:format).and_return("1 example, 1 failures")
+ @formatter.finish
+ @out.should ==
+%[<li class=\"fail\">- it (<a href=\"#details-1\">ERROR - 1</a>)</li>
+<hr>
+<ol id="details">
+<li id="details-1"><p>describe it ERROR</p>
+<p>MSpecExampleError: broken</p>
+<pre>
+path/to/some/file.rb:35:in method</pre>
+</li>
+</ol>
+<p>Finished in 2.0 seconds</p>
+<p class="fail">1 example, 1 failures</p>
+</body>
+</html>
+]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/formatters/method_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/formatters/method_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/formatters/method_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,177 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/formatters/method'
+require 'mspec/runner/mspec'
+require 'mspec/runner/example'
+
+describe MethodFormatter, "#method_type" do
+ before :each do
+ @formatter = MethodFormatter.new
+ end
+
+ it "returns 'class' if the separator is '.' or '::'" do
+ @formatter.method_type('.').should == "class"
+ @formatter.method_type('::').should == "class"
+ end
+
+ it "returns 'instance' if the separator is '#'" do
+ @formatter.method_type('#').should == "instance"
+ end
+
+ it "returns 'unknown' for all other cases" do
+ @formatter.method_type(nil).should == "unknown"
+ end
+end
+
+describe MethodFormatter, "#before" do
+ before :each do
+ @formatter = MethodFormatter.new
+ MSpec.stub!(:register)
+ @formatter.register
+ end
+
+ it "resets the tally counters to 0" do
+ @formatter.tally.counter.examples = 3
+ @formatter.tally.counter.expectations = 4
+ @formatter.tally.counter.failures = 2
+ @formatter.tally.counter.errors = 1
+
+ state = ExampleState.new ContextState.new("describe"), "it"
+ @formatter.before state
+ @formatter.tally.counter.examples.should == 0
+ @formatter.tally.counter.expectations.should == 0
+ @formatter.tally.counter.failures.should == 0
+ @formatter.tally.counter.errors.should == 0
+ end
+
+ it "records the class, method if available" do
+ state = ExampleState.new ContextState.new("Some#method"), "it"
+ @formatter.before state
+ key = "Some#method"
+ @formatter.methods.keys.should include(key)
+ h = @formatter.methods[key]
+ h[:class].should == "Some"
+ h[:method].should == "method"
+ h[:description].should == "Some#method it"
+ end
+
+ it "does not record class, method unless both are available" do
+ state = ExampleState.new ContextState.new("Some method"), "it"
+ @formatter.before state
+ key = "Some method"
+ @formatter.methods.keys.should include(key)
+ h = @formatter.methods[key]
+ h[:class].should == ""
+ h[:method].should == ""
+ h[:description].should == "Some method it"
+ end
+
+ it "sets the method type to unknown if class and method are not available" do
+ state = ExampleState.new ContextState.new("Some method"), "it"
+ @formatter.before state
+ key = "Some method"
+ h = @formatter.methods[key]
+ h[:type].should == "unknown"
+ end
+
+ it "sets the method type based on the class, method separator" do
+ [["C#m", "instance"], ["C.m", "class"], ["C::m", "class"]].each do |k, t|
+ state = ExampleState.new ContextState.new(k), "it"
+ @formatter.before state
+ h = @formatter.methods[k]
+ h[:type].should == t
+ end
+ end
+
+ it "clears the list of exceptions" do
+ state = ExampleState.new ContextState.new("describe"), "it"
+ @formatter.exceptions << "stuff"
+ @formatter.before state
+ @formatter.exceptions.should be_empty
+ end
+end
+
+describe MethodFormatter, "#after" do
+ before :each do
+ @formatter = MethodFormatter.new
+ MSpec.stub!(:register)
+ @formatter.register
+ end
+
+ it "sets the tally counts" do
+ state = ExampleState.new ContextState.new("Some#method"), "it"
+ @formatter.before state
+
+ @formatter.tally.counter.examples = 3
+ @formatter.tally.counter.expectations = 4
+ @formatter.tally.counter.failures = 2
+ @formatter.tally.counter.errors = 1
+
+ @formatter.after state
+ h = @formatter.methods["Some#method"]
+ h[:examples].should == 3
+ h[:expectations].should == 4
+ h[:failures].should == 2
+ h[:errors].should == 1
+ end
+
+ it "renders the list of exceptions" do
+ state = ExampleState.new ContextState.new("Some#method"), "it"
+ @formatter.before state
+
+ exc = ExpectationNotMetError.new "failed"
+ @formatter.exception ExceptionState.new(@state, nil, exc)
+ @formatter.exception ExceptionState.new(@state, nil, exc)
+
+ @formatter.after state
+ h = @formatter.methods["Some#method"]
+ h[:exceptions].should == [
+ %[failed\n\n],
+ %[failed\n\n]
+ ]
+ end
+end
+
+describe MethodFormatter, "#after" do
+ before :each do
+ $stdout = IOStub.new
+ context = ContextState.new "Class#method"
+ @state = ExampleState.new(context, "runs")
+ @formatter = MethodFormatter.new
+ MSpec.stub!(:register)
+ @formatter.register
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints a summary of the results of an example in YAML format" do
+ @formatter.before @state
+ @formatter.tally.counter.examples = 3
+ @formatter.tally.counter.expectations = 4
+ @formatter.tally.counter.failures = 2
+ @formatter.tally.counter.errors = 1
+
+ exc = ExpectationNotMetError.new "failed"
+ @formatter.exception ExceptionState.new(@state, nil, exc)
+ @formatter.exception ExceptionState.new(@state, nil, exc)
+
+ @formatter.after @state
+ @formatter.finish
+ $stdout.should ==
+%[---
+"Class#method":
+ class: "Class"
+ method: "method"
+ type: instance
+ description: "Class#method runs"
+ examples: 3
+ expectations: 4
+ failures: 2
+ errors: 1
+ exceptions:
+ - "failed\\n\\n"
+ - "failed\\n\\n"
+]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/formatters/specdoc_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/formatters/specdoc_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/formatters/specdoc_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,106 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/formatters/specdoc'
+require 'mspec/runner/example'
+
+describe SpecdocFormatter do
+ before :each do
+ @formatter = SpecdocFormatter.new
+ end
+
+ it "responds to #register by registering itself with MSpec for appropriate actions" do
+ MSpec.stub!(:register)
+ MSpec.should_receive(:register).with(:enter, @formatter)
+ @formatter.register
+ end
+end
+
+describe SpecdocFormatter, "#enter" do
+ before :each do
+ $stdout = @out = IOStub.new
+ @formatter = SpecdocFormatter.new
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints the #describe string" do
+ @formatter.enter("describe")
+ @out.should == "\ndescribe\n"
+ end
+end
+
+describe SpecdocFormatter, "#before" do
+ before :each do
+ $stdout = @out = IOStub.new
+ @formatter = SpecdocFormatter.new
+ @state = ExampleState.new ContextState.new("describe"), "it"
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints the #it string" do
+ @formatter.before @state
+ @out.should == "- it"
+ end
+
+ it "resets the #exception? flag" do
+ exc = ExceptionState.new @state, nil, ExpectationNotMetError.new("disappointing")
+ @formatter.exception exc
+ @formatter.exception?.should be_true
+ @formatter.before @state
+ @formatter.exception?.should be_false
+ end
+end
+
+describe SpecdocFormatter, "#exception" do
+ before :each do
+ $stdout = @out = IOStub.new
+ @formatter = SpecdocFormatter.new
+ context = ContextState.new "describe"
+ @state = ExampleState.new context, "it"
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints 'ERROR' if an exception is not an ExpectationNotMetError" do
+ exc = ExceptionState.new @state, nil, MSpecExampleError.new("painful")
+ @formatter.exception exc
+ @out.should == " (ERROR - 1)"
+ end
+
+ it "prints 'FAILED' if an exception is an ExpectationNotMetError" do
+ exc = ExceptionState.new @state, nil, ExpectationNotMetError.new("disappointing")
+ @formatter.exception exc
+ @out.should == " (FAILED - 1)"
+ end
+
+ it "prints the #it string if an exception has already been raised" do
+ exc = ExceptionState.new @state, nil, ExpectationNotMetError.new("disappointing")
+ @formatter.exception exc
+ exc = ExceptionState.new @state, nil, MSpecExampleError.new("painful")
+ @formatter.exception exc
+ @out.should == " (FAILED - 1)\n- it (ERROR - 2)"
+ end
+end
+
+describe SpecdocFormatter, "#after" do
+ before :each do
+ $stdout = @out = IOStub.new
+ @formatter = SpecdocFormatter.new
+ @state = ExampleState.new "describe", "it"
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints a newline character" do
+ @formatter.after @state
+ @out.should == "\n"
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/formatters/spinner_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/formatters/spinner_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/formatters/spinner_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,85 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/formatters/spinner'
+require 'mspec/runner/mspec'
+require 'mspec/runner/example'
+
+describe SpinnerFormatter, "#initialize" do
+ it "permits zero arguments" do
+ SpinnerFormatter.new
+ end
+
+ it "accepts one argument" do
+ SpinnerFormatter.new nil
+ end
+end
+
+describe SpinnerFormatter, "#register" do
+ before :each do
+ @formatter = SpinnerFormatter.new
+ end
+
+ it "registers self with MSpec for appropriate actions" do
+ MSpec.stub!(:register)
+ MSpec.should_receive(:register).with(:start, @formatter)
+ MSpec.should_receive(:register).with(:load, @formatter)
+ MSpec.should_receive(:register).with(:after, @formatter)
+ MSpec.should_receive(:register).with(:finish, @formatter)
+ @formatter.register
+ end
+
+ it "creates TimerAction and TallyAction" do
+ timer = mock("timer")
+ tally = mock("tally")
+ timer.should_receive(:register)
+ tally.should_receive(:register)
+ tally.should_receive(:counter)
+ TimerAction.should_receive(:new).and_return(timer)
+ TallyAction.should_receive(:new).and_return(tally)
+ @formatter.register
+ end
+end
+
+describe SpinnerFormatter, "#print" do
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "ignores the argument to #initialize and writes to $stdout" do
+ $stdout = IOStub.new
+ formatter = SpinnerFormatter.new "some/file"
+ formatter.print "begonias"
+ $stdout.should == "begonias"
+ end
+end
+
+describe SpinnerFormatter, "#after" do
+ before :each do
+ $stdout = IOStub.new
+ MSpec.stub!(:retrieve).and_return(["a", "b"])
+ @formatter = SpinnerFormatter.new
+ @formatter.register
+ @state = ExampleState.new("describe", "it")
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "updates the spinner" do
+ @formatter.start
+ @formatter.load
+ @formatter.after @state
+ @formatter.after @state
+
+ if ENV["TERM"] != "dumb"
+ $stdout.should == "\r[/ | ======== 20% | 00:00:00] " \
+ "\e[0;32m 0F \e[0;32m 0E\e[0m" \
+ "\r[- | ======== 20% | 00:00:00] " \
+ "\e[0;32m 0F \e[0;32m 0E\e[0m"
+ else
+ $stdout.should == "\r[/ | ======== 20% | 00:00:00] " \
+ " 0F 0E\r[- | ======== 20% " \
+ " | 00:00:00] 0F 0E"
+ end
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/formatters/summary_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/formatters/summary_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/formatters/summary_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,26 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/formatters/summary'
+require 'mspec/runner/example'
+
+describe SummaryFormatter, "#after" do
+ before :each do
+ $stdout = @out = IOStub.new
+ @formatter = SummaryFormatter.new
+ @formatter.register
+ context = ContextState.new "describe"
+ @state = ExampleState.new(context, "it")
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "does not print anything" do
+ exc = ExceptionState.new @state, nil, ExpectationNotMetError.new("disappointing")
+ @formatter.exception exc
+ exc = ExceptionState.new @state, nil, MSpecExampleError.new("painful")
+ @formatter.exception exc
+ @formatter.after(@state)
+ @out.should == ""
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/formatters/unit_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/formatters/unit_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/formatters/unit_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,73 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/formatters/unit'
+require 'mspec/runner/example'
+
+describe UnitdiffFormatter, "#finish" do
+ before :each do
+ @tally = mock("tally", :null_object => true)
+ TallyAction.stub!(:new).and_return(@tally)
+ @timer = mock("timer", :null_object => true)
+ TimerAction.stub!(:new).and_return(@timer)
+
+ $stdout = @out = IOStub.new
+ context = ContextState.new "describe"
+ @state = ExampleState.new(context, "it")
+ MSpec.stub!(:register)
+ @formatter = UnitdiffFormatter.new
+ @formatter.register
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "prints a failure message for an exception" do
+ exc = ExceptionState.new @state, nil, MSpecExampleError.new("broken")
+ @formatter.exception exc
+ @formatter.after @state
+ @formatter.finish
+ @out.should =~ /^1\)\ndescribe it ERROR$/
+ end
+
+ it "prints a backtrace for an exception" do
+ exc = ExceptionState.new @state, nil, Exception.new("broken")
+ exc.stub!(:backtrace).and_return("path/to/some/file.rb:35:in method")
+ @formatter.exception exc
+ @formatter.finish
+ @out.should =~ %r[path/to/some/file.rb:35:in method$]
+ end
+
+ it "prints a summary of elapsed time" do
+ @timer.should_receive(:format).and_return("Finished in 2.0 seconds")
+ @formatter.finish
+ @out.should =~ /^Finished in 2.0 seconds$/
+ end
+
+ it "prints a tally of counts" do
+ @tally.should_receive(:format).and_return("1 example, 0 failures")
+ @formatter.finish
+ @out.should =~ /^1 example, 0 failures$/
+ end
+
+ it "prints errors, backtraces, elapsed time, and tallies" do
+ exc = ExceptionState.new @state, nil, Exception.new("broken")
+ exc.stub!(:backtrace).and_return("path/to/some/file.rb:35:in method")
+ @formatter.exception exc
+ @formatter.after @state
+ @timer.should_receive(:format).and_return("Finished in 2.0 seconds")
+ @tally.should_receive(:format).and_return("1 example, 0 failures")
+ @formatter.finish
+ @out.should ==
+%[E
+
+Finished in 2.0 seconds
+
+1)
+describe it ERROR
+Exception: broken:
+path/to/some/file.rb:35:in method
+
+1 example, 0 failures
+]
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/formatters/yaml_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/formatters/yaml_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/formatters/yaml_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,125 @@
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'mspec/runner/formatters/yaml'
+require 'mspec/runner/example'
+
+describe YamlFormatter, "#initialize" do
+ it "permits zero arguments" do
+ YamlFormatter.new
+ end
+
+ it "accepts one argument" do
+ YamlFormatter.new nil
+ end
+end
+
+describe YamlFormatter, "#print" do
+ before :each do
+ $stdout = IOStub.new
+ @out = IOStub.new
+ File.stub!(:open).and_return(@out)
+ @formatter = YamlFormatter.new "some/file"
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "writes to $stdout if #switch has not been called" do
+ @formatter.print "begonias"
+ $stdout.should == "begonias"
+ @out.should == ""
+ end
+
+ it "writes to the file passed to #initialize once #switch has been called" do
+ @formatter.switch
+ @formatter.print "begonias"
+ $stdout.should == ""
+ @out.should == "begonias"
+ end
+
+ it "writes to $stdout once #switch is called if no file was passed to #initialize" do
+ formatter = YamlFormatter.new
+ formatter.switch
+ formatter.print "begonias"
+ $stdout.should == "begonias"
+ @out.should == ""
+ end
+end
+
+describe YamlFormatter, "#finish" do
+ before :each do
+ @tally = mock("tally", :null_object => true)
+ @counter = mock("counter", :null_object => true)
+ @tally.stub!(:counter).and_return(@counter)
+ TallyAction.stub!(:new).and_return(@tally)
+
+ @timer = mock("timer", :null_object => true)
+ TimerAction.stub!(:new).and_return(@timer)
+
+ $stdout = IOStub.new
+ context = ContextState.new "describe"
+ @state = ExampleState.new(context, "it")
+
+ @formatter = YamlFormatter.new
+ @formatter.stub!(:backtrace).and_return("")
+ MSpec.stub!(:register)
+ @formatter.register
+
+ exc = ExceptionState.new @state, nil, MSpecExampleError.new("broken")
+ exc.stub!(:backtrace).and_return("path/to/some/file.rb:35:in method")
+ @formatter.exception exc
+ @formatter.after @state
+ end
+
+ after :each do
+ $stdout = STDOUT
+ end
+
+ it "calls #switch" do
+ @formatter.should_receive(:switch)
+ @formatter.finish
+ end
+
+ it "outputs a failure message and backtrace" do
+ @formatter.finish
+ $stdout.should =~ /describe it ERROR/
+ $stdout.should =~ /MSpecExampleError: broken\\n/
+ $stdout.should =~ %r[path/to/some/file.rb:35:in method]
+ end
+
+ it "outputs an elapsed time" do
+ @timer.should_receive(:elapsed).and_return(4.2)
+ @formatter.finish
+ $stdout.should =~ /time: 4.2/
+ end
+
+ it "outputs a file count" do
+ @counter.should_receive(:files).and_return(3)
+ @formatter.finish
+ $stdout.should =~ /files: 3/
+ end
+
+ it "outputs an example count" do
+ @counter.should_receive(:examples).and_return(3)
+ @formatter.finish
+ $stdout.should =~ /examples: 3/
+ end
+
+ it "outputs an expectation count" do
+ @counter.should_receive(:expectations).and_return(9)
+ @formatter.finish
+ $stdout.should =~ /expectations: 9/
+ end
+
+ it "outputs a failure count" do
+ @counter.should_receive(:failures).and_return(2)
+ @formatter.finish
+ $stdout.should =~ /failures: 2/
+ end
+
+ it "outputs an error count" do
+ @counter.should_receive(:errors).and_return(1)
+ @formatter.finish
+ $stdout.should =~ /errors: 1/
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/mspec_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/mspec_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/mspec_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,589 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/helpers/tmp'
+require 'mspec/matchers/base'
+require 'mspec/runner/mspec'
+require 'mspec/runner/example'
+
+describe MSpec, ".register_files" do
+ it "records which spec files to run" do
+ MSpec.register_files [:one, :two, :three]
+ MSpec.retrieve(:files).should == [:one, :two, :three]
+ end
+end
+
+describe MSpec, ".register_mode" do
+ before :each do
+ MSpec.clear_modes
+ end
+
+ it "sets execution mode flags" do
+ MSpec.register_mode :verify
+ MSpec.retrieve(:modes).should == [:verify]
+ end
+end
+
+describe MSpec, ".register_tags_patterns" do
+ it "records the patterns for generating a tag file from a spec file" do
+ MSpec.register_tags_patterns [[/spec\/ruby/, "spec/tags"], [/frozen/, "ruby"]]
+ MSpec.retrieve(:tags_patterns).should == [[/spec\/ruby/, "spec/tags"], [/frozen/, "ruby"]]
+ end
+end
+
+describe MSpec, ".register_exit" do
+ before :each do
+ MSpec.store :exit, 0
+ end
+
+ it "records the exit code" do
+ MSpec.exit_code.should == 0
+ MSpec.register_exit 1
+ MSpec.exit_code.should == 1
+ end
+end
+
+describe MSpec, ".exit_code" do
+ it "retrieves the code set with .register_exit" do
+ MSpec.register_exit 99
+ MSpec.exit_code.should == 99
+ end
+end
+
+describe MSpec, ".store" do
+ it "records data for MSpec settings" do
+ MSpec.store :anything, :value
+ MSpec.retrieve(:anything).should == :value
+ end
+end
+
+describe MSpec, ".retrieve" do
+ it "accesses .store'd data" do
+ MSpec.register :action, :first
+ MSpec.retrieve(:action).should == [:first]
+ end
+end
+
+describe MSpec, ".randomize" do
+ it "sets the flag to randomize spec execution order" do
+ MSpec.randomize?.should == false
+ MSpec.randomize
+ MSpec.randomize?.should == true
+ MSpec.randomize false
+ MSpec.randomize?.should == false
+ end
+end
+
+describe MSpec, ".register" do
+ it "is the gateway behind the register(symbol, action) facility" do
+ MSpec.register :bonus, :first
+ MSpec.register :bonus, :second
+ MSpec.register :bonus, :second
+ MSpec.retrieve(:bonus).should == [:first, :second]
+ end
+end
+
+describe MSpec, ".unregister" do
+ it "is the gateway behind the unregister(symbol, actions) facility" do
+ MSpec.register :unregister, :first
+ MSpec.register :unregister, :second
+ MSpec.unregister :unregister, :second
+ MSpec.retrieve(:unregister).should == [:first]
+ end
+end
+
+describe MSpec, ".protect" do
+ before :each do
+ MSpec.clear_current
+ @cs = ContextState.new "C#m"
+ @cs.stub!(:state).and_return(@es)
+ @cs.parent = MSpec.current
+
+ @es = ExampleState.new @cs, "runs"
+ ScratchPad.record Exception.new("Sharp!")
+ end
+
+ it "returns true if no exception is raised" do
+ MSpec.protect("passed") { 1 }.should be_true
+ end
+
+ it "returns false if an exception is raised" do
+ MSpec.protect("testing") { raise ScratchPad.recorded }.should be_false
+ end
+
+ it "rescues any exceptions raised when evaluating the block argument" do
+ MSpec.protect("") { raise Exception, "Now you see me..." }
+ end
+
+ it "does not rescue SystemExit" do
+ begin
+ MSpec.protect("") { exit 1 }
+ rescue SystemExit
+ ScratchPad.record :system_exit
+ end
+ ScratchPad.recorded.should == :system_exit
+ end
+
+ it "calls all the exception actions" do
+ exc = ExceptionState.new @es, "testing", ScratchPad.recorded
+ ExceptionState.stub!(:new).and_return(exc)
+ action = mock("exception")
+ action.should_receive(:exception).with(exc)
+ MSpec.register :exception, action
+ MSpec.protect("testing") { raise ScratchPad.recorded }
+ MSpec.unregister :exception, action
+ end
+
+ it "registers a non-zero exit code when an exception is raised" do
+ MSpec.should_receive(:register_exit).with(1)
+ MSpec.protect("testing") { raise ScratchPad.recorded }
+ end
+end
+
+describe MSpec, ".register_current" do
+ before :each do
+ MSpec.clear_current
+ end
+
+ it "sets the value returned by MSpec.current" do
+ MSpec.current.should be_nil
+ MSpec.register_current :a
+ MSpec.current.should == :a
+ end
+end
+
+describe MSpec, ".clear_current" do
+ it "sets the value returned by MSpec.current to nil" do
+ MSpec.register_current :a
+ MSpec.current.should_not be_nil
+ MSpec.clear_current
+ MSpec.current.should be_nil
+ end
+end
+
+describe MSpec, ".current" do
+ before :each do
+ MSpec.clear_current
+ end
+
+ it "returns nil if no ContextState has been registered" do
+ MSpec.current.should be_nil
+ end
+
+ it "returns the most recently registered ContextState" do
+ first = ContextState.new ""
+ second = ContextState.new ""
+ MSpec.register_current first
+ MSpec.current.should == first
+ MSpec.register_current second
+ MSpec.current.should == second
+ end
+end
+
+describe MSpec, ".actions" do
+ before :each do
+ MSpec.store :start, []
+ ScratchPad.record []
+ start_one = mock("one")
+ start_one.stub!(:start).and_return { ScratchPad << :one }
+ start_two = mock("two")
+ start_two.stub!(:start).and_return { ScratchPad << :two }
+ MSpec.register :start, start_one
+ MSpec.register :start, start_two
+ end
+
+ it "does not attempt to run any actions if none have been registered" do
+ MSpec.store :finish, nil
+ lambda { MSpec.actions :finish }.should_not raise_error
+ end
+
+ it "runs each action registered as a start action" do
+ MSpec.actions :start
+ ScratchPad.recorded.should == [:one, :two]
+ end
+end
+
+describe MSpec, ".mode?" do
+ before :each do
+ MSpec.clear_modes
+ end
+
+ it "returns true if the mode has been set" do
+ MSpec.mode?(:verify).should == false
+ MSpec.register_mode :verify
+ MSpec.mode?(:verify).should == true
+ end
+end
+
+describe MSpec, ".clear_modes" do
+ it "clears all registered modes" do
+ MSpec.register_mode(:pretend)
+ MSpec.register_mode(:verify)
+
+ MSpec.mode?(:pretend).should == true
+ MSpec.mode?(:verify).should == true
+
+ MSpec.clear_modes
+
+ MSpec.mode?(:pretend).should == false
+ MSpec.mode?(:verify).should == false
+ end
+end
+
+describe MSpec, ".guarded?" do
+ before :each do
+ MSpec.instance_variable_set :@guarded, []
+ end
+
+ it "returns false if no guard has run" do
+ MSpec.guarded?.should == false
+ end
+
+ it "returns true if a single guard has run" do
+ MSpec.guard
+ MSpec.guarded?.should == true
+ end
+
+ it "returns true if more than one guard has run" do
+ MSpec.guard
+ MSpec.guard
+ MSpec.guarded?.should == true
+ end
+
+ it "returns true until all guards have finished" do
+ MSpec.guard
+ MSpec.guard
+ MSpec.guarded?.should == true
+ MSpec.unguard
+ MSpec.guarded?.should == true
+ MSpec.unguard
+ MSpec.guarded?.should == false
+ end
+end
+
+describe MSpec, ".describe" do
+ before :each do
+ MSpec.clear_current
+ @cs = ContextState.new ""
+ ContextState.stub!(:new).and_return(@cs)
+ MSpec.stub!(:current).and_return(nil)
+ MSpec.stub!(:register_current)
+ end
+
+ it "creates a new ContextState for the block" do
+ ContextState.should_receive(:new).and_return(@cs)
+ MSpec.describe(Object) { }
+ end
+
+ it "accepts an optional second argument" do
+ ContextState.should_receive(:new).and_return(@cs)
+ MSpec.describe(Object, "msg") { }
+ end
+
+ it "registers the newly created ContextState" do
+ MSpec.should_receive(:register_current).with(@cs).twice
+ MSpec.describe(Object) { }
+ end
+
+ it "invokes the ContextState#describe method" do
+ prc = lambda { }
+ @cs.should_receive(:describe).with(&prc)
+ MSpec.describe(Object, "msg", &prc)
+ end
+end
+
+describe MSpec, ".process" do
+ before :each do
+ MSpec.stub!(:files)
+ MSpec.store :start, []
+ MSpec.store :finish, []
+ end
+
+ it "calls all start actions" do
+ start = mock("start")
+ start.stub!(:start).and_return { ScratchPad.record :start }
+ MSpec.register :start, start
+ MSpec.process
+ ScratchPad.recorded.should == :start
+ end
+
+ it "calls all finish actions" do
+ finish = mock("finish")
+ finish.stub!(:finish).and_return { ScratchPad.record :finish }
+ MSpec.register :finish, finish
+ MSpec.process
+ ScratchPad.recorded.should == :finish
+ end
+
+ it "calls the files method" do
+ MSpec.should_receive(:files)
+ MSpec.process
+ end
+end
+
+describe MSpec, ".files" do
+ before :each do
+ MSpec.store :load, []
+ MSpec.store :unload, []
+ MSpec.register_files [:one, :two, :three]
+ Kernel.stub!(:load)
+ end
+
+ it "calls load actions before each file" do
+ load = mock("load")
+ load.stub!(:load).and_return { ScratchPad.record :load }
+ MSpec.register :load, load
+ MSpec.files
+ ScratchPad.recorded.should == :load
+ end
+
+ it "shuffles the file list if .randomize? is true" do
+ MSpec.randomize
+ MSpec.should_receive(:shuffle)
+ MSpec.files
+ MSpec.randomize false
+ end
+
+ it "registers the current file" do
+ MSpec.should_receive(:store).with(:file, :one)
+ MSpec.should_receive(:store).with(:file, :two)
+ MSpec.should_receive(:store).with(:file, :three)
+ MSpec.files
+ end
+end
+
+describe MSpec, ".shuffle" do
+ before :each do
+ @base = (0..100).to_a
+ @list = @base.clone
+ MSpec.shuffle @list
+ end
+
+ it "does not alter the elements in the list" do
+ @base.each do |elt|
+ @list.should include(elt)
+ end
+ end
+
+ it "changes the order of the list" do
+ # obviously, this spec has a certain probability
+ # of failing. If it fails, run it again.
+ @list.should_not == @base
+ end
+end
+
+describe MSpec, ".tags_file" do
+ before :each do
+ MSpec.store :file, "path/to/spec/something/some_spec.rb"
+ MSpec.store :tags_patterns, nil
+ end
+
+ it "returns the default tags file for the current spec file" do
+ MSpec.tags_file.should == "path/to/spec/tags/something/some_tags.txt"
+ end
+
+ it "returns the tags file for the current spec file with custom tags_patterns" do
+ MSpec.register_tags_patterns [[/^(.*)\/spec/, '\1/tags'], [/_spec.rb/, "_tags.txt"]]
+ MSpec.tags_file.should == "path/to/tags/something/some_tags.txt"
+ end
+
+ it "performs multiple substitutions" do
+ MSpec.register_tags_patterns [
+ [%r(/spec/something/), "/spec/other/"],
+ [%r(/spec/), "/spec/tags/"],
+ [/_spec.rb/, "_tags.txt"]
+ ]
+ MSpec.tags_file.should == "path/to/spec/tags/other/some_tags.txt"
+ end
+
+ it "handles cases where no substitution is performed" do
+ MSpec.register_tags_patterns [[/nothing/, "something"]]
+ MSpec.tags_file.should == "path/to/spec/something/some_spec.rb"
+ end
+end
+
+describe MSpec, ".read_tags" do
+ before :each do
+ MSpec.stub!(:tags_file).and_return(File.dirname(__FILE__) + '/tags.txt')
+ end
+
+ it "returns a list of tag instances for matching tag names found" do
+ one = SpecTag.new "fail(broken):Some#method? works"
+ MSpec.read_tags(["fail", "pass"]).should == [one]
+ end
+
+ it "returns [] if no tags names match" do
+ MSpec.read_tags("super").should == []
+ end
+end
+
+describe MSpec, ".read_tags" do
+ before :each do
+ @tag = SpecTag.new "fails:Some#method"
+ File.open(tmp("tags.txt"), "w") do |f|
+ f.puts ""
+ f.puts @tag
+ f.puts ""
+ end
+ MSpec.stub!(:tags_file).and_return(tmp("tags.txt"))
+ end
+
+ it "does not return a tag object for empty lines" do
+ MSpec.read_tags(["fails"]).should == [@tag]
+ end
+end
+
+describe MSpec, ".write_tags" do
+ before :each do
+ FileUtils.cp File.dirname(__FILE__) + "/tags.txt", tmp("tags.txt")
+ MSpec.stub!(:tags_file).and_return(tmp("tags.txt"))
+ @tag1 = SpecTag.new "check(broken):Tag#rewrite works"
+ @tag2 = SpecTag.new "broken:Tag#write_tags fails"
+ end
+
+ after :all do
+ File.delete tmp("tags.txt") rescue nil
+ end
+
+ it "overwrites the tags in the tag file" do
+ IO.read(tmp("tags.txt")).should == %[fail(broken):Some#method? works
+incomplete(20%):The#best method ever
+benchmark(0.01825):The#fastest method today
+extended():\"Multi-line\\ntext\\ntag\"
+]
+ MSpec.write_tags [@tag1, @tag2]
+ IO.read(tmp("tags.txt")).should == %[check(broken):Tag#rewrite works
+broken:Tag#write_tags fails
+]
+ end
+end
+
+describe MSpec, ".write_tag" do
+ before :each do
+ FileUtils.stub!(:mkdir_p)
+ MSpec.stub!(:tags_file).and_return(tmp("tags.txt"))
+ @tag = SpecTag.new "fail(broken):Some#method works"
+ end
+
+ after :all do
+ File.delete tmp("tags.txt") rescue nil
+ end
+
+ it "writes a tag to the tags file for the current spec file" do
+ MSpec.write_tag @tag
+ IO.read(tmp("tags.txt")).should == "fail(broken):Some#method works\n"
+ end
+
+ it "does not write a duplicate tag" do
+ File.open(tmp("tags.txt"), "w") { |f| f.puts @tag }
+ MSpec.write_tag @tag
+ IO.read(tmp("tags.txt")).should == "fail(broken):Some#method works\n"
+ end
+end
+
+describe MSpec, ".delete_tag" do
+ before :each do
+ FileUtils.cp File.dirname(__FILE__) + "/tags.txt", tmp("tags.txt")
+ MSpec.stub!(:tags_file).and_return(tmp("tags.txt"))
+ @tag = SpecTag.new "fail(Comments don't matter):Some#method? works"
+ end
+
+ after :each do
+ File.delete tmp("tags.txt") rescue nil
+ end
+
+ it "deletes the tag if it exists" do
+ MSpec.delete_tag(@tag).should == true
+ IO.read(tmp("tags.txt")).should == %[incomplete(20%):The#best method ever
+benchmark(0.01825):The#fastest method today
+extended():\"Multi-line\\ntext\\ntag\"
+]
+ end
+
+ it "deletes a tag with escaped newlines" do
+ MSpec.delete_tag(SpecTag.new('extended:"Multi-line\ntext\ntag"')).should == true
+ IO.read(tmp("tags.txt")).should == %[fail(broken):Some#method? works
+incomplete(20%):The#best method ever
+benchmark(0.01825):The#fastest method today
+]
+ end
+
+ it "does not change the tags file contents if the tag doesn't exist" do
+ @tag.tag = "failed"
+ MSpec.delete_tag(@tag).should == false
+ IO.read(tmp("tags.txt")).should == %[fail(broken):Some#method? works
+incomplete(20%):The#best method ever
+benchmark(0.01825):The#fastest method today
+extended():\"Multi-line\\ntext\\ntag\"
+]
+ end
+
+ it "deletes the tag file if it is empty" do
+ MSpec.delete_tag(@tag).should == true
+ MSpec.delete_tag(SpecTag.new("incomplete:The#best method ever")).should == true
+ MSpec.delete_tag(SpecTag.new("benchmark:The#fastest method today")).should == true
+ MSpec.delete_tag(SpecTag.new("extended:\"Multi-line\ntext\ntag\"")).should == true
+ File.exist?(tmp("tags.txt")).should == false
+ end
+end
+
+describe MSpec, ".delete_tags" do
+ before :each do
+ @tags = tmp("tags.txt")
+ FileUtils.cp File.dirname(__FILE__) + "/tags.txt", @tags
+ MSpec.stub!(:tags_file).and_return(@tags)
+ end
+
+ it "deletes the tag file" do
+ MSpec.delete_tags
+ File.exists?(@tags).should be_false
+ end
+end
+
+describe MSpec, ".expectation" do
+ it "sets the flag that an expectation has been reported" do
+ MSpec.clear_expectations
+ MSpec.expectation?.should be_false
+ MSpec.expectation
+ MSpec.expectation?.should be_true
+ end
+end
+
+describe MSpec, ".expectation?" do
+ it "returns true if an expectation has been reported" do
+ MSpec.expectation
+ MSpec.expectation?.should be_true
+ end
+
+ it "returns false if an expectation has not been reported" do
+ MSpec.clear_expectations
+ MSpec.expectation?.should be_false
+ end
+end
+
+describe MSpec, ".clear_expectations" do
+ it "clears the flag that an expectation has been reported" do
+ MSpec.expectation
+ MSpec.expectation?.should be_true
+ MSpec.clear_expectations
+ MSpec.expectation?.should be_false
+ end
+end
+
+describe MSpec, ".register_shared" do
+ it "stores a shared ContextState by description" do
+ parent = ContextState.new "container"
+ state = ContextState.new "shared"
+ state.parent = parent
+ prc = lambda { }
+ state.describe(&prc)
+ MSpec.register_shared(state)
+ MSpec.retrieve(:shared)["shared"].should == state
+ end
+end
+
+describe MSpec, ".retrieve_shared" do
+ it "retrieves the shared ContextState matching description" do
+ state = ContextState.new ""
+ MSpec.retrieve(:shared)["shared"] = state
+ MSpec.retrieve_shared(:shared).should == state
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/shared_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/shared_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/shared_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,27 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/runner/shared'
+
+describe Object, "#it_behaves_like" do
+ before :each do
+ @recv = Object.new
+ def @recv.before(what)
+ yield
+ end
+ @recv.stub!(:it_should_behave_like)
+ end
+
+ it "creates @method set to the name of the aliased method" do
+ @recv.it_behaves_like "something", :some_method
+ @recv.instance_variable_get(:@method).should == :some_method
+ end
+
+ it "creates @object if the passed object is not nil" do
+ @recv.it_behaves_like "something", :some_method, :some_object
+ @recv.instance_variable_get(:@object).should == :some_object
+ end
+
+ it "sends :it_should_behave_like" do
+ @recv.should_receive(:it_should_behave_like)
+ @recv.it_behaves_like "something", :some_method
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/tag_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/tag_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/tag_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,111 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/runner/tag'
+
+describe SpecTag do
+ it "accepts an optional string to parse into fields" do
+ tag = SpecTag.new "tag(comment):description"
+ tag.tag.should == "tag"
+ tag.comment.should == "comment"
+ tag.description.should == "description"
+ end
+end
+
+describe SpecTag, "#parse" do
+ before :each do
+ @tag = SpecTag.new
+ end
+
+ it "accepts 'tag(comment):description'" do
+ @tag.parse "tag(I'm real):Some#method returns a value"
+ @tag.tag.should == "tag"
+ @tag.comment.should == "I'm real"
+ @tag.description.should == "Some#method returns a value"
+ end
+
+ it "accepts 'tag:description'" do
+ @tag.parse "tag:Another#method"
+ @tag.tag.should == "tag"
+ @tag.comment.should == nil
+ @tag.description.should == "Another#method"
+ end
+
+ it "accepts 'tag():description'" do
+ @tag.parse "tag():Another#method"
+ @tag.tag.should == "tag"
+ @tag.comment.should == nil
+ @tag.description.should == "Another#method"
+ end
+
+ it "accepts 'tag:'" do
+ @tag.parse "tag:"
+ @tag.tag.should == "tag"
+ @tag.comment.should == nil
+ @tag.description.should == ""
+ end
+
+ it "accepts 'tag(bug:555):Another#method'" do
+ @tag.parse "tag(bug:555):Another#method"
+ @tag.tag.should == "tag"
+ @tag.comment.should == "bug:555"
+ @tag.description.should == "Another#method"
+ end
+
+ it "accepts 'tag(http://someplace.com/neato):Another#method'" do
+ @tag.parse "tag(http://someplace.com/neato):Another#method"
+ @tag.tag.should == "tag"
+ @tag.comment.should == "http://someplace.com/neato"
+ @tag.description.should == "Another#method"
+ end
+
+ it "accepts 'tag(comment):\"Multi-line\\ntext\"'" do
+ @tag.parse 'tag(comment):"Multi-line\ntext"'
+ @tag.tag.should == "tag"
+ @tag.comment.should == "comment"
+ @tag.description.should == "Multi-line\ntext"
+ end
+
+ it "ignores '#anything'" do
+ @tag.parse "# this could be a comment"
+ @tag.tag.should == nil
+ @tag.comment.should == nil
+ @tag.description.should == nil
+ end
+end
+
+describe SpecTag, "#to_s" do
+ it "formats itself as 'tag(comment):description'" do
+ txt = "tag(comment):description"
+ tag = SpecTag.new txt
+ tag.tag.should == "tag"
+ tag.comment.should == "comment"
+ tag.description.should == "description"
+ tag.to_s.should == txt
+ end
+
+ it "formats itself as 'tag:description" do
+ txt = "tag:description"
+ tag = SpecTag.new txt
+ tag.tag.should == "tag"
+ tag.comment.should == nil
+ tag.description.should == "description"
+ tag.to_s.should == txt
+ end
+
+ it "formats itself as 'tag(comment):\"multi-line\\ntext\\ntag\"'" do
+ txt = 'tag(comment):"multi-line\ntext\ntag"'
+ tag = SpecTag.new txt
+ tag.tag.should == "tag"
+ tag.comment.should == "comment"
+ tag.description.should == "multi-line\ntext\ntag"
+ tag.to_s.should == txt
+ end
+end
+
+describe SpecTag, "#==" do
+ it "returns true if the tags have the same fields" do
+ one = SpecTag.new "tag(this):unicorn"
+ two = SpecTag.new "tag(this):unicorn"
+ one.==(two).should == true
+ [one].==([two]).should == true
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/runner/tags.txt
===================================================================
--- MacRuby/branches/experimental/mspec/spec/runner/tags.txt (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/runner/tags.txt 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,4 @@
+fail(broken):Some#method? works
+incomplete(20%):The#best method ever
+benchmark(0.01825):The#fastest method today
+extended():"Multi-line\ntext\ntag"
Added: MacRuby/branches/experimental/mspec/spec/spec_helper.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/spec_helper.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/spec_helper.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,43 @@
+dir_path = File.dirname(__FILE__)
+lib_path = File.expand_path(dir_path + '/../lib')
+bin_path = File.expand_path(dir_path + '/..')
+$:.unshift lib_path unless $:.include? lib_path
+$:.unshift bin_path unless $:.include? bin_path
+
+require 'pp'
+require 'mspec/helpers/io'
+require 'mspec/helpers/scratch'
+
+# Remove this when MRI has intelligent warnings
+$VERBOSE = nil unless $VERBOSE
+
+class MOSConfig < Hash
+ def initialize
+ self[:includes] = []
+ self[:requires] = []
+ self[:flags] = []
+ self[:options] = []
+ self[:includes] = []
+ self[:excludes] = []
+ self[:patterns] = []
+ self[:xpatterns] = []
+ self[:tags] = []
+ self[:xtags] = []
+ self[:atags] = []
+ self[:astrings] = []
+ self[:target] = 'ruby'
+ self[:command] = nil
+ self[:ltags] = []
+ self[:files] = []
+ end
+end
+
+def new_option
+ config = MOSConfig.new
+ return MSpecOptions.new("spec", 20, config), config
+end
+
+# Just to have an exception name output not be "Exception"
+class MSpecExampleError < Exception
+end
+
Added: MacRuby/branches/experimental/mspec/spec/utils/name_map_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/utils/name_map_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/utils/name_map_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,178 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/utils/name_map'
+
+module NameMapSpecs
+ class A
+ A = self
+
+ def self.a; end
+ def a; end
+ def c; end
+
+ class B
+ def b; end
+ end
+ end
+
+ class Error
+ end
+
+ class Fixnum
+ def f; end
+ end
+
+ def self.n; end
+ def n; end
+end
+
+describe NameMap, "#exception?" do
+ before :each do
+ @map = NameMap.new
+ end
+
+ it "returns true if the constant is Errno" do
+ @map.exception?("Errno").should == true
+ end
+
+ it "returns true if the constant is a kind of Exception" do
+ @map.exception?("Errno::EBADF").should == true
+ @map.exception?("LoadError").should == true
+ @map.exception?("SystemExit").should == true
+ end
+
+ it "returns false if the constant is not a kind of Exception" do
+ @map.exception?("NameMapSpecs::Error").should == false
+ @map.exception?("NameMapSpecs").should == false
+ end
+
+ it "returns false if the constant does not exist" do
+ @map.exception?("Nonexistent").should == false
+ end
+end
+
+describe NameMap, "#class_or_module" do
+ before :each do
+ @map = NameMap.new true
+ end
+
+ it "returns the constant specified by the string" do
+ @map.class_or_module("NameMapSpecs").should == NameMapSpecs
+ end
+
+ it "returns the constant specified by the 'A::B' string" do
+ @map.class_or_module("NameMapSpecs::A").should == NameMapSpecs::A
+ end
+
+ it "returns nil if the constant is not a class or module" do
+ @map.class_or_module("Float::MAX").should == nil
+ end
+
+ it "returns nil if the constant is in the set of excluded constants" do
+ excluded = %w[
+ MSpecScript
+ MkSpec
+ DTracer
+ NameMap
+ OptionParser
+ YAML
+ ]
+
+ excluded.each do |const|
+ @map.class_or_module(const).should == nil
+ end
+ end
+
+ it "returns nil if the constant does not exist" do
+ @map.class_or_module("Heaven").should == nil
+ @map.class_or_module("Hell").should == nil
+ @map.class_or_module("Bush::Brain").should == nil
+ end
+end
+
+describe NameMap, "#dir_name" do
+ before :each do
+ @map = NameMap.new
+ end
+
+ it "returns a directory name from the base name and constant" do
+ @map.dir_name("NameMapSpecs", 'spec/core').should == 'spec/core/namemapspecs'
+ end
+
+ it "returns a directory name from the components in the constants name" do
+ @map.dir_name("NameMapSpecs::A", 'spec').should == 'spec/namemapspecs/a'
+ @map.dir_name("NameMapSpecs::A::B", 'spec').should == 'spec/namemapspecs/a/b'
+ end
+
+ it "returns a directory name without 'class' for constants like TrueClass" do
+ @map.dir_name("TrueClass", 'spec').should == 'spec/true'
+ @map.dir_name("FalseClass", 'spec').should == 'spec/false'
+ end
+
+ it "returns 'exception' for the directory name of any Exception subclass" do
+ @map.dir_name("SystemExit", 'spec').should == 'spec/exception'
+ @map.dir_name("Errno::EBADF", 'spec').should == 'spec/exception'
+ end
+
+ it "returns 'class' for Class" do
+ @map.dir_name("Class", 'spec').should == 'spec/class'
+ end
+end
+
+# These specs do not cover all the mappings, but only describe how the
+# name is derived when the hash item maps to a single value, a hash with
+# a specific item, or a hash with a :default item.
+describe NameMap, "#file_name" do
+ before :each do
+ @map = NameMap.new
+ end
+
+ it "returns the name of the spec file based on the constant and method" do
+ @map.file_name("[]=", "Array").should == "element_set_spec.rb"
+ end
+
+ it "returns the name of the spec file based on the special entry for the method" do
+ @map.file_name("~", "Regexp").should == "match_spec.rb"
+ @map.file_name("~", "Fixnum").should == "complement_spec.rb"
+ end
+
+ it "returns the name of the spec file based on the default entry for the method" do
+ @map.file_name("<<", "NameMapSpecs").should == "append_spec.rb"
+ end
+
+ it "uses the last component of the constant to look up the method name" do
+ @map.file_name("^", "NameMapSpecs::Fixnum").should == "bit_xor_spec.rb"
+ end
+end
+
+describe NameMap, "#namespace" do
+ before :each do
+ @map = NameMap.new
+ end
+
+ it "prepends the module to the constant name" do
+ @map.namespace("SubModule", Fixnum).should == "SubModule::Fixnum"
+ end
+
+ it "does not prepend Object, Class, or Module to the constant name" do
+ @map.namespace("Object", Fixnum).should == "Fixnum"
+ @map.namespace("Module", Integer).should == "Integer"
+ @map.namespace("Class", Float).should == "Float"
+ end
+end
+
+describe NameMap, "#map" do
+ before :each do
+ @map = NameMap.new
+ end
+
+ it "flattens an object hierarchy into a single Hash" do
+ @map.map({}, [NameMapSpecs]).should == {
+ "NameMapSpecs." => ["n"],
+ "NameMapSpecs#" => ["n"],
+ "NameMapSpecs::A." => ["a"],
+ "NameMapSpecs::A#" => ["a", "c"],
+ "NameMapSpecs::A::B#" => ["b"],
+ "NameMapSpecs::Fixnum#" => ["f"]
+ }
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/utils/options_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/utils/options_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/utils/options_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,1291 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/utils/options'
+require 'mspec/version'
+require 'mspec/guards/guard'
+require 'mspec/runner/mspec'
+require 'mspec/runner/formatters'
+
+describe MSpecOption, ".new" do
+ before :each do
+ @opt = MSpecOption.new("-a", "--bdc", "ARG", "desc", :block)
+ end
+
+ it "sets the short attribute" do
+ @opt.short.should == "-a"
+ end
+
+ it "sets the long attribute" do
+ @opt.long.should == "--bdc"
+ end
+
+ it "sets the arg attribute" do
+ @opt.arg.should == "ARG"
+ end
+
+ it "sets the description attribute" do
+ @opt.description.should == "desc"
+ end
+
+ it "sets the block attribute" do
+ @opt.block.should == :block
+ end
+end
+
+describe MSpecOption, "#arg?" do
+ it "returns true if arg attribute is not nil" do
+ MSpecOption.new(nil, nil, "ARG", nil, nil).arg?.should be_true
+ end
+
+ it "returns false if arg attribute is nil" do
+ MSpecOption.new(nil, nil, nil, nil, nil).arg?.should be_false
+ end
+end
+
+describe MSpecOption, "#match?" do
+ before :each do
+ @opt = MSpecOption.new("-a", "--bdc", "ARG", "desc", :block)
+ end
+
+ it "returns true if the argument matches the short option" do
+ @opt.match?("-a").should be_true
+ end
+
+ it "returns true if the argument matches the long option" do
+ @opt.match?("--bdc").should be_true
+ end
+
+ it "returns false if the argument matches neither the short nor long option" do
+ @opt.match?("-b").should be_false
+ @opt.match?("-abdc").should be_false
+ end
+end
+
+describe MSpecOptions, ".new" do
+ before :each do
+ @opt = MSpecOptions.new("cmd", 20, :config)
+ end
+
+ it "sets the banner attribute" do
+ @opt.banner.should == "cmd"
+ end
+
+ it "sets the config attribute" do
+ @opt.config.should == :config
+ end
+
+ it "sets the width attribute" do
+ @opt.width.should == 20
+ end
+
+ it "sets the default width attribute" do
+ MSpecOptions.new.width.should == 30
+ end
+end
+
+describe MSpecOptions, "#on" do
+ before :each do
+ @opt = MSpecOptions.new
+ end
+
+ it "adds a short option" do
+ @opt.should_receive(:add).with("-a", nil, nil, "desc", nil)
+ @opt.on("-a", "desc")
+ end
+
+ it "adds a short option taking an argument" do
+ @opt.should_receive(:add).with("-a", nil, "ARG", "desc", nil)
+ @opt.on("-a", "ARG", "desc")
+ end
+
+ it "adds a long option" do
+ @opt.should_receive(:add).with("-a", nil, nil, "desc", nil)
+ @opt.on("-a", "desc")
+ end
+
+ it "adds a long option taking an argument" do
+ @opt.should_receive(:add).with("-a", nil, nil, "desc", nil)
+ @opt.on("-a", "desc")
+ end
+
+ it "adds a short and long option" do
+ @opt.should_receive(:add).with("-a", nil, nil, "desc", nil)
+ @opt.on("-a", "desc")
+ end
+
+ it "adds a short and long option taking an argument" do
+ @opt.should_receive(:add).with("-a", nil, nil, "desc", nil)
+ @opt.on("-a", "desc")
+ end
+
+ it "raises MSpecOptions::OptionError if pass less than 2 arguments" do
+ lambda { @opt.on }.should raise_error(MSpecOptions::OptionError)
+ lambda { @opt.on "" }.should raise_error(MSpecOptions::OptionError)
+ end
+end
+
+describe MSpecOptions, "#add" do
+ before :each do
+ @opt = MSpecOptions.new "cmd", 20
+ @prc = lambda { }
+ end
+
+ it "adds documentation for an option" do
+ @opt.should_receive(:doc).with(" -t, --typo ARG Correct typo ARG")
+ @opt.add("-t", "--typo", "ARG", "Correct typo ARG", @prc)
+ end
+
+ it "leaves spaces in the documentation for a missing short option" do
+ @opt.should_receive(:doc).with(" --typo ARG Correct typo ARG")
+ @opt.add(nil, "--typo", "ARG", "Correct typo ARG", @prc)
+ end
+
+ it "handles a short option with argument but no long argument" do
+ @opt.should_receive(:doc).with(" -t ARG Correct typo ARG")
+ @opt.add("-t", nil, "ARG", "Correct typo ARG", @prc)
+ end
+
+ it "registers an option" do
+ option = MSpecOption.new "-t", "--typo", "ARG", "Correct typo ARG", @prc
+ MSpecOption.should_receive(:new).with(
+ "-t", "--typo", "ARG", "Correct typo ARG", @prc).and_return(option)
+ @opt.add("-t", "--typo", "ARG", "Correct typo ARG", @prc)
+ @opt.options.should == [option]
+ end
+end
+
+describe MSpecOptions, "#match?" do
+ before :each do
+ @opt = MSpecOptions.new
+ end
+
+ it "returns the MSpecOption instance matching the argument" do
+ @opt.on "-a", "--abdc", "desc"
+ option = @opt.match? "-a"
+ @opt.match?("--abdc").should be(option)
+ option.should be_kind_of(MSpecOption)
+ option.short.should == "-a"
+ option.long.should == "--abdc"
+ option.description.should == "desc"
+ end
+end
+
+describe MSpecOptions, "#process" do
+ before :each do
+ @opt = MSpecOptions.new
+ ScratchPad.clear
+ end
+
+ it "calls the on_extra block if the argument does not match any option" do
+ @opt.on_extra { ScratchPad.record :extra }
+ @opt.process ["-a"], "-a", "-a", nil
+ ScratchPad.recorded.should == :extra
+ end
+
+ it "returns the matching option" do
+ @opt.on "-a", "ARG", "desc"
+ option = @opt.process [], "-a", "-a", "ARG"
+ option.should be_kind_of(MSpecOption)
+ option.short.should == "-a"
+ option.arg.should == "ARG"
+ option.description.should == "desc"
+ end
+
+ it "raises an MSpecOptions::ParseError if arg is nil and there are no more entries in argv" do
+ @opt.on "-a", "ARG", "desc"
+ lambda { @opt.process [], "-a", "-a", nil }.should raise_error(MSpecOptions::ParseError)
+ end
+
+ it "fetches the argument for the option from argv if arg is nil" do
+ @opt.on("-a", "ARG", "desc") { |o| ScratchPad.record o }
+ @opt.process ["ARG"], "-a", "-a", nil
+ ScratchPad.recorded.should == "ARG"
+ end
+
+ it "calls the option's block" do
+ @opt.on("-a", "ARG", "desc") { ScratchPad.record :option }
+ @opt.process [], "-a", "-a", "ARG"
+ ScratchPad.recorded.should == :option
+ end
+
+ it "does not call the option's block if it is nil" do
+ @opt.on "-a", "ARG", "desc"
+ lambda { @opt.process [], "-a", "-a", "ARG" }.should_not raise_error
+ end
+end
+
+describe MSpecOptions, "#split" do
+ before :each do
+ @opt = MSpecOptions.new
+ end
+
+ it "breaks a string at the nth character" do
+ opt, arg, rest = @opt.split "-bdc", 2
+ opt.should == "-b"
+ arg.should == "dc"
+ rest.should == "dc"
+ end
+
+ it "returns nil for arg if there are no characters left" do
+ opt, arg, rest = @opt.split "-b", 2
+ opt.should == "-b"
+ arg.should == nil
+ rest.should == ""
+ end
+end
+
+describe MSpecOptions, "#parse" do
+ before :each do
+ @opt = MSpecOptions.new
+ @prc = lambda { |o| ScratchPad.record [:parsed, o] }
+ ScratchPad.clear
+ end
+
+ it "parses a short option" do
+ @opt.on "-a", "desc", &@prc
+ @opt.parse ["-a"]
+ ScratchPad.recorded.should == [:parsed, nil]
+ end
+
+ it "parse a long option" do
+ @opt.on "--abdc", "desc", &@prc
+ @opt.parse ["--abdc"]
+ ScratchPad.recorded.should == [:parsed, nil]
+ end
+
+ it "parses a short option group" do
+ @opt.on "-a", "ARG", "desc", &@prc
+ @opt.parse ["-a", "ARG"]
+ ScratchPad.recorded.should == [:parsed, "ARG"]
+ end
+
+ it "parses a short option with an argument" do
+ @opt.on "-a", "ARG", "desc", &@prc
+ @opt.parse ["-a", "ARG"]
+ ScratchPad.recorded.should == [:parsed, "ARG"]
+ end
+
+ it "parses a short option with connected argument" do
+ @opt.on "-a", "ARG", "desc", &@prc
+ @opt.parse ["-aARG"]
+ ScratchPad.recorded.should == [:parsed, "ARG"]
+ end
+
+ it "parses a long option with an argument" do
+ @opt.on "--abdc", "ARG", "desc", &@prc
+ @opt.parse ["--abdc", "ARG"]
+ ScratchPad.recorded.should == [:parsed, "ARG"]
+ end
+
+ it "parses a long option with an '=' argument" do
+ @opt.on "--abdc", "ARG", "desc", &@prc
+ @opt.parse ["--abdc=ARG"]
+ ScratchPad.recorded.should == [:parsed, "ARG"]
+ end
+
+ it "parses a short option group with the final option taking an argument" do
+ ScratchPad.record []
+ @opt.on("-a", "desc") { |o| ScratchPad << :a }
+ @opt.on("-b", "ARG", "desc") { |o| ScratchPad << [:b, o] }
+ @opt.parse ["-ab", "ARG"]
+ ScratchPad.recorded.should == [:a, [:b, "ARG"]]
+ end
+
+ it "parses a short option group with a connected argument" do
+ ScratchPad.record []
+ @opt.on("-a", "desc") { |o| ScratchPad << :a }
+ @opt.on("-b", "ARG", "desc") { |o| ScratchPad << [:b, o] }
+ @opt.on("-c", "desc") { |o| ScratchPad << :c }
+ @opt.parse ["-acbARG"]
+ ScratchPad.recorded.should == [:a, :c, [:b, "ARG"]]
+ end
+
+ it "returns the unprocessed entries" do
+ @opt.on "-a", "ARG", "desc", &@prc
+ @opt.parse(["abdc", "-a", "ilny"]).should == ["abdc"]
+ end
+
+ it "calls the on_extra handler with unrecognized options" do
+ ScratchPad.record []
+ @opt.on_extra { |o| ScratchPad << o }
+ @opt.on "-a", "desc"
+ @opt.parse ["-a", "-b"]
+ ScratchPad.recorded.should == ["-b"]
+ end
+
+ it "does not attempt to call the block if it is nil" do
+ @opt.on "-a", "ARG", "desc"
+ @opt.parse(["-a", "ARG"]).should == []
+ end
+
+ it "raises MSpecOptions::ParseError if passed an unrecognized option" do
+ @opt.should_receive(:raise).with(MSpecOptions::ParseError, an_instance_of(String))
+ @opt.stub!(:puts)
+ @opt.stub!(:exit)
+ @opt.parse "-u"
+ end
+end
+
+describe MSpecOptions, "#banner=" do
+ before :each do
+ @opt = MSpecOptions.new
+ end
+
+ it "sets the banner attribute" do
+ @opt.banner.should == ""
+ @opt.banner = "banner"
+ @opt.banner.should == "banner"
+ end
+end
+
+describe MSpecOptions, "#width=" do
+ before :each do
+ @opt = MSpecOptions.new
+ end
+
+ it "sets the width attribute" do
+ @opt.width.should == 30
+ @opt.width = 20
+ @opt.width.should == 20
+ end
+end
+
+describe MSpecOptions, "#config=" do
+ before :each do
+ @opt = MSpecOptions.new
+ end
+
+ it "sets the config attribute" do
+ @opt.config.should be_nil
+ @opt.config = :config
+ @opt.config.should == :config
+ end
+end
+
+describe MSpecOptions, "#doc" do
+ before :each do
+ @opt = MSpecOptions.new "command"
+ end
+
+ it "adds text to be displayed with #to_s" do
+ @opt.doc "Some message"
+ @opt.doc "Another message"
+ @opt.to_s.should == <<-EOD
+command
+
+Some message
+Another message
+EOD
+ end
+end
+
+describe MSpecOptions, "#version" do
+ before :each do
+ @opt = MSpecOptions.new
+ ScratchPad.clear
+ end
+
+ it "installs a basic -v, --version option" do
+ @opt.should_receive(:puts)
+ @opt.should_receive(:exit)
+ @opt.version "1.0.0"
+ @opt.parse "-v"
+ end
+
+ it "accepts a block instead of using the default block" do
+ @opt.version("1.0.0") { |o| ScratchPad.record :version }
+ @opt.parse "-v"
+ ScratchPad.recorded.should == :version
+ end
+end
+
+describe MSpecOptions, "#help" do
+ before :each do
+ @opt = MSpecOptions.new
+ ScratchPad.clear
+ end
+
+ it "installs a basic -h, --help option" do
+ @opt.should_receive(:puts)
+ @opt.should_receive(:exit).with(1)
+ @opt.help
+ @opt.parse "-h"
+ end
+
+ it "accepts a block instead of using the default block" do
+ @opt.help { |o| ScratchPad.record :help }
+ @opt.parse "-h"
+ ScratchPad.recorded.should == :help
+ end
+end
+
+describe MSpecOptions, "#on_extra" do
+ before :each do
+ @opt = MSpecOptions.new
+ ScratchPad.clear
+ end
+
+ it "registers a block to be called when an option is not recognized" do
+ @opt.on_extra { ScratchPad.record :extra }
+ @opt.parse "-g"
+ ScratchPad.recorded.should == :extra
+ end
+end
+
+describe MSpecOptions, "#to_s" do
+ before :each do
+ @opt = MSpecOptions.new "command"
+ end
+
+ it "returns the banner and descriptive strings for all registered options" do
+ @opt.on "-t", "--this ARG", "Adds this ARG to the list"
+ @opt.to_s.should == <<-EOD
+command
+
+ -t, --this ARG Adds this ARG to the list
+EOD
+ end
+end
+
+describe "The -B, --config FILE option" do
+ before :each do
+ @options, @config = new_option
+ end
+
+ it "is enabled with #configure { }" do
+ @options.should_receive(:on).with("-B", "--config", "FILE",
+ an_instance_of(String))
+ @options.configure {}
+ end
+
+ it "calls the passed block" do
+ ["-B", "--config"].each do |opt|
+ ScratchPad.clear
+
+ @options.configure { |x| ScratchPad.record x }
+ @options.parse [opt, "file"]
+ ScratchPad.recorded.should == "file"
+ end
+ end
+end
+
+describe "The -C, --chdir DIR option" do
+ before :each do
+ @options, @config = new_option
+ @options.chdir
+ end
+
+ it "is enabled with #chdir" do
+ @options.should_receive(:on).with("-C", "--chdir", "DIR",
+ an_instance_of(String))
+ @options.chdir
+ end
+
+ it "changes the working directory to DIR" do
+ Dir.should_receive(:chdir).with("dir").twice
+ ["-C", "--chdir"].each do |opt|
+ @options.parse [opt, "dir"]
+ end
+ end
+end
+
+describe "The --prefix STR option" do
+ before :each do
+ @options, @config = new_option
+ end
+
+ it "is enabled with #prefix" do
+ @options.should_receive(:on).with("--prefix", "STR",
+ an_instance_of(String))
+ @options.prefix
+ end
+
+ it "sets the prefix config value" do
+ @options.prefix
+ @options.parse ["--prefix", "some/dir"]
+ @config[:prefix].should == "some/dir"
+ end
+end
+
+describe "The -n, --name RUBY_NAME option" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ @options, @config = new_option
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it "is enabled with #name" do
+ @options.should_receive(:on).with("-n", "--name", "RUBY_NAME",
+ an_instance_of(String))
+ @options.name
+ end
+
+ it "sets RUBY_NAME when invoked" do
+ Object.should_receive(:const_set).with(:RUBY_NAME, "name").twice
+ @options.name
+ @options.parse ["-n", "name"]
+ @options.parse ["--name", "name"]
+ end
+end
+
+describe "The -t, --target TARGET option" do
+ before :each do
+ @options, @config = new_option
+ @options.targets
+ end
+
+ it "is enabled with #targets" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-t", "--target", "TARGET",
+ an_instance_of(String))
+ @options.targets
+ end
+
+ it "sets the target to 'ruby' and flags to verbose with TARGET 'ruby'" do
+ ["-t", "--target"].each do |opt|
+ @options.parse [opt, "ruby"]
+ @config[:target].should == "ruby"
+ end
+ end
+
+ it "sets the target to 'ruby1.9' with TARGET 'r19', 'ruby19' or 'ruby1.9'" do
+ ["-t", "--target"].each do |opt|
+ ["r19", "ruby19", "ruby1.9"].each do |t|
+ @options.parse [opt, t]
+ @config[:target].should == "ruby1.9"
+ end
+ end
+ end
+
+ it "sets the target to 'jruby' with TARGET 'j' or 'jruby'" do
+ ["-t", "--target"].each do |opt|
+ ["j", "jruby"].each do |t|
+ @options.parse [opt, t]
+ @config[:target].should == "jruby"
+ end
+ end
+ end
+
+ it "sets the target to 'shotgun/rubinius' with TARGET 'x' or 'rubinius'" do
+ ["-t", "--target"].each do |opt|
+ ["x", "rubinius"].each do |t|
+ @options.parse [opt, t]
+ @config[:target].should == "./bin/rbx"
+ end
+ end
+ end
+
+ it "set the target to 'rbx' with TARGET 'rbx'" do
+ ["-t", "--target"].each do |opt|
+ ["X", "rbx"].each do |t|
+ @options.parse [opt, t]
+ @config[:target].should == "rbx"
+ end
+ end
+ end
+
+ it "sets the target to TARGET" do
+ ["-t", "--target"].each do |opt|
+ @options.parse [opt, "whateva"]
+ @config[:target].should == "whateva"
+ end
+ end
+end
+
+describe "The -T, --target-opt OPT option" do
+ before :each do
+ @options, @config = new_option
+ @options.targets
+ end
+
+ it "is enabled with #targets" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-T", "--target-opt", "OPT",
+ an_instance_of(String))
+ @options.targets
+ end
+
+ it "adds OPT to flags" do
+ ["-T", "--target-opt"].each do |opt|
+ @config[:flags].delete "--whateva"
+ @options.parse [opt, "--whateva"]
+ @config[:flags].should include("--whateva")
+ end
+ end
+end
+
+describe "The -I, --include DIR option" do
+ before :each do
+ @options, @config = new_option
+ @options.targets
+ end
+
+ it "is enabled with #targets" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-I", "--include", "DIR",
+ an_instance_of(String))
+ @options.targets
+ end
+
+ it "add DIR to the includes list" do
+ ["-I", "--include"].each do |opt|
+ @config[:includes].delete "-Ipackage"
+ @options.parse [opt, "package"]
+ @config[:includes].should include("-Ipackage")
+ end
+ end
+end
+
+describe "The -r, --require LIBRARY option" do
+ before :each do
+ @options, @config = new_option
+ @options.targets
+ end
+
+ it "is enabled with #targets" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-r", "--require", "LIBRARY",
+ an_instance_of(String))
+ @options.targets
+ end
+
+ it "adds LIBRARY to the requires list" do
+ ["-r", "--require"].each do |opt|
+ @config[:requires].delete "-rlibrick"
+ @options.parse [opt, "librick"]
+ @config[:requires].should include("-rlibrick")
+ end
+ end
+end
+
+describe "The -f, --format FORMAT option" do
+ before :each do
+ @options, @config = new_option
+ @options.formatters
+ end
+
+ it "is enabled with #formatters" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-f", "--format", "FORMAT",
+ an_instance_of(String))
+ @options.formatters
+ end
+
+ it "sets the SpecdocFormatter with FORMAT 's' or 'specdoc'" do
+ ["-f", "--format"].each do |opt|
+ ["s", "specdoc"].each do |f|
+ @config[:formatter] = nil
+ @options.parse [opt, f]
+ @config[:formatter].should == SpecdocFormatter
+ end
+ end
+ end
+
+ it "sets the HtmlFormatter with FORMAT 'h' or 'html'" do
+ ["-f", "--format"].each do |opt|
+ ["h", "html"].each do |f|
+ @config[:formatter] = nil
+ @options.parse [opt, f]
+ @config[:formatter].should == HtmlFormatter
+ end
+ end
+ end
+
+ it "sets the DottedFormatter with FORMAT 'd', 'dot' or 'dotted'" do
+ ["-f", "--format"].each do |opt|
+ ["d", "dot", "dotted"].each do |f|
+ @config[:formatter] = nil
+ @options.parse [opt, f]
+ @config[:formatter].should == DottedFormatter
+ end
+ end
+ end
+
+ it "sets the DescribeFormatter with FORMAT 'b' or 'describe'" do
+ ["-f", "--format"].each do |opt|
+ ["b", "describe"].each do |f|
+ @config[:formatter] = nil
+ @options.parse [opt, f]
+ @config[:formatter].should == DescribeFormatter
+ end
+ end
+ end
+
+ it "sets the FileFormatter with FORMAT 'f', 'file'" do
+ ["-f", "--format"].each do |opt|
+ ["f", "file"].each do |f|
+ @config[:formatter] = nil
+ @options.parse [opt, f]
+ @config[:formatter].should == FileFormatter
+ end
+ end
+ end
+
+ it "sets the UnitdiffFormatter with FORMAT 'u', 'unit', or 'unitdiff'" do
+ ["-f", "--format"].each do |opt|
+ ["u", "unit", "unitdiff"].each do |f|
+ @config[:formatter] = nil
+ @options.parse [opt, f]
+ @config[:formatter].should == UnitdiffFormatter
+ end
+ end
+ end
+
+ it "sets the SummaryFormatter with FORMAT 'm' or 'summary'" do
+ ["-f", "--format"].each do |opt|
+ ["m", "summary"].each do |f|
+ @config[:formatter] = nil
+ @options.parse [opt, f]
+ @config[:formatter].should == SummaryFormatter
+ end
+ end
+ end
+
+ it "sets the SpinnerFormatter with FORMAT 'a', '*', or 'spin'" do
+ ["-f", "--format"].each do |opt|
+ ["a", "*", "spin"].each do |f|
+ @config[:formatter] = nil
+ @options.parse [opt, f]
+ @config[:formatter].should == SpinnerFormatter
+ end
+ end
+ end
+
+ it "sets the MethodFormatter with FORMAT 't' or 'method'" do
+ ["-f", "--format"].each do |opt|
+ ["t", "method"].each do |f|
+ @config[:formatter] = nil
+ @options.parse [opt, f]
+ @config[:formatter].should == MethodFormatter
+ end
+ end
+ end
+
+ it "sets the YamlFormatter with FORMAT 'y' or 'yaml'" do
+ ["-f", "--format"].each do |opt|
+ ["y", "yaml"].each do |f|
+ @config[:formatter] = nil
+ @options.parse [opt, f]
+ @config[:formatter].should == YamlFormatter
+ end
+ end
+ end
+end
+
+describe "The -o, --output FILE option" do
+ before :each do
+ @options, @config = new_option
+ @options.formatters
+ end
+
+ it "is enabled with #formatters" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-o", "--output", "FILE",
+ an_instance_of(String))
+ @options.formatters
+ end
+
+ it "sets the output to FILE" do
+ ["-o", "--output"].each do |opt|
+ @config[:output] = nil
+ @options.parse [opt, "some/file"]
+ @config[:output].should == "some/file"
+ end
+ end
+end
+
+describe "The -e, --example STR" do
+ before :each do
+ @options, @config = new_option
+ @options.filters
+ end
+
+ it "is enabled with #filters" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-e", "--example", "STR",
+ an_instance_of(String))
+ @options.filters
+ end
+
+ it "adds STR to the includes list" do
+ ["-e", "--example"].each do |opt|
+ @config[:includes] = []
+ @options.parse [opt, "this spec"]
+ @config[:includes].should include("this spec")
+ end
+ end
+end
+
+describe "The -E, --exclude STR" do
+ before :each do
+ @options, @config = new_option
+ @options.filters
+ end
+
+ it "is enabled with #filters" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-E", "--exclude", "STR",
+ an_instance_of(String))
+ @options.filters
+ end
+
+ it "adds STR to the excludes list" do
+ ["-E", "--exclude"].each do |opt|
+ @config[:excludes] = []
+ @options.parse [opt, "this spec"]
+ @config[:excludes].should include("this spec")
+ end
+ end
+end
+
+describe "The -p, --pattern PATTERN" do
+ before :each do
+ @options, @config = new_option
+ @options.filters
+ end
+
+ it "is enabled with #filters" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-p", "--pattern", "PATTERN",
+ an_instance_of(String))
+ @options.filters
+ end
+
+ it "adds PATTERN to the included patterns list" do
+ ["-p", "--pattern"].each do |opt|
+ @config[:patterns] = []
+ @options.parse [opt, "this spec"]
+ @config[:patterns].should include(/this spec/)
+ end
+ end
+end
+
+describe "The -P, --excl-pattern PATTERN" do
+ before :each do
+ @options, @config = new_option
+ @options.filters
+ end
+
+ it "is enabled with #filters" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-P", "--excl-pattern", "PATTERN",
+ an_instance_of(String))
+ @options.filters
+ end
+
+ it "adds PATTERN to the excluded patterns list" do
+ ["-P", "--excl-pattern"].each do |opt|
+ @config[:xpatterns] = []
+ @options.parse [opt, "this spec"]
+ @config[:xpatterns].should include(/this spec/)
+ end
+ end
+end
+
+describe "The -g, --tag TAG" do
+ before :each do
+ @options, @config = new_option
+ @options.filters
+ end
+
+ it "is enabled with #filters" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-g", "--tag", "TAG",
+ an_instance_of(String))
+ @options.filters
+ end
+
+ it "adds TAG to the included tags list" do
+ ["-g", "--tag"].each do |opt|
+ @config[:tags] = []
+ @options.parse [opt, "this spec"]
+ @config[:tags].should include("this spec")
+ end
+ end
+end
+
+describe "The -G, --excl-tag TAG" do
+ before :each do
+ @options, @config = new_option
+ @options.filters
+ end
+
+ it "is enabled with #filters" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-G", "--excl-tag", "TAG",
+ an_instance_of(String))
+ @options.filters
+ end
+
+ it "adds TAG to the excluded tags list" do
+ ["-G", "--excl-tag"].each do |opt|
+ @config[:xtags] = []
+ @options.parse [opt, "this spec"]
+ @config[:xtags].should include("this spec")
+ end
+ end
+end
+
+describe "The -w, --profile FILE option" do
+ before :each do
+ @options, @config = new_option
+ @options.filters
+ end
+
+ it "is enabled with #filters" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-w", "--profile", "FILE",
+ an_instance_of(String))
+ @options.filters
+ end
+
+ it "adds FILE to the included profiles list" do
+ ["-w", "--profile"].each do |opt|
+ @config[:profiles] = []
+ @options.parse [opt, "spec/profiles/rails.yaml"]
+ @config[:profiles].should include("spec/profiles/rails.yaml")
+ end
+ end
+end
+
+describe "The -W, --excl-profile FILE option" do
+ before :each do
+ @options, @config = new_option
+ @options.filters
+ end
+
+ it "is enabled with #filters" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-W", "--excl-profile", "FILE",
+ an_instance_of(String))
+ @options.filters
+ end
+
+ it "adds FILE to the excluded profiles list" do
+ ["-W", "--excl-profile"].each do |opt|
+ @config[:xprofiles] = []
+ @options.parse [opt, "spec/profiles/rails.yaml"]
+ @config[:xprofiles].should include("spec/profiles/rails.yaml")
+ end
+ end
+end
+
+describe "The -Z, --dry-run option" do
+ before :each do
+ @options, @config = new_option
+ @options.pretend
+ end
+
+ it "is enabled with #pretend" do
+ @options.should_receive(:on).with("-Z", "--dry-run", an_instance_of(String))
+ @options.pretend
+ end
+
+ it "registers the MSpec pretend mode" do
+ MSpec.should_receive(:register_mode).with(:pretend).twice
+ ["-Z", "--dry-run"].each do |opt|
+ @options.parse opt
+ end
+ end
+end
+
+describe "The --background option" do
+ before :each do
+ @options, @config = new_option
+ end
+
+ it "is enabled with #background" do
+ @options.should_receive(:on).with("--background", an_instance_of(String))
+ @options.background
+ end
+
+ it "registers the MSpec background mode" do
+ MSpec.should_receive(:register_mode).with(:background)
+ @options.background
+ @options.parse "--background"
+ end
+end
+
+describe "The --unguarded option" do
+ before :each do
+ @options, @config = new_option
+ @options.unguarded
+ end
+
+ it "is enabled with #unguarded" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("--unguarded", an_instance_of(String))
+ @options.unguarded
+ end
+
+ it "registers the MSpec unguarded mode" do
+ MSpec.should_receive(:register_mode).with(:unguarded)
+ @options.parse "--unguarded"
+ end
+end
+
+describe "The --no-ruby_guard option" do
+ before :each do
+ @options, @config = new_option
+ @options.unguarded
+ end
+
+ it "is enabled with #unguarded" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("--no-ruby_bug", an_instance_of(String))
+ @options.unguarded
+ end
+
+ it "registers the MSpec no_ruby_bug mode" do
+ MSpec.should_receive(:register_mode).with(:no_ruby_bug)
+ @options.parse "--no-ruby_bug"
+ end
+end
+
+describe "The -H, --random option" do
+ before :each do
+ @options, @config = new_option
+ @options.randomize
+ end
+
+ it "is enabled with #randomize" do
+ @options.should_receive(:on).with("-H", "--random", an_instance_of(String))
+ @options.randomize
+ end
+
+ it "registers the MSpec randomize mode" do
+ MSpec.should_receive(:randomize).twice
+ ["-H", "--random"].each do |opt|
+ @options.parse opt
+ end
+ end
+end
+
+describe "The -V, --verbose option" do
+ before :each do
+ @options, @config = new_option
+ @options.verbose
+ end
+
+ it "is enabled with #verbose" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-V", "--verbose", an_instance_of(String))
+ @options.verbose
+ end
+
+ it "registers a verbose output object with MSpec" do
+ MSpec.should_receive(:register).with(:start, anything()).twice
+ MSpec.should_receive(:register).with(:load, anything()).twice
+ ["-V", "--verbose"].each do |opt|
+ @options.parse opt
+ end
+ end
+end
+
+describe "The -m, --marker MARKER option" do
+ before :each do
+ @options, @config = new_option
+ @options.verbose
+ end
+
+ it "is enabled with #verbose" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-m", "--marker", "MARKER",
+ an_instance_of(String))
+ @options.verbose
+ end
+
+ it "registers a marker output object with MSpec" do
+ MSpec.should_receive(:register).with(:load, anything()).twice
+ ["-m", "--marker"].each do |opt|
+ @options.parse [opt, ","]
+ end
+ end
+end
+
+describe "The --int-spec option" do
+ before :each do
+ @options, @config = new_option
+ @options.interrupt
+ end
+
+ it "is enabled with #interrupt" do
+ @options.should_receive(:on).with("--int-spec", an_instance_of(String))
+ @options.interrupt
+ end
+
+ it "sets the abort config option to false to only abort the running spec with ^C" do
+ @config[:abort] = true
+ @options.parse "--int-spec"
+ @config[:abort].should == false
+ end
+end
+
+describe "The -Y, --verify option" do
+ before :each do
+ @options, @config = new_option
+ @options.verify
+ end
+
+ it "is enabled with #interrupt" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-Y", "--verify", an_instance_of(String))
+ @options.verify
+ end
+
+ it "sets the MSpec mode to :verify" do
+ MSpec.should_receive(:register_mode).with(:verify).twice
+ ["-Y", "--verify"].each do |m|
+ @options.parse m
+ end
+ end
+end
+
+describe "The -O, --report option" do
+ before :each do
+ @options, @config = new_option
+ @options.verify
+ end
+
+ it "is enabled with #interrupt" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-O", "--report", an_instance_of(String))
+ @options.verify
+ end
+
+ it "sets the MSpec mode to :report" do
+ MSpec.should_receive(:register_mode).with(:report).twice
+ ["-O", "--report"].each do |m|
+ @options.parse m
+ end
+ end
+end
+
+describe "The --report-on GUARD option" do
+ before :all do
+ MSpec.stub!(:register_mode)
+ end
+
+ before :each do
+ @options, @config = new_option
+ @options.verify
+
+ SpecGuard.clear_guards
+ end
+
+ after :each do
+ SpecGuard.clear_guards
+ end
+
+ it "is enabled with #interrupt" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("--report-on", "GUARD", an_instance_of(String))
+ @options.verify
+ end
+
+ it "sets the MSpec mode to :report_on" do
+ MSpec.should_receive(:register_mode).with(:report_on)
+ @options.parse ["--report-on", "ruby_bug"]
+ end
+
+ it "converts the guard name to a symbol" do
+ name = mock("ruby_bug")
+ name.should_receive(:to_sym)
+ @options.parse ["--report-on", name]
+ end
+
+ it "saves the name of the guard" do
+ @options.parse ["--report-on", "ruby_bug"]
+ SpecGuard.guards.should == [:ruby_bug]
+ end
+end
+
+describe "The -K, --action-tag TAG option" do
+ before :each do
+ @options, @config = new_option
+ @options.action_filters
+ end
+
+ it "is enabled with #action_filters" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-K", "--action-tag", "TAG",
+ an_instance_of(String))
+ @options.action_filters
+ end
+
+ it "adds TAG to the list of tags that trigger actions" do
+ ["-K", "--action-tag"].each do |opt|
+ @config[:atags] = []
+ @options.parse [opt, "action-tag"]
+ @config[:atags].should include("action-tag")
+ end
+ end
+end
+
+describe "The -S, --action-string STR option" do
+ before :each do
+ @options, @config = new_option
+ @options.action_filters
+ end
+
+ it "is enabled with #action_filters" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("-S", "--action-string", "STR",
+ an_instance_of(String))
+ @options.action_filters
+ end
+
+ it "adds STR to the list of spec descriptions that trigger actions" do
+ ["-S", "--action-string"].each do |opt|
+ @config[:astrings] = []
+ @options.parse [opt, "action-str"]
+ @config[:astrings].should include("action-str")
+ end
+ end
+end
+
+describe "The --spec-debug option" do
+ before :each do
+ @options, @config = new_option
+ @options.actions
+ end
+
+ it "is enabled with #actions" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("--spec-debug", an_instance_of(String))
+ @options.actions
+ end
+
+ it "enables the triggering the ruby debugger" do
+ @options.action_filters
+ @options.parse ["-S", "some spec"]
+
+ @config[:debugger] = nil
+ @options.parse "--spec-debug"
+ @config[:debugger].should == true
+ end
+end
+
+describe "The --spec-gdb option" do
+ before :each do
+ @options, @config = new_option
+ @options.actions
+ end
+
+ it "is enabled with #actions" do
+ @options.stub!(:on)
+ @options.should_receive(:on).with("--spec-gdb", an_instance_of(String))
+ @options.actions
+ end
+
+ it "enables triggering the gdb debugger" do
+ @options.action_filters
+ @options.parse ["-S", "some spec"]
+
+ @config[:gdb] = nil
+ @options.parse "--spec-gdb"
+ @config[:gdb].should == true
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/utils/script_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/utils/script_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/utils/script_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,443 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/utils/script'
+require 'mspec/runner/mspec'
+require 'mspec/runner/filters'
+require 'mspec/runner/actions/filter'
+require 'mspec/runner/actions/debug'
+require 'mspec/runner/actions/gdb'
+
+describe MSpecScript, ".config" do
+ it "returns a Hash" do
+ MSpecScript.config.should be_kind_of(Hash)
+ end
+end
+
+describe MSpecScript, ".set" do
+ it "sets the config hash key, value" do
+ MSpecScript.set :a, 10
+ MSpecScript.config[:a].should == 10
+ end
+end
+
+describe MSpecScript, ".get" do
+ it "gets the config hash value for a key" do
+ MSpecScript.set :a, 10
+ MSpecScript.get(:a).should == 10
+ end
+end
+
+describe MSpecScript, "#config" do
+ it "returns the MSpecScript config hash" do
+ MSpecScript.set :b, 5
+ MSpecScript.new.config[:b].should == 5
+ end
+
+ it "returns the MSpecScript config hash from subclasses" do
+ class MSSClass < MSpecScript; end
+ MSpecScript.set :b, 5
+ MSSClass.new.config[:b].should == 5
+ end
+end
+
+describe MSpecScript, "#load_default" do
+ before :all do
+ @verbose = $VERBOSE
+ $VERBOSE = nil
+ end
+
+ after :all do
+ $VERBOSE = @verbose
+ end
+
+ before :each do
+ @version = RUBY_VERSION
+ if Object.const_defined? :RUBY_ENGINE
+ @engine = Object.const_get :RUBY_ENGINE
+ end
+ @script = MSpecScript.new
+ MSpecScript.stub!(:new).and_return(@script)
+ end
+
+ after :each do
+ Object.const_set :RUBY_VERSION, @version
+ Object.const_set :RUBY_ENGINE, @engine if @engine
+ end
+
+ it "attempts to load 'default.mspec'" do
+ @script.should_receive(:load).with('default.mspec').and_return(true)
+ @script.load_default
+ end
+
+ it "attempts to load a config file based on RUBY_ENGINE and RUBY_VERSION" do
+ Object.const_set :RUBY_ENGINE, "ybur"
+ Object.const_set :RUBY_VERSION, "1.8.9"
+ default = "ybur.1.8.mspec"
+ @script.should_receive(:load).with('default.mspec').and_return(false)
+ @script.should_receive(:load).with(default)
+ @script.load_default
+ end
+end
+
+describe MSpecScript, ".main" do
+ before :each do
+ @script = mock("MSpecScript", :null_object => true)
+ MSpecScript.stub!(:new).and_return(@script)
+ end
+
+ it "creates an instance of MSpecScript" do
+ MSpecScript.should_receive(:new).and_return(@script)
+ MSpecScript.main
+ end
+
+ it "attempts to load the default config" do
+ @script.should_receive(:load_default)
+ MSpecScript.main
+ end
+
+ it "attempts to load the '~/.mspecrc' script" do
+ @script.should_receive(:load).with('~/.mspecrc')
+ MSpecScript.main
+ end
+
+ it "calls the #options method on the script" do
+ @script.should_receive(:options)
+ MSpecScript.main
+ end
+
+ it "calls the #signals method on the script" do
+ @script.should_receive(:signals)
+ MSpecScript.main
+ end
+
+ it "calls the #register method on the script" do
+ @script.should_receive(:register)
+ MSpecScript.main
+ end
+
+ it "calls the #run method on the script" do
+ @script.should_receive(:run)
+ MSpecScript.main
+ end
+end
+
+describe MSpecScript, "#initialize" do
+ before :each do
+ @config = MSpecScript.new.config
+ end
+
+ it "sets the default config values" do
+ @config[:formatter].should == nil
+ @config[:includes].should == []
+ @config[:excludes].should == []
+ @config[:patterns].should == []
+ @config[:xpatterns].should == []
+ @config[:tags].should == []
+ @config[:xtags].should == []
+ @config[:atags].should == []
+ @config[:astrings].should == []
+ @config[:abort].should == true
+ @config[:config_ext].should == '.mspec'
+ end
+end
+
+describe MSpecScript, "#load" do
+ before :each do
+ File.stub!(:exist?).and_return(false)
+ @script = MSpecScript.new
+ @file = "default.mspec"
+ @base = "default"
+ end
+
+ it "attempts to locate the file through the expanded path name" do
+ File.should_receive(:expand_path).with(@file).and_return(@file)
+ File.should_receive(:exist?).with(@file).and_return(true)
+ Kernel.should_receive(:load).with(@file).and_return(:loaded)
+ @script.load(@file).should == :loaded
+ end
+
+ it "appends config[:config_ext] to the name and attempts to locate the file through the expanded path name" do
+ File.should_receive(:expand_path).with(@base).and_return(@base)
+ File.should_receive(:expand_path).with(@file).and_return(@file)
+ File.should_receive(:exist?).with(@base).and_return(false)
+ File.should_receive(:exist?).with(@file).and_return(true)
+ Kernel.should_receive(:load).with(@file).and_return(:loaded)
+ @script.load(@base).should == :loaded
+ end
+
+ it "attemps to locate the file in '.'" do
+ path = File.join ".", @file
+ File.should_receive(:exist?).with(path).and_return(true)
+ Kernel.should_receive(:load).with(path).and_return(:loaded)
+ @script.load(@file).should == :loaded
+ end
+
+ it "appends config[:config_ext] to the name and attempts to locate the file in '.'" do
+ path = File.join ".", @file
+ File.should_receive(:exist?).with(path).and_return(true)
+ Kernel.should_receive(:load).with(path).and_return(:loaded)
+ @script.load(@base).should == :loaded
+ end
+
+ it "attemps to locate the file in 'spec'" do
+ path = File.join "spec", @file
+ File.should_receive(:exist?).with(path).and_return(true)
+ Kernel.should_receive(:load).with(path).and_return(:loaded)
+ @script.load(@file).should == :loaded
+ end
+
+ it "appends config[:config_ext] to the name and attempts to locate the file in 'spec'" do
+ path = File.join "spec", @file
+ File.should_receive(:exist?).with(path).and_return(true)
+ Kernel.should_receive(:load).with(path).and_return(:loaded)
+ @script.load(@base).should == :loaded
+ end
+end
+
+describe MSpecScript, "#custom_options" do
+ before :each do
+ @script = MSpecScript.new
+ end
+
+ after :each do
+ end
+
+ it "prints 'None'" do
+ options = mock("options")
+ options.should_receive(:doc).with(" No custom options registered")
+ @script.custom_options options
+ end
+end
+
+describe MSpecScript, "#register" do
+ before :each do
+ @script = MSpecScript.new
+
+ @formatter = mock("formatter", :null_object => true)
+ @script.config[:formatter] = @formatter
+ end
+
+ it "creates and registers the formatter" do
+ @formatter.should_receive(:new).and_return(@formatter)
+ @formatter.should_receive(:register)
+ @script.register
+ end
+
+ it "does not register the formatter if config[:formatter] is false" do
+ @script.config[:formatter] = false
+ @script.register
+ end
+
+ it "calls #custom_register" do
+ @script.should_receive(:custom_register)
+ @script.register
+ end
+
+ it "registers :formatter with the formatter instance" do
+ @formatter.stub!(:new).and_return(@formatter)
+ MSpec.should_receive(:store).with(:formatter, @formatter)
+ @script.register
+ end
+
+ it "does not register :formatter if config[:formatter] is false" do
+ @script.config[:formatter] = false
+ MSpec.should_not_receive(:store)
+ @script.register
+ end
+end
+
+describe MSpecScript, "#register" do
+ before :each do
+ @script = MSpecScript.new
+
+ @formatter = mock("formatter", :null_object => true)
+ @script.config[:formatter] = @formatter
+
+ @filter = mock("filter")
+ @filter.should_receive(:register)
+
+ @ary = ["some", "spec"]
+ end
+
+ it "creates and registers a MatchFilter for include specs" do
+ MatchFilter.should_receive(:new).with(:include, *@ary).and_return(@filter)
+ @script.config[:includes] = @ary
+ @script.register
+ end
+
+ it "creates and registers a MatchFilter for excluded specs" do
+ MatchFilter.should_receive(:new).with(:exclude, *@ary).and_return(@filter)
+ @script.config[:excludes] = @ary
+ @script.register
+ end
+
+ it "creates and registers a RegexpFilter for include specs" do
+ RegexpFilter.should_receive(:new).with(:include, *@ary).and_return(@filter)
+ @script.config[:patterns] = @ary
+ @script.register
+ end
+
+ it "creates and registers a RegexpFilter for excluded specs" do
+ RegexpFilter.should_receive(:new).with(:exclude, *@ary).and_return(@filter)
+ @script.config[:xpatterns] = @ary
+ @script.register
+ end
+
+ it "creates and registers a TagFilter for include specs" do
+ TagFilter.should_receive(:new).with(:include, *@ary).and_return(@filter)
+ @script.config[:tags] = @ary
+ @script.register
+ end
+
+ it "creates and registers a TagFilter for excluded specs" do
+ TagFilter.should_receive(:new).with(:exclude, *@ary).and_return(@filter)
+ @script.config[:xtags] = @ary
+ @script.register
+ end
+
+ it "creates and registers a ProfileFilter for include specs" do
+ ProfileFilter.should_receive(:new).with(:include, *@ary).and_return(@filter)
+ @script.config[:profiles] = @ary
+ @script.register
+ end
+
+ it "creates and registers a ProfileFilter for excluded specs" do
+ ProfileFilter.should_receive(:new).with(:exclude, *@ary).and_return(@filter)
+ @script.config[:xprofiles] = @ary
+ @script.register
+ end
+
+ it "creates and registers a DebugAction for excluded specs" do
+ @script.config[:atags] = ["some"]
+ @script.config[:astrings] = ["string"]
+ DebugAction.should_receive(:new).with(["some"], ["string"]).and_return(@filter)
+ @script.config[:debugger] = true
+ @script.register
+ end
+
+ it "creates and registers a GdbAction for excluded specs" do
+ @script.config[:atags] = ["some"]
+ @script.config[:astrings] = ["string"]
+ GdbAction.should_receive(:new).with(["some"], ["string"]).and_return(@filter)
+ @script.config[:gdb] = true
+ @script.register
+ end
+end
+
+describe MSpecScript, "#signals" do
+ before :each do
+ @script = MSpecScript.new
+ @abort = @script.config[:abort]
+ end
+
+ after :each do
+ @script.config[:abort] = @abort
+ end
+
+ it "traps the INT signal if config[:abort] is true" do
+ Signal.should_receive(:trap).with("INT")
+ @script.config[:abort] = true
+ @script.signals
+ end
+
+ it "does not trap the INT signal if config[:abort] is not true" do
+ Signal.should_not_receive(:trap).with("INT")
+ @script.config[:abort] = false
+ @script.signals
+ end
+end
+
+describe MSpecScript, "#entries" do
+ before :each do
+ @script = MSpecScript.new
+
+ File.stub!(:expand_path).and_return("name")
+ File.stub!(:file?).and_return(false)
+ File.stub!(:directory?).and_return(false)
+ end
+
+ it "returns the pattern in an array if it is a file" do
+ File.should_receive(:expand_path).with("file").and_return("file")
+ File.should_receive(:file?).with("file").and_return(true)
+ @script.entries("file").should == ["file"]
+ end
+
+ it "returns Dir['pattern/**/*_spec.rb'] if pattern is a directory" do
+ File.should_receive(:directory?).with("name").and_return(true)
+ File.stub!(:expand_path).and_return("name","name/**/*_spec.rb")
+ Dir.should_receive(:[]).with("name/**/*_spec.rb").and_return(["dir1", "dir2"])
+ @script.entries("name").should == ["dir1", "dir2"]
+ end
+
+ it "returns Dir[pattern] if pattern is neither a file nor a directory" do
+ Dir.should_receive(:[]).with("pattern").and_return(["file1", "file2"])
+ @script.entries("pattern").should == ["file1", "file2"]
+ end
+
+ describe "with config[:prefix] set" do
+ before :each do
+ prefix = "prefix/dir"
+ @script.config[:prefix] = prefix
+ @name = prefix + "/name"
+ end
+
+ it "returns the pattern in an array if it is a file" do
+ File.should_receive(:expand_path).with(@name).and_return(@name)
+ File.should_receive(:file?).with(@name).and_return(true)
+ @script.entries("name").should == [@name]
+ end
+
+ it "returns Dir['pattern/**/*_spec.rb'] if pattern is a directory" do
+ File.stub!(:expand_path).and_return(@name, @name+"/**/*_spec.rb")
+ File.should_receive(:directory?).with(@name).and_return(true)
+ Dir.should_receive(:[]).with(@name + "/**/*_spec.rb").and_return(["dir1", "dir2"])
+ @script.entries("name").should == ["dir1", "dir2"]
+ end
+
+ it "returns Dir[pattern] if pattern is neither a file nor a directory" do
+ Dir.should_receive(:[]).with("pattern").and_return(["file1", "file2"])
+ @script.entries("pattern").should == ["file1", "file2"]
+ end
+ end
+end
+
+describe MSpecScript, "#files" do
+ before :each do
+ @script = MSpecScript.new
+ end
+
+ it "accumlates the values returned by #entries" do
+ @script.should_receive(:entries).and_return(["file1"], ["file2"])
+ @script.files(["a", "b"]).should == ["file1", "file2"]
+ end
+
+ it "strips a leading '^' and removes the values returned by #entries" do
+ @script.should_receive(:entries).and_return(["file1"], ["file2"], ["file1"])
+ @script.files(["a", "b", "^a"]).should == ["file2"]
+ end
+
+ it "processes the array elements in order" do
+ @script.should_receive(:entries).and_return(["file1"], ["file1"], ["file2"])
+ @script.files(["^a", "a", "b"]).should == ["file1", "file2"]
+ end
+end
+
+describe MSpecScript, "#files" do
+ before :each do
+ MSpecScript.set :files, ["file1", "file2"]
+
+ @script = MSpecScript.new
+ end
+
+ after :each do
+ MSpecScript.config.delete :files
+ end
+
+ it "looks up items with leading ':' in the config object" do
+ @script.should_receive(:entries).and_return(["file1"], ["file2"])
+ @script.files(":files").should == ["file1", "file2"]
+ end
+
+ it "returns an empty list if the config key is not set" do
+ @script.files(":all_files").should == []
+ end
+end
Added: MacRuby/branches/experimental/mspec/spec/utils/version_spec.rb
===================================================================
--- MacRuby/branches/experimental/mspec/spec/utils/version_spec.rb (rev 0)
+++ MacRuby/branches/experimental/mspec/spec/utils/version_spec.rb 2009-03-11 23:10:17 UTC (rev 876)
@@ -0,0 +1,47 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+require 'mspec/utils/version'
+
+describe SpecVersion, "#to_s" do
+ it "returns the string with which it was initialized" do
+ SpecVersion.new("1.8").to_s.should == "1.8"
+ SpecVersion.new("2.118.9.2").to_s.should == "2.118.9.2"
+ end
+end
+
+describe SpecVersion, "#to_str" do
+ it "returns the same string as #to_s" do
+ version = SpecVersion.new("2.118.9.2")
+ version.to_str.should == version.to_s
+ end
+end
+
+describe SpecVersion, "#to_i with ceil = false" do
+ it "returns an integer representation of the version string" do
+ SpecVersion.new("1.8.6.22").to_i.should == 10108060022
+ end
+
+ it "replaces missing version parts with zeros" do
+ SpecVersion.new("1.8").to_i.should == 10108000000
+ SpecVersion.new("1.8.6").to_i.should == 10108060000
+ SpecVersion.new("1.8.7.333").to_i.should == 10108070333
+ end
+end
+
+describe SpecVersion, "#to_i with ceil = true" do
+ it "returns an integer representation of the version string" do
+ SpecVersion.new("1.8.6.22", true).to_i.should == 10108060022
+ end
+
+ it "fills in 9s for missing tiny and patchlevel values" do
+ SpecVersion.new("1.8", true).to_i.should == 10108999999
+ SpecVersion.new("1.8.6", true).to_i.should == 10108069999
+ SpecVersion.new("1.8.7.333", true).to_i.should == 10108070333
+ end
+end
+
+describe SpecVersion, "#to_int" do
+ it "returns the same value as #to_i" do
+ version = SpecVersion.new("4.16.87.333")
+ version.to_int.should == version.to_i
+ end
+end
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090311/90519fec/attachment-0001.html>
More information about the macruby-changes
mailing list