sprig 0.2.0 → 0.3.0

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -11
  3. data/lib/generators/sprig/install_generator.rb +5 -1
  4. data/lib/sprig.rb +5 -1
  5. data/lib/sprig/configuration.rb +19 -2
  6. data/lib/sprig/helpers.rb +15 -3
  7. data/lib/sprig/version.rb +8 -1
  8. data/spec/feature/configurations_spec.rb +5 -5
  9. data/spec/fixtures/seeds/shared/comments.yml +4 -0
  10. data/spec/fixtures/seeds/shared/files/cat.png +0 -0
  11. data/spec/fixtures/seeds/shared/invalid_users.yml +4 -0
  12. data/spec/fixtures/seeds/shared/legacy_posts.yml +4 -0
  13. data/spec/fixtures/seeds/shared/posts.csv +2 -0
  14. data/spec/fixtures/seeds/shared/posts.json +1 -0
  15. data/spec/fixtures/seeds/shared/posts.md +5 -0
  16. data/spec/fixtures/seeds/shared/posts.yml +4 -0
  17. data/spec/fixtures/seeds/shared/posts_delete_existing_by.yml +7 -0
  18. data/spec/fixtures/seeds/shared/posts_find_existing_by_missing.yml +7 -0
  19. data/spec/fixtures/seeds/shared/posts_find_existing_by_multiple.yml +8 -0
  20. data/spec/fixtures/seeds/shared/posts_find_existing_by_single.yml +7 -0
  21. data/spec/fixtures/seeds/shared/posts_missing_dependency.yml +5 -0
  22. data/spec/fixtures/seeds/shared/posts_missing_record.yml +5 -0
  23. data/spec/fixtures/seeds/shared/posts_partially_dynamic_value.yml +4 -0
  24. data/spec/fixtures/seeds/shared/posts_with_cyclic_dependencies.yml +4 -0
  25. data/spec/fixtures/seeds/shared/posts_with_files.yml +5 -0
  26. data/spec/fixtures/seeds/shared/posts_with_habtm.yml +7 -0
  27. data/spec/fixtures/seeds/shared/tags.yml +5 -0
  28. data/spec/lib/generators/sprig/install_generator_spec.rb +6 -2
  29. data/spec/lib/sprig/configuration_spec.rb +6 -6
  30. data/spec/lib/sprig/directive_list_spec.rb +4 -4
  31. data/spec/lib/sprig/directive_spec.rb +19 -9
  32. data/spec/lib/sprig/null_record_spec.rb +2 -2
  33. data/spec/lib/sprig/parser/base_spec.rb +1 -1
  34. data/spec/lib/sprig/process_notifier_spec.rb +1 -1
  35. data/spec/lib/sprig/seed/entry_spec.rb +3 -3
  36. data/spec/lib/sprig/seed/record_spec.rb +3 -3
  37. data/spec/lib/sprig/source_spec.rb +2 -2
  38. data/spec/lib/sprig_spec.rb +8 -8
  39. data/spec/spec_helper.rb +24 -8
  40. data/spec/sprig_shared_spec.rb +467 -0
  41. data/spec/sprig_spec.rb +37 -37
  42. data/spec/support/helpers/logger_mock.rb +2 -1
  43. metadata +89 -58
  44. data/lib/sprig/data.rb +0 -6
  45. data/spec/db/activerecord.db +0 -0
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Sprig::DirectiveList do
3
+ RSpec.describe Sprig::DirectiveList do
4
4
 
5
5
  describe "#add_seeds_to_hopper" do
6
6
  let(:hopper) { Array.new }
@@ -10,13 +10,13 @@ describe Sprig::DirectiveList do
10
10
  subject { described_class.new(Post) }
11
11
 
12
12
  before do
13
- Sprig::Directive.stub(:new).with(Post).and_return(directive)
13
+ allow(Sprig::Directive).to receive(:new).with(Post).and_return(directive)
14
14
 
15
- Sprig::Seed::Factory.stub(:new_from_directive).with(directive).and_return(seed_factory)
15
+ allow(Sprig::Seed::Factory).to receive(:new_from_directive).with(directive).and_return(seed_factory)
16
16
  end
17
17
 
18
18
  it "builds seeds from directives and adds to the given array" do
19
- seed_factory.should_receive(:add_seeds_to_hopper).with(hopper)
19
+ expect(seed_factory).to receive(:add_seeds_to_hopper).with(hopper)
20
20
 
