activerecord-model-spaces 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,186 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'active_support/core_ext/class' # SchemaDumper needs this
4
+
5
+ require 'active_record/model_spaces/table_manager'
6
+
7
+ module ActiveRecord
8
+ module ModelSpaces
9
+
10
+ describe TableManager do
11
+
12
+ describe "initialize" do
13
+ it "should initialize with a model" do
14
+ m = double('model')
15
+ c = double('connection')
16
+ m.should_receive(:connection).and_return(c)
17
+ tm = TableManager.new(m)
18
+ tm.model.should == m
19
+ tm.connection.should == c
20
+ end
21
+
22
+ it "should initialize with a model name" do
23
+ c = double('connection')
24
+ ActiveRecord::ModelSpaces.should_receive(:connection).and_return(c)
25
+ tm = TableManager.new("ActiveRecord::ModelSpaces")
26
+ tm.model.should == ActiveRecord::ModelSpaces
27
+ tm.connection.should == c
28
+ end
29
+ end
30
+
31
+ def create_table_manager(model=nil)
32
+ model ||= double('model')
33
+ connection = double('connection')
34
+ model.stub(:connection).and_return(connection)
35
+ TableManager.new(model)
36
+ end
37
+
38
+ describe "create table" do
39
+ it "should extract the base_table schema, and use it to create a new table" do
40
+ tm = create_table_manager
41
+ tm.connection.should_receive(:table_exists?).with('bars')
42
+
43
+ tsc = double('table-schema-copier')
44
+ tm.should_receive(:get_table_schema_copier).with(tm.connection).and_return(tsc)
45
+
46
+ tsc.should_receive(:copy_table_schema).with(tm.connection, 'foos', 'bars')
47
+
48
+ tm.create_table('foos', 'bars')
49
+ end
50
+ end
51
+
52
+ describe "drop table" do
53
+ it "should drop the given table if it exists" do
54
+ tm = create_table_manager
55
+ tm.connection.should_receive(:table_exists?).with("foos").and_return(true)
56
+ tm.connection.should_receive(:execute).with("drop table foos")
57
+ tm.drop_table("foos")
58
+ end
59
+
60
+ it "should do nothing if the given table does not exist" do
61
+ tm = create_table_manager
62
+ tm.connection.should_receive(:table_exists?).with("foos").and_return(false)
63
+ tm.drop_table("foos")
64
+ end
65
+ end
66
+
67
+ describe "recreate table" do
68
+ it "should drop the table if it exists, and recreate it from the base table if the table_name is different from the base_table_name" do
69
+ tm = create_table_manager
70
+ tm.should_receive(:drop_table).with("bars")
71
+ tm.should_receive(:create_table).with("foos", "bars")
72
+ tm.recreate_table("foos", "bars")
73
+ end
74
+
75
+ it "should do nothing if the base_table_name is the same as the table_name" do
76
+ tm = create_table_manager
77
+ tm.recreate_table("foos", "foos")
78
+ end
79
+ end
80
+
81
+ describe "truncate table" do
82
+ it "should truncate the given table" do
83
+ tm = create_table_manager
84
+ tm.connection.should_receive(:execute).with("truncate table foos")
85
+ tm.truncate_table('foos')
86
+ end
87
+ end
88
+
89
+ describe "copy table" do
90
+ it "should copy data from the source to the target table if source and target are different" do
91
+ tm = create_table_manager
92
+ tm.connection.should_receive(:execute).with("insert into bars select * from foos")
93
+ tm.copy_table('foos', 'bars')
94
+ end
95
+
96
+ it "should do nothing if source and target are the same" do
97
+ tm = create_table_manager
98
+ tm.copy_table('foos', 'foos')
99
+ end
100
+ end
101
+
102
+ describe "get_table_schema_copier" do
103
+ it "should get a TableSchemaCopier specialised for the connection adapter, if available" do
104
+ c = double('connection')
105
+ c.stub(:adapter_name).and_return('MySQL')
106
+
107
+ tm = create_table_manager
108
+ tm.send(:get_table_schema_copier, c).should == MySQLTableSchemaCopier
109
+ end
110
+
111
+ it "should get a DefaultTableSchemaCopier if no specialised TableSchemaCopier available" do
112
+ c = double('connection')
113
+ c.stub(:adapter_name).and_return('Random')
114
+
115
+ tm = create_table_manager
116
+ tm.send(:get_table_schema_copier, c).should == DefaultTableSchemaCopier
117
+ end
118
+ end
119
+
120
+ describe MySQLTableSchemaCopier do
121
+
122
+ describe "copy_table_schema" do
123
+ it "should ask mysql for the create-table statement, modify it and execute the modified statement" do
124
+ c = double('connection')
125
+ c.should_receive(:select_rows).with("SHOW CREATE TABLE `foos`").and_return([["foos", "CREATE TABLE `foos` (blah)"]])
126
+ c.should_receive(:execute).with("CREATE TABLE `bars` (blah)")
127
+
128
+ MySQLTableSchemaCopier.copy_table_schema(c, "foos", "bars")
129
+ end
130
+ end
131
+
132
+ describe "table_schema" do
133
+ it "should ask mysql for the create-table statement for the table" do
134
+ c = double('connection')
135
+ c.should_receive(:select_rows).with("SHOW CREATE TABLE `foos`").and_return([["foos", "CREATE TABLE `foos` (blah)"]])
136
+ MySQLTableSchemaCopier.table_schema(c, "foos").should == "CREATE TABLE `foos` (blah)"
137
+ end
138
+ end
139
+
140
+ describe "change_table_name" do
141
+ it "should change the table name in the CREATE TABLE statement" do
142
+ MySQLTableSchemaCopier.change_table_name('foos', 'bars', "CREATE TABLE `foos` (blah)").should ==
143
+ "CREATE TABLE `bars` (blah)"
144
+ end
145
+ end
146
+
147
+ end
148
+
149
+ describe DefaultTableSchemaCopier do
150
+
151
+ describe "copy_table_schema" do
152
+ it "should extract ruby schema, modify and eval it to create a new table" do
153
+ c = double('connection')
154
+ c.should_receive(:instance_eval).with('create_table "bars" ()')
155
+
156
+ DefaultTableSchemaCopier.should_receive(:table_schema).with(c, "foos").and_return('create_table "foos" ()')
157
+
158
+ DefaultTableSchemaCopier.copy_table_schema(c, "foos", "bars")
159
+ end
160
+ end
161
+
162
+ describe "table_schema" do
163
+ it "should use the schema dumper to retrieve ruby code to create a table" do
164
+ c = double('connection')
165
+
166
+ sd = double('schema-dumper')
167
+ ActiveRecord::SchemaDumper.should_receive(:new).with(c).and_return(sd)
168
+
169
+ sd.should_receive(:table).with('foos', anything).and_return(StringIO.new('create_table "foos" ()'))
170
+
171
+ DefaultTableSchemaCopier.table_schema(c, "foos").should == 'create_table "foos" ()'
172
+ end
173
+ end
174
+
175
+ describe "change_table_name" do
176
+ it "should alter the provided schema generating code to change the table_name" do
177
+ tm = create_table_manager
178
+ DefaultTableSchemaCopier.change_table_name( "foos", "bars", 'create_table "foos" (blahblah)\nadd_index "foos" blahblah').should ==
179
+ 'create_table "bars" (blahblah)\nadd_index "bars" blahblah'
180
+ end
181
+ end
182
+
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,90 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'active_record/model_spaces/table_names'
4
+ module ActiveRecord
5
+ module ModelSpaces
6
+ describe TableNames do
7
+
8
+ describe "base_table_name" do
9
+ it "should underscore and pluralize the classname" do
10
+ TableNames.base_table_name("FooBar").should == "foo_bars"
11
+ end
12
+
13
+ it "should remove module names" do
14
+ TableNames.base_table_name(ModelSpaces).should == "model_spaces"
15
+ end
16
+ end
17
+
18
+ describe "model_space_table_name" do
19
+ it "should return base_table_name if no model-space or model-space-key given" do
20
+ TableNames.model_space_table_name(nil, nil, "foo_bars").should == "foo_bars"
21
+ end
22
+
23
+ it "should return base_table_name if an empty model-space and model-space-key given" do
24
+ TableNames.model_space_table_name("", "", "foo_bars").should == "foo_bars"
25
+ end
26
+
27
+ it "should prefix with model-space-name if given alone" do
28
+ TableNames.model_space_table_name("blarghl", nil, "foo_bars").should == "blarghl__foo_bars"
29
+ end
30
+
31
+ it "should prefix a model-space-name and model-space-key if bothgiven" do
32
+ TableNames.model_space_table_name("blarghl", "one", "foo_bars").should == "blarghl__one__foo_bars"
33
+ end
34
+
35
+ it "should raise an error if a model-space-key is given without a model-space-name" do
36
+
37
+ expect {
38
+ TableNames.model_space_table_name(nil, "one", "FooBar")
39
+ }.to raise_error /model_space_key cannot be non-empty if model_space_name is empty/
40
+
41
+ end
42
+ end
43
+
44
+ describe "table_name" do
45
+ it "should always suffix version provided if non-nil and >0" do
46
+ TableNames.table_name("blarghl", "one", "foo_bars", nil, nil).should == "blarghl__one__foo_bars"
47
+ TableNames.table_name("blarghl", "one", "foo_bars", nil, 1).should == "blarghl__one__foo_bars__1"
48
+ TableNames.table_name("blarghl", "one", "foo_bars", 0, nil).should == "blarghl__one__foo_bars"
49
+ TableNames.table_name("blarghl", "one", "foo_bars", 0, 1).should == "blarghl__one__foo_bars__1"
50
+
51
+ TableNames.table_name("blarghl", "one", "foo_bars", 1, 0).should == "blarghl__one__foo_bars"
52
+ TableNames.table_name("blarghl", "one", "foo_bars", 1, 1).should == "blarghl__one__foo_bars__1"
53
+ TableNames.table_name("blarghl", "one", "foo_bars", 1, 2).should == "blarghl__one__foo_bars__2"
54
+ TableNames.table_name("blarghl", "one", "foo_bars", 1, 3).should == "blarghl__one__foo_bars__3"
55
+
56
+ TableNames.table_name("blarghl", "one", "foo_bars", 2, 0).should == "blarghl__one__foo_bars"
57
+ TableNames.table_name("blarghl", "one", "foo_bars", 2, 1).should == "blarghl__one__foo_bars__1"
58
+ TableNames.table_name("blarghl", "one", "foo_bars", 2, 2).should == "blarghl__one__foo_bars__2"
59
+ TableNames.table_name("blarghl", "one", "foo_bars", 2, 3).should == "blarghl__one__foo_bars__3"
60
+ TableNames.table_name("blarghl", "one", "foo_bars", 2, 4).should == "blarghl__one__foo_bars__4"
61
+ end
62
+ end
63
+
64
+ describe "next_version" do
65
+ it "should return the next version" do
66
+ TableNames.next_version(nil, nil).should == 0
67
+ TableNames.next_version(nil, 0).should == 0
68
+ TableNames.next_version(nil, 1).should == 0
69
+
70
+ TableNames.next_version(0, nil).should == 0
71
+ TableNames.next_version(0, 0).should == 0
72
+ TableNames.next_version(0, 1).should == 0
73
+
74
+ TableNames.next_version(1, nil).should == 1
75
+ TableNames.next_version(1, 0).should == 1
76
+ TableNames.next_version(1, 1).should == 0
77
+ TableNames.next_version(1, 2).should == 1
78
+
79
+ TableNames.next_version(2, nil).should == 1
80
+ TableNames.next_version(2, 0).should == 1
81
+ TableNames.next_version(2, 1).should == 2
82
+ TableNames.next_version(2, 2).should == 0
83
+ TableNames.next_version(2, 3).should == 1
84
+ end
85
+ end
86
+
87
+
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,106 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'active_record'
4
+ require 'active_record/model_spaces/util'
5
+
6
+ module ActiveRecord
7
+ module ModelSpaces
8
+
9
+ describe Util do
10
+
11
+ describe "name_from_model" do
12
+ it "should stringify the model" do
13
+ m = double('model')
14
+ mk = double('model-key')
15
+ m.should_receive(:to_s).and_return(mk)
16
+ Util.name_from_model(m).should == mk
17
+ end
18
+
19
+ end
20
+
21
+ describe "model_from_name" do
22
+ it "should return the model class from the classname" do
23
+ Util.model_from_name("ActiveRecord::ModelSpaces").should == ActiveRecord::ModelSpaces
24
+ end
25
+
26
+ it "should do nothing if given a model class" do
27
+ Util.model_from_name(ActiveRecord::ModelSpaces).should == ActiveRecord::ModelSpaces
28
+ end
29
+ end
30
+
31
+ describe "require_for_classname" do
32
+ it "should require a file based on the classname then eval the classname to get the class" do
33
+ Kernel.should_receive(:require).with('active_record/model_spaces/foo_table_schema_copier')
34
+ klass = double('the-class')
35
+ Kernel.should_receive(:eval).with("ActiveRecord::ModelSpaces::FooTableSchemaCopier").and_return(klass)
36
+ Util.require_for_classname("ActiveRecord::ModelSpaces::FooTableSchemaCopier").should == klass
37
+ end
38
+
39
+ it "should return false in the case of any error" do
40
+ Kernel.should_receive(:require).with('active_record/model_spaces/foo_table_schema_copier').and_return{raise "boo"}
41
+ Util.require_for_classname("ActiveRecord::ModelSpaces::FooTableSchemaCopier").should == false
42
+ end
43
+ end
44
+
45
+ describe "class_for_classname" do
46
+ it "should eval a classname to get a class" do
47
+ klass = double('the-class')
48
+ Kernel.should_receive(:eval).with("ActiveRecord::ModelSpaces::FooTableSchemaCopier").and_return(klass)
49
+
50
+ Util.class_for_classname("ActiveRecord::ModelSpaces::FooTableSchemaCopier").should == klass
51
+ end
52
+
53
+ it "should return false in the case of any error" do
54
+ Kernel.should_receive(:eval).with("ActiveRecord::ModelSpaces::FooTableSchemaCopier").and_return{raise "boo"}
55
+ Util.class_for_classname("ActiveRecord::ModelSpaces::FooTableSchemaCopier").should == false
56
+ end
57
+ end
58
+
59
+ describe "class_from_classname" do
60
+ it "should try class_for_classname then require_for_classname to find a class" do
61
+ klass = double('the-class')
62
+
63
+ Kernel.should_receive(:eval).with("ActiveRecord::ModelSpaces::FooTableSchemaCopier").and_return{raise "boo"}
64
+
65
+ Kernel.should_receive(:require).with('active_record/model_spaces/foo_table_schema_copier').and_return do
66
+ Kernel.rspec_reset
67
+ Kernel.should_receive(:eval).with("ActiveRecord::ModelSpaces::FooTableSchemaCopier").and_return(klass)
68
+ end
69
+
70
+ Util.class_from_classname("ActiveRecord::ModelSpaces::FooTableSchemaCopier").should == klass
71
+ end
72
+ end
73
+
74
+ describe "all_model_superclasses" do
75
+ it "should return an ordered list of all model superclasses of a class" do
76
+ c1 = Class.new(ActiveRecord::Base)
77
+ c2 = Class.new(c1)
78
+ c3 = Class.new(c2)
79
+
80
+ Util.all_model_superclasses(c3).should == [c3,c2,c1]
81
+ end
82
+ end
83
+
84
+ describe "is_active_record_model?" do
85
+ it "should return true for direct or indirect subclasses of ActiveRecord::Base" do
86
+ c1 = Class.new(ActiveRecord::Base)
87
+ Util.is_active_record_model?(c1).should == true
88
+
89
+ c2 = Class.new(c1)
90
+ Util.is_active_record_model?(c2).should ==true
91
+ end
92
+
93
+ it "should return false for non-subclasses of ActiveRecord::Base" do
94
+ Util.is_active_record_model?(ActiveRecord::Base).should == false
95
+
96
+ c1 = Class.new
97
+ Util.is_active_record_model?(c1).should == false
98
+
99
+ c2 = Class.new
100
+ Util.is_active_record_model?(c2).should == false
101
+ end
102
+ end
103
+
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,116 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module ActiveRecord
4
+ describe ModelSpaces do
5
+
6
+ describe "with_context" do
7
+ it "should pass with_context calls to the registry" do
8
+ ModelSpaces::REGISTRY.should_receive(:with_context).and_return do |model_space_name, model_space_key, &block|
9
+ model_space_name.should == :foo_space
10
+ model_space_key.should == :one
11
+ block.call
12
+ end
13
+
14
+ ModelSpaces.with_context(:foo_space, :one) do
15
+ :result
16
+ end.should == :result
17
+ end
18
+ end
19
+
20
+ describe "active_key" do
21
+ it "should pass active_key calls to the registry" do
22
+ ModelSpaces::REGISTRY.should_receive(:active_key).with(:foo_space)
23
+ ModelSpaces.active_key(:foo_space)
24
+ end
25
+ end
26
+
27
+ describe "kill_context" do
28
+ it "should pass kill_context calls to the registry" do
29
+ ModelSpaces::REGISTRY.should_receive(:kill_context).with(:foo_space, :one)
30
+ ModelSpaces.kill_context(:foo_space, :one)
31
+ end
32
+ end
33
+
34
+ describe "enforce_context" do
35
+ it "should pass enforce_contrext calls to the registry" do
36
+ ec = double('enforce-context')
37
+ ModelSpaces::REGISTRY.should_receive(:enforce_context).and_return(ec)
38
+ ModelSpaces.enforce_context.should == ec
39
+ end
40
+ end
41
+
42
+ describe "set_enforce_context" do
43
+ it "should pass set_enforce_context calls to the registry" do
44
+ ec = double('enforce-context')
45
+ ModelSpaces::REGISTRY.should_receive(:set_enforce_context).with(ec)
46
+ ModelSpaces.set_enforce_context(ec)
47
+ end
48
+ end
49
+
50
+ def create_model_spaces_class
51
+ klass = Class.new
52
+ klass.class_eval do
53
+ include ActiveRecord::ModelSpaces
54
+ end
55
+ klass
56
+ end
57
+
58
+ it "should pass set_table_name calls to the registry" do
59
+ klass = create_model_spaces_class
60
+ ModelSpaces::REGISTRY.should_receive(:set_base_table_name).with(klass, "random_models")
61
+ klass.set_table_name("random_models")
62
+ end
63
+
64
+ it "should pass table_name= calls to the registry" do
65
+ klass = create_model_spaces_class
66
+ ModelSpaces::REGISTRY.should_receive(:set_base_table_name).with(klass, "random_models")
67
+ klass.table_name = "random_models"
68
+ end
69
+
70
+ it "should pass in_model_space calls to the registry" do
71
+ klass = create_model_spaces_class
72
+ ModelSpaces::REGISTRY.should_receive(:register_model).with(klass, :foo_space, {})
73
+ klass.in_model_space :foo_space
74
+ end
75
+
76
+ it "should pass table_name calls to the registry" do
77
+ klass = create_model_spaces_class
78
+ ModelSpaces::REGISTRY.should_receive(:table_name).with(klass).and_return("foos")
79
+ klass.table_name.should == "foos"
80
+ end
81
+
82
+ it "should pass current_table_name calls to the registry" do
83
+ klass = create_model_spaces_class
84
+ ModelSpaces::REGISTRY.should_receive(:current_table_name).with(klass).and_return("foos")
85
+ klass.current_table_name.should == "foos"
86
+ end
87
+
88
+ it "should pass working_table_name calls to the registry" do
89
+ klass = create_model_spaces_class
90
+ ModelSpaces::REGISTRY.should_receive(:working_table_name).with(klass).and_return("foos")
91
+ klass.working_table_name.should == "foos"
92
+ end
93
+
94
+ it "should pass new_version calls to the registry" do
95
+ klass = create_model_spaces_class
96
+ ModelSpaces::REGISTRY.should_receive(:new_version).with(klass).and_return do |k, &proc|
97
+ proc.call.should == :blah
98
+ end
99
+ klass.new_version{:blah}
100
+ end
101
+
102
+ it "should pass updated_version calls to the registry" do
103
+ klass = create_model_spaces_class
104
+ ModelSpaces::REGISTRY.should_receive(:updated_version).with(klass).and_return do |k, &proc|
105
+ proc.call.should == :blah
106
+ end
107
+ klass.updated_version{:blah}
108
+ end
109
+
110
+ it "should pass hoover calls to the registry" do
111
+ klass = create_model_spaces_class
112
+ ModelSpaces::REGISTRY.should_receive(:hoover).with(klass).and_return(true)
113
+ klass.hoover
114
+ end
115
+ end
116
+ end