mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	Add in-tree mspec and ruby/spec
* For easier modifications of ruby/spec by MRI developers. * .gitignore: track changes under spec. * spec/mspec, spec/rubyspec: add in-tree mspec and ruby/spec. These files can therefore be updated like any other file in MRI. Instructions are provided in spec/README. [Feature #13156] [ruby-core:79246] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58595 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									ed7d803500
								
							
						
					
					
						commit
						95e8c48dd3
					
				
					 4645 changed files with 230678 additions and 4 deletions
				
			
		
							
								
								
									
										4
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -172,10 +172,6 @@ y.tab.c
 | 
				
			||||||
/gems/*.gem
 | 
					/gems/*.gem
 | 
				
			||||||
/gems/*-*
 | 
					/gems/*-*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# /spec/
 | 
					 | 
				
			||||||
/spec/mspec
 | 
					 | 
				
			||||||
/spec/rubyspec
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# /tool/
 | 
					# /tool/
 | 
				
			||||||
/tool/config.guess
 | 
					/tool/config.guess
 | 
				
			||||||
/tool/config.sub
 | 
					/tool/config.sub
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										26
									
								
								spec/mspec/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								spec/mspec/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					pkg
 | 
				
			||||||
 | 
					*.rbc
 | 
				
			||||||
 | 
					*.iml
 | 
				
			||||||
 | 
					*.iws
 | 
				
			||||||
 | 
					*.ipr
 | 
				
			||||||
 | 
					*.sw?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.rbx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ctags dir
 | 
				
			||||||
 | 
					/tags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*.gem
 | 
				
			||||||
 | 
					.bundle
 | 
				
			||||||
 | 
					.config
 | 
				
			||||||
 | 
					.yardoc
 | 
				
			||||||
 | 
					InstalledFiles
 | 
				
			||||||
 | 
					_yardoc
 | 
				
			||||||
 | 
					coverage
 | 
				
			||||||
 | 
					doc/
 | 
				
			||||||
 | 
					lib/bundler/man
 | 
				
			||||||
 | 
					rdoc
 | 
				
			||||||
 | 
					spec/reports
 | 
				
			||||||
 | 
					test/tmp
 | 
				
			||||||
 | 
					test/version_tmp
 | 
				
			||||||
 | 
					tmp
 | 
				
			||||||
							
								
								
									
										9
									
								
								spec/mspec/.travis.yml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								spec/mspec/.travis.yml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					sudo: false
 | 
				
			||||||
 | 
					language: ruby
 | 
				
			||||||
 | 
					script:
 | 
				
			||||||
 | 
					  - bundle exec rspec
 | 
				
			||||||
 | 
					rvm:
 | 
				
			||||||
 | 
					  - 2.2.7
 | 
				
			||||||
 | 
					  - 2.3.4
 | 
				
			||||||
 | 
					  - 2.4.1
 | 
				
			||||||
 | 
					  - ruby-head
 | 
				
			||||||
							
								
								
									
										4
									
								
								spec/mspec/Gemfile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								spec/mspec/Gemfile
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					source 'https://rubygems.org'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Specify your gem's dependencies in mspec.gemspec
 | 
				
			||||||
 | 
					gemspec
 | 
				
			||||||
							
								
								
									
										30
									
								
								spec/mspec/Gemfile.lock
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								spec/mspec/Gemfile.lock
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					PATH
 | 
				
			||||||
 | 
					  remote: .
 | 
				
			||||||
 | 
					  specs:
 | 
				
			||||||
 | 
					    mspec (1.8.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GEM
 | 
				
			||||||
 | 
					  remote: https://rubygems.org/
 | 
				
			||||||
 | 
					  specs:
 | 
				
			||||||
 | 
					    diff-lcs (1.2.5)
 | 
				
			||||||
 | 
					    rake (10.4.2)
 | 
				
			||||||
 | 
					    rspec (2.14.1)
 | 
				
			||||||
 | 
					      rspec-core (~> 2.14.0)
 | 
				
			||||||
 | 
					      rspec-expectations (~> 2.14.0)
 | 
				
			||||||
 | 
					      rspec-mocks (~> 2.14.0)
 | 
				
			||||||
 | 
					    rspec-core (2.14.8)
 | 
				
			||||||
 | 
					    rspec-expectations (2.14.5)
 | 
				
			||||||
 | 
					      diff-lcs (>= 1.1.3, < 2.0)
 | 
				
			||||||
 | 
					    rspec-mocks (2.14.6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PLATFORMS
 | 
				
			||||||
 | 
					  java
 | 
				
			||||||
 | 
					  ruby
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEPENDENCIES
 | 
				
			||||||
 | 
					  mspec!
 | 
				
			||||||
 | 
					  rake (~> 10.0)
 | 
				
			||||||
 | 
					  rspec (~> 2.14.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BUNDLED WITH
 | 
				
			||||||
 | 
					   1.10.2
 | 
				
			||||||
							
								
								
									
										22
									
								
								spec/mspec/LICENSE
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								spec/mspec/LICENSE
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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.
 | 
				
			||||||
							
								
								
									
										88
									
								
								spec/mspec/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								spec/mspec/README.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,88 @@
 | 
				
			||||||
 | 
					[](https://travis-ci.org/ruby/mspec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  1. 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  2. 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  3. MSpec provides various helper methods to simplify some specs, for
 | 
				
			||||||
 | 
					     example, creating temporary file names.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  4. MSpec has several specialized runner scripts that includes a
 | 
				
			||||||
 | 
					     configuration facility with a default project file and user-specific
 | 
				
			||||||
 | 
					     overrides.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Bundler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A Gemfile is provided. Use Bundler to install gem dependencies. To install
 | 
				
			||||||
 | 
					Bundler, run the following:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					gem install bundler
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To install the gem dependencies with Bundler, run the following:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					ruby -S bundle install
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Running Specs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Use RSpec to run the MSpec specs. There are no plans currently to make the
 | 
				
			||||||
 | 
					MSpec specs runnable by MSpec.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					After installing the gem dependencies, the specs can be run as follows:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					ruby -S bundle exec rspec
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Or
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					ruby -S rake
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To run an individual spec file, use the following example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					ruby -S bundle exec rspec spec/helpers/ruby_exe_spec.rb
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See http://ruby.github.io/rubyspec.github.io/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Source Code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See https://github.com/ruby/mspec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See the LICENSE in the source code.
 | 
				
			||||||
							
								
								
									
										7
									
								
								spec/mspec/Rakefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								spec/mspec/Rakefile
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					require 'bundler/gem_tasks'
 | 
				
			||||||
 | 
					require 'bundler/setup'
 | 
				
			||||||
 | 
					require 'rspec/core/rake_task'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RSpec::Core::RakeTask.new(:spec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					task :default => :spec
 | 
				
			||||||
							
								
								
									
										7
									
								
								spec/mspec/bin/mkspec
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								spec/mspec/bin/mkspec
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env ruby
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$:.unshift File.expand_path('../../lib', __FILE__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require 'mspec/commands/mkspec'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MkSpec.main
 | 
				
			||||||
							
								
								
									
										1
									
								
								spec/mspec/bin/mkspec.bat
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								spec/mspec/bin/mkspec.bat
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					@"ruby.exe" "%~dpn0" %*
 | 
				
			||||||
							
								
								
									
										7
									
								
								spec/mspec/bin/mspec
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								spec/mspec/bin/mspec
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env ruby
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$:.unshift File.expand_path('../../lib', __FILE__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require 'mspec/commands/mspec'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MSpecMain.main
 | 
				
			||||||
							
								
								
									
										7
									
								
								spec/mspec/bin/mspec-ci
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								spec/mspec/bin/mspec-ci
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env ruby
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$:.unshift File.expand_path('../../lib', __FILE__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require 'mspec/commands/mspec-ci'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MSpecCI.main
 | 
				
			||||||
							
								
								
									
										1
									
								
								spec/mspec/bin/mspec-ci.bat
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								spec/mspec/bin/mspec-ci.bat
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					@"ruby.exe" "%~dpn0" %*
 | 
				
			||||||
							
								
								
									
										7
									
								
								spec/mspec/bin/mspec-run
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								spec/mspec/bin/mspec-run
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env ruby
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$:.unshift File.expand_path('../../lib', __FILE__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require 'mspec/commands/mspec-run'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MSpecRun.main
 | 
				
			||||||
							
								
								
									
										1
									
								
								spec/mspec/bin/mspec-run.bat
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								spec/mspec/bin/mspec-run.bat
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					@"ruby.exe" "%~dpn0" %*
 | 
				
			||||||
							
								
								
									
										7
									
								
								spec/mspec/bin/mspec-tag
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								spec/mspec/bin/mspec-tag
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env ruby
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$:.unshift File.expand_path('../../lib', __FILE__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require 'mspec/commands/mspec-tag'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MSpecTag.main
 | 
				
			||||||
							
								
								
									
										1
									
								
								spec/mspec/bin/mspec-tag.bat
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								spec/mspec/bin/mspec-tag.bat
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					@"ruby.exe" "%~dpn0" %*
 | 
				
			||||||
							
								
								
									
										1
									
								
								spec/mspec/bin/mspec.bat
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								spec/mspec/bin/mspec.bat
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					@"ruby.exe" "%~dpn0" %*
 | 
				
			||||||
							
								
								
									
										20
									
								
								spec/mspec/lib/mspec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								spec/mspec/lib/mspec.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					require 'mspec/matchers'
 | 
				
			||||||
 | 
					require 'mspec/expectations'
 | 
				
			||||||
 | 
					require 'mspec/mocks'
 | 
				
			||||||
 | 
					require 'mspec/runner'
 | 
				
			||||||
 | 
					require 'mspec/guards'
 | 
				
			||||||
 | 
					require 'mspec/helpers'
 | 
				
			||||||
 | 
					require 'mspec/version'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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.
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					  require 'pp'
 | 
				
			||||||
 | 
					rescue LoadError
 | 
				
			||||||
 | 
					  module Kernel
 | 
				
			||||||
 | 
					    def pretty_inspect
 | 
				
			||||||
 | 
					      inspect
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										155
									
								
								spec/mspec/lib/mspec/commands/mkspec.rb
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										155
									
								
								spec/mspec/lib/mspec/commands/mkspec.rb
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,155 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env ruby
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require 'rbconfig'
 | 
				
			||||||
 | 
					require 'mspec/version'
 | 
				
			||||||
 | 
					require 'mspec/utils/options'
 | 
				
			||||||
 | 
					require 'mspec/utils/name_map'
 | 
				
			||||||
 | 
					require 'mspec/helpers/fs'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MkSpec
 | 
				
			||||||
 | 
					  attr_reader :config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def initialize
 | 
				
			||||||
 | 
					    @config = {
 | 
				
			||||||
 | 
					      :constants => [],
 | 
				
			||||||
 | 
					      :requires  => [],
 | 
				
			||||||
 | 
					      :base      => "core",
 | 
				
			||||||
 | 
					      :version   => nil
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    @map = NameMap.new true
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def options(argv=ARGV)
 | 
				
			||||||
 | 
					    options = MSpecOptions.new "mkspec [options]", 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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.on("-V", "--version-guard", "VERSION",
 | 
				
			||||||
 | 
					               "Specify version for ruby_version_is guards") do |version|
 | 
				
			||||||
 | 
					      config[:version] = version
 | 
				
			||||||
 | 
					    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 -r complex -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
 | 
				
			||||||
 | 
					      mkdir_p subdir
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    subdir
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def write_requires(dir, file)
 | 
				
			||||||
 | 
					    prefix = config[:base] + '/'
 | 
				
			||||||
 | 
					    raise dir unless dir.start_with? prefix
 | 
				
			||||||
 | 
					    sub = dir[prefix.size..-1]
 | 
				
			||||||
 | 
					    parents = '../' * (sub.split('/').length + 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    File.open(file, 'w') do |f|
 | 
				
			||||||
 | 
					      f.puts "require File.expand_path('../#{parents}spec_helper', __FILE__)"
 | 
				
			||||||
 | 
					      config[:requires].each do |lib|
 | 
				
			||||||
 | 
					        f.puts "require '#{lib}'"
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def write_version(f)
 | 
				
			||||||
 | 
					    f.puts ""
 | 
				
			||||||
 | 
					    if version = config[:version]
 | 
				
			||||||
 | 
					      f.puts "ruby_version_is #{version} do"
 | 
				
			||||||
 | 
					      yield "  "
 | 
				
			||||||
 | 
					      f.puts "end"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      yield ""
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def write_spec(file, meth, exists)
 | 
				
			||||||
 | 
					    if exists
 | 
				
			||||||
 | 
					      out = `#{ruby} #{MSPEC_HOME}/bin/mspec-run --dry-run --unguarded -fs -e '#{meth}' #{file}`
 | 
				
			||||||
 | 
					      return if out.include?(meth)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    File.open file, 'a' do |f|
 | 
				
			||||||
 | 
					      write_version(f) do |indent|
 | 
				
			||||||
 | 
					        f.puts <<-EOS
 | 
				
			||||||
 | 
					#{indent}describe "#{meth}" do
 | 
				
			||||||
 | 
					#{indent}  it "needs to be reviewed for spec completeness"
 | 
				
			||||||
 | 
					#{indent}end
 | 
				
			||||||
 | 
					EOS
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    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 = 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(RbConfig::CONFIG['bindir'],
 | 
				
			||||||
 | 
					                     RbConfig::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
 | 
				
			||||||
							
								
								
									
										79
									
								
								spec/mspec/lib/mspec/commands/mspec-ci.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								spec/mspec/lib/mspec/commands/mspec-ci.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,79 @@
 | 
				
			||||||
 | 
					#!/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.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.debug
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tags = ["fails", "critical", "unstable", "incomplete", "unsupported"]
 | 
				
			||||||
 | 
					    tags += Array(config[:ci_xtags])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    require 'mspec/runner/filters/tag'
 | 
				
			||||||
 | 
					    filter = TagFilter.new(:exclude, *tags)
 | 
				
			||||||
 | 
					    filter.register
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MSpec.process
 | 
				
			||||||
 | 
					    exit MSpec.exit_code
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										87
									
								
								spec/mspec/lib/mspec/commands/mspec-run.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								spec/mspec/lib/mspec/commands/mspec-run.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,87 @@
 | 
				
			||||||
 | 
					#!/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.repeat
 | 
				
			||||||
 | 
					    options.pretend
 | 
				
			||||||
 | 
					    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.debug
 | 
				
			||||||
 | 
					    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 "\n   4. To run some specs matching 'this crashes'"
 | 
				
			||||||
 | 
					    options.doc "\n     $ mspec -e 'this crashes' path/to/the_file_spec.rb"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    options.doc ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    patterns = options.parse argv
 | 
				
			||||||
 | 
					    @files = files_from_patterns(patterns)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def run
 | 
				
			||||||
 | 
					    MSpec.register_tags_patterns config[:tags_patterns]
 | 
				
			||||||
 | 
					    MSpec.register_files @files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MSpec.process
 | 
				
			||||||
 | 
					    exit MSpec.exit_code
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										133
									
								
								spec/mspec/lib/mspec/commands/mspec-tag.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								spec/mspec/lib/mspec/commands/mspec-tag.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,133 @@
 | 
				
			||||||
 | 
					#!/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.debug
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					    require 'mspec/runner/actions'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										163
									
								
								spec/mspec/lib/mspec/commands/mspec.rb
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										163
									
								
								spec/mspec/lib/mspec/commands/mspec.rb
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,163 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env ruby
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require 'mspec/version'
 | 
				
			||||||
 | 
					require 'mspec/utils/options'
 | 
				
			||||||
 | 
					require 'mspec/utils/script'
 | 
				
			||||||
 | 
					require 'mspec/helpers/tmp'
 | 
				
			||||||
 | 
					require 'mspec/runner/actions/filter'
 | 
				
			||||||
 | 
					require 'mspec/runner/actions/timer'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MSpecMain < MSpecScript
 | 
				
			||||||
 | 
					  def initialize
 | 
				
			||||||
 | 
					    super
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config[:loadpath] = []
 | 
				
			||||||
 | 
					    config[:requires] = []
 | 
				
			||||||
 | 
					    config[:target]   = ENV['RUBY'] || 'ruby'
 | 
				
			||||||
 | 
					    config[:flags]    = []
 | 
				
			||||||
 | 
					    config[:command]  = nil
 | 
				
			||||||
 | 
					    config[:options]  = []
 | 
				
			||||||
 | 
					    config[:launch]   = []
 | 
				
			||||||
 | 
					  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("--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.doc "   example: $ mspec run -h\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    options.on_extra { |o| config[:options] << o }
 | 
				
			||||||
 | 
					    options.parse(argv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if config[:multi]
 | 
				
			||||||
 | 
					      options = MSpecOptions.new "mspec", 30, config
 | 
				
			||||||
 | 
					      options.all
 | 
				
			||||||
 | 
					      patterns = options.parse(config[:options])
 | 
				
			||||||
 | 
					      @files = files_from_patterns(patterns)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def register; end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def multi_exec(argv)
 | 
				
			||||||
 | 
					    MSpec.register_files @files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    require 'mspec/runner/formatters/multi'
 | 
				
			||||||
 | 
					    formatter = MultiFormatter.new
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    output_files = []
 | 
				
			||||||
 | 
					    processes = [cores, @files.size].min
 | 
				
			||||||
 | 
					    children = processes.times.map { |i|
 | 
				
			||||||
 | 
					      name = tmp "mspec-multi-#{i}"
 | 
				
			||||||
 | 
					      output_files << name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      env = {
 | 
				
			||||||
 | 
					        "SPEC_TEMP_DIR" => "rubyspec_temp_#{i}",
 | 
				
			||||||
 | 
					        "MSPEC_MULTI" => i.to_s
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      command = argv + ["-o", name]
 | 
				
			||||||
 | 
					      $stderr.puts "$ #{command.join(' ')}" if $MSPEC_DEBUG
 | 
				
			||||||
 | 
					      IO.popen([env, *command], "rb+")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    puts children.map { |child| child.gets }.uniq
 | 
				
			||||||
 | 
					    formatter.start
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    until @files.empty?
 | 
				
			||||||
 | 
					      IO.select(children)[0].each { |io|
 | 
				
			||||||
 | 
					        reply = io.read(1)
 | 
				
			||||||
 | 
					        case reply
 | 
				
			||||||
 | 
					        when '.'
 | 
				
			||||||
 | 
					          formatter.unload
 | 
				
			||||||
 | 
					        when nil
 | 
				
			||||||
 | 
					          raise "Worker died!"
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          while chunk = (io.read_nonblock(4096) rescue nil)
 | 
				
			||||||
 | 
					            reply += chunk
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					          raise reply
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					        io.puts @files.shift unless @files.empty?
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ok = true
 | 
				
			||||||
 | 
					    children.each { |child|
 | 
				
			||||||
 | 
					      child.puts "QUIT"
 | 
				
			||||||
 | 
					      Process.wait(child.pid)
 | 
				
			||||||
 | 
					      ok &&= $?.success?
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    formatter.aggregate_results(output_files)
 | 
				
			||||||
 | 
					    formatter.finish
 | 
				
			||||||
 | 
					    ok
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def run
 | 
				
			||||||
 | 
					    argv = config[:target].split(/\s+/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    argv.concat config[:launch]
 | 
				
			||||||
 | 
					    argv.concat config[:flags]
 | 
				
			||||||
 | 
					    argv.concat config[:loadpath]
 | 
				
			||||||
 | 
					    argv.concat config[:requires]
 | 
				
			||||||
 | 
					    argv << "#{MSPEC_HOME}/bin/mspec-#{ config[:command] || "run" }"
 | 
				
			||||||
 | 
					    argv.concat config[:options]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if config[:multi]
 | 
				
			||||||
 | 
					      exit multi_exec(argv)
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      $stderr.puts "$ #{argv.join(' ')}"
 | 
				
			||||||
 | 
					      exec(*argv)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										2
									
								
								spec/mspec/lib/mspec/expectations.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								spec/mspec/lib/mspec/expectations.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,2 @@
 | 
				
			||||||
 | 
					require 'mspec/expectations/expectations'
 | 
				
			||||||
 | 
					require 'mspec/expectations/should'
 | 
				
			||||||
							
								
								
									
										21
									
								
								spec/mspec/lib/mspec/expectations/expectations.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								spec/mspec/lib/mspec/expectations/expectations.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					class SpecExpectationNotMetError < StandardError
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SpecExpectationNotFoundError < StandardError
 | 
				
			||||||
 | 
					  def message
 | 
				
			||||||
 | 
					    "No behavior expectation was found in the example"
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SpecExpectation
 | 
				
			||||||
 | 
					  def self.fail_with(expected, actual)
 | 
				
			||||||
 | 
					    expected_to_s = expected.to_s
 | 
				
			||||||
 | 
					    actual_to_s = actual.to_s
 | 
				
			||||||
 | 
					    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 SpecExpectationNotMetError, message
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										29
									
								
								spec/mspec/lib/mspec/expectations/should.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								spec/mspec/lib/mspec/expectations/should.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  NO_MATCHER_GIVEN = Object.new
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def should(matcher = NO_MATCHER_GIVEN)
 | 
				
			||||||
 | 
					    MSpec.expectation
 | 
				
			||||||
 | 
					    MSpec.actions :expectation, MSpec.current.state
 | 
				
			||||||
 | 
					    unless matcher.equal? NO_MATCHER_GIVEN
 | 
				
			||||||
 | 
					      unless matcher.matches? self
 | 
				
			||||||
 | 
					        expected, actual = matcher.failure_message
 | 
				
			||||||
 | 
					        SpecExpectation.fail_with(expected, actual)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      SpecPositiveOperatorMatcher.new(self)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def should_not(matcher = NO_MATCHER_GIVEN)
 | 
				
			||||||
 | 
					    MSpec.expectation
 | 
				
			||||||
 | 
					    MSpec.actions :expectation, MSpec.current.state
 | 
				
			||||||
 | 
					    unless matcher.equal? NO_MATCHER_GIVEN
 | 
				
			||||||
 | 
					      if matcher.matches? self
 | 
				
			||||||
 | 
					        expected, actual = matcher.negative_failure_message
 | 
				
			||||||
 | 
					        SpecExpectation.fail_with(expected, actual)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      SpecNegativeOperatorMatcher.new(self)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										12
									
								
								spec/mspec/lib/mspec/guards.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								spec/mspec/lib/mspec/guards.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					require 'mspec/utils/ruby_name'
 | 
				
			||||||
 | 
					require 'mspec/guards/block_device'
 | 
				
			||||||
 | 
					require 'mspec/guards/bug'
 | 
				
			||||||
 | 
					require 'mspec/guards/conflict'
 | 
				
			||||||
 | 
					require 'mspec/guards/endian'
 | 
				
			||||||
 | 
					require 'mspec/guards/feature'
 | 
				
			||||||
 | 
					require 'mspec/guards/guard'
 | 
				
			||||||
 | 
					require 'mspec/guards/platform'
 | 
				
			||||||
 | 
					require 'mspec/guards/quarantine'
 | 
				
			||||||
 | 
					require 'mspec/guards/support'
 | 
				
			||||||
 | 
					require 'mspec/guards/superuser'
 | 
				
			||||||
 | 
					require 'mspec/guards/version'
 | 
				
			||||||
							
								
								
									
										18
									
								
								spec/mspec/lib/mspec/guards/block_device.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								spec/mspec/lib/mspec/guards/block_device.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,18 @@
 | 
				
			||||||
 | 
					require 'mspec/guards/guard'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BlockDeviceGuard < SpecGuard
 | 
				
			||||||
 | 
					  def match?
 | 
				
			||||||
 | 
					    platform_is_not :freebsd, :windows, :opal do
 | 
				
			||||||
 | 
					      block = `find /dev /devices -type b 2> /dev/null`
 | 
				
			||||||
 | 
					      return !(block.nil? || block.empty?)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    false
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def with_block_device(&block)
 | 
				
			||||||
 | 
					    BlockDeviceGuard.new.run_if(:with_block_device, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										30
									
								
								spec/mspec/lib/mspec/guards/bug.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								spec/mspec/lib/mspec/guards/bug.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					require 'mspec/guards/version'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BugGuard < VersionGuard
 | 
				
			||||||
 | 
					  def initialize(bug, version)
 | 
				
			||||||
 | 
					    @bug = bug
 | 
				
			||||||
 | 
					    if String === version
 | 
				
			||||||
 | 
					      MSpec.deprecate "ruby_bug with a single version", 'an exclusive range ("2.1"..."2.3")'
 | 
				
			||||||
 | 
					      @version = SpecVersion.new version, true
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      super(version)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    @parameters = [@bug, @version]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def match?
 | 
				
			||||||
 | 
					    return false if MSpec.mode? :no_ruby_bug
 | 
				
			||||||
 | 
					    return false unless PlatformGuard.standard?
 | 
				
			||||||
 | 
					    if Range === @version
 | 
				
			||||||
 | 
					      super
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      FULL_RUBY_VERSION <= @version
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def ruby_bug(bug, version, &block)
 | 
				
			||||||
 | 
					    BugGuard.new(bug, version).run_unless(:ruby_bug, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										19
									
								
								spec/mspec/lib/mspec/guards/conflict.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								spec/mspec/lib/mspec/guards/conflict.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					require 'mspec/guards/guard'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConflictsGuard < SpecGuard
 | 
				
			||||||
 | 
					  def match?
 | 
				
			||||||
 | 
					    # Always convert constants to symbols regardless of version.
 | 
				
			||||||
 | 
					    constants = Object.constants.map { |x| x.to_sym }
 | 
				
			||||||
 | 
					    @parameters.any? { |mod| constants.include? mod }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  # In some cases, libraries will modify another Ruby method's
 | 
				
			||||||
 | 
					  # behavior. The specs for the method's behavior will then fail
 | 
				
			||||||
 | 
					  # if that library is loaded. This guard will not run if any of
 | 
				
			||||||
 | 
					  # the specified constants exist in Object.constants.
 | 
				
			||||||
 | 
					  def conflicts_with(*modules, &block)
 | 
				
			||||||
 | 
					    ConflictsGuard.new(*modules).run_unless(:conflicts_with, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										27
									
								
								spec/mspec/lib/mspec/guards/endian.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								spec/mspec/lib/mspec/guards/endian.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					require 'mspec/guards/guard'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Despite that these are inverses, the two classes are
 | 
				
			||||||
 | 
					# used to simplify MSpec guard reporting modes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EndianGuard < SpecGuard
 | 
				
			||||||
 | 
					  def pattern
 | 
				
			||||||
 | 
					    @pattern ||= [1].pack('L')
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					  private :pattern
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BigEndianGuard < EndianGuard
 | 
				
			||||||
 | 
					  def match?
 | 
				
			||||||
 | 
					    pattern[-1] == ?\001
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def big_endian(&block)
 | 
				
			||||||
 | 
					    BigEndianGuard.new.run_if(:big_endian, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def little_endian(&block)
 | 
				
			||||||
 | 
					    BigEndianGuard.new.run_unless(:little_endian, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										43
									
								
								spec/mspec/lib/mspec/guards/feature.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								spec/mspec/lib/mspec/guards/feature.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,43 @@
 | 
				
			||||||
 | 
					require 'mspec/guards/guard'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FeatureGuard < SpecGuard
 | 
				
			||||||
 | 
					  def self.enabled?(*features)
 | 
				
			||||||
 | 
					    new(*features).match?
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def match?
 | 
				
			||||||
 | 
					    @parameters.all? { |f| MSpec.feature_enabled? f }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  # Provides better documentation in the specs by
 | 
				
			||||||
 | 
					  # naming sets of features that work together as
 | 
				
			||||||
 | 
					  # a whole. Examples include :encoding, :fiber,
 | 
				
			||||||
 | 
					  # :continuation, :fork.
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # Usage example:
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  #   with_feature :encoding do
 | 
				
			||||||
 | 
					  #     # specs for a method that provides aspects
 | 
				
			||||||
 | 
					  #     # of the encoding feature
 | 
				
			||||||
 | 
					  #   end
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # Multiple features must all be enabled for the
 | 
				
			||||||
 | 
					  # guard to run:
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  #   with_feature :one, :two do
 | 
				
			||||||
 | 
					  #     # these specs will run if features :one AND
 | 
				
			||||||
 | 
					  #     # :two are enabled.
 | 
				
			||||||
 | 
					  #   end
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # The implementation must explicitly enable a feature
 | 
				
			||||||
 | 
					  # by adding code like the following to the .mspec
 | 
				
			||||||
 | 
					  # configuration file:
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  #   MSpec.enable_feature :encoding
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  def with_feature(*features, &block)
 | 
				
			||||||
 | 
					    FeatureGuard.new(*features).run_if(:with_feature, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										118
									
								
								spec/mspec/lib/mspec/guards/guard.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								spec/mspec/lib/mspec/guards/guard.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,118 @@
 | 
				
			||||||
 | 
					require 'mspec/runner/mspec'
 | 
				
			||||||
 | 
					require 'mspec/runner/actions/tally'
 | 
				
			||||||
 | 
					require 'mspec/utils/ruby_name'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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:
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  #  :major  => "8"
 | 
				
			||||||
 | 
					  #  :minor  => "8.2"
 | 
				
			||||||
 | 
					  #  :tiny   => "8.2.3"
 | 
				
			||||||
 | 
					  #  :teeny  => "8.2.3"
 | 
				
			||||||
 | 
					  #  :full   => "8.2.3"
 | 
				
			||||||
 | 
					  def self.ruby_version(which = :minor)
 | 
				
			||||||
 | 
					    case which
 | 
				
			||||||
 | 
					    when :major
 | 
				
			||||||
 | 
					      n = 1
 | 
				
			||||||
 | 
					    when :minor
 | 
				
			||||||
 | 
					      n = 2
 | 
				
			||||||
 | 
					    when :tiny, :teeny, :full
 | 
				
			||||||
 | 
					      n = 3
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RUBY_VERSION.split('.')[0,n].join('.')
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  attr_accessor :name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def initialize(*args)
 | 
				
			||||||
 | 
					    @parameters = args
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def yield?(invert = false)
 | 
				
			||||||
 | 
					    return true if MSpec.mode? :unguarded
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    allow = match? ^ invert
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if !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 run_if(name, &block)
 | 
				
			||||||
 | 
					    @name = name
 | 
				
			||||||
 | 
					    yield if yield?(false)
 | 
				
			||||||
 | 
					  ensure
 | 
				
			||||||
 | 
					    unregister
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def run_unless(name, &block)
 | 
				
			||||||
 | 
					    @name = name
 | 
				
			||||||
 | 
					    yield if yield?(true)
 | 
				
			||||||
 | 
					  ensure
 | 
				
			||||||
 | 
					    unregister
 | 
				
			||||||
 | 
					  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 match?
 | 
				
			||||||
 | 
					    raise "must be implemented by the subclass"
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										78
									
								
								spec/mspec/lib/mspec/guards/platform.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								spec/mspec/lib/mspec/guards/platform.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,78 @@
 | 
				
			||||||
 | 
					require 'mspec/guards/guard'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PlatformGuard < SpecGuard
 | 
				
			||||||
 | 
					  def self.implementation?(*args)
 | 
				
			||||||
 | 
					    args.any? do |name|
 | 
				
			||||||
 | 
					      case name
 | 
				
			||||||
 | 
					      when :rubinius
 | 
				
			||||||
 | 
					        RUBY_NAME.start_with?('rbx')
 | 
				
			||||||
 | 
					      when :ruby, :jruby, :truffleruby, :ironruby, :macruby, :maglev, :topaz, :opal
 | 
				
			||||||
 | 
					        RUBY_NAME.start_with?(name.to_s)
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        raise "unknown implementation #{name}"
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.standard?
 | 
				
			||||||
 | 
					    implementation? :ruby
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HOST_OS = begin
 | 
				
			||||||
 | 
					    require 'rbconfig'
 | 
				
			||||||
 | 
					    RbConfig::CONFIG['host_os'] || RUBY_PLATFORM
 | 
				
			||||||
 | 
					  rescue LoadError
 | 
				
			||||||
 | 
					    RUBY_PLATFORM
 | 
				
			||||||
 | 
					  end.downcase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.os?(*oses)
 | 
				
			||||||
 | 
					    oses.any? do |os|
 | 
				
			||||||
 | 
					      raise ":java is not a valid OS" if os == :java
 | 
				
			||||||
 | 
					      if os == :windows
 | 
				
			||||||
 | 
					        HOST_OS =~ /(mswin|mingw)/
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        HOST_OS.include?(os.to_s)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.windows?
 | 
				
			||||||
 | 
					    os?(:windows)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.wordsize?(size)
 | 
				
			||||||
 | 
					    size == 8 * 1.size
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def initialize(*args)
 | 
				
			||||||
 | 
					    if args.last.is_a?(Hash)
 | 
				
			||||||
 | 
					      @options, @platforms = args.last, args[0..-2]
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      @options, @platforms = {}, args
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    @parameters = args
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def match?
 | 
				
			||||||
 | 
					    match = @platforms.empty? ? true : PlatformGuard.os?(*@platforms)
 | 
				
			||||||
 | 
					    @options.each do |key, value|
 | 
				
			||||||
 | 
					      case key
 | 
				
			||||||
 | 
					      when :os
 | 
				
			||||||
 | 
					        match &&= PlatformGuard.os?(*value)
 | 
				
			||||||
 | 
					      when :wordsize
 | 
				
			||||||
 | 
					        match &&= PlatformGuard.wordsize? value
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    match
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def platform_is(*args, &block)
 | 
				
			||||||
 | 
					    PlatformGuard.new(*args).run_if(:platform_is, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def platform_is_not(*args, &block)
 | 
				
			||||||
 | 
					    PlatformGuard.new(*args).run_unless(:platform_is_not, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										13
									
								
								spec/mspec/lib/mspec/guards/quarantine.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								spec/mspec/lib/mspec/guards/quarantine.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					require 'mspec/guards/guard'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class QuarantineGuard < SpecGuard
 | 
				
			||||||
 | 
					  def match?
 | 
				
			||||||
 | 
					    true
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def quarantine!(&block)
 | 
				
			||||||
 | 
					    QuarantineGuard.new.run_unless(:quarantine!, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										17
									
								
								spec/mspec/lib/mspec/guards/superuser.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								spec/mspec/lib/mspec/guards/superuser.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					require 'mspec/guards/guard'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SuperUserGuard < SpecGuard
 | 
				
			||||||
 | 
					  def match?
 | 
				
			||||||
 | 
					    Process.euid == 0
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def as_superuser(&block)
 | 
				
			||||||
 | 
					    SuperUserGuard.new.run_if(:as_superuser, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def as_user(&block)
 | 
				
			||||||
 | 
					    SuperUserGuard.new.run_unless(:as_user, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										16
									
								
								spec/mspec/lib/mspec/guards/support.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								spec/mspec/lib/mspec/guards/support.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					require 'mspec/guards/platform'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SupportedGuard < SpecGuard
 | 
				
			||||||
 | 
					  def match?
 | 
				
			||||||
 | 
					    if @parameters.include? :ruby
 | 
				
			||||||
 | 
					      raise Exception, "improper use of not_supported_on guard"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    !PlatformGuard.standard? and PlatformGuard.implementation?(*@parameters)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def not_supported_on(*args, &block)
 | 
				
			||||||
 | 
					    SupportedGuard.new(*args).run_unless(:not_supported_on, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										39
									
								
								spec/mspec/lib/mspec/guards/version.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								spec/mspec/lib/mspec/guards/version.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					require 'mspec/utils/deprecate'
 | 
				
			||||||
 | 
					require 'mspec/utils/version'
 | 
				
			||||||
 | 
					require 'mspec/guards/guard'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VersionGuard < SpecGuard
 | 
				
			||||||
 | 
					  FULL_RUBY_VERSION = SpecVersion.new SpecGuard.ruby_version(:full)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def initialize(version)
 | 
				
			||||||
 | 
					    case version
 | 
				
			||||||
 | 
					    when String
 | 
				
			||||||
 | 
					      @version = SpecVersion.new version
 | 
				
			||||||
 | 
					    when Range
 | 
				
			||||||
 | 
					      MSpec.deprecate "an empty version range end", 'a specific version' if version.end.empty?
 | 
				
			||||||
 | 
					      a = SpecVersion.new version.begin
 | 
				
			||||||
 | 
					      b = SpecVersion.new version.end
 | 
				
			||||||
 | 
					      unless version.exclude_end?
 | 
				
			||||||
 | 
					        MSpec.deprecate "ruby_version_is with an inclusive range", 'an exclusive range ("2.1"..."2.3")'
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					      @version = version.exclude_end? ? a...b : a..b
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      raise "version must be a String or Range but was a #{version.class}"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    @parameters = [version]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def match?
 | 
				
			||||||
 | 
					    if Range === @version
 | 
				
			||||||
 | 
					      @version.include? FULL_RUBY_VERSION
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      FULL_RUBY_VERSION >= @version
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def ruby_version_is(*args, &block)
 | 
				
			||||||
 | 
					    VersionGuard.new(*args).run_if(:ruby_version_is, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										12
									
								
								spec/mspec/lib/mspec/helpers.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								spec/mspec/lib/mspec/helpers.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					require 'mspec/helpers/argf'
 | 
				
			||||||
 | 
					require 'mspec/helpers/argv'
 | 
				
			||||||
 | 
					require 'mspec/helpers/datetime'
 | 
				
			||||||
 | 
					require 'mspec/helpers/fixture'
 | 
				
			||||||
 | 
					require 'mspec/helpers/flunk'
 | 
				
			||||||
 | 
					require 'mspec/helpers/fs'
 | 
				
			||||||
 | 
					require 'mspec/helpers/io'
 | 
				
			||||||
 | 
					require 'mspec/helpers/mock_to_path'
 | 
				
			||||||
 | 
					require 'mspec/helpers/numeric'
 | 
				
			||||||
 | 
					require 'mspec/helpers/ruby_exe'
 | 
				
			||||||
 | 
					require 'mspec/helpers/scratch'
 | 
				
			||||||
 | 
					require 'mspec/helpers/tmp'
 | 
				
			||||||
							
								
								
									
										37
									
								
								spec/mspec/lib/mspec/helpers/argf.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								spec/mspec/lib/mspec/helpers/argf.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,37 @@
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  # Convenience helper for specs using ARGF.
 | 
				
			||||||
 | 
					  # Set @argf to an instance of ARGF.class with the given +argv+.
 | 
				
			||||||
 | 
					  # That instance must be used instead of ARGF as ARGF is global
 | 
				
			||||||
 | 
					  # and it is not always possible to reset its state correctly.
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # The helper yields to the block and then close
 | 
				
			||||||
 | 
					  # the files open by the instance. Example:
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  #   describe "That" do
 | 
				
			||||||
 | 
					  #     it "does something" do
 | 
				
			||||||
 | 
					  #       argf ['a', 'b'] do
 | 
				
			||||||
 | 
					  #         # do something
 | 
				
			||||||
 | 
					  #       end
 | 
				
			||||||
 | 
					  #     end
 | 
				
			||||||
 | 
					  #   end
 | 
				
			||||||
 | 
					  def argf(argv)
 | 
				
			||||||
 | 
					    if argv.empty? or argv.length > 2
 | 
				
			||||||
 | 
					      raise "Only 1 or 2 filenames are allowed for the argf helper so files can be properly closed: #{argv.inspect}"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    @argf ||= nil
 | 
				
			||||||
 | 
					    raise "Cannot nest calls to the argf helper" if @argf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @argf = ARGF.class.new(*argv)
 | 
				
			||||||
 | 
					    @__mspec_saved_argf_file__ = @argf.file
 | 
				
			||||||
 | 
					    begin
 | 
				
			||||||
 | 
					      yield
 | 
				
			||||||
 | 
					    ensure
 | 
				
			||||||
 | 
					      file1 = @__mspec_saved_argf_file__
 | 
				
			||||||
 | 
					      file2 = @argf.file # Either the first file or the second
 | 
				
			||||||
 | 
					      file1.close if !file1.closed? and file1 != STDIN
 | 
				
			||||||
 | 
					      file2.close if !file2.closed? and file2 != STDIN
 | 
				
			||||||
 | 
					      @argf = nil
 | 
				
			||||||
 | 
					      @__mspec_saved_argf_file__ = nil
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										46
									
								
								spec/mspec/lib/mspec/helpers/argv.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								spec/mspec/lib/mspec/helpers/argv.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					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.dup
 | 
				
			||||||
 | 
					      ARGV.replace args
 | 
				
			||||||
 | 
					      if block_given?
 | 
				
			||||||
 | 
					        begin
 | 
				
			||||||
 | 
					          yield
 | 
				
			||||||
 | 
					        ensure
 | 
				
			||||||
 | 
					          argv :restore
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										51
									
								
								spec/mspec/lib/mspec/helpers/datetime.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								spec/mspec/lib/mspec/helpers/datetime.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,51 @@
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  # The new_datetime helper makes writing DateTime specs more simple by
 | 
				
			||||||
 | 
					  # providing default constructor values and accepting a Hash of only the
 | 
				
			||||||
 | 
					  # constructor values needed for the particular spec. For example:
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  #   new_datetime :hour => 1, :minute => 20
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # Possible keys are:
 | 
				
			||||||
 | 
					  #   :year, :month, :day, :hour, :minute, :second, :offset and :sg.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def new_datetime(opts={})
 | 
				
			||||||
 | 
					    require 'date'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    value = {
 | 
				
			||||||
 | 
					      :year   => -4712,
 | 
				
			||||||
 | 
					      :month  => 1,
 | 
				
			||||||
 | 
					      :day    => 1,
 | 
				
			||||||
 | 
					      :hour   => 0,
 | 
				
			||||||
 | 
					      :minute => 0,
 | 
				
			||||||
 | 
					      :second => 0,
 | 
				
			||||||
 | 
					      :offset => 0,
 | 
				
			||||||
 | 
					      :sg     => Date::ITALY
 | 
				
			||||||
 | 
					    }.merge opts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DateTime.new value[:year], value[:month], value[:day], value[:hour],
 | 
				
			||||||
 | 
					      value[:minute], value[:second], value[:offset], value[:sg]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def with_timezone(name, offset = nil, daylight_saving_zone = "")
 | 
				
			||||||
 | 
					    zone = name.dup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if offset
 | 
				
			||||||
 | 
					      # TZ convention is backwards
 | 
				
			||||||
 | 
					      offset = -offset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      zone += offset.to_s
 | 
				
			||||||
 | 
					      zone += ":00:00"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    zone += daylight_saving_zone
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    old = ENV["TZ"]
 | 
				
			||||||
 | 
					    ENV["TZ"] = zone
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    begin
 | 
				
			||||||
 | 
					      yield
 | 
				
			||||||
 | 
					    ensure
 | 
				
			||||||
 | 
					      ENV["TZ"] = old
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										26
									
								
								spec/mspec/lib/mspec/helpers/fixture.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								spec/mspec/lib/mspec/helpers/fixture.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  # Returns the name of a fixture file by adjoining the directory
 | 
				
			||||||
 | 
					  # of the +file+ argument with "fixtures" and the contents of the
 | 
				
			||||||
 | 
					  # +args+ array. For example,
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  #   +file+ == "some/example_spec.rb"
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # and
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  #   +args+ == ["subdir", "file.txt"]
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # then the result is the expanded path of
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  #   "some/fixtures/subdir/file.txt".
 | 
				
			||||||
 | 
					  def fixture(file, *args)
 | 
				
			||||||
 | 
					    path = File.dirname(file)
 | 
				
			||||||
 | 
					    path = path[0..-7] if path[-7..-1] == "/shared"
 | 
				
			||||||
 | 
					    fixtures = path[-9..-1] == "/fixtures" ? "" : "fixtures"
 | 
				
			||||||
 | 
					    if File.respond_to?(:realpath)
 | 
				
			||||||
 | 
					      path = File.realpath(path)
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      path = File.expand_path(path)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    File.join(path, fixtures, args)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										5
									
								
								spec/mspec/lib/mspec/helpers/flunk.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								spec/mspec/lib/mspec/helpers/flunk.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def flunk(msg="This example is a failure")
 | 
				
			||||||
 | 
					    SpecExpectation.fail_with "Failed:", msg
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										62
									
								
								spec/mspec/lib/mspec/helpers/fs.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								spec/mspec/lib/mspec/helpers/fs.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,62 @@
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  # Copies a file
 | 
				
			||||||
 | 
					  def cp(source, dest)
 | 
				
			||||||
 | 
					    File.open(dest, "w") do |d|
 | 
				
			||||||
 | 
					      File.open(source, "r") do |s|
 | 
				
			||||||
 | 
					        while data = s.read(1024)
 | 
				
			||||||
 | 
					          d.write data
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Creates each directory in path that does not exist.
 | 
				
			||||||
 | 
					  def mkdir_p(path)
 | 
				
			||||||
 | 
					    parts = File.expand_path(path).split %r[/|\\]
 | 
				
			||||||
 | 
					    name = parts.shift
 | 
				
			||||||
 | 
					    parts.each do |part|
 | 
				
			||||||
 | 
					      name = File.join name, part
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if File.file? name
 | 
				
			||||||
 | 
					        raise ArgumentError, "path component of #{path} is a file"
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Dir.mkdir name unless File.directory? name
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Recursively removes all files and directories in +path+
 | 
				
			||||||
 | 
					  # if +path+ is a directory. Removes the file if +path+ is
 | 
				
			||||||
 | 
					  # a file.
 | 
				
			||||||
 | 
					  def rm_r(*paths)
 | 
				
			||||||
 | 
					    paths.each do |path|
 | 
				
			||||||
 | 
					      path = File.expand_path path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      prefix = SPEC_TEMP_DIR
 | 
				
			||||||
 | 
					      unless path[0, prefix.size] == prefix
 | 
				
			||||||
 | 
					        raise ArgumentError, "#{path} is not prefixed by #{prefix}"
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # File.symlink? needs to be checked first as
 | 
				
			||||||
 | 
					      # File.exist? returns false for dangling symlinks
 | 
				
			||||||
 | 
					      if File.symlink? path
 | 
				
			||||||
 | 
					        File.unlink path
 | 
				
			||||||
 | 
					      elsif File.directory? path
 | 
				
			||||||
 | 
					        Dir.entries(path).each { |x| rm_r "#{path}/#{x}" unless x =~ /^\.\.?$/ }
 | 
				
			||||||
 | 
					        Dir.rmdir path
 | 
				
			||||||
 | 
					      elsif File.exist? path
 | 
				
			||||||
 | 
					        File.delete path
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Creates a file +name+. Creates the directory for +name+
 | 
				
			||||||
 | 
					  # if it does not exist.
 | 
				
			||||||
 | 
					  def touch(name, mode="w")
 | 
				
			||||||
 | 
					    mkdir_p File.dirname(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    File.open(name, mode) do |f|
 | 
				
			||||||
 | 
					      yield f if block_given?
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										113
									
								
								spec/mspec/lib/mspec/helpers/io.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								spec/mspec/lib/mspec/helpers/io.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,113 @@
 | 
				
			||||||
 | 
					require 'mspec/guards/feature'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IOStub
 | 
				
			||||||
 | 
					  def initialize
 | 
				
			||||||
 | 
					    @buffer = []
 | 
				
			||||||
 | 
					    @output = ''
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def write(*str)
 | 
				
			||||||
 | 
					    self << str.join
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def << str
 | 
				
			||||||
 | 
					    @buffer << str
 | 
				
			||||||
 | 
					    self
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def print(*str)
 | 
				
			||||||
 | 
					    write(str.join + $\.to_s)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def method_missing(name, *args, &block)
 | 
				
			||||||
 | 
					    to_s.send(name, *args, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def == other
 | 
				
			||||||
 | 
					    to_s == other
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def =~ other
 | 
				
			||||||
 | 
					    to_s =~ other
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def puts(*str)
 | 
				
			||||||
 | 
					    if str.empty?
 | 
				
			||||||
 | 
					      write "\n"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      write(str.collect { |s| s.to_s.chomp }.concat([nil]).join("\n"))
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def printf(format, *args)
 | 
				
			||||||
 | 
					    self << sprintf(format, *args)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def flush
 | 
				
			||||||
 | 
					    @output += @buffer.join('')
 | 
				
			||||||
 | 
					    @buffer.clear
 | 
				
			||||||
 | 
					    self
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def to_s
 | 
				
			||||||
 | 
					    flush
 | 
				
			||||||
 | 
					    @output
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  alias_method :to_str, :to_s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def inspect
 | 
				
			||||||
 | 
					    to_s.inspect
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  # Creates a "bare" file descriptor (i.e. one that is not associated
 | 
				
			||||||
 | 
					  # with any Ruby object). The file descriptor can safely be passed
 | 
				
			||||||
 | 
					  # to IO.new without creating a Ruby object alias to the fd.
 | 
				
			||||||
 | 
					  def new_fd(name, mode="w:utf-8")
 | 
				
			||||||
 | 
					    mode = options_or_mode(mode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if mode.kind_of? Hash
 | 
				
			||||||
 | 
					      if mode.key? :mode
 | 
				
			||||||
 | 
					        mode = mode[:mode]
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        raise ArgumentError, "new_fd options Hash must include :mode"
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    IO.sysopen name, fmode(mode)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Creates an IO instance for a temporary file name. The file
 | 
				
			||||||
 | 
					  # must be deleted.
 | 
				
			||||||
 | 
					  def new_io(name, mode="w:utf-8")
 | 
				
			||||||
 | 
					    IO.new new_fd(name, options_or_mode(mode)), options_or_mode(mode)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # This helper simplifies passing file access modes regardless of
 | 
				
			||||||
 | 
					  # whether the :encoding feature is enabled. Only the access specifier
 | 
				
			||||||
 | 
					  # itself will be returned if :encoding is not enabled. Otherwise,
 | 
				
			||||||
 | 
					  # the full mode string will be returned (i.e. the helper is a no-op).
 | 
				
			||||||
 | 
					  def fmode(mode)
 | 
				
			||||||
 | 
					    if FeatureGuard.enabled? :encoding
 | 
				
			||||||
 | 
					      mode
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      mode.split(':').first
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # This helper simplifies passing file access modes or options regardless of
 | 
				
			||||||
 | 
					  # whether the :encoding feature is enabled. Only the access specifier itself
 | 
				
			||||||
 | 
					  # will be returned if :encoding is not enabled. Otherwise, the full mode
 | 
				
			||||||
 | 
					  # string or option will be returned (i.e. the helper is a no-op).
 | 
				
			||||||
 | 
					  def options_or_mode(oom)
 | 
				
			||||||
 | 
					    return fmode(oom) if oom.kind_of? String
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if FeatureGuard.enabled? :encoding
 | 
				
			||||||
 | 
					      oom
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      fmode(oom[:mode] || "r:utf-8")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										8
									
								
								spec/mspec/lib/mspec/helpers/mock_to_path.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								spec/mspec/lib/mspec/helpers/mock_to_path.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def mock_to_path(path)
 | 
				
			||||||
 | 
					    # Cannot use our Object#mock here since it conflicts with RSpec
 | 
				
			||||||
 | 
					    obj = MockObject.new('path')
 | 
				
			||||||
 | 
					    obj.should_receive(:to_path).and_return(path)
 | 
				
			||||||
 | 
					    obj
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										72
									
								
								spec/mspec/lib/mspec/helpers/numeric.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								spec/mspec/lib/mspec/helpers/numeric.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,72 @@
 | 
				
			||||||
 | 
					require 'mspec/guards/platform'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def nan_value
 | 
				
			||||||
 | 
					    0/0.0
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def infinity_value
 | 
				
			||||||
 | 
					    1/0.0
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def bignum_value(plus=0)
 | 
				
			||||||
 | 
					    0x8000_0000_0000_0000 + plus
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # This is a bit hairy, but we need to be able to write specs that cover the
 | 
				
			||||||
 | 
					  # boundary between Fixnum and Bignum for operations like Fixnum#<<. Since
 | 
				
			||||||
 | 
					  # this boundary is implementation-dependent, we use these helpers to write
 | 
				
			||||||
 | 
					  # specs based on the relationship between values rather than specific
 | 
				
			||||||
 | 
					  # values.
 | 
				
			||||||
 | 
					  if PlatformGuard.standard? or PlatformGuard.implementation? :topaz
 | 
				
			||||||
 | 
					    if PlatformGuard.wordsize? 32
 | 
				
			||||||
 | 
					      def fixnum_max
 | 
				
			||||||
 | 
					        (2**30) - 1
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      def fixnum_min
 | 
				
			||||||
 | 
					        -(2**30)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    elsif PlatformGuard.wordsize? 64
 | 
				
			||||||
 | 
					      def fixnum_max
 | 
				
			||||||
 | 
					        (2**62) - 1
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      def fixnum_min
 | 
				
			||||||
 | 
					        -(2**62)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  elsif PlatformGuard.implementation? :opal
 | 
				
			||||||
 | 
					    def fixnum_max
 | 
				
			||||||
 | 
					      Integer::MAX
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def fixnum_min
 | 
				
			||||||
 | 
					      Integer::MIN
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  elsif PlatformGuard.implementation? :rubinius
 | 
				
			||||||
 | 
					    def fixnum_max
 | 
				
			||||||
 | 
					      Fixnum::MAX
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def fixnum_min
 | 
				
			||||||
 | 
					      Fixnum::MIN
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  elsif PlatformGuard.implementation?(:jruby) || PlatformGuard.implementation?(:truffleruby)
 | 
				
			||||||
 | 
					    def fixnum_max
 | 
				
			||||||
 | 
					      9223372036854775807
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def fixnum_min
 | 
				
			||||||
 | 
					      -9223372036854775808
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    def fixnum_max
 | 
				
			||||||
 | 
					      raise "unknown implementation for fixnum_max() helper"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def fixnum_min
 | 
				
			||||||
 | 
					      raise "unknown implementation for fixnum_min() helper"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										178
									
								
								spec/mspec/lib/mspec/helpers/ruby_exe.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								spec/mspec/lib/mspec/helpers/ruby_exe.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,178 @@
 | 
				
			||||||
 | 
					require 'mspec/utils/ruby_name'
 | 
				
			||||||
 | 
					require 'mspec/guards/platform'
 | 
				
			||||||
 | 
					require 'mspec/helpers/tmp'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The ruby_exe helper provides a wrapper for invoking the
 | 
				
			||||||
 | 
					# same Ruby interpreter with the same falgs 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 three
 | 
				
			||||||
 | 
					# keys: :options, :args and :env. For example:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   ruby_exe('file.rb', :options => "-w",
 | 
				
			||||||
 | 
					#                       :args => "> file.txt",
 | 
				
			||||||
 | 
					#                       :env => { :FOO => "bar" })
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# will be executed as
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   `#{RUBY_EXE} -w #{'file.rb'} > file.txt`
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# with access to ENV["FOO"] with value "bar".
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# If +nil+ is passed for the first argument, the command line
 | 
				
			||||||
 | 
					# will be built only from the options hash.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The RUBY_EXE constant is setup by mspec automatically
 | 
				
			||||||
 | 
					# and is used by ruby_exe and ruby_cmd. 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.
 | 
				
			||||||
 | 
					# The flags will then be appended to the resulting value.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# 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.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Additionally, the flags passed to mspec
 | 
				
			||||||
 | 
					# (with -T on the command line or in the config with set :flags)
 | 
				
			||||||
 | 
					# will be appended to RUBY_EXE so that the interpreter
 | 
				
			||||||
 | 
					# is always called with those flags.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 'maglev'
 | 
				
			||||||
 | 
					        "maglev-ruby"
 | 
				
			||||||
 | 
					      when 'topaz'
 | 
				
			||||||
 | 
					        "topaz"
 | 
				
			||||||
 | 
					      when 'ironruby'
 | 
				
			||||||
 | 
					        "ir"
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    when :name
 | 
				
			||||||
 | 
					      require 'rbconfig'
 | 
				
			||||||
 | 
					      bin = RUBY_NAME + (RbConfig::CONFIG['EXEEXT'] || RbConfig::CONFIG['exeext'] || '')
 | 
				
			||||||
 | 
					      File.join(".", bin)
 | 
				
			||||||
 | 
					    when :install_name
 | 
				
			||||||
 | 
					      require 'rbconfig'
 | 
				
			||||||
 | 
					      bin = RbConfig::CONFIG["RUBY_INSTALL_NAME"] || RbConfig::CONFIG["ruby_install_name"]
 | 
				
			||||||
 | 
					      bin << (RbConfig::CONFIG['EXEEXT'] || RbConfig::CONFIG['exeext'] || '')
 | 
				
			||||||
 | 
					      File.join(RbConfig::CONFIG['bindir'], bin)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def resolve_ruby_exe
 | 
				
			||||||
 | 
					    [:env, :engine, :name, :install_name].each do |option|
 | 
				
			||||||
 | 
					      next unless exe = ruby_exe_options(option)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if File.file?(exe) and File.executable?(exe)
 | 
				
			||||||
 | 
					        exe = File.expand_path(exe)
 | 
				
			||||||
 | 
					        exe = exe.tr('/', '\\') if PlatformGuard.windows?
 | 
				
			||||||
 | 
					        flags = ENV['RUBY_FLAGS']
 | 
				
			||||||
 | 
					        if flags and !flags.empty?
 | 
				
			||||||
 | 
					          return exe + ' ' + flags
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          return exe
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    raise Exception, "Unable to find a suitable ruby executable."
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def ruby_exe(code, opts = {})
 | 
				
			||||||
 | 
					    if opts[:dir]
 | 
				
			||||||
 | 
					      raise "ruby_exe(..., dir: dir) is no longer supported, use Dir.chdir"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env = opts[:env] || {}
 | 
				
			||||||
 | 
					    saved_env = {}
 | 
				
			||||||
 | 
					    env.each do |key, value|
 | 
				
			||||||
 | 
					      key = key.to_s
 | 
				
			||||||
 | 
					      saved_env[key] = ENV[key] if ENV.key? key
 | 
				
			||||||
 | 
					      ENV[key] = value
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    escape = opts.delete(:escape)
 | 
				
			||||||
 | 
					    if code and !File.exist?(code) and escape != false
 | 
				
			||||||
 | 
					      tmpfile = tmp("rubyexe.rb")
 | 
				
			||||||
 | 
					      File.open(tmpfile, "w") { |f| f.write(code) }
 | 
				
			||||||
 | 
					      code = tmpfile
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    begin
 | 
				
			||||||
 | 
					      platform_is_not :opal do
 | 
				
			||||||
 | 
					        `#{ruby_cmd(code, opts)}`
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    ensure
 | 
				
			||||||
 | 
					      saved_env.each { |key, value| ENV[key] = value }
 | 
				
			||||||
 | 
					      env.keys.each do |key|
 | 
				
			||||||
 | 
					        key = key.to_s
 | 
				
			||||||
 | 
					        ENV.delete key unless saved_env.key? key
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					      File.delete tmpfile if tmpfile
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def ruby_cmd(code, opts = {})
 | 
				
			||||||
 | 
					    body = code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if opts[:escape]
 | 
				
			||||||
 | 
					      raise "escape: true is no longer supported in ruby_cmd, use ruby_exe or a fixture"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if code and !File.exist?(code)
 | 
				
			||||||
 | 
					      body = "-e #{code.inspect}"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [RUBY_EXE, opts[:options], body, opts[:args]].compact.join(' ')
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  unless Object.const_defined?(:RUBY_EXE) and RUBY_EXE
 | 
				
			||||||
 | 
					    RUBY_EXE = resolve_ruby_exe
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										17
									
								
								spec/mspec/lib/mspec/helpers/scratch.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								spec/mspec/lib/mspec/helpers/scratch.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										45
									
								
								spec/mspec/lib/mspec/helpers/tmp.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								spec/mspec/lib/mspec/helpers/tmp.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,45 @@
 | 
				
			||||||
 | 
					# Creates a temporary directory in the current working directory
 | 
				
			||||||
 | 
					# for temporary files created while running the specs. All specs
 | 
				
			||||||
 | 
					# should clean up any temporary files created so that the temp
 | 
				
			||||||
 | 
					# directory is empty when the process exits.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPEC_TEMP_DIR = File.expand_path(ENV["SPEC_TEMP_DIR"] || "rubyspec_temp")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPEC_TEMP_UNIQUIFIER = "0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPEC_TEMP_DIR_PID = Process.pid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					at_exit do
 | 
				
			||||||
 | 
					  begin
 | 
				
			||||||
 | 
					    if SPEC_TEMP_DIR_PID == Process.pid
 | 
				
			||||||
 | 
					      Dir.delete SPEC_TEMP_DIR if File.directory? SPEC_TEMP_DIR
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  rescue SystemCallError
 | 
				
			||||||
 | 
					    STDERR.puts <<-EOM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-----------------------------------------------------
 | 
				
			||||||
 | 
					The rubyspec temp directory is not empty. Ensure that
 | 
				
			||||||
 | 
					all specs are cleaning up temporary files:
 | 
				
			||||||
 | 
					  #{SPEC_TEMP_DIR}
 | 
				
			||||||
 | 
					-----------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    EOM
 | 
				
			||||||
 | 
					  rescue Object => e
 | 
				
			||||||
 | 
					    STDERR.puts "failed to remove spec temp directory"
 | 
				
			||||||
 | 
					    STDERR.puts e.message
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def tmp(name, uniquify=true)
 | 
				
			||||||
 | 
					    Dir.mkdir SPEC_TEMP_DIR unless Dir.exist? SPEC_TEMP_DIR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if uniquify and !name.empty?
 | 
				
			||||||
 | 
					      slash = name.rindex "/"
 | 
				
			||||||
 | 
					      index = slash ? slash + 1 : 0
 | 
				
			||||||
 | 
					      name.insert index, "#{SPEC_TEMP_UNIQUIFIER.succ!}-"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    File.join SPEC_TEMP_DIR, name
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										35
									
								
								spec/mspec/lib/mspec/matchers.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								spec/mspec/lib/mspec/matchers.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					require 'mspec/matchers/base'
 | 
				
			||||||
 | 
					require 'mspec/matchers/be_an_instance_of'
 | 
				
			||||||
 | 
					require 'mspec/matchers/be_ancestor_of'
 | 
				
			||||||
 | 
					require 'mspec/matchers/be_close'
 | 
				
			||||||
 | 
					require 'mspec/matchers/be_computed_by'
 | 
				
			||||||
 | 
					require 'mspec/matchers/be_empty'
 | 
				
			||||||
 | 
					require 'mspec/matchers/be_false'
 | 
				
			||||||
 | 
					require 'mspec/matchers/be_kind_of'
 | 
				
			||||||
 | 
					require 'mspec/matchers/be_nan'
 | 
				
			||||||
 | 
					require 'mspec/matchers/be_nil'
 | 
				
			||||||
 | 
					require 'mspec/matchers/be_true'
 | 
				
			||||||
 | 
					require 'mspec/matchers/be_true_or_false'
 | 
				
			||||||
 | 
					require 'mspec/matchers/complain'
 | 
				
			||||||
 | 
					require 'mspec/matchers/eql'
 | 
				
			||||||
 | 
					require 'mspec/matchers/equal'
 | 
				
			||||||
 | 
					require 'mspec/matchers/equal_element'
 | 
				
			||||||
 | 
					require 'mspec/matchers/have_constant'
 | 
				
			||||||
 | 
					require 'mspec/matchers/have_class_variable'
 | 
				
			||||||
 | 
					require 'mspec/matchers/have_instance_method'
 | 
				
			||||||
 | 
					require 'mspec/matchers/have_instance_variable'
 | 
				
			||||||
 | 
					require 'mspec/matchers/have_method'
 | 
				
			||||||
 | 
					require 'mspec/matchers/have_private_instance_method'
 | 
				
			||||||
 | 
					require 'mspec/matchers/have_private_method'
 | 
				
			||||||
 | 
					require 'mspec/matchers/have_protected_instance_method'
 | 
				
			||||||
 | 
					require 'mspec/matchers/have_public_instance_method'
 | 
				
			||||||
 | 
					require 'mspec/matchers/have_singleton_method'
 | 
				
			||||||
 | 
					require 'mspec/matchers/include'
 | 
				
			||||||
 | 
					require 'mspec/matchers/infinity'
 | 
				
			||||||
 | 
					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'
 | 
				
			||||||
 | 
					require 'mspec/matchers/signed_zero'
 | 
				
			||||||
 | 
					require 'mspec/matchers/block_caller'
 | 
				
			||||||
							
								
								
									
										95
									
								
								spec/mspec/lib/mspec/matchers/base.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								spec/mspec/lib/mspec/matchers/base.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,95 @@
 | 
				
			||||||
 | 
					class SpecPositiveOperatorMatcher
 | 
				
			||||||
 | 
					  def initialize(actual)
 | 
				
			||||||
 | 
					    @actual = actual
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def ==(expected)
 | 
				
			||||||
 | 
					    unless @actual == expected
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Expected #{@actual.pretty_inspect}",
 | 
				
			||||||
 | 
					                            "to equal #{expected.pretty_inspect}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def <(expected)
 | 
				
			||||||
 | 
					    unless @actual < expected
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Expected #{@actual.pretty_inspect}",
 | 
				
			||||||
 | 
					                            "to be less than #{expected.pretty_inspect}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def <=(expected)
 | 
				
			||||||
 | 
					    unless @actual <= expected
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Expected #{@actual.pretty_inspect}",
 | 
				
			||||||
 | 
					                            "to be less than or equal to #{expected.pretty_inspect}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def >(expected)
 | 
				
			||||||
 | 
					    unless @actual > expected
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Expected #{@actual.pretty_inspect}",
 | 
				
			||||||
 | 
					                            "to be greater than #{expected.pretty_inspect}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def >=(expected)
 | 
				
			||||||
 | 
					    unless @actual >= expected
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Expected #{@actual.pretty_inspect}",
 | 
				
			||||||
 | 
					                            "to be greater than or equal to #{expected.pretty_inspect}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def =~(expected)
 | 
				
			||||||
 | 
					    unless @actual =~ expected
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Expected #{@actual.pretty_inspect}",
 | 
				
			||||||
 | 
					                            "to match #{expected.pretty_inspect}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SpecNegativeOperatorMatcher
 | 
				
			||||||
 | 
					  def initialize(actual)
 | 
				
			||||||
 | 
					    @actual = actual
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def ==(expected)
 | 
				
			||||||
 | 
					    if @actual == expected
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Expected #{@actual.pretty_inspect}",
 | 
				
			||||||
 | 
					                            "not to equal #{expected.pretty_inspect}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def <(expected)
 | 
				
			||||||
 | 
					    if @actual < expected
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Expected #{@actual.pretty_inspect}",
 | 
				
			||||||
 | 
					                            "not to be less than #{expected.pretty_inspect}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def <=(expected)
 | 
				
			||||||
 | 
					    if @actual <= expected
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Expected #{@actual.pretty_inspect}",
 | 
				
			||||||
 | 
					                            "not to be less than or equal to #{expected.pretty_inspect}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def >(expected)
 | 
				
			||||||
 | 
					    if @actual > expected
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Expected #{@actual.pretty_inspect}",
 | 
				
			||||||
 | 
					                            "not to be greater than #{expected.pretty_inspect}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def >=(expected)
 | 
				
			||||||
 | 
					    if @actual >= expected
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Expected #{@actual.pretty_inspect}",
 | 
				
			||||||
 | 
					                            "not to be greater than or equal to #{expected.pretty_inspect}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def =~(expected)
 | 
				
			||||||
 | 
					    if @actual =~ expected
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Expected #{@actual.pretty_inspect}",
 | 
				
			||||||
 | 
					                            "not to match #{expected.pretty_inspect}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										26
									
								
								spec/mspec/lib/mspec/matchers/be_an_instance_of.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								spec/mspec/lib/mspec/matchers/be_an_instance_of.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										24
									
								
								spec/mspec/lib/mspec/matchers/be_ancestor_of.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								spec/mspec/lib/mspec/matchers/be_ancestor_of.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										27
									
								
								spec/mspec/lib/mspec/matchers/be_close.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								spec/mspec/lib/mspec/matchers/be_close.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										37
									
								
								spec/mspec/lib/mspec/matchers/be_computed_by.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								spec/mspec/lib/mspec/matchers/be_computed_by.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,37 @@
 | 
				
			||||||
 | 
					class BeComputedByMatcher
 | 
				
			||||||
 | 
					  def initialize(sym, *args)
 | 
				
			||||||
 | 
					    @method = sym
 | 
				
			||||||
 | 
					    @args = args
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def matches?(array)
 | 
				
			||||||
 | 
					    array.each do |line|
 | 
				
			||||||
 | 
					      @receiver = line.shift
 | 
				
			||||||
 | 
					      @value = line.pop
 | 
				
			||||||
 | 
					      @arguments = line
 | 
				
			||||||
 | 
					      @arguments += @args
 | 
				
			||||||
 | 
					      @actual = @receiver.send(@method, *@arguments)
 | 
				
			||||||
 | 
					      return false unless @actual == @value
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def method_call
 | 
				
			||||||
 | 
					    method_call = "#{@receiver.inspect}.#{@method}"
 | 
				
			||||||
 | 
					    unless @arguments.empty?
 | 
				
			||||||
 | 
					      method_call = "#{method_call} from #{@arguments.map { |x| x.inspect }.join(", ")}"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    method_call
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@value.inspect}", "to be computed by #{method_call} (computed #{@actual.inspect} instead)"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def be_computed_by(sym, *args)
 | 
				
			||||||
 | 
					    BeComputedByMatcher.new(sym, *args)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										20
									
								
								spec/mspec/lib/mspec/matchers/be_empty.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								spec/mspec/lib/mspec/matchers/be_empty.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										20
									
								
								spec/mspec/lib/mspec/matchers/be_false.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								spec/mspec/lib/mspec/matchers/be_false.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										24
									
								
								spec/mspec/lib/mspec/matchers/be_kind_of.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								spec/mspec/lib/mspec/matchers/be_kind_of.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										20
									
								
								spec/mspec/lib/mspec/matchers/be_nan.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								spec/mspec/lib/mspec/matchers/be_nan.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					class BeNaNMatcher
 | 
				
			||||||
 | 
					  def matches?(actual)
 | 
				
			||||||
 | 
					    @actual = actual
 | 
				
			||||||
 | 
					    @actual.kind_of?(Float) && @actual.nan?
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@actual}", "to be NaN"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def negative_failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@actual}", "not to be NaN"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def be_nan
 | 
				
			||||||
 | 
					    BeNaNMatcher.new
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										20
									
								
								spec/mspec/lib/mspec/matchers/be_nil.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								spec/mspec/lib/mspec/matchers/be_nil.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										20
									
								
								spec/mspec/lib/mspec/matchers/be_true.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								spec/mspec/lib/mspec/matchers/be_true.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										20
									
								
								spec/mspec/lib/mspec/matchers/be_true_or_false.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								spec/mspec/lib/mspec/matchers/be_true_or_false.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					class BeTrueOrFalseMatcher
 | 
				
			||||||
 | 
					  def matches?(actual)
 | 
				
			||||||
 | 
					    @actual = actual
 | 
				
			||||||
 | 
					    @actual == true || @actual == false
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@actual.inspect}", "to be true or false"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def negative_failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@actual.inspect}", "not to be true or false"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def be_true_or_false
 | 
				
			||||||
 | 
					    BeTrueOrFalseMatcher.new
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										35
									
								
								spec/mspec/lib/mspec/matchers/block_caller.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								spec/mspec/lib/mspec/matchers/block_caller.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					class BlockingMatcher
 | 
				
			||||||
 | 
					  def matches?(block)
 | 
				
			||||||
 | 
					    started = false
 | 
				
			||||||
 | 
					    blocking = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    thread = Thread.new do
 | 
				
			||||||
 | 
					      started = true
 | 
				
			||||||
 | 
					      block.call
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      blocking = false
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while !started and status = thread.status and status != "sleep"
 | 
				
			||||||
 | 
					      Thread.pass
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    thread.kill
 | 
				
			||||||
 | 
					    thread.join
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    blocking
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def failure_message
 | 
				
			||||||
 | 
					    ['Expected the given Proc', 'to block the caller']
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def negative_failure_message
 | 
				
			||||||
 | 
					    ['Expected the given Proc', 'to not block the caller']
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def block_caller(timeout = 0.1)
 | 
				
			||||||
 | 
					    BlockingMatcher.new
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										56
									
								
								spec/mspec/lib/mspec/matchers/complain.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								spec/mspec/lib/mspec/matchers/complain.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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}", "but got: #{@stderr.chomp.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}", "but got: #{@stderr.chomp.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
 | 
				
			||||||
							
								
								
									
										26
									
								
								spec/mspec/lib/mspec/matchers/eql.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								spec/mspec/lib/mspec/matchers/eql.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										26
									
								
								spec/mspec/lib/mspec/matchers/equal.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								spec/mspec/lib/mspec/matchers/equal.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										78
									
								
								spec/mspec/lib/mspec/matchers/equal_element.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								spec/mspec/lib/mspec/matchers/equal_element.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										12
									
								
								spec/mspec/lib/mspec/matchers/have_class_variable.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								spec/mspec/lib/mspec/matchers/have_class_variable.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					require 'mspec/matchers/variable'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HaveClassVariableMatcher < VariableMatcher
 | 
				
			||||||
 | 
					  self.variables_method = :class_variables
 | 
				
			||||||
 | 
					  self.description      = 'class variable'
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def have_class_variable(variable)
 | 
				
			||||||
 | 
					    HaveClassVariableMatcher.new(variable)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										12
									
								
								spec/mspec/lib/mspec/matchers/have_constant.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								spec/mspec/lib/mspec/matchers/have_constant.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					require 'mspec/matchers/variable'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HaveConstantMatcher < VariableMatcher
 | 
				
			||||||
 | 
					  self.variables_method = :constants
 | 
				
			||||||
 | 
					  self.description      = 'constant'
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def have_constant(variable)
 | 
				
			||||||
 | 
					    HaveConstantMatcher.new(variable)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										24
									
								
								spec/mspec/lib/mspec/matchers/have_instance_method.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								spec/mspec/lib/mspec/matchers/have_instance_method.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										12
									
								
								spec/mspec/lib/mspec/matchers/have_instance_variable.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								spec/mspec/lib/mspec/matchers/have_instance_variable.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					require 'mspec/matchers/variable'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HaveInstanceVariableMatcher < VariableMatcher
 | 
				
			||||||
 | 
					  self.variables_method = :instance_variables
 | 
				
			||||||
 | 
					  self.description      = 'instance variable'
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def have_instance_variable(variable)
 | 
				
			||||||
 | 
					    HaveInstanceVariableMatcher.new(variable)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										24
									
								
								spec/mspec/lib/mspec/matchers/have_method.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								spec/mspec/lib/mspec/matchers/have_method.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										24
									
								
								spec/mspec/lib/mspec/matchers/have_private_method.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								spec/mspec/lib/mspec/matchers/have_private_method.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					require 'mspec/matchers/method'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HavePrivateMethodMatcher < MethodMatcher
 | 
				
			||||||
 | 
					  def matches?(mod)
 | 
				
			||||||
 | 
					    @mod = mod
 | 
				
			||||||
 | 
					    mod.private_methods(@include_super).include? @method
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@mod} to have private method '#{@method.to_s}'",
 | 
				
			||||||
 | 
					     "but it does not"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def negative_failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@mod} NOT to have private method '#{@method.to_s}'",
 | 
				
			||||||
 | 
					     "but it does"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def have_private_method(method, include_super=true)
 | 
				
			||||||
 | 
					    HavePrivateMethodMatcher.new method, include_super
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					require 'mspec/matchers/method'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HaveProtectedInstanceMethodMatcher < MethodMatcher
 | 
				
			||||||
 | 
					  def matches?(mod)
 | 
				
			||||||
 | 
					    @mod = mod
 | 
				
			||||||
 | 
					    mod.protected_instance_methods(@include_super).include? @method
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@mod} to have protected instance method '#{@method.to_s}'",
 | 
				
			||||||
 | 
					     "but it does not"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def negative_failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@mod} NOT to have protected instance method '#{@method.to_s}'",
 | 
				
			||||||
 | 
					     "but it does"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def have_protected_instance_method(method, include_super=true)
 | 
				
			||||||
 | 
					    HaveProtectedInstanceMethodMatcher.new method, include_super
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										24
									
								
								spec/mspec/lib/mspec/matchers/have_public_instance_method.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								spec/mspec/lib/mspec/matchers/have_public_instance_method.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					require 'mspec/matchers/method'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HavePublicInstanceMethodMatcher < MethodMatcher
 | 
				
			||||||
 | 
					  def matches?(mod)
 | 
				
			||||||
 | 
					    @mod = mod
 | 
				
			||||||
 | 
					    mod.public_instance_methods(@include_super).include? @method
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@mod} to have public instance method '#{@method.to_s}'",
 | 
				
			||||||
 | 
					     "but it does not"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def negative_failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@mod} NOT to have public instance method '#{@method.to_s}'",
 | 
				
			||||||
 | 
					     "but it does"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def have_public_instance_method(method, include_super=true)
 | 
				
			||||||
 | 
					    HavePublicInstanceMethodMatcher.new method, include_super
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										24
									
								
								spec/mspec/lib/mspec/matchers/have_singleton_method.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								spec/mspec/lib/mspec/matchers/have_singleton_method.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					require 'mspec/matchers/method'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HaveSingletonMethodMatcher < MethodMatcher
 | 
				
			||||||
 | 
					  def matches?(obj)
 | 
				
			||||||
 | 
					    @obj = obj
 | 
				
			||||||
 | 
					    obj.singleton_methods(@include_super).include? @method
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@obj} to have singleton method '#{@method.to_s}'",
 | 
				
			||||||
 | 
					     "but it does not"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def negative_failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@obj} NOT to have singleton method '#{@method.to_s}'",
 | 
				
			||||||
 | 
					     "but it does"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def have_singleton_method(method, include_super=true)
 | 
				
			||||||
 | 
					    HaveSingletonMethodMatcher.new method, include_super
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										32
									
								
								spec/mspec/lib/mspec/matchers/include.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								spec/mspec/lib/mspec/matchers/include.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										28
									
								
								spec/mspec/lib/mspec/matchers/infinity.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								spec/mspec/lib/mspec/matchers/infinity.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					class InfinityMatcher
 | 
				
			||||||
 | 
					  def initialize(expected_sign)
 | 
				
			||||||
 | 
					    @expected_sign = expected_sign
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def matches?(actual)
 | 
				
			||||||
 | 
					    @actual = actual
 | 
				
			||||||
 | 
					    @actual.kind_of?(Float) && @actual.infinite? == @expected_sign
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@actual}", "to be #{"-" if @expected_sign == -1}Infinity"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def negative_failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@actual}", "not to be #{"-" if @expected_sign == -1}Infinity"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def be_positive_infinity
 | 
				
			||||||
 | 
					    InfinityMatcher.new(1)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def be_negative_infinity
 | 
				
			||||||
 | 
					    InfinityMatcher.new(-1)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										47
									
								
								spec/mspec/lib/mspec/matchers/match_yaml.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								spec/mspec/lib/mspec/matchers/match_yaml.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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) == clean_yaml(@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").sub(/\n\.\.\.\n$/, "\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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								spec/mspec/lib/mspec/matchers/method.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								spec/mspec/lib/mspec/matchers/method.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					class MethodMatcher
 | 
				
			||||||
 | 
					  def initialize(method, include_super=true)
 | 
				
			||||||
 | 
					    @include_super = include_super
 | 
				
			||||||
 | 
					    @method = method.to_sym
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def matches?(mod)
 | 
				
			||||||
 | 
					    raise Exception, "define #matches? in the subclass"
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										67
									
								
								spec/mspec/lib/mspec/matchers/output.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								spec/mspec/lib/mspec/matchers/output.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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.inspect}\n"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    unless @err.nil?
 | 
				
			||||||
 | 
					      expected_out += "  $stderr: #{@err.inspect}\n"
 | 
				
			||||||
 | 
					      actual_out += "  $stderr: #{@stderr.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
 | 
				
			||||||
							
								
								
									
										71
									
								
								spec/mspec/lib/mspec/matchers/output_to_fd.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								spec/mspec/lib/mspec/matchers/output_to_fd.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,71 @@
 | 
				
			||||||
 | 
					require 'mspec/helpers/tmp'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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 with_tmp
 | 
				
			||||||
 | 
					    path = tmp("mspec_output_to_#{$$}_#{Time.now.to_i}")
 | 
				
			||||||
 | 
					    File.open(path, 'w+') { |io|
 | 
				
			||||||
 | 
					      yield(io)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ensure
 | 
				
			||||||
 | 
					    File.delete path if path
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def matches?(block)
 | 
				
			||||||
 | 
					    old_to = @to.dup
 | 
				
			||||||
 | 
					    with_tmp do |out|
 | 
				
			||||||
 | 
					      # Replacing with a file handle so that Readline etc. work
 | 
				
			||||||
 | 
					      @to.reopen out
 | 
				
			||||||
 | 
					      begin
 | 
				
			||||||
 | 
					        block.call
 | 
				
			||||||
 | 
					      ensure
 | 
				
			||||||
 | 
					        @to.reopen old_to
 | 
				
			||||||
 | 
					        old_to.close
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      out.rewind
 | 
				
			||||||
 | 
					      @actual = out.read
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      case @expected
 | 
				
			||||||
 | 
					      when Regexp
 | 
				
			||||||
 | 
					        !(@actual =~ @expected).nil?
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        @actual == @expected
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  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
 | 
				
			||||||
							
								
								
									
										79
									
								
								spec/mspec/lib/mspec/matchers/raise_error.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								spec/mspec/lib/mspec/matchers/raise_error.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,79 @@
 | 
				
			||||||
 | 
					require 'mspec/utils/deprecate'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RaiseErrorMatcher
 | 
				
			||||||
 | 
					  def initialize(exception, message, &block)
 | 
				
			||||||
 | 
					    @exception = exception
 | 
				
			||||||
 | 
					    @message = message
 | 
				
			||||||
 | 
					    @block = block
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def matches?(proc)
 | 
				
			||||||
 | 
					    @result = proc.call
 | 
				
			||||||
 | 
					    return false
 | 
				
			||||||
 | 
					  rescue Exception => @actual
 | 
				
			||||||
 | 
					    if matching_exception?(@actual)
 | 
				
			||||||
 | 
					      return true
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      raise @actual
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def matching_exception?(exc)
 | 
				
			||||||
 | 
					    return false unless @exception === exc
 | 
				
			||||||
 | 
					    if @message then
 | 
				
			||||||
 | 
					      case @message
 | 
				
			||||||
 | 
					      when String
 | 
				
			||||||
 | 
					        return false if @message != exc.message
 | 
				
			||||||
 | 
					      when Regexp
 | 
				
			||||||
 | 
					        return false if @message !~ exc.message
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # The block has its own expectations and will throw an exception if it fails
 | 
				
			||||||
 | 
					    @block[exc] if @block
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def exception_class_and_message(exception_class, message)
 | 
				
			||||||
 | 
					    if message
 | 
				
			||||||
 | 
					      "#{exception_class} (#{message})"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      "#{exception_class}"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def format_expected_exception
 | 
				
			||||||
 | 
					    exception_class_and_message(@exception, @message)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def format_exception(exception)
 | 
				
			||||||
 | 
					    exception_class_and_message(exception.class, exception.message)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def failure_message
 | 
				
			||||||
 | 
					    message = ["Expected #{format_expected_exception}"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if @actual then
 | 
				
			||||||
 | 
					      message << "but got #{format_exception(@actual)}"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      message << "but no exception was raised (#{@result.pretty_inspect.chomp} was returned)"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    message
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def negative_failure_message
 | 
				
			||||||
 | 
					    message = ["Expected to not get #{format_expected_exception}", ""]
 | 
				
			||||||
 | 
					    unless @actual.class == @exception
 | 
				
			||||||
 | 
					      message[1] = "but got #{format_exception(@actual)}"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    message
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def raise_error(exception=Exception, message=nil, &block)
 | 
				
			||||||
 | 
					    RaiseErrorMatcher.new(exception, message, &block)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										24
									
								
								spec/mspec/lib/mspec/matchers/respond_to.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								spec/mspec/lib/mspec/matchers/respond_to.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										28
									
								
								spec/mspec/lib/mspec/matchers/signed_zero.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								spec/mspec/lib/mspec/matchers/signed_zero.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					class SignedZeroMatcher
 | 
				
			||||||
 | 
					  def initialize(expected_sign)
 | 
				
			||||||
 | 
					    @expected_sign = expected_sign
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def matches?(actual)
 | 
				
			||||||
 | 
					    @actual = actual
 | 
				
			||||||
 | 
					    (1.0/actual).infinite? == @expected_sign
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@actual}", "to be #{"-" if @expected_sign == -1}0.0"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def negative_failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@actual}", "not to be #{"-" if @expected_sign == -1}0.0"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  def be_positive_zero
 | 
				
			||||||
 | 
					    SignedZeroMatcher.new(1)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def be_negative_zero
 | 
				
			||||||
 | 
					    SignedZeroMatcher.new(-1)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										24
									
								
								spec/mspec/lib/mspec/matchers/variable.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								spec/mspec/lib/mspec/matchers/variable.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					class VariableMatcher
 | 
				
			||||||
 | 
					  class << self
 | 
				
			||||||
 | 
					    attr_accessor :variables_method, :description
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def initialize(variable)
 | 
				
			||||||
 | 
					    @variable = variable.to_sym
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def matches?(object)
 | 
				
			||||||
 | 
					    @object = object
 | 
				
			||||||
 | 
					    @object.send(self.class.variables_method).include? @variable
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@object} to have #{self.class.description} '#{@variable}'",
 | 
				
			||||||
 | 
					     "but it does not"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def negative_failure_message
 | 
				
			||||||
 | 
					    ["Expected #{@object} NOT to have #{self.class.description} '#{@variable}'",
 | 
				
			||||||
 | 
					     "but it does"]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										3
									
								
								spec/mspec/lib/mspec/mocks.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								spec/mspec/lib/mspec/mocks.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					require 'mspec/mocks/mock'
 | 
				
			||||||
 | 
					require 'mspec/mocks/proxy'
 | 
				
			||||||
 | 
					require 'mspec/mocks/object'
 | 
				
			||||||
							
								
								
									
										197
									
								
								spec/mspec/lib/mspec/mocks/mock.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								spec/mspec/lib/mspec/mocks/mock.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,197 @@
 | 
				
			||||||
 | 
					require 'mspec/expectations/expectations'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Object
 | 
				
			||||||
 | 
					  alias_method :__mspec_object_id__, :object_id
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module Mock
 | 
				
			||||||
 | 
					  def self.reset
 | 
				
			||||||
 | 
					    @mocks = @stubs = @objects = nil
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.objects
 | 
				
			||||||
 | 
					    @objects ||= {}
 | 
				
			||||||
 | 
					  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)
 | 
				
			||||||
 | 
					    :"__mspec_#{obj.__mspec_object_id__}_#{sym}__"
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.replaced_key(obj, sym)
 | 
				
			||||||
 | 
					    [replaced_name(obj, sym), sym]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.has_key?(keys, sym)
 | 
				
			||||||
 | 
					    !!keys.find { |k| k.first == sym }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.replaced?(sym)
 | 
				
			||||||
 | 
					    has_key?(mocks.keys, sym) or has_key?(stubs.keys, sym)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.clear_replaced(key)
 | 
				
			||||||
 | 
					    mocks.delete key
 | 
				
			||||||
 | 
					    stubs.delete key
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.mock_respond_to?(obj, sym, include_private = false)
 | 
				
			||||||
 | 
					    name = replaced_name(obj, :respond_to?)
 | 
				
			||||||
 | 
					    if replaced? name
 | 
				
			||||||
 | 
					      obj.__send__ name, sym, include_private
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      obj.respond_to? sym, include_private
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.install_method(obj, sym, type=nil)
 | 
				
			||||||
 | 
					    meta = obj.singleton_class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    key = replaced_key obj, sym
 | 
				
			||||||
 | 
					    sym = sym.to_sym
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (sym == :respond_to? or mock_respond_to?(obj, sym, true)) and !replaced?(key.first)
 | 
				
			||||||
 | 
					      meta.__send__ :alias_method, key.first, sym
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    meta.class_eval {
 | 
				
			||||||
 | 
					      define_method(sym) do |*args, &block|
 | 
				
			||||||
 | 
					        Mock.verify_call self, sym, *args, &block
 | 
				
			||||||
 | 
					      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
 | 
				
			||||||
 | 
					    objects[key] = obj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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|
 | 
				
			||||||
 | 
					      obj = objects[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
 | 
				
			||||||
 | 
					          SpecExpectation.fail_with(
 | 
				
			||||||
 | 
					            "Mock '#{name_or_inspect obj}' expected to receive '#{key.last}' " + \
 | 
				
			||||||
 | 
					            "#{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
 | 
				
			||||||
 | 
					    compare = compare.first if compare.length <= 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    key = replaced_key obj, sym
 | 
				
			||||||
 | 
					    [mocks, stubs].each do |proxies|
 | 
				
			||||||
 | 
					      proxies[key].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
 | 
				
			||||||
 | 
					                SpecExpectation.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
 | 
				
			||||||
 | 
					            SpecExpectation.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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if proxy.raising?
 | 
				
			||||||
 | 
					            raise proxy.raising
 | 
				
			||||||
 | 
					          else
 | 
				
			||||||
 | 
					            return proxy.returning
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if sym.to_sym == :respond_to?
 | 
				
			||||||
 | 
					      mock_respond_to? obj, compare
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      SpecExpectation.fail_with("Mock '#{name_or_inspect obj}': method #{sym}\n",
 | 
				
			||||||
 | 
					                            "called with unexpected arguments (#{Array(compare).join(' ')})")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def self.cleanup
 | 
				
			||||||
 | 
					    objects.each do |key, obj|
 | 
				
			||||||
 | 
					      if obj.kind_of? MockIntObject
 | 
				
			||||||
 | 
					        clear_replaced key
 | 
				
			||||||
 | 
					        next
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      replaced = key.first
 | 
				
			||||||
 | 
					      sym = key.last
 | 
				
			||||||
 | 
					      meta = obj.singleton_class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if mock_respond_to? obj, replaced, true
 | 
				
			||||||
 | 
					        meta.__send__ :alias_method, sym, replaced
 | 
				
			||||||
 | 
					        meta.__send__ :remove_method, replaced
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        meta.__send__ :remove_method, sym
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      clear_replaced key
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  ensure
 | 
				
			||||||
 | 
					    reset
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										28
									
								
								spec/mspec/lib/mspec/mocks/object.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								spec/mspec/lib/mspec/mocks/object.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def mock_int(val)
 | 
				
			||||||
 | 
					    MockIntObject.new(val)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def mock_numeric(name, options={})
 | 
				
			||||||
 | 
					    NumericMockObject.new name, options
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										186
									
								
								spec/mspec/lib/mspec/mocks/proxy.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								spec/mspec/lib/mspec/mocks/proxy.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,186 @@
 | 
				
			||||||
 | 
					class MockObject
 | 
				
			||||||
 | 
					  def initialize(name, options={})
 | 
				
			||||||
 | 
					    @name = name
 | 
				
			||||||
 | 
					    @null = options[:null_object]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def method_missing(sym, *args, &block)
 | 
				
			||||||
 | 
					    @null ? self : super
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					  private :method_missing
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NumericMockObject < Numeric
 | 
				
			||||||
 | 
					  def initialize(name, options={})
 | 
				
			||||||
 | 
					    @name = name
 | 
				
			||||||
 | 
					    @null = options[:null_object]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def method_missing(sym, *args, &block)
 | 
				
			||||||
 | 
					    @null ? self : super
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def singleton_method_added(val)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MockIntObject
 | 
				
			||||||
 | 
					  def initialize(val)
 | 
				
			||||||
 | 
					    @value = val
 | 
				
			||||||
 | 
					    @calls = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    key = [self, :to_int]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Mock.objects[key] = self
 | 
				
			||||||
 | 
					    Mock.mocks[key] << self
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  attr_reader :calls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def to_int
 | 
				
			||||||
 | 
					    @calls += 1
 | 
				
			||||||
 | 
					    @value.to_int
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def count
 | 
				
			||||||
 | 
					    [:at_least, 1]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MockProxy
 | 
				
			||||||
 | 
					  attr_reader :raising, :yielding
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def initialize(type=nil)
 | 
				
			||||||
 | 
					    @multiple_returns = nil
 | 
				
			||||||
 | 
					    @returning = nil
 | 
				
			||||||
 | 
					    @raising   = 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?
 | 
				
			||||||
 | 
					    if args.length == 1
 | 
				
			||||||
 | 
					      @arguments = args.first
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      @arguments = args
 | 
				
			||||||
 | 
					    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_raise(exception)
 | 
				
			||||||
 | 
					    if exception.kind_of? String
 | 
				
			||||||
 | 
					      @raising = RuntimeError.new exception
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      @raising = exception
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def raising?
 | 
				
			||||||
 | 
					    @raising != nil
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def and_yield(*args)
 | 
				
			||||||
 | 
					    @yielding << args
 | 
				
			||||||
 | 
					    self
 | 
				
			||||||
 | 
					  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
 | 
				
			||||||
							
								
								
									
										12
									
								
								spec/mspec/lib/mspec/runner.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								spec/mspec/lib/mspec/runner.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					require 'mspec/mocks'
 | 
				
			||||||
 | 
					require 'mspec/runner/mspec'
 | 
				
			||||||
 | 
					require 'mspec/runner/context'
 | 
				
			||||||
 | 
					require 'mspec/runner/evaluate'
 | 
				
			||||||
 | 
					require 'mspec/runner/example'
 | 
				
			||||||
 | 
					require 'mspec/runner/exception'
 | 
				
			||||||
 | 
					require 'mspec/runner/object'
 | 
				
			||||||
 | 
					require 'mspec/runner/formatters'
 | 
				
			||||||
 | 
					require 'mspec/runner/actions'
 | 
				
			||||||
 | 
					require 'mspec/runner/filters'
 | 
				
			||||||
 | 
					require 'mspec/runner/shared'
 | 
				
			||||||
 | 
					require 'mspec/runner/tag'
 | 
				
			||||||
							
								
								
									
										6
									
								
								spec/mspec/lib/mspec/runner/actions.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								spec/mspec/lib/mspec/runner/actions.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					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'
 | 
				
			||||||
							
								
								
									
										40
									
								
								spec/mspec/lib/mspec/runner/actions/filter.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								spec/mspec/lib/mspec/runner/actions/filter.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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 = descs.empty? ? nil : MatchFilter.new(nil, *descs)
 | 
				
			||||||
 | 
					    @tfilter = nil
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def ===(string)
 | 
				
			||||||
 | 
					    @sfilter === string or @tfilter === string
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def load
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
							
								
								
									
										301
									
								
								spec/mspec/lib/mspec/runner/actions/leakchecker.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										301
									
								
								spec/mspec/lib/mspec/runner/actions/leakchecker.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,301 @@
 | 
				
			||||||
 | 
					# Adapted from ruby's test/lib/leakchecker.rb.
 | 
				
			||||||
 | 
					# Ruby's 2-clause BSDL follows.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					# modification, are permitted provided that the following conditions
 | 
				
			||||||
 | 
					# are met:
 | 
				
			||||||
 | 
					# 1. Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					# notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					# 2. Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					# notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 | 
					# documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 | 
				
			||||||
 | 
					# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
				
			||||||
 | 
					# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
				
			||||||
 | 
					# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 | 
				
			||||||
 | 
					# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
				
			||||||
 | 
					# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
				
			||||||
 | 
					# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 | 
					# SUCH DAMAGE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LeakChecker
 | 
				
			||||||
 | 
					  def initialize
 | 
				
			||||||
 | 
					    @fd_info = find_fds
 | 
				
			||||||
 | 
					    @tempfile_info = find_tempfiles
 | 
				
			||||||
 | 
					    @thread_info = find_threads
 | 
				
			||||||
 | 
					    @env_info = find_env
 | 
				
			||||||
 | 
					    @argv_info = find_argv
 | 
				
			||||||
 | 
					    @encoding_info = find_encodings
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def check(test_name)
 | 
				
			||||||
 | 
					    @no_leaks = true
 | 
				
			||||||
 | 
					    leaks = [
 | 
				
			||||||
 | 
					      check_fd_leak(test_name),
 | 
				
			||||||
 | 
					      check_tempfile_leak(test_name),
 | 
				
			||||||
 | 
					      check_thread_leak(test_name),
 | 
				
			||||||
 | 
					      check_process_leak(test_name),
 | 
				
			||||||
 | 
					      check_env(test_name),
 | 
				
			||||||
 | 
					      check_argv(test_name),
 | 
				
			||||||
 | 
					      check_encodings(test_name)
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    GC.start if leaks.any?
 | 
				
			||||||
 | 
					    return leaks.none?
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private
 | 
				
			||||||
 | 
					  def find_fds
 | 
				
			||||||
 | 
					    fd_dir = "/proc/self/fd"
 | 
				
			||||||
 | 
					    if File.directory?(fd_dir)
 | 
				
			||||||
 | 
					      fds = Dir.open(fd_dir) {|d|
 | 
				
			||||||
 | 
					        a = d.grep(/\A\d+\z/, &:to_i)
 | 
				
			||||||
 | 
					        if d.respond_to? :fileno
 | 
				
			||||||
 | 
					          a -= [d.fileno]
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					        a
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      fds.sort
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      []
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def check_fd_leak(test_name)
 | 
				
			||||||
 | 
					    leaked = false
 | 
				
			||||||
 | 
					    live1 = @fd_info
 | 
				
			||||||
 | 
					    if IO.respond_to?(:console) and (m = IO.method(:console)).arity.nonzero?
 | 
				
			||||||
 | 
					      m[:close]
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    live2 = find_fds
 | 
				
			||||||
 | 
					    fd_closed = live1 - live2
 | 
				
			||||||
 | 
					    if !fd_closed.empty?
 | 
				
			||||||
 | 
					      fd_closed.each {|fd|
 | 
				
			||||||
 | 
					        puts "Closed file descriptor: #{test_name}: #{fd}"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    fd_leaked = live2 - live1
 | 
				
			||||||
 | 
					    if !fd_leaked.empty?
 | 
				
			||||||
 | 
					      leaked = true
 | 
				
			||||||
 | 
					      h = {}
 | 
				
			||||||
 | 
					      ObjectSpace.each_object(IO) {|io|
 | 
				
			||||||
 | 
					        inspect = io.inspect
 | 
				
			||||||
 | 
					        begin
 | 
				
			||||||
 | 
					          autoclose = io.autoclose?
 | 
				
			||||||
 | 
					          fd = io.fileno
 | 
				
			||||||
 | 
					        rescue IOError # closed IO object
 | 
				
			||||||
 | 
					          next
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					        (h[fd] ||= []) << [io, autoclose, inspect]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      fd_leaked.each {|fd|
 | 
				
			||||||
 | 
					        str = ''
 | 
				
			||||||
 | 
					        if h[fd]
 | 
				
			||||||
 | 
					          str << ' :'
 | 
				
			||||||
 | 
					          h[fd].map {|io, autoclose, inspect|
 | 
				
			||||||
 | 
					            s = ' ' + inspect
 | 
				
			||||||
 | 
					            s << "(not-autoclose)" if !autoclose
 | 
				
			||||||
 | 
					            s
 | 
				
			||||||
 | 
					          }.sort.each {|s|
 | 
				
			||||||
 | 
					            str << s
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					        puts "Leaked file descriptor: #{test_name}: #{fd}#{str}"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      #system("lsof -p #$$") if !fd_leaked.empty?
 | 
				
			||||||
 | 
					      h.each {|fd, list|
 | 
				
			||||||
 | 
					        next if list.length <= 1
 | 
				
			||||||
 | 
					        if 1 < list.count {|io, autoclose, inspect| autoclose }
 | 
				
			||||||
 | 
					          str = list.map {|io, autoclose, inspect| " #{inspect}" + (autoclose ? "(autoclose)" : "") }.sort.join
 | 
				
			||||||
 | 
					          puts "Multiple autoclose IO object for a file descriptor:#{str}"
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    @fd_info = live2
 | 
				
			||||||
 | 
					    return leaked
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def extend_tempfile_counter
 | 
				
			||||||
 | 
					    return if defined? LeakChecker::TempfileCounter
 | 
				
			||||||
 | 
					    m = Module.new {
 | 
				
			||||||
 | 
					      @count = 0
 | 
				
			||||||
 | 
					      class << self
 | 
				
			||||||
 | 
					        attr_accessor :count
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      def new(data)
 | 
				
			||||||
 | 
					        LeakChecker::TempfileCounter.count += 1
 | 
				
			||||||
 | 
					        super(data)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    LeakChecker.const_set(:TempfileCounter, m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class << Tempfile::Remover
 | 
				
			||||||
 | 
					      prepend LeakChecker::TempfileCounter
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def find_tempfiles(prev_count=-1)
 | 
				
			||||||
 | 
					    return [prev_count, []] unless defined? Tempfile
 | 
				
			||||||
 | 
					    extend_tempfile_counter
 | 
				
			||||||
 | 
					    count = TempfileCounter.count
 | 
				
			||||||
 | 
					    if prev_count == count
 | 
				
			||||||
 | 
					      [prev_count, []]
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      tempfiles = ObjectSpace.each_object(Tempfile).find_all {|t| t.path }
 | 
				
			||||||
 | 
					      [count, tempfiles]
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def check_tempfile_leak(test_name)
 | 
				
			||||||
 | 
					    return false unless defined? Tempfile
 | 
				
			||||||
 | 
					    count1, initial_tempfiles = @tempfile_info
 | 
				
			||||||
 | 
					    count2, current_tempfiles = find_tempfiles(count1)
 | 
				
			||||||
 | 
					    leaked = false
 | 
				
			||||||
 | 
					    tempfiles_leaked = current_tempfiles - initial_tempfiles
 | 
				
			||||||
 | 
					    if !tempfiles_leaked.empty?
 | 
				
			||||||
 | 
					      leaked = true
 | 
				
			||||||
 | 
					      list = tempfiles_leaked.map {|t| t.inspect }.sort
 | 
				
			||||||
 | 
					      list.each {|str|
 | 
				
			||||||
 | 
					        puts "Leaked tempfile: #{test_name}: #{str}"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      tempfiles_leaked.each {|t| t.close! }
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    @tempfile_info = [count2, initial_tempfiles]
 | 
				
			||||||
 | 
					    return leaked
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def find_threads
 | 
				
			||||||
 | 
					    Thread.list.find_all {|t|
 | 
				
			||||||
 | 
					      t != Thread.current && t.alive?
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def check_thread_leak(test_name)
 | 
				
			||||||
 | 
					    live1 = @thread_info
 | 
				
			||||||
 | 
					    live2 = find_threads
 | 
				
			||||||
 | 
					    thread_finished = live1 - live2
 | 
				
			||||||
 | 
					    leaked = false
 | 
				
			||||||
 | 
					    if !thread_finished.empty?
 | 
				
			||||||
 | 
					      list = thread_finished.map {|t| t.inspect }.sort
 | 
				
			||||||
 | 
					      list.each {|str|
 | 
				
			||||||
 | 
					        puts "Finished thread: #{test_name}: #{str}"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    thread_leaked = live2 - live1
 | 
				
			||||||
 | 
					    if !thread_leaked.empty?
 | 
				
			||||||
 | 
					      leaked = true
 | 
				
			||||||
 | 
					      list = thread_leaked.map {|t| t.inspect }.sort
 | 
				
			||||||
 | 
					      list.each {|str|
 | 
				
			||||||
 | 
					        puts "Leaked thread: #{test_name}: #{str}"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    @thread_info = live2
 | 
				
			||||||
 | 
					    return leaked
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def check_process_leak(test_name)
 | 
				
			||||||
 | 
					    subprocesses_leaked = Process.waitall
 | 
				
			||||||
 | 
					    subprocesses_leaked.each { |pid, status|
 | 
				
			||||||
 | 
					      puts "Leaked subprocess: #{pid}: #{status}"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return !subprocesses_leaked.empty?
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def find_env
 | 
				
			||||||
 | 
					    ENV.to_h
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def check_env(test_name)
 | 
				
			||||||
 | 
					    old_env = @env_info
 | 
				
			||||||
 | 
					    new_env = find_env
 | 
				
			||||||
 | 
					    return false if old_env == new_env
 | 
				
			||||||
 | 
					    (old_env.keys | new_env.keys).sort.each {|k|
 | 
				
			||||||
 | 
					      if old_env.has_key?(k)
 | 
				
			||||||
 | 
					        if new_env.has_key?(k)
 | 
				
			||||||
 | 
					          if old_env[k] != new_env[k]
 | 
				
			||||||
 | 
					            puts "Environment variable changed: #{test_name} : #{k.inspect} changed : #{old_env[k].inspect} -> #{new_env[k].inspect}"
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          puts "Environment variable changed: #{test_name} : #{k.inspect} deleted"
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        if new_env.has_key?(k)
 | 
				
			||||||
 | 
					          puts "Environment variable changed: #{test_name} : #{k.inspect} added"
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          flunk "unreachable"
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    @env_info = new_env
 | 
				
			||||||
 | 
					    return true
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def find_argv
 | 
				
			||||||
 | 
					    ARGV.map { |e| e.dup }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def check_argv(test_name)
 | 
				
			||||||
 | 
					    old_argv = @argv_info
 | 
				
			||||||
 | 
					    new_argv = find_argv
 | 
				
			||||||
 | 
					    leaked = false
 | 
				
			||||||
 | 
					    if new_argv != old_argv
 | 
				
			||||||
 | 
					      puts "ARGV changed: #{test_name} : #{old_argv.inspect} to #{new_argv.inspect}"
 | 
				
			||||||
 | 
					      @argv_info = new_argv
 | 
				
			||||||
 | 
					      leaked = true
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    return leaked
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def find_encodings
 | 
				
			||||||
 | 
					    [Encoding.default_internal, Encoding.default_external]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def check_encodings(test_name)
 | 
				
			||||||
 | 
					    old_internal, old_external = @encoding_info
 | 
				
			||||||
 | 
					    new_internal, new_external = find_encodings
 | 
				
			||||||
 | 
					    leaked = false
 | 
				
			||||||
 | 
					    if new_internal != old_internal
 | 
				
			||||||
 | 
					      leaked = true
 | 
				
			||||||
 | 
					      puts "Encoding.default_internal changed: #{test_name} : #{old_internal} to #{new_internal}"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    if new_external != old_external
 | 
				
			||||||
 | 
					      leaked = true
 | 
				
			||||||
 | 
					      puts "Encoding.default_external changed: #{test_name} : #{old_external} to #{new_external}"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    @encoding_info = [new_internal, new_external]
 | 
				
			||||||
 | 
					    return leaked
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def puts(*args)
 | 
				
			||||||
 | 
					    if @no_leaks
 | 
				
			||||||
 | 
					      @no_leaks = false
 | 
				
			||||||
 | 
					      print "\n"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    super(*args)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LeakCheckerAction
 | 
				
			||||||
 | 
					  def register
 | 
				
			||||||
 | 
					    MSpec.register :start, self
 | 
				
			||||||
 | 
					    MSpec.register :after, self
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def start
 | 
				
			||||||
 | 
					    @checker = LeakChecker.new
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def after(state)
 | 
				
			||||||
 | 
					    unless @checker.check(state.description)
 | 
				
			||||||
 | 
					      if state.example
 | 
				
			||||||
 | 
					        puts state.example.source_location.join(':')
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										133
									
								
								spec/mspec/lib/mspec/runner/actions/tag.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								spec/mspec/lib/mspec/runner/actions/tag.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										56
									
								
								spec/mspec/lib/mspec/runner/actions/taglist.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								spec/mspec/lib/mspec/runner/actions/taglist.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue