rails-erd 0.2.0 → 0.3.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.
@@ -115,7 +115,7 @@ class AttributeTest < ActiveSupport::TestCase
115
115
  # Type descriptions ========================================================
116
116
  test "type_description should return short type description" do
117
117
  create_model "Foo", :a => :binary
118
- assert_equal "blob", create_attribute(Foo, "a").type_description
118
+ assert_equal "binary", create_attribute(Foo, "a").type_description
119
119
  end
120
120
 
121
121
  test "type_description should return short type description without limit if standard" do
@@ -123,7 +123,7 @@ class AttributeTest < ActiveSupport::TestCase
123
123
  create_model "Foo"
124
124
  add_column :foos, :my_str, :string, :limit => 255
125
125
  ActiveRecord::Base.connection.native_database_types[:string]
126
- assert_equal "str (255)", create_attribute(Foo, "my_str").type_description
126
+ assert_equal "string (255)", create_attribute(Foo, "my_str").type_description
127
127
  end
128
128
  end
129
129
 
@@ -131,7 +131,7 @@ class AttributeTest < ActiveSupport::TestCase
131
131
  with_native_limit :string, 456 do
132
132
  create_model "Foo"
133
133
  add_column :foos, :my_str, :string, :limit => 456
134
- assert_equal "str", create_attribute(Foo, "my_str").type_description
134
+ assert_equal "string", create_attribute(Foo, "my_str").type_description
135
135
  end
136
136
  end
137
137
 
@@ -139,6 +139,28 @@ class AttributeTest < ActiveSupport::TestCase
139
139
  create_model "Foo", :a => :integer do
140
140
  validates_presence_of :a
141
141
  end
142
- assert_equal "int ∗", create_attribute(Foo, "a").type_description
142
+ assert_equal "integer ∗", create_attribute(Foo, "a").type_description
143
+ end
144
+
145
+ test "limit should return nil if there is no limit" do
146
+ create_model "Foo"
147
+ add_column :foos, :my_txt, :text
148
+ assert_equal nil, create_attribute(Foo, "my_txt").limit
149
+ end
150
+
151
+ test "limit should return nil if equal to standard database limit" do
152
+ with_native_limit :string, 456 do
153
+ create_model "Foo"
154
+ add_column :foos, :my_str, :string, :limit => 456
155
+ assert_equal nil, create_attribute(Foo, "my_str").limit
156
+ end
157
+ end
158
+
159
+ test "limit should return limit if nonstandard" do
160
+ with_native_limit :string, 456 do
161
+ create_model "Foo"
162
+ add_column :foos, :my_str, :string, :limit => 255
163
+ assert_equal 255, create_attribute(Foo, "my_str").limit
164
+ end
143
165
  end
144
166
  end
@@ -1,25 +1,117 @@
1
1
  require File.expand_path("../test_helper", File.dirname(__FILE__))
2
2
 
3
3
  class CardinalityTest < ActiveSupport::TestCase
4
- # Cardinality order ========================================================
5
- test "cardinalities should be sorted in order of maniness" do
6
- assert_equal [Relationship::Cardinality::OneToOne, Relationship::Cardinality::OneToMany, Relationship::Cardinality::ManyToMany],
7
- [Relationship::Cardinality::OneToMany, Relationship::Cardinality::ManyToMany, Relationship::Cardinality::OneToOne].sort
4
+ def setup
5
+ @n = Relationship::Cardinality::N
6
+ end
7
+
8
+ # Cardinality construction =================================================
9
+ test "new should return cardinality object" do
10
+ assert_kind_of Relationship::Cardinality, Relationship::Cardinality.new(1, 1..@n)
8
11
  end
9
12
 
10
13
  # Cardinality properties ===================================================
