synthesis 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +18 -0
- data/README +55 -0
- data/Rakefile +92 -0
- data/lib/synthesis.rb +12 -0
- data/lib/synthesis/adapter.rb +27 -0
- data/lib/synthesis/adapter/expectations.rb +13 -0
- data/lib/synthesis/adapter/expectations/expectations_adapter.rb +7 -0
- data/lib/synthesis/adapter/expectations/suite_runner.rb +7 -0
- data/lib/synthesis/adapter/mocha.rb +12 -0
- data/lib/synthesis/adapter/mocha/class_method.rb +17 -0
- data/lib/synthesis/adapter/mocha/expectation_record.rb +13 -0
- data/lib/synthesis/adapter/mocha/method_invocation_watcher.rb +12 -0
- data/lib/synthesis/adapter/mocha/mocha_adapter.rb +8 -0
- data/lib/synthesis/adapter/mocha/object.rb +20 -0
- data/lib/synthesis/expectation.rb +81 -0
- data/lib/synthesis/expectation_record.rb +59 -0
- data/lib/synthesis/logging.rb +21 -0
- data/lib/synthesis/method_invocation_watcher.rb +8 -0
- data/lib/synthesis/object.rb +5 -0
- data/lib/synthesis/recordable.rb +15 -0
- data/lib/synthesis/report.rb +21 -0
- data/lib/synthesis/runner.rb +10 -0
- data/lib/synthesis/task.rb +39 -0
- data/test/synthesis/adapter/mocha/expectation_record_test.rb +16 -0
- data/test/synthesis/adapter/mocha/method_invocation_watcher_test.rb +29 -0
- data/test/synthesis/adapter/mocha/object_test.rb +19 -0
- data/test/synthesis/expectation_record_test.rb +46 -0
- data/test/synthesis/expectation_test.rb +68 -0
- data/test/synthesis/method_invocation_watcher_test.rb +13 -0
- data/test/synthesis/recordable_test.rb +22 -0
- data/test_project/expectations/test/data_brander_test.rb +9 -0
- data/test_project/expectations/test/storage_test.rb +14 -0
- data/test_project/lib/data_brander.rb +11 -0
- data/test_project/lib/storage.rb +9 -0
- data/test_project/mocha/test/data_brander_test.rb +10 -0
- data/test_project/mocha/test/storage_test.rb +12 -0
- data/test_project/test_project.rb +3 -0
- 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,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,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,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,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,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,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
|
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
|
+
|