amee-data-persistence 1.0.0

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.
@@ -0,0 +1,54 @@
1
+ # Copyright (C) 2011 AMEE UK Ltd. - http://www.amee.com
2
+ # Released as Open Source Software under the BSD 3-Clause license. See LICENSE.txt for details.
3
+
4
+ # :title: Class: AMEE::Db::BaseConfig
5
+
6
+ require 'singleton'
7
+
8
+ module AMEE
9
+ module Db
10
+
11
+ # A singleton class for configuration. Automatically initialised on first use
12
+ # Use like so:
13
+ #
14
+ # AMEE::Db::Config.instance.store_everything?
15
+ #
16
+ # Separated into BaseConfig and Config to allow unit testing of singleton.
17
+ #
18
+ class BaseConfig
19
+
20
+ def initialize
21
+ # Default is metadata
22
+ @storage_method = load_storage_method || :metadata
23
+ end
24
+
25
+ attr_reader :storage_method
26
+
27
+ def store_metadata?
28
+ [:metadata, :outputs, :everything].include? storage_method
29
+ end
30
+
31
+ def store_outputs?
32
+ [:outputs, :everything].include? storage_method
33
+ end
34
+
35
+ def store_everything?
36
+ [:everything].include? storage_method
37
+ end
38
+
39
+ private
40
+
41
+ def load_storage_method
42
+ m = YAML.load_file("#{RAILS_ROOT}/config/persistence.yml")['method'].to_sym rescue nil
43
+ raise "amee-data-persistence: Invalid storage method" unless [:metadata, :outputs, :everything].include? m
44
+ m
45
+ end
46
+
47
+ end
48
+
49
+ class Config < BaseConfig
50
+ include Singleton
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,72 @@
1
+ # Copyright (C) 2011 AMEE UK Ltd. - http://www.amee.com
2
+ # Released as Open Source Software under the BSD 3-Clause license. See LICENSE.txt for details.
3
+
4
+ # :title: Class AMEE::Db::Term
5
+
6
+ module AMEE
7
+ module Db
8
+
9
+ # This class represents a database record for a calculation term used with
10
+ # the <i>AMEE:DataAbstraction::OngoingCalculation</i> class. This class stores
11
+ # the label, value and unit attributes of specific calculation terms, and is
12
+ # owned by an associated <i>AMEE::Db::Calculation</i> record
13
+ #
14
+ # This class is typically used by proxy, via the <tt>#update_calculation!</tt>,
15
+ # and <tt>#to_hash</tt> methods of the <i>AMEE::Db::Calculation</i> class, and
16
+ # ultimately called from the <tt>find</tt>, <tt>find_by_type</tt>,
17
+ # <tt>#save</tt>, <tt>#delete</tt>, and <tt>#get_db_calculation</tt> methods
18
+ # associated with the <i>AMEE:DataAbstraction::OngoingCalculation</i> class.
19
+ #
20
+ class Term < ActiveRecord::Base
21
+
22
+ belongs_to :calculation, :class_name => "AMEE::Db::Calculation"
23
+ validates_presence_of :calculation_id, :label
24
+ before_save :initialize_units
25
+ before_save :initialize_value
26
+
27
+ # Returns a <i>Hash</i> representation of <tt>self</tt>, e.g.
28
+ #
29
+ # my_term.to_hash #=> { :value => 1600,
30
+ # :unit => <Quantify::Unit::SI> }
31
+ #
32
+ # my_term.to_hash #=> { :value => 234.1,
33
+ # :unit => <Quantify::Unit::NonSI>,
34
+ # :per_unit => <Quantify::Unit::SI> }
35
+ #
36
+ # This method is called as part of <tt>AMEE::Db::Calculation#to_hash</tt>
37
+ # in order to provide a full hash representation of a calculation.
38
+ #
39
+ def to_hash
40
+ sub_hash = {}
41
+ # Float method called on term value in order to initialize
42
+ # explicitly numeric values as numeric objects.
43
+ #
44
+ sub_hash[:value] = AMEE::DataAbstraction::Term.convert_value_to_type(self.value, self.value_type)
45
+ sub_hash[:unit] = Unit.for(unit) if unit
46
+ sub_hash[:per_unit] = Unit.for(per_unit) if per_unit
47
+ { label.to_sym => sub_hash }
48
+ end
49
+
50
+ private
51
+
52
+ # Serialize all unit attributes using the string provided by the
53
+ # <tt>label</tt> attribute of a <i>Quantify::Unit::Base</i> object
54
+ #
55
+ def initialize_units
56
+ if unit
57
+ self.unit = unit.is_a?(Quantify::Unit::Base) ? unit.label : unit
58
+ end
59
+ if per_unit
60
+ self.per_unit = per_unit.is_a?(Quantify::Unit::Base) ? per_unit.label : per_unit
61
+ end
62
+ end
63
+
64
+ def initialize_value
65
+ unless self.value.nil?
66
+ self.value_type = self.value.class.to_s
67
+ self.value = self.value.to_s
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,31 @@
1
+
2
+ # Authors:: James Hetherington, James Smith, Andrew Berkeley, George Palmer
3
+ # Copyright:: Copyright (c) 2011 AMEE UK Ltd
4
+ # License:: Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject
10
+ # to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included
13
+ # in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+
24
+ require 'amee-data-abstraction'
25
+ require 'amee-data-persistence'
26
+
27
+ # include the <i>AMEE::DataAbstraction::PersistenceSupport</i> module within the
28
+ # <i>AMEE::DataAbstraction::OngoingCalculation</i> class providing interface
29
+ # methods for managing persistence of calculations.
30
+ #
31
+ ::AMEE::DataAbstraction::OngoingCalculation.class_eval { include ::AMEE::DataAbstraction::PersistenceSupport }
@@ -0,0 +1,176 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ include AMEE::Db
4
+
5
+ describe Calculation do
6
+
7
+ valid_calculation_attributes = { :profile_item_uid => "G8T8E8SHSH46",
8
+ :calculation_type => :electricity }
9
+
10
+ after(:all) do
11
+ Calculation.delete_all
12
+ end
13
+
14
+ describe "new calculation" do
15
+
16
+ before(:all) do
17
+ @attr = valid_calculation_attributes
18
+ end
19
+
20
+ it "should be valid with profile item uid and calculation type" do
21
+ @calculation = Calculation.new @attr
22
+ @calculation.should be_valid
23
+ end
24
+
25
+ it "should be valid without profile item uid" do
26
+ @calculation = Calculation.new @attr.merge(:profile_item_uid => "")
27
+ @calculation.should be_valid
28
+ end
29
+
30
+ it "should not be valid without calculation type" do
31
+ @calculation = Calculation.new @attr.merge(:calculation_type => "")
32
+ @calculation.should_not be_valid
33
+ end
34
+
35
+ it "should be valid with profile uid additionally specified" do
36
+ @calculation = Calculation.new @attr.merge(:profile_uid => "GFD8E8SHSH46")
37
+ @calculation.should be_valid
38
+ end
39
+
40
+ it "should not be valid with non-canonical (short) profile item uid" do
41
+ @calculation = Calculation.new @attr.merge(:profile_item_uid => "GFD8E8SHS")
42
+ @calculation.should_not be_valid
43
+ end
44
+
45
+ it "should not be valid with non-canonical (lowercase) profile item uid" do
46
+ @calculation = Calculation.new @attr.merge(:profile_item_uid => "gfd8e8shsh46")
47
+ @calculation.should_not be_valid
48
+ end
49
+
50
+ it "should not be valid with non-canonical (short) profile uid" do
51
+ @calculation = Calculation.new @attr.merge(:profile_uid => "GFD8E8SHS")
52
+ @calculation.should_not be_valid
53
+ end
54
+
55
+ it "should not be valid with non-canonical (lowercase) profile uid" do
56
+ @calculation = Calculation.new @attr.merge(:profile_uid => "gfd8e8shsh46")
57
+ @calculation.should_not be_valid
58
+ end
59
+
60
+ it "should not be valid with non-canonical (invalid characters) profile uid" do
61
+ @calculation = Calculation.new @attr.merge(:profile_uid => "gfd8&sh*h4.")
62
+ @calculation.should_not be_valid
63
+ end
64
+
65
+ it "should create a new calculation" do
66
+ @calculation = Calculation.create @attr
67
+ @calculation.is_a?(Calculation).should be_true
68
+ end
69
+
70
+ it "should save calculation type as string" do
71
+ @calculation = Calculation.create! @attr
72
+ @calculation.reload
73
+ @calculation.calculation_type.should == 'electricity'
74
+ @calculation.calculation_type.class.should == String
75
+ @calculation.type.should == :electricity
76
+ @calculation.type.class.should == Symbol
77
+ end
78
+
79
+ end
80
+
81
+ describe "updating calculation" do
82
+
83
+ valid_term_attributes = { :country => {:value => 'Argentina'},
84
+ :usage => {:value => 500, :unit => Unit.kWh},
85
+ :co2 => {:value => 1234.5, :unit => Unit.kg} }
86
+
87
+ before(:each) do
88
+ @calculation = Calculation.create valid_calculation_attributes
89
+ end
90
+
91
+ it "should update primary attributes" do
92
+ @calculation.profile_item_uid.should == "G8T8E8SHSH46"
93
+ @calculation.profile_uid.should == nil
94
+ @calculation.update_calculation!(:profile_uid => "ASD603SHSHFD", :profile_item_uid => "ASN603DHSREW")
95
+ @calculation.profile_item_uid.should == "ASN603DHSREW"
96
+ @calculation.profile_uid.should == "ASD603SHSHFD"
97
+ end
98
+
99
+ it "should not matter which order attributes updated" do
100
+ @calculation.profile_item_uid.should == "G8T8E8SHSH46"
101
+ @calculation.update_calculation!(:profile_uid => "ASD603SHSHFD",
102
+ :calculation_type => :energy,
103
+ :profile_item_uid => "ASN603DHSREW")
104
+ @calculation.profile_item_uid.should == "ASN603DHSREW"
105
+ @calculation.profile_uid.should == "ASD603SHSHFD"
106
+ @calculation.type.should == :energy
107
+ @calculation.update_calculation!(:profile_uid => nil,
108
+ :profile_item_uid => "ASN603DHSREW",
109
+ :calculation_type => :electricity)
110
+ @calculation.profile_item_uid.should == "ASN603DHSREW"
111
+ @calculation.profile_uid.should == nil
112
+ @calculation.type.should == :electricity
113
+ end
114
+
115
+ it "should allow removal of profile item uid" do
116
+ @calculation.profile_item_uid.should == "G8T8E8SHSH46"
117
+ @calculation.profile_uid.should == nil
118
+ @calculation.update_calculation!(:profile_uid => "ASD603SHSHFD", :profile_item_uid => nil)
119
+ @calculation.profile_item_uid.should == nil
120
+ end
121
+
122
+ it "should update associated terms" do
123
+ @calculation.to_hash.should == { :profile_item_uid => "G8T8E8SHSH46",
124
+ :profile_uid => nil }
125
+ @calculation.type.should == :electricity
126
+ @calculation.update_calculation! valid_term_attributes.merge :calculation_type => :power
127
+ hash = @calculation.to_hash
128
+ hash.keys.map!(&:to_s).sort!.should == [ :profile_item_uid, :usage, :co2, :country,
129
+ :profile_uid].map!(&:to_s).sort!
130
+ hash[:co2][:unit].should be_a Quantify::Unit::SI
131
+ hash[:co2][:value].should eql 1234.5
132
+ hash[:co2][:unit].name.should eql 'kilogram'
133
+ hash[:usage][:unit].should be_a Quantify::Unit::NonSI
134
+ hash[:usage][:value].should eql 500
135
+ hash[:usage][:unit].name.should eql 'kilowatt hour'
136
+ hash[:country][:value].should eql 'Argentina'
137
+ @calculation.calculation_type.should eql 'power'
138
+ @calculation.type.should eql :power
139
+ @calculation.update_calculation! valid_term_attributes.merge :calculation_type => :electricity
140
+ @calculation.calculation_type.should eql 'electricity'
141
+ @calculation.type.should eql :electricity
142
+ end
143
+
144
+ it "should update associated terms, removing unspecified terms" do
145
+ @calculation.to_hash.should == { :profile_item_uid => "G8T8E8SHSH46",
146
+ :profile_uid => nil }
147
+ @calculation.type.should == :electricity
148
+ @calculation.update_calculation! valid_term_attributes
149
+ hash = @calculation.to_hash
150
+ hash.keys.map!(&:to_s).sort!.should == [:profile_item_uid, :usage, :co2, :country,
151
+ :profile_uid ].map!(&:to_s).sort!
152
+ @calculation.type.should == :electricity
153
+ @calculation.update_calculation! :usage => {:value => 600000, :unit => Unit.kWh}, :country => {:value =>'Argentina'}
154
+ hash = @calculation.to_hash
155
+ hash.keys.map!(&:to_s).sort!.should == [ :profile_item_uid, :usage, :country,
156
+ :profile_uid ].map!(&:to_s).sort!
157
+ hash[:co2].should be_a NilClass
158
+ hash[:usage][:unit].should be_a Quantify::Unit::NonSI
159
+ hash[:usage][:value].should == 600000
160
+ hash[:usage][:unit].name.should == 'kilowatt hour'
161
+ hash[:country][:value].should == 'Argentina'
162
+ @calculation.type.should == :electricity
163
+ end
164
+
165
+ it "should find by atttribute" do
166
+ calc = Calculation.find :first, :conditions => {:calculation_type => 'electricity'}
167
+ calc.class.should == Calculation
168
+ calc.type.should == :electricity
169
+ end
170
+
171
+ end
172
+
173
+
174
+
175
+ end
176
+
@@ -0,0 +1,92 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
+
3
+ describe AMEE::Db::Config do
4
+
5
+ describe 'with everything stored' do
6
+
7
+ before :all do
8
+ flexmock(YAML) do |mock|
9
+ mock.should_receive(:load_file).and_return('method' => 'everything').once
10
+ end
11
+ @config = AMEE::Db::BaseConfig.new
12
+ end
13
+
14
+ it 'should load method from file' do
15
+ @config.storage_method.should be(:everything)
16
+ end
17
+
18
+ it 'should correctly answer query methods' do
19
+ @config.store_metadata?.should be_true
20
+ @config.store_outputs?.should be_true
21
+ @config.store_everything?.should be_true
22
+ end
23
+
24
+ end
25
+
26
+ describe 'with metadata stored' do
27
+
28
+ before :all do
29
+ flexmock(YAML) do |mock|
30
+ mock.should_receive(:load_file).and_return('method' => 'metadata').once
31
+ end
32
+ @config = AMEE::Db::BaseConfig.new
33
+ end
34
+
35
+ it 'should correctly answer query methods' do
36
+ @config.store_metadata?.should be_true
37
+ @config.store_outputs?.should be_false
38
+ @config.store_everything?.should be_false
39
+ end
40
+
41
+ end
42
+
43
+ describe 'with outputs stored' do
44
+
45
+ before :all do
46
+ flexmock(YAML) do |mock|
47
+ mock.should_receive(:load_file).and_return('method' => 'outputs').once
48
+ end
49
+ @config = AMEE::Db::BaseConfig.new
50
+ end
51
+
52
+ it 'should correctly answer query methods' do
53
+ @config.store_metadata?.should be_true
54
+ @config.store_outputs?.should be_true
55
+ @config.store_everything?.should be_false
56
+ end
57
+
58
+ end
59
+
60
+ describe 'with invalid method' do
61
+
62
+ before :all do
63
+ flexmock(YAML) do |mock|
64
+ mock.should_receive(:load_file).and_return('method' => 'invalid').once
65
+ end
66
+ end
67
+
68
+ it 'should raise an exception on load' do
69
+ lambda {
70
+ AMEE::Db::BaseConfig.new
71
+ }.should raise_error
72
+ end
73
+
74
+ end
75
+
76
+ describe 'with invalid data in file' do
77
+
78
+ before :all do
79
+ flexmock(YAML) do |mock|
80
+ mock.should_receive(:load_file).and_return({}).once
81
+ end
82
+ end
83
+
84
+ it 'should raise an exception on load' do
85
+ lambda {
86
+ AMEE::Db::BaseConfig.new
87
+ }.should raise_error
88
+ end
89
+
90
+ end
91
+
92
+ end
@@ -0,0 +1,356 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe AMEE::DataAbstraction::OngoingCalculation do
4
+
5
+ before(:all) do
6
+ populate_db
7
+ initialize_calculation_set
8
+ end
9
+
10
+ after(:all) do
11
+ AMEE::Db::Calculation.delete_all
12
+ end
13
+
14
+ describe "find" do
15
+
16
+ before(:each) do
17
+ choose_mock
18
+ yaml_load_mock(:everything)
19
+ @reference = AMEE::Db::Calculation.find(:first).id
20
+ end
21
+
22
+ it "should create new ongoing calculation from db record" do
23
+ @db_calculation = AMEE::Db::Calculation.find :first
24
+ @ongoing_calculation = AMEE::DataAbstraction::OngoingCalculation.initialize_from_db_record @db_calculation
25
+ @ongoing_calculation.is_a?(AMEE::DataAbstraction::OngoingCalculation).should be_true
26
+ @ongoing_calculation.label.should == :electricity
27
+ @ongoing_calculation.profile_item_uid.should == "J38DY57SK591"
28
+ @ongoing_calculation.profile_uid.should be_nil
29
+ hash = @ongoing_calculation.to_hash
30
+ hash[:co2][:value].should == 1200
31
+ hash[:country][:value].should == 'Argentina'
32
+ hash[:usage][:value].should == 6000
33
+ hash[:profile_item_uid].should == "J38DY57SK591"
34
+ hash[:profile_uid].should be_nil
35
+ end
36
+
37
+ it "should create new ongoing calculation from db record with find" do
38
+ @ongoing_calculation = AMEE::DataAbstraction::OngoingCalculation.find :first
39
+ @ongoing_calculation.is_a?(AMEE::DataAbstraction::OngoingCalculation).should be_true
40
+ @ongoing_calculation.label.should == :electricity
41
+ @ongoing_calculation.profile_item_uid.should == "J38DY57SK591"
42
+ @ongoing_calculation.profile_uid.should be_nil
43
+ hash = @ongoing_calculation.to_hash
44
+ hash[:co2][:value].should == 1200
45
+ hash[:country][:value].should == 'Argentina'
46
+ hash[:usage][:value].should == 6000
47
+ hash[:profile_item_uid].should == "J38DY57SK591"
48
+ hash[:profile_uid].should be_nil
49
+ end
50
+
51
+ it "should create new ongoing calculation from db record with find and calculation type" do
52
+ @ongoing_calculation = AMEE::DataAbstraction::OngoingCalculation.find :first, :conditions => {:calculation_type => 'electricity'}
53
+ @ongoing_calculation.label.should == :electricity
54
+ @ongoing_calculation.is_a?(AMEE::DataAbstraction::OngoingCalculation).should be_true
55
+ @ongoing_calculation.profile_item_uid.should == "J38DY57SK591"
56
+ @ongoing_calculation.profile_uid.should be_nil
57
+ hash = @ongoing_calculation.to_hash
58
+ hash[:co2][:value].should == 1200
59
+ hash[:country][:value].should == 'Argentina'
60
+ hash[:usage][:value].should == 6000
61
+ hash[:profile_item_uid].should == "J38DY57SK591"
62
+ hash[:profile_uid].should be_nil
63
+ end
64
+
65
+ it "should create new ongoing calculation from db record with find and profile item uid" do
66
+ @ongoing_calculation = AMEE::DataAbstraction::OngoingCalculation.find :first, :conditions => {:profile_item_uid => "K588DH47SMN5"}
67
+ @ongoing_calculation.label.should == :electricity
68
+ @ongoing_calculation.is_a?(AMEE::DataAbstraction::OngoingCalculation).should be_true
69
+ @ongoing_calculation.profile_item_uid.should == "K588DH47SMN5"
70
+ @ongoing_calculation.profile_uid.should == "H9KJ49FKIWO5"
71
+ hash = @ongoing_calculation.to_hash
72
+ hash[:co2][:value].should == 1.2
73
+ hash[:country][:value].should == 'Argentina'
74
+ hash[:usage][:value].should == 12345
75
+ hash[:profile_item_uid].should == "K588DH47SMN5"
76
+ hash[:profile_uid].should == "H9KJ49FKIWO5"
77
+ end
78
+
79
+ it "should create multiple new ongoing calculations from db record with find" do
80
+ @ongoing_calculations = AMEE::DataAbstraction::OngoingCalculation.find :all
81
+ @ongoing_calculations.class.should == AMEE::DataAbstraction::CalculationCollection
82
+ @ongoing_calculations.each do |on_calc|
83
+ on_calc.label.should == :electricity
84
+ on_calc.is_a?(AMEE::DataAbstraction::OngoingCalculation).should be_true
85
+ on_calc.profile_item_uid.should_not be_nil
86
+ hash = on_calc.to_hash
87
+ hash[:co2][:value].should_not be_nil
88
+ hash[:country][:value].should == 'Argentina'
89
+ hash[:usage][:value].should_not be_nil
90
+ end
91
+ end
92
+
93
+ it "should create new ongoing calculation from db record with #find_by_type" do
94
+ @ongoing_calculation = AMEE::DataAbstraction::OngoingCalculation.find_by_type :first, :electricity
95
+ @ongoing_calculation.label.should == :electricity
96
+ @ongoing_calculation.is_a?(AMEE::DataAbstraction::OngoingCalculation).should be_true
97
+ @ongoing_calculation.profile_item_uid.should == "J38DY57SK591"
98
+ @ongoing_calculation.profile_uid.should == nil
99
+ hash = @ongoing_calculation.to_hash
100
+ hash[:co2][:value].should == 1200
101
+ hash[:country][:value].should == 'Argentina'
102
+ hash[:usage][:value].should == 6000
103
+ hash[:profile_item_uid].should == "J38DY57SK591"
104
+ hash[:profile_uid].should == nil
105
+ end
106
+
107
+ it "should create multiple new ongoing calculations from db record with #find_by_type" do
108
+ @ongoing_calculations = AMEE::DataAbstraction::OngoingCalculation.find_by_type :all, :electricity
109
+ @ongoing_calculations.class.should == AMEE::DataAbstraction::CalculationCollection
110
+ @ongoing_calculations.each do |on_calc|
111
+ on_calc.label.should == :electricity
112
+ on_calc.is_a?(AMEE::DataAbstraction::OngoingCalculation).should be_true
113
+ on_calc.profile_item_uid.should_not be_nil
114
+ hash = on_calc.to_hash
115
+ hash[:co2][:value].should_not be_nil
116
+ hash[:country][:value].should == 'Argentina'
117
+ hash[:usage][:value].should_not be_nil
118
+ end
119
+ end
120
+
121
+ it "should instantiate record at ongoing calc #db_calculation attribute" do
122
+ @ongoing_calculation = AMEE::DataAbstraction::OngoingCalculation.find :first
123
+ @ongoing_calculation.label.should == :electricity
124
+ @ongoing_calculation.to_hash[:co2][:value].should == 1200
125
+ @ongoing_calculation.db_calculation.is_a?(AMEE::Db::Calculation).should be_true
126
+ @ongoing_calculation.db_calculation.id.should == @reference
127
+ end
128
+
129
+ it "should find assocaited db instance by id" do
130
+ @ongoing_calculation = AMEE::DataAbstraction::OngoingCalculation.find @reference
131
+ @ongoing_calculation.id.should == @reference
132
+ end
133
+
134
+
135
+ it "should give nil id, if not saved" do
136
+ Calculations[:electricity].begin_calculation.db_calculation.should be_nil
137
+ Calculations[:electricity].begin_calculation.id.should be_nil
138
+ end
139
+ end
140
+
141
+ describe "when storage method is :everything" do
142
+
143
+ before(:each) do
144
+ choose_mock
145
+ yaml_load_mock(:everything)
146
+ @ongoing_calculation = AMEE::DataAbstraction::OngoingCalculation.find :first
147
+ end
148
+
149
+ it "should find storage method" do
150
+ AMEE::DataAbstraction::OngoingCalculation.storage_method.should == :everything
151
+ end
152
+
153
+ it "should start off dirty" do
154
+ @ongoing_calculation.should be_dirty
155
+ end
156
+
157
+ it "should establish whether inputs to be stored" do
158
+ AMEE::DataAbstraction::OngoingCalculation.store_inputs?.should be_true
159
+ end
160
+
161
+ it "should establish whether outputs to be stored" do
162
+ AMEE::DataAbstraction::OngoingCalculation.store_outputs?.should be_true
163
+ end
164
+
165
+ it "should establish whether metadata to be stored" do
166
+ AMEE::DataAbstraction::OngoingCalculation.store_metadata?.should be_true
167
+ end
168
+
169
+ it "should return array of terms for storing which includes all terms" do
170
+ @ongoing_calculation.stored_terms.should == @ongoing_calculation.terms
171
+ end
172
+
173
+ it "should return hash with all terms" do
174
+ hash = @ongoing_calculation.to_hash
175
+ hash.is_a?(Hash).should be_true
176
+ hash.should == @ongoing_calculation.to_hash(:full)
177
+ hash.keys.map!(&:to_s).sort!.should == [:profile_item_uid, :profile_uid, :calculation_type,
178
+ :co2, :usage, :country ].map!(&:to_s).sort!
179
+ end
180
+
181
+ it "should save all terms" do
182
+ record = @ongoing_calculation.db_calculation
183
+ # show that db record has values
184
+ record.to_hash.keys.map!(&:to_s).sort!.should == [:profile_item_uid, :profile_uid, :co2,
185
+ :usage, :country ].map!(&:to_s).sort!
186
+ record.to_hash[:co2][:value].should == 1200
187
+ record.to_hash[:usage][:value].should == 6000
188
+ # wipe terms from db record by updating with nothing
189
+ record.update_calculation!(options={})
190
+ # show that db record contains no terms
191
+ record.to_hash.keys.map!(&:to_s).sort!.should == [:profile_item_uid, :profile_uid ].map!(&:to_s).sort!
192
+ # show that by saving ongoing calculation, db record has terms
193
+ @ongoing_calculation.save
194
+ record = @ongoing_calculation.db_calculation
195
+ record.to_hash.keys.map!(&:to_s).sort!.should == [:profile_item_uid, :profile_uid, :co2,
196
+ :usage, :country ].map!(&:to_s).sort!
197
+ record.to_hash[:co2][:value].should == 1200
198
+ record.to_hash[:usage][:value].should == 6000
199
+ end
200
+
201
+ end
202
+
203
+ describe "when storage method is :metadata" do
204
+
205
+ before(:each) do
206
+ choose_mock
207
+ yaml_load_mock(:metadata)
208
+ @ongoing_calculation = AMEE::DataAbstraction::OngoingCalculation.find :first
209
+ end
210
+
211
+ it "should find storage method" do
212
+ AMEE::DataAbstraction::OngoingCalculation.storage_method.should == :metadata
213
+ end
214
+
215
+ it "should establish whether inputs to be stored" do
216
+ AMEE::DataAbstraction::OngoingCalculation.store_inputs?.should be_false
217
+ end
218
+
219
+ it "should establish whether outputs to be stored" do
220
+ AMEE::DataAbstraction::OngoingCalculation.store_outputs?.should be_false
221
+ end
222
+
223
+ it "should establish whether metadata to be stored" do
224
+ AMEE::DataAbstraction::OngoingCalculation.store_metadata?.should be_true
225
+ end
226
+
227
+ it "should start off dirty" do
228
+ @ongoing_calculation.should be_dirty
229
+ end
230
+
231
+ it "should return array of terms for storing which includes only metadata" do
232
+ @ongoing_calculation.stored_terms.should_not == @ongoing_calculation.terms
233
+ end
234
+
235
+ it "should return hash with only metadata terms" do
236
+ hash = @ongoing_calculation.to_hash
237
+ hash.is_a?(Hash).should be_true
238
+ hash.should_not == @ongoing_calculation.to_hash(:full)
239
+ hash.keys.map!(&:to_s).sort!.should == [:profile_item_uid, :profile_uid,
240
+ :calculation_type ].map!(&:to_s).sort!
241
+ end
242
+
243
+ it "should save only metadata terms" do
244
+ record = @ongoing_calculation.db_calculation
245
+ # show that db record has values
246
+ record.to_hash.keys.map!(&:to_s).sort!.should == [:profile_item_uid, :profile_uid, :co2,
247
+ :usage, :country ].map!(&:to_s).sort!
248
+ record.to_hash[:co2][:value].should == 1200
249
+ record.to_hash[:usage][:value].should == 6000
250
+ # show that db record contains no terms after save
251
+ @ongoing_calculation.save
252
+ record = @ongoing_calculation.db_calculation
253
+ record.to_hash.keys.map!(&:to_s).sort!.should == [:profile_item_uid, :profile_uid ].map!(&:to_s).sort!
254
+ record.to_hash[:co2].should == nil
255
+ record.to_hash[:usage].should == nil
256
+ end
257
+
258
+ end
259
+
260
+ describe "when storage method is :outputs" do
261
+
262
+ before(:each) do
263
+ choose_mock
264
+ yaml_load_mock(:outputs)
265
+ @ongoing_calculation = AMEE::DataAbstraction::OngoingCalculation.find :first
266
+ end
267
+
268
+ it "should find storage method" do
269
+ AMEE::DataAbstraction::OngoingCalculation.storage_method.should == :outputs
270
+ end
271
+
272
+ it "should establish whether inputs to be stored" do
273
+ AMEE::DataAbstraction::OngoingCalculation.store_inputs?.should be_false
274
+ end
275
+
276
+ it "should establish whether outputs to be stored" do
277
+ AMEE::DataAbstraction::OngoingCalculation.store_outputs?.should be_true
278
+ end
279
+
280
+ it "should establish whether metadata to be stored" do
281
+ AMEE::DataAbstraction::OngoingCalculation.store_metadata?.should be_true
282
+ end
283
+
284
+ it "should start off dirty" do
285
+ @ongoing_calculation.should be_dirty
286
+ end
287
+
288
+ it "should return array of terms for storing which includes only outputs and metadata" do
289
+ @ongoing_calculation.stored_terms.should_not == @ongoing_calculation.terms
290
+ end
291
+
292
+ it "should return hash with only output and metadata terms" do
293
+ hash = @ongoing_calculation.to_hash
294
+ hash.is_a?(Hash).should be_true
295
+ hash.should_not == @ongoing_calculation.to_hash(:full)
296
+ hash.keys.map!(&:to_s).sort!.should == [:profile_item_uid, :profile_uid,
297
+ :calculation_type, :co2 ].map!(&:to_s).sort!
298
+ end
299
+
300
+ it "should save only output terms" do
301
+ record = @ongoing_calculation.db_calculation
302
+ # show that db record has all values
303
+ record.to_hash.keys.map!(&:to_s).sort!.should == [:profile_item_uid, :profile_uid, :co2,
304
+ :usage, :country ].map!(&:to_s).sort!
305
+ record.to_hash[:co2][:value].should == 1200
306
+ record.to_hash[:usage][:value].should == 6000
307
+ # show that db record contains only output terms after save
308
+ @ongoing_calculation.save
309
+ record = @ongoing_calculation.db_calculation
310
+ record.to_hash.keys.map!(&:to_s).sort!.should == [:profile_item_uid, :profile_uid, :co2 ].map!(&:to_s).sort!
311
+ record.to_hash[:co2][:value].should == 1200
312
+ record.to_hash[:usage].should == nil
313
+ end
314
+
315
+ end
316
+
317
+ describe "saving" do
318
+
319
+ before :each do
320
+ choose_mock
321
+ yaml_load_mock(:outputs)
322
+ @ongoing_calculation = AMEE::DataAbstraction::OngoingCalculation.find :first
323
+ end
324
+
325
+ it "should return true if successful" do
326
+ @ongoing_calculation.save.should eql true
327
+ end
328
+
329
+ it "should return false if unsuccessful" do
330
+ # Mock to make save fail
331
+ flexmock(@ongoing_calculation.db_calculation).should_receive(:save!).and_raise(ActiveRecord::RecordNotSaved)
332
+ # Saving should now return false, propogating errors from AR::Base
333
+ @ongoing_calculation.save.should eql false
334
+ end
335
+
336
+ end
337
+
338
+ describe "deleting calculation" do
339
+
340
+ before(:all) do
341
+ choose_mock
342
+ delete_mock
343
+ @ongoing_calculation = AMEE::DataAbstraction::OngoingCalculation.find :first
344
+ end
345
+
346
+ it "should remove record from db" do
347
+ db_reference = @ongoing_calculation.db_calculation.id
348
+ item_uid = @ongoing_calculation.send :profile_item_uid
349
+ @ongoing_calculation.delete
350
+ @ongoing_calculation.db_calculation.should be_nil
351
+ AMEE::Db::Calculation.find_by_profile_item_uid(item_uid).should be_nil
352
+ lambda{AMEE::Db::Calculation.find(db_reference)}.should raise_error
353
+ end
354
+ end
355
+
356
+ end