21
21
  subject.add_seeds_to_hopper(hopper)
22
22
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Sprig::Directive do
3
+ RSpec.describe Sprig::Directive do
4
4
 
5
5
  module Users
6
6
  class Admin < User
@@ -11,19 +11,25 @@ describe Sprig::Directive do
11
11
  context "given a class" do
12
12
  subject { described_class.new(Post) }
13
13
 
14
- its(:klass) { should == Post }
14
+ it "returns the class" do
15
+ expect(subject.klass).to eq(Post)
16
+ end
15
17
  end
16
18
 
17
19
  context "given a class within a module" do
18
20
  subject { described_class.new(Users::Admin) }
19
21
 
20
- its(:klass) { should == Users::Admin }
22
+ it "returns the full class" do
23
+ expect(subject.klass).to eq(Users::Admin)
24
+ end
21
25
  end
22
26
 
23
27
  context "given options with a class" do
24
28
  subject { described_class.new(:class => Post) }
25
29
 
26
- its(:klass) { should == Post }
30
+ it "returns the class" do
31
+ expect(subject.klass).to eq(Post)
32
+ end
27
33
  end
28
34
 
29
35
  context "given options without a class" do
@@ -45,13 +51,17 @@ describe Sprig::Directive do
45
51
  context "given no options" do
46
52
  subject { described_class.new(Post) }
47
53
 
48
- its(:options) { should == {} }
54
+ it "returns an empty hash" do
55
+ expect(subject.options).to eq({})
56
+ end
49
57
  end
50
58
 
51
59
  context "given options" do
52
60
  subject { described_class.new(:class => Post, :source => 'source') }
53
61
 
54
- its(:options) { should == { :source => 'source' } }
62
+ it "returns a the options" do
63
+ expect(subject.options).to eq(:source => 'source')
64
+ end
55
65
  end
56
66
  end
57
67
 
@@ -62,11 +72,11 @@ describe Sprig::Directive do
62
72
  subject { described_class.new(:class => Post, :source => 'source') }
63
73
 
64
74
  before do
65
- Sprig::Source.stub(:new).with('posts', { :source => 'source' }).and_return(datasource)
75
+ allow(Sprig::Source).to receive(:new).with('posts', { :source => 'source' }).and_return(datasource)
66
76
  end
67
77
 
68
78
  it "returns a sprig data source" do
69
- subject.datasource.should == datasource
79
+ expect(subject.datasource).to eq(datasource)
70
80
  end
71
81
  end
72
82
 
@@ -74,7 +84,7 @@ describe Sprig::Directive do
74
84
  subject { described_class.new(Users::Admin) }
75
85
 
76
86
  it "passes the correct path to Source" do
77
- Sprig::Source.should_receive(:new).with("users_admins", {})
87
+ expect(Sprig::Source).to receive(:new).with("users_admins", {})
78
88
 
79
89
  subject.datasource
80
90
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Sprig::NullRecord do
3
+ RSpec.describe Sprig::NullRecord do
4
4
  let(:error_msg) { 'Something bad happened.' }
5
5
  subject { described_class.new(error_msg) }
6
6
 
@@ -14,7 +14,7 @@ describe Sprig::NullRecord do
14
14
 
15
15
  describe "#method_missing" do
16
16
  it "returns nil for undefined method calls" do
17
- subject.enhance_your_calm.should == nil
17
+ expect(subject.enhance_your_calm).to eq(nil)
18
18
  end
19
19
  end
20
20
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Sprig::Parser::Base do
3
+ RSpec.describe Sprig::Parser::Base do
4
4
  describe "#parse" do
5
5
  it "enforces implementation in a subclass" do
