synthesis 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/COPYING +18 -0
  2. data/README +55 -0
  3. data/Rakefile +92 -0
  4. data/lib/synthesis.rb +12 -0
  5. data/lib/synthesis/adapter.rb +27 -0
  6. data/lib/synthesis/adapter/expectations.rb +13 -0
  7. data/lib/synthesis/adapter/expectations/expectations_adapter.rb +7 -0
  8. data/lib/synthesis/adapter/expectations/suite_runner.rb +7 -0
  9. data/lib/synthesis/adapter/mocha.rb +12 -0
  10. data/lib/synthesis/adapter/mocha/class_method.rb +17 -0
  11. data/lib/synthesis/adapter/mocha/expectation_record.rb +13 -0
  12. data/lib/synthesis/adapter/mocha/method_invocation_watcher.rb +12 -0
  13. data/lib/synthesis/adapter/mocha/mocha_adapter.rb +8 -0
  14. data/lib/synthesis/adapter/mocha/object.rb +20 -0
  15. data/lib/synthesis/expectation.rb +81 -0
  16. data/lib/synthesis/expectation_record.rb +59 -0
  17. data/lib/synthesis/logging.rb +21 -0
  18. data/lib/synthesis/method_invocation_watcher.rb +8 -0
  19. data/lib/synthesis/object.rb +5 -0
  20. data/lib/synthesis/recordable.rb +15 -0
  21. data/lib/synthesis/report.rb +21 -0
  22. data/lib/synthesis/runner.rb +10 -0
  23. data/lib/synthesis/task.rb +39 -0
  24. data/test/synthesis/adapter/mocha/expectation_record_test.rb +16 -0
  25. data/test/synthesis/adapter/mocha/method_invocation_watcher_test.rb +29 -0
  26. data/test/synthesis/adapter/mocha/object_test.rb +19 -0
  27. data/test/synthesis/expectation_record_test.rb +46 -0
  28. data/test/synthesis/expectation_test.rb +68 -0
  29. data/test/synthesis/method_invocation_watcher_test.rb +13 -0
  30. data/test/synthesis/recordable_test.rb +22 -0
  31. data/test_project/expectations/test/data_brander_test.rb +9 -0
  32. data/test_project/expectations/test/storage_test.rb +14 -0
  33. data/test_project/lib/data_brander.rb +11 -0
  34. data/test_project/lib/storage.rb +9 -0
  35. data/test_project/mocha/test/data_brander_test.rb +10 -0
  36. data/test_project/mocha/test/storage_test.rb +12 -0
  37. data/test_project/test_project.rb +3 -0
  38. metadata +95 -0
