drunit 0.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -17,7 +17,7 @@ end
17
17
 
18
18
  spec = Gem::Specification.new do |s|
19
19
  s.name = %q{drunit}
20
- s.version = "0.2"
20
+ s.version = "0.4.1"
21
21
  s.summary = %q{A library for running tests across multiple applications from a single test case.}
22
22
  s.description = %q{A library for running tests across multiple applications from a single test case.}
23
23
 
@@ -43,10 +43,3 @@ end
43
43
 
44
44
  desc "Clean files generated by rake tasks"
45
45
  task :clobber => [:clobber_rdoc, :clobber_package]
46
-
47
- desc "Generate a gemspec file"
48
- task :gemspec do
49
- File.open("#{spec.name}.gemspec", 'w') do |f|
50
- f.write spec.to_ruby
51
- end
52
- end
@@ -3,42 +3,30 @@ require 'ruby2ruby'
3
3
 
4
4
  module Drunit
5
5
  class RemoteApp
6
- def initialize(name, boot = nil)
6
+ def initialize(name, boot = nil, dir = nil)
7
7
  @name = name
8
8
  @boot = boot
9
- @boot ||= "#{name}/test/drunit_test_helper.rb" if File.exist? "#{name}/test/drunit_test_helper.rb"
10
- @boot ||= "#{name}/test/test_helper.rb" if File.exist? "#{name}/test/test_helper.rb"
9
+ @dir = File.expand_path(dir || name)
10
+ @boot ||= "test/drunit_test_helper.rb" if File.exist? "#{@dir}/test/drunit_test_helper.rb"
11
+ @boot ||= "test/test_helper.rb" if File.exist? "#{@dir}/test/test_helper.rb"
11
12
  @remote_object = nil
12
13
  end
13
14
 
14
- def run(method_name, file, line, *args, &block)
15
- raise_or_return(app.eval(block_to_source(method_name, &block), file, line, method_name, *args), method_name)
16
- end
17
-
18
- def last_assertion_count
19
- app.last_assertion_count
15
+ def new_test_case(class_name = "Test::Unit::TestCase")
16
+ app.new_test_case(class_name)
20
17
  end
21
18
 
22
19
  private
23
- def raise_or_return(e, method_name)
24
- return e unless e.is_a? Exception
25
- if first_remote_line = e.backtrace.grep(Regexp.new(method_name)).last
26
- index = e.backtrace.index(first_remote_line)
27
- raise e, e.message, e.backtrace[0..index] + ["RemoteApp<#{@name}>"] + caller(0)
28
- end
29
- raise e
30
- end
31
-
32
20
  def get_url(pipe)
33
21
  pipe.each_line do |line|
34
22
  return $1 if line =~ /^DRUNIT:URI (.*)$/
35
- STDERR.puts "From drunit_remote>> #{line}"
23
+ STDERR.puts "From drunit_remote(#{@name})>> #{line}"
36
24
  end
37
25
  end
38
26
 
39
27
  def start_app!
40
28
  drb_server = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "bin", "drunit_remote"))
41
- pipe = IO.popen("#{drb_server} #{@boot}")
29
+ pipe = IO.popen("cd #{@dir} && #{drb_server} #{@boot}")
42
30
  pid = pipe.pid
43
31
  url = get_url(pipe) or raise "Could not establish connection to the remote drunit instance."
44
32
  remote_object = DRbObject.new(nil, url)
@@ -49,11 +37,5 @@ module Drunit
49
37
  def app
50
38
  @remote_object ||= start_app!
51
39
  end
52
-
53
- def block_to_source(method_name, &block)
54
- m = Module.new
55
- m.send(:define_method, method_name, &block)
56
- Ruby2Ruby.translate(m, method_name)
57
- end
58
40
  end
59
41
  end
@@ -0,0 +1,31 @@
1
+ module Drunit
2
+ class RemoteError < RuntimeError
3
+
4
+ class << self
5
+ def name
6
+ @name || super
7
+ end
8
+ attr_writer :name
9
+ end
10
+
11
+ def initialize(exception_name)
12
+ @exception_name = exception_name.to_s
13
+ end
14
+
15
+ def class
16
+ type = look_up_exception
17
+ return type if type
18
+ super.name = @exception_name #Now we hope and prey that the name of the class is checked imidiately
19
+ super
20
+ end
21
+
22
+ def look_up_exception
23
+ @exception_name.split("::").inject(Object){|node, part|
24
+ node && node.const_defined?(part) && node.const_get(part)
25
+ }
26
+ end
27
+
28
+ end
29
+ end
30
+
31
+
@@ -1,54 +1,54 @@
1
1
  require 'drb'
