rails-erd 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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