11
- test "one_to_one should return true for one to one cardinalities" do
12
- assert_equal [true, false, false], [Relationship::Cardinality::OneToOne,
13
- Relationship::Cardinality::OneToMany, Relationship::Cardinality::ManyToMany].map(&:one_to_one?)
14
+ test "source_optional should return true if source range starts at zero" do
15
+ assert_equal true, Relationship::Cardinality.new(0..1, 1).source_optional?
16
+ end
17
+
18
+ test "source_optional should return false if source range starts at one or more" do
19
+ assert_equal false, Relationship::Cardinality.new(1..2, 0..1).source_optional?
20
+ end
21
+
22
+ test "destination_optional should return true if destination range starts at zero" do
23
+ assert_equal true, Relationship::Cardinality.new(1, 0..1).destination_optional?
24
+ end
25
+
26
+ test "destination_optional should return false if destination range starts at one or more" do
27
+ assert_equal false, Relationship::Cardinality.new(0..1, 1..2).destination_optional?
28
+ end
29
+
30
+ test "inverse should return inverse cardinality" do
31
+ assert_equal Relationship::Cardinality.new(23..45, 0..15), Relationship::Cardinality.new(0..15, 23..45).inverse
32
+ end
33
+
34
+ # Cardinality equality =====================================================
35
+ test "cardinalities are equal if they have the same boundaries" do
36
+ assert_equal Relationship::Cardinality.new(1, 1..Relationship::Cardinality::N),
37
+ Relationship::Cardinality.new(1, 1..Relationship::Cardinality::N)
38
+ end
39
+
40
+ test "cardinalities are not equal if they have a different source range" do
41
+ assert_not_equal Relationship::Cardinality.new(0..1, 1..Relationship::Cardinality::N),
42
+ Relationship::Cardinality.new(1..1, 1..Relationship::Cardinality::N)
43
+ end
44
+
45
+ test "cardinalities are not equal if they have a different destination range" do
46
+ assert_not_equal Relationship::Cardinality.new(0..1, 1..Relationship::Cardinality::N),
47
+ Relationship::Cardinality.new(0..1, 2..Relationship::Cardinality::N)
48
+ end
49
+
50
+ # Cardinal names ===========================================================
51
+ test "one_to_one should return true if source and destination are exactly one" do
52
+ assert_equal true, Relationship::Cardinality.new(1, 1).one_to_one?
53
+ end
54
+
55
+ test "one_to_one should return true if source and destination range are less than or equal to one" do
56
+ assert_equal true, Relationship::Cardinality.new(0..1, 0..1).one_to_one?
14
57
  end
15
58
 
16
- test "one_to_many should return true for one to many cardinalities" do
17
- assert_equal [false, true, false], [Relationship::Cardinality::OneToOne,
18
- Relationship::Cardinality::OneToMany, Relationship::Cardinality::ManyToMany].map(&:one_to_many?)
59
+ test "one_to_one should return false if source range upper limit is more than one" do
60
+ assert_equal false, Relationship::Cardinality.new(0..15, 0..1).one_to_one?
61
+ end
62
+
63
+ test "one_to_one should return false if destination range upper limit is more than one" do
64
+ assert_equal false, Relationship::Cardinality.new(0..1, 0..15).one_to_one?
65
+ end
66
+
67
+ test "one_to_many should return true if source is exactly one and destination is higher than one" do
68
+ assert_equal true, Relationship::Cardinality.new(1, 15).one_to_many?
69
+ end
70
+
71
+ test "one_to_many should return true if source is less than or equal to one and destination is higher than one" do
72
+ assert_equal true, Relationship::Cardinality.new(0..1, 0..15).one_to_many?
73
+ end
74
+
75
+ test "one_to_many should return false if source range upper limit is more than one" do
76
+ assert_equal false, Relationship::Cardinality.new(0..15, 0..15).one_to_many?
77
+ end
78
+
79
+ test "one_to_many should return false if destination range upper limit is one" do
80
+ assert_equal false, Relationship::Cardinality.new(0..1, 1).one_to_many?
81
+ end
82
+
83
+ test "many_to_many should return true if source and destination are higher than one" do
84
+ assert_equal true, Relationship::Cardinality.new(15, 15).many_to_many?
85
+ end
86
+
87
+ test "many_to_many should return true if source and destination upper limits are higher than one" do
88
+ assert_equal true, Relationship::Cardinality.new(0..15, 0..15).many_to_many?
19
89
  end
20
90
 
