rasta 0.1.8-x86-mswin32-60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,138 @@
1
+
2
+ module Rasta
3
+ module Fixture
4
+ module BaseFixture
5
+ def initialize_run(sheet)
6
+ @sheet = sheet
7
+ @metrics = Metrics.new
8
+ end
9
+
10
+ # Called by fixture.rb on each worksheet
11
+ def run
12
+ generate_rspec_tests
13
+ teardown_tests
14
+ end
15
+
16
+ # Call into rspec to run the current set of tests
17
+ # and then remove the example from the group which
18
+ # if we dont will run test 1 then test 1,2 then test 1,2,3
19
+ # and we'll get duplicate test results accordingly
20
+ def run_rspec_test
21
+ Spec::Runner.options.run_examples
22
+ Spec::Runner.options.remove_example_group(Spec::Runner.options.example_groups[0])
23
+ end
24
+
25
+ # This is called after all testcases are run
26
+ # for the worksheet.
27
+ def teardown_tests
28
+ @sheet.select_home_cell
29
+ end
30
+
31
+ # Allow access to the current failure count from RSpec
32
+ # which will let us change the tab color based on the test results
33
+ def current_failure_count
34
+ Spec::Runner.options.reporter.failure_count
35
+ end
36
+
37
+ # Iterate over spreadsheet cells, create the
38
+ # test fixtures and call your test. Generally
39
+ # you will need to iterate over the spreadsheet
40
+ # cells and once you have the information you need
41
+ # to actually run the rspec test you should
42
+ # use:
43
+ # select_output_cell(cell)
44
+ # This tells the reporter which spreadsheet
45
+ # cell should get the results
46
+ # create_rspec_test(test_fixture, cell)
47
+ # This is a method you create which will create
48
+ # rspec testcase(s) based on the inputs
49
+ # run_rspec_test
50
+ # This will run the test set up by create_test
51
+ def generate_rspec_tests
52
+ end
53
+
54
+ # This is the guts of the rspec test you want to call
55
+ # so for example something like
56
+ #
57
+ # describe 'test' do
58
+ # before(:all) do
59
+ # end
60
+ # it "testcase 1" do
61
+ # end
62
+ # it "testcase 2" do
63
+ # end
64
+ # ... etc ...
65
+ # after(:all) do
66
+ # end
67
+ # end
68
+ def create_rspec_test(args)
69
+ end
70
+
71
+ # This is how the fixture notifies the rspec reporter
72
+ # which spreadsheet cell to dump the results into
73
+ def select_output_cell(c)
74
+ Spec::Runner.options.reporter.set_current_spreadsheet_cell = c
75
+ end
76
+
77
+ # ==================================================
78
+ # Dont enable these, even in the base fixture or
79
+ # it could fail if the function is in a superclass of
80
+ # the test fixture. These are here to show what could
81
+ # be in the test fixture and if so we'll call them
82
+
83
+ # This is called by the fixture before any test
84
+ # is run on the worksheet so you can perform any
85
+ # setup needed
86
+ #def before_all
87
+ #end
88
+
89
+ # This method is called before each set of tests
90
+ # typically a row or column of tests or potentially
91
+ # before each cell, depending on the fixture
92
+ #def before_each
93
+ #end
94
+
95
+ # This method is called after each set of tests
96
+ # typically a row or column of tests or potentially
97
+ # after each cell, depending on the fixture
98
+ #def after_each
99
+ #end
100
+
101
+ # This is called by the fixture after all tests
102
+ # are run on the worksheet so you can perform any
103
+ # teardown needed
104
+ #def after_all
105
+ #end
106
+ # ==================================================
107
+
108
+
109
+ # Store metrics as the fixture is running
110
+ class Metrics
111
+ attr_accessor :attribute_count, :method_count, :record_count
112
+ def initialize
113
+ reset_page_counts
114
+ reset_record_counts
115
+ end
116
+ # Counts tracked on a worksheet scope
117
+ def reset_page_counts
118
+ @record_count = 0
119
+ end
120
+ # Counts tracked on a record scope
121
+ def reset_record_counts
122
+ @attribute_count = 0
123
+ @method_count = 0
124
+ end
125
+ def inc(attribute_name)
126
+ eval("@#{attribute_name.to_s} += 1")
127
+ end
128
+ end
129
+
130
+ # Store any extention in the tab name. This can be used to pass
131
+ # additional information to the fixture
132
+ def tab_extension=(x)
133
+ @tab_extension = x
134
+ end
135
+
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,183 @@
1
+ require 'spec'
2
+ require 'rasta/fixture/base_fixture'
3
+
4
+ module Rasta
5
+ module Fixture
6
+ module RastaFixture
7
+ include Rasta::Fixture::BaseFixture
8
+ attr_accessor :pending, :comment
9
+
10
+ GREEN = 35
11
+ RED = 40
12
+
13
+ def generate_rspec_tests
14
+ @metrics.reset_page_counts
15
+ @test_fixture = self
16
+ initial_failure_count = current_failure_count
17
+
18
+ try(:before_all)
19
+ @sheet.each do |record|
20
+ @metrics.reset_record_counts
21
+ @current_record = record
22
+ @metrics.inc(:record_count)
23
+ @test_fixture = self.dup #make a copy so attributes don't bleed between rows
24
+ try(:before_each)
25
+ record.each do |cell|
26
+ call_test_fixture(cell)
27
+ end
28
+ try(:after_each)
29
+ @test_fixture = self
30
+ end
31
+ try(:after_all)
32
+
33
+ update_tab_color(current_failure_count > initial_failure_count)
34
+ end
35
+
36
+ # Check to see if the cell's header is an attribute
37
+ # or a method and call it or raise an error
38
+ def call_test_fixture(cell)
39
+ name = cell.header
40
+ return if cell.value.nil? || cell.header.nil?
41
+ if cell.header == 'pending'
42
+ @test_fixture.pending = cell.value
43
+ elsif self.methods.include?(name + '=')
44
+ call_fixture_attribute(name, cell.value)
45
+ else
46
+ # don't specifically check that the method
47
+ # exists so we can allow for things like
48
+ # dynamic methods. An exception still gets thrown
49
+ # so we should be able to handle missing methods
50
+ call_fixture_method(cell)
51
+ end
52
+ end
53
+
54
+ # For cell headers detected as test fixture
55
+ # attributes, set the attribute
56
+ def call_fixture_attribute(name, value)
57
+ @metrics.inc(:attribute_count)
58
+ @test_fixture.send("#{name}=", value)
59
+ end
60
+
61
+ # For cell headers detected as test fixture
62
+ # methods, call the method and run the rspec test
63
+ def call_fixture_method(cell)
64
+ @metrics.inc(:method_count)
65
+ create_rspec_test(cell)
66
+ run_rspec_test
67
+ end
68
+
69
+ # Given a cell that is a method call
70
+ # create an rspec test that can check the
71
+ # return value and handle any exceptions
72
+ def create_rspec_test(cell)
73
+ select_output_cell(cell)
74
+ test_method_name = "#{cell.header}()"
75
+ test_fixture = @test_fixture
76
+ describe "#{cell.sheet.name}[#{cell.name}]" do
77
+ include TestCaseHelperMethods
78
+
79
+ before(:all) do
80
+ @fixture = test_fixture
81
+ @cell = cell
82
+ @@actual_value = nil
83
+ # If the cell's value is an exception, parse it out so we can handle properly
84
+ @exception_expected = !(@cell.value.to_s =~ /^error\s*((?:(?!:\s).)*):?\s*(.*)/).nil?
85
+ if @exception_expected
86
+ @exception = eval($1) if $1 != ''
87
+ @exception_message = $2 if $2 != ''
88
+ end
89
+ end
90
+
91
+ it "#{test_method_name} should handle exceptions" do
92
+ set_pending_status
93
+ check_for_errors
94
+ end
95
+ it "#{test_method_name} should == #{cell.value.to_s}" do
96
+ set_pending_status
97
+ check_test_result
98
+ end
99
+
100
+ after(:all) do
101
+ @fixture = nil
102
+ end
103
+ end
104
+ end
105
+
106
+ def update_tab_color(result)
107
+ result ? @sheet.ole_object.Tab.ColorIndex = RED : @sheet.ole_object.Tab.ColorIndex = GREEN
108
+ end
109
+ private :update_tab_color
110
+
111
+ module TestCaseHelperMethods
112
+ @@actual_value = nil
113
+ def check_for_errors
114
+ if @exception_expected
115
+ if @exception
116
+ lambda{ @fixture.send @cell.header }.should raise_error(@exception, @exception_message)
117
+ else
118
+ lambda{ @fixture.send @cell.header }.should raise_error
119
+ end
120
+ else
121
+ lambda{ @@actual_value = @fixture.send @cell.header }.should_not raise_error
122
+ end
123
+ end
124
+
125
+ def check_test_result
126
+ return if @exception_expected
127
+ # Allow spreadsheet values of nil be captured to
128
+ # run methods that do not have a return. This is done
129
+ # this way because if we tranlated the cell value to nil then
130
+ # we couldn't tell the difference between a cell=nil vs an empty cell
131
+ if @cell.value == 'nil'
132
+ expected_value = nil
133
+ else
134
+ expected_value = @cell.value
135
+ end
136
+ case expected_value
137
+ when /^(<=|>=|>|<)(.+)/
138
+ eval("@@actual_value.should #{$1} #{$2}")
139
+ when Regexp
140
+ @@actual_value.should =~ expected_value
141
+ else
142
+ @@actual_value.should == expected_value
143
+ end
144
+ end
145
+
146
+ def set_pending_status
147
+ if @fixture.methods.include?('pending') and @fixture.pending
148
+ pending(@fixture.pending)
149
+ end
150
+ end
151
+
152
+ end
153
+
154
+ # Call a method in the test fixture and if it
155
+ # throws an exception, create an rspec test. This
156
+ # is not for standard tests, but for setup and
157
+ # teardown tasks that should happen but are not part
158
+ # of the actual test cases.
159
+ def try(method)
160
+ return if !method
161
+ if @test_fixture.methods.include?(method.to_s)
162
+ begin
163
+ @test_fixture.send method
164
+ rescue SystemExit
165
+ exit
166
+ rescue Interrupt
167
+ exits
168
+ rescue => error_message
169
+ # If the method gets an error, re-raise the error
170
+ # in the context of rspec so the results pick it up
171
+ describe "#{@test_fixture.class}[#{@current_record.to_s}] #{method.to_s}()" do
172
+ it "should not throw an exception" do
173
+ lambda{raise error_message}.should_not raise_error
174
+ end
175
+ end
176
+ run_rspec_test
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+
@@ -0,0 +1,195 @@
1
+ require 'fileutils'
2
+
3
+ module Rasta
4
+
5
+ module Fixture
6
+
7
+ # Load and run a fixture, indicated by the spreadsheet tab name
8
+ class FixtureLoader
9
+
10
+ def initialize(sheet, loaded_classes)
11
+
12
+ # We're making an assumption here
13
+ # that the fixture class matches the
14
+ # spreadsheet tab name for the fixture
15
+ base_sheet_name = sheet.name.dup
16
+ base_sheet_name.gsub!(/#.*/, '')
17
+
18
+ # If the tab name has a dotted extension, grab it
19
+ tab_extension = base_sheet_name[/\..*/].sub(/^./,'') if base_sheet_name[/\..*/]
20
+
21
+ # Remove any extension found from the name
22
+ base_sheet_name.gsub!(/\..*/, '')
23
+
24
+ # Get a reference to the loaded class
25
+ classname = find_class_by_name(base_sheet_name, loaded_classes)
26
+
27
+ # Instantiate the test fixture
28
+ begin
29
+ fixture = classname.new
30
+ fixture.initialize_run(sheet)
31
+ fixture.tab_extension = tab_extension
32
+ rescue ArgumentError => e
33
+ raise ArgumentError, "Unable to load class #{@classname}. Make sure the class includes the Rasta fixture: #{e.inspect + e.backtrace.join("\n")}"
34
+ end
35
+
36
+ # Run the test fixture
37
+ fixture.run
38
+ fixture = nil
39
+ end
40
+
41
+ def find_class_by_name(classname, loaded_classes)
42
+ config = Configuration.instance
43
+ ObjectSpace.each_object(Class) do |klass|
44
+ # don't try to load a class unless it is
45
+ # something we actually loaded ourselves
46
+ next unless loaded_classes.include?(klass.name)
47
+ if config.module
48
+ return klass if klass.name =~ /#{config.module}::#{classname}$/
49
+ else
50
+ return klass if klass.name =~ /(^|:)#{classname}$/
51
+ end
52
+ end
53
+ raise ArgumentError, "Class '#{config.module}::#{classname}' not found!"
54
+ end
55
+ end
56
+
57
+ # Manage requests to run spreadsheets and send each to the FixtureLoader
58
+ class FixtureRunner
59
+ def initialize
60
+ @workbooks = []
61
+ prepare_results_directory
62
+ end
63
+
64
+ def add(spreadsheet)
65
+ require 'rasta/spreadsheet'
66
+ raise IOError, "File not found: #{spreadsheet}" if ! File.exists?(File.expand_path(spreadsheet))
67
+ workingfile = copy(spreadsheet)
68
+ config = Configuration.instance
69
+ @excel = Rasta::Spreadsheet::Excel.instance
70
+ @excel.pagecount = config.pagecount.to_i
71
+ @excel.recordcount = config.recordcount.to_i
72
+ @excel.continue = config.continue
73
+ @excel.visible = config.visible
74
+ @workbooks << workingfile
75
+ end
76
+
77
+ ##
78
+ # Copies the spreadsheet with results in the [results_path] parameter
79
+ # provided when calling runxls.rb. If no parameter is provided, the results
80
+ # are saved into the results folder within the working dir.
81
+ def copy(spreadsheet)
82
+ config = Configuration.instance
83
+ testfilename = generate_testfile(spreadsheet)
84
+ while File.exists?(File.expand_path(testfilename))
85
+ testfilename = generate_testfile(spreadsheet)
86
+ end
87
+ FileUtils.cp(spreadsheet, testfilename)
88
+ return testfilename
89
+ end
90
+ def generate_testfile(spreadsheet)
91
+ config = Configuration.instance
92
+ config.result_index += 1
93
+ filename = config.results_path + '/' + File.basename(spreadsheet)
94
+ filename.sub!(/(\.\w{3})$/, ".#{config.result_index}" + '\1')
95
+ return filename
96
+ end
97
+ def prepare_results_directory
98
+ config = Configuration.instance
99
+ if File.expand_path(config.results_path) != config.results_path
100
+ config.results_path = Dir.getwd + '/' + config.results_path
101
+ end
102
+ # Remove the existing results
103
+ begin
104
+ FileUtils.rm(Dir.glob(File.join(config.results_path, "*"))) if File.exists?(config.results_path)
105
+ rescue Errno::EACCES
106
+ # The file is probably open so ignore and we'll create a new file
107
+ end
108
+ # Create a new results directory
109
+ begin
110
+ FileUtils.mkdir_p(config.results_path) if !File.exists?(config.results_path)
111
+ rescue => e
112
+ puts "Creating directory #{config.results_path}"
113
+ raise IOError, e.message
114
+ end
115
+ end
116
+ # Load the files in the fixture path and
117
+ # track which classes got loaded so we can hopefully
118
+ # reduce the chance of namespace issues. There may
119
+ # be a better way to handle this
120
+ def load_test_fixtures
121
+ before_classes = []
122
+ after_classes = []
123
+ ObjectSpace.each_object(Class) { |x| before_classes << x.name }
124
+ config = Configuration.instance
125
+ if config.require.size > 0
126
+ config.require.each { |file| do_require file }
127
+ else
128
+ # Look through all of the .rb files in the fixture path to see if
129
+ # we can find the file that has the class specified
130
+ if File.directory?(config.fixture_path)
131
+ fixture_files = File.join(config.fixture_path.gsub('\\','/'), "**", "*.rb")
132
+ Dir.glob(fixture_files).each {|f| do_require f }
133
+ else
134
+ do_require config.fixture_path
135
+ end
136
+ end
137
+ ObjectSpace.each_object(Class) { |x| after_classes << x.name }
138
+ return (after_classes - before_classes)
139
+ end
140
+
141
+ def do_require(filename)
142
+ raise LoadError, "Unable to require file '#{filename}'" unless require filename
143
+ end
144
+
145
+ def execute
146
+ loaded_classes = load_test_fixtures
147
+ initialize_rspec
148
+ begin
149
+ start_rspec
150
+ @workbooks.each do |workbook|
151
+ begin
152
+ book = Rasta::Spreadsheet::Book.new(workbook)
153
+ book.each do |sheet|
154
+ FixtureLoader.new(sheet, loaded_classes)
155
+ end
156
+ ensure
157
+ book.save
158
+ end
159
+ end
160
+ # move this in the loop once I work out the
161
+ # way to do this in rspec properly
162
+ stop_rspec
163
+ ensure
164
+ @excel.cleanup
165
+ end
166
+ end
167
+
168
+ def initialize_rspec
169
+ require 'rasta/extensions/rspec_extensions'
170
+ require 'rasta/formatter/spreadsheet_formatter'
171
+ require 'spec/runner/formatter/progress_bar_formatter'
172
+ require 'spec/runner/formatter/html_formatter'
173
+ end
174
+ private :initialize_rspec
175
+
176
+ def start_rspec
177
+ config = Configuration.instance
178
+ Spec::Runner.options.backtrace_tweaker = Spec::Runner::NoisyBacktraceTweaker.new
179
+ Spec::Runner.options.parse_format("Formatter::ProgressBarFormatter")
180
+ Spec::Runner.options.parse_format("Formatter::BaseTextFormatter:#{config.results_path}/results.txt")
181
+ Spec::Runner.options.parse_format("Formatter::HtmlFormatter:#{config.results_path}/results.html")
182
+ Spec::Runner.options.parse_format("Formatter::SpreadsheetFormatter:#{config.results_path}/spreadsheet.out")
183
+ Spec::Runner.options.reporter.initialize_spreadsheet
184
+ end
185
+ private :start_rspec
186
+
187
+ def stop_rspec
188
+ Spec::Runner.options.reporter.original_dump if Spec::Runner.options
189
+ Spec::Runner.options.clear_format_options;
190
+ end
191
+ private :stop_rspec
192
+
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec/runner/formatter/base_formatter'
2
+ module Spec
3
+ module Runner
4
+ module Formatter
5
+ class SpreadsheetFormatter < Spec::Runner::Formatter::BaseFormatter
6
+ GREEN = 35
7
+ RED = 40
8
+ YELLOW = 19
9
+ NONE = -4142
10
+
11
+ def cell=(c)
12
+ @cell = c
13
+ end
14
+
15
+ def example_failed(example, counter, failure)
16
+ if @cell
17
+ failure.exception.backtrace ? @cell.color = YELLOW : @cell.color = RED
18
+ comment = "method: " + @cell.header + "()\n"
19
+ comment += failure.exception.message.gsub(/,\s+/,",\n")
20
+ comment += "\n" + failure.exception.backtrace.join("\n") if failure.exception.backtrace
21
+ @cell.comment = comment
22
+ end
23
+ end
24
+
25
+ def example_passed(example)
26
+ @cell.color = GREEN if @cell && @cell.color == NONE
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+ end