mongo_mapper 0.15.1 → 0.15.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -269,4 +269,22 @@ describe "BelongsToProxy" do
269
269
  end.should_not raise_error
270
270
  end
271
271
  end
272
+
273
+ context "foreign_key=" do
274
+ it "should reset parent when foreign key is changed" do
275
+ post = @post_class.create!
276
+ comment = @comment_class.create!(post: post)
277
+ another_post = @post_class.create!
278
+
279
+ comment.post.should == post
280
+
281
+ comment.post_id = another_post.id
282
+
283
+ comment.post.should == another_post
284
+
285
+ comment.post_id = nil
286
+
287
+ comment.post.should == nil
288
+ end
289
+ end
272
290
  end
@@ -97,4 +97,32 @@ describe "OneEmbeddedProxy" do
97
97
  post.author.address.id.should_not be_nil
98
98
  end
99
99
 
100
+ it "should keep the reference to assigned document" do
101
+ @post_class.one(:author, :class => @author_class)
102
+ post = @post_class.new
103
+ new_author = @author_class.new
104
+ post.author = new_author
105
+ new_author.name = 'Frank'
106
+
107
+ post.author.name.should == 'Frank'
108
+ end
109
+
110
+ it "should update references for parent and root" do
111
+ @post_class.key(:author_name, String)
112
+ @post_class.one(:author, :class => @author_class)
113
+ @post_class.before_save do
114
+ self.author_name = author.name
115
+ end
116
+
117
+ author = @author_class.new
118
+ @post_class.create!(author: author)
119
+ author.save!
120
+
121
+ post = @post_class.create!(author: author)
122
+ post.author.name = 'Frank'
123
+ post.author.save!
124
+
125
+ post.author.name.should == 'Frank'
126
+ post.author_name.should == 'Frank'
127
+ end
100
128
  end
@@ -403,4 +403,14 @@ describe "OneProxy" do
403
403
  article.paper_id.should == @paper.id
404
404
  end
405
405
  end
406
- end
406
+
407
+ it "should keep the reference to assigned document" do
408
+ @post_class.one(:author, :class => @author_class)
409
+ post = @post_class.new
410
+ new_author = @author_class.new
411
+ post.author = new_author
412
+ new_author.name = 'Frank'
413
+
414
+ post.author.name.should == 'Frank'
415
+ end
416
+ end
@@ -280,6 +280,27 @@ describe "Dirty" do
280
280
  end
281
281
  end
282
282
 
283
+ context "Document having Array key with typecast option" do
284
+ before do
285
+ @author_id = BSON::ObjectId.new
286
+ @doc = Doc('Book') { key :author_ids, Array, typecast: "ObjectId" }
287
+ @doc.plugin MongoMapper::Plugins::Dirty
288
+ @book = @doc.create!(author_ids: [@author_id])
289
+ end
290
+
291
+ context "changed" do
292
+ it "should be empty if assigned the same array" do
293
+ @book.author_ids = [@author_id]
294
+ @book.changed.should be_empty
295
+ end
296
+
297
+ it "should be empty if assigned the same but before-typecasted array" do
298
+ @book.author_ids = [@author_id.to_s]
299
+ @book.changed.should be_empty
300
+ end
301
+ end
302
+ end
303
+
283
304
  context "Embedded documents" do
284
305
  before do
285
306
  @edoc = EDoc('Duck') { key :name, String }
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'DirtyWithCallbacks' do
4
+ it 'should update its changes/previous_changes before after_create/after_update callbacks' do
5
+ history = {}
6
+
7
+ document = Doc {
8
+ key :x, String
9
+
10
+ after_save {
11
+ history[:after_save] = {
12
+ changes: changes,
13
+ previous_changes: previous_changes,
14
+ }
15
+ }
16
+ after_create {
17
+ history[:after_create] = {
18
+ changes: changes,
19
+ previous_changes: previous_changes,
20
+ }
21
+ }
22
+ after_update {
23
+ history[:after_update] = {
24
+ changes: changes,
25
+ previous_changes: previous_changes,
26
+ }
27
+ }
28
+ }
29
+
30
+ d = document.new(x: 'hello')
31
+ d.save
32
+
33
+ history.should == {
34
+ after_save: {
35
+ changes: {},
36
+ previous_changes: {'x' => [nil, 'hello']},
37
+ },
38
+ after_create: {
39
+ changes: {},
40
+ previous_changes: {'x' => [nil, 'hello']},
41
+ },
42
+ }
43
+ history.clear
44
+
45
+ d.x = 'world'
46
+ d.save!
47
+
48
+ history.should == {
49
+ after_save: {
50
+ changes: {},
51
+ previous_changes: {'x' => ['hello', 'world']},
52
+ },
53
+ after_update: {
54
+ changes: {},
55
+ previous_changes: {'x' => ['hello', 'world']},
56
+ },
57
+ }
58
+ end
59
+ end
@@ -200,6 +200,19 @@ describe "Scopes" do
200
200
  Blog.scopes.keys.map(&:to_s).should =~ %w(by_slug by_title published)
