Merge lp:~sylvain-pineau/checkbox-editor/xls_test_export into lp:checkbox-editor

Proposed by Sylvain Pineau
Status: Merged
Approved by: Javier Collado
Approved revision: 138
Merged at revision: 140
Proposed branch: lp:~sylvain-pineau/checkbox-editor/xls_test_export
Merge into: lp:checkbox-editor
Diff against target: 256 lines (+191/-2)
5 files modified
checkbox_editor/_testplanxls.pl (+156/-0)
checkbox_editor/data.py (+30/-1)
checkbox_editor/editor.py (+1/-0)
debian/control (+3/-1)
setup.py (+1/-0)
To merge this branch: bzr merge lp:~sylvain-pineau/checkbox-editor/xls_test_export
Reviewer Review Type Date Requested Status
Sylvain Pineau (community) Needs Resubmitting
Javier Collado (community) Needs Fixing
Review via email: mp+78085@code.launchpad.net

Description of the change

This change allows XLS compatible output for test procedure in addition of the existing TXT and HTML formats.

Internally, test tree is exported as a json file in a temp file then a perl script performs the full export thanks to the Spreadsheet::WriteExcel module.

Dependencies have been added to the control file and setup.py modified to install the perl script.

To post a comment you must log in.
Revision history for this message
Javier Collado (javier.collado) wrote :

Sylvain, thanks for this merge proposal. Since I haven't found yet the perfect python library for writing xls files, let's go with the perl code.

Let me make a couple of comments:
* bin/_testplanxls.pl: This isn't a good path (it ends up in /usr/bin after package installation). Could you use something under /usr/share/checkbox-editor or under the python package directory (look at the glade files for example)?

* f.close isn't needed. Since you're opening using the with statement to create a context manager, the file will be closed automatically.

* os.close and os.remove are fine, but maybe you can get rid of those lines also if you use tempfile.NamedTemporaryFile in the with statement instead of open. What do you think about this?

* Could you use subprocess instead of pexpect? I know pexpect works better for some use cases, but but I prefer not to add a new dependency (by the way, python-pexpect is missing in the debian/control file) if that's not really needed.

review: Needs Fixing
136. By Sylvain Pineau

Use subprocess instead of pexpect
Store perl code in dist-packages

137. By Sylvain Pineau

Use a sequence instead of a simple string to execute perl code from subprocess

138. By Sylvain Pineau

Remove the need to have a shell started by subprocess

Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

Thanks for your review, I've fixed the need of pexpect and change the location of my perl code once installed.

review: Needs Resubmitting
Revision history for this message
Javier Collado (javier.collado) wrote :

Thanks for your changes.

