amee-data-persistence 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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