tldr 0.6.0 → 0.6.2
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 +4 -4
- data/CHANGELOG.md +10 -0
- data/Rakefile +1 -0
- data/lib/tldr/{parallelizer.rb → executor.rb} +9 -15
- data/lib/tldr/planner.rb +16 -4
- data/lib/tldr/reporters/default.rb +2 -2
- data/lib/tldr/runner.rb +35 -31
- data/lib/tldr/strategizer.rb +22 -7
- data/lib/tldr/value/plan.rb +1 -1
- data/lib/tldr/value/test.rb +3 -3
- data/lib/tldr/version.rb +1 -1
- data/lib/tldr.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82e76ebc309cbf643c22244a1674aa3a7ae32578006ce05fac262aec15292bec
|
4
|
+
data.tar.gz: 99610ebabba0d069f3618f6fa7cf79793c44491c4764463283e304fe329c7247
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de39822a1208f86b69a45ac1185d2c6de22462282a6fa2f59054e84bfa55b135f61279ae3b9be2f61463557a2a04516397bd02083a6c2c8a26c8e627875a44d1
|
7
|
+
data.tar.gz: ae0c0ed4ec84f2969a0b223a668351ce475536121fb59e2b56a4fbd7be18be844d5fec3aaf3d5ebfd5cf37ddb6a0a02afeef1f0e1f2f975c7d2796d322ab0ccb
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## [0.6.2]
|
2
|
+
|
3
|
+
* Since TLDR runs fine on 3.1, reduce the gem requirement
|
4
|
+
|
5
|
+
## [0.6.1]
|
6
|
+
|
7
|
+
* Correctly report the number of test classes that run
|
8
|
+
* Finish planning the test run before starting the clock on the timer (that's
|
9
|
+
a millisecond or two in savings!)
|
10
|
+
|
1
11
|
## [0.6.0]
|
2
12
|
|
3
13
|
* When `dont_run_these_in_parallel!` and `run_these_together!` are called from a
|
data/Rakefile
CHANGED
@@ -1,26 +1,20 @@
|
|
1
1
|
class TLDR
|
2
|
-
class
|
2
|
+
class Executor
|
3
3
|
def initialize
|
4
|
-
@strategizer = Strategizer.new
|
5
4
|
@thread_pool = Concurrent::ThreadPoolExecutor.new(
|
6
5
|
name: "tldr",
|
7
6
|
auto_terminate: true
|
8
7
|
)
|
9
8
|
end
|
10
9
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
)
|
20
|
-
|
21
|
-
run_in_sequence(strategy.prepend_thread_unsafe_tests, &blk) +
|
22
|
-
run_in_parallel(strategy.parallel_tests_and_groups, &blk) +
|
23
|
-
run_in_sequence(strategy.thread_unsafe_tests, &blk)
|
10
|
+
def execute plan, &blk
|
11
|
+
if plan.strategy.parallel?
|
12
|
+
run_in_sequence(plan.strategy.prepend_sequential_tests, &blk) +
|
13
|
+
run_in_parallel(plan.strategy.parallel_tests_and_groups, &blk) +
|
14
|
+
run_in_sequence(plan.strategy.append_sequential_tests, &blk)
|
15
|
+
else
|
16
|
+
run_in_sequence(plan.tests, &blk)
|
17
|
+
end
|
24
18
|
end
|
25
19
|
|
26
20
|
private
|
data/lib/tldr/planner.rb
CHANGED
@@ -2,6 +2,10 @@ require "pathname"
|
|
2
2
|
|
3
3
|
class TLDR
|
4
4
|
class Planner
|
5
|
+
def initialize
|
6
|
+
@strategizer = Strategizer.new
|
7
|
+
end
|
8
|
+
|
5
9
|
def plan config
|
6
10
|
$VERBOSE = config.warnings
|
7
11
|
search_locations = PathUtil.expand_paths config.paths, globs: false
|
@@ -12,8 +16,7 @@ class TLDR
|
|
12
16
|
|
13
17
|
tests = gather_tests
|
14
18
|
config.update_after_gathering_tests! tests
|
15
|
-
|
16
|
-
Plan.new prepend(
|
19
|
+
tests_to_run = prepend(
|
17
20
|
shuffle(
|
18
21
|
exclude_by_path(
|
19
22
|
exclude_by_name(
|
@@ -29,6 +32,15 @@ class TLDR
|
|
29
32
|
),
|
30
33
|
config
|
31
34
|
)
|
35
|
+
|
36
|
+
strategy = @strategizer.strategize(
|
37
|
+
tests_to_run,
|
38
|
+
GROUPED_TESTS,
|
39
|
+
THREAD_UNSAFE_TESTS,
|
40
|
+
config
|
41
|
+
)
|
42
|
+
|
43
|
+
Plan.new tests_to_run, strategy
|
32
44
|
end
|
33
45
|
|
34
46
|
private
|
@@ -68,7 +80,7 @@ class TLDR
|
|
68
80
|
|
69
81
|
tests.reject { |test|
|
70
82
|
name_excludes.any? { |filter|
|
71
|
-
filter === test.
|
83
|
+
filter === test.method_name.to_s || filter === "#{test.test_class}##{test.method_name}"
|
72
84
|
}
|
73
85
|
}
|
74
86
|
end
|
@@ -89,7 +101,7 @@ class TLDR
|
|
89
101
|
|
90
102
|
tests.select { |test|
|
91
103
|
name_filters.any? { |filter|
|
92
|
-
filter === test.
|
104
|
+
filter === test.method_name.to_s || filter === "#{test.test_class}##{test.method_name}"
|
93
105
|
}
|
94
106
|
}
|
95
107
|
end
|
@@ -87,7 +87,7 @@ class TLDR
|
|
87
87
|
@out.print "Finished in #{duration}ms."
|
88
88
|
|
89
89
|
@out.print "\n\n"
|
90
|
-
class_count = test_results.uniq { |result| result.test.
|
90
|
+
class_count = test_results.uniq { |result| result.test.test_class }.size
|
91
91
|
test_count = test_results.size
|
92
92
|
@out.print [
|
93
93
|
plural(class_count, "test class", "test classes"),
|
@@ -127,7 +127,7 @@ class TLDR
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def describe test, location = test.location
|
130
|
-
"#{test.
|
130
|
+
"#{test.test_class}##{test.method_name} [#{location.locator}]"
|
131
131
|
end
|
132
132
|
|
133
133
|
def plural count, singular, plural = "#{singular}s"
|
data/lib/tldr/runner.rb
CHANGED
@@ -3,7 +3,7 @@ require "irb"
|
|
3
3
|
class TLDR
|
4
4
|
class Runner
|
5
5
|
def initialize
|
6
|
-
@
|
6
|
+
@executor = Executor.new
|
7
7
|
@wip = Concurrent::Array.new
|
8
8
|
@results = Concurrent::Array.new
|
9
9
|
@run_aborted = Concurrent::AtomicBoolean.new false
|
@@ -12,8 +12,8 @@ class TLDR
|
|
12
12
|
def run config, plan
|
13
13
|
@wip.clear
|
14
14
|
@results.clear
|
15
|
-
reporter = config.reporter.new
|
16
|
-
reporter.before_suite
|
15
|
+
reporter = config.reporter.new(config)
|
16
|
+
reporter.before_suite(plan.tests)
|
17
17
|
|
18
18
|
time_bomb = Thread.new {
|
19
19
|
explode = proc do
|
@@ -34,34 +34,8 @@ class TLDR
|
|
34
34
|
end
|
35
35
|
}
|
36
36
|
|
37
|
-
results = @
|
38
|
-
|
39
|
-
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :microsecond)
|
40
|
-
wip_test = WIPTest.new test, start_time
|
41
|
-
@wip << wip_test
|
42
|
-
runtime = time_it(start_time) do
|
43
|
-
instance = test.klass.new
|
44
|
-
instance.setup if instance.respond_to? :setup
|
45
|
-
if instance.respond_to? :around
|
46
|
-
did_run = false
|
47
|
-
instance.around {
|
48
|
-
did_run = true
|
49
|
-
instance.send(test.method)
|
50
|
-
}
|
51
|
-
raise Error, "#{test.klass}#around failed to yield or call the passed test block" unless did_run
|
52
|
-
else
|
53
|
-
instance.send(test.method)
|
54
|
-
end
|
55
|
-
instance.teardown if instance.respond_to? :teardown
|
56
|
-
rescue Skip, Failure, StandardError => e
|
57
|
-
end
|
58
|
-
TestResult.new(test, e, runtime).tap do |result|
|
59
|
-
next if @run_aborted.true?
|
60
|
-
@results << result
|
61
|
-
@wip.delete wip_test
|
62
|
-
reporter.after_test result
|
63
|
-
fail_fast reporter, plan, result if result.failing? && config.fail_fast
|
64
|
-
end
|
37
|
+
results = @executor.execute(plan) { |test|
|
38
|
+
run_test(test, config, plan, reporter)
|
65
39
|
}.tap do
|
66
40
|
time_bomb.kill
|
67
41
|
end
|
@@ -74,6 +48,36 @@ class TLDR
|
|
74
48
|
|
75
49
|
private
|
76
50
|
|
51
|
+
def run_test test, config, plan, reporter
|
52
|
+
e = nil
|
53
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :microsecond)
|
54
|
+
wip_test = WIPTest.new test, start_time
|
55
|
+
@wip << wip_test
|
56
|
+
runtime = time_it(start_time) do
|
57
|
+
instance = test.test_class.new
|
58
|
+
instance.setup if instance.respond_to? :setup
|
59
|
+
if instance.respond_to? :around
|
60
|
+
did_run = false
|
61
|
+
instance.around {
|
62
|
+
did_run = true
|
63
|
+
instance.send(test.method_name)
|
64
|
+
}
|
65
|
+
raise Error, "#{test.test_class}#around failed to yield or call the passed test block" unless did_run
|
66
|
+
else
|
67
|
+
instance.send(test.method_name)
|
68
|
+
end
|
69
|
+
instance.teardown if instance.respond_to? :teardown
|
70
|
+
rescue Skip, Failure, StandardError => e
|
71
|
+
end
|
72
|
+
TestResult.new(test, e, runtime).tap do |result|
|
73
|
+
next if @run_aborted.true?
|
74
|
+
@results << result
|
75
|
+
@wip.delete wip_test
|
76
|
+
reporter.after_test result
|
77
|
+
fail_fast reporter, plan, result if result.failing? && config.fail_fast
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
77
81
|
def fail_fast reporter, plan, fast_failed_result
|
78
82
|
unless @run_aborted.true?
|
79
83
|
@run_aborted.make_true
|
data/lib/tldr/strategizer.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
class TLDR
|
2
2
|
class Strategizer
|
3
|
-
Strategy = Struct.new :
|
3
|
+
Strategy = Struct.new :parallel?, :prepend_sequential_tests,
|
4
|
+
:parallel_tests_and_groups, :append_sequential_tests,
|
5
|
+
keyword_init: true
|
4
6
|
|
5
7
|
# Combine all discovered test methods with any methods grouped by run_these_together!
|
6
8
|
#
|
@@ -8,13 +10,15 @@ class TLDR
|
|
8
10
|
# - Map over tests to build out groups in order to retain shuffle order
|
9
11
|
# (group will run in position of first test in the group)
|
10
12
|
# - If a test is in multiple groups, only run it once
|
11
|
-
def strategize all_tests, run_these_together_groups, thread_unsafe_test_groups,
|
13
|
+
def strategize all_tests, run_these_together_groups, thread_unsafe_test_groups, config
|
14
|
+
return Strategy.new(parallel?: false) if run_sequentially?(all_tests, config)
|
15
|
+
|
12
16
|
thread_unsafe_tests, thread_safe_tests = partition_unsafe(all_tests, thread_unsafe_test_groups)
|
13
|
-
|
17
|
+
prepend_sequential_tests, append_sequential_tests = partition_prepend(thread_unsafe_tests, config)
|
14
18
|
|
15
|
-
grouped_tests = prepare_run_together_groups run_these_together_groups, thread_safe_tests,
|
19
|
+
grouped_tests = prepare_run_together_groups run_these_together_groups, thread_safe_tests, append_sequential_tests
|
16
20
|
already_included_groups = []
|
17
|
-
|
21
|
+
parallel_tests_and_groups = thread_safe_tests.map { |test|
|
18
22
|
if (group = grouped_tests.find { |group| group.tests.include? test })
|
19
23
|
if already_included_groups.include? group
|
20
24
|
next
|
@@ -28,11 +32,21 @@ class TLDR
|
|
28
32
|
else
|
29
33
|
test
|
30
34
|
end
|
31
|
-
}.compact
|
35
|
+
}.compact
|
36
|
+
Strategy.new(
|
37
|
+
parallel?: true,
|
38
|
+
prepend_sequential_tests:,
|
39
|
+
parallel_tests_and_groups:,
|
40
|
+
append_sequential_tests:
|
41
|
+
)
|
32
42
|
end
|
33
43
|
|
34
44
|
private
|
35
45
|
|
46
|
+
def run_sequentially? all_tests, config
|
47
|
+
all_tests.size < 2 || !config.parallel
|
48
|
+
end
|
49
|
+
|
36
50
|
def partition_unsafe tests, thread_unsafe_test_groups
|
37
51
|
tests.partition { |test|
|
38
52
|
thread_unsafe_test_groups.any? { |group| group.tests.include? test }
|
@@ -41,7 +55,8 @@ class TLDR
|
|
41
55
|
|
42
56
|
# Sadly duplicative with Planner.rb, necessitating the extraction of PathUtil
|
43
57
|
# Suboptimal, but we do indeed need to do this work in two places ¯\_(ツ)_/¯
|
44
|
-
def partition_prepend thread_unsafe_tests,
|
58
|
+
def partition_prepend thread_unsafe_tests, config
|
59
|
+
prepend_paths = config.no_prepend ? [] : config.prepend_paths
|
45
60
|
locations = PathUtil.expand_paths prepend_paths
|
46
61
|
|
47
62
|
thread_unsafe_tests.partition { |test|
|
data/lib/tldr/value/plan.rb
CHANGED
data/lib/tldr/value/test.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
class TLDR
|
2
|
-
Test = Struct.new :
|
2
|
+
Test = Struct.new :test_class, :method_name do
|
3
3
|
attr_reader :file, :line, :location
|
4
4
|
|
5
5
|
def initialize(*args)
|
6
6
|
super
|
7
|
-
@file, @line = SorbetCompatibility.unwrap_method(
|
7
|
+
@file, @line = SorbetCompatibility.unwrap_method(test_class.instance_method(method_name)).source_location
|
8
8
|
@location = Location.new file, line
|
9
9
|
end
|
10
10
|
|
11
11
|
# Memoizing at call time, because re-parsing isn't free and isn't usually necessary
|
12
12
|
def end_line
|
13
13
|
@end_line ||= begin
|
14
|
-
test_method = SorbetCompatibility.unwrap_method
|
14
|
+
test_method = SorbetCompatibility.unwrap_method test_class.instance_method(method_name)
|
15
15
|
RubyVM::AbstractSyntaxTree.of(test_method).last_lineno
|
16
16
|
end
|
17
17
|
end
|
data/lib/tldr/version.rb
CHANGED
data/lib/tldr.rb
CHANGED
@@ -5,8 +5,8 @@ require_relative "tldr/assertions"
|
|
5
5
|
require_relative "tldr/backtrace_filter"
|
6
6
|
require_relative "tldr/class_util"
|
7
7
|
require_relative "tldr/error"
|
8
|
+
require_relative "tldr/executor"
|
8
9
|
require_relative "tldr/parallel_controls"
|
9
|
-
require_relative "tldr/parallelizer"
|
10
10
|
require_relative "tldr/path_util"
|
11
11
|
require_relative "tldr/planner"
|
12
12
|
require_relative "tldr/reporters"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tldr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Searls
|
@@ -61,8 +61,8 @@ files:
|
|
61
61
|
- lib/tldr/backtrace_filter.rb
|
62
62
|
- lib/tldr/class_util.rb
|
63
63
|
- lib/tldr/error.rb
|
64
|
+
- lib/tldr/executor.rb
|
64
65
|
- lib/tldr/parallel_controls.rb
|
65
|
-
- lib/tldr/parallelizer.rb
|
66
66
|
- lib/tldr/path_util.rb
|
67
67
|
- lib/tldr/planner.rb
|
68
68
|
- lib/tldr/rake.rb
|
@@ -100,14 +100,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 3.
|
103
|
+
version: '3.1'
|
104
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
105
|
requirements:
|
106
106
|
- - ">="
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: '0'
|
109
109
|
requirements: []
|
110
|
-
rubygems_version: 3.
|
110
|
+
rubygems_version: 3.3.26
|
111
111
|
signing_key:
|
112
112
|
specification_version: 4
|
113
113
|
summary: TLDR will run your tests, but only for 1.8 seconds.
|