2
2
  require 'test/unit'
3
+ require File.join(File.dirname(__FILE__), *%w[remote_error])
3
4
 
4
5
  module Drunit
5
- class RemoteError < RuntimeError
6
- def initialize(real_exception)
7
- @real_exception = real_exception
8
- end
9
- end
10
-
11
6
  class RemoteTest
12
- attr_reader :last_assertion_count
7
+ def new_test_case(name)
8
+ tc = Class.new(eval(name, Object.class_eval{ binding }))
9
+ tc.send(:include, TestCaseModule)
10
+ tc.allocate
11
+ end
13
12
 
14
- class TestCase
15
- include Test::Unit::Assertions
16
- attr_reader :assertion_count
13
+ module TestCaseModule
14
+ def self.included(other)
15
+ other.send(:class_eval) do
16
+ include DRb::DRbUndumped
17
+ attr_reader :assertion_count
18
+ end
19
+ end
17
20
 
18
- def initialize(code, source_file, source_line, method_name)
21
+ def initialize
19
22
  @assertion_count = 0
20
- @method_name = method_name
21
- instance_eval(code, source_file, source_line)
22
23
  end
23
24
 
24
25
  def add_assertion
25
26
  @assertion_count += 1
26
27
  end
27
28
 
28
- def run(*args)
29
- send(@method_name, *args)
29
+ def define(code, source_file, source_line)
30
+ instance_eval(code, source_file, source_line)
30
31
  end
31
- end
32
32
 
33
- def eval(code, source_file, source_line, method_name, *args)
34
- test_case = TestCase.new(code, source_file, source_line, method_name)
35
- return rewrite_exceptions{ test_case.run(*args) }
36
- rescue Exception => e
37
- return e
38
- ensure
39
- @last_assertion_count = defined?(test_case.assertion_count) ? test_case.assertion_count : 0
40
- end
41
- private
42
- # We need to strib down and generalise the exceptions to prevent the integration project from having to know anything about anything.
43
- def rewrite_exceptions
44
- return yield
45
- rescue Test::Unit::AssertionFailedError
46
- raise
47
- rescue ArgumentError => e
48
- raise e unless e.message =~ /Anonymous modules /
49
- raise NameError, "Const Missing", e.backtrace[3..-1]
50
- rescue Exception => e
51
- raise Drunit::RemoteError.new(e.class.name), e.message, e.backtrace
33
+ def run(method_name, *args)
34
+ @assertion_count = 0
35
+ rewrite_exceptions{ __send__(method_name, *args) }
36
+ end
37
+
38
+ private
39
+ # We need to strip down and generalise the exceptions to prevent the integration project from having to know anything about anything.
40
+ def rewrite_exceptions
41
+ begin
42
+ return yield
43
+ rescue Test::Unit::AssertionFailedError
44
+ raise
45
+ rescue ArgumentError => e
46
+ raise e unless e.message =~ /Anonymous modules /
47
+ raise NameError, "Const Missing", e.backtrace[3..-1]
48
+ rescue Exception => e
49
+ raise Drunit::RemoteError.new(e.class.name), e.message, e.backtrace
50
+ end
51
+ end
52
52
  end
53
53
  end
54
54
  end
data/lib/drunit.rb CHANGED
@@ -1,47 +1,76 @@
1
+ require "rubygems"
2
+
1
3
  module Drunit
2
- class RemoteError < RuntimeError
3
- def self.name
4
- @@name
5
- end
6
4
 
7
- def class
8
- if type = look_up_exception
9
- return type
10
- else
11
- @@name = @real_exception.to_s
12
- super
13
- end
5
+ module ClassMethods
6
+ def RemoteApp(name, *args)
7
+ const_set "RemoteAppFor_#{name}", RemoteApp.new(name, *args)
14
8
  end
15
9
 
16
- def look_up_exception
17
- @real_exception.split("::").inject(Object){|node, part|
18
- node && node.const_defined?(part) && node.const_get(part)
19
- }
10
+ def drunit_test_case_class_name
11
+ @drunit_test_case_class_name ||
12
+ (superclass.respond_to?(:drunit_test_case_class_name) ? superclass.drunit_test_case_class_name : "Test::Unit::TestCase")
20
13
  end
