undestroy 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ require "undestroy/version"
2
+ require "undestroy/config"
3
+ require "undestroy/transfer"
4
+ require "undestroy/archive"
5
+ require "undestroy/binding"
6
+
7
+ module Undestroy
8
+ end
9
+
10
+
@@ -0,0 +1,42 @@
1
+ module Undestroy::Test::Fixtures::ActiveRecordModels
2
+
3
+ class Blog < Undestroy::Test::ARMain
4
+ undestroy
5
+ has_many :posts, :dependent => :destroy
6
+ end
7
+
8
+ class Post < Undestroy::Test::ARMain
9
+ undestroy
10
+ belongs_to :blog
11
+ end
12
+
13
+ def self.add_blog_tables(model)
14
+ model.connection.create_table :blogs do |t|
15
+ t.string :name
16
+ end
17
+ model.connection.create_table :archive_blogs do |t|
18
+ t.string :name
19
+ t.datetime :deleted_at
20
+ end
21
+
22
+ model.connection.create_table :posts do |t|
23
+ t.integer :blog_id
24
+ t.string :title
25
+ t.text :body
26
+ end
27
+ model.connection.create_table :archive_posts do |t|
28
+ t.datetime :deleted_at
29
+ t.integer :blog_id
30
+ t.string :title
31
+ t.text :body
32
+ end
33
+ end
34
+
35
+ def self.remove_blog_tables(model)
36
+ model.connection.drop_table :blogs
37
+ model.connection.drop_table :archive_blogs
38
+ model.connection.drop_table :posts
39
+ model.connection.drop_table :archive_posts
40
+ end
41
+
42
+ end
@@ -0,0 +1,41 @@
1
+
2
+ class Undestroy::Test::Fixtures::ARFixture
3
+ attr_accessor :attributes
4
+ attr_reader :saved
5
+
6
+ alias :saved? :saved
7
+
8
+ def initialize(attributes={})
9
+ @saved = false
10
+ self.attributes = attributes.dup
11
+ self.attributes.delete(:id)
12
+ end
13
+
14
+ def [](key)
15
+ self.attributes[key.to_sym]
16
+ end
17
+
18
+ def []=(key, val)
19
+ self.attributes[key.to_sym] = val
20
+ end
21
+
22
+ # Method missing won't catch this one
23
+ def id
24
+ self.attributes[:id]
25
+ end
26
+
27
+ def save
28
+ @saved = true
29
+ end
30
+
31
+ # Shortcut to build an instance for testing purposes.
32
+ def self.construct(attributes={})
33
+ self.new.tap do |fixture|
34
+ attributes.each do |field, value|
35
+ fixture[field] = value
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+
@@ -0,0 +1,21 @@
1
+
2
+ class Undestroy::Test::Fixtures::Archive
3
+ def initialize(args)
4
+ @@data[:args] = args
5
+ end
6
+
7
+ def run
8
+ @@data[:calls] << [:run]
9
+ end
10
+
11
+ def self.data
12
+ @@data
13
+ end
14
+
15
+ def self.reset
16
+ @@data = { :calls => [] }
17
+ end
18
+ end
19
+
20
+ Undestroy::Test::Fixtures::Archive.reset
21
+
@@ -1,2 +1,43 @@
1
- require 'assert'
1
+ require 'undestroy'
2
+
3
+ ActiveRecord::Base.configurations = {
4
+ 'main' => {
5
+ :adapter => 'sqlite3',
6
+ :database => 'tmp/main.db'
7
+ },
8
+ 'alt' => {
9
+ :adapter => 'sqlite3',
10
+ :database => 'tmp/alt.db'
11
+ },
12
+ }
13
+
14
+ module Undestroy::Test
15
+
16
+ class Base < Assert::Context
17
+
18
+ teardown_once do
19
+ `rm -f tmp/*.db`
20
+ end
21
+
22
+ end
23
+
24
+ ActiveRecord::Base.establish_connection 'main'
25
+ class ARMain < ActiveRecord::Base
26
+ self.abstract_class = true
27
+ end
28
+
29
+ class ARAlt < ActiveRecord::Base
30
+ self.abstract_class = true
31
+ establish_connection 'alt'
32
+ end
33
+
34
+ module Integration
35
+ end
36
+
37
+ module Fixtures
38
+ autoload :ActiveRecordModels, 'test/fixtures/active_record_models'
39
+ autoload :ARFixture, 'test/fixtures/ar'
40
+ autoload :Archive, 'test/fixtures/archive'
41
+ end
42
+ end
2
43
 
