fixture_builder 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +97 -0
- data/Rakefile +11 -0
- data/VERSION +1 -0
- data/fixture_builder.gemspec +31 -0
- data/lib/fixture_builder.rb +25 -0
- data/lib/fixture_builder/builder.rb +112 -0
- data/lib/fixture_builder/configuration.rb +112 -0
- data/lib/fixture_builder/delegations.rb +20 -0
- data/lib/fixture_builder/namer.rb +64 -0
- data/lib/fixture_builder/version.rb +3 -0
- data/lib/tasks/fixture_builder.rake +19 -0
- data/test/fixture_builder_test.rb +43 -0
- data/test/fixtures/.gitkeep +0 -0
- data/test/legacy_fixture_mode_fixture_generation_test.rb +40 -0
- data/test/legacy_fixture_mode_test.rb +41 -0
- data/test/legacy_fixtures/magical_creatures.yml +12 -0
- data/test/namer_test.rb +44 -0
- data/test/test_helper.rb +43 -0
- data/tmp/.gitkeep +0 -0
- metadata +168 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.8.7@fixture_builder --create
|
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 [name of plugin creator]
|
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.markdown
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
FixtureBuilder
|
2
|
+
==============
|
3
|
+
|
4
|
+
Based on the code from fixture_scenarios, by Chris Wanstrath. Allows you to build file fixtures from an object mother factory.
|
5
|
+
|
6
|
+
Installing
|
7
|
+
==========
|
8
|
+
|
9
|
+
1. Install as a plugin or gem: `gem install fixture_builder`
|
10
|
+
1. Create a file which configures and declares your fixtures (see below for example)
|
11
|
+
1. Require the above file in your `spec_helper.rb` or `test_helper.rb`
|
12
|
+
|
13
|
+
|
14
|
+
Example
|
15
|
+
=======
|
16
|
+
|
17
|
+
When using an object mother such as factory_girl it can be setup like the following:
|
18
|
+
|
19
|
+
# I usually put this file in spec/support/fixture_builder.rb
|
20
|
+
FixtureBuilder.configure do |fbuilder|
|
21
|
+
# rebuild fixtures automatically when these files change:
|
22
|
+
fbuilder.files_to_check += Dir["spec/factories/*.rb", "spec/support/fixture_builder.rb"]
|
23
|
+
|
24
|
+
# now declare objects
|
25
|
+
fbuilder.factory do
|
26
|
+
david = Factory(:user, :unique_name => "david")
|
27
|
+
ipod = Factory(:product, :name => "iPod")
|
28
|
+
Factory(:purchase, :user => david, :product => ipod)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
The block passed to the factory method initiates the creation of the fixture files. Before yielding to the block, FixtureBuilder cleans out the test database completely. When the block finishes, it dumps the state of the database into fixtures, like this:
|
33
|
+
|
34
|
+
# users.yml
|
35
|
+
david:
|
36
|
+
created_at: 2010-09-18 17:21:23.926511 Z
|
37
|
+
unique_name: david
|
38
|
+
id: 1
|
39
|
+
|
40
|
+
# products.yml
|
41
|
+
i_pod:
|
42
|
+
name: iPod
|
43
|
+
id: 1
|
44
|
+
|
45
|
+
# purchases.yml
|
46
|
+
purchase_001:
|
47
|
+
product_id: 1
|
48
|
+
user_id: 1
|
49
|
+
|
50
|
+
FixtureBuilder guesses about how to name fixtures based on a prioritized list of attribute names. You can also hint at a name or manually name an object. Both of the following lines would work to rename `purchase_001` to `davids_ipod`:
|
51
|
+
|
52
|
+
fbuilder.name(:davids_ipod, Factory(:purchase, :user => david, :product => ipod))
|
53
|
+
@davids_ipod = Factory(:purchase, :user => david, :product => ipod)
|
54
|
+
|
55
|
+
Another way to name fixtures is to use the name_model_with. To use it you create a block that returns how you want a certain model name based on the record field.
|
56
|
+
|
57
|
+
fbuilder.name_model_with(User) do |record|
|
58
|
+
[record['first_name'], record['last_name']].join('_')
|
59
|
+
end
|
60
|
+
|
61
|
+
For all User fixture {first_name: 'foo', last_name: 'bar'} it would generate `foo_bar` as the fixture name.
|
62
|
+
|
63
|
+
There are also additional configuration options that can be changed to override the defaults:
|
64
|
+
|
65
|
+
* files_to_check: array of filenames that when changed cause fixtures to be rebuilt
|
66
|
+
* fixture_builder_file: the pathname of the file used to store file changes.
|
67
|
+
* record_name_fields: array of field names to use as a fixture's name prefix, it will use the first matching field it finds
|
68
|
+
* skip_tables: array of table names to skip building fixtures
|
69
|
+
* select_sql: sql string to use for select
|
70
|
+
* delete_sql: sql string to use for deletes
|
71
|
+
|
72
|
+
By default these are set as:
|
73
|
+
|
74
|
+
* files_to_check: %w{ db/schema.rb }
|
75
|
+
* fixture_builder_file: RAILS_ROOT/tmp/fixture_builder.yml
|
76
|
+
* record_name_fields: %w{ schema_migrations }
|
77
|
+
* skip_tables: %w{ schema_migrations }
|
78
|
+
* select_sql: SELECT * FROM %s
|
79
|
+
* delete_sql: DELETE FROM %s
|
80
|
+
|
81
|
+
Sequence Collisions
|
82
|
+
===================
|
83
|
+
|
84
|
+
One problem with generating your fixtures is that sequences can collide. When the fixtures are generated only as needed, sometimes the process that generates the fixtures will be different than the process that runs the tests. This results in collisions when you still use factories in your tests. Here's a solution for FactoryGirl which resets sequences numbers to 1000 (to avoid conflicts with fixture data which should e sequenced < 1000) before the tests run:
|
85
|
+
|
86
|
+
FixtureBuilder.configure do |fbuilder|
|
87
|
+
...
|
88
|
+
end
|
89
|
+
|
90
|
+
# Have factory girl generate non-colliding sequences starting at 1000 for data created after the fixtures
|
91
|
+
Factory.sequences.each do |name, seq|
|
92
|
+
seq.instance_variable_set(:@value, 1000)
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
Copyright (c) 2009 Ryan Dy & David Stevenson, released under the MIT license
|
data/Rakefile
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.2
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'fixture_builder/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = %q{fixture_builder}
|
7
|
+
s.version = FixtureBuilder::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
10
|
+
s.authors = ['Ryan Dy', 'David Stevenson']
|
11
|
+
s.date = %q{2011-04-29}
|
12
|
+
s.description = %q{FixtureBuilder allows testers to use their existing factories, like FactoryGirl, to generate high performance fixtures that can be shared across all your tests}
|
13
|
+
s.email = %q{mail@ryandy.com}
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
'README.markdown'
|
16
|
+
]
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.require_paths = ['lib']
|
21
|
+
|
22
|
+
s.homepage = %q{http://github.com/rdy/fixture_builder}
|
23
|
+
s.rubyforge_project = %q{fixture_builder}
|
24
|
+
s.summary = %q{Build YAML fixtures using object factories}
|
25
|
+
|
26
|
+
s.add_dependency(%q{activerecord}, '>= 2')
|
27
|
+
s.add_dependency(%q{activesupport}, '>= 2')
|
28
|
+
s.add_development_dependency(%q{rake}, '0.8.7')
|
29
|
+
s.add_development_dependency(%q{test-unit})
|
30
|
+
s.add_development_dependency(%q{sqlite3})
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'fixture_builder/delegations'
|
2
|
+
require 'fixture_builder/configuration'
|
3
|
+
require 'fixture_builder/namer'
|
4
|
+
require 'fixture_builder/builder'
|
5
|
+
|
6
|
+
module FixtureBuilder
|
7
|
+
class << self
|
8
|
+
def configuration(opts = {})
|
9
|
+
@configuration ||= FixtureBuilder::Configuration.new(opts)
|
10
|
+
end
|
11
|
+
|
12
|
+
def configure(opts = {})
|
13
|
+
yield configuration(opts)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
begin
|
18
|
+
class Railtie < ::Rails::Railtie
|
19
|
+
rake_tasks do
|
20
|
+
load "tasks/fixture_builder.rake"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
rescue LoadError, NameError
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module FixtureBuilder
|
2
|
+
class Builder
|
3
|
+
include Delegations::Namer
|
4
|
+
include Delegations::Configuration
|
5
|
+
|
6
|
+
def initialize(configuration, namer, builder_block)
|
7
|
+
@configuration = configuration
|
8
|
+
@namer = namer
|
9
|
+
@builder_block = builder_block
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate!
|
13
|
+
say "Building fixtures"
|
14
|
+
clean_out_old_data
|
15
|
+
create_fixture_objects
|
16
|
+
write_data_to_files
|
17
|
+
after_build.call if after_build
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def create_fixture_objects
|
23
|
+
load_legacy_fixtures if legacy_fixtures.present?
|
24
|
+
surface_errors { instance_eval &@builder_block }
|
25
|
+
end
|
26
|
+
|
27
|
+
def load_legacy_fixtures
|
28
|
+
legacy_fixtures.each do |fixture_file|
|
29
|
+
fixtures = ::Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*'))
|
30
|
+
populate_custom_names(fixtures)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def surface_errors
|
35
|
+
yield
|
36
|
+
rescue Object => error
|
37
|
+
puts
|
38
|
+
say "There was an error building fixtures", error.inspect
|
39
|
+
puts
|
40
|
+
puts error.backtrace
|
41
|
+
puts
|
42
|
+
exit!
|
43
|
+
end
|
44
|
+
|
45
|
+
def write_data_to_files
|
46
|
+
delete_yml_files
|
47
|
+
dump_empty_fixtures_for_all_tables
|
48
|
+
dump_tables
|
49
|
+
end
|
50
|
+
|
51
|
+
def clean_out_old_data
|
52
|
+
delete_tables
|
53
|
+
delete_yml_files
|
54
|
+
end
|
55
|
+
|
56
|
+
def delete_tables
|
57
|
+
tables.each { |t| ActiveRecord::Base.connection.delete(delete_sql % ActiveRecord::Base.connection.quote_table_name(t)) }
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete_yml_files
|
61
|
+
FileUtils.rm(Dir.glob(fixtures_dir('*.yml'))) rescue nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def say(*messages)
|
65
|
+
puts messages.map { |message| "=> #{message}" }
|
66
|
+
end
|
67
|
+
|
68
|
+
def dump_empty_fixtures_for_all_tables
|
69
|
+
tables.each do |table_name|
|
70
|
+
write_fixture_file({}, table_name)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def dump_tables
|
75
|
+
default_date_format = Date::DATE_FORMATS[:default]
|
76
|
+
Date::DATE_FORMATS[:default] = Date::DATE_FORMATS[:db]
|
77
|
+
begin
|
78
|
+
fixtures = tables.inject([]) do |files, table_name|
|
79
|
+
table_klass = table_name.classify.constantize rescue nil
|
80
|
+
if table_klass
|
81
|
+
rows = table_klass.all.collect(&:attributes)
|
82
|
+
else
|
83
|
+
rows = ActiveRecord::Base.connection.select_all(select_sql % ActiveRecord::Base.connection.quote_table_name(table_name))
|
84
|
+
end
|
85
|
+
next files if rows.empty?
|
86
|
+
|
87
|
+
row_index = '000'
|
88
|
+
fixture_data = rows.inject({}) do |hash, record|
|
89
|
+
hash.merge(record_name(record, table_name, row_index) => record)
|
90
|
+
end
|
91
|
+
|
92
|
+
write_fixture_file fixture_data, table_name
|
93
|
+
|
94
|
+
files + [File.basename(fixture_file(table_name))]
|
95
|
+
end
|
96
|
+
ensure
|
97
|
+
Date::DATE_FORMATS[:default] = default_date_format
|
98
|
+
end
|
99
|
+
say "Built #{fixtures.to_sentence}"
|
100
|
+
end
|
101
|
+
|
102
|
+
def write_fixture_file(fixture_data, table_name)
|
103
|
+
File.open(fixture_file(table_name), 'w') do |file|
|
104
|
+
file.write fixture_data.to_yaml
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def fixture_file(table_name)
|
109
|
+
fixtures_dir("#{table_name}.yml")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
require 'active_support/core_ext/string'
|
3
|
+
require 'digest/md5'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
module FixtureBuilder
|
7
|
+
class Configuration
|
8
|
+
include Delegations::Namer
|
9
|
+
|
10
|
+
ACCESSIBLE_ATTRIBUTES = [:select_sql, :delete_sql, :skip_tables, :files_to_check, :record_name_fields,
|
11
|
+
:fixture_builder_file, :after_build, :legacy_fixtures, :model_name_procs]
|
12
|
+
attr_accessor(*ACCESSIBLE_ATTRIBUTES)
|
13
|
+
|
14
|
+
SCHEMA_FILES = ['db/schema.rb', 'db/development_structure.sql', 'db/test_structure.sql', 'db/production_structure.sql']
|
15
|
+
|
16
|
+
def initialize(opts={})
|
17
|
+
@namer = Namer.new(self)
|
18
|
+
@file_hashes = file_hashes
|
19
|
+
end
|
20
|
+
|
21
|
+
def include(*args)
|
22
|
+
class_eval do
|
23
|
+
args.each do |arg|
|
24
|
+
include arg
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def factory(&block)
|
30
|
+
self.files_to_check += @legacy_fixtures.to_a
|
31
|
+
return unless rebuild_fixtures?
|
32
|
+
@builder = Builder.new(self, @namer, block).generate!
|
33
|
+
write_config
|
34
|
+
end
|
35
|
+
|
36
|
+
def select_sql
|
37
|
+
@select_sql ||= "SELECT * FROM %s"
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete_sql
|
41
|
+
@delete_sql ||= "DELETE FROM %s"
|
42
|
+
end
|
43
|
+
|
44
|
+
def skip_tables
|
45
|
+
@skip_tables ||= %w{ schema_migrations }
|
46
|
+
end
|
47
|
+
|
48
|
+
def files_to_check
|
49
|
+
@files_to_check ||= schema_definition_files
|
50
|
+
end
|
51
|
+
|
52
|
+
def schema_definition_files
|
53
|
+
Dir['db/*'].inject([]) do |result, file|
|
54
|
+
result << file if SCHEMA_FILES.include?(file)
|
55
|
+
result
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def files_to_check=(files)
|
60
|
+
@files_to_check = files
|
61
|
+
@file_hashes = file_hashes
|
62
|
+
@files_to_check
|
63
|
+
end
|
64
|
+
|
65
|
+
def record_name_fields
|
66
|
+
@record_name_fields ||= %w{ unique_name display_name name title username login }
|
67
|
+
end
|
68
|
+
|
69
|
+
def fixture_builder_file
|
70
|
+
@fixture_builder_file ||= ::Rails.root.join('tmp', 'fixture_builder.yml')
|
71
|
+
end
|
72
|
+
|
73
|
+
def name_model_with(model_class, &block)
|
74
|
+
@namer.name_model_with(model_class, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
def tables
|
78
|
+
ActiveRecord::Base.connection.tables - skip_tables
|
79
|
+
end
|
80
|
+
|
81
|
+
def fixtures_dir(path = '')
|
82
|
+
File.expand_path(File.join(::Rails.root, spec_or_test_dir, 'fixtures', path))
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def spec_or_test_dir
|
88
|
+
File.exists?(File.join(::Rails.root, 'spec')) ? 'spec' : 'test'
|
89
|
+
end
|
90
|
+
|
91
|
+
def file_hashes
|
92
|
+
files_to_check.inject({}) do |hash, filename|
|
93
|
+
hash[filename] = Digest::MD5.hexdigest(File.read(filename))
|
94
|
+
hash
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def read_config
|
99
|
+
return {} unless File.exist?(fixture_builder_file)
|
100
|
+
YAML.load_file(fixture_builder_file)
|
101
|
+
end
|
102
|
+
|
103
|
+
def write_config
|
104
|
+
FileUtils.mkdir_p(File.dirname(fixture_builder_file))
|
105
|
+
File.open(fixture_builder_file, 'w') { |f| f.write(YAML.dump(@file_hashes)) }
|
106
|
+
end
|
107
|
+
|
108
|
+
def rebuild_fixtures?
|
109
|
+
@file_hashes != read_config
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
|
3
|
+
module FixtureBuilder
|
4
|
+
module Delegations
|
5
|
+
module Configuration
|
6
|
+
def self.included(base)
|
7
|
+
methods_to_delegate = [:fixtures_dir, :tables, :legacy_fixtures].concat(::FixtureBuilder::Configuration::ACCESSIBLE_ATTRIBUTES).flatten
|
8
|
+
methods_to_delegate.each do |meth|
|
9
|
+
base.delegate(meth, :to => :@configuration)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Namer
|
15
|
+
def self.included(base)
|
16
|
+
base.delegate :record_name, :populate_custom_names, :name, :name_model_with, :to => :@namer
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module FixtureBuilder
|
2
|
+
class Namer
|
3
|
+
include Delegations::Configuration
|
4
|
+
|
5
|
+
def initialize(configuration)
|
6
|
+
@configuration = configuration
|
7
|
+
@custom_names = {}
|
8
|
+
@model_name_procs = {}
|
9
|
+
@record_names = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def name_model_with(model_class, &block)
|
13
|
+
@model_name_procs[model_class.table_name] = block
|
14
|
+
end
|
15
|
+
|
16
|
+
def name(custom_name, *model_objects)
|
17
|
+
raise "Cannot name an object blank" unless custom_name.present?
|
18
|
+
model_objects.each do |model_object|
|
19
|
+
raise "Cannot name a blank object" unless model_object.present?
|
20
|
+
key = [model_object.class.table_name, model_object.id]
|
21
|
+
raise "Cannot set name for #{key.inspect} object twice" if @custom_names[key]
|
22
|
+
@custom_names[key] = custom_name
|
23
|
+
model_object
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def populate_custom_names(fixtures)
|
28
|
+
fixtures.each do |fixture|
|
29
|
+
name = fixture[0]
|
30
|
+
id = fixture[1]['id'].to_i
|
31
|
+
table_name = fixture[1].model_class.table_name
|
32
|
+
key = [table_name, id]
|
33
|
+
@custom_names[key] = name
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def record_name(record_hash, table_name, row_index)
|
38
|
+
key = [table_name, record_hash['id'].to_i]
|
39
|
+
name = case
|
40
|
+
when name_proc = @model_name_procs[table_name]
|
41
|
+
name_proc.call(record_hash, row_index.succ!)
|
42
|
+
when custom = @custom_names[key]
|
43
|
+
custom
|
44
|
+
else
|
45
|
+
inferred_record_name(record_hash, table_name, row_index)
|
46
|
+
end
|
47
|
+
@record_names << name
|
48
|
+
name.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
def inferred_record_name(record_hash, table_name, row_index)
|
53
|
+
record_name_fields.each do |try|
|
54
|
+
if name = record_hash[try]
|
55
|
+
inferred_name = name.underscore.gsub(/\W/, ' ').squeeze(' ').tr(' ', '_')
|
56
|
+
count = @record_names.select { |name| name.to_s.starts_with?(inferred_name) }.size
|
57
|
+
# CHANGED == to starts_with?
|
58
|
+
return count.zero? ? inferred_name : "#{inferred_name}_#{count}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
[table_name, row_index.succ!].join('_')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
namespace :spec do
|
2
|
+
namespace :fixture_builder do
|
3
|
+
desc "Deletes the generated fixtures in spec/fixtures"
|
4
|
+
task :clean do
|
5
|
+
FileUtils.rm_f("tmp/fixture_builder.yml")
|
6
|
+
FileUtils.rm_f(Dir.glob('spec/fixtures/*.yml'))
|
7
|
+
puts "Automatically generated fixtures removed"
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Build the generated fixtures to spec/fixtures if dirty"
|
11
|
+
task :build => :environment do
|
12
|
+
ActiveRecord::Base.establish_connection('test')
|
13
|
+
Dir.glob(File.join(Rails.root, '{spec,test}', '**', 'fixture_builder.rb')).each{|file| require(file)}
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Clean and rebuild the generated fixtures to spec/fixtures"
|
17
|
+
task :rebuild => [:clean, :build]
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
+
|
3
|
+
|
4
|
+
class Model
|
5
|
+
def self.table_name
|
6
|
+
'models'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class FixtureBuilderTest < Test::Unit::TestCase
|
11
|
+
def teardown
|
12
|
+
FixtureBuilder.instance_variable_set(:'@configuration', nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_name_with
|
16
|
+
hash = {
|
17
|
+
'id' => 1,
|
18
|
+
'email' => 'bob@example.com'
|
19
|
+
}
|
20
|
+
FixtureBuilder.configure do |config|
|
21
|
+
config.name_model_with Model do |record_hash, index|
|
22
|
+
[record_hash['email'].split('@').first, index].join('_')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
assert_equal 'bob_001', FixtureBuilder.configuration.send(:record_name, hash, Model.table_name, '000')
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_configure
|
29
|
+
FixtureBuilder.configure do |config|
|
30
|
+
assert config.is_a?(FixtureBuilder::Configuration)
|
31
|
+
@called = true
|
32
|
+
end
|
33
|
+
assert @called
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_spec_or_test_dir
|
37
|
+
assert_equal 'test', FixtureBuilder.configuration.send(:spec_or_test_dir)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_fixtures_dir
|
41
|
+
assert_match /test\/fixtures$/, FixtureBuilder.configuration.send(:fixtures_dir).to_s
|
42
|
+
end
|
43
|
+
end
|
File without changes
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
+
|
3
|
+
create_and_blow_away_old_db
|
4
|
+
force_fixture_generation
|
5
|
+
|
6
|
+
FixtureBuilder.configure do |fbuilder|
|
7
|
+
fbuilder.legacy_fixtures = Dir[test_path("legacy_fixtures/*.yml"), test_path("other_legacy_fixture_set/*.yml")]
|
8
|
+
fbuilder.factory do
|
9
|
+
MagicalCreature.create(:name => "frank", :species => "unicorn")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class LegacyFixtureModeFixtureGenerationTest < Test::Unit::TestCase
|
14
|
+
@@magical_creatures = YAML.load(File.open(test_path("fixtures/magical_creatures.yml")))
|
15
|
+
|
16
|
+
def test_legacy_fixtures_created
|
17
|
+
alice = MagicalCreature.find_by_name("alice")
|
18
|
+
assert_equal "alice", alice.name
|
19
|
+
assert_equal "mermaid", alice.species
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_invalid_legacy_fixtures_created
|
23
|
+
bigfoot = MagicalCreature.find(5)
|
24
|
+
assert_equal "bigfoot", bigfoot.name
|
25
|
+
|
26
|
+
assert_equal 5, @@magical_creatures['bigfoot']['id']
|
27
|
+
assert_equal "bigfoot", @@magical_creatures['bigfoot']['name']
|
28
|
+
assert_nil @@magical_creatures['bigfoot']['species']
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_new_fixtures_are_created
|
32
|
+
assert_equal "frank", @@magical_creatures['frank']['name']
|
33
|
+
assert_equal "unicorn", @@magical_creatures['frank']['species']
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_legacy_fixtures_retain_fixture_name
|
37
|
+
assert_equal "alice", @@magical_creatures['alice_the_mermaid']['name']
|
38
|
+
assert_equal "mermaid", @@magical_creatures['alice_the_mermaid']['species']
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
+
|
3
|
+
class LegacyFixtureModeTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
create_and_blow_away_old_db
|
6
|
+
force_fixture_generation
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown
|
10
|
+
FixtureBuilder.send(:remove_instance_variable, :@configuration)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_load_legacy_fixtures
|
14
|
+
FixtureBuilder.configure do |fbuilder|
|
15
|
+
fbuilder.legacy_fixtures = Dir[test_path("legacy_fixtures/*.yml"), test_path("other_legacy_fixture_set/*.yml")]
|
16
|
+
fbuilder.factory do
|
17
|
+
end
|
18
|
+
end
|
19
|
+
assert_equal 3, MagicalCreature.all.size
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_generate_new_fixtures_without_legacy
|
23
|
+
FixtureBuilder.configure do |fbuilder|
|
24
|
+
fbuilder.files_to_check += Dir[test_path("*.rb")]
|
25
|
+
fbuilder.factory do
|
26
|
+
MagicalCreature.create :name => "Melinda", :species => "Philanthropist"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
assert_equal 1, MagicalCreature.all.size
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_new_and_old_fixtures
|
33
|
+
FixtureBuilder.configure do |fbuilder|
|
34
|
+
fbuilder.legacy_fixtures = Dir[test_path("legacy_fixtures/*.yml"), test_path("other_legacy_fixture_set/*.yml")]
|
35
|
+
fbuilder.factory do
|
36
|
+
MagicalCreature.create :name => "Barry", :species => "Party Guy"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
assert_equal 4, MagicalCreature.all.size
|
40
|
+
end
|
41
|
+
end
|
data/test/namer_test.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
+
|
3
|
+
class Model
|
4
|
+
def self.table_name
|
5
|
+
'models'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class NamerTest < Test::Unit::TestCase
|
10
|
+
def setup
|
11
|
+
configuration = FixtureBuilder::Configuration.new
|
12
|
+
@namer = FixtureBuilder::Namer.new(configuration)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_name_with
|
16
|
+
hash = {
|
17
|
+
'id' => 1,
|
18
|
+
'email' => 'bob@example.com'
|
19
|
+
}
|
20
|
+
|
21
|
+
@namer.name_model_with Model do |record_hash, index|
|
22
|
+
[record_hash['email'].split('@').first, index].join('_')
|
23
|
+
end
|
24
|
+
|
25
|
+
assert_equal 'bob_001', @namer.record_name(hash, Model.table_name, '000')
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_record_name_without_name_with_or_custom_name
|
29
|
+
hash = {
|
30
|
+
'id' => 1,
|
31
|
+
'email' => 'bob@example.com'
|
32
|
+
}
|
33
|
+
assert_equal 'models_001', @namer.record_name(hash, Model.table_name, '000')
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_record_name_with_inferred_record_name
|
37
|
+
hash = {
|
38
|
+
'id' => 1,
|
39
|
+
'title' => 'foo',
|
40
|
+
'email' => 'bob@example.com'
|
41
|
+
}
|
42
|
+
assert_equal 'foo', @namer.record_name(hash, Model.table_name, '000')
|
43
|
+
end
|
44
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'test/unit'
|
4
|
+
require 'fixture_builder'
|
5
|
+
|
6
|
+
class Rails
|
7
|
+
def self.root
|
8
|
+
Pathname.new(File.join(File.dirname(__FILE__), '..'))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_path(glob)
|
13
|
+
File.join(Rails.root, 'test', glob)
|
14
|
+
end
|
15
|
+
|
16
|
+
require "active_support/concern"
|
17
|
+
require "active_record"
|
18
|
+
require "sqlite3"
|
19
|
+
require "active_record/fixtures"
|
20
|
+
|
21
|
+
class MagicalCreature < ActiveRecord::Base
|
22
|
+
validates_presence_of :name, :species
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_and_blow_away_old_db
|
26
|
+
ActiveRecord::Base.configurations['test'] = {
|
27
|
+
'adapter' => 'sqlite3',
|
28
|
+
'database' => 'test.db'
|
29
|
+
}
|
30
|
+
ActiveRecord::Base.establish_connection(:test)
|
31
|
+
|
32
|
+
ActiveRecord::Base.connection.create_table(:magical_creatures, :force => true) do |t|
|
33
|
+
t.column :name, :string
|
34
|
+
t.column :species, :string
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def force_fixture_generation
|
39
|
+
begin
|
40
|
+
FileUtils.rm(File.expand_path("../../tmp/fixture_builder.yml", __FILE__))
|
41
|
+
rescue
|
42
|
+
end
|
43
|
+
end
|
data/tmp/.gitkeep
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fixture_builder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 0.3.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Ryan Dy
|
14
|
+
- David Stevenson
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-04-29 00:00:00 -07:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: activerecord
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 7
|
31
|
+
segments:
|
32
|
+
- 2
|
33
|
+
version: "2"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: activesupport
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 7
|
45
|
+
segments:
|
46
|
+
- 2
|
47
|
+
version: "2"
|
48
|
+
type: :runtime
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: rake
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - "="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 49
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
- 8
|
62
|
+
- 7
|
63
|
+
version: 0.8.7
|
64
|
+
type: :development
|
65
|
+
version_requirements: *id003
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: test-unit
|
68
|
+
prerelease: false
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
hash: 3
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
type: :development
|
79
|
+
version_requirements: *id004
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: sqlite3
|
82
|
+
prerelease: false
|
83
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
type: :development
|
93
|
+
version_requirements: *id005
|
94
|
+
description: FixtureBuilder allows testers to use their existing factories, like FactoryGirl, to generate high performance fixtures that can be shared across all your tests
|
95
|
+
email: mail@ryandy.com
|
96
|
+
executables: []
|
97
|
+
|
98
|
+
extensions: []
|
99
|
+
|
100
|
+
extra_rdoc_files:
|
101
|
+
- README.markdown
|
102
|
+
files:
|
103
|
+
- .gitignore
|
104
|
+
- .pairs
|
105
|
+
- .rvmrc
|
106
|
+
- Gemfile
|
107
|
+
- MIT-LICENSE
|
108
|
+
- README.markdown
|
109
|
+
- Rakefile
|
110
|
+
- VERSION
|
111
|
+
- fixture_builder.gemspec
|
112
|
+
- lib/fixture_builder.rb
|
113
|
+
- lib/fixture_builder/builder.rb
|
114
|
+
- lib/fixture_builder/configuration.rb
|
115
|
+
- lib/fixture_builder/delegations.rb
|
116
|
+
- lib/fixture_builder/namer.rb
|
117
|
+
- lib/fixture_builder/version.rb
|
118
|
+
- lib/tasks/fixture_builder.rake
|
119
|
+
- test/fixture_builder_test.rb
|
120
|
+
- test/fixtures/.gitkeep
|
121
|
+
- test/legacy_fixture_mode_fixture_generation_test.rb
|
122
|
+
- test/legacy_fixture_mode_test.rb
|
123
|
+
- test/legacy_fixtures/magical_creatures.yml
|
124
|
+
- test/namer_test.rb
|
125
|
+
- test/test_helper.rb
|
126
|
+
- tmp/.gitkeep
|
127
|
+
has_rdoc: true
|
128
|
+
homepage: http://github.com/rdy/fixture_builder
|
129
|
+
licenses: []
|
130
|
+
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
133
|
+
|
134
|
+
require_paths:
|
135
|
+
- lib
|
136
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
hash: 3
|
142
|
+
segments:
|
143
|
+
- 0
|
144
|
+
version: "0"
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
none: false
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
hash: 3
|
151
|
+
segments:
|
152
|
+
- 0
|
153
|
+
version: "0"
|
154
|
+
requirements: []
|
155
|
+
|
156
|
+
rubyforge_project: fixture_builder
|
157
|
+
rubygems_version: 1.6.2
|
158
|
+
signing_key:
|
159
|
+
specification_version: 3
|
160
|
+
summary: Build YAML fixtures using object factories
|
161
|
+
test_files:
|
162
|
+
- test/fixture_builder_test.rb
|
163
|
+
- test/fixtures/.gitkeep
|
164
|
+
- test/legacy_fixture_mode_fixture_generation_test.rb
|
165
|
+
- test/legacy_fixture_mode_test.rb
|
166
|
+
- test/legacy_fixtures/magical_creatures.yml
|
167
|
+
- test/namer_test.rb
|
168
|
+
- test/test_helper.rb
|