data/COPYING ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2007 nutrun.com, Stuart Caborn, George Malamidis
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,55 @@
1
+ = Synthesis
2
+
3
+ == Philosophy
4
+
5
+ Currently we believe that developers are writing unnecessary functional tests to cover uncertainty about the validity of simulated interactions in their unit tests. In other words, we cannot be certain that all our unit tests 'join up'. If it were possible to correlate the simulated interactions in our unit tests, then we should be able to do away with the need to write large numbers of slow and annoying functional tests (apart from those which interact with the boundaries of the SUT).
6
+
7
+ == Installation
8
+
9
+ sudo gem i synthesis
10
+
11
+ == Dependencies
12
+
13
+ Synthesis's core doesn't have any dependencies.
14
+
15
+ When used with the Expectations adapter, it will depend on the Expectations[http://expectations.rubyforge.org] library.
16
+
17
+ When used with the Mocha adapter, it will depend on the Mocha[http://mocha.rubyforge.org] library.
18
+
19
+ == Usage
20
+
21
+ Synthesis can be used through its Rake task. It currently has two supported adapters: Mocha (with Test::Unit) and Expectations. If +adapter+ is not explicitly specified, the Mocha adapter will be used by default.
22
+
23
+ By default, Synthesis outputs to +STDOUT+, but output can be redirected to alternative IO streams.
24
+
25
+ Synthesis can be setup to ignore certain classes or modules when collecting expectations for verification.
26
+
27
+ If +pattern+ is not specified, it will default to <tt>test/**/*.rb</tt>
28
+
29
+ To use with Test::Unit and Mocha, ignoring Array and Hash:
30
+
31
+ require "synthesis/task"
32
+
33
+ Synthesis::Task.new do |t|
34
+ t.pattern = 'test/unit/**/*_test.rb'
35
+ t.ignore Array, Hash
36
+ end
37
+
38
+ To use with Expectations, redirecting output to a file
39
+
40
+ require "synthesis/task"
41
+
42
+ Synthesis::Task.new do |t|
43
+ t.adapter = :expectations
44
+ t.out = File.new "synthesis.test.txt", "a"
45
+ end
46
+
47
+ == Known Issues
48
+
49
+ Synthesis will currently ignore dynamically generated at runtime methods.
50
+
51
+ == Related reading
52
+
53
+ * Synthesized Testing: A Primer ( http://nutrun.com/weblog/synthesized-testing-a-primer )
54
+ * Using Synthesis With Test::Unit and Mocha ( http://nutrun.com/weblog/using-synthesis-with-test-unit-and-mocha )
55
+ * Using Synthesis With Expectations ( http://nutrun.com/weblog/using-synthesis-with-expectations )
data/Rakefile ADDED
@@ -0,0 +1,92 @@
1
+ require "rubygems"
2
+ require "rake/testtask"
3
+ require "rake/gempackagetask"
4
+ require 'rake/rdoctask'
5
+ require 'rake/contrib/sshpublisher'
6
+ require File.dirname(__FILE__) + "/lib/synthesis/task"
7
+
8
+ task :default => :test
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.pattern = 'test/**/*_test.rb'
11
+ end
12
+
13
+ Synthesis::Task.new('synthesis:test:expectations') do |t|
14
+ t.adapter = :expectations
15
+ t.pattern = 'test_project/expectations/test/*_test.rb'
16
+ end
17
+
18
+ Synthesis::Task.new do |t|
19
+ t.pattern = 'test_project/mocha/test/*_test.rb'
20
+ t.ignore Array, Hash
21
+ # t.out = File.new('synthesis.test.txt', 'a')
22
+ end
23
+
24
+ desc 'Generate RDoc'
25
+ Rake::RDocTask.new do |task|
26
+ task.main = 'README'
27
+ task.title = 'synthesis'
28
+ task.rdoc_dir = 'doc'
29
+ task.options << "--line-numbers" << "--inline-source"
30
+ task.rdoc_files.include('README', 'lib/**/*.rb')
31
+ end
32
+
33
+ desc "Upload RDoc to RubyForge"
34
+ task :publish_rdoc do
35
+ Rake::Task[:rdoc].invoke
36
+ Rake::SshDirPublisher.new("gmalamid@rubyforge.org", "/var/www/gforge-projects/synthesis", "doc").upload
37
+ end
38
+
39
+ namespace :svn do
40
+ task :st do
41
+ puts %x[svn st]
42
+ end
43
+
44
+ task :up do
45
+ puts %x[svn up]
46
+ end
47
+
48
+ task :add do
49
+ %x[svn st].split(/\n/).each do |line|
50
+ trimmed_line = line.delete('?').lstrip
51
+ if line[0,1] =~ /\?/
52
+ %x[svn add #{trimmed_line}]
53
+ puts %[added #{trimmed_line}]
54
+ end
55
+ end
56
+ end
57
+
58
+ task :delete do
59
+ %x[svn st].split(/\n/).each do |line|
60
+ trimmed_line = line.delete('!').lstrip
61
+ if line[0,1] =~ /\!/
62
+ %x[svn rm #{trimmed_line}]
63
+ puts %[removed #{trimmed_line}]
64
+ end
65
+ end
66
+ end
67
+
68
+ desc "Run before checking in"
69
+ task :pc => ['svn:add', 'svn:delete', 'svn:up', :default, 'svn:st']
70
+ end
71
+
72
+ gem_spec = Gem::Specification.new do |s|
73
+ s.name = 'synthesis'
74
+ s.version = '0.0.1'
75
+ s.platform = Gem::Platform::RUBY
76
+ s.rubyforge_project = "synthesis"
77
+ s.summary, s.description = 'A tool for Synthesized Testing'
78
+ s.author = 'Stuart Caborn, George Malamidis'
79
+ s.email = 'george@nutrun.com'
80
+ s.homepage = 'http://nutrun.com/synthesis'
81
+ s.has_rdoc = true
82
+ s.rdoc_options += ['--quiet', '--title', 'Queueue', '--main', 'README', '--inline-source']
83
+ s.extra_rdoc_files = ['README', 'COPYING']
84
+ excluded = FileList['etc/*']
85
+ # s.test_files = FileList['test/**/*_test.rb']
86
+ s.files = FileList['**/*.rb', 'COPYING', 'README', 'Rakefile'] - excluded
87
+ end
88
+
89
+ Rake::GemPackageTask.new(gem_spec) do |t|
90
+ t.need_zip = false
91
+ t.need_tar = false
92
+ end
data/lib/synthesis.rb ADDED
@@ -0,0 +1,12 @@
1
+ require "set"
2
+
3
+ $: << File.dirname(__FILE__)
4
+
5
+ require "synthesis/logging"
6
+ require "synthesis/recordable"
7
+ require "synthesis/object"
8
+ require "synthesis/expectation_record"
9
+ require "synthesis/method_invocation_watcher"
10
+ require "synthesis/expectation"
11
+ require "synthesis/report"
12
+ require "synthesis/adapter"
@@ -0,0 +1,27 @@
1
+ module Synthesis
2
+ # Subclasses of Synthesis::Adapter must implement the run method
3
+ class Adapter
4
+ include Logging
5
+
6
+ def initialize(pattern)
7
+ @pattern = pattern
8
+ end
9
+
10
+ def fail_unless(&block)
11
+ log "Collecting expectations..."
12
+ Dir[@pattern].each { |t| require t }
13
+ exit -1 unless yield
14
+ log "Verifying expectation invocations..."
15
+ ExpectationRecord.record_invocations
16
+ yield
17
+ end
18
+
19
+ def self.inherited(subclass)
20
+ @adapter = subclass
21
+ end
22
+
23
+ def self.load(pattern)
24
+ @adapter.new(pattern)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ require "rubygems"
2
+ require "mocha_standalone"
3
+ require "expectations"
4
+
5
+ $: << File.dirname(__FILE__) + "/../../"
6
+
7
+ require "synthesis"
8
+ require "synthesis/adapter/mocha/object"
9
+ require "synthesis/adapter/mocha/class_method"
10
+ require "synthesis/adapter/mocha/expectation_record"
11
+ require "synthesis/adapter/mocha/method_invocation_watcher"
12
+ require "synthesis/adapter/expectations/expectations_adapter"
13
+ require "synthesis/adapter/expectations/suite_runner"
@@ -0,0 +1,7 @@
1
+ module Synthesis
2
+ class ExpectationsAdapter < Adapter
3
+ def run
4
+ fail_unless { Expectations::SuiteRunner.instance.suite.execute }
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Expectations
2
+ class SuiteRunner
3
+ def initialize
4
+ self.suite = Expectations::Suite.new
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ require "rubygems"
2
+ require "mocha_standalone"
3
+ require "test/unit"
4
+
5
+ $: << File.dirname(__FILE__) + "/../../"
6
+
7
+ require "synthesis"
8
+ require "synthesis/adapter/mocha/object"
9
+ require "synthesis/adapter/mocha/class_method"
10
+ require "synthesis/adapter/mocha/expectation_record"
11
+ require "synthesis/adapter/mocha/method_invocation_watcher"
12
+ require "synthesis/adapter/mocha/mocha_adapter"
@@ -0,0 +1,17 @@
1
+ module Mocha
2
+ class ClassMethod
3
+ alias mocha_stub stub
4
+
5
+ def stub
6
+ @stubbee.mocked!
7
+ mocha_stub
8
+ end
9
+
10
+ alias mocha_unstub unstub
11
+
12
+ def unstub
13
+ mocha_unstub
14
+ @stubbee.unmocked!
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ module Synthesis
2
+ class ExpectationRecord
3
+ class << self
4
+ alias_method :add_mocha_expectation, :add_expectation
5
+
6
+ def add_expectation(obj, meth, args = [])
7
+ # Ignone things like "foo = mock"
8
+ return nil if obj.is_a?(Class::AnyInstance)
9
+ add_mocha_expectation(obj, meth, args)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module Synthesis
2
+ class MethodInvocationWatcher
3
+ class << self
4
+ alias mocha_invoked invoked
5
+
6
+ def invoked(receiver, method, args = [])
7
+ return nil if receiver.mocked?
8
+ mocha_invoked(receiver, method, args)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ module Synthesis
2
+ class MochaAdapter < Adapter
3
+ def run
4
+ Test::Unit.run = true # Yes means no...
5
+ fail_unless { Test::Unit::AutoRunner.run }
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,20 @@
1
+ class Object
2
+ alias mocha_expects expects
3
+
4
+ def expects(meth)
5
+ Synthesis::ExpectationRecord.add_expectation(self, meth)
6
+ mocha_expects(meth)
7
+ end
8
+
9
+ def mocked!
10
+ @mocked = true
11
+ end
12
+
13
+ def unmocked!
14
+ @mocked = false
15
+ end
16
+
17
+ def mocked?
18
+ @mocked
19
+ end
20
+ end
@@ -0,0 +1,81 @@
1
+ module Synthesis
2
+ module Expectation
3
+ def self.new(receiver, method, args = [])
4
+ if receiver.is_a?(Class) || receiver.is_a?(Module)
5
+ Singleton.new(receiver, method, args)
6
+ else
7
+ Instance.new(receiver, method, args)
8
+ end
9
+ end
10
+
11
+ class Expectation
12
+ include Logging
13
+ attr_reader :receiver, :method, :args
14
+
15
+ def initialize(receiver, method, args)
16
+ @receiver, @method, @args = receiver, method, args
17
+ end
18
+
19
+ def record_invocations
20
+ meta_receiver.extend Recordable
21
+ meta_receiver.recordable_method @method
22
+ rescue NameError => e
23
+ log "Failed to record #{@method} on #{@receiver} : #{e.message}"
24
+ end
25
+
26
+ def ==(other)
27
+ eql?(other)
28
+ end
29
+
30
+ def invoked?
31
+ @invoked
32
+ end
33
+
34
+ def invoked!
35
+ @invoked = true
36
+ end
37
+ end
38
+
39
+ class Singleton < Expectation
40
+ def meta_receiver
41
+ @receiver.__metaclass__
42
+ end
43
+
44
+ def eql?(other)
45
+ @receiver.name == other.receiver.name && @method == other.method
46
+ end
47
+
48
+ def hash
49
+ (@receiver.name.hash * 23) + @method.hash
50
+ end
51
+
52
+ def to_s
53
+ "#{@receiver.name}.#{@method}"
54
+ end
55
+ end
56
+
57
+ class Instance < Expectation
58
+ def meta_receiver
59
+ @receiver.class
60
+ end
61
+
62
+ def eql?(other)
63
+ meta_receiver.name == other.meta_receiver.name && @method == other.method
64
+ end
65
+
66
+ def hash
67
+ (meta_receiver.name.hash * 23) + @method.hash
68
+ end
69
+
70
+ def to_s
71
+ "#{meta_receiver.name}.new.#{@method}"
72
+ end
73
+ end
74
+
75
+ class NilExpectation < Expectation
76
+ def initialize;end
77
+ def invoked!;end
78
+ def record_invocations;end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,59 @@
1
+ module Synthesis
2
+ class ExpectationRecord
3
+ class << self
4
+ include Logging
5
+
6
+ def add_expectation(receiver, method, args = [])
7
+ expectations << Expectation.new(receiver, method, args) unless ignore? receiver
8
+ end
9
+
10
+ def ignore(*args)
11
+ ignored.merge args
12
+ end
13
+
14
+ def expectations
15
+ @expectations ||= Set.new
16
+ end
17
+
18
+ def ignored
19
+ @ignored ||= Set.new
20
+ end
21
+
22
+ def [](matcher)
23
+ expectations.detect { |e| e == matcher } || Expectation::NilExpectation.new
24
+ end
25
+
26
+ def record_invocations
27
+ expectations.each { |e| e.record_invocations }
28
+ end
29
+
30
+ def tested_expectations
31
+ expectations.select { |e| e.invoked? }
32
+ end
33
+
34
+ def untested_expectations
35
+ expectations.select { |e| !e.invoked? }
36
+ end
37
+
38
+ def print_tested_expectations
39
+ log; log "Tested Expectations: "
40
+ tested_expectations.each { |e| log e }
41
+ end
42
+
43
+ def print_untested_expectations
44
+ log; log "Untested Expectations: "
45
+ untested_expectations.each { |e| log e }
46
+ end
47
+
48
+ def print_ignored
49
+ log; log "Ignoring: #{ignored.to_a * ', '}"
50
+ end
51
+
52
+ private
53
+
54
+ def ignore?(obj)
55
+ ignored.include?(obj.class) || ignored.include?(obj)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,21 @@
1
+ module Synthesis
2
+ module Logging
3
+ def silence!
4
+ @silent = true
5
+ end
6
+
7
+ def speak!
8
+ @silent = false
9
+ end
10
+
11
+ protected
12
+
13
+ def log(msg = '')
14
+ out.puts "[Synthesis] #{msg}" unless @silent
15
+ end
16
+
17
+ def out
18
+ Synthesis::Logging.const_defined?(:OUT) ? OUT : STDOUT
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ module Synthesis
2
+ class MethodInvocationWatcher
3
+ def self.invoked(receiver, method, args = [])
4
+ matcher = Expectation.new(receiver, method, args)
5
+ ExpectationRecord[matcher].invoked!
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ class Object
2
+ def __metaclass__
3
+ class << self; self end
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ module Synthesis
2
+ module Recordable
3
+ def recordable_method(method)
4
+ alias_method "__recordable__#{method}", method
5
+ class_eval @@recordable_method_def[method]
6
+ end
7
+
8
+ @@recordable_method_def = proc { |method| %(
9
+ def #{method}(*args, &block)
10
+ MethodInvocationWatcher.invoked(self, "#{method}".intern, args)
11
+ send "__recordable__#{method}", *args, &block
12
+ end
13
+ )}
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ module Synthesis
2
+ extend Logging
3
+
4
+ def report!
5
+ if failed?
6
+ ExpectationRecord.print_tested_expectations
7
+ ExpectationRecord.print_untested_expectations
8
+ ExpectationRecord.print_ignored
9
+ log; log "FAILED."
10
+ return -1
11
+ end
12
+ log; log "SUCCESS."
13
+ 0
14
+ end
15
+
16
+ def failed?
17
+ ExpectationRecord.untested_expectations.any?
18
+ end
19
+
20
+ module_function :report!, :failed?
21
+ end
@@ -0,0 +1,10 @@
1
+ module Synthesis
2
+ class Runner
3
+ def self.run(adapter, pattern)
4
+ require "synthesis/adapter/#{adapter}"
5
+ Adapter.load(pattern).run
6
+ end
7
+ end
8
+ end
9
+
10
+ at_exit { exit Synthesis.report! unless $! }
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rake'
3
+ require 'rake/tasklib'
4
+
5
+ module Synthesis
6
+ class Task < Rake::TaskLib
7
+ attr_accessor :verbose, :pattern, :ruby_opts, :adapter, :out
8
+
9
+ def initialize(name='synthesis:test')
10
+ @name = name
11
+ @ignored = []
12
+ yield self if block_given?
13
+ @pattern ||= 'test/**/*.rb'
14
+ @ruby_opts ||= []
15
+ @adapter ||= :mocha
16
+ define
17
+ end
18
+
19
+ def ignore(*classes)
20
+ @ignored << classes
21
+ @ignored.flatten!
22
+ end
23
+
24
+ def define
25
+ desc "Run Synthesis tests"
26
+ task @name do
27
+ RakeFileUtils.verbose(@verbose) do
28
+ @ruby_opts.unshift("-w") if @warning
29
+ require File.dirname(__FILE__) + "/../synthesis"
30
+ require File.dirname(__FILE__) + "/../synthesis/runner"
31
+ Synthesis::Logging.const_set(:OUT, @out) if @out
32
+ Synthesis::ExpectationRecord.ignore(*@ignored)
33
+ Synthesis::Runner.run(@adapter, @pattern)
34
+ end
35
+ end
36
+ self
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,16 @@
1
+ require "test/unit"
2
+ require File.dirname(__FILE__) + "/../../../../lib/synthesis/adapter/mocha"
3
+
4
+ module Synthesis
5
+ class ExpectationRecordTest < Test::Unit::TestCase
6
+ def teardown
7
+ ExpectationRecord.expectations.clear
8
+ end
9
+
10
+ def test_does_not_add_any_instance_expectation
11
+ any = Class::AnyInstance.new(Object)
12
+ ExpectationRecord.add_expectation(any, :foo)
13
+ assert_equal(0, ExpectationRecord.expectations.size)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ %w(test/unit rubygems mocha).each { |l| require l }
2
+ require File.dirname(__FILE__) + "/../../../../lib/synthesis/adapter/mocha"
3
+
4
+ module Synthesis
5
+ class MethodInvocationWatcherTest < Test::Unit::TestCase
6
+ def teardown
7
+ ExpectationRecord.expectations.clear
8
+ end
9
+
10
+ def test_ignores_invocation_for_mocked_object
11
+ foo = Class.new { def self.bar;end }
12
+ ExpectationRecord.add_expectation foo, :bar
13
+ ExpectationRecord.record_invocations
14
+ e = ExpectationRecord.expectations.to_a[0]
15
+ foo.expects(:bar)
16
+ foo.bar
17
+ assert !e.invoked?
18
+ end
19
+
20
+ def test_records_invocation_for_non_mocked_object
21
+ foo = Class.new { def self.bar;end }
22
+ ExpectationRecord.add_expectation foo, :bar
23
+ ExpectationRecord.record_invocations
24
+ e = ExpectationRecord.expectations.to_a[0]
25
+ foo.bar
26
+ assert e.invoked?
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ %w(test/unit rubygems mocha).each { |l| require l }
2
+ require File.dirname(__FILE__) + "/../../../../lib/synthesis/adapter/mocha"
3
+
4
+ module Synthesis
5
+ class ObjectTest < Test::Unit::TestCase
6
+ def test_records_singleton_method_expectation
7
+ ExpectationRecord.expects(:add_expectation).with(Hash, :foo)
8
+ Hash.expects(:foo)
9
+ Hash.foo
10
+ end
11
+
12
+ def test_records_instance_method_expectation
13
+ hash = Hash.new
14
+ ExpectationRecord.expects(:add_expectation).with(hash, :foo)
15
+ hash.expects(:foo)
16
+ hash.foo
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,46 @@
1
+ %w(test/unit rubygems mocha).each { |l| require l }
2
+ require File.dirname(__FILE__) + "/../../lib/synthesis"
3
+
4
+ module Synthesis
5
+ class ExpectationRecordTest < Test::Unit::TestCase
6
+ def teardown
7
+ ExpectationRecord.expectations.clear
8
+ ExpectationRecord.ignored.clear
9
+ end
10
+
11
+ def test_adds_expectation
12
+ ExpectationRecord.add_expectation Object.new, :to_s
13
+ assert_equal(1, ExpectationRecord.expectations.size)
14
+ end
15
+
16
+ def test_watches_expectation_invocations
17
+ c = Class.new { def foo; end }
18
+ ExpectationRecord.add_expectation c.new, :foo
19
+ ExpectationRecord.record_invocations
20
+ a = c.new
21
+ MethodInvocationWatcher.expects(:invoked).with(a, :foo, [])
22
+ a.foo
23
+ end
24
+
25
+ def test_finds_expectation
26
+ ExpectationRecord.add_expectation Object.new, :foo
27
+ expected = ExpectationRecord.expectations.to_a[0]
28
+ matcher = Expectation.new Object.new, :foo
29
+ actual = ExpectationRecord[matcher]
30
+ assert_equal(expected, actual)
31
+ end
32
+
33
+ def test_returns_nil_expectation_on_no_expectation_found
34
+ ExpectationRecord.add_expectation Object.new, :foo
35
+ matcher = Expectation.new Object.new, :bar
36
+ actual_instance = ExpectationRecord[matcher]
37
+ assert_kind_of Expectation::NilExpectation, actual_instance
38
+ end
39
+
40
+ def test_does_not_add_expectation_for_ignored_class
41
+ ExpectationRecord.ignore Hash
42
+ ExpectationRecord.add_expectation Hash, :foo
43
+ assert ExpectationRecord.expectations.empty?
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,68 @@
1
+ require "test/unit"
2
+ require File.dirname(__FILE__) + "/../../lib/synthesis"
3
+
4
+ module Synthesis
5
+ class ExpectationTest < Test::Unit::TestCase
6
+ def test_creates_singleton_method_expectation_given_class
7
+ expectation = Expectation.new Class.new, :foo
8
+ assert_kind_of Expectation::Singleton, expectation
9
+ end
10
+
11
+ def test_creates_instance_method_expectation_given_instance
12
+ expectation = Expectation.new Class.new.new, :foo
13
+ assert_kind_of Expectation::Instance, expectation
14
+ end
15
+
16
+ def test_creates_singleton_method_expectation_given_module
17
+ expectation = Expectation.new Module.new, :foo
18
+ assert_kind_of Expectation::Singleton, expectation
19
+ end
20
+
21
+ def test_records_instance_receiver_method_invocations
22
+ receiver = Class.new { def foo;end }
23
+ expectation = Expectation.new receiver.new, :foo
24
+ expectation.record_invocations
25
+ assert_respond_to receiver.new, :__recordable__foo
26
+ end
27
+
28
+ def test_records_singleton_receiver_method_invocations
29
+ receiver = Class.new { def self.foo;end }
30
+ expectation = Expectation.new receiver, :foo
31
+ expectation.record_invocations
32
+ assert_respond_to receiver, :__recordable__foo
33
+ end
34
+
35
+ def test_equality
36
+ exp1 = Expectation.new Object.new, :foo
37
+ exp2 = Expectation.new Object.new, :foo
38
+ assert_equal exp1, exp2
39
+ end
40
+
41
+ def test_non_equality
42
+ exp1 = Expectation.new Hash.new, :foo
43
+ exp2 = Expectation.new Array.new, :foo
44
+ assert_not_equal exp1, exp2
45
+ end
46
+
47
+ def test_make_sure_equality_works_with_uniq
48
+ arr = [
49
+ Expectation.new(String, :new, []),
50
+ Expectation.new(String, :new, [])
51
+ ]
52
+ assert_equal(1, arr.uniq.size)
53
+ end
54
+
55
+ def test_does_not_blow_up_on_name_error
56
+ expectation = Expectation.new(Hash, :bad)
57
+ silent(expectation) do
58
+ assert_nothing_raised(NameError) { expectation.record_invocations }
59
+ end
60
+ end
61
+
62
+ def silent(object)
63
+ object.silence!
64
+ yield
65
+ object.speak!
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,13 @@
1
+ %w(test/unit rubygems mocha).each { |l| require l }
2
+ require File.dirname(__FILE__) + "/../../lib/synthesis"
3
+
4
+ module Synthesis
5
+ class MethodInvocationWatcherTest < Test::Unit::TestCase
6
+ def test_marks_expectation_invoked
7
+ ExpectationRecord.add_expectation(Hash, :to_s, [])
8
+ MethodInvocationWatcher.invoked(Hash, :to_s, [])
9
+ expectation = ExpectationRecord.expectations.to_a.first
10
+ assert expectation.invoked?
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ %w(test/unit rubygems mocha).each { |l| require l }
2
+ require File.dirname(__FILE__) + "/../../lib/synthesis"
3
+
4
+ module Synthesis
5
+ class RecordableTest < Test::Unit::TestCase
6
+ def test_redefines_method
7
+ foo = Class.new { def a; end }
8
+ foo.extend Recordable
9
+ foo.recordable_method(:a)
10
+ assert_respond_to(foo.new, :__recordable__a)
11
+ end
12
+
13
+ def test_records_method_invocation
14
+ foo = Class.new { def b; end }
15
+ foo.extend Recordable
16
+ foo.recordable_method(:b)
17
+ bar = foo.new
18
+ MethodInvocationWatcher.expects(:invoked).with(bar, :b, [])
19
+ bar.b
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ require "rubygems"
2
+ require "expectations"
3
+ require File.dirname(__FILE__) + "/../../test_project"
4
+
5
+ Expectations do
6
+ expect Storage.new('whatever').to_receive(:save).with('METAL - rock') do |storage|
7
+ DataBrander.new(storage).save_branded 'rock'
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ require "rubygems"
2
+ require "expectations"
3
+ require File.dirname(__FILE__) + "/../../test_project"
4
+
5
+ Expectations do
6
+ expect "rock" do
7
+ begin
8
+ Storage.new('test.txt').save('rock')
9
+ File.read 'test.txt'
10
+ ensure
11
+ FileUtils.rm_f 'test.txt'
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ class DataBrander
2
+ BRAND = "METAL"
3
+
4
+ def initialize(pstore)
5
+ @pstore = pstore
6
+ end
7
+
8
+ def save_branded(data)
9
+ @pstore.save "#{BRAND} - #{data}"
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ class Storage
2
+ def initialize(filename)
3
+ @filename = filename
4
+ end
5
+
6
+ def save(val)
7
+ File.open(@filename, 'w') {|f| f << val}
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ %w(test/unit rubygems mocha).each { |l| require l }
2
+ require File.dirname(__FILE__) + "/../../test_project"
3
+
4
+ class DataBranderTest < Test::Unit::TestCase
5
+ def test_saves_branded_to_pstore
6
+ pstore = Storage.new 'whatever'
7
+ pstore.expects(:save).with('METAL - rock')
8
+ DataBrander.new(pstore).save_branded 'rock'
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ require "test/unit"
2
+ require "fileutils"
3
+ require File.dirname(__FILE__) + "/../../test_project"
4
+
5
+ class StorageTest < Test::Unit::TestCase
6
+ def test_saves_to_file
7
+ Storage.new('test.txt').save('rock')
8
+ assert_equal 'rock', File.read('test.txt')
9
+ ensure
10
+ FileUtils.rm_f('test.txt')
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ $: << File.dirname(__FILE__) + '/lib/'
2
+ require "storage"
3
+ require "data_brander"
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: synthesis
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Stuart Caborn, George Malamidis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-01-12 00:00:00 +00:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: george@nutrun.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ - COPYING
25
+ files:
26
+ - lib/synthesis/adapter/expectations/expectations_adapter.rb
27
+ - lib/synthesis/adapter/expectations/suite_runner.rb
28
+ - lib/synthesis/adapter/expectations.rb
29
+ - lib/synthesis/adapter/mocha/class_method.rb
30
+ - lib/synthesis/adapter/mocha/expectation_record.rb
31
+ - lib/synthesis/adapter/mocha/method_invocation_watcher.rb
32
+ - lib/synthesis/adapter/mocha/mocha_adapter.rb
33
+ - lib/synthesis/adapter/mocha/object.rb
34
+ - lib/synthesis/adapter/mocha.rb
35
+ - lib/synthesis/adapter.rb
36
+ - lib/synthesis/expectation.rb
37
+ - lib/synthesis/expectation_record.rb
38
+ - lib/synthesis/logging.rb
39
+ - lib/synthesis/method_invocation_watcher.rb
40
+ - lib/synthesis/object.rb
41
+ - lib/synthesis/recordable.rb
42
+ - lib/synthesis/report.rb
43
+ - lib/synthesis/runner.rb
44
+ - lib/synthesis/task.rb
45
+ - lib/synthesis.rb
46
+ - test/synthesis/adapter/mocha/expectation_record_test.rb
47
+ - test/synthesis/adapter/mocha/method_invocation_watcher_test.rb
48
+ - test/synthesis/adapter/mocha/object_test.rb
49
+ - test/synthesis/expectation_record_test.rb
50
+ - test/synthesis/expectation_test.rb
51
+ - test/synthesis/method_invocation_watcher_test.rb
52
+ - test/synthesis/recordable_test.rb
53
+ - test_project/expectations/test/data_brander_test.rb
54
+ - test_project/expectations/test/storage_test.rb
55
+ - test_project/lib/data_brander.rb
56
+ - test_project/lib/storage.rb
57
+ - test_project/mocha/test/data_brander_test.rb
58
+ - test_project/mocha/test/storage_test.rb
59
+ - test_project/test_project.rb
60
+ - COPYING
61
+ - README
62
+ - Rakefile
63
+ has_rdoc: true
64
+ homepage: http://nutrun.com/synthesis
65
+ post_install_message:
66
+ rdoc_options:
67
+ - --quiet
68
+ - --title
69
+ - Queueue
70
+ - --main
71
+ - README
72
+ - --inline-source
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ version:
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ version:
87
+ requirements: []
88
+
89
+ rubyforge_project: synthesis
90
+ rubygems_version: 1.0.1
91
+ signing_key:
92
+ specification_version: 2
93
+ summary: A tool for Synthesized Testing
94
+ test_files: []
95
+