tconsole 1.1.0pre8 → 1.1.0pre9

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -29,9 +29,9 @@ willing to merge it in, though.
29
29
  Installing tconsole
30
30
  ------
31
31
  gem install tconsole
32
-
32
+
33
33
  Prereleases of tconsole come out pretty frequently. You can install the latest prerelease version with:
34
-
34
+
35
35
  gem installt console --pre
36
36
 
37
37
  How to use tconsole
@@ -39,68 +39,55 @@ How to use tconsole
39
39
  In your shell of choice, cd into your Rails project's directory and then run `bundle exec tconsole` to fire up the console. You should see something like this:
40
40
 
41
41
  bundle exec tconsole
42
-
42
+
43
43
  Loading your Rails environment...
44
44
  Environment loaded in 7.160264s.
45
-
46
- >
47
-
45
+
46
+ >
47
+
48
48
  Now that you're in the console, let's test out the all command! Running all from the console runs all of your unit, functional, and integration tests:
49
49
 
50
50
  > all
51
51
  Running tests...
52
-
53
- Run options:
52
+
53
+ Run options:
54
54
 
55
55
  # Running tests:
56
56
 
57
57
  ....................................................................................
58
-
58
+
59
59
  Finished tests in 6.054574s, 6.4999 tests/s, 10.5822 assertions/s.
60
60
 
61
61
  39 tests, 45 assertions, 0 failures, 0 errors, 0 skips
62
62
 
63
63
  Test time (including load): 82.806741s
64
-
65
- >
66
-
67
- If you want to focus in on a particular subset of your tests, like units, functionals, or integration, just enter that keyword:
68
64
 
69
- > units
70
-
71
- > functionals
72
-
73
- > integration
74
-
65
+ >
75
66
 
76
- If you'd like to just run the tests that are related to recent changes
77
- you've made:
67
+ If you want to focus in on a particular subset of your tests, like units, functionals, or integration, just enter that keyword:
78
68
 
79
- > recent
69
+ > units
80
70
 
81
- Or if you'd like to run the tests for changes you've made since your
82
- last commit:
71
+ > functionals
83
72
 
84
- > uncommitted
73
+ > integration
85
74
 
86
- You can also focus in on just the tests in a given filename by entering a test file name into tconsole:
75
+ You can also specify to run all tests in a specific class:
87
76
 
88
- > test/unit/user_test.rb
77
+ > UserTest
89
78
 
90
- You can go one bit deeper and just run a particular test in that file
91
- with an extra argument:
79
+ You can go one bit deeper and just run a particular test in that file as
80
+ well:
92
81
 
93
- > test/unit/user_test.rb test_that_user_is_healthy
82
+ > UserTest#test_that_user_is_healthy
94
83
 
95
- That command will load up the user_test.rb file and then only run the
96
- test named test_that_user_is_healthy. You can add a specific test name
97
- argument to any tconsole command that runs tests.
84
+ You can list more than just one class or class and method to run, and
85
+ tconsole will run them all.
98
86
 
99
- There are a few special ! commands that use data from past test runs. The `!failed` command will rerun all of your files
100
- that included failing tests in the last test run:
87
+ There are a few special ! commands that use data from past test runs. The `!failed` command will rerun the set of tests that failed during the last run:
101
88
 
102
89
  > !failed
103
-
90
+
104
91
  There's also a `!timings` command that will show you a listing of your last test run's test times, sorted to help you
105
92
  improve slow tests:
106
93
 
@@ -125,11 +112,11 @@ improve slow tests:
125
112
  If you update your environment, maybe by editing your Gemfile or changing one of your application's configuration files, you can use the `reload` command to reload the entire environment:
126
113
 
127
114
  > reload
128
-
115
+
129
116
  And then finally, you can run the `exit` command to quit:
130
117
 
131
118
  > exit
132
-
119
+
133
120
  Reporting Issues and Contributing
134
121
  ------