21
- end
22
14
 
23
- module ClassMethods
24
- def RemoteApp(name, *args)
25
- const_set "RemoteAppFor_#{name}", RemoteApp.new(name, *args)
15
+ def set_drunit_test_case_class_name(name)
16
+ @drunit_test_case_class_name = name
26
17
  end
27
18
  end
28
19
 
29
20
  def in_app(name, *args, &block)
30
- file, line, method = caller(2).first.split(":")
31
- method ||= "unknown_method"
32
- remote_app_for(name).run(method.gsub(/^in /, "").gsub(/[^a-zA-Z0-9_?!]/, ""), file, line.to_i, *args, &block)
21
+ file, line, method = caller_file_and_method_for_block(&block)
22
+ test_case = remote_test_case_for(name)
23
+ test_case.define(block_to_source(method, &block), file, line)
24
+ test_case.run(method, *args)
25
+ rescue Exception => e
26
+ rewrite_backtrace(e, method, name) or raise
33
27
  ensure
34
- remote_app_for(name).last_assertion_count.times{ add_assertion } rescue nil
28
+ test_case.assertion_count.times{ add_assertion } rescue nil
29
+ end
30
+
31
+ private
32
+ def rewrite_backtrace(e, method_name, app_name)
33
+ backtrace = e.backtrace
34
+ if first_remote_line = backtrace.grep(Regexp.new(method_name)).first
35
+ index = backtrace.index(first_remote_line)
36
+ backtrace = backtrace[0..index] + ["in drunit_remote(#{app_name})"] + caller(1)
37
+ backtrace.map!{|line| line.gsub(/\(druby:\/\/[^\)]+\) /, "")}
38
+ raise e, e.message, backtrace
39
+ end
40
+ end
41
+
42
+ def block_to_source(method_name, &block)
43
+ m = Module.new
44
+ m.send(:define_method, method_name, &block)
45
+ Ruby2Ruby.translate(m, method_name)
35
46
  end
36
47
 
37
48
  def remote_app_for(name)
38
49
  self.class.const_get("RemoteAppFor_#{name}")
39
50
  end
40
51
 