I've just pushed the changes with a couple of minor changes:
- Moved _testplanxls.pl to script/_testplanxls.pl
- Added lintian override for the script not being executable
  (setup.py probably removes executable permissions, but since the script is run using perl, there's no need to install it with those permissions.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'checkbox_editor/_testplanxls.pl'
2--- checkbox_editor/_testplanxls.pl 1970-01-01 00:00:00 +0000
3+++ checkbox_editor/_testplanxls.pl 2011-10-10 12:38:10 +0000
4@@ -0,0 +1,156 @@
5+#!/usr/bin/perl
6+
7+use strict;
8+use JSON::XS;
9+use Spreadsheet::WriteExcel;
10+
11+die "$0 expects two filenames, aborting !" unless $#ARGV;
12+
13+my $plan = shift;
14+my $dest = shift;
15+
16+open( F, $plan ) || die "Can't open JSON test plan, aborting !";
17+my $f = join( "", <F> );
18+close F;
19+my $json_obj = JSON::XS->new->allow_nonref(1);
20+my $json = $json_obj->decode($f);
21+
22+#require Data::Dumper;
23+#print "JSON content is: ", Data::Dumper::Dumper( $json ), "\n";
24+
25+my $workbook = Spreadsheet::WriteExcel->new($dest);
26+$workbook->compatibility_mode();
27+my $worksheet4 = $workbook->add_worksheet('Test Descriptions');
28+$worksheet4->freeze_panes( 6, 0 );
29+$_->outline_settings( 1, 0, 0, 1 ) for $workbook->sheets();
30+$_->hide_gridlines(2) for $workbook->sheets();
31+$workbook->set_custom_color( 22, 230, 230, 230 ); # == Gray 10% (OOo)
32+$workbook->set_custom_color( 53, 220, 76, 0 ); # == Ubuntu Orange
33+my $i = 1;
34+
35+my $format01 = $workbook->add_format( # Titles
36+ align => 'left',
37+ size => 12,
38+ bold => 1,
39+);
40+my $format02 = $workbook->add_format( # Headlines
41+ align => 'center',
42+ size => 10,
43+ bold => 1,
44+);
45+my $format03 = $workbook->add_format(
46+ align => 'left',
47+ valign => 'vcenter',
48+ text_wrap => 1,
49+ size => 8,
50+);
51+my $format04 = $workbook->add_format(
52+ align => 'left',
53+ valign => 'vcenter',
54+ text_wrap => 1,
55+ size => 8,
56+ bg_color => 22,
57+);
58+my $format05 = $workbook->add_format(
59+ align => 'left',
60+ size => 24,
61+ color => 53,
62+);
63+my $format10 = $workbook->add_format( # Comments with indent lvl 1
64+ align => 'left',
65+ valign => 'vcenter',
66+ text_wrap => 1,
67+ size => 8,
68+ indent => 1,
69+);
70+my $format11 = $workbook->add_format( # Comments with indent lvl 1
71+ align => 'left',
72+ valign => 'vcenter',
73+ text_wrap => 1,
74+ size => 8,
75+ indent => 1,
76+ bg_color => 22,
77+);
78+my $format12 = $workbook->add_format( # Test categories
79+ align => 'left',
80+ size => 10,
81+ bold => 1,
82+);
83+$_->set_font('Verdana') for @{ $workbook->{_formats} };
84+
85+# Create the test descriptions sheet
86+$i = 1;
87+$worksheet4->write( $i, 1, 'System Test Plan', $format05 );
88+$worksheet4->set_row( $i, 30 );
89+$i += 2;
90+$worksheet4->set_row( $i, 15 );
91+$worksheet4->write( $i++, 1, 'Tests Descriptions', $format01 );
92+$i++;
93+
94+my $level = 1;
95+my $max_level = 1;
96+
97+sub find_max_level { # Find the maximum depth of the test tree
98+ my $tree = shift;
99+ foreach my $job ( @{$tree} ) {
100+ if ( scalar @{ $job->{'children'} } ) {
101+ $level++;
102+ find_max_level( $job->{'children'} );
103+ $level--;
104+ }
105+ else {
106+ $max_level = $level if $level > $max_level;
107+ }
108+ }
109+}
110+
111+sub write_test {
112+ my $tree = shift;
113+ foreach my $job ( @{$tree} ) {
114+ unless ( scalar @{ $job->{'children'} } ) {
115+ my $name = $job->{'description'}->{'name'};
116+ my $desc = $job->{'description'}->{'description'};
117+ s/\n//g for $name;
118+ $name =~ s/.*\///;
119+ my @lines = $desc =~ /\n/gm;
120+ my $lines = scalar(@lines);
121+ $worksheet4->set_row( $i, 12 + 11 * $lines, undef, 0, $level )
122+ if $level;
123+ $worksheet4->write( $i, $max_level + 1,
124+ $name, $i % 2 ? $format04 : $format03 );
125+
126+ $worksheet4->write( $i, $max_level + 2,
127+ $desc, $i % 2 ? $format11 : $format10 );
128+ $i++;
129+ }
130+ else {
131+ $worksheet4->set_row( $i, undef, undef, 0, $level, 0 );
132+ if ( ref $job->{'description'} eq 'HASH' ) {
133+ $worksheet4->write( $i++, $level + 1,
134+ $job->{'description'}->{'name'}, $format12 );
135+ }
136+ else {
137+ my $title = $job->{'description'};
138+ $title =~ s/\.txt(\.in)?$//;
139+ $worksheet4->write( $i++, $level + 1, $title, $format12 );
140+ }
141+ $level++;
142+ write_test( $job->{'children'} );
143+ $level--;
144+ }
145+ }
146+}
147+
148+find_max_level($json);
149+$level = 0;
150+
151+$worksheet4->set_column( 0, 0, 5 );
152+$worksheet4->set_column( $_, $_, 2 ) for ( 1 .. $max_level );
153+$worksheet4->set_column( $max_level + 1, $max_level + 1, 55 );
154+$worksheet4->set_column( $max_level + 2, $max_level + 2, 90 );
155+
156+$worksheet4->write( $i++, $max_level + 1, [ 'Name', 'Description' ],
157+ $format02 );
158+
159+write_test($json);
160+$worksheet4->autofilter( 5, $max_level + 1, $i, $max_level + 2 );
161
162=== modified file 'checkbox_editor/data.py'
163--- checkbox_editor/data.py 2010-09-23 17:30:29 +0000
164+++ checkbox_editor/data.py 2011-10-10 12:38:10 +0000
165@@ -2,8 +2,11 @@
166 This module contains a simple test suite parser class that can be used
167 by other modules to extract information from a test suite
168 """
169-import os, sys, re
170+import os, sys, re, json
171+import logging
172+import subprocess
173 from cStringIO import StringIO
174+from tempfile import NamedTemporaryFile
175
176 class InternalParsingError(Exception):
177 def __init__(self, filename, lines, failed_line, message):
178@@ -268,6 +271,7 @@
179 @staticmethod
180 def get(report_type, *args, **kwargs):
181 report_type_to_factory = {'Text file': 'TxtReporter',
182+ 'XLS file': 'XlsReporter',
183 'Single HTML file': 'SingleHtmlReporter',
184 'Multiple HTML files': 'MultipleHtmlReporter'}
185
186@@ -276,6 +280,31 @@
187 return factory(*args, **kwargs)
188
189
190+class XlsReporter(Reporter):
191+ """
192+ Write a report of selected data
193+ """
194+ def write_report(self):
195+ """
196+ Write XLS report
197+ """
198+ with NamedTemporaryFile(delete=False) as f:
199+ f.write(json.dumps(self.tree, indent=4))
200+
201+ reporter = os.path.join(os.path.dirname(os.path.realpath(__file__)),
202+ '_testplanxls.pl')
203+
204+ try:
205+ output = subprocess.check_output(
206+ ["perl", reporter, f.name, self.destination],
207+ stderr=subprocess.STDOUT)
208+ logging.info("XLS Test Plan generated successfully %s" % output)
209+ except subprocess.CalledProcessError, e:
210+ logging.error("XLS Test Plan:\n%s" % e.output)
211+
212+ os.unlink(f.name)
213+
214+
215 class TxtReporter(Reporter):
216 """
217 Write a report of selected data
218
219=== modified file 'checkbox_editor/editor.py'
220--- checkbox_editor/editor.py 2011-10-07 15:13:36 +0000
221+++ checkbox_editor/editor.py 2011-10-10 12:38:10 +0000
222@@ -731,6 +731,7 @@
223
224
225 filter_patterns = {'Text file': '*.txt',
226+ 'XLS file': '*.xls',
227 'Single HTML file': '*.html',
228 'Multiple HTML files': '*'}
229 for name, pattern in filter_patterns.items():
230
231=== modified file 'debian/control'
232--- debian/control 2011-06-17 15:12:07 +0000
233+++ debian/control 2011-10-10 12:38:10 +0000
234@@ -10,7 +10,9 @@
235 Package: checkbox-editor
236 Section: python
237 Architecture: all
238-Depends: ${misc:Depends}, ${python:Depends}, python-gtk2, yelp, bzr, apport-gtk, python-jinja2, python-apt
239+Depends: ${misc:Depends}, ${python:Depends}, python-gtk2, yelp, bzr, apport-gtk, python-jinja2, python-apt,
240+ libjson-xs-perl,
241+ libspreadsheet-writeexcel-perl
242 Recommends: packager
243 Suggests: make
244 XB-Python-Version: ${python:Versions}
245
246=== modified file 'setup.py'
247--- setup.py 2011-04-08 16:16:46 +0000
248+++ setup.py 2011-10-10 12:38:10 +0000
249@@ -48,6 +48,7 @@
250 interface.""",
251 packages = ['checkbox_editor'],
252 package_data={'checkbox_editor': ['glade/*',
253+ '*.pl',
254 'help/*.xml',
255 'help/figures/*']},
256 scripts = ['bin/checkbox-editor'],

Subscribers

People subscribed via source and target branches

to all changes: