rasta 0.1.8-x86-mswin32-60

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