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: 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