rails-erd 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -23,29 +23,56 @@ class DomainTest < ActiveSupport::TestCase
23
23
  assert_nil Domain.generate.name
24
24
  end
25
25
 
26
- test "inspect should display relationships" do
26
+ test "inspect should display object id only" do
27
27
  create_model "Foo", :bar => :references do
28
28
  belongs_to :bar
29
29
  end
30
30
  create_model "Bar"
31
- assert_match %r{#<RailsERD::Domain:.* \{Bar => Foo\}>}, Domain.generate.inspect
31
+ assert_match %r{#<RailsERD::Domain:.*>}, Domain.generate.inspect
32
32
  end
33
33
 
34
34
  # Entity processing ========================================================
35
- test "entity_for should return associated entity for given model" do
35
+ test "entity_by_name should return associated entity for given name" do
36
36
  create_model "Foo"
37
- assert_equal Foo, Domain.generate.entity_for(Foo).model
37
+ assert_equal Foo, Domain.generate.entity_by_name("Foo").model
38
38
  end
39
39
 
40
40
  test "entities should return domain entities" do
41
41
  create_models "Foo", "Bar"
42
- assert_equal [Entity] * 2, Domain.generate.entities.collect(&:class)
42
+ assert_equal [Domain::Entity] * 2, Domain.generate.entities.collect(&:class)
43
43
  end
44
44
 
45
45
  test "entities should return all domain entities sorted by name" do
46
46
  create_models "Foo", "Bar", "Baz", "Qux"
47
47
  assert_equal [Bar, Baz, Foo, Qux], Domain.generate.entities.collect(&:model)
48
48
  end
49
+
50
+ test "entities should include abstract entities" do
51
+ create_model "Stronghold" do
52
+ has_many :cannons, :as => :defensible
53
+ end
54
+ assert_equal ["Defensible", "Stronghold"], Domain.generate.entities.collect(&:name)
55
+ end
56
+
57
+ test "entities should include abstract entities only once" do
58
+ create_model "Stronghold" do
59
+ has_many :cannons, :as => :defensible
60
+ end
61
+ create_model "Galleon" do
62
+ has_many :cannons, :as => :defensible
63
+ end
64
+ assert_equal ["Defensible", "Galleon", "Stronghold"], Domain.generate.entities.collect(&:name)
65
+ end
66
+
67
+ test "entities should omit abstract models" do
68
+ Object.const_set :Foo, Class.new(ActiveRecord::Base) { self.abstract_class = true }
69
+ create_model "Bar", Foo do
70
+ set_table_name "bars"
71
+ end
72
+ create_table "foos", {}, true
73
+ create_table "bars", {}, true
74
+ assert_equal ["Bar"], Domain.generate.entities.collect(&:name)
75
+ end
49
76
 
50
77
  # Relationship processing ==================================================
51
78
  test "relationships should return empty array for empty domain" do
@@ -61,7 +88,7 @@ class DomainTest < ActiveSupport::TestCase
61
88
  create_model "Bar", :baz => :references do
62
89
  belongs_to :baz
63
90
  end
64
- assert_equal [Relationship] * 3, Domain.generate.relationships.collect(&:class)
91
+ assert_equal [Domain::Relationship] * 3, Domain.generate.relationships.collect(&:class)
65
92
  end
66
93
 
67
94
  test "relationships should count mutual relationship as one" do
@@ -71,7 +98,23 @@ class DomainTest < ActiveSupport::TestCase
71
98
  create_model "Bar" do
72
99
  has_many :foos
73
100
  end
74
- assert_equal [Relationship], Domain.generate.relationships.collect(&:class)
101
+ assert_equal [Domain::Relationship], Domain.generate.relationships.collect(&:class)
102
+ end
103
+
104
+ test "relationships should count mutual indirect relationship as one" do
105
+ create_model "Wizard" do
106
+ has_many :spell_masteries
107
+ has_many :spells, :through => :spell_masteries
108
+ end
109
+ create_model "Spell" do
110
+ has_many :spell_masteries
111
+ has_many :wizards, :through => :spell_masteries
112
+ end
113
+ create_model "SpellMastery", :wizard => :references, :spell => :references do
114
+ belongs_to :wizard
115
+ belongs_to :spell
116
+ end
117
+ assert_equal [Domain::Relationship], Domain.generate.relationships.select(&:indirect?).collect(&:class)
75
118
  end
76
119
 
77
120
  test "relationships should count relationship between same models with distinct foreign key seperately" do
@@ -81,9 +124,62 @@ class DomainTest < ActiveSupport::TestCase
81
124
  create_model "Bar" do
82
125
  has_many :foos, :foreign_key => :special_bar_id
83
126
  end
84
- assert_equal [Relationship] * 2, Domain.generate.relationships.collect(&:class)
127
+ assert_equal [Domain::Relationship] * 2, Domain.generate.relationships.collect(&:class)
128
+ end
129
+
130
+ # Specialization processing ================================================
131
+ test "specializations should return empty array for empty domain" do
132
+ assert_equal [], Domain.generate.specializations
133
+ end
134
+
135
+ test "specializations should return empty array for domain without single table inheritance" do
136
+ create_simple_domain
137
+ assert_equal [], Domain.generate.specializations
138
+ end
139
+
140
+ test "specializations should return specializations in domain model" do
141
+ create_specialization
142
+ assert_equal [Domain::Specialization], Domain.generate.specializations.collect(&:class)
143
+ end
144
+
145
+ test "specializations should return specializations of specializations in domain model" do
146
+ create_specialization
147
+ Object.const_set :BelgianBeer, Class.new(Beer)
148
+ assert_equal [Domain::Specialization] * 2, Domain.generate.specializations.collect(&:class)
149
+ end
150
+
151
+ test "specializations should return generalizations in domain model" do
152
+ create_model "Post" do
153
+ has_many :assets, :as => :attachable
154
+ end
155
+ create_model "Asset", :attachable => :references do
156
+ belongs_to :attachable, :polymorphic => true
157
+ end
158
+ assert_equal [Domain::Specialization], Domain.generate.specializations.collect(&:class)
159
+ end
160
+
161
+ test "specializations should return generalizations and specializations in domain model" do
162
+ create_model "Content", :type => :string do
163
+ has_many :assets, :as => :attachable
164
+ end
165
+ Object.const_set :Post, Class.new(Content)
166
+ create_model "Asset", :attachable => :references do
167
+ belongs_to :attachable, :polymorphic => true
168
+ end
169
+ assert_equal [Domain::Specialization] * 2, Domain.generate.specializations.collect(&:class)
85
170
  end
86
171
 
172
+ # test "generalizations should ..." do
173
+ # # TODO
174
+ # create_model "Post" do
175
+ # has_many :assets, :as => :attachable
176
+ # end
177
+ # create_model "Asset", :attachable => :references do
178
+ # belongs_to :attachable, :polymorphic => true
179
+ # end
180
+ # assert_equal [], Domain.generate.relationships
181
+ # end
182
+
87
183
  # Erroneous associations ===================================================
88
184
  test "relationships should omit bad has_many associations" do
89
185
  create_model "Foo" do
@@ -128,6 +224,19 @@ class DomainTest < ActiveSupport::TestCase
128
224
  assert_match /model Bar exists, but is not included in domain/, output
129
225
  end
130
226
 
227
+ test "relationships should output a warning when an association to a non existent generalization is encountere" do
228
+ create_model "Foo" do
229
+ has_many :bars, :as => :foo
230
+ end
231
+ create_model "Bar", :foobar => :references do
232
+ belongs_to :foo_bar, :polymorphic => true
233
+ end
234
+ output = collect_stdout do
235
+ Domain.generate.relationships
236
+ end
237
+ assert_match /polymorphic interface FooBar does not exist/, output
238
+ end
239
+
131
240
  test "relationships should not warn when a bad association is encountered if warnings are disabled" do
132
241
  create_model "Foo" do
133
242
  has_many :flabs
@@ -137,4 +246,18 @@ class DomainTest < ActiveSupport::TestCase
137
246
  end
138
247
  assert_equal "", output
139
248
  end
249
+
250
+ # Erroneous models =========================================================
251
+ test "entities should omit bad models" do
252
+ Object.const_set :Foo, Class.new(ActiveRecord::Base)
253
+ assert_equal [], Domain.generate(:warn => false).entities
254
+ end
255
+
256
+ test "entities should output a warning when a model table does not exist" do
257
+ Object.const_set :Foo, Class.new(ActiveRecord::Base)
258
+ output = collect_stdout do
259
+ Domain.generate.entities
260
+ end
261
+ assert_match /Ignoring invalid model Foo \(table foos does not exist\)/, output
262
+ end
140
263
  end
@@ -1,31 +1,39 @@
1
1
  require File.expand_path("../test_helper", File.dirname(__FILE__))
2
2
 
3
3
  class EntityTest < ActiveSupport::TestCase
4
+ def create_entity(model)
5
+ Domain::Entity.new(Domain.new, model.name, model)
6
+ end
7
+
8
+ def create_generalized_entity(name)
9
+ Domain::Entity.new(Domain.new, name)
10
+ end
11
+
4
12
  # Entity ===================================================================
5
13
  test "model should return active record model" do
6
14
  create_models "Foo"
7
- assert_equal Foo, Entity.new(Domain.new, Foo).model
15
+ assert_equal Foo, create_entity(Foo).model
8
16
  end
9
17
 
10
18
  test "name should return model name" do
11
19
  create_models "Foo"
12
- assert_equal "Foo", Entity.new(Domain.new, Foo).name
20
+ assert_equal "Foo", create_entity(Foo).name
13
21
  end
14
22
 
15
23
  test "spaceship should sort entities by name" do
16
24
  create_models "Foo", "Bar"
17
- foo, bar = Entity.new(Domain.new, Foo), Entity.new(Domain.new, Bar)
25
+ foo, bar = create_entity(Foo), create_entity(Bar)
18
26
  assert_equal [bar, foo], [foo, bar].sort
19
27
  end
20
28
 
21
29
  test "to_s should equal name" do
22
30
  create_models "Foo"
23
- assert_equal "Foo", Entity.new(Domain.new, Foo).to_s
31
+ assert_equal "Foo", create_entity(Foo).to_s
24
32
  end
25
33
 
26
34
  test "inspect should show name" do
27
35
  create_models "Foo"
28
- assert_match %r{#<RailsERD::Entity:.* @model=Foo>}, Entity.new(Domain.new, Foo).inspect
36
+ assert_match %r{#<RailsERD::Domain::Entity:.* @model=Foo>}, create_entity(Foo).inspect
29
37
  end
30
38
 
31
39
  test "relationships should return relationships for this model" do
@@ -38,7 +46,7 @@ class EntityTest < ActiveSupport::TestCase
38
46
  create_model "Baz"
39
47
 
40
48
  domain = Domain.generate
41
- foo = domain.entity_for(Foo)
49
+ foo = domain.entity_by_name("Foo")
42
50
  assert_equal domain.relationships.select { |r| r.destination == foo }, foo.relationships
43
51
  end
44
52
 
@@ -51,39 +59,39 @@ class EntityTest < ActiveSupport::TestCase
51
59
  create_model "Baz"
52
60
 
53
61
  domain = Domain.generate
54
- foo = domain.entity_for(Foo)
62
+ foo = domain.entity_by_name("Foo")
55
63
  assert_equal domain.relationships.select { |r| r.destination == foo }, foo.relationships
56
64
  end
57
65
 
58
- test "parent should return nil for regular entities" do
59
- create_model "Foo"
60
- assert_nil Entity.new(Domain.new, Foo).parent
61
- end
62
-
63
- test "parent should return nil for descended models with distinct tables" do
64
- create_model "Foo", :type => :string
65
- Object.const_set :SpecialFoo, Class.new(Foo)
66
- SpecialFoo.class_eval do
67
- set_table_name "special_foo"
68
- end
69
- create_table "special_foo", {}, true
70
- assert_nil Entity.new(Domain.new, SpecialFoo).parent
71
- end
72
-
73
- test "parent should return parent entity for child entities" do
74
- create_model "Foo", :type => :string
75
- Object.const_set :SpecialFoo, Class.new(Foo)
76
- domain = Domain.generate
77
- assert_equal domain.entity_for(Foo), Entity.new(domain, SpecialFoo).parent
78
- end
79
-
80
- test "parent should return parent entity for children of child entities" do
81
- create_model "Foo", :type => :string
82
- Object.const_set :SpecialFoo, Class.new(Foo)
83
- Object.const_set :VerySpecialFoo, Class.new(SpecialFoo)
84
- domain = Domain.generate
85
- assert_equal domain.entity_for(SpecialFoo), Entity.new(domain, VerySpecialFoo).parent
86
- end
66
+ # test "parent should return nil for regular entities" do
67
+ # create_model "Foo"
68
+ # assert_nil create_entity(Foo).parent
69
+ # end
70
+ #
71
+ # test "parent should return nil for specialized entities with distinct tables" do
72
+ # create_model "Foo", :type => :string
73
+ # Object.const_set :SpecialFoo, Class.new(Foo)
74
+ # SpecialFoo.class_eval do
75
+ # set_table_name "special_foo"
76
+ # end
77
+ # create_table "special_foo", {}, true
78
+ # assert_nil create_entity(SpecialFoo).parent
79
+ # end
80
+ #
81
+ # test "parent should return parent entity for specialized entities" do
82
+ # create_model "Foo", :type => :string
83
+ # Object.const_set :SpecialFoo, Class.new(Foo)
84
+ # domain = Domain.generate
85
+ # assert_equal domain.entity_by_name("Foo"), Domain::Entity.from_models(domain, [SpecialFoo]).first.parent
86
+ # end
87
+ #
88
+ # test "parent should return parent entity for specializations of specialized entities" do
89
+ # create_model "Foo", :type => :string
90
+ # Object.const_set :SpecialFoo, Class.new(Foo)
91
+ # Object.const_set :VerySpecialFoo, Class.new(SpecialFoo)
92
+ # domain = Domain.generate
93
+ # assert_equal domain.entity_by_name("SpecialFoo"), Domain::Entity.from_models(domain, [VerySpecialFoo]).first.parent
94
+ # end
87
95
 
88
96
  # Entity properties ========================================================
89
97
  test "connected should return false for unconnected entities" do
@@ -112,42 +120,138 @@ class EntityTest < ActiveSupport::TestCase
112
120
  assert_equal [false, false], Domain.generate.entities.map(&:disconnected?)
113
121
  end
114
122
 
115
- test "descendant should return false for regular entities" do
123
+ test "specialized should return false for regular entities" do
116
124
  create_model "Foo"
117
- assert_equal false, Entity.new(Domain.new, Foo).descendant?
125
+ assert_equal false, create_entity(Foo).specialized?
118
126
  end
119
127
 
120
- test "descendant should return false for descended models with distinct tables" do
128
+ test "specialized should return false for child entities with distinct tables" do
121
129
  create_model "Foo", :type => :string
122
130
  Object.const_set :SpecialFoo, Class.new(Foo)
123
131
  SpecialFoo.class_eval do
124
132
  set_table_name "special_foo"
125
133
  end
126
134
  create_table "special_foo", {}, true
127
- assert_equal false, Entity.new(Domain.new, SpecialFoo).descendant?
135
+ assert_equal false, create_entity(SpecialFoo).specialized?
128
136
  end
129
137
 
130
- test "descendant should return true for child entities" do
138
+ test "specialized should return true for specialized entities" do
131
139
  create_model "Foo", :type => :string
132
140
  Object.const_set :SpecialFoo, Class.new(Foo)
133
- assert_equal true, Entity.new(Domain.new, SpecialFoo).descendant?
141
+ assert_equal true, create_entity(SpecialFoo).specialized?
134
142
  end
135
143
 
136
- test "descendant should return true for children of child entities" do
144
+ test "specialized should return true for specialations of specialized entities" do
137
145
  create_model "Foo", :type => :string
138
146
  Object.const_set :SpecialFoo, Class.new(Foo)
139
147
  Object.const_set :VerySpecialFoo, Class.new(SpecialFoo)
140
- assert_equal true, Entity.new(Domain.new, VerySpecialFoo).descendant?
148
+ assert_equal true, create_entity(VerySpecialFoo).specialized?
149
+ end
150
+
151
+ test "abstract should return true for specialized entity" do
152
+ create_model "Foo", :type => :string
153
+ Object.const_set :SpecialFoo, Class.new(Foo)
154
+ assert_equal true, create_entity(SpecialFoo).abstract?
155
+ end
156
+
157
+ test "generalized should return false for regular entity" do
158
+ create_model "Concrete"
159
+ assert_equal false, create_entity(Concrete).generalized?
160
+ end
161
+
162
+ test "abstract should return false for regular entity" do
163
+ create_model "Concrete"
164
+ assert_equal false, create_entity(Concrete).abstract?
141
165
  end
142
166
 
143
167
  # Attribute processing =====================================================
144
168
  test "attributes should return list of attributes" do
145
169
  create_model "Bar", :some_column => :integer, :another_column => :string
146
- assert_equal [Attribute] * 3, Entity.new(Domain.new, Bar).attributes.collect(&:class)
170
+ assert_equal [Domain::Attribute] * 3, create_entity(Bar).attributes.collect(&:class)
147
171
  end
148
172
 
149
173
  test "attributes should return attributes sorted by name" do
150
174
  create_model "Bar", :some_column => :integer, :another_column => :string
151
- assert_equal ["another_column", "id", "some_column"], Entity.new(Domain.new, Bar).attributes.collect(&:name)
175
+ assert_equal ["another_column", "id", "some_column"], create_entity(Bar).attributes.collect(&:name)
176
+ end
177
+
178
+ # Generalized entity =======================================================
179
+ test "model should return nil for generalized entity" do
180
+ assert_nil create_generalized_entity("MyAbstractModel").model
181
+ end
182
+
183
+ test "name should return given name for generalized entity" do
184
+ assert_equal "MyAbstractModel", create_generalized_entity("MyAbstractModel").name
185
+ end
186
+
187
+ test "attributes should return empty array for generalized entity" do
188
+ assert_equal [], create_generalized_entity("MyAbstractModel").attributes
189
+ end
190
+
191
+ test "generalized should return true for generalized entity" do
192
+ assert_equal true, create_generalized_entity("MyAbstractModel").generalized?
193
+ end
194
+
195
+ test "specialized should return false for generalized entity" do
196
+ assert_equal false, create_generalized_entity("MyAbstractModel").specialized?
197
+ end
198
+
199
+ test "abstract should return true for generalized entity" do
200
+ assert_equal true, create_generalized_entity("MyAbstractModel").abstract?
201
+ end
202
+
203
+ test "relationships should return relationships for generalized entity" do
204
+ create_model "Stronghold" do
205
+ has_many :cannons, :as => :defensible
206
+ end
207
+ create_model "Cannon", :defensible => :references do
208
+ belongs_to :defensible, :polymorphic => true
209
+ end
210
+
211
+ domain = Domain.generate
212
+ defensible = domain.entity_by_name("Defensible")
213
+ assert_equal domain.relationships, defensible.relationships
214
+ end
215
+
216
+ test "relationships should return relationships for generalized entity in reverse alphabetic order" do
217
+ create_model "Stronghold" do
218
+ has_many :cannons, :as => :defensible
219
+ end
220
+ create_model "Cannon", :defensible => :references do
221
+ belongs_to :defensible, :polymorphic => true
222
+ end
223
+
224
+ domain = Domain.generate
225
+ defensible = domain.entity_by_name("Defensible")
226
+ assert_equal domain.relationships, defensible.relationships
227
+ end
228
+
229
+ # Children =================================================================
230
+ test "children should return empty array for regular entities" do
231
+ create_model "Foo"
232
+ assert_equal [], create_entity(Foo).children
233
+ end
234
+
235
+ test "children should return inherited entities for regular entities with single table inheritance" do
236
+ create_model "Beverage", :type => :string
237
+ create_model "Whisky", Beverage
238
+ create_model "Beer", Beverage
239
+ domain = Domain.generate
240
+ assert_equal [domain.entity_by_name("Beer"), domain.entity_by_name("Whisky")], domain.entity_by_name("Beverage").children
241
+ end
242
+
243
+ test "children should return inherited entities for generalized entities" do
244
+ create_model "Stronghold" do
245
+ has_many :cannons, :as => :defensible
246
+ end
247
+ create_model "Galleon" do
248
+ has_many :cannons, :as => :defensible
249
+ end
250
+ create_model "Cannon", :defensible => :references do
251
+ belongs_to :defensible, :polymorphic => true
252
+ end
253
+ domain = Domain.generate
254
+ assert_equal [domain.entity_by_name("Galleon"), domain.entity_by_name("Stronghold")],
255
+ domain.entity_by_name("Defensible").children
152
256
  end
153
257
  end