activefacts-api 0.8.9 → 0.8.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,6 +2,7 @@
2
2
  # ActiveFacts tests: Entity classes in the Runtime API
3
3
  # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
4
  #
5
+ require 'rspec'
5
6
  require 'activefacts/api'
6
7
 
7
8
  describe "Entity Type class definitions" do
@@ -0,0 +1,401 @@
1
+ require 'rspec'
2
+ require 'activefacts/api'
3
+
4
+ describe "An Entity Type" do
5
+ before :all do
6
+ module Mod
7
+ class Name < String
8
+ value_type
9
+ end
10
+
11
+ class Number < Int
12
+ value_type
13
+ end
14
+ end
15
+ end
16
+ before :each do
17
+ @c = ActiveFacts::API::Constellation.new(Mod)
18
+ end
19
+
20
+ describe "whose instances are identified by a single value role" do
21
+ before :all do
22
+ module Mod
23
+ class Business
24
+ identified_by :name
25
+ one_to_one :name
26
+ end
27
+ end
28
+ end
29
+
30
+ it "should fail if the role isn't one-to-one" do
31
+ pending "Lacks a check for one-to-one identifying role" do
32
+ proc do
33
+ module Mod
34
+ class Cat
35
+ identified_by :name
36
+ has_one :name
37
+ end
38
+ end
39
+ end.should raise_error
40
+ end
41
+ end
42
+
43
+ describe "when asserted" do
44
+ before :each do
45
+ @bus = @c.Business('Acme')
46
+ @acme = @c.Name['Acme']
47
+ end
48
+
49
+ it "should return a new instance if not previously present" do
50
+ @bus.should be_a(Mod::Business)
51
+ end
52
+
53
+ it "should assert the identifying value" do
54
+ @acme.should be_a(Mod::Name)
55
+ end
56
+
57
+ it "should be found in the constellation using the value" do
58
+ @c.Business[['Acme']].should == @bus
59
+ @c.Business[[@acme]].should == @bus
60
+ end
61
+
62
+ it "should belong to the constellation" do
63
+ @bus.constellation.should == @c
64
+ end
65
+
66
+ it "should be assigned to the value's counterpart role" do
67
+ @acme.business.should == @bus
68
+ end
69
+
70
+ it "should return a previously-existing instance" do
71
+ @c.Business[['Acme']].should == @bus
72
+ @c.Business.size.should == 1
73
+ end
74
+ end
75
+
76
+ describe "when the value is changed" do
77
+ before :each do
78
+ @fly = @c.Business('Fly')
79
+ @bus = @c.Business('Acme')
80
+ @acme = @c.Name['Acme']
81
+ end
82
+
83
+ it "should fail if the new value already exists" do
84
+ pending "Doesn't check validity of rename" do
85
+ proc do
86
+ @bus.name = 'Acme'
87
+ end.should raise_error
88
+ end
89
+ end
90
+
91
+ describe "to a previously-nonexistent value" do
92
+ before :each do
93
+ @bus.name = 'Bloggs'
94
+ end
95
+
96
+ it "should assert the new identifier" do
97
+ @c.Name['Bloggs'].should be_a(Mod::Name)
98
+ end
99
+
100
+ it "should allow the change" do
101
+ @bus.name.should == 'Bloggs'
102
+ @c.Business.size.should == 2
103
+ end
104
+
105
+ it "should be found under the new identifier" do
106
+ pending "entities are not re-indexed on identifier assignment" do
107
+ @c.Business['Bloggs'].should == @bus
108
+ end
109
+ end
110
+
111
+ it "should be in the constellation's index under the new identifier" do
112
+ pending "entities are not re-indexed on identifier assignment" do
113
+ @c.Business.keys[0].should == ['Bloggs']
114
+ end
115
+ end
116
+
117
+ it "should be the counterpart of the new identifier" do
118
+ @c.Name['Bloggs'].business.should == @bus
119
+ end
120
+
121
+ it "should not be found in the constellation using the old value" do
122
+ pending "entities are not de-indexed on identifier assignment" do
123
+ @c.Business[['Acme']].should be_nil
124
+ end
125
+ end
126
+
127
+ it "the old value's back-reference is set to nil" do
128
+ @acme.business.should be_nil
129
+ end
130
+
131
+ describe "and the old identifying value plays no other roles" do
132
+ describe "and the player of the identifying role is not independent" do
133
+ it "should retract the previous value" do
134
+ pending "All value types default to independent" do
135
+ @c.Name['Acme'].should be_nil
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ describe "when retracted" do
144
+ before :each do
145
+ @bus = @c.Business('Acme')
146
+ @acme = @c.Name['Acme']
147
+ end
148
+
149
+ it "should disappear from the constellation" do
150
+ @bus.retract
151
+ @c.Business[['Acme']].should be_nil
152
+ end
153
+
154
+ describe "and the identifying value plays no other roles" do
155
+ describe "and the player of the identifying role is not independent" do
156
+ before :each do
157
+ @bus.retract
158
+ end
159
+
160
+ it "should retract the identifying value also" do
161
+ pending "All value types default to independent" do
162
+ @c.Name['Acme'].should be_nil
163
+ end
164
+ end
165
+
166
+ it "should not appear as the value's counterpart role" do
167
+ @acme.business.should be_nil
168
+ end
169
+ end
170
+
171
+ describe "and the identifying value plays other roles" do
172
+ before :all do
173
+ module Mod
174
+ class Dog
175
+ identified_by :name
176
+ one_to_one :name
177
+ end
178
+ end
179
+ end
180
+ before :each do
181
+ @c.Dog("Acme")
182
+ @bus.retract
183
+ end
184
+
185
+ it "should retain the identifying value, but with a nil counterpart role" do
186
+ @c.Name['Acme'].should == @acme
187
+ @acme.business.should be_nil
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ describe "identified by two values" do
195
+ before :all do
196
+ module Mod
197
+ class Building
198
+ identified_by :name
199
+ one_to_one :name
200
+ end
201
+
202
+ class Room
203
+ identified_by :building, :number
204
+ has_one :building
205
+ has_one :number
206
+ end
207
+ end
208
+ end
209
+ before :each do
210
+ @c = ActiveFacts::API::Constellation.new(Mod)
211
+ end
212
+
213
+ it "should fail if any role is one-to-one" do
214
+ pending "Lacks a check for one-to-one identifying role" do
215
+ proc do
216
+ module Mod
217
+ class Floor
218
+ identified_by :building, :number
219
+ has_one :building
220
+ one_to_one :number # Error, invalid identifier
221
+ end
222
+ end
223
+ end.should raise_error
224
+ end
225
+ end
226
+
227
+ describe "when asserted" do
228
+ before :each do
229
+ @b = @c.Building('Mackay')
230
+ @mackay = @c.Name['Mackay']
231
+ @r = @c.Room(@b, 101)
232
+ @rn = @r.number
233
+ end
234
+
235
+ it "should return a new instance if not previously present" do
236
+ @r.should be_a(Mod::Room)
237
+ end
238
+
239
+ it "should assert the identifying values" do
240
+ @rn.should be_a(Mod::Number)
241
+ @c.Number[@rn].should == @rn # Yes
242
+ @c.Number[101].should == @rn # No
243
+ @c.Number[101].should be_eql 101 # No
244
+ end
245
+
246
+ it "should be found in the constellation using the value" do
247
+ @c.Room[[@b.identifying_role_values, @rn]].should == @r
248
+ @c.Room[[@b.identifying_role_values, 101]].should == @r
249
+ @c.Room[[['Mackay'], 101]].should == @r
250
+ end
251
+
252
+ it "should belong to the constellation" do
253
+ @r.constellation.should == @c
254
+ end
255
+
256
+ it "should be added to the values' counterpart roles" do
257
+ @rn.all_room.to_a.should == [@r]
258
+ @b.all_room.to_a.should == [@r]
259
+ end
260
+
261
+ it "should return a previously-existing instance" do
262
+ @c.Room(@b, 101).should == @r
263
+ @c.Room(['Mackay'], 101).should == @r
264
+ @c.Room.size.should == 1
265
+ end
266
+ end
267
+
268
+ describe "when the value is changed" do
269
+ before :each do
270
+ @b = @c.Building('Mackay')
271
+ @mackay = @c.Name['Mackay']
272
+ @r = @c.Room(@b, 101)
273
+ @rn = @r.number
274
+ end
275
+
276
+ it "should fail if the new value already exists" do
277
+ @c.Room(@b, 102)
278
+ pending "Doesn't check validity of rename" do
279
+ proc {
280
+ @r.number = 102
281
+ }.should raise_error
282
+ end
283
+ end
284
+
285
+ describe "to a previously-nonexistent value" do
286
+ before :each do
287
+ @r.number = 103
288
+ @new_number = @r.number
289
+ end
290
+
291
+ it "should assert the new identifier" do
292
+ @new_number.should_not be_nil
293
+ end
294
+
295
+ it "should allow the change" do
296
+ @r.number.should == @new_number
297
+ @r.number.should be_eql(103)
298
+ end
299
+
300
+ it "should be found under the new identifier" do
301
+ pending "entities are not re-indexed on identifier assignment" do
302
+ @c.Room[[@b.identifying_role_values, 103]].should == @r
303
+ @c.Room[[['Mackay'], 101]].should be_nil
304
+ end
305
+ end
306
+
307
+ it "should be in the constellation's index under the new identifier" do
308
+ pending "entities are not de-indexed on identifier assignment" do
309
+ @c.Room.keys[0].should == [['Mackay'], @r.number]
310
+ end
311
+ end
312
+
313
+ it "should be included in the counterparts of the new identifier roles" do
314
+ @b.all_room.to_a.should == [@r]
315
+ @new_number.all_room.to_a.should == [@r]
316
+ end
317
+
318
+ it "should not be found in the constellation using the old value" do
319
+ pending "entities are not de-indexed on identifier assignment" do
320
+ @c.Room.keys[0].should_not == [['Mackay'],101]
321
+ end
322
+ end
323
+
324
+ it "the old value's back-reference is set to nil" do
325
+ @rn.all_room.to_a.should_not be_include(@r)
326
+ end
327
+
328
+ describe "and the old identifying value plays no other roles" do
329
+ describe "and the player of the identifying role is not independent" do
330
+ it "should retract the previous value" do
331
+ pending "All value types default to independent" do
332
+ @c.Number[101].should be_nil
333
+ end
334
+ end
335
+ end
336
+ end
337
+ end
338
+ end
339
+
340
+ =begin
341
+ describe "when retracted" do
342
+ it "should disappear from the constellation"
343
+ describe "and the identifying value plays no other roles" do
344
+ describe "and the player of the identifying role is not independent" do
345
+ it "should retract the identifying value also"
346
+ it "should not appear as the value's counterpart role"
347
+ end
348
+ describe "and the identifying value plays other roles" do
349
+ it "should retain the identifying value, but with a nil counterpart role"
350
+ end
351
+ end
352
+ end
353
+ =end
354
+
355
+ end
356
+
357
+ =begin
358
+ describe "which inherits its identification from a supertype" do
359
+ describe "which also has a secondary supertype" do
360
+ end
361
+ end
362
+
363
+ describe "which has a supertype that has separate identification" do
364
+ before :each do
365
+ module Mod
366
+ class Animal
367
+ identified_by :number
368
+ one_to_one :neumber
369
+ end
370
+ class Dog < Animal
371
+ identified_by :name
372
+ one_to_one :name
373
+ end
374
+ end
375
+ end
376
+
377
+ describe "when asserted" do
378
+ describe "and both identifiers are new" do
379
+ it "should be found using the respective identifiers"
380
+ end
381
+ describe "and only the supertype identifier is new" do
382
+ it "should be rejected because of the duplicate subtype identifier"
383
+ end
384
+ describe "and only the subtype identifier is new" do
385
+ it "should be rejected because of the duplicate supertype identifier"
386
+ end
387
+ end
388
+
389
+ describe "when the subtype identifier is changed" do
390
+ it "should fail if the new subtype value already exists"
391
+ it "should allow the change if the new subtype value doesn't already exist"
392
+ end
393
+
394
+ describe "when the supertype identifier is changed" do
395
+ it "should fail if the new supertype value already exists"
396
+ it "should allow the change if the new supertype value doesn't already exist"
397
+ end
398
+
399
+ end
400
+ =end
401
+ end
@@ -0,0 +1,384 @@
1
+ #
2
+ # ActiveFacts tests: Value instances in the Runtime API
3
+ # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
+ #
5
+ require 'rspec'
6
+ require 'activefacts/api'
7
+
8
+ describe "An instance of every type of ObjectType" do
9
+ before :each do
10
+ Object.send :remove_const, :Mod if Object.const_defined?("Mod")
11
+ module Mod
12
+ # These are the base value types we're going to test:
13
+ @base_types = [
14
+ Int, Real, AutoCounter, String, Date, DateTime, Decimal
15
+ ]
16
+
17
+ # Construct the names of the roles they play:
18
+ @base_type_roles = @base_types.map do |t|
19
+ t.name.snakecase
20
+ end
21
+ @role_names = @base_type_roles.inject([]) {|a, t|
22
+ a << :"#{t}_value"
23
+ } +
24
+ @base_type_roles.inject([]) {|a, t|
25
+ a << :"#{t}_sub_value"
26
+ }
27
+
28
+ # Create a value type and a subtype of that value type for each base type:
29
+ @base_types.each do |base_type|
30
+ eval <<-END
31
+ class #{base_type.name}Value < #{base_type.name}
32
+ value_type
33
+ end
34
+
35
+ class #{base_type.name}SubValue < #{base_type.name}Value
36
+ # Note no new "value_type" is required here, it comes through inheritance
37
+ end
38
+ END
39
+ end
40
+
41
+ # Create a TestByX, TestByXSub, and TestSubByX class for all base types X
42
+ # Each class has a has_one and a one_to_one for all roles.
43
+ # and is identified by the has_one :x role
44
+ @base_types.each do |base_type|
45
+ code = <<-END
46
+ class TestBy#{base_type.name}
47
+ identified_by :#{base_type.name.snakecase}_value#{
48
+ @role_names.map do |role_name|
49
+ %Q{
50
+ has_one :#{role_name}#{
51
+ mandatory = (role_name == (base_type.name.snakecase+'_value').to_sym ? ', :mandatory => true' : '')
52
+ }
53
+ one_to_one :one_#{role_name}, :class => #{role_name.to_s.camelcase}}
54
+ end*""
55
+ }
56
+ end
57
+
58
+ class TestBy#{base_type.name}Sub
59
+ identified_by :#{base_type.name.snakecase}_sub_value#{
60
+ @role_names.map do |role_name|
61
+ %Q{
62
+ has_one :#{role_name}
63
+ one_to_one :one_#{role_name}, :class => #{role_name.to_s.camelcase}}
64
+ end*""
65
+ }
66
+ end
67
+
68
+ class TestSubBy#{base_type.name} < TestBy#{base_type.name}
69
+ # Entity subtypes, inherit identification and all roles
70
+ end
71
+
72
+ class TestBy#{base_type.name}Entity
73
+ identified_by :test_by_#{base_type.name.snakecase}
74
+ one_to_one :test_by_#{base_type.name.snakecase}
75
+ end
76
+ END
77
+ eval code
78
+ end
79
+ end
80
+
81
+ # Simple Values
82
+ @int = 0
83
+ @real = 0.0
84
+ @auto_counter = 0
85
+ @new_auto_counter = :new
86
+ @string = "zero"
87
+ @date = [2008, 04, 19]
88
+ @date_time = [2008, 04, 19, 10, 28, 14]
89
+ @decimal = BigDecimal.new('98765432109876543210')
90
+
91
+ # Value Type instances
92
+ @int_value = Mod::IntValue.new(1)
93
+ @real_value = Mod::RealValue.new(1.0)
94
+ @auto_counter_value = Mod::AutoCounterValue.new(1)
95
+ @new_auto_counter_value = Mod::AutoCounterValue.new(:new)
96
+ @string_value = Mod::StringValue.new("one")
97
+ @date_value = Mod::DateValue.new(2008, 04, 20)
98
+ # Parse the date:
99
+ @date_value = Mod::DateValue.new '2nd Nov 2001'
100
+ d = ::Date.civil(2008, 04, 20)
101
+ @date_time_value = Mod::DateTimeValue.new d # 2008, 04, 20, 10, 28, 14
102
+ # This next isn't in the same pattern; it makes a Decimal from a BigDecimal rather than a String (coverage reasons)
103
+ @decimal_value = Mod::DecimalValue.new(BigDecimal.new('98765432109876543210'))
104
+
105
+ # Value SubType instances
106
+ @int_sub_value = Mod::IntSubValue.new(4)
107
+ @real_sub_value = Mod::RealSubValue.new(4.0)
108
+ @auto_counter_sub_value = Mod::AutoCounterSubValue.new(4)
109
+ @auto_counter_sub_value_new = Mod::AutoCounterSubValue.new(:new)
110
+ @string_sub_value = Mod::StringSubValue.new("five")
111
+ @date_sub_value = Mod::DateSubValue.new(2008, 04, 25)
112
+ @date_time_sub_value = Mod::DateTimeSubValue.new(::DateTime.civil(2008, 04, 26, 10, 28, 14))
113
+ # This next isn't in the same pattern; it makes a Decimal from a BigNum rather than a String (coverage reasons)
114
+ @decimal_sub_value = Mod::DecimalSubValue.new(98765432109876543210)
115
+
116
+ # Entities identified by Value Type, SubType and Entity-by-value-type instances
117
+ @test_by_int = Mod::TestByInt.new(2)
118
+ @test_by_real = Mod::TestByReal.new(2.0)
119
+ @test_by_auto_counter = Mod::TestByAutoCounter.new(2)
120
+ @test_by_auto_counter_new = Mod::TestByAutoCounter.new(:new)
121
+ @test_by_string = Mod::TestByString.new("two")
122
+ @test_by_date = Mod::TestByDate.new(Date.new(2008,04,28))
123
+ #@test_by_date = Mod::TestByDate.new(2008,04,28)
124
+ # Pass an array of values directly to DateTime.civil:
125
+ @test_by_date_time = Mod::TestByDateTime.new([[2008,04,28,10,28,15]])
126
+ #@test_by_date_time = Mod::TestByDateTime.new(DateTime.new(2008,04,28,10,28,15))
127
+ @test_by_decimal = Mod::TestByDecimal.new('98765432109876543210')
128
+
129
+ @test_by_int_sub = Mod::TestByIntSub.new(2)
130
+ @test_by_real_sub = Mod::TestByRealSub.new(5.0)
131
+ @test_by_auto_counter_sub = Mod::TestByAutoCounterSub.new(6)
132
+ @test_by_auto_counter_new_sub = Mod::TestByAutoCounterSub.new(:new)
133
+ @test_by_string_sub = Mod::TestByStringSub.new("six")
134
+ @test_by_date_sub = Mod::TestByDateSub.new(Date.new(2008,04,27))
135
+ @test_by_date_time_sub = Mod::TestByDateTimeSub.new(2008,04,29,10,28,15)
136
+ @test_by_decimal_sub = Mod::TestByDecimalSub.new('98765432109876543210')
137
+
138
+ @test_by_int_entity = Mod::TestByIntEntity.new(@test_by_int)
139
+ @test_by_real_entity = Mod::TestByRealEntity.new(@test_by_real)
140
+ @test_by_auto_counter_entity = Mod::TestByAutoCounterEntity.new(@test_by_auto_counter)
141
+ @test_by_auto_counter_new_entity = Mod::TestByAutoCounterEntity.new(@test_by_auto_counter_new)
142
+ @test_by_string_entity = Mod::TestByStringEntity.new(@test_by_string)
143
+ @test_by_date_entity = Mod::TestByDateEntity.new(@test_by_date)
144
+ @test_by_date_time_entity = Mod::TestByDateTimeEntity.new(@test_by_date_time)
145
+ @test_by_decimal_entity = Mod::TestByDecimalEntity.new(@test_by_decimal)
146
+
147
+ # Entity subtypes
148
+ @test_sub_by_int = Mod::TestSubByInt.new(2)
149
+ @test_sub_by_real = Mod::TestSubByReal.new(2.0)
150
+ @test_sub_by_auto_counter = Mod::TestSubByAutoCounter.new(2)
151
+ @test_sub_by_auto_counter_new = Mod::TestSubByAutoCounter.new(:new)
152
+ @test_sub_by_string = Mod::TestSubByString.new("two")
153
+ @test_sub_by_date = Mod::TestSubByDate.new(Date.new(2008,04,28))
154
+ @test_sub_by_date_time = Mod::TestSubByDateTime.new(2008,04,28,10,28,15)
155
+ @test_sub_by_decimal = Mod::TestSubByDecimal.new('98765432109876543210')
156
+
157
+ # These arrays get zipped together in various ways. Keep them aligned.
158
+ @values = [
159
+ @int, @real, @auto_counter, @new_auto_counter,
160
+ @string, @date, @date_time, @decimal
161
+ ]
162
+ @classes = [
163
+ Int, Real, AutoCounter, AutoCounter,
164
+ String, Date, DateTime, Decimal
165
+ ]
166
+ @value_types = [
167
+ Mod::IntValue, Mod::RealValue, Mod::AutoCounterValue, Mod::AutoCounterValue,
168
+ Mod::StringValue, Mod::DateValue, Mod::DateTimeValue, Mod::DecimalValue,
169
+ Mod::IntSubValue, Mod::RealSubValue, Mod::AutoCounterSubValue, Mod::AutoCounterSubValue,
170
+ Mod::StringSubValue, Mod::DateSubValue, Mod::DateTimeSubValue, Mod::DecimalSubValue,
171
+ ]
172
+ @value_instances = [
173
+ @int_value, @real_value, @auto_counter_value, @new_auto_counter_value,
174
+ @string_value, @date_value, @date_time_value, @decimal_value,
175
+ @int_sub_value, @real_sub_value, @auto_counter_sub_value, @auto_counter_sub_value_new,
176
+ @string_sub_value, @date_sub_value, @date_time_sub_value, @decimal_sub_value,
177
+ @int_value, @real_value, @auto_counter_value, @new_auto_counter_value,
178
+ @string_value, @date_value, @date_time_value, @decimal_value,
179
+ ]
180
+ @entity_types = [
181
+ Mod::TestByInt, Mod::TestByReal, Mod::TestByAutoCounter, Mod::TestByAutoCounter,
182
+ Mod::TestByString, Mod::TestByDate, Mod::TestByDateTime, Mod::TestByDecimal,
183
+ Mod::TestByIntSub, Mod::TestByRealSub, Mod::TestByAutoCounterSub, Mod::TestByAutoCounterSub,
184
+ Mod::TestByStringSub, Mod::TestByDateSub, Mod::TestByDateTimeSub, Mod::TestByDecimalSub,
185
+ Mod::TestSubByInt, Mod::TestSubByReal, Mod::TestSubByAutoCounter, Mod::TestSubByAutoCounter,
186
+ Mod::TestSubByString, Mod::TestSubByDate, Mod::TestSubByDateTime, Mod::TestByDecimalEntity,
187
+ ]
188
+ @entities = [
189
+ @test_by_int, @test_by_real, @test_by_auto_counter, @test_by_auto_counter_new,
190
+ @test_by_string, @test_by_date, @test_by_date_time, @test_by_decimal,
191
+ @test_by_int_sub, @test_by_real_sub, @test_by_auto_counter_sub, @test_by_auto_counter_new_sub,
192
+ @test_by_string_sub, @test_by_date_sub, @test_by_date_time_sub, @test_by_decimal_sub,
193
+ @test_sub_by_int, @test_sub_by_real, @test_sub_by_auto_counter, @test_sub_by_auto_counter_new,
194
+ @test_sub_by_string, @test_sub_by_date, @test_sub_by_date_time, @test_sub_by_decimal,
195
+ ]
196
+ @entities_by_entity = [
197
+ @test_by_int_entity,
198
+ @test_by_real_entity,
199
+ @test_by_auto_counter_entity,
200
+ @test_by_auto_counter_new_entity,
201
+ @test_by_string_entity,
202
+ @test_by_date_entity,
203
+ @test_by_date_time_entity,
204
+ @test_by_decimal_entity,
205
+ ]
206
+ @entities_by_entity_types = [
207
+ Mod::TestByIntEntity, Mod::TestByRealEntity, Mod::TestByAutoCounterEntity, Mod::TestByAutoCounterEntity,
208
+ Mod::TestByStringEntity, Mod::TestByDateEntity, Mod::TestByDateTimeEntity, Mod::TestByDecimalEntity,
209
+ ]
210
+ @test_role_names = [
211
+ :int_value, :real_value, :auto_counter_value, :auto_counter_value,
212
+ :string_value, :date_value, :date_time_value, :decimal_value,
213
+ :int_sub_value, :real_sub_value, :auto_counter_sub_value, :auto_counter_sub_value,
214
+ :string_sub_value, :date_sub_value, :date_time_sub_value, :decimal_sub_value,
215
+ :int_value, :real_value, :auto_counter_value, :auto_counter_value,
216
+ :string_value, :date_value, :date_time_value, :decimal_value,
217
+ ]
218
+ @role_values = [
219
+ 3, 4.0, 5, 6,
220
+ "three", Date.new(2008,4,21), DateTime.new(2008,4,22,10,28,16),
221
+ '98765432109876543210'
222
+ ]
223
+ @role_alternate_values = [
224
+ 4, 5.0, 6, 7,
225
+ "four", Date.new(2009,4,21), DateTime.new(2009,4,22,10,28,16),
226
+ '98765432109876543211'
227
+ ]
228
+ @subtype_role_instances = [
229
+ Mod::IntSubValue.new(6), Mod::RealSubValue.new(6.0),
230
+ Mod::AutoCounterSubValue.new(:new), Mod::AutoCounterSubValue.new(8),
231
+ Mod::StringSubValue.new("seven"),
232
+ Mod::DateSubValue.new(2008,4,29), Mod::DateTimeSubValue.new(2008,4,30,10,28,16),
233
+ Mod::DecimalSubValue.new('98765432109876543210'),
234
+ ]
235
+ end
236
+
237
+ describe "verbalisation" do
238
+ it "if a value type, should verbalise" do
239
+ @value_types.each do |value_type|
240
+ #puts "#{value_type} verbalises as #{value_type.verbalise}"
241
+ value_type.respond_to?(:verbalise).should be_true
242
+ verbalisation = value_type.verbalise
243
+ verbalisation.should =~ %r{\b#{value_type.basename}\b}
244
+ verbalisation.should =~ %r{\b#{value_type.superclass.basename}\b}
245
+ end
246
+ end
247
+
248
+ it "if an entity type, should verbalise" do
249
+ @entity_types.each do |entity_type|
250
+ #puts entity_type.verbalise
251
+ entity_type.respond_to?(:verbalise).should be_true
252
+ verbalisation = entity_type.verbalise
253
+ verbalisation.should =~ %r{\b#{entity_type.basename}\b}
254
+
255
+ # All identifying roles should be in the verbalisation.
256
+ # Strictly this should be the role name, but we don't set names here.
257
+ entity_type.identifying_role_names.each do |ir|
258
+ role = entity_type.roles(ir)
259
+ role.should_not be_nil
260
+ counterpart_object_type = role.counterpart.object_type
261
+ verbalisation.should =~ %r{\b#{counterpart_object_type.basename}\b}
262
+ end
263
+ end
264
+ end
265
+
266
+ it "should inspect" do
267
+ (@value_instances+@entities+@entities_by_entity).each do |object|
268
+ object.inspect
269
+ end
270
+ end
271
+
272
+ it "if a value, should verbalise" do
273
+ @value_instances.each do |value|
274
+ #puts value.verbalise
275
+ value.respond_to?(:verbalise).should be_true
276
+ verbalisation = value.verbalise
277
+ verbalisation.should =~ %r{\b#{value.class.basename}\b}
278
+ end
279
+ end
280
+
281
+ it "if an entity, should respond to verbalise" do
282
+ (@entities+@entities_by_entity).each do |entity|
283
+ #puts entity.verbalise
284
+ entity.respond_to?(:verbalise).should be_true
285
+ verbalisation = entity.verbalise
286
+ verbalisation.should =~ %r{\b#{entity.class.basename}\b}
287
+ entity.class.identifying_role_names.each do |ir|
288
+ role = entity.class.roles(ir)
289
+ role.should_not be_nil
290
+ counterpart_object_type = role.counterpart.object_type
291
+ verbalisation.should =~ %r{\b#{counterpart_object_type.basename}\b}
292
+ end
293
+ end
294
+ end
295
+ end
296
+
297
+ it "should respond to constellation" do
298
+ (@value_instances+@entities+@entities_by_entity).each do |instance|
299
+ instance.respond_to?(:constellation).should be_true
300
+ end
301
+ end
302
+
303
+ it "should return the module in response to .vocabulary()" do
304
+ (@value_types+@entity_types).zip((@value_instances+@entities+@entities_by_entity)).each do |object_type, instance|
305
+ instance.class.vocabulary.should == Mod
306
+ end
307
+ end
308
+
309
+ it "should disallow treating an unresolved AutoCounter as an integer" do
310
+ c = ActiveFacts::API::Constellation.new(Mod)
311
+ a = c.AutoCounterValue(:new)
312
+ lambda {
313
+ b = 2 + a
314
+ }.should raise_error
315
+ a.assign(3)
316
+ lambda {
317
+ b = 2 + a
318
+ a.to_i
319
+ }.should_not raise_error
320
+ end
321
+
322
+ it "should complain when not enough identifying values are provided for an entity" do
323
+ c = ActiveFacts::API::Constellation.new(Mod)
324
+ lambda {
325
+ c.TestByInt(:int_value => nil)
326
+ }.should raise_error
327
+ end
328
+
329
+ it "should complain when too many identifying values are provided for an entity" do
330
+ c = ActiveFacts::API::Constellation.new(Mod)
331
+ lambda {
332
+ c.TestByInt(2, 3)
333
+ }.should raise_error
334
+ end
335
+
336
+ it "should handle a non-mandatory missing identifying role" do
337
+ module Mod2
338
+ class Word
339
+ identified_by :singular, :plural
340
+ has_one :singular, :class => "Spelling", :mandatory => true
341
+ has_one :plural, :class => "Spelling"
342
+ end
343
+ class Spelling < String
344
+ value_type
345
+ end
346
+ end
347
+ c = ActiveFacts::API::Constellation.new(Mod2)
348
+ s = c.Word('sheep')
349
+ f = c.Word('fish', :plural => nil)
350
+ a = c.Word('aircraft', nil)
351
+ s.plural.should be_nil
352
+ f.plural.should be_nil
353
+ a.plural.should be_nil
354
+ end
355
+
356
+ it "should handle a unary as an identifying role" do
357
+ module Mod2
358
+ class Status
359
+ identified_by :is_ok
360
+ maybe :is_ok
361
+ end
362
+ end
363
+ c = ActiveFacts::API::Constellation.new(Mod2)
364
+
365
+ n = c.Status(:is_ok => nil)
366
+ t = c.Status(:is_ok => true)
367
+ f = c.Status(:is_ok => false)
368
+ s = c.Status(:is_ok => 'foo')
369
+ n.is_ok.should == nil
370
+ t.is_ok.should == true
371
+ f.is_ok.should == false
372
+ s.is_ok.should == true
373
+
374
+ n.is_ok = nil
375
+ t.is_ok = true
376
+ f.is_ok = false
377
+ s.is_ok = true
378
+ n.is_ok.should == nil
379
+ t.is_ok.should == true
380
+ f.is_ok.should == false
381
+ s.is_ok.should == true
382
+ end
383
+
384
+ end