Changed State to use composite, natural keys.
[merb_mart.git] / autotest.bak / merb_rspec.rb
blob9ff1f7263bfccdc520d6abe9784d4ebdf722259c
1 # Adapted from Autotest::Rails, RSpec's autotest class, as well as merb-core's.
2 require 'autotest'
4 class RspecCommandError < StandardError; end
6 class Autotest::MerbRspec < Autotest
8   # +model_tests_dir+::      the directory to find model-centric tests
9   # +controller_tests_dir+:: the directory to find controller-centric tests
10   # +view_tests_dir+::       the directory to find view-centric tests
11   # +fixtures_dir+::         the directory to find fixtures in
12   attr_accessor :model_tests_dir, :controller_tests_dir, :view_tests_dir, :fixtures_dir
14   def initialize # :nodoc:
15     super
17     initialize_test_layout
19     # Ignore any happenings in these directories
20     add_exception %r%^\./(?:doc|log|public|tmp)%
22     # Ignore any mappings that Autotest may have already set up
23     clear_mappings
25     # Any changes to a file in the root of the 'lib' directory will run any
26     # model test with a corresponding name.
27     add_mapping %r%^lib\/.*\.rb% do |filename, _|
28       files_matching %r%#{model_test_for(filename)}$%
29     end
31     add_mapping %r%^spec/(spec_helper|shared/.*)\.rb$% do
32       files_matching %r%^spec/.*_spec\.rb$%
33     end
35     # Any changes to a fixture will run corresponding view, controller and
36     # model tests
37     add_mapping %r%^#{fixtures_dir}/(.*)s.yml% do |_, m|
38       [
39         model_test_for(m[1]),
40         controller_test_for(m[1]),
41         view_test_for(m[1])
42       ]
43     end
45     # Any change to a test or spec will cause it to be run
46     add_mapping %r%^spec/(unit|models|integration|controllers|views|functional)/.*rb$% do |filename, _|
47       filename
48     end
50     # Any change to a model will cause it's corresponding test to be run
51     add_mapping %r%^app/models/(.*)\.rb$% do |_, m|
52       model_test_for(m[1])
53     end
55     # Any change to the global helper will result in all view and controller
56     # tests being run
57     add_mapping %r%^app/helpers/global_helpers.rb% do
58       files_matching %r%^spec/(views|functional|controllers)/.*_spec\.rb$%
59     end
61     # Any change to a helper will run it's corresponding view and controller
62     # tests, unless the helper is the global helper. Changes to the global
63     # helper run all view and controller tests.
64     add_mapping %r%^app/helpers/(.*)_helper(s)?.rb% do |_, m|
65       if m[1] == "global" then
66         files_matching %r%^spec/(views|functional|controllers)/.*_spec\.rb$%
67       else
68         [
69           view_test_for(m[1]),
70           controller_test_for(m[1])
71         ]
72       end
73     end
75     # Changes to views result in their corresponding view and controller test
76     # being run
77     add_mapping %r%^app/views/(.*)/% do |_, m|
78       [
79         view_test_for(m[1]),
80         controller_test_for(m[1])
81       ]
82     end
84     # Changes to a controller result in its corresponding test being run. If
85     # the controller is the exception or application controller, all
86     # controller tests are run.
87     add_mapping %r%^app/controllers/(.*)\.rb$% do |_, m|
88       if ["application", "exception"].include?(m[1])
89         files_matching %r%^spec/(controllers|views|functional)/.*_spec\.rb$%
90       else
91         controller_test_for(m[1])
92       end
93     end
95     # If a change is made to the router, run all controller and view tests
96     add_mapping %r%^config/router.rb$% do # FIX
97       files_matching %r%^spec/(controllers|views|functional)/.*_spec\.rb$%
98     end
100     # If any of the major files governing the environment are altered, run
101     # everything
102     add_mapping %r%^spec/spec_helper.rb|config/(init|rack|environments/test.rb|database.yml)% do # FIX
103       files_matching %r%^spec/(unit|models|controllers|views|functional)/.*_spec\.rb$%
104     end
105   end
107   def failed_results(results)
108     results.scan(/^\d+\)\n(?:\e\[\d*m)?(?:.*?Error in )?'([^\n]*)'(?: FAILED)?(?:\e\[\d*m)?\n(.*?)\n\n/m)
109   end
111   def handle_results(results)
112     @failures = failed_results(results)
113     @files_to_test = consolidate_failures @failures
114     unless $TESTING
115       if @files_to_test.empty?
116         hook :green
117       else
118         hook :red
119       end
120     end
121     @tainted = true unless @files_to_test.empty?
122   end
124   def consolidate_failures(failed)
125     filters = Hash.new { |h,k| h[k] = [] }
126     failed.each do |spec, failed_trace|
127       find_files.keys.select { |f| f =~ /spec\// }.each do |f|
128         if failed_trace =~ Regexp.new(f)
129           filters[f] << spec
130           break
131         end
132       end
133     end
134     filters
135   end
137   def make_test_cmd(files_to_test)
138     [
139       ruby,
140       "-S",
141       spec_command,
142       add_options_if_present,
143       files_to_test.keys.flatten.join(' ')
144     ].join(" ")
145   end
147   def add_options_if_present
148     File.exist?("spec/spec.opts") ? "-O spec/spec.opts " : ""
149   end
151   # Finds the proper spec command to use. Precendence is set in the
152   # lazily-evaluated method spec_commands.  Alias + Override that in
153   # ~/.autotest to provide a different spec command then the default
154   # paths provided.
155   def spec_command(separator=File::ALT_SEPARATOR)
156     unless defined? @spec_command then
157       @spec_command = spec_commands.find { |cmd| File.exists? cmd }
159       raise RspecCommandError, "No spec command could be found!" unless @spec_command
161       @spec_command.gsub!(File::SEPARATOR, separator) if separator
162     end
163     @spec_command
164   end
166   # Autotest will look for spec commands in the following
167   # locations, in this order:
168   #
169   #   * default spec bin/loader installed in Rubygems
170   #   * any spec command found in PATH
171   def spec_commands
172     [ File.join(Config::CONFIG['bindir'], 'spec'), 'spec' ]
173   end
175 private
177   # Determines the paths we can expect tests or specs to reside, as well as
178   # corresponding fixtures.
179   def initialize_test_layout
180     self.model_tests_dir      = "spec/models"
181     self.controller_tests_dir = "spec/controllers"
182     self.view_tests_dir       = "spec/views"
183     self.fixtures_dir         = "spec/fixtures"
184   end
186   # Given a filename and the test type, this method will return the
187   # corresponding test's or spec's name.
188   #
189   # ==== Arguments
190   # +filename+<String>:: the file name of the model, view, or controller
191   # +kind_of_test+<Symbol>:: the type of test we that we should run
192   #
193   # ==== Returns
194   # String:: the name of the corresponding test or spec
195   #
196   # ==== Example
197   #
198   #   > test_for("user", :model)
199   #   => "user_test.rb"
200   #   > test_for("login", :controller)
201   #   => "login_controller_test.rb"
202   #   > test_for("form", :view)
203   #   => "form_view_spec.rb" # If you're running a RSpec-like suite
204   def test_for(filename, kind_of_test) # :nodoc:
205     name  = [filename]
206     name << kind_of_test.to_s if kind_of_test == :view
207     name << "spec"
208     return name.join("_") + ".rb"
209   end
211   def model_test_for(filename)
212     [model_tests_dir, test_for(filename, :model)].join("/")
213   end
215   def controller_test_for(filename)
216     [controller_tests_dir, test_for(filename, :controller)].join("/")
217   end
219   def view_test_for(filename)
220     [view_tests_dir, test_for(filename, :view)].join("/")
221   end