soda 0.0.1
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.
- data/lib/FieldUtils.rb +102 -0
- data/lib/Soda.rb +2628 -0
- data/lib/SodaCSV.rb +88 -0
- data/lib/SodaFireFox.rb +118 -0
- data/lib/SodaLogReporter.rb +810 -0
- data/lib/SodaReportSummery.rb +470 -0
- data/lib/SodaReporter.rb +452 -0
- data/lib/SodaTestCheck.rb +347 -0
- data/lib/SodaUtils.rb +931 -0
- data/lib/SodaXML.rb +129 -0
- data/lib/fields/CheckBoxField.rb +87 -0
- data/lib/fields/FileField.rb +37 -0
- data/lib/fields/LiField.rb +40 -0
- data/lib/fields/RadioField.rb +44 -0
- data/lib/fields/SelectField.rb +59 -0
- data/lib/fields/SodaField.rb +363 -0
- data/lib/fields/TextField.rb +31 -0
- data/lib/soda.rb +2 -0
- data/lib/utils/sodalookups.rb +465 -0
- metadata +114 -0
data/lib/SodaCSV.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
###############################################################################
|
2
|
+
# Copyright (c) 2010, SugarCRM, Inc.
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
# * Redistributions of source code must retain the above copyright
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
9
|
+
# * Redistributions in binary form must reproduce the above copyright
|
10
|
+
# notice, this list of conditions and the following disclaimer in the
|
11
|
+
# documentation and/or other materials provided with the distribution.
|
12
|
+
# * Neither the name of SugarCRM, Inc. nor the
|
13
|
+
# names of its contributors may be used to endorse or promote products
|
14
|
+
# derived from this software without specific prior written permission.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL SugarCRM, Inc. BE LIABLE FOR ANY
|
20
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
21
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
22
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
23
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
24
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
25
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
26
|
+
###############################################################################
|
27
|
+
|
28
|
+
###############################################################################
|
29
|
+
# Needed Ruby Libs:
|
30
|
+
###############################################################################
|
31
|
+
require "csv"
|
32
|
+
|
33
|
+
###############################################################################
|
34
|
+
# SodaCSV -- Class
|
35
|
+
# This class parses CSV files and converts them into records that can be
|
36
|
+
# accessed as variables in Soda XML scripts. The first ROW of CSV file is
|
37
|
+
# the variable names to be used Then each subsequent ROW is data.
|
38
|
+
#
|
39
|
+
# Params:
|
40
|
+
# file: This the csv file.
|
41
|
+
#
|
42
|
+
# Results:
|
43
|
+
# None.
|
44
|
+
#
|
45
|
+
###############################################################################
|
46
|
+
class SodaCSV
|
47
|
+
attr_accessor :fieldMap, :csvdata
|
48
|
+
|
49
|
+
def initialize(file)
|
50
|
+
@csvdata = CSV.open(file, 'r')
|
51
|
+
@fieldMap = @csvdata.shift
|
52
|
+
end
|
53
|
+
|
54
|
+
###############################################################################
|
55
|
+
# nextRecord -- Method
|
56
|
+
# This method pulls the next record from the CSV and returns it as a hash.
|
57
|
+
#
|
58
|
+
# Params:
|
59
|
+
# None.
|
60
|
+
#
|
61
|
+
# Results:
|
62
|
+
# returns a filled hash on success, or nil on error or no data.
|
63
|
+
#
|
64
|
+
###############################################################################
|
65
|
+
def nextRecord()
|
66
|
+
record = {}
|
67
|
+
data = @csvdata.shift
|
68
|
+
all_nil = true
|
69
|
+
|
70
|
+
if (!data.empty?)
|
71
|
+
@fieldMap.each_index do|k|
|
72
|
+
if (!data[k].to_s.empty?)
|
73
|
+
all_nil = false
|
74
|
+
end
|
75
|
+
record[@fieldMap[k]] = data[k]
|
76
|
+
end
|
77
|
+
else
|
78
|
+
record = nil
|
79
|
+
end
|
80
|
+
|
81
|
+
if ( (all_nil != false) || (record == nil) )
|
82
|
+
record = nil
|
83
|
+
end
|
84
|
+
|
85
|
+
return record
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
data/lib/SodaFireFox.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
###############################################################################
|
2
|
+
# Copyright (c) 2010, SugarCRM, Inc.
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
# * Redistributions of source code must retain the above copyright
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
9
|
+
# * Redistributions in binary form must reproduce the above copyright
|
10
|
+
# notice, this list of conditions and the following disclaimer in the
|
11
|
+
# documentation and/or other materials provided with the distribution.
|
12
|
+
# * Neither the name of SugarCRM, Inc. nor the
|
13
|
+
# names of its contributors may be used to endorse or promote products
|
14
|
+
# derived from this software without specific prior written permission.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL SugarCRM, Inc. BE LIABLE FOR ANY
|
20
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
21
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
22
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
23
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
24
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
25
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
26
|
+
###############################################################################
|
27
|
+
|
28
|
+
###############################################################################
|
29
|
+
# Needed ruby libs:
|
30
|
+
###############################################################################
|
31
|
+
require 'rubygems'
|
32
|
+
require 'watir'
|
33
|
+
require 'SodaUtils'
|
34
|
+
|
35
|
+
###############################################################################
|
36
|
+
# SodaFireFox -- MOdule
|
37
|
+
# This module is for doing firefox things with soda.
|
38
|
+
###############################################################################
|
39
|
+
module SodaFireFox
|
40
|
+
|
41
|
+
###############################################################################
|
42
|
+
# CreateFireFoxBrowser -- Function
|
43
|
+
# This function will create a new firewatir object.
|
44
|
+
#
|
45
|
+
# Params:
|
46
|
+
# options: This is the same options that you would pass to a FireWatir.new
|
47
|
+
#
|
48
|
+
# Results:
|
49
|
+
# A hash is always returned, if the 'browser' keys value is nil there
|
50
|
+
# was an error and the eaception for that error is returned in the hash.
|
51
|
+
#
|
52
|
+
###############################################################################
|
53
|
+
def SodaFireFox.CreateFireFoxBrowser(options = nil)
|
54
|
+
result = {
|
55
|
+
"browser" => nil,
|
56
|
+
"exception" => nil
|
57
|
+
}
|
58
|
+
|
59
|
+
Watir::Browser.default = "firefox"
|
60
|
+
|
61
|
+
begin
|
62
|
+
if (options != nil)
|
63
|
+
result['browser'] = Watir::Browser.new(options)
|
64
|
+
else
|
65
|
+
result['browser'] = Watir::Browser.new()
|
66
|
+
end
|
67
|
+
rescue Exception => e
|
68
|
+
result['exception'] = e
|
69
|
+
result['browser'] = nil
|
70
|
+
ensure
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
return result
|
75
|
+
end
|
76
|
+
|
77
|
+
###############################################################################
|
78
|
+
# CloseBrowser -- function
|
79
|
+
# This function trys to close browsers, using this because of a lame
|
80
|
+
# watir bug.
|
81
|
+
#
|
82
|
+
# Input:
|
83
|
+
# watirobj: This is the watir object to use to execute js script.
|
84
|
+
#
|
85
|
+
# Output:
|
86
|
+
# returns the result of the jsscript.
|
87
|
+
#
|
88
|
+
###############################################################################
|
89
|
+
def SodaFireFox.CloseBrowser(watirobj)
|
90
|
+
result = 0
|
91
|
+
jssh = <<JS
|
92
|
+
var windows = getWindows();
|
93
|
+
var len = windows.length -1;
|
94
|
+
var closed = 0;
|
95
|
+
|
96
|
+
for(var i = len; i >= len; i--) {
|
97
|
+
windows[i].close();
|
98
|
+
closed += 1;
|
99
|
+
}
|
100
|
+
|
101
|
+
closed;
|
102
|
+
JS
|
103
|
+
|
104
|
+
begin
|
105
|
+
result = watirobj.js_eval(jssh)
|
106
|
+
result = result.to_i()
|
107
|
+
rescue Exception => e
|
108
|
+
$curSoda.rep.ReportException(e, true, false)
|
109
|
+
ensure
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
return result
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end # end module #
|
118
|
+
|
@@ -0,0 +1,810 @@
|
|
1
|
+
###############################################################################
|
2
|
+
# Copyright (c) 2010, SugarCRM, Inc.
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
# * Redistributions of source code must retain the above copyright
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
9
|
+
# * Redistributions in binary form must reproduce the above copyright
|
10
|
+
# notice, this list of conditions and the following disclaimer in the
|
11
|
+
# documentation and/or other materials provided with the distribution.
|
12
|
+
# * Neither the name of SugarCRM, Inc. nor the
|
13
|
+
# names of its contributors may be used to endorse or promote products
|
14
|
+
# derived from this software without specific prior written permission.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL SugarCRM, Inc. BE LIABLE FOR ANY
|
20
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
21
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
22
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
23
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
24
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
25
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
26
|
+
###############################################################################
|
27
|
+
|
28
|
+
###############################################################################
|
29
|
+
# Needed Ruby Libs:
|
30
|
+
###############################################################################
|
31
|
+
require 'strscan'
|
32
|
+
|
33
|
+
###############################################################################
|
34
|
+
# SodaLogReporter -- Class
|
35
|
+
# This is a simple class to take a raw soda report file and turn it into
|
36
|
+
# a more readable html report file.
|
37
|
+
#
|
38
|
+
# Params:
|
39
|
+
# sodalog_file: This is the log file to be used to generate the html.
|
40
|
+
#
|
41
|
+
# output_file: This is the name of the html report file to create.
|
42
|
+
#
|
43
|
+
# Results:
|
44
|
+
# None.
|
45
|
+
#
|
46
|
+
###############################################################################
|
47
|
+
class SodaLogReporter
|
48
|
+
|
49
|
+
@SodaLogFile = nil
|
50
|
+
@OutPutFile = nil
|
51
|
+
@BackTraceID = nil
|
52
|
+
@EventDumpID = nil
|
53
|
+
|
54
|
+
def initialize (sodalog_file, output_file)
|
55
|
+
|
56
|
+
if (!File.exist?(sodalog_file))
|
57
|
+
raise(ArgumentError, "(!)Can't find file: #{sodalog_file}!\n", caller)
|
58
|
+
end
|
59
|
+
|
60
|
+
if (!output_file)
|
61
|
+
raise(ArgumentError, "(!)Missing argument: output_file!\n", caller)
|
62
|
+
end
|
63
|
+
|
64
|
+
@SodaLogFile = sodalog_file
|
65
|
+
@OutPutFile = output_file
|
66
|
+
@BackTraceID = 0
|
67
|
+
@EventDumpID = 0
|
68
|
+
end
|
69
|
+
|
70
|
+
###############################################################################
|
71
|
+
# GenerateHtmlHeader -- Method
|
72
|
+
# This function will create the proper html header for the report file that
|
73
|
+
# we generate.
|
74
|
+
#
|
75
|
+
# Params:
|
76
|
+
# title: This is to set the HTML <title>#{title}</title>
|
77
|
+
#
|
78
|
+
# Results:
|
79
|
+
# returns a string containing HTML code.
|
80
|
+
#
|
81
|
+
###############################################################################
|
82
|
+
def GenerateHtmlHeader (title = "Soda Test Report:")
|
83
|
+
header = <<HTML
|
84
|
+
<html>
|
85
|
+
<script language=javascript type='text/javascript'>
|
86
|
+
function hidediv(name, href_id) {
|
87
|
+
document.getElementById(name).style.display = 'none';
|
88
|
+
document.getElementById(href_id).innerHTML="[ Expand Backtrace ]<b>+</b>";
|
89
|
+
document.getElementById(href_id).href="javascript:showdiv('" + name +
|
90
|
+
"', '" + href_id + "')";
|
91
|
+
}
|
92
|
+
|
93
|
+
function showdiv(name, href_id) {
|
94
|
+
document.getElementById(name).style.display = 'inline';
|
95
|
+
document.getElementById(href_id).innerHTML="[ Collapse Backtrace ]<b>-</b>";
|
96
|
+
document.getElementById(href_id).href="javascript:hidediv('" + name +
|
97
|
+
"', '" + href_id + "')";
|
98
|
+
}
|
99
|
+
</script>
|
100
|
+
|
101
|
+
<style type="text/css">
|
102
|
+
body
|
103
|
+
{
|
104
|
+
margin: 0px;
|
105
|
+
font-family: Arial, Verdana, Helvetica, sans-serif;
|
106
|
+
}
|
107
|
+
|
108
|
+
fieldset, table, pre
|
109
|
+
{
|
110
|
+
margin-bottom:0;
|
111
|
+
}
|
112
|
+
|
113
|
+
p
|
114
|
+
{
|
115
|
+
margin-top: 0px;
|
116
|
+
margin-bottom: 0px;
|
117
|
+
}
|
118
|
+
|
119
|
+
textarea
|
120
|
+
{
|
121
|
+
font-family: Arial,Verdana,Helvetica,sans-serif;
|
122
|
+
}
|
123
|
+
|
124
|
+
td
|
125
|
+
{
|
126
|
+
text-align: left;
|
127
|
+
vertical-align: top;
|
128
|
+
}
|
129
|
+
|
130
|
+
.td_msgtype
|
131
|
+
{
|
132
|
+
text-align: center;
|
133
|
+
vertical-align: middle;
|
134
|
+
}
|
135
|
+
|
136
|
+
.tr_normal
|
137
|
+
{
|
138
|
+
background: #e5eef3;
|
139
|
+
}
|
140
|
+
|
141
|
+
.tr_header
|
142
|
+
{
|
143
|
+
background: #a4a4a4;
|
144
|
+
font-weight: bold;
|
145
|
+
}
|
146
|
+
|
147
|
+
.tr_module
|
148
|
+
{
|
149
|
+
background: #3c78c8;
|
150
|
+
}
|
151
|
+
|
152
|
+
.tr_error
|
153
|
+
{
|
154
|
+
background: #ff0000;
|
155
|
+
}
|
156
|
+
|
157
|
+
.tr_warning
|
158
|
+
{
|
159
|
+
background: #eeff30;
|
160
|
+
}
|
161
|
+
|
162
|
+
.tr_assert_passed
|
163
|
+
{
|
164
|
+
background: #7ff98a;
|
165
|
+
}
|
166
|
+
|
167
|
+
.highlight {
|
168
|
+
background-color: #8888FF;
|
169
|
+
}
|
170
|
+
|
171
|
+
.highlight_report {
|
172
|
+
background-color: #5dec6d;
|
173
|
+
}
|
174
|
+
|
175
|
+
table
|
176
|
+
{
|
177
|
+
background: #ffff;
|
178
|
+
border: 1px solid black;
|
179
|
+
border-bottom: 1px solid #0000;
|
180
|
+
border-right: 1px solid #0000;
|
181
|
+
color: #0000;
|
182
|
+
padding: 4px;
|
183
|
+
font-size: 11px;
|
184
|
+
}
|
185
|
+
</style>
|
186
|
+
<title>#{title}</title>
|
187
|
+
<body>
|
188
|
+
<table>
|
189
|
+
<tr class="tr_header">
|
190
|
+
<td nowrap>
|
191
|
+
Date Time:
|
192
|
+
</td>
|
193
|
+
<td nowrap>
|
194
|
+
Message Type:
|
195
|
+
</td>
|
196
|
+
<td>
|
197
|
+
Message:
|
198
|
+
</td>
|
199
|
+
</tr>
|
200
|
+
|
201
|
+
HTML
|
202
|
+
return header
|
203
|
+
end
|
204
|
+
|
205
|
+
|
206
|
+
###############################################################################
|
207
|
+
# SafeHTMLStr -- Method
|
208
|
+
# This method makes a string html safe by peforming proper escapes.
|
209
|
+
#
|
210
|
+
# Params:
|
211
|
+
# str: The string to make safe.
|
212
|
+
#
|
213
|
+
# Result:
|
214
|
+
# returns a safe html string.
|
215
|
+
#
|
216
|
+
###############################################################################
|
217
|
+
def SafeHTMLStr(str)
|
218
|
+
str = str.gsub("<", "<")
|
219
|
+
str = str.gsub(">", ">")
|
220
|
+
return str
|
221
|
+
end
|
222
|
+
|
223
|
+
###############################################################################
|
224
|
+
# FormatTestResults -- Method
|
225
|
+
# This method takes the results log file line and generates a nice and
|
226
|
+
# happy html row.
|
227
|
+
#
|
228
|
+
# Prams:
|
229
|
+
# line: This is the "Soda Test Report" line from the log file.
|
230
|
+
#
|
231
|
+
# Results:
|
232
|
+
# returns a hash that is the expected format.
|
233
|
+
#
|
234
|
+
# Data: Hash format:
|
235
|
+
# row_data['date']
|
236
|
+
# row_data['msg_type']
|
237
|
+
# row_data['msg']
|
238
|
+
# row_data['error']
|
239
|
+
#
|
240
|
+
###############################################################################
|
241
|
+
def FormatTestResults (line)
|
242
|
+
row_data = Hash.new()
|
243
|
+
table_html = "<table>\n"
|
244
|
+
line =~ /\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\](\(.\))(.*)/
|
245
|
+
row_data['date'] = "#{$1}"
|
246
|
+
row_data['msg_type'] = "Results"
|
247
|
+
rpt_msg = "#{$3}"
|
248
|
+
res_data = rpt_msg.split("--")
|
249
|
+
res_data.shift()
|
250
|
+
|
251
|
+
res_data.each do |dline|
|
252
|
+
dline_data = dline.split(":")
|
253
|
+
if ( (dline_data[1].nil?) || (dline_data[1].empty?) )
|
254
|
+
dline_data[1] = ""
|
255
|
+
end
|
256
|
+
|
257
|
+
table_html << "<tr class=\"tr_normal\""+
|
258
|
+
" \"onMouseOver=\"this.className='highlight_report'\" "+
|
259
|
+
"onMouseOut=\"this.className='tr_normal'\">" +
|
260
|
+
"\n\t<td><b>#{dline_data[0]}:</b></td>\n"
|
261
|
+
|
262
|
+
case dline_data[0]
|
263
|
+
when /test\s+failure\s+count/i
|
264
|
+
if (dline_data[1].to_i() > 0)
|
265
|
+
table_html << "\t<td><font color=\"#FF0000\">" +
|
266
|
+
"<b>#{dline_data[1]}</b>\n\t</td>\n"
|
267
|
+
else
|
268
|
+
table_html << "\t<td><b>#{dline_data[1]}</b>" +
|
269
|
+
"\n\t</td>\n"
|
270
|
+
end
|
271
|
+
when /assert\s+failures/i
|
272
|
+
if (dline_data[1].to_i() > 0)
|
273
|
+
table_html << "\t<td><font color=\"#FF0000\">" +
|
274
|
+
"<b>#{dline_data[1]}</b>\n\t</td>\n"
|
275
|
+
else
|
276
|
+
table_html << "\t<td><b>#{dline_data[1]}</b>" +
|
277
|
+
"\n\t</td>\n"
|
278
|
+
end
|
279
|
+
when /test\s+major\s+exceptions/i
|
280
|
+
if (dline_data[1].to_i() > 0)
|
281
|
+
table_html << "\t<td><font color=\"#FF0000\">" +
|
282
|
+
"<b>#{dline_data[1]}</b>\n\t</td>\n"
|
283
|
+
else
|
284
|
+
table_html << "\t<td><b>#{dline_data[1]}</b>" +
|
285
|
+
"\n\t</td>\n"
|
286
|
+
end
|
287
|
+
when /test\s+exceptions/i
|
288
|
+
if (dline_data[1].to_i() > 0)
|
289
|
+
table_html << "\t<td><font color=\"#FF0000\">" +
|
290
|
+
"<b>#{dline_data[1]}</b>\n\t</td>\n"
|
291
|
+
else
|
292
|
+
table_html << "\t<td><b>#{dline_data[1]}</b>" +
|
293
|
+
"\n\t</td>\n"
|
294
|
+
end
|
295
|
+
when /test\s+css\s+error\s+count/i
|
296
|
+
if (dline_data[1].to_i() > 0)
|
297
|
+
table_html << "\t<td><font color=\"#FF0000\">" +
|
298
|
+
"<b>#{dline_data[1]}</b>\n\t</td>\n"
|
299
|
+
else
|
300
|
+
table_html << "\t<td><b>#{dline_data[1]}</b>" +
|
301
|
+
"\n\t</td>\n"
|
302
|
+
end
|
303
|
+
when /test\s+javascript\s+error\s+count/i
|
304
|
+
if (dline_data[1].to_i() > 0)
|
305
|
+
table_html << "\t<td><font color=\"#FF0000\">" +
|
306
|
+
"<b>#{dline_data[1]}</b>\n\t</td>\n"
|
307
|
+
else
|
308
|
+
table_html << "\t<td><b>#{dline_data[1]}</b>" +
|
309
|
+
"\n\t</td>\n"
|
310
|
+
end
|
311
|
+
else
|
312
|
+
table_html << "\t<td><b>#{dline_data[1]}</b>" +
|
313
|
+
"\n\t</td>\n"
|
314
|
+
end
|
315
|
+
|
316
|
+
table_html << "</tr>\n"
|
317
|
+
end
|
318
|
+
table_html << "\n</table>\n"
|
319
|
+
row_data['msg'] = table_html
|
320
|
+
|
321
|
+
return row_data
|
322
|
+
end
|
323
|
+
|
324
|
+
###############################################################################
|
325
|
+
# FormatHTMLSavedResults -- Method
|
326
|
+
# This method takes the "HTML Saved" line from the Soda log file and
|
327
|
+
# generates a happy html table row from it.
|
328
|
+
#
|
329
|
+
# Params:
|
330
|
+
# line: This is the "HTML Saved" line from the raw soda log file.
|
331
|
+
#
|
332
|
+
# Results:
|
333
|
+
# returns a hash that is the expected format.
|
334
|
+
#
|
335
|
+
# Data: Hash format:
|
336
|
+
# row_data['date']
|
337
|
+
# row_data['msg_type']
|
338
|
+
# row_data['msg']
|
339
|
+
#
|
340
|
+
###############################################################################
|
341
|
+
def FormatHTMLSavedResults (line)
|
342
|
+
row_data = Hash.new()
|
343
|
+
|
344
|
+
line =~ /\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\](\(.\))(.*)/
|
345
|
+
row_data['date'] = "#{$1}"
|
346
|
+
row_data['msg_type'] = "#{$2}"
|
347
|
+
sav_msg = "#{$3}"
|
348
|
+
sav_msg =~ /^(html\ssaved:\s+)(.*)/i
|
349
|
+
base_name = File.basename($2)
|
350
|
+
row_data['msg'] = "<b>#{$1}</b>" +
|
351
|
+
"<a href=\"#{base_name}\" target=\"_blank\">#{$2}</a>"
|
352
|
+
|
353
|
+
return row_data
|
354
|
+
end
|
355
|
+
|
356
|
+
###############################################################################
|
357
|
+
# FormatExceptionBT -- Method
|
358
|
+
# This method takes a exception bt from the soda log and makes a nicely
|
359
|
+
# formatted html table row with it.
|
360
|
+
#
|
361
|
+
# Params:
|
362
|
+
# line: The bt line from the raw soda log file.
|
363
|
+
#
|
364
|
+
# Results:
|
365
|
+
# returns a hash that is the expected format.
|
366
|
+
#
|
367
|
+
# Data: Hash format:
|
368
|
+
# row_data['date']
|
369
|
+
# row_data['msg_type']
|
370
|
+
# row_data['msg']
|
371
|
+
#
|
372
|
+
###############################################################################
|
373
|
+
def FormatExceptionBT (line)
|
374
|
+
row_data = Hash.new()
|
375
|
+
btid = "bt_div_#{@BackTraceID}"
|
376
|
+
href_id = "href_div_#{@BackTraceID}"
|
377
|
+
@BackTraceID += 1
|
378
|
+
|
379
|
+
line =~ /(\w+\s+\w+:)/i
|
380
|
+
row_data['msg_type'] = "bt"
|
381
|
+
row_data['date'] = ""
|
382
|
+
|
383
|
+
row_html = "\t<b>#{$1}</b>" +
|
384
|
+
"\t<a id=\"#{href_id}\" href=\"javascript:showdiv('#{btid}',"+
|
385
|
+
" '#{href_id}')\">[ Expand Backtrace ]<b>+</b><br>\n" +
|
386
|
+
"</a><br>\t<div id=\"#{btid}\" style=\"display: none\">\n"
|
387
|
+
|
388
|
+
line.gsub(/(\w+\s+\w+:)/i, "")
|
389
|
+
e_data = line.split("--")
|
390
|
+
e_data.each do |e|
|
391
|
+
row_html << "\t\t#{e}<br>\n"
|
392
|
+
end
|
393
|
+
row_html << "\t<a href=\"javascript:hidediv('#{btid}', '#{href_id}')\">" +
|
394
|
+
"[ Collaspe Backtrace ]<b>-</b></a>\t\t</div>\n\n"
|
395
|
+
row_data['msg'] = row_html
|
396
|
+
|
397
|
+
return row_data
|
398
|
+
end
|
399
|
+
|
400
|
+
###############################################################################
|
401
|
+
# FormatMajorException -- Method
|
402
|
+
# This method takes a major exception line from a raw soda log and craetes
|
403
|
+
# a nice happy html row from it.
|
404
|
+
#
|
405
|
+
# Params:
|
406
|
+
# line: the line from the soda log.
|
407
|
+
#
|
408
|
+
# Results:
|
409
|
+
# returns a hash of formated html
|
410
|
+
#
|
411
|
+
###############################################################################
|
412
|
+
def FormatMajorException(line)
|
413
|
+
row_data = Hash.new()
|
414
|
+
|
415
|
+
line =~ /\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\](\(.\))(.*)/
|
416
|
+
row_data['date'] = "#{$1}"
|
417
|
+
row_data['msg_type'] = "#{$2}"
|
418
|
+
msg = "#{$3}"
|
419
|
+
msg_data = msg.split("--")
|
420
|
+
msg_data[0] = msg_data[0].gsub(/^major\sexception/i,
|
421
|
+
"<b>Major Exception:</b> ")
|
422
|
+
msg_data[1] = msg_data[1].gsub(/^exception\smessage:/i,
|
423
|
+
"<b>Exception Message:</b>")
|
424
|
+
row_data['msg'] = "#{msg_data[0]}</br>#{msg_data[1]}"
|
425
|
+
|
426
|
+
return row_data
|
427
|
+
end
|
428
|
+
|
429
|
+
###############################################################################
|
430
|
+
# FormatAssertionFailed -- Method
|
431
|
+
# This method takes an assertion failed line from the raw soda log and
|
432
|
+
# creates a nice happy html row from it.
|
433
|
+
#
|
434
|
+
# Params:
|
435
|
+
# line: This is the assertion failed line from the log file.
|
436
|
+
#
|
437
|
+
# Results:
|
438
|
+
# returns a hash that is the expected format.
|
439
|
+
#
|
440
|
+
# Data: Hash format:
|
441
|
+
# row_data['date']
|
442
|
+
# row_data['msg_type']
|
443
|
+
# row_data['msg']
|
444
|
+
#
|
445
|
+
###############################################################################
|
446
|
+
def FormatAssertionFailed (line)
|
447
|
+
row_data = Hash.new()
|
448
|
+
|
449
|
+
line =~ /\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\](\(.\))(.*)/
|
450
|
+
row_data['date'] = "#{$1}"
|
451
|
+
row_data['msg_type'] = "#{$2}"
|
452
|
+
msg = "#{$3}"
|
453
|
+
assert_data = msg.split("--")
|
454
|
+
|
455
|
+
if ( (assert_data[3].nil?) || (assert_data[3].empty?))
|
456
|
+
assert_data[3] = "No message found in log file."
|
457
|
+
else
|
458
|
+
assert_data[3] = assert_data[3].gsub(/^Assertion\s+Message:/i, "")
|
459
|
+
end
|
460
|
+
|
461
|
+
if ( (assert_data[4].nil?) || (assert_data[4].empty?))
|
462
|
+
assert_data[4] = "No line number found!"
|
463
|
+
end
|
464
|
+
|
465
|
+
url_html = "<a href=\"#{assert_data[1]}\">#{assert_data[1]}</a>"
|
466
|
+
row_data['msg'] = "<b>#{assert_data[0]}</b><br>\n" +
|
467
|
+
"<b>URL:</b> #{url_html}<br>\n" +
|
468
|
+
"<b>Test File:</b> #{assert_data[2]}</br>\n" +
|
469
|
+
"<b>Message:</b> #{assert_data[3]}<br>\n" +
|
470
|
+
"<b>Line Number:</b> #{assert_data[4]}<br>\n"
|
471
|
+
|
472
|
+
return row_data
|
473
|
+
end
|
474
|
+
|
475
|
+
###############################################################################
|
476
|
+
# FormatAssertionPassed -- Method
|
477
|
+
# This method takes an assertion passed line from the raw soda log and
|
478
|
+
# creates a nice happy html row from it.
|
479
|
+
#
|
480
|
+
# Params:
|
481
|
+
# line: This is the assertion passed line from the log file.
|
482
|
+
#
|
483
|
+
# Results:
|
484
|
+
# returns a hash that is the expected format.
|
485
|
+
#
|
486
|
+
# Data: Hash format:
|
487
|
+
# row_data['date']
|
488
|
+
# row_data['msg_type']
|
489
|
+
# row_data['msg']
|
490
|
+
#
|
491
|
+
###############################################################################
|
492
|
+
def FormatAssertionPassed (line)
|
493
|
+
row_data = Hash.new()
|
494
|
+
|
495
|
+
line =~ /\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\](\(.\))(.*)/
|
496
|
+
row_data['date'] = "#{$1}"
|
497
|
+
row_data['msg_type'] = "AP"
|
498
|
+
msg = "#{$3}"
|
499
|
+
row_data['msg'] = "#{msg}"
|
500
|
+
|
501
|
+
return row_data
|
502
|
+
end
|
503
|
+
|
504
|
+
###############################################################################
|
505
|
+
# FormatEventDump -- Method
|
506
|
+
# This method formats a soda event dump log message.
|
507
|
+
#
|
508
|
+
# Params:
|
509
|
+
# line: This is the soda log line.
|
510
|
+
#
|
511
|
+
# Results:
|
512
|
+
# returns a hash that is the expected format.
|
513
|
+
#
|
514
|
+
###############################################################################
|
515
|
+
def FormatEventDump(line)
|
516
|
+
ed_id = "ed_div_#{@EventDumpID}"
|
517
|
+
href_id = "href_div_ed_#{@EventDumpID}"
|
518
|
+
@EventDumpID += 1
|
519
|
+
row_data = Hash.new()
|
520
|
+
line =~ /\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\](\(.\))(.*)/
|
521
|
+
row_data['date'] = "#{$1}"
|
522
|
+
row_data['msg_type'] = "#{$2}"
|
523
|
+
msg = "#{$3}"
|
524
|
+
|
525
|
+
msg =~ /^(.*:)\s+(--.*)/
|
526
|
+
msg_data = "#{$2}"
|
527
|
+
msg_text = "#{$1}"
|
528
|
+
|
529
|
+
e_data = msg_data.chop()
|
530
|
+
|
531
|
+
row_html = "\t<b>#{msg_text}:</b>" +
|
532
|
+
"\t<a id=\"#{href_id}\" href=\"javascript:showdiv('#{ed_id}',"+
|
533
|
+
" '#{href_id}')\">[ Expand Event Dump ]<b>+</b><br>\n" +
|
534
|
+
"</a><br>\t<div id=\"#{ed_id}\" style=\"display: none\">\n"
|
535
|
+
|
536
|
+
e_data = msg_data.split("--")
|
537
|
+
e_data.each do |e|
|
538
|
+
row_html << "\t\t#{e}<br>\n"
|
539
|
+
end
|
540
|
+
|
541
|
+
row_html << "\t<a href=\"javascript:hidediv('#{ed_id}'" +
|
542
|
+
", '#{href_id}')\">"
|
543
|
+
"[ Collaspe Event Dump ]<b>-</b></a>\t\t</div>\n"
|
544
|
+
|
545
|
+
row_data['msg'] = row_html
|
546
|
+
return row_data
|
547
|
+
end
|
548
|
+
|
549
|
+
###############################################################################
|
550
|
+
# FormatJSError -- Method
|
551
|
+
# This method takes a java script soda error line and formats it into
|
552
|
+
# html.
|
553
|
+
#
|
554
|
+
# Params:
|
555
|
+
# line: This is the js error line from a soda log.
|
556
|
+
#
|
557
|
+
# Results:
|
558
|
+
# returns a hash that is the expected format.
|
559
|
+
#
|
560
|
+
###############################################################################
|
561
|
+
def FormatJSError(line)
|
562
|
+
row_data = Hash.new()
|
563
|
+
line =~ /\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\](\(.\))(.*)/
|
564
|
+
row_data['date'] = "#{$1}"
|
565
|
+
row_data['msg_type'] = "#{$2}"
|
566
|
+
msg = "#{$3}"
|
567
|
+
row_html = ""
|
568
|
+
|
569
|
+
msg_data = msg.split(/--/)
|
570
|
+
msg_data.each do |d|
|
571
|
+
info = d.split(/::/)
|
572
|
+
|
573
|
+
if (info.length < 2)
|
574
|
+
row_html << "\t<b>#{info[0]}</b><br>\n"
|
575
|
+
else
|
576
|
+
row_html << "\t<b>#{info[0]}:</b> #{info[1]}<br>\n"
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
row_data['msg'] = row_html
|
581
|
+
return row_data
|
582
|
+
end
|
583
|
+
|
584
|
+
###############################################################################
|
585
|
+
# FormatModuleLine -- Method
|
586
|
+
# This method takes a module lines and formats it for html.
|
587
|
+
#
|
588
|
+
# Params:
|
589
|
+
# line: The raw soda log line.
|
590
|
+
#
|
591
|
+
# Results:
|
592
|
+
# returns a hash that is the expected format.
|
593
|
+
#
|
594
|
+
###############################################################################
|
595
|
+
def FormatModuleLine(type, line)
|
596
|
+
row_data = Hash.new()
|
597
|
+
line =~ /\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\](\(.\))(.*)/
|
598
|
+
row_data['date'] = "#{$1}"
|
599
|
+
row_data['msg_type'] = "M"
|
600
|
+
msg = "#{$3}"
|
601
|
+
row_html = ""
|
602
|
+
|
603
|
+
case type
|
604
|
+
when /module/i
|
605
|
+
msg = msg.gsub(/^module:/i, "<b>Module:</b>")
|
606
|
+
when /test/i
|
607
|
+
msg = msg.gsub(/^test:/i, "<b>Test:</b>")
|
608
|
+
when /lib/i
|
609
|
+
msg = msg.gsub(/^lib:/i, "<b>Lib:</b>")
|
610
|
+
end
|
611
|
+
|
612
|
+
row_data['msg'] = msg
|
613
|
+
|
614
|
+
return row_data
|
615
|
+
end
|
616
|
+
|
617
|
+
###############################################################################
|
618
|
+
# FormatReplacingString -- Method
|
619
|
+
# This method finds the replace string message and reformats it a little.
|
620
|
+
#
|
621
|
+
# Input:
|
622
|
+
# line: a soda log file line.
|
623
|
+
#
|
624
|
+
# Output:
|
625
|
+
# a row_data hash.
|
626
|
+
#
|
627
|
+
###############################################################################
|
628
|
+
def FormatReplacingString(line)
|
629
|
+
row_data = Hash.new()
|
630
|
+
msg = ""
|
631
|
+
|
632
|
+
line =~ /\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\](\(.\))(.*)/
|
633
|
+
row_data['date'] = "#{$1}"
|
634
|
+
row_data['msg_type'] = "#{$2}"
|
635
|
+
|
636
|
+
msg = $3
|
637
|
+
data = msg.split(/'*'/)
|
638
|
+
data.each do |d|
|
639
|
+
next if (d =~ /with/i) || (d =~ /replacing\s+string/i)
|
640
|
+
tmp = d
|
641
|
+
tmp = Regexp.escape(tmp)
|
642
|
+
msg = msg.gsub(/'#{tmp}'/, "<b>'#{d}'</b>")
|
643
|
+
end
|
644
|
+
|
645
|
+
row_data['msg'] = msg
|
646
|
+
|
647
|
+
return row_data
|
648
|
+
end
|
649
|
+
|
650
|
+
|
651
|
+
###############################################################################
|
652
|
+
# FormatClickingElement -- Method
|
653
|
+
# This method finds the replace string message and reformats it a little.
|
654
|
+
#
|
655
|
+
# Input:
|
656
|
+
# line: a soda log file line.
|
657
|
+
#
|
658
|
+
# Output:
|
659
|
+
# a row_data hash.
|
660
|
+
#
|
661
|
+
###############################################################################
|
662
|
+
def FormatClickingElement(line)
|
663
|
+
row_data = {}
|
664
|
+
tmp = ""
|
665
|
+
line =~ /\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\](\(.\))(.*)/
|
666
|
+
row_data['date'] = "#{$1}"
|
667
|
+
row_data['msg_type'] = "#{$2}"
|
668
|
+
tmp = "#{$3}"
|
669
|
+
tmp = SafeHTMLStr("#{tmp}")
|
670
|
+
tmp = tmp.gsub(/\{/, "<b>{")
|
671
|
+
tmp = tmp.gsub(/\}/, "}</b>")
|
672
|
+
row_data['msg'] = "#{tmp}"
|
673
|
+
|
674
|
+
return row_data
|
675
|
+
end
|
676
|
+
|
677
|
+
###############################################################################
|
678
|
+
# GenerateTableRow -- Method
|
679
|
+
# This function generates a new html table row from a row log line.
|
680
|
+
#
|
681
|
+
# Params:
|
682
|
+
# line: This is a line from a raw soda report file.
|
683
|
+
#
|
684
|
+
# Results:
|
685
|
+
# returns a string of html that is a table row.
|
686
|
+
#
|
687
|
+
###############################################################################
|
688
|
+
def GenerateTableRow(line)
|
689
|
+
row_html = ""
|
690
|
+
tr_style = "tr_normal"
|
691
|
+
row_data = Hash.new()
|
692
|
+
|
693
|
+
case line
|
694
|
+
when /assertion:\s+passed/i
|
695
|
+
row_data = FormatAssertionPassed(line)
|
696
|
+
when /exception\s+backtrace/i
|
697
|
+
row_data = FormatExceptionBT(line)
|
698
|
+
when /assertion:\s+failed/i
|
699
|
+
row_data = FormatAssertionFailed(line)
|
700
|
+
when /soda\s+test\s+report:/i
|
701
|
+
row_data = FormatTestResults(line)
|
702
|
+
when /html\s+saved/i
|
703
|
+
row_data = FormatHTMLSavedResults(line)
|
704
|
+
when /\(E\)/
|
705
|
+
row_data = FormatEventDump(line)
|
706
|
+
when /major\sexception/i
|
707
|
+
row_data = FormatMajorException(line)
|
708
|
+
when /javascript\s+error:/i
|
709
|
+
row_data = FormatJSError(line)
|
710
|
+
when /css\s+error:/i
|
711
|
+
row_data = FormatJSError(line)
|
712
|
+
when /\(\*\)module:/i
|
713
|
+
row_data = FormatModuleLine("module", line)
|
714
|
+
when /\(\*\)test:/i
|
715
|
+
row_data = FormatModuleLine("test", line)
|
716
|
+
when /\(\*\)lib:/i
|
717
|
+
row_data = FormatModuleLine("lib", line)
|
718
|
+
when /replacing string/i
|
719
|
+
row_data = FormatReplacingString(line)
|
720
|
+
when /clicking\selement:/i
|
721
|
+
row_data = FormatClickingElement(line)
|
722
|
+
when /setting\selement:/i
|
723
|
+
row_data = FormatClickingElement(line)
|
724
|
+
when /expected element:/i
|
725
|
+
row_data = FormatClickingElement(line)
|
726
|
+
when /element:/i
|
727
|
+
row_data = FormatClickingElement(line)
|
728
|
+
else
|
729
|
+
line =~ /\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\](\(.\))(.*)/
|
730
|
+
row_data['date'] = "#{$1}"
|
731
|
+
row_data['msg_type'] = "#{$2}"
|
732
|
+
row_data['msg'] = SafeHTMLStr("#{$3}")
|
733
|
+
end
|
734
|
+
|
735
|
+
row_data['msg_type'] = row_data['msg_type'].gsub("(", "")
|
736
|
+
row_data['msg_type'] = row_data['msg_type'].gsub(")", "")
|
737
|
+
|
738
|
+
case row_data['msg_type'].to_s()
|
739
|
+
when "!"
|
740
|
+
row_data['msg_type'] = "Failure"
|
741
|
+
tr_style = "tr_error"
|
742
|
+
when "*"
|
743
|
+
row_data['msg_type'] = "Log"
|
744
|
+
when "W"
|
745
|
+
row_data['msg_type'] = "Warning"
|
746
|
+
tr_style = "tr_warning"
|
747
|
+
when "E"
|
748
|
+
row_data['msg_type'] = "Event Dump"
|
749
|
+
when "bt"
|
750
|
+
row_data['msg_type'] = "BackTrace"
|
751
|
+
when "AP"
|
752
|
+
row_data['msg_type'] = "Assertion Passed"
|
753
|
+
tr_style = "tr_assert_passed"
|
754
|
+
when "M"
|
755
|
+
row_data['msg_type'] = "Un/Load"
|
756
|
+
tr_style = "tr_module"
|
757
|
+
else
|
758
|
+
row_data['msg_type'] = "Log"
|
759
|
+
end
|
760
|
+
|
761
|
+
if ( (row_data['msg'].empty?) && (row_data['date'].empty?) )
|
762
|
+
return ""
|
763
|
+
end
|
764
|
+
|
765
|
+
row_html = "<tr class=\"#{tr_style}\" "+
|
766
|
+
"onMouseOver=\"this.className='highlight'\" " +
|
767
|
+
"onMouseOut=\"this.className='#{tr_style}'\">\n" +
|
768
|
+
"\t<td>" + row_data['date'] + "</td>\n" +
|
769
|
+
"\t<td class=\"td_msgtype\">" + row_data['msg_type'] + "</td>\n" +
|
770
|
+
"\t<td>" + row_data['msg'] + "</td>\n</tr>\n"
|
771
|
+
|
772
|
+
return row_html
|
773
|
+
end
|
774
|
+
|
775
|
+
###############################################################################
|
776
|
+
# GenerateReport -- Method
|
777
|
+
# This function generates an html report file.
|
778
|
+
#
|
779
|
+
# Params:
|
780
|
+
# None.
|
781
|
+
#
|
782
|
+
# Results:
|
783
|
+
# None.
|
784
|
+
#
|
785
|
+
###############################################################################
|
786
|
+
def GenerateReport
|
787
|
+
html = GenerateHtmlHeader()
|
788
|
+
rep_file = File.new(@OutPutFile, "w+")
|
789
|
+
rep_file.write(html)
|
790
|
+
|
791
|
+
log = File.open(@SodaLogFile, "r")
|
792
|
+
log.each do |line|
|
793
|
+
line = line.chomp()
|
794
|
+
if (line.empty?)
|
795
|
+
next
|
796
|
+
end
|
797
|
+
|
798
|
+
tmp = GenerateTableRow(line)
|
799
|
+
if (!tmp.empty?)
|
800
|
+
rep_file.write(tmp)
|
801
|
+
end
|
802
|
+
end
|
803
|
+
|
804
|
+
rep_file.write("\n</table>\n</body>\n</html>\n")
|
805
|
+
rep_file.close()
|
806
|
+
log.close()
|
807
|
+
end
|
808
|
+
|
809
|
+
end
|
810
|
+
|