nicetest 0.1.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
- checksums.yaml.gz.sig +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +97 -0
- data/exe/nicetest +6 -0
- data/lib/minitest/nicetest_plugin.rb +34 -0
- data/lib/minitest/reporters_plugin.rb +49 -0
- data/lib/minitest/superdiff_plugin.rb +95 -0
- data/lib/nicetest/backtrace_filter.rb +85 -0
- data/lib/nicetest/cli.rb +212 -0
- data/lib/nicetest/logger.rb +47 -0
- data/lib/nicetest/version.rb +5 -0
- data/lib/nicetest.rb +19 -0
- data.tar.gz.sig +0 -0
- metadata +162 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f8b1e58e35c866d01e21b5b8e397e05c3506002d3af25681a8178e6c26d4f2e3
|
4
|
+
data.tar.gz: 8f032d23008336df8010de48bb4a4cf872e4416d52a092ce76e231a7a09cb934
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1cc1cd63f09d3d3c5a2abca7fcd6bf9b914eb61391efb146cb0c01c0c77139b32ee8a32d493f1cef49b69bcf8df9ebda39bda69607f84f94b39535f30ef7b0fd
|
7
|
+
data.tar.gz: a19a0494f63b94dd40cfa2a493d31eb0ee1eea53ab33b08fc05e775d715dfc9c3f8e0eda533e1923cbdbe984da52d6fd6c9325da67b13ed968955dbf86e5c217
|
checksums.yaml.gz.sig
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 Ian Ker-Seymer
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# ☀️ nicetest
|
2
|
+
|
3
|
+
Enhance your minitest experience with nicetest—a gem offering a CLI, pretty
|
4
|
+
assertion diffs, pre-configured reporters, focus checks, and colorful backtrace
|
5
|
+
filters for seamless test running.
|
6
|
+
|
7
|
+
## Features
|
8
|
+
|
9
|
+
- A decent CLI for running tests, which is compatible with existing minitest plugin options
|
10
|
+
- Fancier diffs using [`super_diff`](https://github.com/mcmire/super_diff)
|
11
|
+
- Bundled [`minitest-reporters`](https://github.com/minitest-reporters/minitest-reporters), with defaults configured
|
12
|
+
- Bundled [`minitest-focus`](https://github.com/minitest/minitest-focus), with CI sanity check
|
13
|
+
- A pretty backtrace filter
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
### Take it with you
|
18
|
+
|
19
|
+
`nicetest` runs well on most `minitest` suites without hassle, so you can just
|
20
|
+
use it wherever you happen to be:
|
21
|
+
|
22
|
+
```sh
|
23
|
+
# Gem install it
|
24
|
+
$ gem install nicetest
|
25
|
+
|
26
|
+
# Go into a repo
|
27
|
+
$ git clone https://github.com/Shopfy/liquid; cd liquid; bundle install
|
28
|
+
|
29
|
+
# Run the tests
|
30
|
+
$ nicetest --reporter doc test/integration/capture_test.rb
|
31
|
+
Started with run options --reporter doc --seed 12874
|
32
|
+
|
33
|
+
CaptureTest
|
34
|
+
test_increment_assign_score_by_bytes_not_characters PASS (0.00s)
|
35
|
+
test_captures_block_content_in_variable PASS (0.00s)
|
36
|
+
test_capture_to_variable_from_outer_scope_if_existing PASS (0.00s)
|
37
|
+
test_assigning_from_capture PASS (0.00s)
|
38
|
+
test_capture_with_hyphen_in_variable_name PASS (0.00s)
|
39
|
+
|
40
|
+
Finished in 0.00123s
|
41
|
+
5 tests, 5 assertions, 0 failures, 0 errors, 0 skips
|
42
|
+
```
|
43
|
+
|
44
|
+
### Add to project
|
45
|
+
|
46
|
+
|
47
|
+
Add to your `test_helper.rb`:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
# test/test_helper.rb
|
51
|
+
|
52
|
+
require "nicetest"
|
53
|
+
|
54
|
+
# whatever else you do... can probably remove some stuff
|
55
|
+
```
|
56
|
+
|
57
|
+
Then, make it easy to run:
|
58
|
+
|
59
|
+
```sh
|
60
|
+
# Add to Gemfile
|
61
|
+
$ bundle add nicetest
|
62
|
+
|
63
|
+
# Make a bin/test executable
|
64
|
+
$ bundle binstub nicetest && mv bin/nicetest bin/test
|
65
|
+
```
|
66
|
+
|
67
|
+
You can run it now:
|
68
|
+
|
69
|
+
```sh
|
70
|
+
# Run tests
|
71
|
+
$ bin/test
|
72
|
+
|
73
|
+
# In CI
|
74
|
+
$ bin/test --reporter doc,junit
|
75
|
+
```
|
76
|
+
|
77
|
+
### What about Rakefile?
|
78
|
+
|
79
|
+
If you want to use Rake, just do this:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
# Rakefile
|
83
|
+
|
84
|
+
task :test do
|
85
|
+
sh("bin/test")
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
## Contributing
|
90
|
+
|
91
|
+
Bug reports and pull requests are welcome on GitHub at
|
92
|
+
https://github.com/ianks/nicetest.
|
93
|
+
|
94
|
+
## License
|
95
|
+
|
96
|
+
The gem is available as open source under the terms of the [MIT
|
97
|
+
License](https://opensource.org/licenses/MIT).
|
data/exe/nicetest
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# opts.banner = "Usage: example.rb [options]"
|
4
|
+
require "nicetest/cli"
|
5
|
+
|
6
|
+
module Minitest
|
7
|
+
class << self
|
8
|
+
def plugin_nicetest_options(opts, options)
|
9
|
+
opts.banner = Nicetest::Cli::BANNER
|
10
|
+
ValidateMinitestFocus.apply!
|
11
|
+
end
|
12
|
+
|
13
|
+
def plugin_nicetest_init(_options)
|
14
|
+
Minitest.backtrace_filter = Nicetest::BacktraceFilter.new
|
15
|
+
end
|
16
|
+
|
17
|
+
module ValidateMinitestFocus
|
18
|
+
class << self
|
19
|
+
def apply!
|
20
|
+
if ENV["CI"]
|
21
|
+
Minitest::Test.singleton_class.prepend(ValidateMinitestFocus::NoFocus)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module NoFocus
|
27
|
+
def focus(name = nil)
|
28
|
+
location = caller_locations(1, 1).first
|
29
|
+
Nicetest.logger.fatal!("cannot use `focus` in CI (#{location.path}:#{location.lineno})")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Minitest
|
4
|
+
module ReportersPlugin
|
5
|
+
MAPPING = {
|
6
|
+
"none" => ->(_options) { nil },
|
7
|
+
"default" => ->(options) { Minitest::Reporters::DefaultReporter.new(io: options[:io]) },
|
8
|
+
"spec" => ->(options) { Minitest::Reporters::SpecReporter.new(io: options[:io]) },
|
9
|
+
"doc" => ->(options) { MAPPING["spec"].call(options) },
|
10
|
+
"junit" => ->(options) {
|
11
|
+
ENV["MINITEST_REPORTERS_REPORTS_DIR"] ||= "tmp/nicetest/junit/#{Time.now.to_i}"
|
12
|
+
Minitest::Reporters::JUnitReporter.new(io: options[:io])
|
13
|
+
},
|
14
|
+
"progress" => ->(options) { Minitest::Reporters::ProgressReporter.new(io: options[:io]) },
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def plugin_reporters_options(opts, options)
|
20
|
+
options[:reporters] = ["progress"]
|
21
|
+
|
22
|
+
vals = Minitest::ReportersPlugin::MAPPING.keys.join(",")
|
23
|
+
description = <<~DESC.strip
|
24
|
+
The reporters to use for test output as comma-seperated list.
|
25
|
+
DESC
|
26
|
+
|
27
|
+
opts.on("-r", "--reporter #{vals}", Array, description) do |reporters|
|
28
|
+
reporters = options[:reporters] + reporters if reporters == ["junit"]
|
29
|
+
|
30
|
+
is_subset = (reporters - Minitest::ReportersPlugin::MAPPING.keys).empty?
|
31
|
+
raise OptionParser::InvalidArgument, "Invalid reporter: #{reporters.join(", ")}" unless is_subset
|
32
|
+
|
33
|
+
options[:reporters] = reporters
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def plugin_reporters_init(options)
|
38
|
+
return if options[:reporters].nil? || options[:reporters].empty?
|
39
|
+
|
40
|
+
require "minitest/reporters"
|
41
|
+
|
42
|
+
reporters = options[:reporters].map do |reporter|
|
43
|
+
ReportersPlugin::MAPPING.fetch(reporter).call(options)
|
44
|
+
end.compact
|
45
|
+
|
46
|
+
Minitest::Reporters.use!(reporters, ENV, Minitest.backtrace_filter) unless reporters.empty?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Minitest
|
4
|
+
class << self
|
5
|
+
def plugin_superdiff_options(opts, options)
|
6
|
+
opts.on("--no-superdiff", "Disable superdiff") do
|
7
|
+
options[:no_superdiff] = true
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def plugin_superdiff_init(options)
|
12
|
+
return if options[:no_superdiff]
|
13
|
+
|
14
|
+
require "super_diff"
|
15
|
+
Minitest::Assertions.prepend(SuperdiffPlugin)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module SuperdiffPlugin
|
20
|
+
module Helpers
|
21
|
+
extend self
|
22
|
+
def inspect_styled(obj, style, prefix: nil)
|
23
|
+
obj = SuperDiff.inspect_object(obj, as_lines: false)
|
24
|
+
SuperDiff::Core::Helpers.style(style, "#{prefix}#{obj}")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def diff(expected, actual)
|
29
|
+
SuperDiff::EqualityMatchers::Main.call(expected: expected, actual: actual)
|
30
|
+
end
|
31
|
+
|
32
|
+
def mu_pp(obj)
|
33
|
+
SuperDiff.inspect_object(obj, as_lines: false)
|
34
|
+
end
|
35
|
+
|
36
|
+
def assert_includes(collection, item, message = nil)
|
37
|
+
super
|
38
|
+
rescue Minitest::Assertion => e
|
39
|
+
raise if message
|
40
|
+
|
41
|
+
exception = Minitest::Assertion.new(AssertIncludesMessage.new(collection: collection, item: item))
|
42
|
+
exception.set_backtrace(e.backtrace)
|
43
|
+
raise exception
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class AssertIncludesMessage
|
48
|
+
include SuperdiffPlugin::Helpers
|
49
|
+
|
50
|
+
def initialize(collection:, item:)
|
51
|
+
@collection = collection
|
52
|
+
@item = item
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_s
|
56
|
+
return @to_s if defined?(@to_s)
|
57
|
+
|
58
|
+
content = if (diff = optional_diff)
|
59
|
+
collection = inspect_styled(@collection, :expected)
|
60
|
+
item = inspect_styled(@item, :actual)
|
61
|
+
|
62
|
+
<<~OUTPUT.strip
|
63
|
+
Expected #{collection} to include #{item}, but it did not.
|
64
|
+
|
65
|
+
#{diff}
|
66
|
+
OUTPUT
|
67
|
+
else
|
68
|
+
expected = inspect_styled(@collection, :expected, prefix: " Collection: ")
|
69
|
+
actual = inspect_styled(@item, :actual, prefix: "Missing item: ")
|
70
|
+
|
71
|
+
<<~OUTPUT.strip
|
72
|
+
Expected collection to include item but it did not.
|
73
|
+
|
74
|
+
#{expected}
|
75
|
+
#{actual}
|
76
|
+
OUTPUT
|
77
|
+
end
|
78
|
+
|
79
|
+
@to_s ||= content
|
80
|
+
end
|
81
|
+
|
82
|
+
def optional_diff
|
83
|
+
case @collection
|
84
|
+
when Array, Set
|
85
|
+
collection_with_item = @collection + [@item].flatten(1)
|
86
|
+
basic_diff(@collection, collection_with_item)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def basic_diff(expected, actual)
|
91
|
+
content = SuperDiff.diff(expected, actual)
|
92
|
+
"\nDiff:\n\n#{content}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pastel"
|
4
|
+
|
5
|
+
module Nicetest
|
6
|
+
class BacktraceFilter
|
7
|
+
BUNDLER_REGEX = %r{/bundler/gems}
|
8
|
+
GEMS_DEFAULT_DIR = Regexp.escape(Gem.default_dir)
|
9
|
+
GEMS_PATHS = Gem.path.map { |path| Regexp.new(Regexp.escape(path)) }
|
10
|
+
|
11
|
+
attr_reader :pastel
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@pastel = Cli::PASTEL
|
15
|
+
@silence_pattern = Regexp.union([
|
16
|
+
/sorbet-runtime/,
|
17
|
+
Regexp.escape(RbConfig::CONFIG["rubylibdir"]),
|
18
|
+
%r{/gems/bundler-\d+\.\d+\.\d+/lib/bundler},
|
19
|
+
%r{/gems/minitest-\d+\.\d+\.\d+/lib/minitest},
|
20
|
+
%r{/gems/minitest-reporters-\d+\.\d+\.\d+/lib/minitest},
|
21
|
+
%r{(bin|exe)/bundle:},
|
22
|
+
/internal:warning/,
|
23
|
+
])
|
24
|
+
@dim_pattern = Regexp.union([
|
25
|
+
GEMS_DEFAULT_DIR,
|
26
|
+
*GEMS_PATHS,
|
27
|
+
BUNDLER_REGEX,
|
28
|
+
])
|
29
|
+
end
|
30
|
+
|
31
|
+
def filter(backtrace)
|
32
|
+
bt = []
|
33
|
+
first_line = true
|
34
|
+
cwd = Dir.pwd
|
35
|
+
|
36
|
+
backtrace.each do |line|
|
37
|
+
silenced = silence?(line)
|
38
|
+
|
39
|
+
next if silenced && !first_line
|
40
|
+
|
41
|
+
first_line = false
|
42
|
+
|
43
|
+
bt << if silenced || (dim?(line) && !line.start_with?(cwd))
|
44
|
+
pastel.dim(trim_prefix(line))
|
45
|
+
else
|
46
|
+
colorize_line(trim_prefix(line))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
bt
|
51
|
+
end
|
52
|
+
|
53
|
+
def dim?(line)
|
54
|
+
@dim_pattern.match?(line)
|
55
|
+
end
|
56
|
+
|
57
|
+
def silence?(line)
|
58
|
+
@silence_pattern.match?(line)
|
59
|
+
end
|
60
|
+
|
61
|
+
def trim_prefix(line)
|
62
|
+
line = line.delete_prefix(Dir.pwd + "/")
|
63
|
+
line.sub!(ENV["HOME"], "~")
|
64
|
+
line
|
65
|
+
end
|
66
|
+
|
67
|
+
def colorize_line(line)
|
68
|
+
match = line.match(/(.*):(\d+):in `(.*)'/)
|
69
|
+
|
70
|
+
if match
|
71
|
+
file = match[1]
|
72
|
+
line_number = match[2]
|
73
|
+
method = match[3]
|
74
|
+
|
75
|
+
colored_file = pastel.cyan(file)
|
76
|
+
colored_line_number = pastel.green(line_number)
|
77
|
+
colored_method = pastel.yellow(method)
|
78
|
+
|
79
|
+
"#{colored_file}:#{colored_line_number}:in `#{colored_method}'"
|
80
|
+
else
|
81
|
+
line
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/nicetest/cli.rb
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pastel"
|
4
|
+
require "minitest"
|
5
|
+
require "optparse"
|
6
|
+
require "English"
|
7
|
+
require "set"
|
8
|
+
|
9
|
+
module Nicetest
|
10
|
+
class Cli
|
11
|
+
def initialize(argv)
|
12
|
+
@argv = argv
|
13
|
+
@logger = Logger.new($stderr)
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
cli_options = Opts.parse!(@argv)
|
18
|
+
if (dir = cli_options.cd)
|
19
|
+
run_in_directory(dir)
|
20
|
+
elsif File.exist?("Gemfile") && !File.read("Gemfile").include?("nicetest")
|
21
|
+
run_in_directory(".")
|
22
|
+
else
|
23
|
+
run_tests
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def run_tests
|
28
|
+
disable_autorun!
|
29
|
+
adjust_load_path!
|
30
|
+
|
31
|
+
args = @argv.dup
|
32
|
+
argv_test_files = select_file_args(args)
|
33
|
+
argv_test_files = glob_test_files("test") if argv_test_files.empty?
|
34
|
+
args -= argv_test_files
|
35
|
+
|
36
|
+
required_files = argv_test_files.flat_map do |file_or_dir|
|
37
|
+
require_path_or_dir(file_or_dir)
|
38
|
+
end
|
39
|
+
|
40
|
+
@logger.fatal!("no test files found") if required_files.compact.empty?
|
41
|
+
|
42
|
+
Minitest.run(args)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def fetch_dep_loadpaths(gemspec, seen = {})
|
48
|
+
return [] if seen[gemspec.name]
|
49
|
+
|
50
|
+
seen[gemspec.name] = true
|
51
|
+
load_paths = gemspec.full_require_paths
|
52
|
+
|
53
|
+
gemspec.dependencies.each do |dep|
|
54
|
+
dep_spec = Gem.loaded_specs[dep.name]
|
55
|
+
next unless dep_spec
|
56
|
+
|
57
|
+
load_paths.concat(fetch_dep_loadpaths(dep_spec, seen))
|
58
|
+
end
|
59
|
+
|
60
|
+
load_paths
|
61
|
+
end
|
62
|
+
|
63
|
+
def run_in_directory(input_dir)
|
64
|
+
dir = File.expand_path(input_dir)
|
65
|
+
dir.delete_suffix!("/") # remove trailing slash
|
66
|
+
|
67
|
+
chdir = if input_dir != "."
|
68
|
+
->(&blk) do
|
69
|
+
@logger.info("changing directory to #{dir}")
|
70
|
+
Dir.chdir(dir, &blk)
|
71
|
+
end
|
72
|
+
else
|
73
|
+
->(&blk) { blk.call }
|
74
|
+
end
|
75
|
+
|
76
|
+
loadpaths = fetch_dep_loadpaths(Gem.loaded_specs["nicetest"]).map { |path| "-I#{path}" }
|
77
|
+
requires = ["-rnicetest"]
|
78
|
+
args_with_removed_leading_path = @argv.map do |arg|
|
79
|
+
arg = arg.dup
|
80
|
+
arg.delete_prefix!(dir)
|
81
|
+
arg.delete_prefix!(File.expand_path(dir))
|
82
|
+
arg.delete_prefix!("/")
|
83
|
+
arg
|
84
|
+
end
|
85
|
+
|
86
|
+
run_proc = proc do
|
87
|
+
requires << "-rbundler/setup" if File.exist?("Gemfile")
|
88
|
+
|
89
|
+
cmd = [
|
90
|
+
RbConfig.ruby,
|
91
|
+
*loadpaths,
|
92
|
+
*requires,
|
93
|
+
"-e",
|
94
|
+
"exit(Nicetest::Cli.new(ARGV).run_tests)",
|
95
|
+
"--",
|
96
|
+
*args_with_removed_leading_path,
|
97
|
+
]
|
98
|
+
@logger.debug("running #{cmd.join(" ")}")
|
99
|
+
system(*cmd)
|
100
|
+
$CHILD_STATUS.exitstatus
|
101
|
+
end
|
102
|
+
|
103
|
+
chdir.call do
|
104
|
+
if defined?(Bundler)
|
105
|
+
Bundler.with_unbundled_env(&run_proc)
|
106
|
+
else
|
107
|
+
run_proc.call
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def select_file_args(args)
|
113
|
+
args = args.dup
|
114
|
+
Minitest.instance_variable_set(:@extensions, Set.new) # Avoid double-loading plugins
|
115
|
+
Minitest.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
|
116
|
+
# this will remove all options from the args array
|
117
|
+
temporarily_disable_optparse_callbacks { Minitest.process_args(args) }
|
118
|
+
args
|
119
|
+
end
|
120
|
+
|
121
|
+
def glob_test_files(dir)
|
122
|
+
Dir.glob("#{dir}/**{,/*/**}/*_test.rb")
|
123
|
+
end
|
124
|
+
|
125
|
+
def require_path_or_dir(path_or_dir)
|
126
|
+
if path_or_dir.end_with?(".rb")
|
127
|
+
[try_require(path_or_dir)]
|
128
|
+
else
|
129
|
+
Dir.glob("#{path_or_dir}/**{,/*/**}/*_test.rb").map do |f|
|
130
|
+
try_require(f)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def try_require(path)
|
136
|
+
full_path = File.expand_path(path)
|
137
|
+
require full_path
|
138
|
+
true
|
139
|
+
rescue => e
|
140
|
+
bt = e.backtrace.first(10).map { |line| "\t#{PASTEL.dim(line)}" }.join("\n")
|
141
|
+
@logger.warn("could not require #{full_path} (#{e.class}: #{e.message})\n#{bt}")
|
142
|
+
nil
|
143
|
+
end
|
144
|
+
|
145
|
+
def disable_autorun!
|
146
|
+
Minitest.class_variable_set(:@@installed_at_exit, true) # rubocop:disable Style/ClassVars
|
147
|
+
end
|
148
|
+
|
149
|
+
def adjust_load_path!
|
150
|
+
$LOAD_PATH.unshift(File.expand_path("test"))
|
151
|
+
end
|
152
|
+
|
153
|
+
def temporarily_disable_optparse_callbacks(&blk)
|
154
|
+
OptionParser.class_eval do
|
155
|
+
def noop_callback!(*); end
|
156
|
+
|
157
|
+
original_callback = instance_method(:callback!)
|
158
|
+
define_method(:callback!, instance_method(:noop_callback!))
|
159
|
+
|
160
|
+
yield
|
161
|
+
|
162
|
+
define_method(:callback!, original_callback)
|
163
|
+
remove_method(:noop_callback!)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
Opts = Struct.new(:cd) do
|
168
|
+
class << self
|
169
|
+
def parse!(argv)
|
170
|
+
old_officious = OptionParser::Officious.dup
|
171
|
+
OptionParser::Officious.clear
|
172
|
+
|
173
|
+
options = new
|
174
|
+
parser = OptionParser.new do |opts|
|
175
|
+
opts.banner = ""
|
176
|
+
opts.raise_unknown = false
|
177
|
+
opts.on("--cd=DIR", "Change directory before running tests") do |dir|
|
178
|
+
options[:cd] = dir
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
parser.parse!(argv)
|
183
|
+
OptionParser::Officious.replace(old_officious)
|
184
|
+
options
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
PASTEL = Pastel.new
|
190
|
+
|
191
|
+
BANNER = <<~BANNER
|
192
|
+
☀️ #{PASTEL.bold.cyan("nicetest")} #{PASTEL.dim.italic(Nicetest::VERSION)}
|
193
|
+
|
194
|
+
A minimalistic test runner for Minitest.
|
195
|
+
|
196
|
+
#{PASTEL.bold("Usage")}
|
197
|
+
|
198
|
+
nicetest [options] [files or directories]
|
199
|
+
|
200
|
+
#{PASTEL.bold("Examples")}
|
201
|
+
|
202
|
+
$ nicetest
|
203
|
+
$ nicetest test/models --reporter spec
|
204
|
+
$ nicetest test/models/user_test.rb:12
|
205
|
+
|
206
|
+
#{PASTEL.bold("Nicetest Options")}
|
207
|
+
--cd=DIR Change directory before running tests
|
208
|
+
#{PASTEL.bold("Minitest Options")}
|
209
|
+
|
210
|
+
BANNER
|
211
|
+
end
|
212
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
module Nicetest
|
6
|
+
class Logger
|
7
|
+
def initialize(io)
|
8
|
+
@pastel = Cli::PASTEL
|
9
|
+
@io = io
|
10
|
+
end
|
11
|
+
|
12
|
+
def warn(message)
|
13
|
+
log("warn ", message, color: :yellow)
|
14
|
+
end
|
15
|
+
|
16
|
+
def error(message)
|
17
|
+
log("error", message, color: :red)
|
18
|
+
end
|
19
|
+
|
20
|
+
def info(message)
|
21
|
+
log("info ", message, color: :cyan)
|
22
|
+
end
|
23
|
+
|
24
|
+
def debug(message)
|
25
|
+
if ENV["NICETEST_DEBUG"] == "1"
|
26
|
+
log("debug", message, color: :blue)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def fatal!(message)
|
31
|
+
error(message)
|
32
|
+
exit(1)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def log(level, message, color:)
|
38
|
+
@io.puts "#{target_level(level, color: color)} #{message}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def target_level(level, color:)
|
42
|
+
level = @pastel.bold.send(color, level)
|
43
|
+
logname = @pastel.dim.italic("nicetest →")
|
44
|
+
"#{level} #{logname}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/nicetest.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pastel"
|
4
|
+
require "minitest/focus"
|
5
|
+
|
6
|
+
require_relative "nicetest/version"
|
7
|
+
require_relative "nicetest/logger"
|
8
|
+
require_relative "nicetest/cli"
|
9
|
+
require_relative "nicetest/backtrace_filter"
|
10
|
+
|
11
|
+
module Nicetest
|
12
|
+
class Error < StandardError; end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def logger
|
16
|
+
@logger ||= Logger.new($stderr)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data.tar.gz.sig
ADDED
Binary file
|
metadata
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nicetest
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ian Ker-Seymer
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIDODCCAiCgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBCMRQwEgYDVQQDDAtpLmtl
|
14
|
+
cnNleW1lcjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYD
|
15
|
+
Y29tMB4XDTI0MDQxODA1MzY0N1oXDTI1MDQxODA1MzY0N1owQjEUMBIGA1UEAwwL
|
16
|
+
aS5rZXJzZXltZXIxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixk
|
17
|
+
ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMJ2pG+er4cP
|
18
|
+
PasxsMIKL9/tmLL4gh80EMuF3SCS0qZoh+Oo8dkvRYxW8NXdwEIcp3cCNgE+5G+J
|
19
|
+
TCMOVF8S15n1Z1P7xxXiXxa/BIofKKbtatVRngm14uR/6pjdkvLXqlrWdS57bNwv
|
20
|
+
7LtpzYVfDHfsl/qRWaEi4jq00PNCRSWjcva8teqswjBg8KlwGtyygpezPbVSWP8Y
|
21
|
+
vzWZmVF7fqRBXU78Ah0+pNOhslBXDTvI3xJdN4hQ3H7rLjpD/qxKWq/8o+Qvx6cX
|
22
|
+
dNZ3ugH/Pr3BAsqt4JFLXin9AK7PO9GDMH5JXJrUb+hAt2VNIZqpz9VlKA6BA0jN
|
23
|
+
eWGea+yCZkECAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
|
24
|
+
BBYEFOkrF6hsocaIMOjR/K3JBzyXCLJPMA0GCSqGSIb3DQEBCwUAA4IBAQARHgco
|
25
|
+
yCxWUqN+HBGewmSB7T4oq6YS2FtU62K+GuWWCTqjl5byLKMXQW8HPDja9TC1My1m
|
26
|
+
2r0uDshtUvUjuB/Vfe9jVMTjnPBspHZYo0MRuMPc7owJaahjkqD3l7w9aa8Ci5aC
|
27
|
+
YU4Aj71Sc8s7YIxgHn/yIUdCe1yu6cC0+h+Ss9r/Yjr53NNXwjGQlDmH1eHcVQGZ
|
28
|
+
mEoVcZO1uWNtRPPsn1gfvKLPjRe5pclXQnGviS5DiH0Du+8QMxQGBJnYz2zSMW7G
|
29
|
+
Lvd35BNvZkhFzs9xfykhurpkT2TiP2F3ZFn9dwLXMFe41pwrtEYLIWhYi8mUG4Ek
|
30
|
+
6aR8M/tqIpChVV39
|
31
|
+
-----END CERTIFICATE-----
|
32
|
+
date: 2024-07-21 00:00:00.000000000 Z
|
33
|
+
dependencies:
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: minitest
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.0'
|
41
|
+
type: :runtime
|
42
|
+
prerelease: false
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: minitest-focus
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.4'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.4'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: minitest-reporters
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.4'
|
69
|
+
type: :runtime
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.4'
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: optparse
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.5.0
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.5.0
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: pastel
|
92
|
+
requirement: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.8'
|
97
|
+
type: :runtime
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.8'
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: super_diff
|
106
|
+
requirement: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.12'
|
111
|
+
type: :runtime
|
112
|
+
prerelease: false
|
113
|
+
version_requirements: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.12'
|
118
|
+
description: Configure Minitest with common plugins and options to make it even nicer
|
119
|
+
to use.
|
120
|
+
email:
|
121
|
+
- ian.kerseymer@shopify.com
|
122
|
+
executables:
|
123
|
+
- nicetest
|
124
|
+
extensions: []
|
125
|
+
extra_rdoc_files: []
|
126
|
+
files:
|
127
|
+
- LICENSE.txt
|
128
|
+
- README.md
|
129
|
+
- exe/nicetest
|
130
|
+
- lib/minitest/nicetest_plugin.rb
|
131
|
+
- lib/minitest/reporters_plugin.rb
|
132
|
+
- lib/minitest/superdiff_plugin.rb
|
133
|
+
- lib/nicetest.rb
|
134
|
+
- lib/nicetest/backtrace_filter.rb
|
135
|
+
- lib/nicetest/cli.rb
|
136
|
+
- lib/nicetest/logger.rb
|
137
|
+
- lib/nicetest/version.rb
|
138
|
+
homepage: https://github.com/ianks/nicetest
|
139
|
+
licenses:
|
140
|
+
- MIT
|
141
|
+
metadata:
|
142
|
+
allowed_push_host: https://rubygems.org
|
143
|
+
post_install_message:
|
144
|
+
rdoc_options: []
|
145
|
+
require_paths:
|
146
|
+
- lib
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: 3.0.0
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
requirements: []
|
158
|
+
rubygems_version: 3.5.9
|
159
|
+
signing_key:
|
160
|
+
specification_version: 4
|
161
|
+
summary: A slightly fancier configuration for Minitest
|
162
|
+
test_files: []
|
metadata.gz.sig
ADDED
Binary file
|