activefacts-api 0.8.9 → 0.8.10

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.
@@ -2,6 +2,7 @@
2
2
  # ActiveFacts tests: Value instances 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 "AutoCounter Value Type instances" do
@@ -51,9 +52,13 @@ describe "AutoCounter Value Type instances" do
51
52
  }.should raise_error
52
53
  end
53
54
 
54
- it "should not allow its identifying roles to be assigned" do
55
+ it "should not allow its value to be re-assigned" do
55
56
  lambda {
56
- @thing.thing_id = @thing_id
57
+ @thing.thing_id.assign(3)
58
+ }.should_not raise_error
59
+ lambda {
60
+ @thing.thing_id.assign(4)
61
+ #@thing.thing_id.assign(@thing_id)
57
62
  }.should raise_error
58
63
  end
59
64
 
@@ -77,8 +82,8 @@ describe "AutoCounter Value Type instances" do
77
82
  facets = []
78
83
  facets << @constellation.ThingFacet(thing, 0)
79
84
  facets << @constellation.ThingFacet(thing, 1)
80
- facets[0].thing.object_id.should == facets[1].thing.object_id
81
- facets[0].thing.thing_id.object_id.should == facets[1].thing.thing_id.object_id
85
+ facets[0].thing.should be_eql(facets[1].thing)
86
+ facets[0].thing.thing_id.should be_eql(facets[1].thing.thing_id)
82
87
  end
83
88
 
84
89
  end