135
122
 
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "drb/drb"
4
+
5
+ class Server
6
+ def connected?
7
+ true
8
+ end
9
+
10
+ def load_environment
11
+ ENV['RAILS_ENV'] ||= "test"
12
+
13
+ require './config/application'
14
+
15
+ ::Rails.application
16
+ ::Rails::Engine.class_eval do
17
+ def eager_load!
18
+ # turn off eager_loading
19
+ end
20
+ end
21
+
22
+ true
23
+ end
24
+
25
+ def stop
26
+ DRb.stop_service
27
+ end
28
+ end
29
+
30
+ socket = "/tmp/test.#{Process.pid}"
31
+
32
+ server_pid = fork do
33
+ server = Server.new
34
+
35
+ drb_server = DRb.start_service("drbunix:#{socket}", server)
36
+ DRb.thread.join
37
+ end
38
+
39
+ wait_until = Time.now + 10
40
+ DRb.start_service
41
+
42
+ loaded = false
43
+ until loaded || Time.now > wait_until
44
+ begin
45
+ puts "Trying to load environment"
46
+ server = DRbObject.new_with_uri("drbunix:#{socket}")
47
+ loaded = server.connected?
48
+ rescue
49
+ puts "Couldn't connect. Waiting."
50
+ sleep(1)
51
+ end
52
+ end
53
+
54
+ if !loaded
55
+ puts "Wasn't able to connect"
56
+ end
57
+
58
+ puts "Connected! Attempting to load environment"
59
+ server.load_environment
60
+ puts "Environment loaded!"
61
+
62
+ # Clean it all up
63
+ server.stop
data/lib/tconsole.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "tconsole/version"
2
2
  require "tconsole/config"
3
+ require "tconsole/console"
3
4
  require "tconsole/server"
4
5
  require "tconsole/test_result"
5
6
  require "tconsole/util"
@@ -8,24 +9,7 @@ require "readline"
8
9
  require "benchmark"
9
10
  require "drb/drb"
10
11
  require "term/ansicolor"
