hornsby 0.4.2

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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Lachie Cox
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,154 @@
1
+ = Hornsby
2
+
3
+ A Scenario Builder without the fixture pain.
4
+
5
+ == Usage
6
+
7
+ Scenarios look like:
8
+
9
+ scenario :apple do
10
+ @apple = Fruit.create! :species => 'apple'
11
+ end
12
+
13
+ scenario :orange do
14
+ @orange = Fruit.create! :species => 'orange'
15
+ end
16
+
17
+ scenario :fruitbowl => [:apple,:orange] do
18
+ @fruitbowl = FruitBowl.create! :fruit => [@apple,@orange]
19
+ end
20
+
21
+ scenario :kitchen => :fruitbowl do
22
+ @kitchen = Kitchen.create! :fruitbowl => @fruitbowl
23
+ end
24
+
25
+ ...and you use them in specs like:
26
+
27
+ describe Fruit, "@apple" do
28
+ before do
29
+ hornsby_scenario :apple
30
+ end
31
+
32
+ it "should be an apple" do
33
+ @apple.species.should == 'apple'
34
+ end
35
+ end
36
+
37
+ describe FruitBowl, "with and apple and an orange" do
38
+ before do
39
+ hornsby_scenario :fruitbowl
40
+ end
41
+
42
+ it "should have 2 fruits" do
43
+ @fruitbowl.should have(2).fruit
44
+ end
45
+ end
46
+
47
+ All scenarios are run only once, no matter how many times they were called, meaning that you don't need to worry about
48
+ duplicating data.
49
+
50
+ There's also a possibility to delete preloaded data with hornsby_clear. When called without arguments it will drop all data.
51
+ You can also pass it table names, that will be cleared of any data. Beware that any scenarios already executed will still be
52
+ marked as executed, so you won't be able to execute them again. If you want to execute those scenarios later in test, you
53
+ can pass :undo option with list of scenarios to mark as not executed or :all if you want to mark that no scenario has been executed.
54
+
55
+ hornsby_clear :fruits, :trees # Deletes trees and fruits tables
56
+ hornsby_clear # Deletes all data except tables that are defined by Hornsby.skip_tables
57
+ hornsby_clear :fruits, :undo => :apples # Deletes fruits table and marks :apples scenario as not executed
58
+ hornsby_clear :undo => :all # Deletes all tables and marks all scenario as not executed (fresh start)
59
+
60
+ Hornsby searches for scenario files in this particular order in Rails (Merb) root:
61
+ * hornsby_scenarios.rb
62
+ * hornsby_scenarios/*.rb
63
+ * hornsby_scenario.rb
64
+ * hornsby_scenario/*.rb
65
+ * spec/hornsby_scenarios.rb
66
+ * spec/hornsby_scenarios/*.rb
67
+ * spec/hornsby_scenario.rb
68
+ * spec/hornsby_scenario/*.rb
69
+ * test/hornsby_scenarios.rb
70
+ * test/hornsby_scenarios/*.rb
71
+ * test/hornsby_scenario.rb
72
+ * test/hornsby_scenario/*.rb
73
+ You can pass :root option to override framework root and :filename option to pass custom filename pattern
74
+
75
+ == Setup
76
+
77
+ The easiest way to install this gem for Ruby on Rails is just add this line to config/environment.rb (or config/environments/test.rb):
78
+
79
+ config.gem 'sinsiliux-hornsby', :lib => 'hornsby', :source => 'http://gems.github.com'
80
+
81
+ If you’re not using rails, then you can install it through command line
82
+
83
+ gem sources -a http://gems.github.com
84
+ sudo gem install sinsiliux-hornsby
85
+
86
+ Lastly you could use it as plugin:
87
+
88
+ ruby script/plugin install git://github.com/sinsiliux/hornsby.git
89
+
90
+ Hornsby scenarios is activated by calling enable_hornsby. For specifics on how to call that in your testing framework see a little lower.
91
+ enable_hornsby supports these parameters:
92
+ * root - custom framework root if automatic detection fails for some reason (eg. not rails/merb project)
93
+ * filename - custom files pattern with hornsby scenarios
94
+ * scenarios - list of hornsby scenarios that should be preloaded (available in all tests, never reloaded so they're much faster)
95
+
96
+ === RSpec
97
+
98
+ Add the following to spec_helper.rb
99
+
100
+ Spec::Runner.configure do |config|
101
+ ...
102
+
103
+ config.enable_hornsby :filename => 'scenarios.rb', :scenarios => :preloaded_scenario
104
+ end
105
+
106
+ === Test::Unit
107
+
108
+ Add the following lines to test_helper.rb
109
+
110
+ class ActiveSupport::TestCase
111
+ ...
112
+
113
+ enable_hornsby
114
+ end
115
+
116
+ == Advanced Usage
117
+
118
+ Its just ruby, right? So go nuts:
119
+
120
+ 1.upto(9) do |i|
121
+ scenario("user_#{i}") do
122
+ user = User.create! :name => "user#{i}"
123
+ instance_variable_set("@user_#{i}",user)
124
+ end
125
+ end
126
+
127
+ == Transactions
128
+
129
+ Hornsby scenarios is transactional, meaning that after every test transaction is dropped and database is reset to
130
+ starting point. Starting point is empty database + any scenarios that you specify in configure_rspec.
131
+
132
+ == Rake
133
+
134
+ If you'd like simply to load your scenarios into a database, use the rake task like so:
135
+
136
+ $ rake hornsby:scenario RAILS_ENV=test SCENARIO=fruitbowl
137
+
138
+ == TODO
139
+
140
+ * Add scenario namespaces for better organisation.
141
+ * Add ability to revert one scenario.
142
+ * Add preloading scenarios for whole block of tests.
143
+
144
+ == Credits
145
+
146
+ Lachie Cox <lachie@smartbomb.com.au>
147
+
148
+ Andrius Chamentauskas <sinsiliux@gmail.com>
149
+
150
+ The code is based on Err's code found in this post: http://errtheblog.com/post/7708
151
+
152
+ == License
153
+
154
+ MIT, see LICENCE
@@ -0,0 +1,159 @@
1
+ require File.join(File.dirname(__FILE__), 'hornsby/context')
2
+ require File.join(File.dirname(__FILE__), 'hornsby/helper')
3
+ require File.join(File.dirname(__FILE__), 'hornsby/errors')
4
+ if defined? Spec
5
+ require File.join(File.dirname(__FILE__), 'hornsby/rspec_extensions')
6
+ else
7
+ require File.join(File.dirname(__FILE__), 'hornsby/test_unit_extensions')
8
+ end
9
+
10
+ class Hornsby
11
+ SCENARIO_FILES = [nil, "spec", "test"].map do |dir|
12
+ ["hornsby_scenarios", "hornsby_scenario"].map do |file|
13
+ path = File.join([dir, file].compact)
14
+ ["#{path}.rb", File.join(path, "*.rb")]
15
+ end
16
+ end.flatten
17
+
18
+ @@delete_sql = "DELETE FROM %s"
19
+
20
+ cattr_reader :scenarios
21
+ cattr_accessor :executed_scenarios
22
+ # @@namespaces = {}
23
+ @@scenarios = {}
24
+ @@executed_scenarios = Set.new
25
+ @@global_executed_scenarios = []
26
+
27
+ @@global_context = Hornsby::Context
28
+ @@context = nil
29
+
30
+ def self.framework_root
31
+ @@framework_root ||= RAILS_ROOT rescue Rails.root rescue Merb.root rescue nil
32
+ end
33
+
34
+ def self.configure_rspec(config, options = {})
35
+ raise '### This is deprecated! Please use config.enable_hornsby instead of Hornsby.configure_rspec(config)'
36
+ end
37
+
38
+ def self.setup(current_context)
39
+ @@context = @@global_context.clone
40
+ @@executed_scenarios = Set.new(@@global_executed_scenarios)
41
+ copy_ivars(current_context, true)
42
+ ActiveRecord::Base.connection.increment_open_transactions
43
+ ActiveRecord::Base.connection.transaction_joinable = false
44
+ ActiveRecord::Base.connection.begin_db_transaction
45
+ end
46
+
47
+ def self.teardown
48
+ ActiveRecord::Base.connection.rollback_db_transaction
49
+ ActiveRecord::Base.connection.decrement_open_transactions
50
+ end
51
+
52
+ def self.build(*names)
53
+ scenarios = names.map {|name| @@scenarios[name.to_sym] or raise ScenarioNotFoundError, name}
54
+
55
+ scenarios.each {|s| s.build}
56
+ end
57
+
58
+ def self.load(options = {})
59
+ return unless @@scenarios.empty?
60
+
61
+ delete_tables
62
+ @@framework_root = options[:root] if options[:root]
63
+ load_scenarios_files(options[:filename] || SCENARIO_FILES)
64
+
65
+ @@context = @@global_context
66
+ @@global_scenarios = Hornsby.build(*options[:scenarios]) if options[:scenarios]
67
+ @@global_executed_scenarios = @@executed_scenarios.to_a
68
+ end
69
+
70
+ def self.load_scenarios_files(*patterns)
71
+ patterns.flatten!
72
+ patterns.collect! {|pattern| File.join(framework_root, pattern)} if framework_root
73
+
74
+ patterns.each do |pattern|
75
+ unless (files = Dir.glob(pattern)).empty?
76
+ files.each{|f| self.module_eval File.read(f)}
77
+ return
78
+ end
79
+ end
80
+
81
+ raise "Scenarios file not found! Put scenarios in #{patterns.join(' or ')} or pass custom filename with :filename option"
82
+ end
83
+
84
+ def self.scenario(scenario, &block)
85
+ self.new(scenario, &block)
86
+ end
87
+
88
+ def self.delete_tables(*args)
89
+ args = tables if args.blank?
90
+ args.each { |t| ActiveRecord::Base.connection.delete(@@delete_sql % t) }
91
+ end
92
+
93
+ def self.tables
94
+ ActiveRecord::Base.connection.tables - skip_tables
95
+ end
96
+
97
+ def self.skip_tables
98
+ %w( schema_info schema_migrations )
99
+ end
100
+
101
+ def self.copy_ivars(to, reload = false)
102
+ @@context.copy_ivars(to, reload)
103
+ end
104
+
105
+ attr_reader :scenario
106
+
107
+ def initialize(scenario, &block)
108
+ @scenario, @parents = parse_name(scenario)
109
+ @block = block
110
+
111
+ @@scenarios[@scenario] = self
112
+ end
113
+
114
+ def parse_name(name)
115
+ case name
116
+ when Hash
117
+ return name.keys.first.to_sym, [name.values.first].flatten.map{|sc| parse_name(sc).first}
118
+ when Symbol, String
119
+ return name.to_sym, []
120
+ else
121
+ raise TypeError, "Pass scenarios names as strings or symbols only, cannot build scenario '#{name.inspect}'"
122
+ end
123
+ end
124
+
125
+ def say(*messages)
126
+ puts messages.map { |message| "=> #{message}" }
127
+ end
128
+
129
+ def build
130
+ build_parent_scenarios(@@context)
131
+ build_scenario(@@context)
132
+ self
133
+ end
134
+
135
+ def build_scenario(context)
136
+ surface_errors { context.execute(&@block) } unless @@executed_scenarios.include?(@scenario)
137
+ @@executed_scenarios << @scenario
138
+ end
139
+
140
+ def build_parent_scenarios(context)
141
+ @parents.each do |p|
142
+ parent = @@scenarios[p] or raise ScenarioNotFoundError, p
143
+
144
+ parent.build_parent_scenarios(context)
145
+ parent.build_scenario(context)
146
+ end
147
+ end
148
+
149
+ def surface_errors
150
+ yield
151
+ rescue StandardError => error
152
+ puts
153
+ say "There was an error building scenario '#{@scenario}'", error.inspect
154
+ puts
155
+ puts error.backtrace
156
+ puts
157
+ raise error
158
+ end
159
+ end
@@ -0,0 +1,15 @@
1
+ class Hornsby
2
+ module Context
3
+ def self.execute(&block)
4
+ module_eval(&block) if block
5
+ end
6
+
7
+ def self.copy_ivars(to, reload = false)
8
+ instance_variables.each do |iv|
9
+ v = instance_variable_get(iv)
10
+ v.reload if reload and v.respond_to?(:reload)
11
+ to.instance_variable_set(iv, v)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ class Hornsby
2
+ class ScenarioNotFoundError < NameError
3
+ def initialize(*args)
4
+ @scenarios = args
5
+ end
6
+
7
+ def to_s
8
+ "Scenario(s) not found '#{@scenarios.join(',')}'"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ class Hornsby
2
+ module Helper
3
+ def hornsby_scenario(*names)
4
+ Hornsby.build(*names)
5
+ Hornsby.copy_ivars(self)
6
+ end
7
+
8
+ alias :hornsby_scenarios :hornsby_scenario
9
+
10
+ def hornsby_clear(*args)
11
+ options = args.extract_options!
12
+ Hornsby.delete_tables(*args)
13
+
14
+ if options[:undo] == :all
15
+ Hornsby.executed_scenarios.clear
16
+ else
17
+ undo = [options[:undo]].flatten.compact
18
+ unless (not_found = undo - Hornsby.executed_scenarios.to_a).blank?
19
+ raise(ArgumentError, "Scenario(s) #{not_found} not found")
20
+ end
21
+ Hornsby.executed_scenarios -= undo
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,17 @@
1
+ module Spec
2
+ module Runner
3
+ class Configuration
4
+ def enable_hornsby(options = {})
5
+ Hornsby.load(options)
6
+
7
+ include(Hornsby::Helper)
8
+ before do
9
+ Hornsby.setup(self)
10
+ end
11
+ after do
12
+ Hornsby.teardown
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Test
2
+ module Unit
3
+ class TestCase
4
+ def run_with_hornsby(result, &progress_block)
5
+ Hornsby.setup(self)
6
+ run_without_hornsby(result, &progress_block)
7
+ Hornsby.teardown
8
+ end
9
+
10
+ def self.enable_hornsby(options = {})
11
+ include Hornsby::Helper
12
+ Hornsby.load(options)
13
+ alias_method_chain :run, :hornsby
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__)+'/../hornsby'
2
+
3
+ namespace :hornsby do
4
+
5
+ desc "Load the scenario named in the env var SCENARIO"
6
+ task :scenario => :environment do
7
+ raise "set SCENARIO to define which scenario to load" unless ENV['SCENARIO']
8
+ ::Hornsby.load
9
+ ::Hornsby.build(ENV['SCENARIO'])
10
+ end
11
+
12
+ end
@@ -0,0 +1,8 @@
1
+ test:
2
+ adapter: mysql
3
+ socket: /var/run/mysqld/mysqld.sock
4
+ encoding: utf8
5
+ database: hornsby_test
6
+ username: root
7
+ password:
8
+ host: localhost
@@ -0,0 +1,2 @@
1
+ class Fruit < ActiveRecord::Base
2
+ end
@@ -0,0 +1,10 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :fruits, :force => true do |t|
3
+ t.string :species
4
+ t.integer :average_diameter
5
+ end
6
+
7
+ create_table :trees, :force => true do |t|
8
+ t.string :name
9
+ end
10
+ end
@@ -0,0 +1,46 @@
1
+ scenario(:just_apple) do
2
+ @apple = Fruit.create! :species => 'apple'
3
+ end
4
+
5
+ scenario(:many_apples => [:just_apple, :just_apple, :just_apple])
6
+
7
+ scenario(:bananas_and_apples => :just_apple) do
8
+ @banana = Fruit.create! :species => 'banana'
9
+ end
10
+
11
+ scenario(:just_orange) do
12
+ @orange = Fruit.create! :species => 'orange'
13
+ end
14
+
15
+ scenario(:fruit => [:just_apple,:just_orange]) do
16
+ @fruit = [@orange,@apple]
17
+ end
18
+
19
+ scenario(:bananas_and_apples_and_oranges => [:bananas_and_apples,:just_orange]) do
20
+ @fruit = [@orange,@apple,@banana]
21
+ end
22
+
23
+ scenario(:cherry) do
24
+ @cherry = Fruit.create! :species => 'cherry', :average_diameter => 3
25
+ end
26
+
27
+ scenario(:big_cherry => :cherry) do
28
+ @big_cherry = Fruit.create! :species => @cherry.species, :average_diameter => 7
29
+ end
30
+
31
+ scenario(:cherry_basket => [:big_cherry, :cherry]) do
32
+ @basket = [@cherry, @big_cherry]
33
+ end
34
+
35
+
36
+ scenario :parent_not_existing => :not_existing
37
+
38
+ # Hornsby.namespace(:pitted_fruit) do
39
+ # scenario(:peach) do
40
+ # @peach = Fruit.create! :species => 'peach'
41
+ # end
42
+ #
43
+ # scenario(:nectarine) do
44
+ # @nectarine = Fruit.create! :species => 'nectarine'
45
+ # end
46
+ # end
@@ -0,0 +1,194 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Hornsby do
4
+ describe "scenario files" do
5
+ it "should be loaded from specified dirs" do
6
+ Hornsby::SCENARIO_FILES.should == ["hornsby_scenarios.rb", "hornsby_scenarios/*.rb", "hornsby_scenario.rb", "hornsby_scenario/*.rb", "spec/hornsby_scenarios.rb", "spec/hornsby_scenarios/*.rb", "spec/hornsby_scenario.rb", "spec/hornsby_scenario/*.rb", "test/hornsby_scenarios.rb", "test/hornsby_scenarios/*.rb", "test/hornsby_scenario.rb", "test/hornsby_scenario/*.rb"]
7
+ end
8
+ end
9
+
10
+ describe "with just_apple scenario" do
11
+ before do
12
+ hornsby_scenario :just_apple
13
+ end
14
+
15
+ it "should create @apple" do
16
+ @apple.should_not be_nil
17
+ end
18
+
19
+ it "should create Fruit @apple" do
20
+ @apple.should be_instance_of(Fruit)
21
+ end
22
+
23
+ it "should not create @banana" do
24
+ @banana.should be_nil
25
+ end
26
+
27
+ it "should have correct species" do
28
+ @apple.species.should == 'apple'
29
+ end
30
+ end
31
+
32
+ describe "with bananas_and_apples scenario" do
33
+ before do
34
+ hornsby_scenario :bananas_and_apples
35
+ end
36
+
37
+ it "should have correct @apple species" do
38
+ @apple.species.should == 'apple'
39
+ end
40
+
41
+ it "should have correct @banana species" do
42
+ @banana.species.should == 'banana'
43
+ end
44
+ end
45
+
46
+ describe "with fruit scenario" do
47
+ before do
48
+ hornsby_scenario :fruit
49
+ end
50
+
51
+ it "should have 2 fruits" do
52
+ @fruit.should have(2).items
53
+ end
54
+
55
+ it "should have an @apple" do
56
+ @apple.species.should == 'apple'
57
+ end
58
+
59
+ it "should have an @orange" do
60
+ @orange.species.should == 'orange'
61
+ end
62
+
63
+ it "should have no @banana" do
64
+ @banana.should be_nil
65
+ end
66
+ end
67
+
68
+ describe 'with preloaded cherry scenario' do
69
+ it "should have correct size after changed by second test" do
70
+ @cherry.average_diameter.should == 3
71
+ @cherry.update_attribute(:average_diameter, 1)
72
+ @cherry.average_diameter.should == 1
73
+ end
74
+
75
+ it "should have correct size" do
76
+ @cherry.average_diameter.should == 3
77
+ @cherry.update_attribute(:average_diameter, 5)
78
+ @cherry.average_diameter.should == 5
79
+ end
80
+
81
+ it "should create big cherry" do
82
+ @big_cherry.species.should == 'cherry'
83
+ end
84
+ end
85
+
86
+ describe 'hornsby_clear' do
87
+ before do
88
+ hornsby_scenario :just_apple
89
+ end
90
+
91
+ it "should clear scenarios when calling hornsby_clear" do
92
+ hornsby_clear
93
+ Fruit.count.should == 0
94
+ end
95
+
96
+ it "should clear only tables passed" do
97
+ Tree.create!(:name => 'oak')
98
+ hornsby_clear :fruits
99
+ Tree.count.should == 1
100
+ Fruit.count.should == 0
101
+ end
102
+
103
+ it "should mark scenarios as undone when passed :undone option" do
104
+ hornsby_scenario :fruit
105
+ hornsby_clear :undo => [:just_apple]
106
+ Fruit.count.should == 0
107
+ hornsby_scenario :fruit
108
+ Fruit.count.should == 1
109
+ end
110
+
111
+ it "should mark all scenarios as undone when passed :undone option as :all" do
112
+ hornsby_scenario :fruit
113
+ hornsby_clear :undo => :all
114
+ Fruit.count.should == 0
115
+ hornsby_scenario :fruit
116
+ Fruit.count.should == 2
117
+ end
118
+
119
+ it "should raise error when not executed scenarios passed to :undo option" do
120
+ lambda {
121
+ hornsby_clear :undo => :just_orange
122
+ }.should raise_error(ArgumentError)
123
+ end
124
+ end
125
+
126
+ describe 'with many apples scenario' do
127
+ before do
128
+ hornsby_scenario :many_apples, :cherry, :cherry_basket
129
+ end
130
+
131
+ it "should create only one apple" do
132
+ Fruit.all(:conditions => 'species = "apple"').size.should == 1
133
+ end
134
+
135
+ it "should create only two cherries even if they were preloaded" do
136
+ Fruit.all(:conditions => 'species = "cherry"').size.should == 2
137
+ end
138
+
139
+ it "should contain cherries in basket if basket is loaded in test and cherries preloaded" do
140
+ @basket.should == [@cherry, @big_cherry]
141
+ end
142
+ end
143
+
144
+ describe 'transactions' do
145
+ before do
146
+ hornsby_scenario :just_apple
147
+ end
148
+
149
+ it "should drop only inner transaction" do
150
+ @apple.reload.should_not be_nil
151
+ begin
152
+ ActiveRecord::Base.transaction do
153
+ f = Fruit.create(:species => 'orange')
154
+ f.reload.should_not be_nil
155
+ raise 'some error'
156
+ end
157
+ rescue
158
+ end
159
+ @apple.reload.should_not be_nil
160
+ Fruit.find_by_species('orange').should be_nil
161
+ end
162
+ end
163
+
164
+ describe 'errors' do
165
+ it 'should raise ScenarioNotFoundError when scenario could not be found' do
166
+ lambda {
167
+ hornsby_scenario :not_existing
168
+ }.should raise_error(Hornsby::ScenarioNotFoundError, "Scenario(s) not found 'not_existing'")
169
+ end
170
+
171
+ it 'should raise ScenarioNotFoundError when scenario parent could not be found' do
172
+ lambda {
173
+ hornsby_scenario :parent_not_existing
174
+ }.should raise_error(Hornsby::ScenarioNotFoundError, "Scenario(s) not found 'not_existing'")
175
+ end
176
+
177
+ it 'should raise TypeError when scenario name is not symbol or string' do
178
+ lambda {
179
+ Hornsby.new(1)
180
+ }.should raise_error(TypeError, "Pass scenarios names as strings or symbols only, cannot build scenario '1'")
181
+ end
182
+ end
183
+
184
+ #describe "with pitted namespace" do
185
+ # before do
186
+ # Hornsby.build('pitted:peach').copy_ivars(self)
187
+ # end
188
+
189
+ # it "should have @peach" do
190
+ # @peach.species.should == 'peach'
191
+ # end
192
+ #end
193
+ end
194
+
@@ -0,0 +1,24 @@
1
+ require 'fileutils'
2
+ require 'activerecord'
3
+ begin
4
+ require 'mysqlplus'
5
+ rescue LoadError
6
+ end
7
+
8
+ spec_dir = File.dirname(__FILE__)
9
+ Dir.chdir spec_dir
10
+
11
+ ActiveRecord::Base.logger = Logger.new(File.join(spec_dir, "..", "debug.log"))
12
+
13
+ databases = YAML::load(IO.read("db/database.yml"))
14
+ db_info = databases[ENV["DB"] || "test"]
15
+ ActiveRecord::Base.establish_connection(db_info)
16
+
17
+ require 'spec/autorun'
18
+ require '../lib/hornsby'
19
+ require 'db/fruit'
20
+ require 'db/tree'
21
+
22
+ Spec::Runner.configure do |config|
23
+ config.enable_hornsby(:root => File.expand_path(File.join(spec_dir, '..')), :scenarios => :big_cherry)
24
+ end
@@ -0,0 +1,195 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require 'shoulda'
3
+
4
+ class HornsbyTest < ActiveSupport::TestCase
5
+ context "scenario files" do
6
+ should "be loaded from specified dirs" do
7
+ assert(Hornsby::SCENARIO_FILES == ["hornsby_scenarios.rb", "hornsby_scenarios/*.rb", "hornsby_scenario.rb", "hornsby_scenario/*.rb", "spec/hornsby_scenarios.rb", "spec/hornsby_scenarios/*.rb", "spec/hornsby_scenario.rb", "spec/hornsby_scenario/*.rb", "test/hornsby_scenarios.rb", "test/hornsby_scenarios/*.rb", "test/hornsby_scenario.rb", "test/hornsby_scenario/*.rb"])
8
+ end
9
+ end
10
+
11
+ context "with just_apple scenario" do
12
+ setup do
13
+ hornsby_scenario :just_apple
14
+ end
15
+
16
+ should "create @apple" do
17
+ assert(!(@apple.nil?))
18
+ end
19
+
20
+ should "create Fruit @apple" do
21
+ assert(@apple.instance_of?(Fruit))
22
+ end
23
+
24
+ should "not create @banana" do
25
+ assert(@banana.nil?)
26
+ end
27
+
28
+ should "have correct species" do
29
+ assert(@apple.species == 'apple')
30
+ end
31
+ end
32
+
33
+ context "with bananas_and_apples scenario" do
34
+ setup do
35
+ hornsby_scenario :bananas_and_apples
36
+ end
37
+
38
+ should "have correct @apple species" do
39
+ assert(@apple.species == 'apple')
40
+ end
41
+
42
+ should "have correct @banana species" do
43
+ assert(@banana.species == 'banana')
44
+ end
45
+ end
46
+
47
+ context "with fruit scenario" do
48
+ setup do
49
+ hornsby_scenario :fruit
50
+ end
51
+
52
+ should "have 2 fruits" do
53
+ assert(@fruit.size == 2)
54
+ end
55
+
56
+ should "have an @apple" do
57
+ assert(@apple.species == 'apple')
58
+ end
59
+
60
+ should "have an @orange" do
61
+ assert(@orange.species == 'orange')
62
+ end
63
+
64
+ should "have no @banana" do
65
+ assert(@banana.nil?)
66
+ end
67
+ end
68
+
69
+ context 'with preloaded cherry scenario' do
70
+ should "have correct size after changed by second test" do
71
+ assert(@cherry.average_diameter == 3)
72
+ @cherry.update_attribute(:average_diameter, 1)
73
+ assert(@cherry.average_diameter == 1)
74
+ end
75
+
76
+ should "have correct size" do
77
+ assert(@cherry.average_diameter == 3)
78
+ @cherry.update_attribute(:average_diameter, 5)
79
+ assert(@cherry.average_diameter == 5)
80
+ end
81
+
82
+ should "create big cherry" do
83
+ assert(@big_cherry.species == 'cherry')
84
+ end
85
+ end
86
+
87
+ context 'hornsby_clear' do
88
+ setup do
89
+ hornsby_scenario :just_apple
90
+ end
91
+
92
+ should "clear scenarios when calling hornsby_clear" do
93
+ hornsby_clear
94
+ assert(Fruit.count == 0)
95
+ end
96
+
97
+ should "clear only tables passed" do
98
+ Tree.create!(:name => 'oak')
99
+ hornsby_clear :fruits
100
+ assert(Tree.count == 1)
101
+ assert(Fruit.count == 0)
102
+ end
103
+
104
+ should "mark scenarios as undone when passed :undone option" do
105
+ hornsby_scenario :fruit
106
+ hornsby_clear :undo => [:just_apple]
107
+ assert(Fruit.count == 0)
108
+ hornsby_scenario :fruit
109
+ assert(Fruit.count == 1)
110
+ end
111
+
112
+ should "mark all scenarios as undone when passed :undone option as :all" do
113
+ hornsby_scenario :fruit
114
+ hornsby_clear :undo => :all
115
+ assert(Fruit.count == 0)
116
+ hornsby_scenario :fruit
117
+ assert(Fruit.count == 2)
118
+ end
119
+
120
+ should "raise error when not executed scenarios passed to :undo option" do
121
+ assert_raise(ArgumentError) do
122
+ hornsby_clear :undo => :just_orange
123
+ end
124
+ end
125
+ end
126
+
127
+ context 'with many apples scenario' do
128
+ setup do
129
+ hornsby_scenario :many_apples, :cherry, :cherry_basket
130
+ end
131
+
132
+ should "create only one apple" do
133
+ assert(Fruit.all(:conditions => 'species = "apple"').size == 1)
134
+ end
135
+
136
+ should "create only two cherries even if they were preloaded" do
137
+ assert(Fruit.all(:conditions => 'species = "cherry"').size == 2)
138
+ end
139
+
140
+ should "contain cherries in basket if basket is loaded in test and cherries preloaded" do
141
+ assert(@basket == [@cherry, @big_cherry])
142
+ end
143
+ end
144
+
145
+ context 'transactions' do
146
+ setup do
147
+ hornsby_scenario :just_apple
148
+ end
149
+
150
+ should "drop only inner transaction" do
151
+ assert(!(@apple.reload.nil?))
152
+ begin
153
+ ActiveRecord::Base.transaction do
154
+ f = Fruit.create(:species => 'orange')
155
+ assert(!(f.reload.nil?))
156
+ raise 'some error'
157
+ end
158
+ rescue
159
+ end
160
+ assert(!(@apple.reload.nil?))
161
+ assert(Fruit.find_by_species('orange').nil?)
162
+ end
163
+ end
164
+
165
+ context 'errors' do
166
+ should 'raise ScenarioNotFoundError when scenario could not be found' do
167
+ assert_raise(Hornsby::ScenarioNotFoundError, "Scenario(s) not found 'not_existing'") do
168
+ hornsby_scenario :not_existing
169
+ end
170
+ end
171
+
172
+ should 'raise ScenarioNotFoundError when scenario parent could not be found' do
173
+ assert_raise(Hornsby::ScenarioNotFoundError, "Scenario(s) not found 'not_existing'") do
174
+ hornsby_scenario :parent_not_existing
175
+ end
176
+ end
177
+
178
+ should 'raise TypeError when scenario name is not symbol or string' do
179
+ assert_raise(TypeError, "Pass scenarios names as strings or symbols only, cannot build scenario '1'") do
180
+ Hornsby.new(1)
181
+ end
182
+ end
183
+ end
184
+
185
+ #describe "with pitted namespace" do
186
+ # before do
187
+ # Hornsby.build('pitted:peach').copy_ivars(self)
188
+ # end
189
+
190
+ # it "should have @peach" do
191
+ # @peach.species.should == 'peach'
192
+ # end
193
+ #end
194
+ end
195
+
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'fileutils'
3
+ require 'activerecord'
4
+ require 'test/unit'
5
+ require 'active_record/test_case'
6
+ begin
7
+ require 'mysqlplus'
8
+ rescue LoadError
9
+ end
10
+
11
+ spec_dir = File.join(File.dirname(__FILE__), '..', 'spec')
12
+
13
+ ActiveRecord::Base.logger = Logger.new(File.join(spec_dir, "..", "debug.log"))
14
+
15
+ databases = YAML::load(IO.read(spec_dir + "/db/database.yml"))
16
+ db_info = databases[ENV["DB"] || "test"]
17
+ ActiveRecord::Base.establish_connection(db_info)
18
+
19
+ require spec_dir + '/../lib/hornsby'
20
+ require spec_dir + '/db/fruit'
21
+ require spec_dir + '/db/tree'
22
+
23
+ class ActiveSupport::TestCase
24
+ enable_hornsby :root => File.join(File.dirname(__FILE__), '..'), :scenarios => :big_cherry
25
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hornsby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.2
5
+ platform: ruby
6
+ authors:
7
+ - Andrius Chamentauskas
8
+ - Lachie Cox
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-10-12 00:00:00 +03:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: activerecord
18
+ type: :runtime
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 2.0.0
25
+ version:
26
+ description:
27
+ email: sinsiliux@gmail.com
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files: []
33
+
34
+ files:
35
+ - lib/hornsby.rb
36
+ - lib/hornsby/context.rb
37
+ - lib/hornsby/helper.rb
38
+ - lib/hornsby/errors.rb
39
+ - lib/hornsby/rspec_extensions.rb
40
+ - lib/hornsby/test_unit_extensions.rb
41
+ - lib/tasks/hornsby_tasks.rake
42
+ - README.rdoc
43
+ - LICENSE
44
+ has_rdoc: true
45
+ homepage: http://github.com/sinsiliux/hornsby
46
+ licenses: []
47
+
48
+ post_install_message:
49
+ rdoc_options: []
50
+
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.3.5
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Fixtures replacement with scenarios
72
+ test_files:
73
+ - spec/spec_helper.rb
74
+ - spec/hornsby_spec.rb
75
+ - spec/hornsby_scenario.rb
76
+ - spec/db/fruit.rb
77
+ - spec/db/database.yml.example
78
+ - spec/db/schema.rb
79
+ - test/test_helper.rb
80
+ - test/hornsby_test.rb