tconsole 1.1.0pre8 → 1.1.0pre9

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.
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