21
- test "many_to_many should return true for many to many cardinalities" do
22
- assert_equal [false, false, true], [Relationship::Cardinality::OneToOne,
23
- Relationship::Cardinality::OneToMany, Relationship::Cardinality::ManyToMany].map(&:many_to_many?)
91
+ test "many_to_many should return false if source range upper limit is is one" do
92
+ assert_equal false, Relationship::Cardinality.new(1, 0..15).many_to_many?
93
+ end
94
+
95
+ test "many_to_many should return false if destination range upper limit is one" do
96
+ assert_equal false, Relationship::Cardinality.new(0..1, 1).many_to_many?
97
+ end
98
+
99
+ test "inverse of one_to_many should be many_to_one" do
100
+ assert_equal true, Relationship::Cardinality.new(0..1, 0..@n).inverse.many_to_one?
101
+ end
102
+
103
+ # Cardinality order ========================================================
104
+ test "cardinalities should be sorted in order of maniness" do
105
+ card1 = Relationship::Cardinality.new(0..1, 1)
106
+ card2 = Relationship::Cardinality.new(1, 1)
107
+ card3 = Relationship::Cardinality.new(0..1, 1..3)
108
+ card4 = Relationship::Cardinality.new(1, 1..2)
109
+ card5 = Relationship::Cardinality.new(1, 1..@n)
110
+ card6 = Relationship::Cardinality.new(1..5, 1..3)
111
+ card7 = Relationship::Cardinality.new(1..2, 1..15)
112
+ card8 = Relationship::Cardinality.new(1..15, 1..@n)
113
+ card9 = Relationship::Cardinality.new(1..@n, 1..@n)
114
+ assert_equal [card1, card2, card3, card4, card5, card6, card7, card8, card9],
115
+ [card9, card5, card8, card2, card4, card7, card1, card6, card3].sort
24
116
  end
25
117
  end
@@ -9,6 +9,42 @@ class DiagramTest < ActiveSupport::TestCase
9
9
  RailsERD.send :remove_const, :Diagram
10
10
  end
11
11
 
12
+ def retrieve_relationships(options = {})
13
+ klass = Class.new(Diagram)
14
+ [].tap do |relationships|
15
+ klass.class_eval do
16
+ define_method :process_relationship do |relationship|
17
+ relationships << relationship
18
+ end
19
+ end
20
+ klass.create(options)
21
+ end
22
+ end
23
+
24
+ def retrieve_entities(options = {})
25
+ klass = Class.new(Diagram)
26
+ [].tap do |entities|
27
+ klass.class_eval do
28
+ define_method :process_entity do |entity, attributes|
29
+ entities << entity
30
+ end
31
+ end
32
+ klass.create(options)
33
+ end
34
+ end
35
+
36
+ def retrieve_attribute_lists(options = {})
37
+ klass = Class.new(Diagram)
38
+ {}.tap do |attribute_lists|
39
+ klass.class_eval do
40
+ define_method :process_entity do |entity, attributes|
41
+ attribute_lists[entity.model] = attributes
42
+ end
43
+ end
44
+ klass.create(options)
45
+ end
46
+ end
47
+
12
48
  # Diagram ==================================================================
13
49
  test "create class method should return result of save" do
14
50
  create_simple_domain
@@ -54,4 +90,138 @@ class DiagramTest < ActiveSupport::TestCase
54
90
  end.create
55
91
  end
56
92
  end
