tconsole-rails4 2.2.0
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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.gitmodules +3 -0
- data/Gemfile +8 -0
- data/README.md +293 -0
- data/Rakefile +1 -0
- data/bin/rconsole +5 -0
- data/bin/tconsole +5 -0
- data/cibuild +4 -0
- data/lib/tconsole.rb +18 -0
- data/lib/tconsole/config.rb +251 -0
- data/lib/tconsole/console.rb +150 -0
- data/lib/tconsole/minitest_handler.rb +93 -0
- data/lib/tconsole/minitest_reporter.rb +207 -0
- data/lib/tconsole/minitest_server.rb +123 -0
- data/lib/tconsole/reporter.rb +113 -0
- data/lib/tconsole/rspec_server.rb +108 -0
- data/lib/tconsole/runner.rb +139 -0
- data/lib/tconsole/server.rb +174 -0
- data/lib/tconsole/test_result.rb +65 -0
- data/lib/tconsole/util.rb +33 -0
- data/lib/tconsole/version.rb +3 -0
- data/spec/config_spec.rb +94 -0
- data/spec/runner_spec.rb +38 -0
- data/spec/sample_config +3 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/util_spec.rb +26 -0
- data/tconsole.gemspec +27 -0
- data/test/lib/tconsole/config_test.rb +15 -0
- data/test/lib/tconsole_test.rb +6 -0
- data/test/test_helper.rb +8 -0
- metadata +121 -0
@@ -0,0 +1,174 @@
|
|
1
|
+
module TConsole
|
2
|
+
class Server
|
3
|
+
attr_accessor :config, :reporter, :last_result
|
4
|
+
|
5
|
+
def initialize(config, reporter)
|
6
|
+
self.config = config
|
7
|
+
self.reporter = reporter
|
8
|
+
self.last_result = TConsole::TestResult.new
|
9
|
+
end
|
10
|
+
|
11
|
+
# Internal: Outputs a message that a feature hasn't been implemented
|
12
|
+
def not_implemented
|
13
|
+
reporter.error("This feature hasn't been implemented yet.")
|
14
|
+
end
|
15
|
+
|
16
|
+
# Processes the message sent from the console
|
17
|
+
def handle(message)
|
18
|
+
action = message[:action]
|
19
|
+
args = message[:args]
|
20
|
+
|
21
|
+
send(action, *args)
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop
|
25
|
+
Kernel.exit(0)
|
26
|
+
end
|
27
|
+
|
28
|
+
def load_environment
|
29
|
+
result = false
|
30
|
+
|
31
|
+
time = Benchmark.realtime do
|
32
|
+
reporter.info
|
33
|
+
reporter.info("Loading environment...")
|
34
|
+
|
35
|
+
begin
|
36
|
+
# Append our include paths
|
37
|
+
config.include_paths.each do |include_path|
|
38
|
+
$:.unshift(include_path)
|
39
|
+
end
|
40
|
+
|
41
|
+
config.before_load!
|
42
|
+
|
43
|
+
# Load our preload files
|
44
|
+
config.preload_paths.each do |preload_path|
|
45
|
+
require preload_path
|
46
|
+
end
|
47
|
+
|
48
|
+
config.after_load!
|
49
|
+
|
50
|
+
result = true
|
51
|
+
rescue Exception => e
|
52
|
+
reporter.error("Error - Loading your environment failed: #{e.message}")
|
53
|
+
reporter.trace_backtrace(e)
|
54
|
+
return false
|
55
|
+
end
|
56
|
+
|
57
|
+
preload_test_ids
|
58
|
+
end
|
59
|
+
|
60
|
+
reporter.info("Environment loaded in #{"%0.6f" % time}s.")
|
61
|
+
reporter.info
|
62
|
+
|
63
|
+
result
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns an array of possible completions based on the available element data
|
67
|
+
def autocomplete(text)
|
68
|
+
config.cached_elements.keys.grep(/^#{Regexp.escape(text)}/)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Runs the given code in a block and returns the result of the code in the block.
|
72
|
+
# The block's result needs to be marshallable. Otherwise, nil is returned.
|
73
|
+
def run_in_fork(&block)
|
74
|
+
# Pipe for communicating with child so we can get its results back
|
75
|
+
read, write = IO.pipe
|
76
|
+
|
77
|
+
pid = fork do
|
78
|
+
read.close
|
79
|
+
|
80
|
+
result = block.call
|
81
|
+
|
82
|
+
write.puts([Marshal.dump(result)].pack("m0"))
|
83
|
+
end
|
84
|
+
|
85
|
+
write.close
|
86
|
+
response = read.read
|
87
|
+
read.close
|
88
|
+
Process.wait(pid)
|
89
|
+
|
90
|
+
begin
|
91
|
+
reporter.trace("Reading result from fork.")
|
92
|
+
Marshal.load(response.unpack("m")[0])
|
93
|
+
rescue => e
|
94
|
+
reporter.trace("Problem reading result from fork. Returning nil.")
|
95
|
+
reporter.trace(e.message)
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Preloads our autocomplete cache
|
101
|
+
def preload_test_ids
|
102
|
+
# Does nothing by default
|
103
|
+
end
|
104
|
+
|
105
|
+
# Runs all tests against the match patterns given
|
106
|
+
def run_all_tests(match_patterns = nil)
|
107
|
+
reporter.error("This feature hasn't been implemented yet.")
|
108
|
+
end
|
109
|
+
|
110
|
+
# Runs a file set out of the config
|
111
|
+
def run_file_set(set)
|
112
|
+
reporter.error("This feature hasn't been implemented yet.")
|
113
|
+
end
|
114
|
+
|
115
|
+
def run_failed
|
116
|
+
reporter.error("This feature hasn't been implemented yet.")
|
117
|
+
end
|
118
|
+
|
119
|
+
def run_info
|
120
|
+
reporter.info("Defined Constants:")
|
121
|
+
reporter.info(Module.constants.sort.join("\n"))
|
122
|
+
reporter.info
|
123
|
+
reporter.info("Configuration:")
|
124
|
+
reporter.info("Mode: #{config.mode}")
|
125
|
+
reporter.info()
|
126
|
+
reporter.info
|
127
|
+
end
|
128
|
+
|
129
|
+
def show_performance(limit = nil)
|
130
|
+
|
131
|
+
limit = limit.to_i
|
132
|
+
limit = last_result.timings.length if limit == 0
|
133
|
+
|
134
|
+
sorted_timings = last_result.timings.sort_by { |timing| timing[:time] }
|
135
|
+
|
136
|
+
reporter.info
|
137
|
+
reporter.info("Timings from last run:")
|
138
|
+
reporter.info
|
139
|
+
|
140
|
+
if sorted_timings.length == 0
|
141
|
+
reporter.error("No timing data available. Be sure you've run some tests.")
|
142
|
+
else
|
143
|
+
sorted_timings.reverse[0, limit].each do |timing|
|
144
|
+
reporter.timing(timing, last_result.elements[timing[:name]])
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
reporter.info
|
149
|
+
end
|
150
|
+
|
151
|
+
def set(key, value)
|
152
|
+
if key == "fast"
|
153
|
+
if !value.nil?
|
154
|
+
value.downcase!
|
155
|
+
if ["on", "true", "yes"].include?(value)
|
156
|
+
config.fail_fast = true
|
157
|
+
else
|
158
|
+
config.fail_fast = false
|
159
|
+
end
|
160
|
+
|
161
|
+
reporter.exclaim("Fail Fast is now #{config.fail_fast ? "on" : "off"}")
|
162
|
+
reporter.exclaim
|
163
|
+
else
|
164
|
+
reporter.exclaim("Fail fast is currently #{config.fail_fast ? "on" : "off"}")
|
165
|
+
reporter.exclaim
|
166
|
+
end
|
167
|
+
else
|
168
|
+
reporter.warn("I don't know how to set `#{key}`.")
|
169
|
+
reporter.info("Usage: set {key} {value}")
|
170
|
+
reporter.warn
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module TConsole
|
2
|
+
class TestResult
|
3
|
+
# The number of failed tests in the last run
|
4
|
+
attr_accessor :failure_count
|
5
|
+
|
6
|
+
# The number of errors that occurred in the last run
|
7
|
+
attr_accessor :error_count
|
8
|
+
|
9
|
+
# The number of skipped tests
|
10
|
+
attr_accessor :skip_count
|
11
|
+
|
12
|
+
# Details about the failures in the last run
|
13
|
+
attr_accessor :failures
|
14
|
+
|
15
|
+
# The suites that we've run
|
16
|
+
attr_accessor :suites
|
17
|
+
|
18
|
+
# The timings for the tests we've run
|
19
|
+
attr_accessor :timings
|
20
|
+
|
21
|
+
# The element id lookup hash
|
22
|
+
attr_accessor :elements
|
23
|
+
|
24
|
+
# Test counts within various suites
|
25
|
+
attr_accessor :suite_counts
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
self.failure_count = 0
|
29
|
+
self.error_count = 0
|
30
|
+
self.skip_count = 0
|
31
|
+
self.failures = []
|
32
|
+
self.suites = {}
|
33
|
+
self.timings = []
|
34
|
+
|
35
|
+
self.suite_counts = {}
|
36
|
+
self.elements = {}
|
37
|
+
end
|
38
|
+
|
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
|
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
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_timing(suite, method, time)
|
62
|
+
self.timings << { :name => "#{suite}##{method}", :time => time }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module TConsole
|
2
|
+
class Util
|
3
|
+
# Returns [width, height] of terminal when detected, nil if not detected.
|
4
|
+
# Think of this as a simpler version of Highline's Highline::SystemExtensions.terminal_size()
|
5
|
+
#
|
6
|
+
# This is a copy of HIRB's terminal size detection code: https://github.com/cldwalker/hirb/blob/master/lib/hirb/util.rb
|
7
|
+
def self.detect_terminal_size
|
8
|
+
if (ENV['COLUMNS'] =~ /^\d+$/) && (ENV['LINES'] =~ /^\d+$/)
|
9
|
+
[ENV['COLUMNS'].to_i, ENV['LINES'].to_i]
|
10
|
+
elsif (RUBY_PLATFORM =~ /java/ || (!STDIN.tty? && ENV['TERM'])) && command_exists?('tput')
|
11
|
+
[`tput cols`.to_i, `tput lines`.to_i]
|
12
|
+
elsif STDIN.tty? && command_exists?('stty')
|
13
|
+
`stty size`.scan(/\d+/).map { |s| s.to_i }.reverse
|
14
|
+
else
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
rescue
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# Public: Filters a backtrace to exclude things that happened in TConsole
|
22
|
+
#
|
23
|
+
# backtrace: The backtrace array that we're filtering.
|
24
|
+
#
|
25
|
+
# Returns the updated backtrace.
|
26
|
+
def self.filter_backtrace(backtrace)
|
27
|
+
tconsole_path = File.expand_path(File.join(File.dirname(__FILE__), "..", "..")) + File::SEPARATOR
|
28
|
+
backtrace.select do |item|
|
29
|
+
!item.start_with?(tconsole_path)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TConsole::Config do
|
4
|
+
context "a Config without arguments" do
|
5
|
+
before do
|
6
|
+
@config = TConsole::Config.new(:minitest, [])
|
7
|
+
@config.test_dir = "./spec/fixtures/minitest"
|
8
|
+
end
|
9
|
+
|
10
|
+
context "when configured test directory doesn't exist" do
|
11
|
+
before do
|
12
|
+
@config.test_dir = "./monkey_business"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "sets a validation error" do
|
16
|
+
expect(@config.validation_errors[0]).to eq("Couldn't find test directory `./monkey_business`. Exiting.")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when the configuration doesn't include an all file set" do
|
21
|
+
before do
|
22
|
+
@config.file_sets = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
it "sets a validation error" do
|
26
|
+
expect(@config.validation_errors[0]).to eq("No `all` file set is defined in your configuration. Exiting.")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "a Config with the trace argument" do
|
32
|
+
before do
|
33
|
+
@config = TConsole::Config.new(:minitest, Shellwords.shellwords("--trace"))
|
34
|
+
end
|
35
|
+
|
36
|
+
it "has tracing enabled" do
|
37
|
+
expect(@config.trace_execution).to be_true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "a Config with the once argument" do
|
42
|
+
before do
|
43
|
+
@config = TConsole::Config.new(:minitest, Shellwords.shellwords("--once all"))
|
44
|
+
end
|
45
|
+
|
46
|
+
it "has run once enabled" do
|
47
|
+
expect(@config.once).to be_true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "a Config with remaining arguments" do
|
52
|
+
before do
|
53
|
+
@config = TConsole::Config.new(:minitest, Shellwords.shellwords("--trace set fast on"))
|
54
|
+
end
|
55
|
+
|
56
|
+
it "sets remaining args as first command" do
|
57
|
+
expect(@config.run_command).to eq("set fast on")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe ".run" do
|
62
|
+
before do
|
63
|
+
TConsole::Config.run do |config|
|
64
|
+
config.test_dir = "./awesome_sauce"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
after do
|
69
|
+
TConsole::Config.clear_loaded_configs
|
70
|
+
end
|
71
|
+
|
72
|
+
it "saves the run proc" do
|
73
|
+
loaded_configs = TConsole::Config.instance_variable_get(:@loaded_configs)
|
74
|
+
expect(loaded_configs.length).to eq(1)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "runs loaded configs from first to last" do
|
78
|
+
TConsole::Config.run do |config|
|
79
|
+
config.test_dir = "./awesomer_sauce"
|
80
|
+
end
|
81
|
+
|
82
|
+
config = TConsole::Config.configure(:minitest)
|
83
|
+
expect(config.test_dir).to eq("./awesomer_sauce")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe ".load_config" do
|
88
|
+
it "loads configs" do
|
89
|
+
TConsole::Config.load_config(File.join(File.dirname(__FILE__), "sample_config"))
|
90
|
+
loaded_configs = TConsole::Config.instance_variable_get(:@loaded_configs)
|
91
|
+
expect(loaded_configs.length).to eq(1)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/spec/runner_spec.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe TConsole::Runner do
|
4
|
+
before do
|
5
|
+
@runner = TConsole::Runner.new(:minitest)
|
6
|
+
@ps = ChattyProc::PipeServer.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#load_environment" do
|
10
|
+
before do
|
11
|
+
@ps.stub(:write) { }
|
12
|
+
end
|
13
|
+
|
14
|
+
it "returns false if the environment load call fails" do
|
15
|
+
@ps.stub(:read) { false }
|
16
|
+
expect(@runner.load_environment(@ps)).to be_false
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns true if the environment load call succeeds" do
|
20
|
+
@ps.stub(:read) { true }
|
21
|
+
expect(@runner.load_environment(@ps)).to be_true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#console_run_loop" do
|
26
|
+
before do
|
27
|
+
@config = TConsole::Config.new(:minitest)
|
28
|
+
@reporter = TConsole::Reporter.new(@config)
|
29
|
+
@console = TConsole::Console.new(@config, @reporter)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "returns false when loading the environment fails" do
|
33
|
+
@runner.stub(:load_environment) { false }
|
34
|
+
|
35
|
+
expect(@runner.console_run_loop(@console)).to be_false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/spec/sample_config
ADDED
data/spec/spec_helper.rb
ADDED
data/spec/util_spec.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "TConsole::Util" do
|
4
|
+
describe ".filter_backtrace" do
|
5
|
+
before do
|
6
|
+
@non_tconsole_path = "/Users/alan/Projects/commondream/tconsole-test/test/functional/posts_controller_test.rb:16:in `block in <class:PostsControllerTest>'"
|
7
|
+
@tconsole_path = "#{File.expand_path(File.join(File.dirname(__FILE__), ".."))}/posts_controller_test.rb:16:in `block in <class:PostsControllerTest>'"
|
8
|
+
|
9
|
+
@backtrace = [
|
10
|
+
@non_tconsole_path,
|
11
|
+
@tconsole_path
|
12
|
+
]
|
13
|
+
|
14
|
+
@filtered_backtrace = TConsole::Util.filter_backtrace(@backtrace)
|
15
|
+
end
|
16
|
+
|
17
|
+
context "removes tconsole paths" do
|
18
|
+
it { expect(@filtered_backtrace.length).to eq(1) }
|
19
|
+
it { expect(@filtered_backtrace).to_not include(@tconsole_path) }
|
20
|
+
end
|
21
|
+
|
22
|
+
it "doesn't remove non-tconsole paths" do
|
23
|
+
expect(@filtered_backtrace).to include(@non_tconsole_path)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|