tconsole-rails4 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,123 @@
1
+ # -*- coding: utf-8 -*-
2
+ module TConsole
3
+ class MinitestServer < Server
4
+
5
+ # Loads the files that match globs and then executes tests against them. Limit tests
6
+ # with class names, method names, and test ids using match_patterns.
7
+ def run_tests(globs, match_patterns, message = "Running tests...")
8
+ time = Benchmark.realtime do
9
+ reporter.info(message)
10
+ reporter.info
11
+
12
+ paths = []
13
+ globs.each do |glob|
14
+ paths.concat(Dir.glob(glob))
15
+ end
16
+
17
+ if paths.length == 0
18
+ reporter.warn("No test files match your requested test set: #{globs.join(",")}.")
19
+ reporter.warn("Skipping execution.")
20
+ return nil
21
+ end
22
+
23
+ self.last_result = run_in_fork do
24
+
25
+ paths.each do |path|
26
+ reporter.trace("Requested path `#{path}` doesn't exist.") unless File.exist?(path)
27
+ require File.expand_path(path)
28
+ end
29
+
30
+ reporter.trace("Running before_test_run callback")
31
+ config.before_test_run!
32
+ reporter.trace("Completed before_test_run callback")
33
+
34
+ result = nil
35
+ if defined?(::Minitest)
36
+ reporter.trace("Detected minitest.")
37
+ require File.join(File.dirname(__FILE__), "minitest_handler")
38
+ require File.join(File.dirname(__FILE__), "minitest_reporter")
39
+
40
+ reporter.trace("Running tests.")
41
+ runner = MiniTestHandler.new(config)
42
+
43
+ # TODO надо починить Ctrl+C
44
+ # Handle trapping interrupts
45
+ trap("SIGINT") do
46
+ reporter.warn
47
+ reporter.warn("Trapped interrupt. Halting tests.")
48
+
49
+ runner.interrupted = true
50
+ end
51
+
52
+
53
+ result, res_reporter = runner.match_and_run(match_patterns, config)
54
+
55
+ res_reporter.report
56
+ # Make sure minitest doesn't run automatically
57
+ MiniTestHandler.patch_minitest
58
+
59
+ reporter.trace("Finished running tests.")
60
+
61
+ if runner.interrupted
62
+ reporter.error("Test run was interrupted.")
63
+ end
64
+
65
+ elsif defined?(::Test::Unit)
66
+ reporter.error("Sorry, but #{config.app} doesn't support Test::Unit")
67
+ end
68
+
69
+ result
70
+ end
71
+
72
+ if self.last_result == nil
73
+ # Just in case anything crazy goes down with marshalling
74
+ self.last_result = TConsole::TestResult.new
75
+ end
76
+
77
+ config.cache_test_ids(self.last_result)
78
+
79
+ true
80
+ end
81
+
82
+ reporter.info
83
+ reporter.info("Tests ran in #{"%0.6f" % time}s. Finished at #{Time.now.strftime('%Y-%m-%d %l:%M:%S %p')}.")
84
+ reporter.info
85
+ end
86
+
87
+ # Preloads our autocomplete cache
88
+ def preload_test_ids
89
+ result = run_in_fork do
90
+ paths = []
91
+ config.file_sets["all"].each do |glob|
92
+ paths.concat(Dir.glob(glob))
93
+ end
94
+
95
+ paths.each { |path| require File.expand_path(path) }
96
+
97
+ require File.join(File.dirname(__FILE__), "minitest_handler")
98
+ MiniTestHandler.preload_elements
99
+ end
100
+
101
+ config.cache_test_ids(result) unless result.nil?
102
+ end
103
+
104
+ # Runs all tests against the match patterns given
105
+ def run_all_tests(match_patterns = nil)
106
+ run_tests(config.file_sets["all"], match_patterns)
107
+ end
108
+
109
+ # Runs a file set out of the config
110
+ def run_file_set(set)
111
+ run_tests(config.file_sets[set], nil)
112
+ end
113
+
114
+ def run_failed
115
+ if last_result.failures.empty?
116
+ reporter.info("No tests failed in your last run, or you haven't run any tests in this session yet.")
117
+ reporter.info
118
+ else
119
+ run_tests(config.file_sets["all"], last_result.failures)
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,113 @@
1
+ # Manages all output for TConsole
2
+ module TConsole
3
+ class Reporter
4
+ attr_accessor :config
5
+
6
+ def initialize(config)
7
+ self.config = config
8
+ end
9
+
10
+ # Public: Ouptuts an informative message.
11
+ def info(message = "")
12
+ puts message
13
+ end
14
+
15
+ # Public: Outputs a positive informative message.
16
+ # Colors it green if the console supports it.
17
+ def exclaim(message = "")
18
+ puts ::Term::ANSIColor.green(message)
19
+ end
20
+
21
+ # Public: Outputs a warning message.
22
+ def warn(message = "")
23
+ puts ::Term::ANSIColor.yellow(message)
24
+ end
25
+
26
+ # Public: Outputs an error message.
27
+ def error(message = "")
28
+ puts ::Term::ANSIColor.red(message)
29
+ end
30
+
31
+
32
+ # Public: Outputs a trace message, when needed.
33
+ def trace(message = "")
34
+ puts "[tconsole trace] #{message}" if config.trace?
35
+ end
36
+
37
+ # Public: Prints a backtrace out.
38
+ def trace_backtrace(exception)
39
+ trace("===========")
40
+ trace(exception.backtrace.join("\n"))
41
+ trace("===========")
42
+ end
43
+
44
+ # Public: Outputs a timing for the timings command, using the proper
45
+ # color logic
46
+ def timing(timing, test_id)
47
+ output = "#{"%0.6f" % timing[:time]}s #{timing[:name]}"
48
+ if timing[:time] > 1
49
+ print ::Term::ANSIColor.red, output, ::Term::ANSIColor.reset
50
+ else
51
+ print ::Term::ANSIColor.green, output, ::Term::ANSIColor.reset
52
+ end
53
+
54
+ print ::Term::ANSIColor.magenta, " #{last_result}", ::Term::ANSIColor.reset, "\n"
55
+ end
56
+
57
+ # Public: Prints a list of available commands
58
+ def help_message
59
+ puts
60
+ puts "Available commands:"
61
+ puts
62
+ puts "reload # Reload your Rails environment"
63
+ puts "set [variable] [value] # Sets a runtime variable (see below for details)"
64
+ puts "exit # Exit the console"
65
+ puts "!failed # Runs the last set of failing tests"
66
+ puts "!timings [limit] # Lists the timings for the last test run, sorted."
67
+ puts "[filename] [test_pattern] # Run the tests contained in the given file"
68
+ puts ".[command] # Executes the given command in a subshell"
69
+ puts
70
+ puts "Running file sets"
71
+ puts
72
+ puts "File sets are sets of files that are typically run together. For example,"
73
+ puts "in Rails projects it's common to run `rake test:units` to run all of the"
74
+ puts "tests under the units directory."
75
+ puts
76
+ puts "Available file sets:"
77
+
78
+ config.file_sets.each do |set, paths|
79
+ puts set
80
+ end
81
+
82
+ puts
83
+ puts "Working with test patterns:"
84
+ puts
85
+ puts "All of the test execution commands include an optional test_pattern argument. A"
86
+ puts "test pattern can be given to filter the executed tests to only those tests whose"
87
+ puts "name matches the pattern given. This is especially useful when rerunning a failing"
88
+ puts "test."
89
+ puts
90
+ puts "Runtime Variables"
91
+ puts
92
+ puts "You can set runtime variables with the set command. This helps out with changing"
93
+ puts "features that you may want to change at runtime. At present, the following"
94
+ puts "runtime variables are available:"
95
+ puts
96
+ puts "fast # Turns on fail fast mode. Values: on, off"
97
+ puts
98
+
99
+ end
100
+
101
+ # Public: Outputs the tconsole welcome message
102
+ def welcome_message
103
+ info
104
+ info("Welcome to #{config.app} (v#{TConsole::VERSION}). Type 'help' for help or 'exit' to quit.")
105
+ end
106
+
107
+ # Public: Outputs the tconsole exit message
108
+ def exit_message
109
+ info
110
+ info("Exiting. Bye!")
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,108 @@
1
+ module TConsole
2
+ class RSpecServer < Server
3
+
4
+ # Loads the files that match globs and then executes tests against them. Limit tests
5
+ # with class names, method names, and test ids using match_patterns.
6
+ def run_tests(globs, match_patterns, message = "Running tests...")
7
+ time = Benchmark.realtime do
8
+ reporter.info(message)
9
+ reporter.info
10
+
11
+ paths = []
12
+ globs.each do |glob|
13
+ paths.concat(Dir.glob(glob))
14
+ end
15
+
16
+ if paths.length == 0
17
+ reporter.warn("No test files match your requested test set: #{globs.join(",")}.")
18
+ reporter.warn("Skipping execution.")
19
+ return nil
20
+ end
21
+
22
+ self.last_result = run_in_fork do
23
+
24
+ # Make sure rspec is loaded up
25
+ require 'rspec'
26
+
27
+ paths.each do |path|
28
+ reporter.trace("Requested path `#{path}` doesn't exist.") unless File.exist?(path)
29
+ require File.expand_path(path)
30
+ end
31
+
32
+ reporter.trace("Running before_test_run callback")
33
+ config.before_test_run!
34
+ reporter.trace("Completed before_test_run callback")
35
+
36
+ result = nil
37
+ if defined?(::RSpec)
38
+ reporter.trace("Detected rspec.")
39
+
40
+ reporter.trace("Running tests.")
41
+
42
+ # Handle trapping interrupts
43
+ trap("SIGINT") do
44
+ reporter.warn
45
+ reporter.warn("Trapped interrupt. Halting tests.")
46
+ end
47
+
48
+ # Actually run the tests!
49
+ configuration = RSpec::configuration
50
+ world = RSpec::world
51
+ options = RSpec::Core::ConfigurationOptions.new([])
52
+ options.parse_options
53
+
54
+ configuration.error_stream = STDERR
55
+ configuration.output_stream = STDOUT
56
+
57
+ options.configure(configuration)
58
+
59
+ configuration.files_to_run = paths
60
+
61
+ configuration.reporter.report(world.example_count, configuration.randomize? ? configuration.seed : nil) do |reporter|
62
+ begin
63
+ configuration.run_hook(:before, :suite)
64
+ world.example_groups.ordered.map {|g| g.run(reporter)}.all? ? 0 : configuration.failure_exit_code
65
+ ensure
66
+ configuration.run_hook(:after, :suite)
67
+ end
68
+ end
69
+
70
+ # Patch RSpec to disable autorun
71
+ ::RSpec::Core::Runner.class_eval do
72
+ def self.run(args = [], err=$stderr, out=$stdout)
73
+ # do nothing
74
+ end
75
+ end
76
+
77
+ reporter.trace("Finished running tests.")
78
+ end
79
+
80
+ nil
81
+ end
82
+
83
+ if self.last_result == nil
84
+ # Just in case anything crazy goes down with marshalling
85
+ self.last_result = TConsole::TestResult.new
86
+ end
87
+
88
+ config.cache_test_ids(self.last_result)
89
+
90
+ true
91
+ end
92
+
93
+ reporter.info
94
+ reporter.info("Tests ran in #{"%0.6f" % time}s. Finished at #{Time.now.strftime('%Y-%m-%d %l:%M:%S %p')}.")
95
+ reporter.info
96
+ end
97
+
98
+ # Runs all tests against the match patterns given
99
+ def run_all_tests(match_patterns = nil)
100
+ run_tests(config.file_sets["all"], match_patterns)
101
+ end
102
+
103
+ # Runs a file set out of the config
104
+ def run_file_set(set)
105
+ run_tests(config.file_sets[set], nil)
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,139 @@
1
+ module TConsole
2
+ class Runner
3
+
4
+ attr_accessor :mode, :config, :reporter, :console, :stty_save
5
+
6
+ # Public: Sets up the new runner's config.
7
+ def initialize(mode, argv = [])
8
+ self.mode = mode
9
+
10
+ # try to load the default configs
11
+ Config.load_config(File.join(Dir.home, ".#{Config.app(mode)}"))
12
+ Config.load_config(File.join(Dir.pwd, ".#{Config.app(mode)}"))
13
+ self.config = Config.configure(mode, argv)
14
+ self.reporter = Reporter.new(config)
15
+ end
16
+
17
+ # Spawns a new environment. Looks at the results of the environment to determine
18
+ # whether to stop or keep running
19
+ def run
20
+ prepare_process
21
+ reporter.welcome_message
22
+ exit(1) if print_config_errors
23
+
24
+ # Set up our console input handling and history
25
+ console = Console.new(config, reporter)
26
+
27
+ # Start the server
28
+ while console_run_loop(console)
29
+ # just need to run the loop
30
+ end
31
+
32
+ console.store_history
33
+
34
+ cleanup_process
35
+ end
36
+
37
+ # Internal: Set up the process and console.
38
+ def prepare_process
39
+ self.stty_save = `stty -g`.chomp
40
+
41
+ trap("SIGINT", "IGNORE")
42
+ trap("SIGTSTP", "IGNORE")
43
+ end
44
+
45
+ # Internal: Cleans up the process at the end of execution.
46
+ def cleanup_process
47
+ reporter.exit_message
48
+ system("stty", self.stty_save);
49
+ end
50
+
51
+ # Internal: Prints config errors, if there are any.
52
+ #
53
+ # Returns true if there were errors, false otherwise.
54
+ def print_config_errors
55
+ config_errors = @config.validation_errors
56
+ if config_errors.length > 0
57
+ reporter.error
58
+ reporter.error(config_errors.first)
59
+ true
60
+ else
61
+ false
62
+ end
63
+ end
64
+
65
+ # Internal: Environment reload run loop.
66
+ #
67
+ # This run loop handles spawning a new tconsole environment - it's basically
68
+ # just there to handle reloads. Also calls out to the input loop for the
69
+ # console.
70
+ #
71
+ # Returns false if tconsole needs to stop, true otherwise.
72
+ def console_run_loop(console)
73
+ pipe_server = ChattyProc::PipeServer.new
74
+
75
+ reporter.trace("Forking test server.")
76
+ server_pid = fork do
77
+ server_run_loop(pipe_server)
78
+ end
79
+
80
+ pipe_server.caller!
81
+ unless load_environment(pipe_server)
82
+ pipe_server.write({:action => "exit"})
83
+ return false
84
+ end
85
+
86
+ continue = console.read_and_execute(pipe_server)
87
+ reporter.trace("Console read loop returned - continue: #{continue}")
88
+
89
+ Process.waitall
90
+
91
+ continue
92
+ end
93
+
94
+ # Internal: Asks the server to load the environment.
95
+ #
96
+ # Returns true if the environment was loaded, or false otherwise.
97
+ def load_environment(pipe_server)
98
+ reporter.trace("Attempting to load environment.")
99
+ pipe_server.write({:action => "load_environment"})
100
+
101
+ if pipe_server.read
102
+ reporter.trace("Environment loaded successfully.")
103
+ true
104
+ else
105
+ reporter.error("Couldn't load the test environment. Exiting.")
106
+ false
107
+ end
108
+ end
109
+
110
+ # Internal: Run loop for the server.
111
+ def server_run_loop(pipe_server)
112
+ pipe_server.callee!
113
+
114
+ if mode == :minitest
115
+ server = MinitestServer.new(config, reporter)
116
+ elsif mode == :rspec
117
+ server = RSpecServer.new(config, reporter)
118
+ else
119
+ reporter.error
120
+ reporter.error("The given test mode isn't supported.")
121
+ reporter.error
122
+ exit
123
+ end
124
+
125
+ while message = pipe_server.read
126
+ reporter.trace("Server Received Message: #{message[:action]}")
127
+ begin
128
+ result = server.handle(message)
129
+ pipe_server.write(result)
130
+ rescue => e
131
+ reporter.error
132
+ reporter.error("An error occured: #{e.message}")
133
+ reporter.trace_backtrace(e)
134
+ pipe_server.write(nil)
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end