93
+
94
+ # Entity filtering =========================================================
95
+ test "generate should yield entities" do
96
+ create_model "Foo"
97
+ assert_equal [Foo], retrieve_entities.map(&:model)
98
+ end
99
+
100
+ test "generate should filter disconnected entities if disconnected is false" do
101
+ create_model "Book", :author => :references do
102
+ belongs_to :author
103
+ end
104
+ create_model "Author"
105
+ create_model "Table", :type => :string
106
+ assert_equal [Author, Book], retrieve_entities(:disconnected => false).map(&:model)
107
+ end
108
+
109
+ test "generate should yield disconnected entities if disconnected is true" do
110
+ create_model "Foo", :type => :string
111
+ assert_equal [Foo], retrieve_entities(:disconnected => true).map(&:model)
112
+ end
113
+
114
+ test "generate should filter descendant entities" do
115
+ create_model "Foo", :type => :string
116
+ Object.const_set :SpecialFoo, Class.new(Foo)
117
+ assert_equal [Foo], retrieve_entities.map(&:model)
118
+ end
119
+
120
+ test "generate should yield descended entities with distinct tables" do
121
+ create_model "Foo"
122
+ Object.const_set :SpecialFoo, Class.new(Foo)
123
+ SpecialFoo.class_eval do
124
+ set_table_name "special_foo"
125
+ end
126
+ create_table "special_foo", {}, true
127
+ assert_equal [Foo, SpecialFoo], retrieve_entities.map(&:model)
128
+ end
129
+
130
+ # Relationship filtering ===================================================
131
+ test "generate should yield relationships" do
132
+ create_simple_domain
133
+ assert_equal 1, retrieve_relationships.length
134
+ end
135
+
136
+ test "generate should yield indirect relationships if indirect is true" do
137
+ create_model "Foo" do
138
+ has_many :bazs
139
+ has_many :bars
140
+ end
141
+ create_model "Bar", :foo => :references do
142
+ belongs_to :foo
143
+ has_many :bazs, :through => :foo
144
+ end
145
+ create_model "Baz", :foo => :references do
146
+ belongs_to :foo
147
+ end
148
+ assert_equal [false, false, true], retrieve_relationships(:indirect => true).map(&:indirect?)
149
+ end
150
+
151
+ test "generate should filter indirect relationships if indirect is false" do
152
+ create_model "Foo" do
153
+ has_many :bazs
154
+ has_many :bars
155
+ end
156
+ create_model "Bar", :foo => :references do
157
+ belongs_to :foo
158
+ has_many :bazs, :through => :foo
159
+ end
160
+ create_model "Baz", :foo => :references do
161
+ belongs_to :foo
162
+ end
163
+ assert_equal [false, false], retrieve_relationships(:indirect => false).map(&:indirect?)
164
+ end
165
+
166
+ test "generate should filter relationships from descendant entities" do
167
+ create_model "Foo", :bar => :references
168
+ create_model "Bar", :type => :string
169
+ Object.const_set :SpecialBar, Class.new(Bar)
170
+ SpecialBar.class_eval do
171
+ has_many :foos
172
+ end
173
+ assert_equal [], retrieve_relationships
174
+ end
175
+
176
+ test "generate should filter relationships to descendant entities" do
177
+ create_model "Foo", :type => :string, :bar => :references
178
+ Object.const_set :SpecialFoo, Class.new(Foo)
179
+ create_model "Bar" do
180
+ has_many :special_foos
181
+ end
182
+ assert_equal [], retrieve_relationships
183
+ end
184
+
185
+ # Attribute filtering ======================================================
186
+ test "generate should yield regular attributes by default" do
187
+ create_model "Book", :title => :string, :created_at => :datetime, :author => :references do
188
+ belongs_to :author
189
+ end
190
+ create_model "Author"
191
+ assert_equal %w{title}, retrieve_attribute_lists[Book].map(&:name)
192
+ end
193
+
194
+ test "generate should yield primary key attributes if included" do
195
+ create_model "Book", :title => :string
196
+ create_model "Page", :book => :references do
197
+ belongs_to :book
198
+ end
199
+ assert_equal %w{id}, retrieve_attribute_lists(:attributes => [:primary_keys])[Book].map(&:name)
200
+ end
201
+
202
+ test "generate should yield foreign key attributes if included" do
203
+ create_model "Book", :author => :references do
204
+ belongs_to :author
205
+ end
206
+ create_model "Author"
207
+ assert_equal %w{author_id}, retrieve_attribute_lists(:attributes => [:foreign_keys])[Book].map(&:name)
208
+ end
209
+
210
+ test "generate should yield timestamp attributes if included" do
211
+ create_model "Book", :created_at => :datetime, :created_on => :date, :updated_at => :datetime, :updated_on => :date
212
+ create_model "Page", :book => :references do
213
+ belongs_to :book
214
+ end
215
+ assert_equal %w{created_at created_on updated_at updated_on},
216
+ retrieve_attribute_lists(:attributes => [:timestamps])[Book].map(&:name)
217
+ end
218
+
219
+ test "generate should yield combinations of attributes if included" do
220
+ create_model "Book", :created_at => :datetime, :title => :string, :author => :references do
221
+ belongs_to :author
222
+ end
223
+ create_model "Author"
224
+ assert_equal %w{created_at title},
225
+ retrieve_attribute_lists(:attributes => [:regular, :timestamps])[Book].map(&:name)
226
+ end
57
227
  end
@@ -28,7 +28,7 @@ class DomainTest < ActiveSupport::TestCase
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:.* \{Bar => Foo\}>}, Domain.generate.inspect
32
32
  end
33
33
 
34
34
  # Entity processing ========================================================
@@ -89,14 +89,14 @@ class DomainTest < ActiveSupport::TestCase
89
89
  create_model "Foo" do
90
90
  has_many :flabs
91
91
  end
92
- assert_equal [], Domain.generate(:suppress_warnings => true).relationships
92
+ assert_equal [], Domain.generate(:warn => false).relationships
93
93
  end
94
94
 
95
95
  test "relationships should omit bad has_many through association" do
96
96
  create_model "Foo" do
97
97
  has_many :flabs, :through => :bars
98
98
  end
99
- assert_equal [], Domain.generate(:suppress_warnings => true).relationships
99
+ assert_equal [], Domain.generate(:warn => false).relationships
100
100
  end