11
-
12
- Readline.completion_append_character = ""
13
-
14
- # Proc for helping us figure out autocompletes
15
- Readline.completion_proc = Proc.new do |str|
16
- known_commands = TConsole::Console::KNOWN_COMMANDS.grep(/^#{Regexp.escape(str)}/)
17
-
18
- files = Dir[str+'*'].grep(/^#{Regexp.escape(str)}/)
19
- formatted_files = files.collect do |filename|
20
- if File.directory?(filename)
21
- filename + File::SEPARATOR
22
- else
23
- filename
24
- end
25
- end
26
-
27
- known_commands.concat(formatted_files)
28
- end
12
+ require "shellwords"
29
13
 
30
14
  module TConsole
31
15
  class Runner
@@ -42,14 +26,12 @@ module TConsole
42
26
  puts
43
27
  puts "Welcome to tconsole (v#{TConsole::VERSION}). Type 'help' for help or 'exit' to quit."
44
28
 
45
- # Set up our console input handling and history
46
- console = Console.new
47
-
48
29
  # set up the config
49
30
  config = Config.configure
50
31
  config.trace_execution = true if argv.include?("--trace")
51
32
 
52
- port = "1233"
33
+ # Set up our console input handling and history
34
+ console = Console.new(config)
53
35
 
54
36
  # Start the server
55
37
  while running
@@ -60,7 +42,7 @@ module TConsole
60
42
  begin
61
43
  server = Server.new(config)
62
44
 
63
- drb_server = DRb.start_service("druby://localhost:#{port}", server)
45
+ drb_server = DRb.start_service("drbunix:/tmp/tconsole.#{Process.pid}", server)
64
46
  DRb.thread.join
65
47
  rescue Interrupt
66
48
  # do nothing here since the outer process will shut things down for us
@@ -72,34 +54,41 @@ module TConsole
72
54
  # Set up our client connection to the server
73
55
  config.trace("Connecting to testing server.")
74
56
  DRb.start_service
75
- server = DRbObject.new_with_uri("druby://localhost:#{port}")
57
+ server = nil
76
58
 
77
59
  loaded = false
78
60
  until loaded || Time.now > wait_until
79
61
  begin
80
- config.trace("Attempting to load environment.")
81
- running = server.load_environment
82
- loaded = true
83
- rescue => e
84
- config.trace("Could not load environment: #{e.message}")
85
- config.trace("==== Backtrace ====")
86
- config.trace(e.backtrace.join("\n"))
87
- config.trace("==== End Backtrace ====")
88
- loaded = false
89
- rescue Interrupt
90
- # do nothing if we get an interrupt
91
- puts "Interrupted in client"
62
+ server = DRbObject.new_with_uri("drbunix:/tmp/tconsole.#{server_pid}")
63
+
64
+ config.trace("Testing connection to test server.")
65
+ loaded = server.connected?
66
+ rescue
67
+ # do nothing
68
+ config.trace("Not connected to server yet. Retrying.")
69
+ sleep(1)
92
70
  end
93
-
94
- # Give drb a second to get set up
95
- sleep(1)
96
71
  end
97
72
 
98
- if !loaded
73
+ unless loaded
99
74
  puts
100
- puts "Couldn't connect to test environment. Exiting."
75
+ puts "Couldn't connect to the test environment. Exiting."
101
76
  exit(1)
102
77
  end
78
+
79
+ begin
80
+ config.trace("Attempting to load environment.")
81
+ running = server.load_environment
82
+ rescue => e
83
+ config.trace("Could not load environment: #{e.message}")
84
+ config.trace("==== Backtrace ====")
85
+ config.trace(e.backtrace.join("\n"))
86
+ config.trace("==== End Backtrace ====")
87
+
88
+ puts "Couldn't load the test environment. Exiting."
89
+ exit(1)
90
+ end
91
+
103
92
  config.trace("Environment loaded successfully.")
104
93
 
105
94
  running = console.read_and_execute(server) if running
@@ -115,119 +104,6 @@ module TConsole
115
104
  system("stty", stty_save);
116
105
  end
117
106
  end
118
-
119
- class Console
120
- KNOWN_COMMANDS = ["exit", "reload", "help", "units", "functionals", "integration", "recent", "uncommitted", "all", "info", "!failed", "!timings", "set"]
121
-
122
- def initialize
123
- read_history
124
- end
125
-
126
- # Returns true if the app should keep running, false otherwise
127
- def read_and_execute(server)
128
- while line = Readline.readline("tconsole> ", false)
129
- # TODO: Avoid pushing duplicate commands onto the history
130
- Readline::HISTORY << line
131
-
132
- line.strip!
133
- args = line.split(/\s/)
134
-
135
- if line == ""
136
- # do nothing
137
- elsif args[0] == "exit"
138
- return false
139
- elsif args[0] == "reload"
140
- return true
141
- elsif args[0] == "help"
142
- print_help
143
- elsif args[0] == "units" || args[0] == "unit"
144
- server.run_tests(["test/unit/**/*_test.rb"], args[1])
145
- elsif args[0] == "functionals" || args[0] == "functional"
146
- server.run_tests(["test/functional/**/*_test.rb"], args[1])
147
- elsif args[0] == "integration"
148
- server.run_tests(["test/integration/**/*_test.rb"], args[1])
149
- elsif args[0] == "recent"
150
- server.run_recent(args[1])
151
- elsif args[0] == "uncommitted"
152
- server.run_uncommitted(args[1])
153
- elsif args[0] == "all"
154
- server.run_tests(["test/unit/**/*_test.rb", "test/functional/**/*_test.rb", "test/integration/**/*_test.rb"], args[1])
155
- elsif args[0] == "!failed"
156
- server.run_failed
157
- elsif args[0] == "!timings"
158
- server.show_performance(args[1])
159
- elsif args[0] == "info"
160
- server.run_info
161
- elsif args[0] == "set"
162
- server.set(args[1], args[2])
163
- else
164
- server.run_tests([args[0]], args[1])
165
- end
166
- end
167
-
168
- true
169
- end
170
-
171
- # Prints a list of available commands
172
- def print_help
173
- puts
174
- puts "Available commands:"
175
- puts
176
- puts "all [test_pattern] # Run all test types (units, functionals, integration)"
177
- puts "units [test_pattern] # Run unit tests"
178
- puts "functionals [test_pattern] # Run functional tests"
179
- puts "integration [test_pattern] # Run integration tests"
180
- puts "recent [test_pattern] # Run tests for recently changed files"
181
- puts "uncommitted [test_pattern] # Run tests for uncommitted changes"
182
- puts "!failed # Runs the last set of failing tests"
183
- puts "!timings [limit] # Lists the timings for the last test run, sorted."
184
- puts "[filename] [test_pattern] # Run the tests contained in the given file"
185
- puts "reload # Reload your Rails environment"
186
- puts "set [variable] [value] # Sets a runtime variable (see below for details)"
187
- puts "exit # Exit the console"
188
- puts
189
- puts "Working with test patterns:"
190
- puts
191
- puts "All of the test execution commands include an optional test_pattern argument. A"
192
- puts "test pattern can be given to filter the executed tests to only those tests whose"
193
- puts "name matches the pattern given. This is especially useful when rerunning a failing"
194
- puts "test."
195
- puts
196
- puts "Runtime Variables"
197
- puts
198
- puts "You can set runtime variables with the set command. This helps out with changing"
199
- puts "features of TConsole that you may want to change at runtime. At present, the"
200
- puts "following runtime variables are available:"
201
- puts
202
- puts "fast # Turns on fail fast mode. Values: on, off"
203
- puts
204
-
205
- end
206
-
207
- def history_file
208
- File.join(ENV['HOME'], ".tconsole_history")
209
- end
210
-
211
- # Stores last 50 items in history to $HOME/.tconsole_history
212
- def store_history
213
- if ENV['HOME']
214
- File.open(history_file, "w") do |f|
215
- Readline::HISTORY.to_a.reverse[0..49].each do |item|
216
- f.puts(item)
217
- end
218
- end
219
- end
220
- end
221
-
222
- # Loads history from past sessions
223
- def read_history
224
- if ENV['HOME'] && File.exist?(history_file)
225
- File.readlines(history_file).reverse.each do |line|
226
- Readline::HISTORY << line
227
- end
228
- end
229
- end
230
- end
231
107
  end
232
108
 
233
109
 
@@ -22,16 +22,31 @@ module TConsole
22
22
  # test fails. Defaults to false.
23
23
  attr_accessor :fail_fast
24
24
 
25
+ # Defines the file set commands that are available
26
+ attr_accessor :file_sets
27
+
28
+ # Counts of tests in suites
29
+ attr_accessor :cached_suite_counts
30
+
31
+ # Element names we know
32
+ attr_accessor :cached_elements
33
+
25
34
  def initialize
26
35
  self.trace_execution = false
27
36
  self.test_dir = "./test"
28
37
  self.include_paths = ["./test", "./lib"]
29
38
  self.preload_paths = []
30
39
  self.fail_fast = false
40
+ self.file_sets = {
41
+ "all" => ["#{test_dir}/**/*_test.rb"]
42
+ }
31
43
 
32
44
  @after_load = nil
33
45
  @before_load = nil
34
46
  @before_test_run = nil
47
+
48
+ @cached_suite_counts = {}
49
+ @cached_elements = {}
35
50
  end
36
51
 
37
52
  def trace?
@@ -71,12 +86,27 @@ module TConsole
71
86
  @before_test_run.call unless @before_test_run.nil?
72
87
  end
73
88
 
89
+ def cache_test_ids(result)
90
+ self.cached_suite_counts = result.suite_counts
91
+ self.cached_elements = result.elements
92
+ end
93
+
74
94
  # Returns an appropriate tconsole config based on the environment
75
95
  def self.configure
76
96
  if is_rails?
77
97
  config = Config.new
78
98
  config.preload_paths = ["./config/application"]
79
99
  config.include_paths = ["./test"]
100
+ config.file_sets = {
101
+ "all" => ["#{config.test_dir}/unit/**/*_test.rb", "#{config.test_dir}/functional/**/*_test.rb",
102
+ "#{config.test_dir}/integration/**/*_test.rb"],
103
+ "units" => ["#{config.test_dir}/unit/**/*_test.rb"],
104
+ "unit" => ["#{config.test_dir}/unit/**/*_test.rb"],
105
+ "functionals" => ["#{config.test_dir}/functional/**/*_test.rb"],
106
+ "functional" => ["#{config.test_dir}/functional/**/*_test.rb"],
107
+ "integration" => ["#{config.test_dir}/integration/**/*_test.rb"]
108
+ }
109
+
80
110
 
81
111
  config.before_load do
82
112
  ENV["RAILS_ENV"] ||= "test"
@@ -0,0 +1,136 @@
1
+ module TConsole
2
+ class Console
3
+ KNOWN_COMMANDS = ["exit", "reload", "help", "info", "!failed", "!timings", "set"]
4
+
5
+ def initialize(config)
6
+ @config = config
7
+ read_history
8
+
9
+ define_autocomplete
10
+ end
11
+
12
+ def define_autocomplete
13
+ Readline.completion_append_character = ""
14
+
15
+ # Proc for helping us figure out autocompletes
16
+ Readline.completion_proc = Proc.new do |str|
17
+ known_commands = KNOWN_COMMANDS.grep(/^#{Regexp.escape(str)}/)
18
+
19
+ files = Dir[str+'*'].grep(/^#{Regexp.escape(str)}/)
20
+ formatted_files = files.collect do |filename|
21
+ if File.directory?(filename)
22
+ filename + File::SEPARATOR
23
+ else
24
+ filename
25
+ end
26
+ end
27
+
28
+ known_commands.concat(formatted_files).concat(@config.file_sets.keys)
29
+ end
30
+ end
31
+
32
+ # Returns true if the app should keep running, false otherwise
33
+ def read_and_execute(server)
34
+ while line = Readline.readline("tconsole> ", false)
35
+ line.strip!
36
+ args = Shellwords.shellwords(line)
37
+
38
+ # save the line unless we're exiting or repeating the last command
39
+ unless args[0] == "exit" || Readline::HISTORY[Readline::HISTORY.length - 1] == line
40
+ Readline::HISTORY << line
41
+ end
42
+
43
+ if line == ""
44
+ # do nothing
45
+ elsif args[0] == "exit"
46
+ return false
47
+ elsif args[0] == "reload"
48
+ return true
49
+ elsif args[0] == "help"
50
+ print_help
51
+ elsif args[0] == "!failed"
52
+ server.run_failed
53
+ elsif args[0] == "!timings"
54
+ server.show_performance(args[1])
55
+ elsif args[0] == "info"
56
+ server.run_info
57
+ elsif args[0] == "set"
58
+ server.set(args[1], args[2])
59
+ elsif @config.file_sets.has_key?(args[0])
60
+ server.run_file_set(args[0])
61
+ else
62
+ server.run_all_tests(args)
63
+ end
64
+ end
65
+
66
+ true
67
+ end
68
+
69
+ # Prints a list of available commands
70
+ def print_help
71
+ puts
72
+ puts "Available commands:"
73
+ puts
74
+ puts "reload # Reload your Rails environment"
75
+ puts "set [variable] [value] # Sets a runtime variable (see below for details)"
76
+ puts "exit # Exit the console"
77
+ puts "!failed # Runs the last set of failing tests"
78
+ puts "!timings [limit] # Lists the timings for the last test run, sorted."
79
+ puts "[filename] [test_pattern] # Run the tests contained in the given file"
80
+ puts
81
+ puts "Running file sets"
82
+ puts
83
+ puts "File sets are sets of files that are typically run together. For example,"
84
+ puts "in Rails projects it's common to run `rake test:units` to run all of the"
85
+ puts "tests under the units directory."
86
+ puts
87
+ puts "Available file sets:"
88
+
89
+ @config.file_sets.each do |set, paths|
90
+ puts set
91
+ end
92
+
93
+ puts
94
+ puts "Working with test patterns:"
95
+ puts
96
+ puts "All of the test execution commands include an optional test_pattern argument. A"
97
+ puts "test pattern can be given to filter the executed tests to only those tests whose"
98
+ puts "name matches the pattern given. This is especially useful when rerunning a failing"
99
+ puts "test."
100
+ puts
101
+ puts "Runtime Variables"
102
+ puts
103
+ puts "You can set runtime variables with the set command. This helps out with changing"
104
+ puts "features of TConsole that you may want to change at runtime. At present, the"
105
+ puts "following runtime variables are available:"
106
+ puts
107
+ puts "fast # Turns on fail fast mode. Values: on, off"
108
+ puts
109
+
110
+ end
111
+
112
+ def history_file
113
+ File.join(ENV['HOME'], ".tconsole_history")
114
+ end
115
+
116
+ # Stores last 50 items in history to $HOME/.tconsole_history
117
+ def store_history
118
+ if ENV['HOME']
119
+ File.open(history_file, "w") do |f|
120
+ Readline::HISTORY.to_a.reverse[0..49].each do |item|
121
+ f.puts(item)
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ # Loads history from past sessions
128
+ def read_history
129
+ if ENV['HOME'] && File.exist?(history_file)
130
+ File.readlines(history_file).reverse.each do |line|
131
+ Readline::HISTORY << line
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -1,21 +1,16 @@
1
1
  module TConsole
2
2
  class MiniTestHandler
3
- def self.run(name_pattern, config)
4
- args = []
5
- unless name_pattern.nil?
6
- args = ["--name", name_pattern]
7
- end
8
-
3
+ def self.run(match_patterns, config)
9
4
  # Make sure we have a recent version of minitest, and use it
10
5
  if ::MiniTest::Unit.respond_to?(:runner=)
11
- ::MiniTest::Unit.runner = TConsole::MiniTestUnit.new(config)
6
+ ::MiniTest::Unit.runner = TConsole::MiniTestUnit.new(match_patterns, config)
12
7
  else
13
8
  raise "MiniTest v#{MiniTest::Unit::VERSION} is not compatible with tconsole. Please load a more recent version of MiniTest"
14
9
  end
15
10
 
16
11
  # Run it
17
12
  runner = MiniTest::Unit.runner
18
- runner.run(args)
13
+ runner.run
19
14
 
20
15
  # Make sure that minitest doesn't run automatically when the process exits
21
16
  patch_minitest
@@ -48,12 +43,18 @@ module TConsole
48
43
  "P" => ::Term::ANSIColor.green
49
44
  }
50
45
 
51
- attr_accessor :config, :results
46
+ attr_accessor :match_patterns, :config, :results
47
+
48
+ def initialize(match_patterns, config)
49
+ self.match_patterns = match_patterns
50
+ self.match_patterns = [] unless self.match_patterns.is_a?(Array)
52
51
 
53
- def initialize(config)
54
52
  self.config = config
55
53
  self.results = TConsole::TestResult.new
56
54
 
55
+ results.suite_counts = config.cached_suite_counts
56
+ results.elements = config.cached_elements
57
+
57
58
  super()
58
59
  end
59
60
 
@@ -96,21 +97,39 @@ module TConsole
96
97
  end
97
98
 
98
99
  def _run_suite(suite, type)
100
+ @last_suite ||= nil
99
101
  @failed_fast ||= false
100
102
 
101
- filter = options[:filter] || '/./'
102
- filter = Regexp.new $1 if filter =~ /\/(.*)\//
103
+ assertions = suite.send("#{type}_methods").map do |method|
104
+ skip = false
105
+
106
+ # Get our unique id for this particular element
107
+ id = results.add_element(suite, method)
108
+ suite_id = results.elements[suite.to_s]
109
+
110
+ # If we're using failed fast mode and we already failed, just return
111
+ skip = true if @failed_fast
103
112
 
104
- assertions = suite.send("#{type}_methods").grep(filter).map do |method|
105
- if @failed_fast
113
+ # If we've got match patterns, see if this matches them
114
+ if !match_patterns.empty?
115
+ match = match_patterns.find do |pattern|
116
+ pattern == suite.to_s || pattern == "#{suite.to_s}##{method.to_s}" || pattern == suite_id || pattern == id
117
+ end
118
+
119
+ skip = true unless match
120
+ end
121
+
122
+ if skip
106
123
  0
107
124
  else
108
125
  inst = suite.new method
109
126
  inst._assertions = 0
110
127
 
111
128
  # Print the suite name if needed
112
- if results.add_suite(suite)
113
- print("\n\n", ::Term::ANSIColor.cyan, suite, ::Term::ANSIColor.reset, "\n")
129
+ unless @last_suite == suite
130
+ print("\n\n", ::Term::ANSIColor.cyan, suite, ::Term::ANSIColor.reset,
131
+ ::Term::ANSIColor.magenta, " #{suite_id}", ::Term::ANSIColor.reset, "\n")
132
+ @last_suite = suite
114
133
  end
115
134
 
116
135
  @start_time = Time.now
@@ -120,13 +139,16 @@ module TConsole
120
139
 
121
140
  result = "P" if result == "."
122
141
 
142
+ results.failures << id unless result == "P"
143
+
123
144
  if config.fail_fast && result != "P"
124
145
  @failed_fast = true
125
146
  end
126
147
 
127
148
  output = "#{result} #{method}"
128
149
 
129
- print COLOR_MAP[result], " #{output}", ::Term::ANSIColor.reset, " #{time}s\n"
150
+ print COLOR_MAP[result], " #{output}", ::Term::ANSIColor.reset, " #{time}s ",
151
+ ::Term::ANSIColor.magenta, "#{id}", ::Term::ANSIColor.reset, "\n"
130
152
 
131
153
  if @failed_fast
132
154
  print "\n", COLOR_MAP["E"], "Halting tests because of failure.", ::Term::ANSIColor.reset, "\n"
@@ -149,12 +171,10 @@ module TConsole
149
171
  when MiniTest::Assertion then
150
172
  @failures += 1
151
173
  results.failures += 1
152
- results.append_failure_details(klass, meth)
153
174
  "Failure:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
154
175
  else
155
176
  @errors += 1
156
177
  results.errors += 1
157
- results.append_failure_details(klass, meth)
158
178
  bt = MiniTest::filter_backtrace(e.backtrace).join "\n "
159
179
  "Error:\n#{meth}(#{klass}):\n#{e.class}: #{e.message}\n #{bt}\n"
160
180
  end
@@ -7,6 +7,11 @@ module TConsole
7
7
  self.last_result = TConsole::TestResult.new
8
8
  end
9
9
 
10
+ # Basically just a noop that helps us figure out if we're connected or not
11
+ def connected?
12
+ true
13
+ end
14
+
10
15
  def stop
11
16
  DRb.stop_service
12
17
  end
@@ -51,7 +56,9 @@ module TConsole
51
56
  result
52
57
  end
53
58
 
54
- def run_tests(globs, name_pattern, message = "Running tests...")
59
+ # Loads the files that match globs and then executes tests against them. Limit tests
60
+ # with class names, method names, and test ids using match_patterns.
61
+ def run_tests(globs, match_patterns, message = "Running tests...")
55
62
  time = Benchmark.realtime do
56
63
  # Pipe for communicating with child so we can get its results back
57
64
  read, write = IO.pipe
@@ -81,7 +88,7 @@ module TConsole
81
88
  require File.join(File.dirname(__FILE__), "minitest_handler")
82
89
 
83
90
  config.trace("Running tests.")
84
- result = MiniTestHandler.run(name_pattern, config)
91
+ result = MiniTestHandler.run(match_patterns, config)
85
92
  config.trace("Finished running tests.")
86
93
 
87
94
  config.trace("Writing test results back to server.")
@@ -102,6 +109,7 @@ module TConsole
102
109
  begin
103
110
  config.trace("Reading test results from console.")
104
111
  self.last_result = Marshal.load(response.unpack("m")[0])
112
+ config.cache_test_ids(self.last_result)
105
113
  config.trace("Finished reading test results from console.")
106
114
  rescue => e
107
115
  config.trace("Exception: #{e.message}")
@@ -109,7 +117,6 @@ module TConsole
109
117
  config.trace(e.backtrace.join("\n"))
110
118
  config.trace("==== End Backtrace ====")
111
119
 
112
-
113
120
  puts "ERROR: Unable to process test results."
114
121
  puts
115
122
 
@@ -127,68 +134,18 @@ module TConsole
127
134
  puts
128
135
  end
129
136
 
130
- # This code is from the rails test:recents command
131
- def run_recent(test_pattern)
132
- touched_since = Time.now - 600 # 10 minutes ago
133
- files = recent_files(touched_since, "app/models/**/*.rb", "test/unit")
134
- files.concat(recent_files(touched_since, "app/controllers/**/*.rb", "test/functional"))
135
-
136
- message = "Running #{files.length} #{files.length == 1 ? "test file" : "test files"} based on changed files..."
137
- run_tests(files, test_pattern, message)
138
- end
139
-
140
- def run_failed
141
- file_names = last_result.failure_details.map { |detail| filenameify(detail[:class]) }
142
- files_to_rerun = []
143
-
144
- files_to_rerun << file_names.map {|file| (file.match(/controller/)) ? "test/functional/#{file}.rb" : "test/unit/#{file}.rb"}
145
- run_tests(files_to_rerun, nil, "Running last failed tests: #{files_to_rerun.join(", ")}")
137
+ # Runs all tests against the match patterns given
138
+ def run_all_tests(match_patterns = nil)
139
+ run_tests(config.file_sets["all"], match_patterns)
146
140
  end
147
141
 
148
- def recent_files(touched_since, source_pattern, test_path)
149
- Dir.glob(source_pattern).map do |path|
150
- if File.mtime(path) > touched_since
151
- tests = []
152
- source_dir = File.dirname(path).split("/")
153
- source_file = File.basename(path, '.rb')
154
-
155
- # Support subdirs in app/models and app/controllers
156
- modified_test_path = source_dir.length > 2 ? "#{test_path}/" << source_dir[1..source_dir.length].join('/') : test_path
157
-
158
- # For modified files in app/ run the tests for it. ex. /test/functional/account_controller.rb
159
- test = "#{modified_test_path}/#{source_file}_test.rb"
160
- tests.push test if File.exist?(test)
161
-
162
- # For modified files in app, run tests in subdirs too. ex. /test/functional/account/*_test.rb
163
- test = "#{modified_test_path}/#{File.basename(path, '.rb').sub("_controller","")}"
164
- File.glob("#{test}/*_test.rb").each { |f| tests.push f } if File.exist?(test)
165
-
166
- return tests
167
-
168
- end
169
- end.flatten.compact
142
+ # Runs a file set out of the config
143
+ def run_file_set(set)
144
+ run_tests(config.file_sets[set], nil)
170
145
  end
171
146
 
172
- # Based on the code from rake test:uncommitted in Rails
173
- def run_uncommitted(test_pattern)
174
- if File.directory?(".svn")
175
- changed_since_checkin = silence_stderr { `svn status` }.split.map { |path| path.chomp[7 .. -1] }
176
- elsif File.directory?(".git")
177
- changed_since_checkin = silence_stderr { `git ls-files --modified --others` }.split.map { |path| path.chomp }
178
- else
179
- puts "Not a Subversion or Git checkout."
180
- return
181
- end
182
-
183
- models = changed_since_checkin.select { |path| path =~ /app[\\\/]models[\\\/].*\.rb$/ }
184
- controllers = changed_since_checkin.select { |path| path =~ /app[\\\/]controllers[\\\/].*\.rb$/ }
185
-
186
- unit_tests = models.map { |model| "test/unit/#{File.basename(model, '.rb')}_test.rb" }
187
- functional_tests = controllers.map { |controller| "test/functional/#{File.basename(controller, '.rb')}_test.rb" }
188
- files = (unit_tests + functional_tests).uniq.select { |file| File.exist?(file) }
189
-
190
- message = "Running #{files.length} #{files.length == 1 ? "test file" : "test files"} based on uncommitted changes..."
191
- run_tests(files, test_pattern, message)
147
+ def run_failed
148
+ run_tests(config.file_sets["all"], last_result.failures)
192
149
  end
193
150
 
194
151
  def run_info
@@ -18,29 +18,44 @@ module TConsole
18
18
  # The timings for the tests we've run
19
19
  attr_accessor :timings
20
20
 
21
+ # The element id lookup hash
22
+ attr_accessor :elements
23
+
24
+ # Test counts within various suites
25
+ attr_accessor :suite_counts
26
+
21
27
  def initialize
22
28
  self.failures = 0
23
29
  self.errors = 0
24
30
  self.skips = 0
25
- self.failure_details = []
31
+ self.failures = []
26
32
  self.suites = {}
27
33
  self.timings = []
28
- end
29
34
 
30
- # Adds to the failure details that we know about
31
- def append_failure_details(klass, meth)
32
- self.failure_details << { :class => klass.to_s, :method => meth.to_s }
35
+ self.suite_counts = {}
36
+ self.elements = {}
33
37
  end
34
38
 
35
- # Records that we've encountered a particular suite. Returns true
36
- # if it's new or false otherwise.
37
- def add_suite(suite)
38
- if suites.has_key?(suite.to_s)
39
- false
40
- else
41
- suites[suite.to_s] = true
42
- true
39
+ def add_element(suite, method)
40
+ canonical_name = "#{suite}##{method}"
41
+
42
+ # Just return the id if we already know about this
43
+ if id = elements[canonical_name]
44
+ return id
43
45
  end
46
+
47
+ # See if we know about this suite already
48
+ unless suite_id = elements[suite.to_s]
49
+ suite_id = self.suite_counts.length + 1
50
+ elements[suite.to_s] = suite_id
51
+ suite_counts[suite.to_s] ||= 0
52
+ end
53
+
54
+ suite_counts[suite.to_s] += 1
55
+ id = "#{suite_id}-#{suite_counts[suite.to_s]}"
56
+ elements[canonical_name] = id
57
+
58
+ id
44
59
  end
45
60
 
46
61
  def add_timing(suite, method, time)
@@ -1,3 +1,3 @@
1
1
  module TConsole
2
- VERSION = "1.1.0pre8"
2
+ VERSION = "1.1.0pre9"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tconsole
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0pre8
4
+ version: 1.1.0pre9
5
5
  prerelease: 5
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-17 00:00:00.000000000 Z
12
+ date: 2012-02-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: term-ansicolor
16
- requirement: &70230844589280 !ruby/object:Gem::Requirement
16
+ requirement: &70167646243500 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: 1.0.7
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70230844589280
24
+ version_requirements: *70167646243500
25
25
  description: ! " tconsole allows Rails developers to easily and quickly run their
26
26
  tests as a whole or in subsets. It forks the testing processes from\n a preloaded
27
27
  test environment to ensure that developers don't have to reload their entire Rails
@@ -39,8 +39,10 @@ files:
39
39
  - README.md
40
40
  - Rakefile
41
41
  - bin/tconsole
42
+ - drb_connection_test.rb
42
43
  - lib/tconsole.rb
43
44
  - lib/tconsole/config.rb
45
+ - lib/tconsole/console.rb
44
46
  - lib/tconsole/minitest_handler.rb
45
47
  - lib/tconsole/server.rb
46
48
  - lib/tconsole/test_result.rb