rails-erd 0.3.0 → 0.4.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.
@@ -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