ruby-plsql-spec 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +13 -0
  2. data/Gemfile +11 -0
  3. data/History.txt +5 -0
  4. data/INSTALL-Windows.markdown +55 -0
  5. data/License.txt +20 -0
  6. data/README.markdown +91 -0
  7. data/Rakefile +49 -0
  8. data/VERSION +1 -0
  9. data/bin/plsql-spec +5 -0
  10. data/examples/source/award_bonus.rb +29 -0
  11. data/examples/source/betwnstr.rb +19 -0
  12. data/examples/source/remove_rooms_by_name.rb +45 -0
  13. data/examples/source/what_is_profiled.rb +207 -0
  14. data/examples/spec/award_bonus_spec.rb +35 -0
  15. data/examples/spec/betwnstr_spec.rb +24 -0
  16. data/examples/spec/database.yml +16 -0
  17. data/examples/spec/factories/employee_factory.rb +23 -0
  18. data/examples/spec/helpers/inspect_helpers.rb +17 -0
  19. data/examples/spec/helpers/oracle_ebs_helpers.rb +32 -0
  20. data/examples/spec/helpers/time_helpers.rb +5 -0
  21. data/examples/spec/oracle_ebs_spec.rb +61 -0
  22. data/examples/spec/remove_rooms_by_name_spec.rb +51 -0
  23. data/examples/spec/spec_helper.rb +78 -0
  24. data/examples/spec/what_is_profiled_spec.rb +12 -0
  25. data/lib/plsql/coverage.rb +262 -0
  26. data/lib/plsql/coverage/coverage.css +277 -0
  27. data/lib/plsql/coverage/details.html.erb +35 -0
  28. data/lib/plsql/coverage/index.html.erb +71 -0
  29. data/lib/plsql/coverage/jquery.min.js +154 -0
  30. data/lib/plsql/coverage/jquery.tablesorter.min.js +2 -0
  31. data/lib/plsql/coverage/proftab.sql +66 -0
  32. data/lib/plsql/coverage/rcov.js +43 -0
  33. data/lib/plsql/coverage/table_line.html.erb +15 -0
  34. data/lib/plsql/spec.rb +5 -0
  35. data/lib/plsql/spec/cli.rb +81 -0
  36. data/lib/plsql/spec/templates/database.yml +16 -0
  37. data/lib/plsql/spec/templates/helpers/inspect_helpers.rb +17 -0
  38. data/lib/plsql/spec/templates/helpers/time_helpers.rb +5 -0
  39. data/lib/plsql/spec/templates/spec_helper.rb +78 -0
  40. data/lib/plsql/spec/version.rb +5 -0
  41. data/lib/ruby-plsql-spec.rb +1 -0
  42. data/ruby-plsql-spec.gemspec +113 -0
  43. data/spec/plsql/coverage_spec.rb +246 -0
  44. data/spec/plsql/spec/cli_spec.rb +264 -0
  45. data/spec/spec.opts +6 -0
  46. data/spec/spec_helper.rb +61 -0
  47. metadata +177 -0
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ # load 'award_bonus' procedure into the database
4
+ require 'award_bonus'
5
+
6
+ describe "Award bonus" do
7
+ include EmployeeFactory
8
+
9
+ [ [1000, 1234.55, 0.10, 1123.46],
10
+ [nil, 1234.56, 0.10, 123.46],
11
+ [1000, 1234.54, 0.10, 1123.45]
12
+ ].each do |salary, sales_amt, commission_pct, result|
13
+ it "should calculate base salary #{salary.inspect} + sales amount #{sales_amt} * commission percentage #{commission_pct} = salary #{result.inspect}" do
14
+ employee = create_employee(
15
+ :commission_pct => commission_pct,
16
+ :salary => salary
17
+ )
18
+ plsql.award_bonus(employee[:employee_id], sales_amt)
19
+ get_employee(employee[:employee_id])[:salary].should == result
20
+ end
21
+ end
22
+
23
+ it "should raise ORA-06510 exception if commission percentage is missing" do
24
+ salary, sales_amt, commission_pct = 1000, 1234.55, NULL
25
+ employee = create_employee(
26
+ :commission_pct => commission_pct,
27
+ :salary => salary
28
+ )
29
+ lambda {
30
+ plsql.award_bonus(employee[:employee_id], sales_amt)
31
+ }.should raise_error(/ORA-06510/)
32
+ end
33
+
34
+ end
35
+
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ # load 'betwnstr' procedure into the database
4
+ require "betwnstr"
5
+
6
+ describe "Between string" do
7
+ it "should be correct in normal case" do
8
+ plsql.betwnstr('abcdefg', 2, 5).should == 'bcde'
9
+ end
10
+
11
+ it "should be correct with zero start value" do
12
+ plsql.betwnstr('abcdefg', 0, 5).should == 'abcde'
13
+ end
14
+
15
+ it "should be correct with way big end value" do
16
+ plsql.betwnstr('abcdefg', 5, 500).should == 'efg'
17
+ end
18
+
19
+ it "should be correct with NULL string" do
20
+ plsql.betwnstr(NULL, 5, 500).should == NULL
21
+ end
22
+
23
+ end
24
+
@@ -0,0 +1,16 @@
1
+ # Change default connection username, password and database.
2
+ # Specify also host and port if not using tnsnames.ora connection.
3
+ default:
4
+ username: hr
5
+ password: hr
6
+ database: orcl
7
+ # host: localhost
8
+ # port: 1521
9
+
10
+ # Add other connection if needed.
11
+ # You can access them with plsql(:other) where :other is connection name specified below.
12
+
13
+ # other:
14
+ # username: scott
15
+ # password: tiger
16
+ # database: xe
@@ -0,0 +1,23 @@
1
+ module EmployeeFactory
2
+ # Creates new employee with valid field values.
3
+ # Pass in parameters only field values that you want to override.
4
+ def create_employee(params)
5
+ employee = {
6
+ :employee_id => plsql.employees2_seq.nextval,
7
+ :last_name => 'Last',
8
+ :email => 'last@example.com',
9
+ :hire_date => Date.today,
10
+ :job_id => plsql.jobs.first[:job_id],
11
+ :commission_pct => nil,
12
+ :salary => nil
13
+ }.merge(params)
14
+ plsql.employees2.insert employee
15
+ get_employee employee[:employee_id]
16
+ end
17
+
18
+ # Select employee by primary key
19
+ def get_employee(employee_id)
20
+ plsql.employees2.first :employee_id => employee_id
21
+ end
22
+
23
+ end
@@ -0,0 +1,17 @@
1
+ # As ruby-plsql returns NUMBER values as BigDecimal values in Ruby then
2
+ # change format how they are by default displayed
3
+ BigDecimal.class_eval do
4
+ def inspect
5
+ to_s('F')
6
+ end
7
+ end
8
+
9
+ # As ruby-plsql returns NULL as Ruby nil then change nil.inspect to return 'NULL'
10
+ NilClass.class_eval do
11
+ def inspect
12
+ 'NULL'
13
+ end
14
+ end
15
+
16
+ # NULL looks more like SQL NULL than nil
17
+ NULL = nil
@@ -0,0 +1,32 @@
1
+ # initialize Oracle E-Business Suite session with specified user and responsibility
2
+ def init_ebs_user(params={})
3
+ # replace with default user name and responsibility and then it will not be necessary
4
+ # to specify default value as parameter
5
+ params = {
6
+ :user_name => "default user name",
7
+ :responsibility_name => "default responsibility"
8
+ }.merge(params)
9
+
10
+ row = plsql.select(:first, "SELECT usr.user_name, res.responsibility_name, usr.user_id,
11
+ urg.responsibility_id, urg.responsibility_application_id resp_appl_id
12
+ FROM apps.fnd_user_resp_groups urg,
13
+ applsys.fnd_user usr,
14
+ fnd_responsibility_vl res
15
+ WHERE usr.user_name = :user_name
16
+ AND res.responsibility_name = :responsibility_name
17
+ AND urg.user_id = usr.user_id
18
+ AND res.responsibility_id = urg.responsibility_id",
19
+ params[:user_name], params[:responsibility_name])
20
+
21
+ raise ArgumentError, "Wrong user name or responsibility name" unless row
22
+
23
+ plsql.fnd_global.apps_initialize(
24
+ :user_id => row[:user_id],
25
+ :resp_id => row[:responsibility_id],
26
+ :resp_appl_id => row[:resp_appl_id]
27
+ )
28
+
29
+ # uncomment if logging to dbms_output is necessary
30
+ # plsql.dbms_output.put_line("Initialized " + params[:user_name] + " / " + params[:responsibility_name])
31
+
32
+ end
@@ -0,0 +1,5 @@
1
+ # return current date with time 00:00:00
2
+ def Time.today
3
+ t = Time.now
4
+ Time.local(t.year, t.month, t.day)
5
+ end unless Time.respond_to?(:today)
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Oracle E-Business Suite" do
4
+ before(:all) do
5
+ # @old_connection = plsql.connection
6
+ # plsql.connect! "APPS", "APPS", "VIS"
7
+ @user_name = "OPERATIONS"
8
+ @responsibility_name = "System Administrator"
9
+ end
10
+
11
+ after(:all) do
12
+ # plsql.connection = @old_connection
13
+ end
14
+
15
+ if plsql.schema_name == 'APPS'
16
+
17
+ describe "Session initialization" do
18
+ it "should initialize session with valid user and responsibility" do
19
+ lambda {
20
+ init_ebs_user(:user_name => @user_name, :responsibility_name => @responsibility_name)
21
+ }.should_not raise_error
22
+ end
23
+
24
+ it "should raise error with invalid user" do
25
+ lambda {
26
+ init_ebs_user(:user_name => "INVALID", :responsibility_name => @responsibility_name)
27
+ }.should raise_error(/Wrong user name or responsibility name/)
28
+ end
29
+
30
+ it "should raise error with invalid responsibility" do
31
+ lambda {
32
+ init_ebs_user(:user_name => @user_name, :responsibility_name => "INVALID")
33
+ }.should raise_error(/Wrong user name or responsibility name/)
34
+ end
35
+
36
+ it "should raise error with default username and responsibility parameters" do
37
+ lambda {
38
+ init_ebs_user
39
+ }.should raise_error(/Wrong user name or responsibility name/)
40
+ end
41
+
42
+ end
43
+
44
+ describe "Session information" do
45
+ before(:all) do
46
+ init_ebs_user(:user_name => @user_name, :responsibility_name => @responsibility_name)
47
+ end
48
+
49
+ it "should return user name" do
50
+ plsql.fnd_global.user_name.should == @user_name
51
+ end
52
+
53
+ it "should return responsibility name" do
54
+ plsql.fnd_global.resp_name.should == @responsibility_name
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ require 'remove_rooms_by_name'
4
+
5
+ describe "Remove rooms by name" do
6
+ before(:all) do
7
+ plsql.rooms.insert_values(
8
+ [:room_key, :name],
9
+ [1, 'Dining Room'],
10
+ [2, 'Living Room'],
11
+ [3, 'Office'],
12
+ [4, 'Bathroom'],
13
+ [5, 'Bedroom']
14
+ )
15
+ plsql.room_contents.insert_values(
16
+ [:contents_key, :room_key, :name],
17
+ [1, 1, 'Table'],
18
+ [2, 1, 'Hutch'],
19
+ [3, 1, 'Chair'],
20
+ [4, 2, 'Sofa'],
21
+ [5, 2, 'Lamp'],
22
+ [6, 3, 'Desk'],
23
+ [7, 3, 'Chair'],
24
+ [8, 3, 'Computer'],
25
+ [9, 3, 'Whiteboard']
26
+ )
27
+ end
28
+
29
+ it "should remove a room without furniture" do
30
+ rooms_without_b = plsql.rooms.all("WHERE name NOT LIKE 'B%'")
31
+ plsql.remove_rooms_by_name('B%')
32
+ plsql.rooms.all.should == rooms_without_b
33
+ end
34
+
35
+ it "should not remove a room with furniture" do
36
+ lambda {
37
+ lambda {
38
+ plsql.remove_rooms_by_name('Living Room')
39
+ }.should raise_error(/ORA-02292/)
40
+ }.should_not change { plsql.rooms.all }
41
+ end
42
+
43
+ it "should raise exception when NULL value passed" do
44
+ lambda {
45
+ lambda {
46
+ plsql.remove_rooms_by_name(NULL)
47
+ }.should raise_error(/program error/)
48
+ }.should_not change { plsql.rooms.all }
49
+ end
50
+
51
+ end
@@ -0,0 +1,78 @@
1
+ require "rubygems"
2
+ require "ruby-plsql-spec"
3
+ require "yaml"
4
+
5
+ # create all connections specified in database.yml file
6
+ database_config_file = File.expand_path('../database.yml', __FILE__)
7
+ database_config = YAML.load(File.read(database_config_file))
8
+ database_config = {} unless database_config.is_a?(Hash)
9
+ database_connections = database_config.keys.map{|k| k.to_sym}
10
+
11
+ database_config.each do |name, params|
12
+ # change all keys to symbols
13
+ name = name.to_sym
14
+ symbol_params = Hash[*params.map{|k,v| [k.to_sym, v]}.flatten]
15
+
16
+ plsql(name).connect! symbol_params
17
+
18
+ # Set autocommit to false so that automatic commits after each statement are _not_ performed
19
+ plsql(name).connection.autocommit = false
20
+ # reduce network traffic in case of large resultsets
21
+ plsql(name).connection.prefetch_rows = 100
22
+ # log DBMS_OUTPUT to standard output
23
+ if ENV['PLSQL_DBMS_OUTPUT']
24
+ plsql(name).dbms_output_stream = STDOUT
25
+ end
26
+
27
+ # start code coverage collection
28
+ if ENV['PLSQL_COVERAGE']
29
+ PLSQL::Coverage.start(name)
30
+ end
31
+ end
32
+
33
+ # Do logoff when exiting to ensure that session temporary tables
34
+ # (used when calling procedures with table types defined in packages)
35
+ at_exit do
36
+ database_connections.each do |name|
37
+ if ENV['PLSQL_COVERAGE']
38
+ PLSQL::Coverage.stop(name)
39
+ coverage_directory = name == :default ? ENV['PLSQL_COVERAGE'] : "#{ENV['PLSQL_COVERAGE']}/#{name}"
40
+ options = {:directory => coverage_directory}
41
+ options[:ignore_schemas] = ENV['PLSQL_COVERAGE_IGNORE_SCHEMAS'].split(',') if ENV['PLSQL_COVERAGE_IGNORE_SCHEMAS']
42
+ options[:like] = ENV['PLSQL_COVERAGE_LIKE'].split(',') if ENV['PLSQL_COVERAGE_LIKE']
43
+ PLSQL::Coverage.report name, options
44
+ PLSQL::Coverage.cleanup name
45
+ end
46
+ plsql(name).logoff
47
+ end
48
+ end
49
+
50
+ Spec::Runner.configure do |config|
51
+ config.before(:each) do
52
+ database_connections.each do |name|
53
+ plsql(name).savepoint "before_each"
54
+ end
55
+ end
56
+ config.after(:each) do
57
+ # Always perform rollback to savepoint after each test
58
+ database_connections.each do |name|
59
+ plsql(name).rollback_to "before_each"
60
+ end
61
+ end
62
+ config.after(:all) do
63
+ # Always perform rollback after each describe block
64
+ database_connections.each do |name|
65
+ plsql(name).rollback
66
+ end
67
+ end
68
+ end
69
+
70
+ # require all helper methods which are located in any helpers subdirectories
71
+ Dir[File.dirname(__FILE__) + '/**/helpers/*.rb'].each {|f| require f}
72
+
73
+ # require all factory modules which are located in any factories subdirectories
74
+ Dir[File.dirname(__FILE__) + '/**/factories/*.rb'].each {|f| require f}
75
+
76
+ # If necessary add source directory to load path where PL/SQL procedures are defined.
77
+ # It is not required if PL/SQL procedures are already loaded in test database in some other way.
78
+ $:.push File.dirname(__FILE__) + '/../source'
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ require 'what_is_profiled'
4
+
5
+ describe "what is profiled" do
6
+ it "should run driver" do
7
+ lambda {
8
+ plsql.what_is_profiled.driver
9
+ }.should_not raise_error
10
+ end
11
+
12
+ end
@@ -0,0 +1,262 @@
1
+ module PLSQL
2
+ class Coverage
3
+ @@coverages = {}
4
+
5
+ attr_accessor :directory
6
+
7
+ # used in tests to reset coverages cache
8
+ def self.reset_cache
9
+ @@coverages = {}
10
+ end
11
+
12
+ def self.start(connection_alias = nil)
13
+ find_or_new(connection_alias).start
14
+ end
15
+
16
+ def initialize(connection_alias)
17
+ @connection_alias = connection_alias
18
+ end
19
+
20
+ def start
21
+ # ignore repeated invocation
22
+ return false if @started
23
+ create_profiler_tables
24
+ result = plsql(@connection_alias).dbms_profiler.start_profiler(
25
+ :run_comment => "ruby-plsql-spec #{Time.now.xmlschema}",
26
+ :run_number => nil
27
+ )
28
+ @run_number = result[1][:run_number]
29
+ @coverages = nil
30
+ @started = true
31
+ end
32
+
33
+ def self.stop(connection_alias = nil)
34
+ find_or_new(connection_alias).stop
35
+ end
36
+
37
+ def stop
38
+ # ignore repeated invocation
39
+ return false unless @started
40
+ plsql(@connection_alias).dbms_profiler.stop_profiler
41
+ @started = false
42
+ true
43
+ end
44
+
45
+ def self.cleanup(connection_alias = nil)
46
+ find(connection_alias).cleanup
47
+ end
48
+
49
+ def cleanup
50
+ return false if @started
51
+ drop_or_delete_profiler_tables
52
+ true
53
+ end
54
+
55
+ def self.find(connection_alias = nil)
56
+ connection_alias ||= :default
57
+ @@coverages[connection_alias]
58
+ end
59
+
60
+ def self.report(connection_alias = nil, options = {})
61
+ # if first parameter is Hash then consider it as options and use default connection
62
+ if connection_alias.is_a?(Hash)
63
+ options = connection_alias
64
+ connection_alias = nil
65
+ end
66
+ find(connection_alias).report(options)
67
+ end
68
+
69
+ def report(options={})
70
+ # prevent repeated invocation after coverage is reported
71
+ # return if @coverages
72
+
73
+ @directory = options.delete(:directory)
74
+ coverage_data(options)
75
+ create_static_files
76
+ read_templates
77
+
78
+ # Loop through each database object, evaluating it along with the template
79
+ @coverage_data.keys.sort.each do |schema|
80
+ @coverage_data[schema].keys.sort.each do |object|
81
+ details_report(schema, object)
82
+ end
83
+ end
84
+
85
+ index_report
86
+ true
87
+ end
88
+
89
+ def coverage_data(options={})
90
+ quoted_ignore_schemas = if options[:ignore_schemas]
91
+ options[:ignore_schemas].map{|schema| quote_condition_string(schema)}
92
+ else
93
+ %w('SYS')
94
+ end
95
+ quoted_ignore_schemas << "'<anonymous>'"
96
+ like_condition = if options[:like]
97
+ 'AND ((' << Array(options[:like]).map do |like|
98
+ like_schema, like_object = like.split('.')
99
+ condition = "u.unit_owner LIKE #{quote_condition_string(like_schema)}"
100
+ condition << " AND u.unit_name LIKE #{quote_condition_string(like_object)}" if like_object
101
+ end.join(') OR (') << '))'
102
+ else
103
+ nil
104
+ end
105
+ data = {}
106
+ rows = plsql(@connection_alias).select_all <<-EOS
107
+ SELECT u.unit_owner, u.unit_name, d.line# line_number, d.total_occur
108
+ FROM plsql_profiler_units u, plsql_profiler_data d
109
+ WHERE u.runid = #{@run_number}
110
+ AND u.unit_owner NOT IN (#{quoted_ignore_schemas.join(',')})
111
+ AND u.runid = d.runid
112
+ AND u.unit_number = d.unit_number
113
+ #{like_condition}
114
+ ORDER BY u.unit_owner, u.unit_name, d.line#
115
+ EOS
116
+ rows.each do |row|
117
+ unit_owner, unit_name, line_number, total_occur = row
118
+ data[unit_owner] ||= {}
119
+ data[unit_owner][unit_name] ||= {}
120
+ data[unit_owner][unit_name][line_number] = total_occur
121
+ end
122
+ @coverage_data = data
123
+ end
124
+
125
+ private
126
+
127
+ def self.find_or_new(connection_alias) #:nodoc:
128
+ connection_alias ||= :default
129
+ if @@coverages[connection_alias]
130
+ @@coverages[connection_alias]
131
+ else
132
+ @@coverages[connection_alias] = self.new(connection_alias)
133
+ end
134
+ end
135
+
136
+ def create_profiler_tables
137
+ unless PLSQL::Table.find(plsql(@connection_alias), 'plsql_profiler_data')
138
+ proftab_file = File.expand_path('../coverage/proftab.sql', __FILE__)
139
+ File.read(proftab_file).split(";\n").each do |sql|
140
+ if sql =~ /^drop/i
141
+ plsql(@connection_alias).execute sql rescue nil
142
+ elsif sql =~ /^(create|comment)/i
143
+ plsql(@connection_alias).execute sql
144
+ end
145
+ end
146
+ @created_profiler_tables = true
147
+ end
148
+ end
149
+
150
+ def drop_or_delete_profiler_tables
151
+ if @created_profiler_tables
152
+ %w(plsql_profiler_data plsql_profiler_units plsql_profiler_runs).each do |table|
153
+ plsql(@connection_alias).execute "DROP TABLE #{table} CASCADE CONSTRAINTS"
154
+ end
155
+ plsql(@connection_alias).execute "DROP SEQUENCE plsql_profiler_runnumber"
156
+ else @run_number
157
+ plsql(@connection_alias).execute <<-SQL, @run_number
158
+ DECLARE
159
+ PRAGMA AUTONOMOUS_TRANSACTION;
160
+ v_runid BINARY_INTEGER := :runid;
161
+ BEGIN
162
+ DELETE FROM plsql_profiler_data WHERE runid = v_runid;
163
+ DELETE FROM plsql_profiler_units WHERE runid = v_runid;
164
+ DELETE FROM plsql_profiler_runs WHERE runid = v_runid;
165
+ COMMIT;
166
+ END;
167
+ SQL
168
+ end
169
+ end
170
+
171
+ def quote_condition_string(string)
172
+ "'#{string.to_s.upcase.gsub(/[^\w\d\$\%\_]/,'')}'"
173
+ end
174
+
175
+ def create_static_files
176
+ FileUtils.mkdir_p("#{@directory}")
177
+ %w(coverage.css jquery.min.js jquery.tablesorter.min.js rcov.js).each do |file|
178
+ FileUtils.cp File.expand_path("../coverage/#{file}", __FILE__), "#{@directory}/#{file}"
179
+ end
180
+ end
181
+
182
+ def read_templates
183
+ %w(details table_line index).each do |template|
184
+ template_erb = File.read(File.expand_path("../coverage/#{template}.html.erb", __FILE__))
185
+ instance_variable_set("@#{template}_template", ERB.new(template_erb, nil, '><'))
186
+ end
187
+
188
+ @table_lines = []
189
+ @total_lines = @analyzed_lines = @executed_lines = 0
190
+ end
191
+
192
+ def details_report(schema, object)
193
+ source = plsql(@connection_alias).select_all <<-EOS, schema, object
194
+ SELECT s.line, s.text
195
+ FROM all_source s
196
+ WHERE s.owner = :owner
197
+ AND s.name = :name
198
+ AND s.type NOT IN ('PACKAGE')
199
+ ORDER BY s.line
200
+ EOS
201
+ coverage = (@coverage_data[schema]||{})[object]||{}
202
+
203
+ total_lines = source.length
204
+ # return if no access to source of database object
205
+ # or if package body is wrapped
206
+ return if total_lines == 0 || source[0][1] =~ /^\s*PACKAGE BODY .* WRAPPED/i
207
+
208
+ # sometimes first PROCEDURE or FUNCTION line is reported as not executed, force ignoring it
209
+ source.each do |line, text|
210
+ if text =~ /^\s*(PROCEDURE|FUNCTION)/ && coverage[line] == 0
211
+ coverage.delete(line)
212
+ end
213
+ end
214
+
215
+ @total_lines += total_lines
216
+ analyzed_lines = executed_lines = 0
217
+ coverage.each do |line, value|
218
+ analyzed_lines += 1
219
+ executed_lines += 1 if value > 0
220
+ end
221
+ @analyzed_lines += analyzed_lines
222
+ @executed_lines += executed_lines
223
+ total_coverage = (total_lines - analyzed_lines + executed_lines).to_f / total_lines * 100
224
+ code_coverage = analyzed_lines > 0 ? executed_lines.to_f / analyzed_lines * 100 : 0
225
+
226
+ file_name = "#{schema}-#{object}.html"
227
+ object_name = "#{schema}.#{object}"
228
+
229
+ table_line_html = @table_line_template.result binding
230
+ @table_lines << table_line_html
231
+ html = @details_template.result binding
232
+
233
+ File.open("#{@directory}/#{file_name}", "w") do |file|
234
+ file.write html
235
+ end
236
+ end
237
+
238
+ def index_report
239
+ schemas = @coverage_data.keys.sort
240
+ table_lines_html = @table_lines.join("\n")
241
+
242
+ total_lines, analyzed_lines, executed_lines = @total_lines, @analyzed_lines, @executed_lines
243
+ # return if no access to source of database objects
244
+ return if total_lines == 0
245
+
246
+ total_coverage = (total_lines - analyzed_lines + executed_lines).to_f / total_lines * 100
247
+ code_coverage = analyzed_lines > 0 ? executed_lines.to_f / analyzed_lines * 100 : 0
248
+
249
+ schema = file_name = nil
250
+ object_name = 'TOTAL'
251
+
252
+ table_footer_html = @table_line_template.result binding
253
+
254
+ html = @index_template.result binding
255
+
256
+ File.open("#{@directory}/index.html", "w") do |file|
257
+ file.write html
258
+ end
259
+ end
260
+
261
+ end
262
+ end