201
201
  end
202
202
  end
203
+
204
+ context 'with predefined class method name' do
205
+ it 'should raise ArgumentError' do
206
+ bad_names = %i(private public protected allocate new name parent superclass reload)
207
+ bad_names.each do |bad_name|
208
+ -> {
209
+ Doc() do
210
+ scope bad_name, -> {}
211
+ end
212
+ }.should raise_error(ArgumentError, /You tried to define a scope named "#{bad_name}"/)
213
+ end
214
+ end
215
+ end
203
216
  end
204
217
 
205
218
  describe "with_scope" do
@@ -434,4 +447,79 @@ describe "Scopes" do
434
447
  @klass.unsent.sorted.all.should == [two_days_ago, one_day_ago]
435
448
  end
436
449
  end
450
+
451
+ describe "thread safety" do
452
+ before do
453
+ @klass = Doc do
454
+ key :name, String
455
+ end
456
+
457
+ @threads = []
458
+ end
459
+
460
+ after do
461
+ @threads.each do |thread|
462
+ thread.kill
463
+ end
464
+ end
465
+
466
+ def make_thread(&block)
467
+ Thread.new(&block).tap do |thread|
468
+ @threads << thread
469
+ end
470
+ end
471
+
472
+ def wait_for_threads!
473
+ @threads.each { |t| t.join }
474
+ end
475
+
476
+ it "should not taint another thread's active scopes" do
477
+ count_active_scopes = nil
478
+ second_thread_run = false
479
+
480
+ make_thread do
481
+ @klass.with_scope(name: 'foo') do
482
+ loop do
483
+ sleep Float::EPSILON
484
+ break if second_thread_run
485
+ end
486
+ end
487
+ end
488
+
489
+ make_thread do
490
+ count_active_scopes = @klass.active_scopes.length
491
+ second_thread_run = true
492
+ end
493
+
494
+ wait_for_threads!
495
+
496
+ count_active_scopes.should == 0
497
+ end
498
+
499
+ it "should not taint another thread's count method" do
500
+ @klass.create!(name: 'foo')
501
+ @klass.create!(name: 'bar')
502
+
503
+ klass_count = nil
504
+ second_thread_run = false
505
+
506
+ make_thread do
507
+ @klass.with_scope(name: 'foo') do
508
+ loop do
509
+ sleep Float::EPSILON
510
+ break if second_thread_run
511
+ end
512
+ end
513
+ end
514
+
515
+ make_thread do
516
+ klass_count = @klass.count
517
+ second_thread_run = true
518
+ end
519
+
520
+ wait_for_threads!
521
+
522
+ klass_count.should == 2
523
+ end
524
+ end
437
525
  end
@@ -95,5 +95,17 @@ describe "Proxy" do
95
95
  p = Proc.new {|x| x+1}
96
96
  @proxy.send(:collect, &p).should == [2,3]
97
97
  end
98
+
99
+ it "should not respond to private method" do
100
+ @proxy.reload # To load @proxy.target
101
+ @proxy.target.extend(Module.new do
102
+ private
103
+
104
+ def private_foo
105
+ end
106
+ end)
107
+
108
+ lambda { @proxy.private_foo }.should raise_error(NoMethodError, /private method `private_foo' called/)
109
+ end
98
110
  end
99
111
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongo_mapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.1
4
+ version: 0.15.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-10-03 00:00:00.000000000 Z
13
+ date: 2021-02-01 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: mongo
@@ -224,6 +224,7 @@ files:
224
224
  - spec/functional/callbacks_spec.rb
225
225
  - spec/functional/counter_cache_spec.rb
226
226
  - spec/functional/dirty_spec.rb
227
+ - spec/functional/dirty_with_callbacks_spec.rb
227
228
  - spec/functional/document_spec.rb
228
229
  - spec/functional/dumpable_spec.rb
229
230
  - spec/functional/dynamic_querying_spec.rb