birdbath 1.3.4

Sign up to get free protection for your applications and to get access to all the features.
data/.bundle/config ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_DISABLE_SHARED_GEMS: "1"
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.swp
2
+ *.swo
3
+ Gemfile.lock
4
+ pkg/*
5
+ *.gem
6
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in birdbath.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Micah Alles, Patrick Bacon, David Crosby
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.
data/README.rdoc ADDED
@@ -0,0 +1,125 @@
1
+ = Birdbath
2
+
3
+ Birdbath provides methods which let you assert the current state of the schema and run your migrations against the _test_ database.
4
+
5
+ == Install
6
+
7
+ gem install birdbath
8
+
9
+ If you're using it outside of a Rails environment (for whatever reason) include the Birdbath module in your tests:
10
+
11
+ require 'test/unit'
12
+ require 'birdbath'
13
+
14
+ class MyTest < Test::Unit::TestCase
15
+ include Birdbath
16
+
17
+ def test_something
18
+ ...
19
+ end
20
+ end
21
+
22
+ == Use
23
+
24
+ *assert_schema*: verifies the schema of the database exactly matches the one specified.
25
+
26
+ def test_the_schema
27
+ assert_schema do |s|
28
+ s.table :books do |t|
29
+ t.column :id, :integer
30
+ t.column :title, :string, :limit => 5
31
+ t.column :author, :string
32
+ end
33
+
34
+ s.table :reviews do |t|
35
+ t.column :id, :integer
36
+ t.column :book_id, :integer
37
+ t.column :body, :text
38
+ t.column :rating, :integer, :default => 0
39
+ t.index :book_id, :name => 'index_book_id_on_reviews'
40
+ end
41
+ end
42
+ end
43
+
44
+ This would verify there are only two tables defined in the test database: _books_ and _reviews_ (schema_info is ignored). It will also verify that the _book_ table has the three columns, _id_, _title_ and _author_, each with their respective types. Indexes are verified too.
45
+
46
+
47
+ *assert_table*: verify a table is found exactly as specified:
48
+
49
+ assert_table :books do |t|
50
+ t.column :id, :integer
51
+ t.column :title, :string, :limit => 5
52
+ t.column :author, :string
53
+ t.index :author, :name => 'index_author_on_books'
54
+ end
55
+
56
+
57
+ *drop_all_tables*: does just what it says to your _test_ database.
58
+
59
+
60
+ *migrate*: executes the migrations against the test database using the same mechanism as rake db:migrate.
61
+
62
+ def test_the_migrations
63
+ migrate
64
+ migrate :version => 0
65
+ migrate :version => 10
66
+ migrate
67
+ end
68
+
69
+
70
+ This would do the same thing as running the following rake commands, but within a test case:
71
+
72
+ rake db:migrate
73
+ rake db:migrate VERSION=0
74
+ rake db:migrate VERSION=10
75
+ rake db:migrate
76
+
77
+
78
+ By combining the two helpers you can write a test that shows you can run all your migrations and get the final schema:
79
+
80
+ def test_should_be_able_to_migrate_from_an_empty_schema
81
+ drop_all_tables
82
+
83
+ # we shouldn't have any tables
84
+ assert_schema do |s|
85
+ end
86
+
87
+ migrate
88
+
89
+ assert_schema do |s|
90
+ s.table :books do |t|
91
+ t.column :id, :integer
92
+ t.column :title, :string
93
+ t.column :author, :string
94
+ end
95
+
96
+ s.table :reviews do |t|
97
+ t.column :id, :integer
98
+ t.column :book_id, :integer
99
+ t.column :body, :text
100
+ t.column :rating, :integer
101
+ t.index :book_id, :name => 'index_book_id_on_reviews'
102
+ end
103
+ end
104
+ end
105
+
106
+
107
+ The *migrate* helper can also be useful for testing data tranformation migrations:
108
+
109
+ def test_should_get_rid_of_bad_data
110
+ drop_all_tables
111
+ migrate :version => 7
112
+ Book.reset_column_information
113
+ book = Book.create! :title => "bad title\nwith\todd spacing"
114
+ migrate :version => 8 # should cleanse spacing in book titles
115
+ book.reload
116
+ assert_equal "bad title with odd spacing", book.title
117
+ end
118
+
119
+ == Authors
120
+
121
+ * Micah Alles (alles@atomicobject.com)
122
+ * David Crosby (crosby@atomicobject.com)
123
+ * Patrick Bacon (bacon@atomicobject.com)
124
+ * © 2007-2011 {Atomic Object}[http://www.atomicobject.com]
125
+ * More Atomic Object {open source}[http://www.atomicobject.com/pages/Software+Commons] projects
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ # GEM_VERSION = '1.3.3'
5
+ #
6
+ # Hoe.new('birdbath', GEM_VERSION) do |p|
7
+ # p.author = "Micah Alles"
8
+ # p.email = "micah@atomicobject.com"
9
+ # p.url = "http://migrationtest.rubyforge.org"
10
+ # p.summary = "A Rails plugin for testing migrations"
11
+ # p.description = <<-EOS
12
+ # birdbath makes testing your migrations easier by
13
+ # adding helper methods to Test::Unit::TestCase for asserting the
14
+ # current state of the schema and executing migrations against the
15
+ # test database.
16
+ # EOS
17
+ #
18
+ # end
19
+ #
data/birdbath.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "birdbath/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "birdbath"
7
+ s.version = Birdbath::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Micah Alles"]
10
+ s.email = ["micah@atomicobject.com"]
11
+ s.homepage = "http://github.com/atomicobject/birdbath"
12
+ s.summary = %q{A Rails gem for testing migrations}
13
+ s.description = <<-EOS
14
+ birdbath makes testing your migrations easier by
15
+ adding helper methods to Test::Unit::TestCase for asserting the
16
+ current state of the schema and executing migrations against the
17
+ test database.
18
+ EOS
19
+
20
+ s.rubyforge_project = "birdbath"
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.require_paths = ["lib"]
24
+ end
@@ -0,0 +1,30 @@
1
+ Description:
2
+ The controller generator creates stubs for a new controller and its views.
3
+
4
+ The generator takes a controller name and a list of views as arguments.
5
+ The controller name may be given in CamelCase or under_score and should
6
+ not be suffixed with 'Controller'. To create a controller within a
7
+ module, specify the controller name as 'module/controller'.
8
+
9
+ The generator creates a controller class in app/controllers with view
10
+ templates in app/views/controller_name, a helper class in app/helpers,
11
+ and a functional test suite in test/functional.
12
+
13
+ Example:
14
+ ./script/generate controller CreditCard open debit credit close
15
+
16
+ Credit card controller with URLs like /credit_card/debit.
17
+ Controller: app/controllers/credit_card_controller.rb
18
+ Views: app/views/credit_card/debit.rhtml [...]
19
+ Helper: app/helpers/credit_card_helper.rb
20
+ Test: test/functional/credit_card_controller_test.rb
21
+
22
+ Modules Example:
23
+ ./script/generate controller 'admin/credit_card' suspend late_fee
24
+
25
+ Credit card admin controller with URLs /admin/credit_card/suspend.
26
+ Controller: app/controllers/admin/credit_card_controller.rb
27
+ Views: app/views/admin/credit_card/debit.rhtml [...]
28
+ Helper: app/helpers/admin/credit_card_helper.rb
29
+ Test: test/functional/admin/credit_card_controller_test.rb
30
+
@@ -0,0 +1,10 @@
1
+ class FullMigrationTestGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+
5
+ m.directory 'test/migration'
6
+ m.template 'full_migration_test.rb',
7
+ 'test/migration/full_migration_test.rb'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,89 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ #
4
+ # This excercises the full set of migrations for your Rails app.
5
+ # It proves:
6
+ # - After full migration, the database is in the expected state, including:
7
+ # - All table structure
8
+ # - Default data (if any)
9
+ # - Full downward (version 0) migration functions correctly.
10
+ #
11
+ # YOU NEED TO:
12
+ # - Update "see_full_schema"
13
+ # - Update "see_data"
14
+ #
15
+ class FullMigrationTest < ActionController::IntegrationTest
16
+
17
+ #
18
+ # Transactional fixtures can, on occasion, cause migration tests to hang.
19
+ # Applying this setting here will turn transactional fixtures off for THIS
20
+ # SUITE ONLY
21
+ #
22
+ # self.use_transactional_fixtures = false
23
+
24
+ def conn
25
+ ActiveRecord::Base.connection
26
+ end
27
+
28
+ def see_empty_schema
29
+ assert_schema do |s|
30
+ # is nothing
31
+ end
32
+ end
33
+
34
+ #
35
+ # Structure and Content assertions
36
+ #
37
+
38
+ # Fully assert db structure after full migration
39
+ def see_full_schema
40
+ # TODO: add assertions here to verify your schema was built
41
+ flunk "implement me"
42
+
43
+ #
44
+ # Something like this can be used to see the entire schema
45
+ # is as expeted.
46
+ #
47
+ # assert_schema do |s|
48
+ # s.table :cat_tails do |t|
49
+ # t.column :id, :integer
50
+ # t.column :name, :string
51
+ # end
52
+ #
53
+ # s.table :dogs do |t|
54
+ # t.column :id, :integer
55
+ # t.column :name, :string
56
+ # end
57
+ # end
58
+
59
+ #
60
+ # Alternatively individual tables can be checked.
61
+ #
62
+ # assert_table :cats_tails do |s|
63
+ # t.column :id, :integer
64
+ # t.column :name, :string
65
+ # end
66
+ end
67
+
68
+ # Make sure data you expect your migrations to load are in there:
69
+ def see_default_data
70
+ # TODO: add assertions here to verify any default data was loaded
71
+ end
72
+
73
+ #
74
+ # TESTS
75
+ #
76
+
77
+ def test_full_migration
78
+ drop_all_tables
79
+
80
+ see_empty_schema
81
+
82
+ migrate
83
+
84
+ see_full_schema
85
+
86
+ see_default_data
87
+ end
88
+
89
+ end
@@ -0,0 +1,33 @@
1
+ class MigrationTestGenerator < Rails::Generator::NamedBase
2
+ def manifest
3
+ schema_version = class_name.to_i
4
+ raise "Invalid schema version '#{class_name}'" unless schema_version > 0
5
+
6
+ schema_version_string = schema_version.to_s.rjust(3,'0')
7
+
8
+ migration = Dir["db/migrate/#{schema_version_string}*.rb"].first
9
+ raise "No migration found for schema version #{schema_version_string}" unless migration
10
+
11
+ migration_name = File.basename(migration,'.rb').sub(/^\d+_/,'')
12
+ test_class_name = migration_name.camelize + "Test"
13
+ test_file = "test/migration/#{schema_version_string}_#{migration_name}_test.rb"
14
+
15
+ record do |m|
16
+ m.directory 'test/migration'
17
+ m.template 'migration_test.rb', test_file, :assigns => {
18
+ :test_class_name => test_class_name,
19
+ :migration_name => migration_name,
20
+ :schema_version => schema_version,
21
+ :previous_schema_version => previous_schema_version(schema_version_string)
22
+ }
23
+ end
24
+ end
25
+
26
+ def previous_schema_version(current_version_string)
27
+ versions = Dir["db/migrate/*.rb"].map do |migration_file|
28
+ migration_file.match(/db\/migrate\/(\d+)_.*\.rb/)[1]
29
+ end.sort
30
+ prev_index = versions.index(current_version_string) - 1
31
+ prev_index < 0 ? -1 : versions[prev_index].to_i
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class <%= test_class_name %> < Test::Unit::TestCase
4
+
5
+ def teardown
6
+ migrate
7
+ end
8
+
9
+ def test_migration_should_<%= migration_name %>
10
+ drop_all_tables
11
+
12
+ migrate :version => <%= previous_schema_version %>
13
+
14
+ flunk "TODO: setup test data"
15
+
16
+ migrate :version => <%= schema_version %>
17
+
18
+ flunk "TODO: examine results"
19
+
20
+ migrate :version => <%= previous_schema_version %>
21
+
22
+ flunk "TODO: examine results"
23
+ end
24
+
25
+ end
data/init.rb ADDED
@@ -0,0 +1,7 @@
1
+ if RAILS_ENV == 'test'
2
+ require 'birdbath'
3
+ require 'test/unit'
4
+ Test::Unit::TestCase.class_eval do
5
+ include Birdbath
6
+ end
7
+ end
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,3 @@
1
+ module Birdbath
2
+ VERSION = "1.3.4"
3
+ end
data/lib/birdbath.rb ADDED
@@ -0,0 +1,159 @@
1
+ #--
2
+ # Copyright (c) 2007 Micah Alles, Patrick Bacon, David Crosby
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require 'test/unit/assertions'
25
+
26
+ module Birdbath
27
+ def self.migration_dir
28
+ @migration_dir || File.expand_path(RAILS_ROOT + '/db/migrate')
29
+ end
30
+
31
+ #
32
+ # sets the directory in which the migrations reside to be run with migrate
33
+ #
34
+ def self.migration_dir=(new_dir)
35
+ @migration_dir = new_dir
36
+ end
37
+
38
+ #
39
+ # verifies the schema exactly matches the one specified (schema_info does not have to be specified)
40
+ #
41
+ # assert_schema do |s|
42
+ # s.table :dogs do |t|
43
+ # t.column :id, :integer, :default => 2
44
+ # t.column :name, :string
45
+ # end
46
+ # end
47
+ #
48
+ def assert_schema
49
+ schema = Schema.new
50
+ yield schema
51
+ schema.verify
52
+ end
53
+
54
+ #
55
+ # verifies a single table exactly matches the one specified
56
+ #
57
+ # assert_table :dogs do |t|
58
+ # t.column :id, :integer, :default => 2
59
+ # t.column :name, :string
60
+ # end
61
+ #
62
+ def assert_table(name)
63
+ table = Table.new(name)
64
+ yield table
65
+ table.verify
66
+ end
67
+
68
+ #
69
+ # drops all tables in the database
70
+ #
71
+ def drop_all_tables
72
+ ActiveRecord::Base.connection.tables.each do |table|
73
+ ActiveRecord::Base.connection.drop_table(table)
74
+ end
75
+ end
76
+
77
+ #
78
+ # executes your migrations
79
+ #
80
+ # migrate # same as rake db:migrate
81
+ #
82
+ # Options are:
83
+ # * :version - version to migrate to (same as VERSION=.. option to rake db:migrate)
84
+ # * :verbose - print migration status messages to STDOUT, defaults to false
85
+ #
86
+ def migrate(opts={})
87
+ old_verbose = ActiveRecord::Migration.verbose
88
+ ActiveRecord::Migration.verbose = opts[:verbose].nil? ? false : opts[:verbose]
89
+ version = opts[:version] ? opts[:version].to_i : nil
90
+ ActiveRecord::Migrator.migrate(Birdbath.migration_dir, version)
91
+ ensure
92
+ ActiveRecord::Migration.verbose = old_verbose
93
+ end
94
+
95
+ module Connection #:nodoc:
96
+ def conn
97
+ ActiveRecord::Base.connection
98
+ end
99
+ end
100
+
101
+ class Schema
102
+ include Connection
103
+ include Test::Unit::Assertions
104
+
105
+ def initialize #:nodoc:
106
+ @tables = []
107
+ end
108
+
109
+ def table(name)
110
+ table = Table.new(name)
111
+ yield table
112
+ table.verify
113
+ @tables << table
114
+ end
115
+
116
+ def verify #:nodoc:
117
+ actual_tables = conn.tables.reject {|t| t == 'schema_info' || t == 'schema_migrations' }
118
+ expected_tables = @tables.map {|t| t.name }
119
+ assert_equal expected_tables.sort, actual_tables.sort, 'wrong tables in schema'
120
+ end
121
+ end
122
+
123
+ class Table
124
+ include Connection
125
+ include Test::Unit::Assertions
126
+ attr_reader :name
127
+
128
+ def initialize(name) #:nodoc:
129
+ @name = name.to_s
130
+ @columns = []
131
+ @indexes = []
132
+ assert conn.tables.include?(@name), "table <#{@name}> not found in schema"
133
+ end
134
+
135
+ def column(colname,type,options={})
136
+ colname = colname.to_s
137
+ @columns << colname
138
+ col = conn.columns(name).find {|c| c.name == colname }
139
+ assert_not_nil col, "column <#{colname}> not found in table <#{self.name}>"
140
+ assert_equal type, col.type, "wrong type for column <#{colname}> in table <#{name}>"
141
+ options.each do |k,v|
142
+ k = k.to_sym; actual = col.send(k); actual = actual.is_a?(String) ? actual.sub(/'$/,'').sub(/^'/,'') : actual
143
+ assert_equal v, actual, "column <#{colname}> in table <#{name}> has wrong :#{k}"
144
+ end
145
+ end
146
+
147
+ def index(column_name, options = {})
148
+ @indexes << "name <#{options[:name]}> columns <#{Array(column_name).join(",")}> unique <#{options[:unique] == true}>"
149
+ end
150
+
151
+ def verify #:nodoc:
152
+ actual_columns = conn.columns(name).map {|c| c.name }
153
+ assert_equal @columns.sort, actual_columns.sort, "wrong columns for table: <#{name}>"
154
+
155
+ actual_indexes = conn.indexes(@name).collect { |i| "name <#{i.name}> columns <#{i.columns.join(",")}> unique <#{i.unique}>" }
156
+ assert_equal @indexes.sort, actual_indexes.sort, "wrong indexes for table: <#{name}>"
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,17 @@
1
+
2
+ namespace :test do
3
+
4
+ Rake::TestTask.new(:migrations => "db:test:prepare") do |t|
5
+ t.libs << "test"
6
+ t.pattern = 'test/migration/**/*_test.rb'
7
+ t.verbose = true
8
+ end
9
+ Rake::Task['test:migrations'].comment = "Run the migration tests in test/migration"
10
+
11
+ task :migration => 'test:migrations'
12
+ end
13
+
14
+ task :test do
15
+ Rake::Task['test:migrations'].invoke rescue got_error = true
16
+ raise "Test failures" if got_error
17
+ end
@@ -0,0 +1,263 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/helper')
2
+
3
+ class BirdbathTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ load_default_schema
7
+ Birdbath.migration_dir = plugin_path('test/db/migrate_good')
8
+ end
9
+
10
+ #
11
+ # HELPERS
12
+ #
13
+ def see_failure(pattern='')
14
+ err = assert_raise(Test::Unit::AssertionFailedError) do
15
+ yield
16
+ end
17
+ assert_match(/#{pattern}/mi, err.message)
18
+ end
19
+
20
+ def see_no_failure
21
+ assert_nothing_raised do
22
+ yield
23
+ end
24
+ end
25
+
26
+ def declare_columns_on_table(t)
27
+ t.column :id, :integer
28
+ t.column :tail, :string, :default => 'top dog', :limit => 187
29
+ end
30
+
31
+ #
32
+ # TESTS
33
+ #
34
+ def test_assert_schema_should_not_fail_if_schema_is_matched
35
+ see_no_failure do
36
+ assert_schema do |s|
37
+ s.table :dogs do |t|
38
+ declare_columns_on_table(t)
39
+ t.index :tail, :name => 'index_tail_on_dogs'
40
+ end
41
+
42
+ end
43
+ end
44
+ end
45
+
46
+ def test_assert_schema_should_fail_if_a_table_is_not_specified
47
+ see_failure 'wrong tables in schema.*dogs' do
48
+ assert_schema do |s|
49
+ end
50
+ end
51
+ end
52
+
53
+ def test_assert_schema_should_fail_if_a_table_is_not_found
54
+ see_failure 'table <things> not found in schema' do
55
+ assert_schema do |s|
56
+ s.table :things do |t|
57
+ t.column :id, :integer
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def test_assert_schema_should_fail_if_a_column_is_not_specified
64
+ see_failure 'wrong columns for table.*dogs.*tail' do
65
+ assert_schema do |s|
66
+ s.table :dogs do |t|
67
+ t.column :id, :integer
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ def test_assert_schema_should_fail_if_a_column_is_not_found
74
+ see_failure 'column <legs> not found in table <dogs>' do
75
+ assert_schema do |s|
76
+ s.table :dogs do |t|
77
+ t.column :id, :integer
78
+ t.column :tail, :string
79
+ t.column :legs, :integer
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ def test_assert_schema_should_fail_if_wrong_options_not_specified
86
+ see_failure 'column <tail> in table <dogs> has wrong :default' do
87
+ assert_table :dogs do |t|
88
+ t.column :id, :integer
89
+ t.column :tail, :string, :default => "blah"
90
+ end
91
+ end
92
+ end
93
+
94
+ def test_assert_table_should_not_fail_if_table_is_matched
95
+ see_no_failure do
96
+ assert_table :dogs do |t|
97
+ declare_columns_on_table(t)
98
+ t.index :tail, :name => 'index_tail_on_dogs'
99
+ end
100
+ end
101
+ end
102
+
103
+ def test_assert_table_should_fail_if_a_table_is_not_found
104
+ see_failure 'table <things> not found in schema' do
105
+ assert_table :things do |t|
106
+ t.column :id, :integer
107
+ end
108
+ end
109
+ end
110
+
111
+ def test_assert_table_should_fail_if_a_column_is_not_specified
112
+ see_failure 'wrong columns for table.*dogs.*tail' do
113
+ assert_table :dogs do |t|
114
+ t.column :id, :integer
115
+ end
116
+ end
117
+ end
118
+
119
+ def test_assert_table_should_fail_if_a_column_is_not_found
120
+ see_failure 'column <legs> not found in table <dogs>' do
121
+ assert_table :dogs do |t|
122
+ t.column :id, :integer
123
+ t.column :tail, :string
124
+ t.column :legs, :integer
125
+ end
126
+ end
127
+ end
128
+
129
+ def test_assert_table_should_fail_if_wrong_options_not_specified
130
+ see_failure 'column <tail> in table <dogs> has wrong :default' do
131
+ assert_table :dogs do |t|
132
+ t.column :id, :integer
133
+ t.column :tail, :string, :default => "blah"
134
+ end
135
+ end
136
+ end
137
+
138
+ def test_assert_table_should_fail_if_an_index_is_not_specified
139
+ see_failure 'wrong indexes for table: <dogs>' do
140
+ assert_table :dogs do |t|
141
+ declare_columns_on_table(t)
142
+ end
143
+ end
144
+ end
145
+
146
+ def test_assert_schema_should_fail_if_a_column_in_an_index_is_not_found
147
+ see_failure 'wrong indexes for table: <dogs>' do
148
+ assert_table :dogs do |t|
149
+ declare_columns_on_table(t)
150
+ t.index :legs, :name => 'index_legs_on_dogs'
151
+ end
152
+ end
153
+ end
154
+
155
+ def test_assert_schema_should_fail_if_wrong_options_on_an_index
156
+ see_failure 'wrong indexes for table: <dogs>' do
157
+ assert_table :dogs do |t|
158
+ declare_columns_on_table(t)
159
+ t.index :tail, :name => 'index_tail_on_dogs', :unique => true
160
+ end
161
+ end
162
+ end
163
+
164
+ def test_should_drop_all_tables
165
+ if Rails::VERSION::MAJOR >= 2 && Rails::VERSION::MINOR >= 1
166
+ schema_table = 'schema_migrations'
167
+ else
168
+ schema_table = 'schema_info'
169
+ end
170
+ assert_equal ['dogs', schema_table].sort, ActiveRecord::Base.connection.tables.sort
171
+ drop_all_tables
172
+ assert_equal [], ActiveRecord::Base.connection.tables
173
+ drop_all_tables
174
+ assert_equal [], ActiveRecord::Base.connection.tables
175
+ end
176
+
177
+ def test_should_migrate_to_highest_version
178
+ drop_all_tables
179
+ assert_schema do |s|
180
+ end
181
+
182
+ migrate :version => 1
183
+
184
+ assert_schema do |s|
185
+ s.table :top_dogs do |t|
186
+ t.column :id, :integer
187
+ t.column :name, :string
188
+ end
189
+ end
190
+
191
+ migrate :version => 2
192
+
193
+ assert_schema do |s|
194
+ s.table :top_dogs do |t|
195
+ t.column :id, :integer
196
+ t.column :name, :string
197
+ end
198
+ s.table :bottom_dogs do |t|
199
+ t.column :id, :integer
200
+ t.column :name, :string
201
+ t.column :sick, :boolean
202
+ end
203
+ end
204
+
205
+ migrate :version => 3
206
+
207
+ assert_schema do |s|
208
+ s.table :top_dogs do |t|
209
+ t.column :id, :integer
210
+ t.column :name, :string
211
+ end
212
+ s.table :bottom_dogs do |t|
213
+ t.column :id, :integer
214
+ t.column :name, :string
215
+ t.column :sick, :boolean
216
+ end
217
+ s.table :cats do |t|
218
+ t.column :id, :integer
219
+ t.column :lives, :integer
220
+ end
221
+ end
222
+
223
+ migrate :version => 0
224
+
225
+ assert_schema do |s|
226
+ end
227
+
228
+ migrate
229
+
230
+ assert_schema do |s|
231
+ s.table :top_dogs do |t|
232
+ t.column :id, :integer
233
+ t.column :name, :string
234
+ end
235
+ s.table :bottom_dogs do |t|
236
+ t.column :id, :integer
237
+ t.column :name, :string
238
+ t.column :sick, :boolean
239
+ end
240
+ s.table :cats do |t|
241
+ t.column :id, :integer
242
+ t.column :lives, :integer
243
+ end
244
+ end
245
+ end
246
+
247
+ def test_should_have_default_migration_dir_set
248
+ Birdbath.migration_dir = nil
249
+ assert_equal File.expand_path(RAILS_ROOT + '/db/migrate'), Birdbath.migration_dir,
250
+ "wrong default migration dir"
251
+
252
+ end
253
+
254
+ def test_should_raise_error_if_migration_fails
255
+ Birdbath.migration_dir = plugin_path('test/db/migrate_bad')
256
+ drop_all_tables
257
+ err = assert_raise RuntimeError do
258
+ migrate
259
+ end
260
+ assert_match(//i, err.message)
261
+ end
262
+ end
263
+
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: vendor/plugins/birdbath/test/db/test.sqlite3.db
@@ -0,0 +1,8 @@
1
+ class CreateTopDogs < ActiveRecord::Migration
2
+ def self.up
3
+ raise 'boom'
4
+ end
5
+
6
+ def self.down
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ class CreateTopDogs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :top_dogs do |t|
4
+ t.column :name, :string
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :top_dogs
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ class CreateBottomDogs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :bottom_dogs do |t|
4
+ t.column :name, :string
5
+ t.column :sick, :boolean
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :bottom_dogs
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ class CreateCats < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :cats do |t|
4
+ t.column :lives, :integer
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :cats
10
+ end
11
+ end
data/test/db/schema.rb ADDED
@@ -0,0 +1,6 @@
1
+ ActiveRecord::Schema.define(:version => 1) do
2
+ create_table "dogs", :force => true do |t|
3
+ t.column "tail", :string, :default => 'top dog', :limit => 187
4
+ end
5
+ add_index :dogs, :tail, :name => 'index_tail_on_dogs'
6
+ end
@@ -0,0 +1,15 @@
1
+ class Test::Unit::TestCase
2
+
3
+ def self.running_in_foundry
4
+ File.expand_path(File.dirname(__FILE__)) =~ /\/rails_plugin_foundry\//
5
+ end
6
+
7
+ def running_in_foundry
8
+ self.class.running_in_foundry
9
+ end
10
+
11
+ def self.in_foundry_should(behave,&block)
12
+ should(behave,&block) if running_in_foundry
13
+ end
14
+
15
+ end
@@ -0,0 +1,52 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/foundry_only_helper')
3
+
4
+ class FullMigrationTestGeneratorTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ return unless running_in_foundry
8
+ rm_migration_test_path
9
+ end
10
+
11
+ def teardown
12
+ return unless running_in_foundry
13
+ rm_migration_test_path
14
+ end
15
+
16
+
17
+ #
18
+ # HELPERS
19
+ #
20
+
21
+ def migration_test_file
22
+ migration_test_path + "/full_migration_test.rb"
23
+ end
24
+
25
+ def run_generator
26
+ run_in_rails_root 'script/generate full_migration_test'
27
+ end
28
+
29
+ #
30
+ # TESTS
31
+ #
32
+
33
+ in_foundry_should "generate full migration test" do
34
+ run_generator
35
+ assert File.exists?(migration_test_file), "No test file made: #{migration_test_file}"
36
+ generated_code = File.read(migration_test_file)
37
+ source_code = File.read(plugin_path('generators/full_migration_test/templates/full_migration_test.rb'))
38
+ assert_equal source_code, generated_code, "Wrong code generated in #{migration_test_file}"
39
+ end
40
+
41
+ in_foundry_should "create a test that fails in expected fashion" do
42
+ run_generator
43
+ cd RAILS_ROOT do
44
+ @output = `ruby test/migration/full_migration_test.rb`
45
+ end
46
+
47
+ check_output '1 tests, 1 assertions, 1 failures, 0 errors'
48
+ check_output 'implement me'
49
+ check_output 'test_full_migration(FullMigrationTest)'
50
+ end
51
+
52
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,75 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../../../config/environment')
3
+ require 'logger'
4
+ require 'fileutils'
5
+ require 'test_help'
6
+
7
+ plugin_path = RAILS_ROOT + "/vendor/plugins/birdbath"
8
+
9
+ config_location = File.expand_path(plugin_path + "/test/config/database.yml")
10
+
11
+ config = YAML::load(ERB.new(IO.read(config_location)).result)
12
+ ActiveRecord::Base.logger = Logger.new(plugin_path + "/test/log/test.log")
13
+ ActiveRecord::Base.establish_connection(config['test'])
14
+
15
+ Test::Unit::TestCase.fixture_path = plugin_path + "/test/fixtures/"
16
+
17
+ $LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
18
+
19
+ class Test::Unit::TestCase
20
+ include FileUtils
21
+ def plugin_path(path)
22
+ File.expand_path(File.dirname(__FILE__) + '/../' + path)
23
+ end
24
+
25
+ def load_default_schema
26
+ ActiveRecord::Migration.suppress_messages do
27
+ schema_file = plugin_path("/test/db/schema.rb")
28
+ load(schema_file) if File.exist?(schema_file)
29
+ end
30
+ end
31
+
32
+ def migration_test_path
33
+ File.expand_path(RAILS_ROOT + "/test/migration")
34
+ end
35
+
36
+ def run_in_rails_root(command)
37
+ cd RAILS_ROOT do
38
+ @output = `#{command}`
39
+ end
40
+ end
41
+
42
+ def check_output(string_or_regexp)
43
+ assert_not_nil @output, "No output collected"
44
+ case string_or_regexp
45
+ when String
46
+ assert_match(/#{Regexp.escape(string_or_regexp)}/, @output)
47
+ when Regexp
48
+ assert_match(string_or_regexp, @output)
49
+ else
50
+ raise "Can't check output using oddball object #{string_or_regexp.inspect}"
51
+ end
52
+ end
53
+
54
+ def rm_migration_test_path
55
+ rm_rf migration_test_path
56
+ end
57
+
58
+ def self.should(behave,&block)
59
+ return unless running_in_foundry
60
+ @context ||= nil
61
+ @context_setup ||= nil
62
+ context_string = @context.nil? ? '' : @context + ' '
63
+ mname = "test #{context_string}should #{behave}"
64
+ context_setup = @context_setup
65
+ if block_given?
66
+ define_method(mname) do
67
+ instance_eval(&context_setup) unless context_setup.nil?
68
+ instance_eval(&block)
69
+ end
70
+ else
71
+ puts ">>> UNIMPLEMENTED CASE: #{name.sub(/Test$/,'')} should #{behave}"
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,91 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/foundry_only_helper')
3
+
4
+ class MigrationTestGeneratorTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ return unless running_in_foundry
8
+ rm_migration_test_path
9
+ rm_migrations
10
+ end
11
+
12
+ def teardown
13
+ return unless running_in_foundry
14
+ rm_migration_test_path
15
+ rm_migrations
16
+ end
17
+
18
+
19
+ #
20
+ # HELPERS
21
+ #
22
+
23
+ def generate_migration(name)
24
+ run_in_rails_root "script/generate migration #{name}"
25
+ @output =~ /create db\/migrate\/(\d+)_.*\.rb/
26
+ migration = $1
27
+ migration_file = "db/migrate/#{migration}_#{name}.rb"
28
+ assert File.exists?(migration_file), "Migration not there: #{migration_file}"
29
+ migration
30
+ end
31
+
32
+ def generate_migration_test(version)
33
+ run_in_rails_root "script/generate migration_test #{version}"
34
+ end
35
+
36
+ def rm_migrations
37
+ rm Dir["db/migrate/*.rb"]
38
+ end
39
+
40
+ #
41
+ # TESTS
42
+ #
43
+
44
+ in_foundry_should "generate a migration test for schema 1" do
45
+ migration = generate_migration 'create_the_dogs_table'
46
+
47
+ generate_migration_test migration
48
+
49
+ migration_test_file = "test/migration/#{migration}_create_the_dogs_table_test.rb"
50
+ assert File.exists?(migration_test_file), "Migration test not there: #{migration_test_file}"
51
+
52
+ run_in_rails_root "ruby #{migration_test_file}"
53
+ check_output 'test_migration_should_create_the_dogs_table(CreateTheDogsTableTest)'
54
+ check_output '1) Failure:'
55
+ check_output 'TODO: setup test data.'
56
+ check_output '1 tests, 1 assertions, 1 failures, 0 errors'
57
+ end
58
+
59
+ in_foundry_should "generate a migration test for schema 2" do
60
+ generate_migration 'create_the_dogs_table'
61
+ migration = generate_migration 'transfer_cats_data'
62
+ generate_migration_test migration
63
+ migration_test_file = "test/migration/#{migration}_transfer_cats_data_test.rb"
64
+ assert File.exists?(migration_test_file), "Migration test not there: #{migration_test_file}"
65
+
66
+ run_in_rails_root "ruby #{migration_test_file}"
67
+ check_output 'test_migration_should_transfer_cats_data(TransferCatsDataTest)'
68
+ check_output '1) Failure:'
69
+ check_output 'TODO: setup test data.'
70
+ check_output '1 tests, 1 assertions, 1 failures, 0 errors'
71
+ end
72
+
73
+ in_foundry_should "fail if no schema version is provided" do
74
+ generate_migration 'create_the_dogs_table'
75
+ generate_migration_test ''
76
+ check_output 'Usage: script/generate migration_test MigrationTestName [options]'
77
+ end
78
+
79
+ in_foundry_should "fail if bad schema version is provided" do
80
+ generate_migration 'create_the_dogs_table'
81
+ generate_migration_test 'oops'
82
+ check_output(/Invalid schema version 'oops'/i)
83
+ end
84
+
85
+ in_foundry_should "fail if schema version does not correspond to existing migration" do
86
+ migration = generate_migration 'create_the_dogs_table'
87
+ generate_migration_test '2'
88
+ check_output "No migration found for schema version 002"
89
+ end
90
+
91
+ end
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: birdbath
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Micah Alles
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-09 00:00:00.000000000 -04:00
13
+ default_executable:
14
+ dependencies: []
15
+ description: ! "birdbath makes testing your migrations easier by \nadding helper methods
16
+ to Test::Unit::TestCase for asserting the \ncurrent state of the schema and executing
17
+ migrations against the \ntest database.\n"
18
+ email:
19
+ - micah@atomicobject.com
20
+ executables: []
21
+ extensions: []
22
+ extra_rdoc_files: []
23
+ files:
24
+ - .bundle/config
25
+ - .gitignore
26
+ - Gemfile
27
+ - LICENSE
28
+ - README.rdoc
29
+ - Rakefile
30
+ - birdbath.gemspec
31
+ - generators/full_migration_test/USAGE
32
+ - generators/full_migration_test/full_migration_test_generator.rb
33
+ - generators/full_migration_test/templates/full_migration_test.rb
34
+ - generators/migration_test/migration_test_generator.rb
35
+ - generators/migration_test/templates/migration_test.rb
36
+ - init.rb
37
+ - install.rb
38
+ - lib/birdbath.rb
39
+ - lib/birdbath/version.rb
40
+ - tasks/birdbath_tasks.rake
41
+ - test/birdbath_test.rb
42
+ - test/config/database.yml
43
+ - test/db/migrate_bad/001_create_top_dogs.rb
44
+ - test/db/migrate_good/001_create_top_dogs.rb
45
+ - test/db/migrate_good/002_create_bottom_dogs.rb
46
+ - test/db/migrate_good/003_create_cats.rb
47
+ - test/db/schema.rb
48
+ - test/foundry_only_helper.rb
49
+ - test/full_migration_test_generator_test.rb
50
+ - test/helper.rb
51
+ - test/migration_test_generator_test.rb
52
+ - uninstall.rb
53
+ has_rdoc: true
54
+ homepage: http://github.com/atomicobject/birdbath
55
+ licenses: []
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project: birdbath
74
+ rubygems_version: 1.6.2
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: A Rails gem for testing migrations
78
+ test_files: []