activefacts-api 1.8.1 → 1.8.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,439 +0,0 @@
1
- #
2
- # ActiveFacts tests: Value instances in the Runtime API
3
- # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
- #
5
-
6
- VALUE_TYPES = Int, Real, AutoCounter, String, Date, DateTime, Decimal, Guid
7
- RAW_VALUES = [2, 3.0, 4, "5", Date.new(2008, 04, 20), DateTime.new(2008, 04, 20, 10, 28, 14), '43210.98765', '01234567-89ab-cdef-0123-456789abcdef']
8
- ALT_VALUES = [3, 4.0, 5, "6", Date.new(2009, 04, 20), DateTime.new(2009, 04, 20, 10, 28, 14), '56789.01234', 'fedcba987654-3210-fedc-ba98-76543210']
9
- VALUE_SUB_FOR_VALUE = {}
10
- VALUES_FOR_TYPE = VALUE_TYPES.zip(RAW_VALUES, ALT_VALUES).inject({}) do |h, (vt, v1, v2)|
11
- next h unless v1 and v2
12
- h[vt] = [v1, v2]
13
- h
14
- end
15
- VALUE_TYPE_FOR_OBJECT_TYPE = {}
16
- OBJECT_TYPES = []
17
-
18
- module TestValueTypesModule
19
- class ESCID < AutoCounter
20
- value_type
21
- end
22
- BASE_VALUE_TYPE_ROLE_NAMES = VALUE_TYPES.map { |base_type| base_type.name.snakecase }
23
- VALUE_TYPE_ROLE_NAMES = BASE_VALUE_TYPE_ROLE_NAMES.map { |n| [ :"#{n}_val", :"#{n}_sub_val" ] }.flatten
24
-
25
- TestValueTypesModule.module_eval <<-END
26
- class Extra < String
27
- value_type
28
- end
29
- END
30
-
31
- VALUE_TYPES.each do |value_type|
32
- code = <<-END
33
- class #{value_type.name}Val < #{value_type.name}
34
- value_type
35
- has_one :extra
36
- end
37
-
38
- class #{value_type.name}ValSub < #{value_type.name}Val
39
- # Note no new "value_type" is required here, it comes through inheritance
40
- end
41
-
42
- class #{value_type.name}Entity
43
- identified_by :#{identifying_role_name = "id_#{value_type.name.snakecase}_val"}
44
- one_to_one :#{identifying_role_name}, :class => #{value_type.name}Val
45
- has_one :extra
46
- end
47
-
48
- class #{value_type.name}EntitySub < #{value_type.name}Entity
49
- end
50
-
51
- class #{value_type.name}EntitySubCtr < #{value_type.name}Entity
52
- identified_by :counter
53
- one_to_one :counter, :class => "ESCID"
54
- end
55
-
56
- VALUE_SUB_FOR_VALUE[#{value_type.name}Val] = #{value_type.name}ValSub
57
- classes = [
58
- #{value_type.name}Val,
59
- #{value_type.name}ValSub,
60
- #{value_type.name}Entity,
61
- #{value_type.name}EntitySub,
62
- #{value_type.name}EntitySubCtr,
63
- ]
64
- OBJECT_TYPES.concat(classes)
65
- classes.each { |klass| VALUE_TYPE_FOR_OBJECT_TYPE[klass] = value_type }
66
- END
67
- TestValueTypesModule.module_eval code
68
- end
69
- OBJECT_TYPE_NAMES = OBJECT_TYPES.map{|object_type| object_type.basename}
70
-
71
- class Octopus
72
- identified_by :zero
73
- one_to_one :zero, :class => IntVal
74
- maybe :has_a_unary
75
- OBJECT_TYPE_NAMES.each do |object_type_name|
76
- has_one object_type_name.snakecase.to_sym
77
- one_to_one ("one_"+object_type_name.snakecase).to_sym, :class => object_type_name
78
- end
79
- end
80
- end
81
-
82
- describe "Roles of an Object Type" do
83
-
84
- it "should return a roles collection" do
85
- roles = TestValueTypesModule::Octopus.all_role
86
- roles.should_not be_nil
87
- roles.size.should == 2+VALUE_TYPES.size*5*2
88
-
89
- # Quick check of role metadata:
90
- roles.each do |role_name, role|
91
- role.object_type.modspace.should == TestValueTypesModule
92
- if !role.counterpart
93
- role.should be_unary
94
- else
95
- role.counterpart.object_type.modspace.should == TestValueTypesModule
96
- end
97
- end
98
- end
99
- end
100
-
101
- describe "Object type role values" do
102
- def object_identifying_parameters object_type_name, value
103
- if object_type_name =~ /^(.*)EntitySubCtr$/
104
- [{ :"id_#{$1.snakecase}_val" => value, :counter => :new}]
105
- else
106
- [value]
107
- end
108
- end
109
-
110
- =begin
111
- describe "Instantiating bare objects" do
112
- OBJECT_TYPES.each do |object_type|
113
- required_value_type = VALUE_TYPE_FOR_OBJECT_TYPE[object_type]
114
- object_type_name = object_type.basename
115
- values = VALUES_FOR_TYPE[required_value_type]
116
- next unless values
117
-
118
- it "should allow instantiation of a bare #{object_type_name}" do
119
- object_identifying_parameters =
120
- if object_type_name =~ /^(.*)EntitySubCtr$/
121
- [{ :"id_#{$1.snakecase}_val" => values[0], :counter => :new}]
122
- else
123
- [values[0]]
124
- end
125
- object = object_type.new(*object_identifying_parameters)
126
- object.class.should == object_type
127
- object.constellation.should be_nil
128
- end
129
- end
130
- end
131
- =end
132
-
133
- describe "A constellation" do
134
- before :each do
135
- @constellation = ActiveFacts::API::Constellation.new(TestValueTypesModule)
136
- end
137
-
138
- OBJECT_TYPES.each do |object_type|
139
- required_value_type = VALUE_TYPE_FOR_OBJECT_TYPE[object_type]
140
- object_type_name = object_type.basename
141
- values = VALUES_FOR_TYPE[required_value_type]
142
-
143
- it "should return an initially empty instance index collection for #{object_type_name}" do
144
- @constellation.send(object_type_name).should be_empty
145
- end
146
-
147
- next unless values
148
-
149
- it "should allow assertion of an #{object_type_name} instance using #{values[0].inspect}" do
150
- # REVISIT: Assertion of a subtype having the same identifier as a supertype is... dodgey.
151
- # What should it do? Migrate the previous object to its subtype?
152
- object = @constellation.send(object_type_name, *object_identifying_parameters(object_type_name, values[0]))
153
-
154
- # Make sure we got what we expected:
155
- object.class.should == object_type
156
-
157
- # Make sure the instance index contains this single object:
158
- instances = @constellation.send(object_type_name)
159
- instances.size.should == 1
160
- instances.map{|k,o| o}.first.should == object
161
- unless object.class.is_entity_type
162
- # Look up value types using the value instance, not just the raw value:
163
- instances[object.identifying_role_values].should == object
164
- end
165
-
166
- # Make sure all the identifying roles are populated correctly:
167
- if object_type.respond_to?(:identifying_roles)
168
- object.class.identifying_roles.each do |identifying_role|
169
- identifying_value = object.send(identifying_role.name)
170
- identifying_value.should_not be_nil
171
-
172
- counterpart_object_type = identifying_role.counterpart.object_type
173
- role_superclasses = [ counterpart_object_type.superclass, counterpart_object_type.superclass.superclass ]
174
- # Autocounter values do not compare to Integers:
175
- unless role_superclasses.include?(AutoCounter) or identifying_role.object_type.basename =~ /Entity/
176
- identifying_value.should == identifying_role.object_type.new(*values[0])
177
- end
178
- end
179
- end
180
- end
181
-
182
- if object_type.is_entity_type
183
- it "should allow re-assigning a #{object_type_name} entity's identifying role value from #{values[0]} to #{values[1]}" do
184
- object = @constellation.send(object_type_name, *object_identifying_parameters(object_type_name, values[0]))
185
- object.class.identifying_roles.each do |identifying_role|
186
- next if identifying_role.name == :counter
187
- lambda {
188
- object.send(:"#{identifying_role.name}=", values[1])
189
- }.should_not raise_error
190
- end
191
- end
192
-
193
- it "should allow nullifying and reassigning a #{object_type_name} entity's identifying role value" do
194
- object = @constellation.send(object_type_name, *object_identifying_parameters(object_type_name, values[0]))
195
- object.class.identifying_roles.each do |identifying_role|
196
- next if [:counter, :id_guid_val].include?(identifying_role.name)
197
- assigned = object.send(:"#{identifying_role.name}=", nil)
198
- assigned.should be_nil
199
- object.send(:"#{identifying_role.name}=", values[1])
200
- end
201
- end
202
- else
203
- it "should allow initialising value type #{object_type.name} with an instance of that value type" do
204
- params = object_identifying_parameters(object_type_name, values[0])
205
- if object_type.respond_to?(:civil)
206
- # Handle Date/Time specially:
207
- bare_value = object_type.civil(params[0].year)
208
- else
209
- bare_value = object_type.new(*params)
210
- end
211
- object = @constellation.send(object_type_name, bare_value)
212
- # Here, the bare_value is not the same object which has been added to the constellatiom
213
-
214
- # Now link the bare value to an Octopus:
215
- octopus = @constellation.Octopus(0)
216
- octopus_role_name = :"octopus_as_one_#{object_type_name.snakecase}"
217
- object.send(:"#{octopus_role_name}=", octopus)
218
- counterpart_name = object.class.all_role[octopus_role_name].counterpart.name
219
-
220
- # Create a reference by assigning the object from a RoleProxy:
221
- proxy = octopus.send(counterpart_name)
222
-
223
- #proxy.should be_respond_to(:__getobj__)
224
- object2 = @constellation.send(object_type_name, proxy)
225
- object2.should == object
226
- end
227
-
228
- it "should allow adding extra role assignments when asserting an instance" do
229
- object = @constellation.send(object_type_name, *(object_identifying_parameters(object_type_name, values[0]) + [{:extra => 'foo'}]))
230
- object.extra.should == 'foo'
231
- end
232
-
233
- end
234
- end
235
-
236
- end
237
-
238
- describe "Role values" do
239
- before :each do
240
- @constellation = ActiveFacts::API::Constellation.new(TestValueTypesModule)
241
- @object = @constellation.Octopus(0)
242
- @roles = @object.class.all_role
243
- end
244
-
245
- it "should return its constellation and vocabulary" do
246
- # Strictly, these are not role value tests
247
- @object.constellation.should == @constellation
248
- @object.constellation.vocabulary.should == TestValueTypesModule
249
- @object.class.vocabulary.should == TestValueTypesModule
250
- end
251
-
252
- TestValueTypesModule::Octopus.all_role.each do |role_name, role|
253
- next if role_name == :zero
254
-
255
- it "should respond to getting its #{role_name} role" do
256
- @object.should be_respond_to role.name
257
- end
258
-
259
- it "should respond to setting its #{role_name} role" do
260
- @object.should be_respond_to :"#{role.name}="
261
- end
262
-
263
- if role.unary?
264
- it "should allow its #{role_name} unary role to be assigned and reassigned" do
265
- @object.has_a_unary.should be_nil
266
- @object.has_a_unary = true
267
- @object.has_a_unary.should == true
268
- @object.has_a_unary = 23
269
- @object.has_a_unary.should == true
270
- @object.has_a_unary = false
271
- @object.has_a_unary.should be false
272
- @object.has_a_unary = nil
273
- @object.has_a_unary.should be_nil
274
- end
275
- else
276
- it "should allow its #{role_name} role to be assigned and reassigned a base value" do
277
- object_type = role.counterpart.object_type
278
- required_value_type = VALUE_TYPE_FOR_OBJECT_TYPE[object_type]
279
- values = VALUES_FOR_TYPE[required_value_type]
280
- next unless values
281
- value = object_identifying_parameters(object_type.basename, values[0])
282
-
283
- # Set the role to the first value:
284
- assigned = @object.send(:"#{role_name}=", value)
285
- assigned.class.should == object_type
286
- fetched = @object.send(role_name)
287
- fetched.should == assigned
288
-
289
- if role.counterpart.unique # A one-to-one
290
- # The counterpart should point back at us
291
- assigned.send(role.counterpart.name).should == @object
292
- else # A many-to-one
293
- # The counterpart should include us in its RoleValues
294
- reflection = assigned.send(role.counterpart.name)
295
- reflection.should_not be_empty
296
- reflection.size.should == 1
297
- reflection.should include @object
298
- end
299
-
300
- # Update the role to the second value:
301
- value = object_identifying_parameters(object_type.basename, values[1])
302
- assigned2 = @object.send(:"#{role_name}=", value)
303
- assigned2.class.should == object_type
304
- fetched = @object.send(role_name)
305
- fetched.should == assigned2
306
-
307
- if role.counterpart.unique # A one-to-one
308
- # REVISIT: The old counterpart role should be nullified
309
- #assigned.send(role.counterpart.name).should be_nil
310
-
311
- # The counterpart should point back at us
312
- assigned2.send(role.counterpart.name).should == @object
313
- else # A many-to-one
314
- # REVISIT: The old counterpart RoleValues should be empty
315
- reflection = assigned2.send(role.counterpart.name)
316
- #reflection.size.should == 0
317
-
318
- # The counterpart should include us in its RoleValues
319
- reflection2 = assigned2.send(role.counterpart.name)
320
- reflection2.size.should == 1
321
- reflection2.should include @object
322
- end
323
-
324
- # Nullify the role
325
- nullified = @object.send(:"#{role_name}=", nil)
326
- nullified.should be_nil
327
- if role.counterpart.unique # A one-to-one
328
- assigned2.send(role.counterpart.name).should be_nil
329
- else # A many-to-one
330
- reflection3 = assigned2.send(role.counterpart.name)
331
- reflection3.size.should == 0
332
- end
333
- end
334
-
335
- it "should allow its #{role_name} role to be assigned and reassigned a base value" do
336
- object_type = role.counterpart.object_type
337
- required_value_type = VALUE_TYPE_FOR_OBJECT_TYPE[object_type]
338
- values = VALUES_FOR_TYPE[required_value_type]
339
- next unless values
340
- value = object_identifying_parameters(object_type.basename, values[0])
341
-
342
- # Set the role to the first value:
343
- assigned = @object.send(:"#{role_name}=", value)
344
- fetched = @object.send(role_name)
345
- fetched.class.should == object_type
346
- end
347
-
348
- it "should allow its #{role_name} role to be assigned a value instance" do
349
- object_type = role.counterpart.object_type
350
- required_value_type = VALUE_TYPE_FOR_OBJECT_TYPE[object_type]
351
- values = VALUES_FOR_TYPE[required_value_type]
352
- next unless values
353
- value = @constellation.send(object_type.basename, *object_identifying_parameters(object_type.basename, values[0]))
354
-
355
- assigned = @object.send(:"#{role_name}=", value)
356
- assigned.class.should == object_type
357
- fetched = @object.send(role_name)
358
- fetched.should == assigned
359
-
360
- # Nullify the role
361
- nullified = @object.send(:"#{role_name}=", nil)
362
- nullified.should be_nil
363
- end
364
-
365
- it "should allow its #{role_name} role to be assigned a value subtype instance, retaining the subtype" do
366
- object_type = role.counterpart.object_type
367
- required_value_type = VALUE_TYPE_FOR_OBJECT_TYPE[object_type] # The raw value type
368
- values = VALUES_FOR_TYPE[required_value_type]
369
- object_type = VALUE_SUB_FOR_VALUE[object_type] # The value type subtype
370
- next unless values and object_type
371
- value = @constellation.send(object_type.basename, *object_identifying_parameters(object_type.basename, values[0]))
372
- assigned = @object.send(:"#{role_name}=", value)
373
- # This requires the declared type, not the subtype:
374
- # assigned.class.should == role.counterpart.object_type
375
- # This requires the subtype, as the test implies:
376
- assigned.class.should == object_type
377
- fetched = @object.send(role_name)
378
- fetched.should == assigned
379
- end
380
- end
381
-
382
- unless !role.counterpart or # A unary
383
- role.counterpart.unique or # A one-to-one
384
- VALUES_FOR_TYPE[VALUE_TYPE_FOR_OBJECT_TYPE[role.counterpart.object_type]] == nil
385
- describe "Operations on #{role.counterpart.object_type.basename} RoleValues collections" do
386
- before :each do
387
- object_type = role.counterpart.object_type
388
- required_value_type = VALUE_TYPE_FOR_OBJECT_TYPE[object_type]
389
- values = VALUES_FOR_TYPE[required_value_type]
390
- return unless values
391
- value = object_identifying_parameters(object_type.basename, values[0])
392
- assigned = @object.send(:"#{role_name}=", value)
393
- @role_values = assigned.send(role.counterpart.name)
394
- end
395
-
396
- it "should support Array addition" do
397
- added = @role_values + ["foo"]
398
- added.class.should == Array
399
- added.size.should == 2
400
- end
401
-
402
- it "should support Array subtraction" do
403
- # We only added one value, so subtracting it leaves us empty
404
- counterpart_value = @role_values.single
405
- (@role_values - [counterpart_value]).should be_empty
406
- end
407
-
408
- it "should support each" do
409
- count = 0
410
- @role_values.each do |v, *a|
411
- a.size.should == 0
412
- v.should_not be_nil
413
- count += 1
414
- end
415
- count.should == 1
416
- end
417
-
418
- it "should support detect" do
419
- count = 0
420
- @role_values.detect do |v, *a|
421
- a.size.should == 0
422
- v.should_not be_nil
423
- count += 1
424
- false
425
- end
426
- count.should == 1
427
- end
428
-
429
- it "should verbalise" do
430
- @role_values.verbalise.should =~ /Octopus.*Zero '0'/
431
- end
432
-
433
- end
434
- end
435
-
436
- end
437
-
438
- end
439
- end
@@ -1,283 +0,0 @@
1
- #
2
- # ActiveFacts tests: Roles of object_type classes in the Runtime API
3
- # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
- #
5
-
6
- describe "Roles" do
7
- before :each do
8
- Object.send :remove_const, :Mod if Object.const_defined?("Mod")
9
- module Mod
10
- class Name < String
11
- value_type :length => 40, :scale => 0, :restrict => /^[A-Z][a-z0-9]*/
12
- end
13
- class Identifier
14
- identified_by :name
15
- one_to_one :name
16
- end
17
- class LegalEntity
18
- identified_by :name
19
- one_to_one :name
20
- end
21
- class Contract
22
- identified_by :first, :second
23
- has_one :first, :class => LegalEntity
24
- has_one :second, :class => LegalEntity
25
- end
26
- class Person < LegalEntity
27
- # identified_by # No identifier needed, inherit from superclass
28
- # New identifier:
29
- identified_by :family, :name
30
- has_one :family, :class => Name
31
- alias :given :name
32
- alias :given= :name=
33
- has_one :related_to, :class => LegalEntity
34
- end
35
- class Employee
36
- identified_by :name
37
- one_to_one :identifier
38
- one_to_one :name
39
- end
40
- end
41
- # print "object_type: "; p Mod.object_type
42
- end
43
-
44
- it "should associate a role name with a matching existing object_type" do
45
- module Mod
46
- class Existing1 < String
47
- value_type
48
- has_one :name
49
- end
50
- end
51
- role = Mod::Existing1.all_role(:name)
52
- role.should_not be_nil
53
- role.inspect.class.should == String
54
- role.counterpart.object_type.should == Mod::Name
55
- end
56
-
57
- it "should prevent association of a role name with an object_type from the wrong module" do
58
- lambda {
59
- module Mod2
60
- class Unrelated
61
- end
62
- end
63
-
64
- module Mod
65
- class Existing1 < String
66
- value_type
67
- has_one :unrelated, :class => Mod2::Unrelated
68
- end
69
- end
70
- }.should raise_error(ActiveFacts::API::CrossVocabularyRoleException)
71
- end
72
-
73
- it "should prevent association of a role name with a non-object_type" do
74
- lambda {
75
- module Mod
76
- class NonObject
77
- end
78
- class Existing1 < String
79
- value_type
80
- has_one :non_object, :class => NonObject
81
- end
82
- end
83
- }.should raise_error(ActiveFacts::API::CrossVocabularyRoleException)
84
- end
85
-
86
- it "should prevent association of a role name with an implied non-object_type" do
87
- lambda {
88
- module Mod
89
- class NonObject
90
- end
91
- class Existing1 < String
92
- value_type
93
- has_one :non_object
94
- end
95
- end
96
- }.should raise_error(ActiveFacts::API::CrossVocabularyRoleException)
97
- end
98
-
99
- it "should prevent usage of undefined options on a role" do
100
- lambda {
101
- module Mod
102
- class Existing1 < String
103
- value_type
104
- has_one :name, :foo => :anything
105
- end
106
- end
107
- }.should raise_error(ActiveFacts::API::UnrecognisedOptionsException)
108
-
109
- lambda {
110
- module Mod
111
- class Existing1 < String
112
- value_type
113
- one_to_one :name, :foo => :anything
114
- end
115
- end
116
- }.should raise_error(ActiveFacts::API::UnrecognisedOptionsException)
117
-
118
- lambda {
119
- module Mod
120
- class Existing1 < String
121
- value_type
122
- maybe :is_broken, :foo => :anything
123
- end
124
- end
125
- }.should raise_error(ActiveFacts::API::UnrecognisedOptionsException)
126
- end
127
-
128
- it "should provide value type metadata" do
129
- Mod::Name.length.should == 40
130
- Mod::Name.scale.should == 0
131
- end
132
-
133
- it "should inject the respective role name into the matching object_type" do
134
- module Mod
135
- class Existing1 < String
136
- value_type
137
- has_one :name
138
- end
139
- end
140
- # REVISIT: need to make more tests for the class's role accessor methods:
141
- Mod::Name.all_role(:all_existing1).should == Mod::Name.all_existing1_role
142
-
143
- Mod::Name.all_role(:all_existing1).should_not be_nil
144
- Mod::LegalEntity.all_role(:all_contract_as_first).should_not be_nil
145
- end
146
-
147
- it "should associate a role name with a matching object_type after it's created" do
148
- module Mod
149
- class Existing2 < String
150
- value_type
151
- has_one :given_name
152
- end
153
- end
154
- # print "Mod::Existing2.all_role = "; p Mod::Existing2.all_role
155
- r = Mod::Existing2.all_role(:given_name)
156
- r.should_not be_nil
157
- r.counterpart.should be_nil
158
- module Mod
159
- class GivenName < String
160
- value_type
161
- end
162
- end
163
- # puts "Should resolve now:"
164
- r = Mod::Existing2.all_role(:given_name)
165
- r.should_not be_nil
166
- r.counterpart.object_type.should == Mod::GivenName
167
- end
168
-
169
- it "should handle subtyping a value type" do
170
- module Mod
171
- class FamilyName < Name
172
- value_type
173
- one_to_one :patriarch, :class => Person
174
- end
175
- end
176
- r = Mod::FamilyName.all_role(:patriarch)
177
- r.should_not be_nil
178
- r.counterpart.object_type.should == Mod::Person
179
- r.counterpart.object_type.all_role(:family_name_as_patriarch).counterpart.object_type.should == Mod::FamilyName
180
- end
181
-
182
- it "should instantiate the matching object_type on assignment" do
183
- c = ActiveFacts::API::Constellation.new(Mod)
184
- bloggs = c.LegalEntity("Bloggs")
185
- acme = c.LegalEntity("Acme, Inc")
186
- contract = c.Contract("Bloggs", acme)
187
- #contract = c.Contract("Bloggs", "Acme, Inc")
188
- contract.first.should == bloggs
189
- contract.second.should == acme
190
- end
191
-
192
- it "should append the counterpart into the respective role array in the matching object_type" do
193
- c = ActiveFacts::API::Constellation.new(Mod)
194
- foo = c.Name("Foo")
195
- le = c.LegalEntity(foo)
196
- le.respond_to?(:name).should be true
197
- name = le.name
198
- name.respond_to?(:legal_entity).should be true
199
-
200
- #pending
201
- [name.legal_entity].should === [le]
202
- end
203
-
204
- it "should instantiate subclasses sensibly" do
205
- c = ActiveFacts::API::Constellation.new(Mod)
206
- bloggs = c.LegalEntity("Bloggs & Co")
207
- p = c.Person("Fred", "Bloggs")
208
- p.related_to = "Bloggs & Co"
209
- p.related_to.should be_an_instance_of Mod::LegalEntity
210
- p.related_to.should == bloggs
211
-
212
- # REVISIT: The raw instance doesn't override == to compare itself to a RoleProxy unfortunately...
213
- # So this test succeeds when we'd like it to fail
214
- #bloggs.should_not == p.related_to
215
- end
216
-
217
- it "should forward missing methods on the role proxies" do
218
- c = ActiveFacts::API::Constellation.new(Mod)
219
- p = c.Person("Fred", "Bloggs")
220
- lambda {p.family.foo}.should raise_error(NoMethodError)
221
- end
222
-
223
- it "should forward re-raise exceptions from missing methods on the role proxies" do
224
- c = ActiveFacts::API::Constellation.new(Mod)
225
- p = c.Person("Fred", "Bloggs")
226
- class String
227
- def foo
228
- raise "Yawning"
229
- end
230
- end
231
-
232
- lambda {p.family.foo}.should raise_error(RuntimeError)
233
- end
234
-
235
- it "should be able to import an entity from another constellation" do
236
- c1 = ActiveFacts::API::Constellation.new(Mod)
237
- c2 = ActiveFacts::API::Constellation.new(Mod)
238
-
239
- e = c1.Employee("PuppetMaster")
240
- identifier = c2.Identifier "Project2501", :employee => e
241
- identifier.employee.name.should == "PuppetMaster"
242
- end
243
-
244
- it "should create TypeInheritance fact type and roles" do
245
- module Mod
246
- class GivenName < Name
247
- end
248
- class Document
249
- identified_by :name
250
- one_to_one :name
251
- end
252
- class Contract
253
- supertypes Document
254
- end
255
- end
256
- [Mod::GivenName, Mod::Person, Mod::Contract].each do |subtype|
257
- subtype.supertypes.each do |supertype|
258
- # Get the role names:
259
- supertype_role_name = supertype.name.gsub(/.*::/,'').to_sym
260
- subtype_role_name = subtype.name.gsub(/.*::/,'').to_sym
261
-
262
- # Check that the roles are indexed:
263
- subtype.all_role.should include(supertype_role_name)
264
- supertype.all_role.should include(subtype_role_name)
265
-
266
- # Get the role objects:
267
- supertype_role = subtype.all_role[supertype_role_name]
268
- subtype_role = supertype.all_role[subtype_role_name]
269
-
270
- # Check uniqueness and mandatory:
271
- supertype_role.unique.should be true
272
- subtype_role.unique.should be true
273
- supertype_role.mandatory.should be true
274
- subtype_role.mandatory.should be false
275
-
276
- # Check they belong to the same TypeInheritanceFactType:
277
- subtype_role.fact_type.class.should be(ActiveFacts::API::TypeInheritanceFactType)
278
- subtype_role.fact_type.should == supertype_role.fact_type
279
- end
280
- end
281
- end
282
-
283
- end