amee-analytics 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,428 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ include AMEE::DataAbstraction
4
+
5
+ describe TermsList do
6
+
7
+ before(:each) do
8
+ initialize_calculation_set
9
+ calcs = []
10
+ calcs << add_elec_calc(500,240)
11
+ calcs << add_elec_calc(1000,480)
12
+ calcs << add_elec_calc(1234,600)
13
+ @coll = CalculationCollection.new calcs
14
+ @list = @coll.terms
15
+ end
16
+
17
+ it "should initialize a terms list" do
18
+ @list.should be_a AMEE::DataAbstraction::TermsList
19
+ end
20
+
21
+ it "full list should not be analogous" do
22
+ # includes :usage AND :co2 terms
23
+ @list.should_not be_analogous
24
+ @list.all? {|term| term.is_a? AMEE::DataAbstraction::Output }.should be_false
25
+ end
26
+
27
+ it "should filter class using dynamic methods" do
28
+ @list = @list.outputs
29
+ @list.all? {|term| term.is_a? AMEE::DataAbstraction::Output }.should be_true
30
+ @list.labels.all? {|label| label == :co2 }.should be_true
31
+ @list.should be_analogous
32
+ end
33
+
34
+ it "should filter type using dynamic method" do
35
+ @list = @list.co2
36
+ @list.all? {|term| term.is_a? AMEE::DataAbstraction::Output }.should be_true
37
+ @list.labels.all? {|label| label == :co2 }.should be_true
38
+ @list.should be_analogous
39
+ end
40
+
41
+ it "should recognize consistent units" do
42
+ @list.co2.should be_analogous
43
+ @list.co2.should be_homogeneous_units
44
+ @list.co2.should be_homogeneous_per_units
45
+ end
46
+
47
+ it "should recognize non-consistent units" do
48
+ @list.co2.first.unit 'lb'
49
+ @list.co2[1].per_unit 'h'
50
+ @list.co2.should be_analogous
51
+ @list.co2.should_not be_homogeneous
52
+ @list.co2.should_not be_homogeneous_units
53
+ @list.co2.should_not be_homogeneous_per_units
54
+ end
55
+
56
+ it "should raise error when standardizing units on non-analogous list" do
57
+ lambda{@list.standardize_units}.should raise_error
58
+ end
59
+
60
+ it "should standardize term units with predominant units and convert values appropriately if no unit specified" do
61
+ @list.co2.first.unit 'lb'
62
+ @list.co2.first.value.should eql 240
63
+ @list.co2.should_not be_homogeneous
64
+ @list.co2.should_not be_homogeneous_units
65
+ list = @list.co2.standardize_units
66
+ list.should be_homogeneous
67
+ list.should be_homogeneous_units
68
+ list.first.unit.label.should eql 't'
69
+ list.first.value.should be_close 0.1088621688,0.001
70
+ end
71
+
72
+ it "should standardize term per units with predominant per units and convert values appropriately if no per unit specified" do
73
+ @list.co2.each {|term| term.per_unit 'h'}
74
+ @list.co2.first.per_unit 'min'
75
+ @list.co2.first.value.should eql 240
76
+ @list.co2.should_not be_homogeneous
77
+ @list.co2.should_not be_homogeneous_per_units
78
+ list = @list.co2.standardize_units
79
+ list.should be_homogeneous
80
+ list.should be_homogeneous_per_units
81
+ list.first.per_unit.label.should eql 'h'
82
+ list.first.value.should be_close 14400,0.001
83
+ end
84
+
85
+ it "should standardize term units AND per units with predominant units and convert values appropriately if no units specified" do
86
+ @list.co2.each {|term| term.per_unit 'h'}
87
+ @list.co2.first.per_unit 'min'
88
+ @list.co2.first.unit 'lb'
89
+ @list.co2.first.value.should eql 240
90
+ @list.co2.should_not be_homogeneous
91
+ @list.co2.should_not be_homogeneous_units
92
+ @list.co2.should_not be_homogeneous_per_units
93
+ list = @list.co2.standardize_units
94
+ list.should be_homogeneous
95
+ list.should be_homogeneous_units
96
+ list.should be_homogeneous_per_units
97
+ list.first.unit.label.should eql 't'
98
+ list.first.per_unit.label.should eql 'h'
99
+ list.first.value.should be_close 6.531730128,0.001
100
+ end
101
+
102
+ it "should standardize term units with specfied units and convert values appropriately" do
103
+ @list.co2.first.unit 'lb'
104
+ @list.co2.first.value.should eql 240
105
+ @list.co2[1].value.should eql 480
106
+ @list.co2.should_not be_homogeneous
107
+ @list.co2.should_not be_homogeneous_units
108
+ list = @list.co2.standardize_units(:lb)
109
+ list.should be_homogeneous
110
+ list.should be_homogeneous_units
111
+ list.first.unit.label.should eql 'lb'
112
+ list[1].unit.label.should eql 'lb'
113
+ list.first.value.should eql 240.0
114
+ list[1].value.should be_close 1058218.85848741,0.001
115
+ end
116
+
117
+ it "should standardize term per units with specfied per units and convert values appropriately" do
118
+ @list.co2.each {|term| term.per_unit 'h'}
119
+ @list.co2.first.per_unit 'min'
120
+ @list.co2.first.value.should eql 240
121
+ @list.co2[1].value.should eql 480
122
+ @list.co2.should_not be_homogeneous
123
+ @list.co2.should_not be_homogeneous_per_units
124
+ list = @list.co2.standardize_units(nil,:min)
125
+ list.should be_homogeneous
126
+ list.should be_homogeneous_per_units
127
+ list.first.per_unit.label.should eql 'min'
128
+ list[1].per_unit.label.should eql 'min'
129
+ list.first.value.should eql 240.0
130
+ list[1].value.should be_close 8,0.001
131
+ end
132
+
133
+ it "should standardize term units AND per units with specfied units AND per units and convert values appropriately" do
134
+ @list.co2.each {|term| term.per_unit 'h'}
135
+ @list.co2.first.unit 'lb'
136
+ @list.co2.first.per_unit 'min'
137
+ @list.co2.first.value.should eql 240
138
+ @list.co2[1].value.should eql 480
139
+ @list.co2.should_not be_homogeneous
140
+ @list.co2.should_not be_homogeneous_units
141
+ @list.co2.should_not be_homogeneous_per_units
142
+ list = @list.co2.standardize_units(:lb,:min)
143
+ list.should be_homogeneous
144
+ list.should be_homogeneous_units
145
+ list.should be_homogeneous_per_units
146
+ list.first.unit.label.should eql 'lb'
147
+ list.first.per_unit.label.should eql 'min'
148
+ list[1].unit.label.should eql 'lb'
149
+ list[1].per_unit.label.should eql 'min'
150
+ list.first.value.should eql 240.0
151
+ list[1].value.should be_close 17636.9809747902,0.001
152
+ end
153
+
154
+ it "should sum terms" do
155
+ @list.co2.sum.to_s.should eql "1320.0 t"
156
+ end
157
+
158
+ it "should sum terms where units differ" do
159
+ @list.co2.first.unit 'kg'
160
+ @list.co2.sum.to_s.should eql "1080.24 t"
161
+ end
162
+
163
+ it "should sum terms and change unit" do
164
+ @list.co2.sum(:kg).to_s.should eql "1320000.0 kg"
165
+ end
166
+
167
+ it "should sum terms where units differ and change return unit" do
168
+ @list.co2.first.unit 'kg'
169
+ @list.co2.sum(:lb).to_s.should eql "2381521.54102592 lb"
170
+ end
171
+
172
+ it "should return 0.0 if no numerical term values found" do
173
+ @list.country.sum.to_s.should eql "0.0"
174
+ end
175
+
176
+ it "should average terms" do
177
+ @list.co2.mean.to_s.should eql "440.0 t"
178
+ end
179
+
180
+ it "should recognize numeric terms" do
181
+ @list.should_not be_all_numeric
182
+ @list.co2.should be_all_numeric
183
+ @list.usage.should be_all_numeric
184
+ @list.country.should_not be_all_numeric
185
+ end
186
+
187
+ it "should return median of numeric list" do
188
+ @list.co2.median.to_s.should eql "480.0 t"
189
+ end
190
+
191
+ it "should return median of numeric list" do
192
+ @list.usage.median.to_s.should eql "1000.0 kWh"
193
+ end
194
+
195
+ it "should return median of non-numeric list" do
196
+ calcs = []
197
+ calcs << add_transport_calc(500,240)
198
+ calcs << add_transport_calc(1000,480)
199
+ calcs << add_transport_calc(1234,600)
200
+ @coll = CalculationCollection.new calcs
201
+ @list = @coll.terms.type
202
+ @list.each {|term| term.value "car"}
203
+ @list.median.to_s.should eql "car"
204
+ @list.first.value "van"
205
+ @list[1].value "motorbike"
206
+ @list.last.value "lorry"
207
+ @list.median.to_s.should eql "motorbike"
208
+ end
209
+
210
+ it "should return mode of non numeric list" do
211
+ calcs = []
212
+ calcs << add_transport_calc(500,240)
213
+ calcs << add_transport_calc(1000,480)
214
+ calcs << add_transport_calc(1234,600)
215
+ @coll = CalculationCollection.new calcs
216
+ @list = @coll.terms.type
217
+ @list.each {|term| term.value "car"}
218
+ @list.mode.to_s.should eql "car"
219
+ @list.first.value "van"
220
+ @list[1].value "van"
221
+ @list.last.value "lorry"
222
+ @list.mode.to_s.should eql "van"
223
+ end
224
+
225
+ it "should return a TermsList for mode of list with some equal frequencies" do
226
+ calcs = []
227
+ calcs << add_transport_calc(500,240)
228
+ calcs << add_transport_calc(1000,480)
229
+ calcs << add_transport_calc(1234,600)
230
+ @coll = CalculationCollection.new calcs
231
+ @list = @coll.terms.type
232
+ @list.each {|term| term.value "car"}
233
+ @list.mode.to_s.should eql "car"
234
+ @list.first.value "van"
235
+ @list[1].value "motorbike"
236
+ @list.last.value "lorry"
237
+ @list.mode.should be_a TermsList
238
+ @list.mode.size.should eql 3
239
+ end
240
+
241
+ it "should return mode of numeric list" do
242
+ @list.usage.first.value 1000
243
+ @list.usage.mode.to_s.should eql "1000.0 kWh"
244
+ end
245
+
246
+ it "should discover predominant unit" do
247
+ @list.co2.predominant_unit.should eql 't'
248
+ @list.usage.predominant_unit.should eql 'kWh'
249
+ @list.co2.first.unit 'kg'
250
+ @list.co2.predominant_unit.should eql 't'
251
+ @list.co2.last.unit 'kg'
252
+ @list.co2.predominant_unit.should eql 'kg'
253
+ end
254
+
255
+ it "should discover predominant per unit" do
256
+ @list.co2.each {|term| term.per_unit 'h'}
257
+ @list.usage.each {|term| term.per_unit 'm^2'}
258
+ @list.co2.predominant_per_unit.should eql 'h'
259
+ @list.usage.predominant_per_unit.should eql 'm²'
260
+ @list.co2.first.per_unit 'min'
261
+ @list.co2.predominant_per_unit.should eql 'h'
262
+ @list.co2.last.per_unit 'min'
263
+ @list.co2.predominant_per_unit.should eql 'min'
264
+ end
265
+
266
+ it "should sort by value changing list in place" do
267
+ @list=@list.co2
268
+ @list.first.value.should eql 240
269
+ @list[1].value.should eql 480
270
+ @list.last.value.should eql 600
271
+ @list.reverse!
272
+ @list.first.value.should_not eql 240
273
+ @list.last.value.should_not eql 600
274
+ @list.sort_by_value!
275
+ @list.first.value.should eql 240
276
+ @list[1].value.should eql 480
277
+ @list.last.value.should eql 600
278
+ end
279
+
280
+ it "should sort by value creating new list" do
281
+ @list=@list.co2
282
+ @list.first.value.should eql 240
283
+ @list[1].value.should eql 480
284
+ @list.last.value.should eql 600
285
+ @list.reverse!
286
+ @list.first.value.should_not eql 240
287
+ @list.last.value.should_not eql 600
288
+ list = @list.sort_by_value
289
+ list.first.value.should eql 240
290
+ list[1].value.should eql 480
291
+ list.last.value.should eql 600
292
+ end
293
+
294
+ it "should sort by value even if nil values present" do
295
+ calcs = []
296
+ calcs << add_transport_calc(500,240)
297
+ calcs << add_transport_calc(1000,480)
298
+ calcs << add_transport_calc(nil,nil)
299
+ calcs << add_transport_calc(1234,600)
300
+ @coll = CalculationCollection.new calcs
301
+ @list = @coll.co2
302
+ @list.first.value.should eql 240
303
+ @list[1].value.should eql 480
304
+ @list[2].value.should eql nil
305
+ @list.last.value.should eql 600
306
+ @list.reverse!
307
+ @list.first.value.should_not eql 240
308
+ @list.last.value.should_not eql 600
309
+ @list.sort_by_value!
310
+ @list.first.value.should eql 240
311
+ @list[1].value.should eql 480
312
+ @list[2].value.should eql 600
313
+ @list.last.value.should eql nil
314
+ end
315
+
316
+ it "should return self on sort if all nil values present" do
317
+ calcs = []
318
+ calcs << add_transport_calc(nil,nil)
319
+ calcs << add_transport_calc(nil,nil)
320
+ calcs << add_transport_calc(nil,nil)
321
+ calcs << add_transport_calc(nil,nil)
322
+ @coll = CalculationCollection.new calcs
323
+ @list = @coll.co2
324
+ @list.first.value.should eql nil
325
+ @list[1].value.should eql nil
326
+ @list[2].value.should eql nil
327
+ @list.last.value.should eql nil
328
+ @list.reverse!
329
+ @list.first.value.should eql nil
330
+ @list.last.value.should eql nil
331
+ @list.sort_by_value!
332
+ @list.first.value.should eql nil
333
+ @list[1].value.should eql nil
334
+ @list[2].value.should eql nil
335
+ @list.last.value.should eql nil
336
+ end
337
+
338
+ it "should return a new TermList for numeric only terms" do
339
+ @list=@list.co2.numeric_terms.should be_a TermsList
340
+ end
341
+
342
+ it "should add TermsLists" do
343
+ calcs = []
344
+ calcs << add_elec_calc(500,240)
345
+ calcs << add_elec_calc(1000,480)
346
+ calcs << add_elec_calc(1234,600)
347
+ @coll = CalculationCollection.new calcs
348
+ @list1 = @coll.usage
349
+ @list1.should be_a TermsList
350
+ @list1.size.should eql 3
351
+ @list2 = @coll.co2
352
+ @list2.should be_a TermsList
353
+ @list2.size.should eql 3
354
+ @list3 = @list1 + @list2
355
+ @list3.should be_a TermsList
356
+ @list3.size.should eql 6
357
+ end
358
+
359
+ it "should subtract TermsLists" do
360
+ calcs = []
361
+ calcs << add_elec_calc(500,240)
362
+ calcs << add_elec_calc(1000,480)
363
+ calcs << add_elec_calc(1234,600)
364
+ @coll = CalculationCollection.new calcs
365
+ @list1 = @coll.usage
366
+ @list1.should be_a TermsList
367
+ @list1.size.should eql 3
368
+ calcs = []
369
+ calcs << add_elec_calc(1234,600)
370
+ @coll = CalculationCollection.new calcs
371
+ @list2 = @coll.usage
372
+ @list2.should be_a TermsList
373
+ @list2.size.should eql 1
374
+ @list3 = @list1 - @list2
375
+ @list3.should be_a TermsList
376
+ @list3.size.should eql 2
377
+ end
378
+
379
+ it "should add to TermsList using += syntax" do
380
+ @coll = CalculationCollection.new
381
+ @coll << add_transport_calc(500,240)
382
+ @list = TermsList.new
383
+ @list.should be_a TermsList
384
+ @list.size.should eql 0
385
+ @list += @coll.distance
386
+ @list.should be_a TermsList
387
+ @list.size.should eql 1
388
+ @list += @coll.co2
389
+ @list.should be_a TermsList
390
+ @list.size.should eql 2
391
+ end
392
+
393
+ it "should subtract from calculation collection using -= syntax" do
394
+ @coll = CalculationCollection.new
395
+ calc = add_transport_calc(500,240)
396
+ @list = TermsList.new
397
+ @list.should be_a TermsList
398
+ @list.size.should eql 0
399
+ @list += calc.terms
400
+ @list.size.should eql 5
401
+ @list -= calc['distance']
402
+ @list.should be_a TermsList
403
+ @list.size.should eql 4
404
+ @list -= calc['co2']
405
+ @list.should be_a TermsList
406
+ @list.size.should eql 3
407
+ end
408
+
409
+ it "should return representations of each unique term" do
410
+ terms = @coll.terms.first_of_each_type
411
+ terms.should be_a TermsList
412
+ terms.size.should eql 3
413
+ terms.labels.map(&:to_s).sort.should eql ['co2','country','usage']
414
+ end
415
+
416
+ it "should respond to dynamic term methods" do
417
+ @coll.terms.respond_to?(:co2).should be_true
418
+ @coll.terms.respond_to?(:usage).should be_true
419
+ @coll.terms.respond_to?(:distance).should be_false
420
+ end
421
+
422
+ it "should respond to dynamic sort methods" do
423
+ @coll.terms.respond_to?(:sort_by_value).should be_true
424
+ @coll.terms.respond_to?(:sort_by_unit!).should be_true
425
+ @coll.terms.respond_to?(:sort_by_volume).should be_false
426
+ end
427
+
428
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,132 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ require 'amee-analytics'
5
+ require 'amee-data-persistence'
6
+ require 'amee/data_abstraction/persistence_support.rb'
7
+ require 'amee/data_abstraction/calculation_collection_analytics_support'
8
+ require 'amee/data_abstraction/terms_list_analytics_support'
9
+ require 'amee/data_abstraction/term_analytics_support'
10
+
11
+ AMEE::DataAbstraction::OngoingCalculation.class_eval {
12
+ include AMEE::DataAbstraction::PersistenceSupport
13
+ }
14
+ AMEE::DataAbstraction::CalculationCollection.class_eval { include AMEE::DataAbstraction::CalculationCollectionAnalyticsSupport }
15
+ AMEE::DataAbstraction::TermsList.class_eval { include AMEE::DataAbstraction::TermsListAnalyticsSupport }
16
+ AMEE::DataAbstraction::Term.class_eval { include AMEE::DataAbstraction::TermAnalyticsSupport }
17
+
18
+ RAILS_ROOT = '.'
19
+
20
+ Spec::Runner.configure do |config|
21
+ config.mock_with :flexmock
22
+ end
23
+
24
+ def initialize_calculation_set
25
+ eval "Calculations = AMEE::DataAbstraction::CalculationSet.new {
26
+ calculation{
27
+ name 'Electricity'
28
+ label :electricity
29
+ path '/business/energy/electricity/grid'
30
+ drill {
31
+ label :country
32
+ path 'country'
33
+ fixed 'Argentina'
34
+ }
35
+ profile {
36
+ label :usage
37
+ name 'Electricity Used'
38
+ path 'energyPerTime'
39
+ default_unit :kWh
40
+ }
41
+ output {
42
+ label :co2
43
+ name 'Carbon Dioxide'
44
+ path :default
45
+ default_unit :t
46
+ }
47
+ }
48
+ calculation{
49
+ name 'Transport'
50
+ label :transport
51
+ path '/transport/defra/vehicle'
52
+ drill {
53
+ label :type
54
+ path 'type'
55
+ name 'Type'
56
+ }
57
+ drill {
58
+ label :size
59
+ path 'size'
60
+ name 'Size'
61
+ }
62
+ drill {
63
+ label :fuel
64
+ path 'fuel'
65
+ name 'Fuel'
66
+ }
67
+ profile {
68
+ label :distance
69
+ name 'distance'
70
+ path 'distance'
71
+ default_unit :km
72
+ }
73
+ output {
74
+ label :co2
75
+ name 'Carbon Dioxide'
76
+ path :default
77
+ default_unit :t
78
+ }
79
+ }
80
+ }"
81
+ end
82
+
83
+ def add_elec_calc(act,res)
84
+ calc = Calculations[:electricity].begin_calculation
85
+ calc['usage'].value act
86
+ calc['co2'].value res
87
+ return calc
88
+ end
89
+
90
+ def add_transport_calc(act,res)
91
+ calc = Calculations[:transport].begin_calculation
92
+ calc['distance'].value act
93
+ calc['co2'].value res
94
+ return calc
95
+ end
96
+
97
+ VALID_ATTRIBUTES = [{ :profile_item_uid => "G8T8E8SHSH46",
98
+ :calculation_type => :electricity,
99
+ :country => {:value => 'Argentina'},
100
+ :usage => {:value => 500, :unit => Unit.kWh},
101
+ :co2 => {:value => 1234.5, :unit => Unit.kg} },
102
+ { :profile_item_uid => "RUEU38490R0R",
103
+ :calculation_type => :electricity,
104
+ :country => {:value => 'Argentina'},
105
+ :usage => {:value => 12, :unit => Unit.kWh},
106
+ :co2 => {:value => 6, :unit => Unit.kg} }]
107
+
108
+ def find_single_mock
109
+ flexmock(AMEE::DataAbstraction::OngoingCalculation) do |mock|
110
+ mock.should_receive(:find).and_return(single_db_calc(VALID_ATTRIBUTES.first))
111
+ end
112
+ end
113
+
114
+ def find_many_mock
115
+ flexmock(AMEE::DataAbstraction::OngoingCalculation) do |mock|
116
+ mock.should_receive(:find).and_return(many_db_calc)
117
+ end
118
+ end
119
+
120
+ def single_db_calc(data)
121
+ calc = Calculations.calculations[:electricity].begin_calculation
122
+ calc.db_calculation = data.delete(:calculation_type)
123
+ calc.choose_without_validation!(data)
124
+ return calc
125
+ end
126
+
127
+ def many_db_calc
128
+ array = VALID_ATTRIBUTES.map do |data|
129
+ single_db_calc(data)
130
+ end
131
+ return array
132
+ end