6
6
  expect {
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Sprig::ProcessNotifier do
3
+ RSpec.describe Sprig::ProcessNotifier do
4
4
  it_behaves_like "a logging entity" do
5
5
  subject { described_class.new }
6
6
  end
@@ -1,13 +1,13 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Sprig::Seed::Entry do
3
+ RSpec.describe Sprig::Seed::Entry do
4
4
  describe ".success_log_text" do
5
5
  context "on a new record" do
6
6
  it "indicates the record was 'saved'" do
7
7
  subject = described_class.new(Post, { title: "Hello World!", content: "Stuff", sprig_id: 1 }, {})
8
8
  subject.save_record
9
9
 
10
- subject.success_log_text.should == "Saved"
10
+ expect(subject.success_log_text).to eq("Saved")
11
11
  end
12
12
  end
13
13
 
@@ -24,7 +24,7 @@ describe Sprig::Seed::Entry do
24
24
  subject = described_class.new(Post, { title: "Existing title", content: "Existing content", sprig_id: 1 }, { find_existing_by: [:title] })
25
25
  subject.save_record
26
26
 
27
- subject.success_log_text.should == "Updated"
27
+ expect(subject.success_log_text).to eq("Updated")
28
28
  end
29
29
  end
30
30
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Sprig::Seed::Record do
3
+ RSpec.describe Sprig::Seed::Record do
4
4
  describe ".existing?" do
5
5
  let!(:existing) do
6
6
  Post.create(
@@ -13,13 +13,13 @@ describe Sprig::Seed::Record do
13
13
  it "returns true if the record has already been saved to the database" do
14
14
  subject = described_class.new_or_existing(Post, { title: "Existing title" }, { title: "Existing title" })
15
15
 
16
- subject.existing?.should == true
16
+ expect(subject.existing?).to eq(true)
17
17
  end
18
18
 
19
19
  it "returns false if the record is new" do
20
20
  subject = described_class.new_or_existing(Post, { title: "New title" }, { title: "New title" })
21
21
 
22
- subject.existing?.should == false
22
+ expect(subject.existing?).to eq(false)
23
23
  end
24
24
  end
25
25
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Sprig::NullRecord do
3
+ RSpec.describe Sprig::NullRecord do
4
4
  let(:error_msg) { 'Something bad happened.' }
5
5
  subject { described_class.new(error_msg) }
6
6
 
@@ -14,7 +14,7 @@ describe Sprig::NullRecord do
14
14
 
15
15
  describe "#method_missing" do
16
16
  it "returns nil for undefined method calls" do
17
- subject.enhance_your_calm.should == nil
17
+ expect(subject.enhance_your_calm).to eq(nil)
18
18
  end
19
19
  end
20
20
 
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Sprig do
3
+ RSpec.describe Sprig do
4
4
  let(:configuration) { double('Configuration') }
5
5
 
6
6
  before do
7
- Sprig::Configuration.stub(:new).and_return(configuration)
7
+ allow(Sprig::Configuration).to receive(:new).and_return(configuration)
8
8
  end
9
9
 
10
10
  describe '.adapter' do
@@ -61,7 +61,7 @@ describe Sprig do
61
61
  describe ".configuration" do
62
62
  context "when there is not yet a Configuration instance" do
63
63
  it "returns a new Configuration instance" do
64
- described_class.configuration.should == configuration
64
+ expect(described_class.configuration).to eq(configuration)
65
65
  end
66
66
  end
67
67
 
@@ -72,9 +72,9 @@ describe Sprig do
72
72
 
73
73
  it "returns the existing Configuration instance" do
74
74
  new_configuration = double('Configuration')
75
- Sprig::Configuration.stub(:new).and_return(new_configuration)
75
+ allow(Sprig::Configuration).to receive(:new).and_return(new_configuration)
76
76
 
77
- described_class.configuration.should == configuration
77
+ expect(described_class.configuration).to eq(configuration)
78
78
  end
79
79
  end
80
80
  end
@@ -87,16 +87,16 @@ describe Sprig do
87
87
  it "clears the existing configuration" do
88
88
  described_class.reset_configuration
89
89
  new_configuration = double('Configuration')
90
- Sprig::Configuration.stub(:new).and_return(new_configuration)
90
+ allow(Sprig::Configuration).to receive(:new).and_return(new_configuration)
91
91
 
92
- described_class.configuration.should == new_configuration
92
+ expect(described_class.configuration).to eq(new_configuration)
93
93
  end
94
94
  end
95
95
 
96
96
  describe ".configure" do
97
97
  it "yields the configuration" do
98
98
  described_class.configure do |config|
99
- config.should == configuration
99
+ expect(config).to eq(configuration)
100
100
  end
101
101
  end
102
102
  end
@@ -21,6 +21,14 @@ RSpec.configure do |c|
21
21
  c.include ColoredText
22
22
  c.include LoggerMock
23
23
 
24
+ c.disable_monkey_patching!
25
+
26
+ c.order = :random
27
+
28
+ c.mock_with :rspec do |mocks|
29
+ mocks.verify_partial_doubles = true
30
+ end
31
+
24
32
  c.after(:each) do
25
33
  Sprig.reset_configuration
26
34
  end
@@ -56,29 +64,37 @@ require "adapters/#{Sprig.adapter}.rb"
56
64
  #
57
65
  # Setup fake `Rails.root`
58
66
  def stub_rails_root(path='./spec/fixtures')
59
- Rails.stub(:root).and_return(Pathname.new(path))
67
+ allow(Rails).to receive(:root).and_return(Pathname.new(path))
60
68
  end
61
69
 
62
70
  # Setup fake `Rails.env`
63
71
  def stub_rails_env(env='development')
64
- Rails.stub(:env).and_return(env)
72
+ allow(Rails).to receive(:env).and_return(env)
65
73
  end
66
74
 
67
75
  # Copy and Remove Seed files around a spec
68
- def load_seeds(*files)
76
+ def load_seeds(*files, &block)
69
77
  env = Rails.env
78
+ prepare_seeds(env, *files, &block)
79
+ end
80
+
81
+ # Copy and Remove shared seed files around a spec
82
+ def load_shared_seeds(*files, &block)
83
+ prepare_seeds('shared', *files, &block)
84
+ end
70
85
 
71
- `cp -R ./spec/fixtures/seeds/#{env}/files ./spec/fixtures/db/seeds/#{env}`
86
+ def prepare_seeds(directory, *files, &block)
87
+ `cp -R ./spec/fixtures/seeds/#{directory}/files ./spec/fixtures/db/seeds/#{directory}`
72
88
 
73
89
  files.each do |file|
74
- `cp ./spec/fixtures/seeds/#{env}/#{file} ./spec/fixtures/db/seeds/#{env}`
90
+ `cp ./spec/fixtures/seeds/#{directory}/#{file} ./spec/fixtures/db/seeds/#{directory}`
75
91
  end
76
92
 
77
- yield
93
+ block.call
78
94
 
79
- `rm -R ./spec/fixtures/db/seeds/#{env}/files`
95
+ `rm -R ./spec/fixtures/db/seeds/#{directory}/files`
80
96
 
81
97
  files.each do |file|
82
- `rm ./spec/fixtures/db/seeds/#{env}/#{file}`
98
+ `rm ./spec/fixtures/db/seeds/#{directory}/#{file}`
83
99
  end
84
100
  end
@@ -0,0 +1,467 @@
1
+ require 'spec_helper'
2
+ require 'open-uri'
3
+
4
+ RSpec.describe "Seeding an application with shared seeds" do
5
+ let(:missing_record_error) do
6
+ if defined?(ActiveRecord) && Post < ActiveRecord::Base
7
+ ActiveRecord::RecordNotFound
8
+ elsif defined?(Mongoid) && Post < Mongoid::Document
9
+ Mongoid::Errors::DocumentNotFound
10
+ end
11
+ end
12
+
13
+ before do
14
+ stub_rails_root
15
+ end
16
+
17
+ context "with a yaml file" do
18
+ around do |example|
19
+ load_shared_seeds('posts.yml', &example)
20
+ end
21
+
22
+ it "seeds the db" do
23
+ sprig_shared [Post]
24
+
25
+ expect(Post.count).to eq(1)
26
+ expect(Post.pluck(:title)).to eq(['Yaml title'])
27
+ end
28
+ end
29
+
30
+ context "with a csv file" do
31
+ around do |example|
32
+ load_shared_seeds('posts.csv', &example)
33
+ end
34
+
35
+ it "seeds the db" do
36
+ sprig_shared [Post]
37
+
38
+ expect(Post.count).to eq(1)
39
+ expect(Post.pluck(:title)).to eq(['Csv title'])
40
+ end
41
+ end
42
+
43
+ context "with a json file" do
44
+ around do |example|
45
+ load_shared_seeds('posts.json', &example)
46
+ end
47
+
48
+ it "seeds the db" do
49
+ sprig_shared [Post]
50
+
51
+ expect(Post.count).to eq(1)
52
+ expect(Post.pluck(:title)).to eq(['Json title'])
53
+ end
54
+ end
55
+
56
+ context "with a partially-dynamic value" do
57
+ around do |example|
58
+ load_shared_seeds('posts_partially_dynamic_value.yml', &example)
59
+ end
60
+
61
+ it "seeds the db with the full value" do
62
+ sprig_shared [
63
+ {
64
+ :class => Post,
65
+ :source => open('spec/fixtures/seeds/shared/posts_partially_dynamic_value.yml')
66
+ }
67
+ ]
68
+
69
+ expect(Post.count).to eq(1)
70
+ expect(Post.pluck(:title)).to eq(['Partially Dynamic Title'])
71
+ end
72
+ end
73
+
74
+ context "with a symlinked file" do
75
+ around do |example|
76
+ `ln -s ./spec/fixtures/seeds/shared/posts.yml ./spec/fixtures/db/seeds/shared/`
77
+ example.call
78
+ `rm ./spec/fixtures/db/seeds/shared/posts.yml`
79
+ end
80
+
81
+ it "seeds the db" do
82
+ sprig_shared [Post]
83
+
84
+ expect(Post.count).to eq(1)
85
+ expect(Post.pluck(:title)).to eq(['Yaml title'])
86
+ end
87
+ end
88
+
89
+ context "with a google spreadsheet" do
90
+ it "seeds the db", :vcr => { :cassette_name => 'google_spreadsheet_json_posts' } do
91
+ sprig_shared [
92
+ {
93
+ :class => Post,
94
+ :parser => Sprig::Parser::GoogleSpreadsheetJson,
95
+ :source => open('https://spreadsheets.google.com/feeds/list/0AjVLPMnHm86rdDVHQ2dCUS03RTN5ZUtVNzVOYVBwT0E/1/public/values?alt=json'),
96
+ }
97
+ ]
98
+
99
+ expect(Post.count).to eq(1)
100
+ expect(Post.pluck(:title)).to eq(['Google spreadsheet json title'])
101
+ end
102
+ end
103
+
104
+ context "with an invalid custom parser" do
105
+ around do |example|
106
+ load_shared_seeds('posts.yml', &example)
107
+ end
108
+
109
+ it "fails with an argument error" do
110
+ expect {
111
+ sprig_shared [
112
+ {
113
+ :class => Post,
114
+ :source => open('spec/fixtures/seeds/shared/posts.yml'),
115
+ :parser => Object # Not a valid parser
116
+ }
117
+ ]
118
+ }.to raise_error(ArgumentError, 'Parsers must define #parse.')
119
+ end
120
+ end
121
+
122
+ context "with a custom source" do
123
+ around do |example|
124
+ load_shared_seeds('legacy_posts.yml', &example)
125
+ end
126
+
127
+ it "seeds" do
128
+ sprig_shared [
129
+ {
130
+ :class => Post,
131
+ :source => open('spec/fixtures/seeds/shared/legacy_posts.yml')
132
+ }
133
+ ]
134
+
135
+ expect(Post.count).to eq(1)
136
+ expect(Post.pluck(:title)).to eq(['Legacy yaml title'])
137
+ end
138
+ end
139
+
140
+ context "with a custom source that cannot be parsed by native parsers" do
141
+ around do |example|
142
+ load_shared_seeds('posts.md', &example)
143
+ end
144
+
145
+ it "fails with an unparsable file error" do
146
+ expect {
147
+ sprig_shared [
148
+ {
149
+ :class => Post,
150
+ :source => open('spec/fixtures/seeds/shared/posts.md')
151
+ }
152
+ ]
153
+ }.to raise_error(Sprig::Source::ParserDeterminer::UnparsableFileError)
154
+ end
155
+ end
156
+
157
+ context "with an invalid custom source" do
158
+ it "fails with an argument error" do
159
+ expect {
160
+ sprig_shared [ { :class => Post, :source => 42 } ]
161
+ }.to raise_error(ArgumentError, 'Data sources must act like an IO.')
162
+ end
163
+ end
164
+
165
+ context "with multiple file relationships" do
166
+ around do |example|
167
+ load_shared_seeds('posts.yml', 'comments.yml', &example)
168
+ end
169
+
170
+ it "seeds the db" do
171
+ sprig_shared [Post, Comment]
172
+
173
+ expect(Post.count).to eq(1)
174
+ expect(Comment.count).to eq(1)
175
+ expect(Comment.first.post).to eq(Post.first)
176
+ end
177
+ end
178
+
179
+ context "with missing seed files" do
180
+ it "raises a missing file error" do
181
+ expect {
182
+ sprig_shared [Post]
183
+ }.to raise_error(Sprig::Source::SourceDeterminer::FileNotFoundError)
184
+ end
185
+ end
186
+
187
+ context "with a relationship to an undefined record" do
188
+ around do |example|
189
+ load_shared_seeds('posts.yml', 'posts_missing_dependency.yml', &example)
190
+ end
191
+
192
+ it "raises a helpful error message" do
193
+ expect {
194
+ sprig_shared [
195
+ {
196
+ :class => Post,
197
+ :source => open('spec/fixtures/seeds/shared/posts_missing_dependency.yml')
198
+ }
199
+ ]
200
+ }.to raise_error(
201
+ Sprig::DependencySorter::MissingDependencyError,
202
+ "Undefined reference to 'sprig_record(Comment, 42)'"
203
+ )
204
+ end
205
+ end
206
+
207
+ context "with a relationship to a record that didn't save" do
208
+ around do |example|
209
+ load_shared_seeds('invalid_users.yml', 'posts_missing_record.yml', &example)
210
+ end
211
+
212
+ it "does not error, but carries on with the seeding" do
213
+ expect {
214
+ sprig_shared [
215
+ {
216
+ :class => Post,
217
+ :source => open('spec/fixtures/seeds/shared/posts_missing_record.yml')
218
+ },
219
+ {
220
+ :class => User,
221
+ :source => open('spec/fixtures/seeds/shared/invalid_users.yml')
222
+ }
223
+ ]
224
+ }.to_not raise_error
225
+ end
226
+ end
227
+
228
+ context "with multiple files for a class" do
229
+ around do |example|
230
+ load_shared_seeds('posts.yml', 'legacy_posts.yml', &example)
231
+ end
232
+
233
+ it "seeds the db" do
234
+ sprig_shared [
235
+ Post,
236
+ {
237
+ :class => Post,
238
+ :source => open('spec/fixtures/seeds/shared/legacy_posts.yml')
239
+ }
240
+ ]
241
+
242
+ expect(Post.count).to eq(2)
243
+ expect(Post.pluck(:title)).to eq(['Yaml title', 'Legacy yaml title'])
244
+ end
245
+ end
246
+
247
+ context "with files defined as attributes" do
248
+ around do |example|
249
+ load_shared_seeds('posts_with_files.yml', &example)
250
+ end
251
+
252
+ it "seeds the db" do
253
+ sprig_shared [
254
+ {
255
+ :class => Post,
256
+ :source => open('spec/fixtures/seeds/shared/posts_with_files.yml')
257
+ }
258
+ ]
259
+
260
+ expect(Post.count).to eq(1)
261
+ expect(Post.pluck(:photo)).to eq(['cat.png'])
262
+ end
263
+ end
264
+
265
+ context "with has_and_belongs_to_many relationships" do
266
+ around do |example|
267
+ load_shared_seeds('posts_with_habtm.yml', 'tags.yml', &example)
268
+ end
269
+
270
+ it "saves the habtm relationships" do
271
+ sprig_shared [
272
+ Tag,
273
+ {
274
+ :class => Post,
275
+ :source => open('spec/fixtures/seeds/shared/posts_with_habtm.yml')
276
+ }
277
+ ]
278
+
279
+ expect(Post.first.tags.map(&:name)).to eq(['Botany', 'Biology'])
280
+ end
281
+ end
282
+
283
+ context "with cyclic dependencies" do
284
+ around do |example|
285
+ load_shared_seeds('comments.yml', 'posts_with_cyclic_dependencies.yml', &example)
286
+ end
287
+
288
+ it "raises an cyclic dependency error" do
289
+ expect {
290
+ sprig_shared [
291
+ {
292
+ :class => Post,
293
+ :source => open('spec/fixtures/seeds/shared/posts_with_cyclic_dependencies.yml')
294
+ },
295
+ Comment
296
+ ]
297
+ }.to raise_error(Sprig::DependencySorter::CircularDependencyError)
298
+ end
299
+ end
300
+
301
+ context "with a malformed directive" do
302
+ let(:expected_error_message) { "Sprig::Directive must be instantiated with a(n) #{Sprig.adapter_model_class} class or a Hash with :class defined" }
303
+
304
+ context "including a class that is not a subclass of AR" do
305
+ it "raises an argument error" do
306
+ expect {
307
+ sprig_shared [
308
+ Object
309
+ ]
310
+ }.to raise_error(ArgumentError, expected_error_message)
311
+ end
312
+ end
313
+
314
+ context "including a non-class, non-hash" do
315
+ it "raises an argument error" do
316
+ expect {
317
+ sprig_shared [
318
+ 42
319
+ ]
320
+ }.to raise_error(ArgumentError, expected_error_message)
321
+ end
322
+ end
323
+ end
324
+
325
+
326
+ context "with custom seed options" do
327
+ context "using delete_existing_by" do
328
+ around do |example|
329
+ load_shared_seeds('posts_delete_existing_by.yml', &example)
330
+ end
331
+
332
+ context "with an existing record" do
333
+ let!(:existing_match) do
334
+ Post.create(
335
+ :title => "Such Title",
336
+ :content => "Old Content")
337
+ end
338
+
339
+ let!(:existing_nonmatch) do
340
+ Post.create(
341
+ :title => "Wow Title",
342
+ :content => "Much Content")
343
+ end
344
+
345
+ it "replaces only the matching existing record" do
346
+ sprig_shared [
347
+ {
348
+ :class => Post,
349
+ :source => open("spec/fixtures/seeds/shared/posts_delete_existing_by.yml")
350
+ }
351
+ ]
352
+
353
+ expect(Post.count).to eq(2)
354
+
355
+ expect {
356
+ existing_match.reload
357
+ }.to raise_error(missing_record_error)
358
+
359
+ expect {
360
+ existing_nonmatch.reload
361
+ }.to_not raise_error
362
+ end
363
+ end
364
+ end
365
+
366
+ context "using find_existing_by" do
367
+ context "with a missing attribute" do
368
+ around do |example|
369
+ load_shared_seeds('posts_find_existing_by_missing.yml', &example)
370
+ end
371
+
372
+ it "raises a missing attribute error" do
373
+ expect {
374
+ sprig_shared [
375
+ {
376
+ :class => Post,
377
+ :source => open("spec/fixtures/seeds/shared/posts_find_existing_by_missing.yml")
378
+ }
379
+ ]
380
+ }.to raise_error(Sprig::Seed::AttributeCollection::AttributeNotFoundError, "Attribute 'unicorn' is not present.")
381
+ end
382
+ end
383
+
384
+ context "with a single attribute" do
385
+ around do |example|
386
+ load_shared_seeds('posts.yml', 'posts_find_existing_by_single.yml', &example)
387
+ end
388
+
389
+ context "with an existing record" do
390
+ let!(:existing) do
391
+ Post.create(
392
+ :title => "Existing title",
393
+ :content => "Existing content")
394
+ end
395
+
396
+ it "updates the existing record" do
397
+ sprig_shared [
398
+ {
399
+ :class => Post,
400
+ :source => open("spec/fixtures/seeds/shared/posts_find_existing_by_single.yml")
401
+ }
402
+ ]
403
+
404
+ expect(Post.count).to eq(1)
405
+ expect(existing.reload.content).to eq("Updated content")
406
+ end
407
+ end
408
+ end
409
+
410
+ context "with multiple attributes" do
411
+ around do |example|
412
+ load_shared_seeds('posts.yml', 'posts_find_existing_by_multiple.yml', &example)
413
+ end
414
+
415
+ context "with an existing record" do
416
+ let!(:existing) do
417
+ Post.create(
418
+ :title => "Existing title",
419
+ :content => "Existing content",
420
+ :published => false
421
+ )
422
+ end
423
+
424
+ it "updates the existing record" do
425
+ sprig_shared [
426
+ {
427
+ :class => Post,
428
+ :source => open("spec/fixtures/seeds/shared/posts_find_existing_by_multiple.yml")
429
+ }
430
+ ]
431
+
432
+ expect(Post.count).to eq(1)
433
+ expect(existing.reload.published).to eq(true)
434
+ end
435
+ end
436
+ end
437
+ end
438
+
439
+ context "defined within the directive" do
440
+ let!(:existing) do
441
+ Post.create(
442
+ :title => "Yaml title",
443
+ :content => "Existing content")
444
+ end
445
+
446
+ around do |example|
447
+ load_shared_seeds('posts.yml', &example)
448
+ end
449
+
450
+ it "respects the directive option" do
451
+ sprig_shared [
452
+ {
453
+ :class => Post,
454
+ :source => open("spec/fixtures/seeds/shared/posts.yml"),
455
+ :delete_existing_by => :title
456
+ }
457
+ ]
458
+
459
+ expect(Post.count).to eq(1)
460
+
461
+ expect {
462
+ existing.reload
463
+ }.to raise_error(missing_record_error)
464
+ end
465
+ end
466
+ end
467
+ end