52
+ def remote_test_case_for(name)
53
+ @remote_test_cases ||= {}
54
+ @remote_test_cases[name.to_sym] ||= remote_app_for(name).new_test_case(drunit_test_case_class_name)
55
+ end
56
+
57
+ def set_drunit_test_case_class_name(name)
58
+ @drunit_test_case_class_name = name
59
+ end
60
+
61
+ def drunit_test_case_class_name
62
+ @drunit_test_case_class_name || self.class.drunit_test_case_class_name
63
+ end
64
+
65
+ def caller_file_and_method_for_block(&block)
66
+ eval(%%caller(0)[0] =~ /in `(.*)'/; [__FILE__, __LINE__, $1 || 'unknown_method']%, block.binding)
67
+ end
68
+
41
69
  def self.included(other)
42
70
  other.send(:extend, ClassMethods)
43
71
  end
44
72
  end
45
73
 
46
74
  require File.join(File.dirname(__FILE__), *%w[drunit remote_app])
75
+ require File.join(File.dirname(__FILE__), *%w[drunit remote_error])
47
76
 
@@ -7,6 +7,12 @@ end
7
7
  class SomeException < Exception
8
8
  end
9
9
 
10
+ class SomeOtherTestCase
11
+ def assert_in_new_test_case
12
+ add_assertion
13
+ end
14
+ end
15
+
10
16
  module MyModule
11
17
  class SomeOtherException < Exception
12
18
  end
@@ -2,7 +2,7 @@ require File.join(File.dirname(__FILE__), *%w[.. test_helper])
2
2
 
3
3
  class MainTest < Test::Unit::TestCase
4
4
  include Drunit
5
- RemoteApp(:fake_app, FAKE_APP_PATH + "/fake_app.rb")
5
+ RemoteApp(:fake_app, "fake_app.rb", FAKE_APP_PATH)
6
6
  def InApp(*args, &block)
7
7
  in_app(:fake_app, *args, &block)
8
8
  end
@@ -13,6 +13,11 @@ class MainTest < Test::Unit::TestCase
13
13
  end
14
14
  end
15
15
 
16
+ def test_should_be_in_the_given_dir
17
+ actual = InApp{ File.expand_path Dir.pwd }
18
+ assert_equal File.expand_path(FAKE_APP_PATH), actual
19
+ end
20
+
16
21
  def test_should_raise_an_exception
17
22
  assert_raise(RuntimeError) { InApp{ raise "Fail" } }
18
23
  end
@@ -26,7 +31,7 @@ class MainTest < Test::Unit::TestCase
26
31
 
27
32
  def test_should_inject_the_fact_we_are_in_a_remote_app_into_the_backtrace
28
33
  e = assert_raise(RuntimeError) { InApp{ raise "Fail" } }
29
- assert_equal 1, e.backtrace.grep("RemoteApp<fake_app>").size
34
+ assert_equal 1, e.backtrace.grep("in drunit_remote(fake_app)").size, e.backtrace.join("\n")
30
35
  end
31
36
 
32
37
  def test_should_raise_the_assertion_count_when_we_assert
@@ -35,7 +40,19 @@ class MainTest < Test::Unit::TestCase
35
40
  assert_equal original_count + 1, @_result.assertion_count
36
41
  end
37
42
 
43
+ def test_should_not_count_the_same_assert_twice
44
+ original_count = @_result.assertion_count
45
+ InApp{ assert true}
46
+ InApp{ assert true}
47
+ assert_equal original_count + 2, @_result.assertion_count
48
+ end
49
+
38
50
  def test_should_be_able_to_pass_in_simple_params
39
51
  assert_equal 12, InApp(2,6){|a,b| SomeFoo.new.multiply(a, b)}
40
52
  end
53
+
54
+ def test_consistant_remote_instance
55
+ InApp{ @foo = 1 }
56
+ InApp{ assert_equal 1, @foo }
57
+ end
41
58
  end
@@ -0,0 +1,17 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. test_helper])
2
+
3
+ class SomeOtherTestCaseTest < Test::Unit::TestCase
4
+ include Drunit
5
+ RemoteApp(:fake_app, FAKE_APP_PATH + "/fake_app.rb")
6
+ def InApp(*args, &block)
7
+ in_app(:fake_app, *args, &block)
8
+ end
9
+
10
+ set_drunit_test_case_class_name "SomeOtherTestCase"
11
+
12
+ def test_foo
13
+ InApp{ assert_in_new_test_case }
14
+ end
15
+
16
+ end
17
+
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: drunit
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.2"
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 4
8
+ - 1
9
+ version: 0.4.1
5
10
  platform: ruby
6
11
  authors:
7
12
  - Tom Lea
@@ -9,8 +14,8 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2009-04-07 00:00:00 +01:00
13
- default_executable: drunit_remote
17
+ date: 2010-03-25 00:00:00 +00:00
18
+ default_executable:
14
19
  dependencies: []
15
20
 
16
21
  description: A library for running tests across multiple applications from a single test case.
@@ -25,15 +30,18 @@ files:
25
30
  - Rakefile
26
31
  - README.markdown
27
32
  - lib/drunit/remote_app.rb
33
+ - lib/drunit/remote_error.rb
28
34
  - lib/drunit/remote_test.rb
29
35
  - lib/drunit.rb
30
36
  - test/fake_app/fake_app.rb
31
37
  - test/test_helper.rb
32
38
  - test/unit/exception_handling_test.rb
33
39
  - test/unit/main_test.rb
34
- - bin/drunit_remote
40
+ - test/unit/test_case_switching_test.rb
35
41
  has_rdoc: true
36
42
  homepage:
43
+ licenses: []
44
+
37
45
  post_install_message:
38
46
  rdoc_options:
39
47
  - --line-numbers
@@ -46,21 +54,24 @@ required_ruby_version: !ruby/object:Gem::Requirement
46
54
  requirements:
47
55
  - - ">="
48
56
  - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
49
59
  version: "0"
50
- version:
51
60
  required_rubygems_version: !ruby/object:Gem::Requirement
52
61
  requirements:
53
62
  - - ">="
54
63
  - !ruby/object:Gem::Version
64
+ segments:
65
+ - 0
55
66
  version: "0"
56
- version:
57
67
  requirements: []
58
68
 
59
69
  rubyforge_project:
60
- rubygems_version: 1.3.1
70
+ rubygems_version: 1.3.6
61
71
  signing_key:
62
- specification_version: 2
72
+ specification_version: 3
63
73
  summary: A library for running tests across multiple applications from a single test case.
64
74
  test_files:
65
75
  - test/unit/exception_handling_test.rb
66
76
  - test/unit/main_test.rb
77
+ - test/unit/test_case_switching_test.rb