101
101
 
102
102
  test "relationships should omit association to model outside domain" do
@@ -104,7 +104,7 @@ class DomainTest < ActiveSupport::TestCase
104
104
  has_many :bars
105
105
  end
106
106
  create_model "Bar", :foo => :references
107
- assert_equal [], Domain.new([Foo], :suppress_warnings => true).relationships
107
+ assert_equal [], Domain.new([Foo], :warn => false).relationships
108
108
  end
109
109
 
110
110
  test "relationships should output a warning when a bad association is encountered" do
@@ -114,7 +114,7 @@ class DomainTest < ActiveSupport::TestCase
114
114
  output = collect_stdout do
115
115
  Domain.generate.relationships
116
116
  end
117
- assert_match /Invalid association :flabs on Foo/, output
117
+ assert_match /Ignoring invalid association :flabs on Foo/, output
118
118
  end
119
119
 
120
120
  test "relationships should output a warning when an association to model outside domain is encountered" do
@@ -125,15 +125,15 @@ class DomainTest < ActiveSupport::TestCase
125
125
  output = collect_stdout do
126
126
  Domain.new([Foo]).relationships
127
127
  end
128
- assert_match /model Bar exists, but is not included in the domain/, output
128
+ assert_match /model Bar exists, but is not included in domain/, output
129
129
  end
130
130
 
131
- test "relationships should suppress warnings when a bad association is encountered if warning suppression is enabled" do
131
+ test "relationships should not warn when a bad association is encountered if warnings are disabled" do
132
132
  create_model "Foo" do
133
133
  has_many :flabs
134
134
  end
135
135
  output = collect_stdout do
136
- Domain.generate(:suppress_warnings => true).relationships
136
+ Domain.generate(:warn => false).relationships
137
137
  end
138
138
  assert_equal "", output
139
139
  end
@@ -54,7 +54,37 @@ class EntityTest < ActiveSupport::TestCase
54
54
  foo = domain.entity_for(Foo)
55
55
  assert_equal domain.relationships.select { |r| r.destination == foo }, foo.relationships
56
56
  end
57
-
57
+
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
87
+
58
88
  # Entity properties ========================================================
59
89
  test "connected should return false for unconnected entities" do
60
90
  create_models "Foo", "Bar"
@@ -68,6 +98,47 @@ class EntityTest < ActiveSupport::TestCase
68
98
  create_model "Bar"
69
99
  assert_equal [true, true], Domain.generate.entities.map(&:connected?)
70
100
  end
101
+
102
+ test "disconnected should return true for unconnected entities" do
103
+ create_models "Foo", "Bar"
104
+ assert_equal [true, true], Domain.generate.entities.map(&:disconnected?)
105
+ end
106
+
107
+ test "disconnected should return false for connected entities" do
108
+ create_model "Foo", :bar => :references do
109
+ belongs_to :bar
110
+ end
111
+ create_model "Bar"
112
+ assert_equal [false, false], Domain.generate.entities.map(&:disconnected?)
113
+ end
114
+
115
+ test "descendant should return false for regular entities" do
116
+ create_model "Foo"
117
+ assert_equal false, Entity.new(Domain.new, Foo).descendant?
118
+ end
119
+
120
+ test "descendant should return false for descended models with distinct tables" do
121
+ create_model "Foo", :type => :string
122
+ Object.const_set :SpecialFoo, Class.new(Foo)
123
+ SpecialFoo.class_eval do
124
+ set_table_name "special_foo"
125
+ end
126
+ create_table "special_foo", {}, true
127
+ assert_equal false, Entity.new(Domain.new, SpecialFoo).descendant?
128
+ end
129
+
130
+ test "descendant should return true for child entities" do
131
+ create_model "Foo", :type => :string
132
+ Object.const_set :SpecialFoo, Class.new(Foo)
133
+ assert_equal true, Entity.new(Domain.new, SpecialFoo).descendant?
134
+ end
135
+
136
+ test "descendant should return true for children of child entities" do
137
+ create_model "Foo", :type => :string
138
+ Object.const_set :SpecialFoo, Class.new(Foo)
139
+ Object.const_set :VerySpecialFoo, Class.new(SpecialFoo)
140
+ assert_equal true, Entity.new(Domain.new, VerySpecialFoo).descendant?
141
+ end
71
142
 
72
143
  # Attribute processing =====================================================
73
144
  test "attributes should return list of attributes" do