@@ -0,0 +1,180 @@
1
+ require 'assert'
2
+
3
+ module Undestroy::Test::Integration::ActiveRecordTest
4
+
5
+ class Base < Undestroy::Test::Base
6
+ desc 'ActiveRecord integration'
7
+
8
+ setup do
9
+ @ar = Undestroy::Test::ARMain
10
+ @ar_alt = Undestroy::Test::ARAlt
11
+ end
12
+
13
+ end
14
+
15
+ class ActiveRecordExtension < Base
16
+ desc 'extensions'
17
+
18
+ should "add extensions to AR" do
19
+ assert_respond_to :undestroy_model_binding, ActiveRecord::Base
20
+ end
21
+ end
22
+
23
+ class BasicModelWithoutUndestroy < Base
24
+ desc 'basic model without Undestroy'
25
+
26
+ setup do
27
+ @ar.connection.create_table :basic_model_table do |t|
28
+ t.string :name
29
+ end
30
+ @model = Class.new(@ar)
31
+ @model.table_name = 'basic_model_table'
32
+ end
33
+
34
+ teardown do
35
+ @ar.connection.drop_table :basic_model_table
36
+ end
37
+
38
+ should "successfully traverse the model lifecycle" do
39
+ record = @model.create!(:name => 'bar')
40
+ assert @model.first
41
+ assert_not_raises { record.destroy }
42
+ end
43
+ end
44
+
45
+ class BasicModel < Base
46
+ desc 'basic model with Undestroy'
47
+
48
+ setup do
49
+ @ar.connection.create_table :basic_model_table do |t|
50
+ t.string :name
51
+ end
52
+ @ar.connection.create_table :archive_basic_model_table do |t|
53
+ t.string :name
54
+ t.datetime :deleted_at
55
+ end
56
+ @model = Class.new(@ar)
57
+ @model.table_name = 'basic_model_table'
58
+ end
59
+
60
+ teardown do
61
+ @ar.connection.drop_table :basic_model_table
62
+ @ar.connection.drop_table :archive_basic_model_table
63
+ end
64
+
65
+ should "create an archive record on destroy" do
66
+ @model.undestroy
67
+ target_class = @model.undestroy_model_binding.config.target_class
68
+
69
+ @model.create(:name => "foo")
70
+ original = @model.first
71
+ original.destroy
72
+ archive = target_class.first
73
+
74
+ assert original
75
+ assert archive
76
+ assert_equal original.id, archive.id
77
+ assert_equal 'foo', archive.name
78
+ assert_kind_of Time, archive.deleted_at
79
+ assert (Time.now - archive.deleted_at) < 1.second
80
+ assert_equal 0, @model.all.size
81
+ end
82
+ end
83
+
84
+ class BasicModelWithDifferentBase < Base
85
+ desc 'basic model with Undestroy and alternate abstract class'
86
+
87
+ setup do
88
+ @ar.connection.create_table :basic_model_table do |t|
89
+ t.string :name
90
+ end
91
+ @ar_alt.connection.create_table :archive_basic_model_table do |t|
92
+ t.string :name
93
+ t.datetime :deleted_at
94
+ end
95
+ @model = Class.new(@ar)
96
+ @model.table_name = 'basic_model_table'
97
+
98
+ @model.undestroy :abstract_class => @ar_alt
99
+ @target_class = @model.undestroy_model_binding.config.target_class
100
+ end
101
+
102
+ teardown do
103
+ @ar.connection.drop_table :basic_model_table
104
+ @ar_alt.connection.drop_table :archive_basic_model_table
105
+ end
106
+
107
+ should "create an archive record on destroy" do
108
+ @model.create!(:name => "bar")
109
+ original = @model.first
110
+ original.destroy
111
+ archive = @target_class.first
112
+
113
+ assert_not @model.first
114
+ assert original
115
+ assert archive
116
+ assert_equal original.id, archive.id
117
+ assert_equal 'bar', archive.name
118
+ assert_kind_of Time, archive.deleted_at
119
+ assert (Time.now - archive.deleted_at) < 1.second
120
+ assert_equal 1, @target_class.all.size
121
+ end
122
+ end
123
+
124
+ class DependentDestroy < Base
125
+ desc 'model with dependent undestroy enabled models'
126
+
127
+ setup do
128
+ @fixtures = Undestroy::Test::Fixtures::ActiveRecordModels
129
+
130
+ @blog = @fixtures::Blog
131
+ @post = @fixtures::Post
132
+ @fixtures.add_blog_tables(@blog)
133
+
134
+ @archive_blog = @blog.undestroy_model_binding.config.target_class
135
+ @archive_post = @post.undestroy_model_binding.config.target_class
136
+ end
137
+
138
+ teardown do
139
+ @fixtures.remove_blog_tables(@blog)
140
+ end
141
+
142
+ should "archive orphan blog" do
143
+ blog = @blog.create!(:name => "Foo Blog")
144
+ assert @blog.first
145
+ blog.destroy
146
+ assert_not @blog.first
147
+ assert @archive_blog.first
148
+ assert_equal "Foo Blog", @archive_blog.first.name
149
+ end
150
+
151
+ should "archive post" do
152
+ blog = @blog.create!(:name => "Bar Blog")
153
+ post = @post.create!(:title => "Foo Post", :body => "text", :blog => blog)
154
+ assert blog and post
155
+ post.destroy
156
+ archive = @archive_post.first
157
+
158
+ assert_not @post.first
159
+ assert archive
160
+ assert_equal post.id, archive.id
161
+ assert_equal "text", archive.body
162
+ assert_equal "Foo Post", archive.title
163
+ assert_equal blog.id, archive.blog_id
164
+ end
165
+
166
+ should "remove all posts and archive them when the blog is destroyed" do
167
+ blog = @blog.create!(:name => "My Verbose Blog")
168
+ posts = (1..10).collect do |i|
169
+ @post.create!(:title => "Article #{i}", :body => "Some text", :blog => blog)
170
+ end
171
+ blog.destroy
172
+
173
+ assert_equal 0, @blog.all.size
174
+ assert_equal 0, @post.all.size
175
+ assert_equal 1, @archive_blog.all.size
176
+ assert_equal 10, @archive_post.all.size
177
+ end
178
+ end
179
+
180
+ end
@@ -0,0 +1,115 @@
1
+ require 'assert'
2
+
3
+ module Undestroy::Archive::Test
4
+ class Base < Undestroy::Test::Base
5
+ subject { Undestroy::Archive }
6
+ desc 'Undestroy::Archive class'
7
+
8
+ setup do
9
+ @default_init = {
10
+ :source => Undestroy::Test::Fixtures::ARFixture.construct(:id => 1, :name => "Foo"),
11
+ :config => Undestroy::Config.new
12
+ }
13
+ end
14
+
15
+ def archive_instance(args={})
16
+ Undestroy::Archive.new(@default_init.merge(args))
17
+ end
18
+ end
19
+
20
+ class BasicInstance < Base
21
+ subject { archive_instance }
22
+ desc 'basic instance'
23
+
24
+ should have_accessors :source, :config, :transfer
25
+ end
26
+
27
+ class InitMethod < Base
28
+ desc 'initialize method'
29
+
30
+ should "require :source and :config options in hash argument" do
31
+ assert_raises(ArgumentError) { subject.new }
32
+ assert_raises(ArgumentError) { subject.new :source => nil }
33
+ assert_raises(ArgumentError) { subject.new :config => nil }
34
+ end
35
+
36
+ should "set the source to source attr" do
37
+ obj = archive_instance :source => "foo"
38
+ assert_equal "foo", obj.source
39
+ end
40
+
41
+ should "set the config to config attr" do
42
+ obj = archive_instance :config => "foo"
43
+ assert_equal "foo", obj.config
44
+ end
45
+
46
+ should "set optional :transfer to transfer attr" do
47
+ obj = archive_instance :transfer => "foo"
48
+ assert_equal "foo", obj.transfer
49
+ end
50
+ end
51
+
52
+ class TransferMethod < BasicInstance
53
+ desc 'transfer method'
54
+
55
+ setup do
56
+ @archive = subject
57
+ @archive.config.target_class = Undestroy::Test::Fixtures::ARFixture
58
+ end
59
+
60
+ should "return instance of config.internals[:transfer]" do
61
+ assert_instance_of @archive.config.internals[:transfer], @archive.transfer
62
+ end
63
+
64
+ should "cache the created instance" do
65
+ assert_equal @archive.transfer.object_id, @archive.transfer.object_id
66
+ end
67
+
68
+ should "set fields on instance to config.fields.merge(source.attributes) with evaled procs" do
69
+ target = @archive.transfer.target
70
+ assert_instance_of @archive.config.target_class, @archive.transfer.target
71
+ assert_equal 1, target.attributes[:id]
72
+ assert_equal "Foo", target.attributes[:name]
73
+ assert_instance_of Time, target.attributes[:deleted_at]
74
+ end
75
+
76
+ should "eval lambdas with source instance as argument" do
77
+ val = nil
78
+ @archive.config.fields[:test] = proc { |arg| val = arg; "FOO" }
79
+ target = @archive.transfer.target
80
+ assert_equal @archive.source, val
81
+ assert_equal "FOO", target.attributes[:test]
82
+ end
83
+ end
84
+
85
+ class RunMethod < Base
86
+ desc 'run method'
87
+
88
+ should "exist" do
89
+ assert_respond_to :run, archive_instance
90
+ end
91
+
92
+ should "call run on the transfer model" do
93
+ foo = Class.new do
94
+ @@called = false
95
+ def initialize(options={})
96
+ end
97
+
98
+ def run
99
+ @@called = true
100
+ end
101
+
102
+ def self.called
103
+ @@called
104
+ end
105
+ end
106
+
107
+ archive = archive_instance(:transfer => foo.new)
108
+
109
+ assert !foo.called
110
+ archive.run
111
+ assert foo.called
112
+ end
113
+ end
114
+ end
115
+