@@ -0,0 +1,434 @@
1
+ #
2
+ # ActiveFacts tests: Constellation instances in the Runtime API
3
+ # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
4
+ #
5
+
6
+ require 'rspec'
7
+ require 'activefacts/api'
8
+
9
+ describe "A Constellation instance" do
10
+ before :each do
11
+ Object.send :remove_const, :Mod if Object.const_defined?("Mod")
12
+ module Mod
13
+ @base_types = [
14
+ Int, Real, AutoCounter, String, Date, DateTime
15
+ ]
16
+
17
+ # Create a value type and a subtype of that value type for each base type:
18
+ @base_types.each do |base_type|
19
+ eval <<-END
20
+ class #{base_type.basename}Value < #{base_type.name}
21
+ value_type
22
+ end
23
+
24
+ class #{base_type.basename}SubValue < #{base_type.name}Value
25
+ # Note no new "value_type" is required here, it comes through inheritance
26
+ end
27
+ END
28
+ end
29
+
30
+ class Name < StringValue
31
+ value_type
32
+ #has_one :attr, Name
33
+ end
34
+
35
+ class LegalEntity
36
+ identified_by :name
37
+ has_one :name, :mandatory => true
38
+ end
39
+
40
+ class SurrogateId
41
+ identified_by :auto_counter_value
42
+ has_one :auto_counter_value
43
+ end
44
+
45
+ class Company < LegalEntity
46
+ supertypes SurrogateId
47
+ end
48
+
49
+ class Person < LegalEntity
50
+ identified_by :name, :family_name # REVISIT: want a way to role_alias :name, :given_name
51
+ supertypes :surrogate_id # Use a Symbol binding this time
52
+
53
+ has_one :family_name, :class => Name
54
+ has_one :employer, :class => Company
55
+ one_to_one :birth_name, :class => Name
56
+ end
57
+ end
58
+ @constellation = ActiveFacts::API::Constellation.new(Mod)
59
+ end
60
+
61
+ describe "Vocabulary" do
62
+ it "should create the constellation" do
63
+ Mod.constellation.should be_is_a ActiveFacts::API::Constellation
64
+ end
65
+
66
+ it "should create the constellation by direct populate" do
67
+ Mod.populate do
68
+ Name "foo"
69
+ end.should be_is_a ActiveFacts::API::Constellation
70
+ end
71
+
72
+ it "should verbalise" do
73
+ s = Mod.verbalise
74
+ s.should be_is_a String
75
+ end
76
+ end
77
+
78
+ it "should allow creating a constellation" do
79
+ @constellation = ActiveFacts::API::Constellation.new(Mod)
80
+ end
81
+
82
+ it "should complain when accessing a non-class as a method" do
83
+ Mod::Foo = 23
84
+ lambda { @constellation.Foo }.should raise_error
85
+ end
86
+
87
+ it "should complain when accessing a class that isn't an object type" do
88
+ class Mod::Bar; end
89
+ lambda { @constellation.Bar }.should raise_error
90
+ end
91
+
92
+ it "should allow inspection" do
93
+ lambda { @constellation.inspect }.should_not raise_error
94
+ end
95
+
96
+ it "should support fetching its vocabulary" do
97
+ @constellation.vocabulary.should == Mod
98
+ end
99
+
100
+ # it "should support fetching its query" do
101
+ # pending
102
+ # @constellation.query.should == Mod
103
+ # end
104
+
105
+ it "should support methods to assert instances via the instance index for that type" do
106
+ name = foo = acme = fred_fly = nil
107
+ lambda {
108
+ name = @constellation.Name("foo")
109
+ foo = @constellation.LegalEntity("foo")
110
+ acme = @constellation.Company("Acme, Inc", :auto_counter_value => :new)
111
+ fred_fly = @constellation.Person("fred", "fly", :auto_counter_value => :new)
112
+ }.should_not raise_error
113
+ name.class.should == Mod::Name
114
+ name.constellation.should == @constellation
115
+
116
+ foo.class.should == Mod::LegalEntity
117
+ foo.constellation.should == @constellation
118
+ foo.inspect.should =~ / in Conste/
119
+ foo.verbalise.should =~ /LegalEntity\(/
120
+
121
+ acme.class.should == Mod::Company
122
+ acme.constellation.should == @constellation
123
+ acme.inspect.should =~ / in Conste/
124
+ acme.verbalise.should =~ /Company\(/
125
+
126
+ fred_fly.class.should == Mod::Person
127
+ fred_fly.constellation.should == @constellation
128
+ fred_fly.inspect.should =~ / in Conste/
129
+ fred_fly.verbalise.should =~ /Person\(/
130
+ end
131
+
132
+ it "should re-use instances constructed the same way" do
133
+ name1 = @constellation.Name("foo")
134
+ foo1 = @constellation.LegalEntity("foo")
135
+ acme1 = @constellation.Company("Acme, Inc", :auto_counter_value => :new)
136
+ fred_fly1 = @constellation.Person("fred", "fly", :auto_counter_value => :new)
137
+
138
+ name2 = @constellation.Name("foo")
139
+ foo2 = @constellation.LegalEntity("foo")
140
+ acme2 = @constellation.Company("Acme, Inc", :auto_counter_value => :new)
141
+ fred_fly2 = @constellation.Person("fred", "fly", :auto_counter_value => :new)
142
+
143
+ name1.object_id.should == name2.object_id
144
+ foo1.object_id.should == foo2.object_id
145
+ acme1.object_id.should == acme2.object_id
146
+ fred_fly1.object_id.should == fred_fly2.object_id
147
+ end
148
+
149
+ it "should support methods to assert instances via the class for that type" do
150
+ name = foo = acme = fred_fly = nil
151
+ lambda {
152
+ name = @constellation.Name.assert("foo")
153
+ foo = @constellation.LegalEntity.assert("foo")
154
+ acme = @constellation.Company.assert("Acme, Inc", :auto_counter_value => :new)
155
+ fred_fly = @constellation.Person.assert("fred", "fly", :auto_counter_value => :new)
156
+ }.should_not raise_error
157
+ name.class.should == Mod::Name
158
+ name.constellation.should == @constellation
159
+
160
+ foo.class.should == Mod::LegalEntity
161
+ foo.constellation.should == @constellation
162
+ foo.inspect.should =~ / in Conste/
163
+ foo.verbalise.should =~ /LegalEntity\(/
164
+
165
+ acme.class.should == Mod::Company
166
+ acme.constellation.should == @constellation
167
+ acme.inspect.should =~ / in Conste/
168
+ acme.verbalise.should =~ /Company\(/
169
+
170
+ fred_fly.class.should == Mod::Person
171
+ fred_fly.constellation.should == @constellation
172
+ fred_fly.inspect.should =~ / in Conste/
173
+ fred_fly.verbalise.should =~ /Person\(/
174
+ end
175
+
176
+ it "should support population blocks" do
177
+ @constellation.populate do
178
+ Name("bar")
179
+ LegalEntity("foo")
180
+ Person("Fred", "Nerk", :auto_counter_value => :new)
181
+ Company("Acme, Inc", :auto_counter_value => :new)
182
+ end
183
+ @constellation.Name.size.should == 5
184
+ @constellation.SurrogateId.size.should == 2
185
+ end
186
+
187
+ it "should verbalise itself" do
188
+ @constellation.populate do
189
+ Name("bar")
190
+ LegalEntity("foo")
191
+ c = Company("Acme, Inc", :auto_counter_value => :new)
192
+ p = Person("Fred", "Nerk", :auto_counter_value => :new, :employer => c)
193
+ p.birth_name = "Nerk"
194
+ end
195
+ s = @constellation.verbalise
196
+ names = s.split(/\n/).grep(/\tEvery /).map{|l| l.sub(/.*Every (.*):$/, '\1')}
197
+ expected = ["AutoCounterValue", "Company", "LegalEntity", "Name", "Person", "StringValue", "SurrogateId"]
198
+ names.sort.should == expected
199
+ end
200
+
201
+ it "should support string capitalisation functions" do
202
+ names = ["Company", "LegalEntity", "Name", "Person", "StringValue", "SurrogateId"]
203
+ camelwords = names.map{|n| n.camelwords }
204
+ camelwords.should == [["Company"], ["Legal", "Entity"], ["Name"], ["Person"], ["String", "Value"], ["Surrogate", "Id"]]
205
+
206
+ snakes = names.map{|n| n.snakecase }
207
+ snakes.should == ["company", "legal_entity", "name", "person", "string_value", "surrogate_id"]
208
+
209
+ camelupper = snakes.map{|n| n.camelcase }
210
+ camelupper.should == ["Company", "LegalEntity", "Name", "Person", "StringValue", "SurrogateId"]
211
+
212
+ camellower = snakes.map{|n| n.camelcase(:lower) }
213
+ camellower.should == ["company", "legalEntity", "name", "person", "stringValue", "surrogateId"]
214
+ end
215
+
216
+ it "should allow inspection of instance indices" do
217
+ baz = @constellation.Name("baz")
218
+ @constellation.Name.inspect.class.should == String
219
+ end
220
+
221
+ it "should index value instances, including by its superclasses" do
222
+ baz = @constellation.Name("baz")
223
+ @constellation.Name.keys.sort.should == ["baz"]
224
+
225
+ @constellation.StringValue.keys.sort.should == ["baz"]
226
+ @constellation.StringValue.include?(baz).should == baz
227
+ @constellation.StringValue.include?("baz").should == baz
228
+ end
229
+
230
+ describe "instance indices" do
231
+ it "should support each" do
232
+ baz = @constellation.Name("baz")
233
+ count = 0
234
+ @constellation.Name.each { |rv| count += 1 }
235
+ count.should == 1
236
+ end
237
+
238
+ it "should support detect" do
239
+ baz = @constellation.Name("baz")
240
+ @constellation.Name.detect { |rv| true }.should be_true
241
+ end
242
+ end
243
+
244
+ it "should index entity instances, including by its superclass and secondary supertypes" do
245
+ name = "Acme, Inc"
246
+ fred = "Fred"
247
+ fly = "Fly"
248
+ acme = @constellation.Company name, :auto_counter_value => :new
249
+ fred_fly = @constellation.Person fred, fly, :auto_counter_value => :new
250
+
251
+ # REVISIT: This should be illegal:
252
+ #fred_fly.auto_counter_value = :new
253
+
254
+ @constellation.Person.keys.sort.should == [[fred, fly]]
255
+ @constellation.Company.keys.sort.should == [[name]]
256
+
257
+ @constellation.LegalEntity.keys.sort.should be_include([name])
258
+ @constellation.LegalEntity.keys.sort.should be_include([fred])
259
+
260
+ @constellation.SurrogateId.values.should be_include(acme)
261
+ @constellation.SurrogateId.values.should be_include(fred_fly)
262
+ end
263
+
264
+ it "should handle one-to-ones correctly" do
265
+ person = @constellation.Person "Fred", "Smith", :auto_counter_value => :new, :birth_name => "Nerk"
266
+
267
+ pending "Extra parameters on an assert get processed in Role#adapt before @constellation gets set" do
268
+ #person.birth_name = "Nerk"
269
+
270
+ nerk = @constellation.Name["Nerk"]
271
+ nerk.should_not be_nil
272
+ nerk.person_as_birth_name.should == person
273
+ person.birth_name = nil
274
+ nerk.person_as_birth_name.should be_nil
275
+ @constellation.Name["Nerk"].should_not be_nil
276
+ end
277
+ end
278
+
279
+ it "should allow retraction of instances" do
280
+ person = @constellation.Person "Fred", "Smith", :auto_counter_value => :new, :birth_name => "Nerk"
281
+
282
+ @constellation.retract(@constellation.Name("Smith"))
283
+ @constellation.Name["Smith"].should be_nil
284
+ @constellation.Name["Fred"].should_not be_nil
285
+
286
+ person.family_name.should be_nil
287
+ @constellation.retract(@constellation.Name("Fred"))
288
+ @constellation.Name["Fred"].should be_nil
289
+ pending "Retraction of identifiers doesn't de/re-index" do
290
+ @constellation.Person.size.should == 0
291
+ end
292
+ end
293
+
294
+ it "should fail to recognise references to unresolved forward referenced classes" do
295
+ module Mod2
296
+ class Foo
297
+ identified_by :name
298
+ one_to_one :name
299
+ has_one :bar
300
+ has_one :baz, :class => "BAZ"
301
+ end
302
+
303
+ class Name < String
304
+ value_type
305
+ end
306
+ end
307
+
308
+ @c = ActiveFacts::API::Constellation.new(Mod2)
309
+ le = @c.Foo("Foo")
310
+ lambda {
311
+ le.bar
312
+ }.should raise_error(NoMethodError)
313
+ lambda {
314
+ le.baz
315
+ }.should raise_error(NoMethodError)
316
+
317
+ # Now define the classes and try again:
318
+ module Mod2
319
+ class Bar < String
320
+ value_type
321
+ end
322
+ class BAZ < String
323
+ value_type
324
+ end
325
+ end
326
+ lambda {
327
+ le.bar
328
+ le.bar = 'bar'
329
+ }.should_not raise_error
330
+ lambda {
331
+ le.baz
332
+ le.baz = 'baz'
333
+ }.should_not raise_error
334
+ end
335
+
336
+ it "should not allow references to classes outside the vocabulary" do
337
+ module Outside
338
+ class Other < String
339
+ value_type
340
+ end
341
+ end
342
+
343
+ lambda {
344
+ module Mod
345
+ class IntValue
346
+ has_one :thingummy, :class => Outside::Other
347
+ end
348
+ end
349
+ }.should raise_error
350
+ end
351
+
352
+ it "should disallow unrecognised supertypes" do
353
+ lambda {
354
+ module Mod
355
+ class LegalEntity
356
+ supertypes :foo
357
+ end
358
+ end
359
+ }.should raise_error(NameError)
360
+
361
+ lambda {
362
+ module Mod
363
+ class LegalEntity
364
+ supertypes Bignum
365
+ end
366
+ end
367
+ }.should raise_error(RuntimeError)
368
+
369
+ lambda {
370
+ module Mod
371
+ class LegalEntity
372
+ supertypes 3
373
+ end
374
+ end
375
+ }.should raise_error(RuntimeError)
376
+ end
377
+
378
+ it "should allow supertypes with supertypes" do
379
+ lambda {
380
+ module Mod
381
+ class ListedCompany < Company
382
+ end
383
+ end
384
+ c = @constellation.ListedCompany("foo", :auto_counter_value => 23)
385
+ }.should_not raise_error(NameError)
386
+ end
387
+
388
+ it "should error on invalid :class values" do
389
+ lambda {
390
+ module Mod
391
+ class SurrogateId
392
+ has_one :Name, :class => 3
393
+ end
394
+ end
395
+ }.should raise_error
396
+ end
397
+
398
+ it "should error on misleading :class values" do
399
+ lambda {
400
+ module Mod
401
+ class SurrogateId
402
+ has_one :Name, :class => Extra
403
+ end
404
+ end
405
+ }.should raise_error
406
+ end
407
+
408
+ it "should allow assert using an object of the same type" do
409
+ c = @constellation.Company("foo", :auto_counter_value => 23)
410
+ c2 = ActiveFacts::API::Constellation.new(Mod)
411
+ lambda {
412
+ c2.Company(c, :auto_counter_value => :new)
413
+ }.should_not raise_error
414
+ c2.Company.keys.should == [["foo"]]
415
+ end
416
+
417
+ it "should allow cross-constellation construction" do
418
+ c = @constellation.Company("foo", :auto_counter_value => 23)
419
+ lambda {
420
+ c2 = ActiveFacts::API::Constellation.new(Mod)
421
+ c2.Company(c.name, :auto_counter_value => :new)
422
+ }.should_not raise_error
423
+ end
424
+
425
+ it "should allow cross-constellation assignment" do
426
+ c = @constellation.Company("foo", :auto_counter_value => 23)
427
+ lambda {
428
+ c2 = ActiveFacts::API::Constellation.new(Mod)
429
+ p = c2.Person('Fred', 'Smith', :auto_counter_value => :new)
430
+ p.employer = [c, {:auto_counter_value => :new}]
431
+ }.should_not raise_error
432
+ end
433
+
434
+ end