| require 'socket' | 
 |  | 
 | begin | 
 |   # ssanders: Try to load RSpec based on the LOADPATH, this allows | 
 |   #           projects (e.g. Rails) to provide alternate versions via the buildpath | 
 |   require 'spec' | 
 | rescue LoadError | 
 |   # ssanders: Fallback to loading from the Gem | 
 |   require 'rubygems' | 
 |  | 
 |   gem 'rspec' | 
 |   require 'spec' | 
 | end | 
 | require 'spec/runner/formatter/base_formatter' | 
 |  | 
 | module Spec | 
 | 	module Example | 
 | 		class ExampleGroup | 
 | 			alias_method :initialize_old, :initialize | 
 | 			def initialize(*args, &block) | 
 | 				result = initialize_old(*args, &block) | 
 | 				# ssanders: Override for "pending" examples | 
 | 				unless block | 
 | 					@from = caller | 
 | 					while !@from.empty? && /.*`it'/ !~ @from.first | 
 | 						@from.shift | 
 | 					end | 
 | 					@from.shift | 
 | 				end | 
 | 				result | 
 | 			end | 
 |  | 
 | 			def implementation_backtrace | 
 | 				if @from | 
 | 					@from | 
 | 				else | 
 | 					super | 
 | 				end | 
 | 			end | 
 | 		end | 
 |  | 
 | 		module ExampleMethods | 
 | 			IN_METHOD_RE = /^(.+):in `(.+)'$/ | 
 | 			def rspecTestName | 
 | 				if @DLTK_backtrace.nil? | 
 |  | 
 | 					# tgrimm: This a workaround for a bug in 1.1.12: | 
 | 					filtered_backtrace = respond_to?(:backtrace) ? backtrace : implementation_backtrace | 
 | 					filtered_backtrace = filtered_backtrace.reject { |bt| bt =~ /(example_group_methods|dltk-rspec-runner.rb)/ } | 
 |  | 
 | 					@DLTK_backtrace = filtered_backtrace[0] | 
 | 					if @DLTK_backtrace =~ IN_METHOD_RE  | 
 | 						@DLTK_backtrace = $1 | 
 | 					end | 
 | 				end | 
 | 				description + '<' + @DLTK_backtrace | 
 | 			end | 
 | 		end | 
 | 	end | 
 | end | 
 |  | 
 | module Spec | 
 | 	module Example | 
 | 		module ExampleGroupMethods | 
 | 			def DLTK_examples_to_run | 
 | 				examples_to_run | 
 | 			end | 
 | 		end | 
 | 	end | 
 | end		 | 
 |  | 
 | unless ::Spec::VERSION::MAJOR > 1 || ::Spec::VERSION::MINOR > 0 | 
 | 	module Spec | 
 | 		module DSL | 
 | 			class Example | 
 | 				alias_method :initialize_old, :initialize | 
 | 				def initialize(*args, &block) | 
 | 					result = initialize_old(*args, &block) | 
 | 					@from = caller(0)[3] | 
 | 					Description.description.examples << self | 
 | 					result | 
 | 				end | 
 | 				IN_METHOD_RE = /^(.+):in `(.+)'$/ | 
 | 				def rspecTestName | 
 | 					if @DLTK_backtrace.nil? | 
 | 						backtrace = @from | 
 | 						if backtrace =~ IN_METHOD_RE  | 
 | 							backtrace = $1 | 
 | 						end | 
 | 						@DLTK_backtrace = backtrace | 
 | 					end | 
 | 					description + '<' + @DLTK_backtrace | 
 | 				end | 
 | 			end | 
 | 		end | 
 | 	end | 
 |  | 
 | 	module Spec | 
 | 		module DSL | 
 | 			class Description | 
 | 				def self.description | 
 | 					@@description | 
 | 				end | 
 | 				alias_method :initialize_old, :initialize | 
 | 				def initialize(*args, &block) | 
 | 					result = initialize_old(*args, &block) | 
 | 					@@description = self | 
 | 					result | 
 | 				end | 
 | 				def description_text | 
 | 					description | 
 | 				end | 
 | 				def examples | 
 | 					@examples ||= [] | 
 | 				end | 
 | 			end | 
 | 		end | 
 | 	end | 
 | end | 
 |  | 
 | module DLTK | 
 | 	module RSpec | 
 | 		module EnvVars | 
 | 			# environment variable name to pass communication port number | 
 | 			# to the launched script | 
 | 			PORT = "RUBY_TESTING_PORT" | 
 | 			PATH = "RUBY_TESTING_PATH" | 
 | 		end # of EnvVars | 
 |  | 
 | 		module MessageIds | 
 | 			# Notification that a test run has started.  | 
 | 			# MessageIds.TEST_RUN_START + testCount.toString + " " + version | 
 | 			TEST_RUN_START = "%TESTC  " | 
 |  | 
 | 			# Notification that a test run has ended. | 
 | 			# TEST_RUN_END + elapsedTime.toString(). | 
 | 			TEST_RUN_END   = "%RUNTIME" | 
 |  | 
 | 			# Notification about a test inside the test suite. | 
 | 			# TEST_TREE + testId + "," + testName + "," + isSuite + "," + testcount | 
 | 			# isSuite = "true" or "false" | 
 | 			TEST_TREE      = "%TSTTREE" | 
 |  | 
 | 			#Notification that a test has started. | 
 | 			# MessageIds.TEST_START + testID + "," + testName | 
 | 			TEST_START     = "%TESTS  " | 
 |  | 
 | 			# Notification that a test has ended. | 
 | 			# TEST_END + testID + "," + testName | 
 | 			TEST_END       = "%TESTE  " | 
 |  | 
 | 			# Notification that a test had a error. | 
 | 			# TEST_ERROR + testID + "," + testName. | 
 | 			# After the notification follows the stack trace. | 
 | 			TEST_ERROR     = "%ERROR  " | 
 |  | 
 | 			# Notification that a test had a failure. | 
 | 			# TEST_FAILED + testID + "," + testName. | 
 | 			# After the notification follows the stack trace. | 
 | 			TEST_FAILED    = "%FAILED " | 
 |  | 
 | 			# Notification that a test trace has started. | 
 | 			# The end of the trace is signaled by a TRACE_END | 
 | 			# message. In between the TRACE_START and TRACE_END | 
 | 			# the stack trace is submitted as multiple lines. | 
 | 			TRACE_START    = "%TRACES " | 
 |  | 
 | 			# Notification that a trace ends. | 
 | 			TRACE_END      = "%TRACEE " | 
 |  | 
 | 			# Notification that the expected result has started. | 
 | 			# The end of the expected result is signaled by a EXPECTED_END. | 
 | 			EXPECTED_START = "%EXPECTS" | 
 |  | 
 | 			# Notification that an expected result ends. | 
 | 			EXPECTED_END   = "%EXPECTE" | 
 |  | 
 | 			# Notification that the actual result has started. | 
 | 			# The end of the actual result is signaled by a ACTUAL_END. | 
 | 			ACTUAL_START   = "%ACTUALS" | 
 |  | 
 | 			# Notification that an actual result ends. | 
 | 			ACTUAL_END     = "%ACTUALE" | 
 |  | 
 | 			#Test identifier prefix for ignored tests. | 
 | 			IGNORED_TEST_PREFIX = "@Ignore: " | 
 |  | 
 | 		end # of MessageIds | 
 |  | 
 | 		class SocketConnection | 
 | 			def disconnect | 
 | 				if @socket | 
 | 					#debug "Closing socket" | 
 | 					begin | 
 | 						@socket.close | 
 | 					rescue | 
 | 						debug $!.to_s | 
 | 					end | 
 | 					@socket = nil | 
 | 					#debug "Socket closed" | 
 | 				end | 
 | 			end | 
 |  | 
 | 			def connectSocket(port) | 
 | 				return false unless port > 0 | 
 | 				#debug "Opening socket on #{port}" | 
 | 				for i in 1..10 | 
 | 					#debug "Iteration #{i}" | 
 | 					begin  | 
 | 						@socket = TCPSocket.new('localhost', port) | 
 | 						#debug "Socket opened" | 
 | 						return true | 
 | 					rescue | 
 | 						#debug $!.to_s | 
 | 					end | 
 | 					sleep 1 | 
 | 				end	 | 
 | 				false | 
 | 			end			 | 
 |  | 
 | 			def sendMessage(message) | 
 | 				#puts message | 
 | 				if @socket | 
 | 					@socket.puts message | 
 | 				end | 
 | 			end | 
 |  | 
 | 			def notifyTestTreeEntry(testId, testName, hasChildren, testCount) | 
 | 				sendMessage MessageIds::TEST_TREE + testId + ',' + escapeComma(testName) + ',' + hasChildren.to_s + ',' + testCount.to_s | 
 | 			end | 
 |  | 
 | 			def notifyTestStarted(testId, testName) | 
 | 				sendMessage MessageIds::TEST_START + testId + "," + escapeComma(testName) | 
 | 			end | 
 |  | 
 | 			def notifyTestFailure(testId, testName, status) | 
 | 				sendMessage status + testId + "," + escapeComma(testName) | 
 | 			end | 
 |  | 
 | 			def notifyTestEnded(testId, testName) | 
 | 				sendMessage MessageIds::TEST_END + testId + "," + escapeComma(testName) | 
 | 			end | 
 |  | 
 | 			def notifyTestRunStarted(testCount) | 
 | 				sendMessage MessageIds::TEST_RUN_START + testCount.to_s + " " + "v2" | 
 | 			end | 
 |  | 
 | 			def notifyTestRunEnded(elapsedTime) | 
 | 				sendMessage MessageIds::TEST_RUN_END + elapsedTime.to_s | 
 | 			end | 
 |  | 
 | 			def escapeComma(s) | 
 | 				s.gsub(/([\\,])/, '\\\\\1') | 
 | 			end | 
 |  | 
 | 			private :escapeComma | 
 |  | 
 | 		end | 
 |  | 
 | 		class DLTKFormatter < Spec::Runner::Formatter::BaseFormatter | 
 | 			def initialize(*args) | 
 | 				super | 
 | 				@connection = SocketConnection.new() | 
 | 			end | 
 |  | 
 | 			def start(example_count) | 
 | 				@connection.connectSocket ENV[EnvVars::PORT].to_i | 
 | 				@connection.notifyTestRunStarted example_count | 
 | 			end | 
 |  | 
 | 			# tgrimm: Since rspec 1.2.4 add_example_group was renamed to example_groupe_started | 
 | 			def add_example_group(example_group) | 
 | 				example_group_started(example_group) | 
 | 				if ::Spec::VERSION::MAJOR > 1 || ::Spec::VERSION::MINOR > 0 | 
 | 					super | 
 | 				end | 
 | 			end | 
 |  | 
 | 			def example_group_started(example_group) | 
 | 				options = @options ? @options : ::Spec::Runner.options | 
 | 				examples_to_run = example_group.examples | 
 | 				examples_to_run = examples_to_run.reject do |example| | 
 | 					matcher = ::Spec::Example::ExampleMatcher.new(example_group.description.to_s, example.description) | 
 | 					!matcher.matches?(options.examples) | 
 | 				end unless options.examples.empty? | 
 | 				if examples_to_run.size > 0 then | 
 | 					# ssanders: Ensure that description is never blank | 
 | 					description = example_group.description || example_group.to_s | 
 | 					@connection.notifyTestTreeEntry getTestId(example_group), description, true, examples_to_run.size | 
 | 					examples_to_run.each do |e| | 
 | 						@connection.notifyTestTreeEntry getTestId(e), getTestName(e), false, 1 | 
 | 					end | 
 | 				end | 
 | 			end | 
 |  | 
 | 			unless ::Spec::VERSION::MAJOR > 1 || ::Spec::VERSION::MINOR > 0 | 
 | 				def add_behaviour(description) | 
 | 					add_example_group(description) | 
 | 				end | 
 | 			end | 
 |  | 
 | 			def example_started(example) | 
 | 				@connection.notifyTestStarted getTestId(example), getTestName(example) | 
 | 			end | 
 |  | 
 | 			def example_passed(example) | 
 | 				@connection.notifyTestEnded getTestId(example), getTestName(example) | 
 | 			end | 
 |  | 
 | 			def example_pending(behaviour, example, message = nil) | 
 | 				# ssanders: In older versions and for "pending" the example is actually passed as behaviour | 
 | 				example = behaviour if example.is_a?(String) | 
 | 				@connection.notifyTestEnded getTestId(example), MessageIds::IGNORED_TEST_PREFIX + getTestName(example) | 
 | 			end | 
 |  | 
 | 			EXPECTED_GOT_RE = /^expected: (.+),\n\s+got: (.+) \(using (==|===)\)$/s | 
 |  | 
 | 			def example_failed(example, counter, failure) | 
 | 				testId = getTestId(example) | 
 | 				testName = getTestName(example) | 
 | 				f = failure.exception | 
 | 				if failure.expectation_not_met? | 
 | 					@connection.notifyTestFailure testId, testName, MessageIds::TEST_FAILED | 
 | 					if f.message =~ EXPECTED_GOT_RE | 
 | 						@connection.sendMessage MessageIds::EXPECTED_START | 
 | 						@connection.sendMessage $1 | 
 | 						@connection.sendMessage MessageIds::EXPECTED_END | 
 | 						@connection.sendMessage MessageIds::ACTUAL_START | 
 | 						@connection.sendMessage $2 | 
 | 						@connection.sendMessage MessageIds::ACTUAL_END | 
 | 					end | 
 | 				else | 
 | 					@connection.notifyTestFailure testId, testName, MessageIds::TEST_ERROR | 
 | 				end | 
 | 				@connection.sendMessage MessageIds::TRACE_START | 
 | 				@connection.sendMessage f.message | 
 | 				f.backtrace.each { |line| @connection.sendMessage line } | 
 | 				@connection.sendMessage MessageIds::TRACE_END | 
 | 				@connection.notifyTestEnded testId, testName | 
 | 			end | 
 |  | 
 | 			def dump_summary(duration, example_count, failure_count, pending_count) | 
 | 				@connection.notifyTestRunEnded((duration * 1000).to_i) | 
 | 			end | 
 |  | 
 | 			def close | 
 | 				@connection.disconnect | 
 | 				@connection = nil	 | 
 | 			end | 
 |  | 
 | 			# internal | 
 |  | 
 | 			def getTestId(example) | 
 | 				return example.__id__.to_s | 
 | 			end | 
 |  | 
 | 			def getTestName(example) | 
 | 				if example.respond_to?(:rspecTestName) | 
 | 					name = example.rspecTestName | 
 | 				elsif example.description | 
 | 					name = example.description ? example.description : "NO NAME" | 
 | 					if example.respond_to?(:location) | 
 | 						name += "<" + example.location if example.location | 
 | 					else | 
 | 						name += "<" + example.backtrace if example.backtrace | 
 | 					end | 
 | 				end | 
 | 				return name.to_s | 
 | 			end | 
 |  | 
 | 		end | 
 | 	end | 
 | end | 
 |  | 
 | #if __FILE__ == $0 | 
 | #	ARGV.push 'bowling_spec.rb' | 
 | #end | 
 |  | 
 | ARGV.push '--format' | 
 | ARGV.push 'DLTK::RSpec::DLTKFormatter' | 
 |  | 
 | # tgrimm: RSpec 1.2.1 was release 7 days after 1.2.0, so there's no real reason to support 1.2.0 | 
 | raise "RSpec 1.2.0 is not supported, please update RSpec" if ::Spec::VERSION::STRING == '1.2.0' | 
 |  | 
 | if ::Spec::VERSION::MAJOR > 1 || ::Spec::VERSION::MINOR > 0 | 
 | 	if ::Spec.constants.include?("Extensions") && ::Spec::Extensions::Main.private_method_defined?(:rspec_options) | 
 | 		options = rspec_options | 
 | 	else # ssanders: RSpec > 1.1.4 | 
 | 		options = ::Spec::Runner.options | 
 | 	end | 
 | 	exit ::Spec::Runner::CommandLine.run(options) | 
 | else # ssanders: RSpec < 1.1 | 
 | 	exit ::Spec::Runner::CommandLine.run(ARGV, STDERR, STDOUT) | 
 | end |