activefacts-api 1.8.1 → 1.8.3

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.
@@ -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