pry-test 0.5.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/bin/pry-test +110 -0
- data/ext/mkrf_conf.rb +33 -0
- data/lib/pry-test.rb +5 -0
- data/lib/pry-test/formatters/base_formatter.rb +74 -0
- data/lib/pry-test/formatters/color.rb +26 -0
- data/lib/pry-test/formatters/default_async_formatter.rb +40 -0
- data/lib/pry-test/formatters/default_formatter.rb +24 -0
- data/lib/pry-test/formatters/template.rb +50 -0
- data/lib/pry-test/formatters/views/default/assert_fail.txt.erb +6 -0
- data/lib/pry-test/formatters/views/default/class.txt.erb +2 -0
- data/lib/pry-test/formatters/views/default/suite.txt.erb +9 -0
- data/lib/pry-test/formatters/views/default/test_fail.txt.erb +2 -0
- data/lib/pry-test/formatters/views/default/test_pass.txt.erb +1 -0
- data/lib/pry-test/formatters/views/default_async/test.txt.erb +1 -0
- data/lib/pry-test/runner.rb +73 -0
- data/lib/pry-test/test.rb +85 -0
- data/lib/pry-test/test_wrapper.rb +144 -0
- data/lib/pry-test/version.rb +3 -0
- data/test/color_test.rb +47 -0
- data/test/cpu_latency_test.rb +30 -0
- data/test/fail_test.rb +18 -0
- data/test/io_latency_test.rb +22 -0
- data/test/runner_test.rb +15 -0
- data/test/test_helper.rb +4 -0
- data/test/test_test.rb +70 -0
- data/test/test_wrapper_test.rb +19 -0
- metadata +124 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bff3b5b582f2d0f20a0638c8f2d22fe2c8f34328
|
4
|
+
data.tar.gz: f47f593420062049f74de02e4c33ede5406c680b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9fb57924837b12dea333bd4e62d98f65c504c29482b4f2e151eaa645f3f8e646d24f9e1f0ca19acd088d3a7a842390fcdbdae7f4b0024d6af6ba456a263d5a76
|
7
|
+
data.tar.gz: c97f1dc2c54058853a4aa3a2ebbf815a22ca5153184acca03a0cf26e6eac41823df4ad67e94feacf24afaf7c349d9a7cfb088181d0ddb933924fc155ccc8386d
|
data/bin/pry-test
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "optparse"
|
3
|
+
require_relative "../lib/pry-test"
|
4
|
+
|
5
|
+
include PryTest::Color
|
6
|
+
|
7
|
+
# setup the formatters list ---------------------------------------------------
|
8
|
+
formatter_names = PryTest.formatters.map(&:short_name).sort
|
9
|
+
|
10
|
+
# setup the options -----------------------------------------------------------
|
11
|
+
options = {}
|
12
|
+
parser = OptionParser.new do |opts|
|
13
|
+
opts.banner = "PryTest Usage: pry-test [options] /path/to/test/dir_or_file"
|
14
|
+
|
15
|
+
desc = "Runs tests asynchronously."
|
16
|
+
opts.on("-a", "--async", desc) { |value| options[:async] = value }
|
17
|
+
|
18
|
+
desc = "Runs the PryTest test suite and some additional demo tests."
|
19
|
+
opts.on("--demo", desc) { |value| options[:demo] = value }
|
20
|
+
|
21
|
+
desc = "The formatter to use. [#{formatter_names.join(", ")}]"
|
22
|
+
opts.on("-f", "--formatter [FORMATTER]", desc) do |value|
|
23
|
+
options[:formatter] = value
|
24
|
+
end
|
25
|
+
|
26
|
+
desc = "Stops the test run after the first failure. "
|
27
|
+
opts.on("--fail-fast", desc) { |value| options[:fail_fast] = value }
|
28
|
+
|
29
|
+
desc = "Disabled pry during the test run. "
|
30
|
+
opts.on("--disable-pry", desc) { |value| options[:disable_pry] = value }
|
31
|
+
|
32
|
+
opts.on("-v", "--version", "Show version.") do
|
33
|
+
puts "PryTest #{PryTest::VERSION}"
|
34
|
+
exit 0
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on_tail("-h", "--help", "Show this message.") do
|
38
|
+
puts opts
|
39
|
+
exit 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
parser.parse!
|
43
|
+
|
44
|
+
ENV["MT_DEMO"] = "true" if options[:demo]
|
45
|
+
|
46
|
+
# setup the test path ---------------------------------------------------------
|
47
|
+
path = ARGV.last unless ARGV.last =~ /^-/
|
48
|
+
path = File.expand_path("../../test", __FILE__) if options[:demo]
|
49
|
+
path ||= "test"
|
50
|
+
path = File.join(Dir.pwd, path) unless path =~ /^\//
|
51
|
+
unless File.exist?(path)
|
52
|
+
puts "#{path} not found."
|
53
|
+
puts "Please check the path and try again."
|
54
|
+
exit 1
|
55
|
+
end
|
56
|
+
if path =~ /\.rb$/
|
57
|
+
require path
|
58
|
+
else
|
59
|
+
Dir[File.join(path, "**/*.rb")].each { |path| require path }
|
60
|
+
end
|
61
|
+
|
62
|
+
# setup the formatter ---------------------------------------------------------
|
63
|
+
formatter = PryTest.formatters.find { |f| f.short_name == options[:formatter] }
|
64
|
+
formatter ||= begin
|
65
|
+
if options[:async]
|
66
|
+
PryTest.formatters.find { |f| f.short_name == "default_async" }
|
67
|
+
else
|
68
|
+
PryTest.formatters.find { |f| f.short_name == "default" }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# setup the test runner -------------------------------------------------------
|
73
|
+
runner = PryTest::Runner.new(formatter.new, options)
|
74
|
+
|
75
|
+
# setup pry -------------------------------------------------------------------
|
76
|
+
if options[:async] || RUBY_ENGINE == "jruby" || RUBY_ENGINE == "rbx"
|
77
|
+
optional[:disable_pry] = true
|
78
|
+
end
|
79
|
+
|
80
|
+
if options[:disable_pry]
|
81
|
+
puts magenta("Disabling pry when running with: [#{RUBY_ENGINE}] #{options.inspect}")
|
82
|
+
exit runner.run
|
83
|
+
else
|
84
|
+
begin
|
85
|
+
require "pry"
|
86
|
+
require "pry-stack_explorer"
|
87
|
+
require "pry-rescue"
|
88
|
+
rescue Exception => e
|
89
|
+
puts red(e.message)
|
90
|
+
puts e.backtrace.join("\n")
|
91
|
+
puts red("This can be caused when pry-stack_explorer isn't specified in the Gemfile.")
|
92
|
+
puts red("It might also indicate that pry-stack_explorer & pry are out of sync.")
|
93
|
+
puts red("Try different cominations of GEM versions for pry & pry-stack_explorer.")
|
94
|
+
exit 1
|
95
|
+
end
|
96
|
+
|
97
|
+
Pry.config.hooks.add_hook :before_session, :print_instructions do |_, _, _pry_|
|
98
|
+
puts
|
99
|
+
puts magenta(" Pry session started")
|
100
|
+
puts magenta("".ljust(80, "-"))
|
101
|
+
puts " #{magenta " Failures:"} Type #{green "up"} to see the line that failed"
|
102
|
+
puts " #{magenta "Exceptions:"} Type #{green "whereami"} to get your bearings"
|
103
|
+
puts
|
104
|
+
puts " Type #{green "exit"} or #{green "<CTL-D>"} to continue"
|
105
|
+
puts magenta("".ljust(80, "-"))
|
106
|
+
puts
|
107
|
+
end
|
108
|
+
|
109
|
+
exit Pry.rescue { runner.run }
|
110
|
+
end
|
data/ext/mkrf_conf.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# based on instructions here:
|
2
|
+
# http://en.wikibooks.org/wiki/Ruby_Programming/RubyGems#How_to_install_different_versions_of_gems_depending_on_which_version_of_ruby_the_installee_is_using
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rubygems/command.rb'
|
5
|
+
require 'rubygems/dependency_installer.rb'
|
6
|
+
|
7
|
+
begin
|
8
|
+
Gem::Command.build_args = ARGV
|
9
|
+
rescue NoMethodError
|
10
|
+
end
|
11
|
+
|
12
|
+
installer = Gem::DependencyInstaller.new
|
13
|
+
|
14
|
+
begin
|
15
|
+
if !(RUBY_ENGINE =~ /jruby/i)
|
16
|
+
puts "Installing pry and pry-stack_explorer."
|
17
|
+
installer.install "pry"
|
18
|
+
installer.install "pry-stack_explorer"
|
19
|
+
installer.install "pry-rescue"
|
20
|
+
else
|
21
|
+
puts "Platform is java... skip install for pry and pry-stack_explorer."
|
22
|
+
end
|
23
|
+
rescue Exception => e
|
24
|
+
puts e.message
|
25
|
+
puts e.backtrace.join("\n")
|
26
|
+
exit(1)
|
27
|
+
end
|
28
|
+
|
29
|
+
f = File.open(File.expand_path("../Rakefile", __FILE__), "w") # create dummy rakefile to indicate success
|
30
|
+
f.write("task :default\n")
|
31
|
+
f.close
|
32
|
+
|
33
|
+
exit
|
data/lib/pry-test.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
module PryTest
|
2
|
+
|
3
|
+
class << self
|
4
|
+
def formatters
|
5
|
+
@formatters ||= []
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
# The base class for formatters.
|
10
|
+
# Defines the API that formatters can/should implement
|
11
|
+
# to control test run output.
|
12
|
+
class BaseFormatter
|
13
|
+
attr_accessor :passed, :failed, :duration
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def inherited(subclass)
|
17
|
+
PryTest.formatters << subclass
|
18
|
+
end
|
19
|
+
|
20
|
+
def short_name
|
21
|
+
@short_name || name
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_short_name(value)
|
25
|
+
@short_name = value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@duration = 0
|
31
|
+
@passed = 0
|
32
|
+
@failed = 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def before_suite(test_classes)
|
36
|
+
end
|
37
|
+
|
38
|
+
def before_class(test_class)
|
39
|
+
end
|
40
|
+
|
41
|
+
def before_test(test)
|
42
|
+
end
|
43
|
+
|
44
|
+
def after_test(test)
|
45
|
+
end
|
46
|
+
|
47
|
+
def after_class(test_class)
|
48
|
+
end
|
49
|
+
|
50
|
+
def after_results(runner)
|
51
|
+
@duration = runner.duration
|
52
|
+
@passed = runner.passed
|
53
|
+
@failed = runner.failed
|
54
|
+
end
|
55
|
+
|
56
|
+
def after_suite(test_classes)
|
57
|
+
end
|
58
|
+
|
59
|
+
def render(template_name, template_context=nil)
|
60
|
+
puts text_to_render(template_name, template_context)
|
61
|
+
end
|
62
|
+
|
63
|
+
def render_inline(template_name, template_context=nil)
|
64
|
+
print text_to_render(template_name, template_context)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def text_to_render(template_name, template_context=nil)
|
70
|
+
Template.new(template_context || self).render_to_string(template_name)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module PryTest
|
2
|
+
module Color
|
3
|
+
extend self
|
4
|
+
|
5
|
+
colors = {
|
6
|
+
:red => 31,
|
7
|
+
:green => 32,
|
8
|
+
:yellow => 33,
|
9
|
+
:blue => 34,
|
10
|
+
:magenta => 35,
|
11
|
+
:cyan => 36,
|
12
|
+
:white => 37,
|
13
|
+
:gray => 90
|
14
|
+
}
|
15
|
+
|
16
|
+
def default(text)
|
17
|
+
text
|
18
|
+
end
|
19
|
+
|
20
|
+
colors.each do |name, code|
|
21
|
+
define_method name do |text|
|
22
|
+
"\e[#{code}m#{text}\e[0m"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative "base_formatter"
|
2
|
+
|
3
|
+
module PryTest
|
4
|
+
class DefaultAsyncFormatter < PryTest::BaseFormatter
|
5
|
+
set_short_name "default_async"
|
6
|
+
|
7
|
+
def after_test(test)
|
8
|
+
render_inline "default_async/test", test
|
9
|
+
end
|
10
|
+
|
11
|
+
def after_suite(test_classes)
|
12
|
+
puts
|
13
|
+
test_classes.each do |test_class|
|
14
|
+
render_output_for_test_class test_class
|
15
|
+
end
|
16
|
+
|
17
|
+
render "default/suite"
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def render_output_for_test_class(test_class)
|
23
|
+
render "default/class", test_class
|
24
|
+
test_class.tests.each do |test|
|
25
|
+
render_output_for_test test
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def render_output_for_test(test)
|
30
|
+
return unless test.finished?
|
31
|
+
|
32
|
+
if test.passed?
|
33
|
+
render "default/test_pass", test
|
34
|
+
else
|
35
|
+
render "default/test_fail", test
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative "base_formatter"
|
2
|
+
|
3
|
+
module PryTest
|
4
|
+
class DefaultFormatter < PryTest::BaseFormatter
|
5
|
+
set_short_name "default"
|
6
|
+
|
7
|
+
def before_class(test_class)
|
8
|
+
render "default/class", test_class
|
9
|
+
end
|
10
|
+
|
11
|
+
def after_test(test)
|
12
|
+
if test.passed?
|
13
|
+
render "default/test_pass", test
|
14
|
+
else
|
15
|
+
render "default/test_fail", test
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def after_suite(test_classes)
|
20
|
+
render "default/suite"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative "color"
|
2
|
+
|
3
|
+
module PryTest
|
4
|
+
class Template
|
5
|
+
include Color
|
6
|
+
|
7
|
+
def self.view(name)
|
8
|
+
@views ||= {}
|
9
|
+
@views[name] ||= File.read(File.expand_path("../views/#{name}.txt.erb", __FILE__))
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(context)
|
13
|
+
@context = context
|
14
|
+
end
|
15
|
+
|
16
|
+
def render_to_string(name)
|
17
|
+
instance_eval do
|
18
|
+
ERB.new(self.class.view(name), nil, "%<>-").result(binding)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def partial(name, *collection)
|
23
|
+
return render_to_string(name) if collection.empty?
|
24
|
+
collection.map do |item|
|
25
|
+
Template.new(item).render_to_string(name)
|
26
|
+
end.join("\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
def duration_color(duration)
|
30
|
+
return :yellow if @context.duration <= 0.01
|
31
|
+
:red
|
32
|
+
end
|
33
|
+
|
34
|
+
def assert_lines(assert)
|
35
|
+
index = assert[:line_num] - 1
|
36
|
+
start = index - 2
|
37
|
+
start = 0 if start <= 0
|
38
|
+
finish = index + 2
|
39
|
+
finish = assert[:lines].length - 1 if finish >= assert[:lines].length
|
40
|
+
(start..finish).map do |i|
|
41
|
+
{
|
42
|
+
:line_num => (i + 1),
|
43
|
+
:line => assert[:lines][i],
|
44
|
+
:color => (i == index ? :red : :gray)
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<%= @context[:file_path].strip %><%= gray ":" %><%= red @context[:line_num] %>
|
2
|
+
<%= red "".ljust(80, "-") %>
|
3
|
+
<% assert_lines(@context).each do |line| -%>
|
4
|
+
<%= send line[:color], line[:line_num].to_s.rjust(4) %><%= gray "|" %> <%= send line[:color], line[:line] -%>
|
5
|
+
<% end -%>
|
6
|
+
<%= red "".ljust(80, "-") %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
|
2
|
+
--------------------------------------------------------------------------------
|
3
|
+
<%= green "#{@context.passed} Passed" -%>
|
4
|
+
<% if @context.failed > 0 -%>
|
5
|
+
, <%= red "#{@context.failed} Failed" -%>
|
6
|
+
<% end -%>
|
7
|
+
Finished in <%= yellow @context.duration %> seconds.
|
8
|
+
--------------------------------------------------------------------------------
|
9
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= send duration_color(@context.duration), @context.duration %> <%= green @context.desc -%>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= gray "." -%>
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require "os"
|
2
|
+
require "thread"
|
3
|
+
|
4
|
+
module PryTest
|
5
|
+
class Runner
|
6
|
+
class << self
|
7
|
+
attr_accessor :exit
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :formatter, :options, :active_test, :duration, :passed, :failed
|
11
|
+
|
12
|
+
def initialize(formatter, options={})
|
13
|
+
@formatter = formatter
|
14
|
+
@options = options
|
15
|
+
reset
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
test_classes = PryTest::Test.subclasses.shuffle
|
20
|
+
tests = test_classes.map{ |klass| klass.tests }.flatten
|
21
|
+
formatter.before_suite(test_classes)
|
22
|
+
start = Time.now
|
23
|
+
|
24
|
+
test_classes.each do |test_class|
|
25
|
+
formatter.before_class(test_class)
|
26
|
+
test_class.tests.shuffle.each do |test|
|
27
|
+
@active_test = test
|
28
|
+
if @options[:async]
|
29
|
+
@tests ||= Queue.new
|
30
|
+
@tests << test
|
31
|
+
else
|
32
|
+
test.invoke(@formatter, @options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
formatter.after_class(test_class)
|
36
|
+
end
|
37
|
+
|
38
|
+
run_threads if @options[:async]
|
39
|
+
|
40
|
+
@duration = Time.now - start
|
41
|
+
@passed = tests.select{ |test| test.passed? }.count
|
42
|
+
@failed = tests.select{ |test| !test.passed? }.count
|
43
|
+
formatter.after_results(self)
|
44
|
+
formatter.after_suite(test_classes)
|
45
|
+
@failed
|
46
|
+
end
|
47
|
+
|
48
|
+
def reset
|
49
|
+
@duration = 0
|
50
|
+
@passed = 0
|
51
|
+
@failed = 0
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def run_threads
|
57
|
+
threads = []
|
58
|
+
thread_count = OS.cpu_count
|
59
|
+
thread_count = 2 if thread_count < 2
|
60
|
+
puts "PryTest is running #{thread_count} threads."
|
61
|
+
thread_count.times do
|
62
|
+
threads << Thread.new do
|
63
|
+
while @tests.empty? == false
|
64
|
+
Thread.current.kill if PryTest::Runner.exit
|
65
|
+
@tests.pop.invoke(@formatter, @options)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
threads.each { |t| t.join }
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module PryTest
|
2
|
+
|
3
|
+
# Superclass for all test classes.
|
4
|
+
# @example Create a subclass with a test.
|
5
|
+
# class SimpleTest < PryTest::Test
|
6
|
+
# test "common sense" do
|
7
|
+
# assert 1 > 0
|
8
|
+
# end
|
9
|
+
# end
|
10
|
+
class Test
|
11
|
+
class << self
|
12
|
+
|
13
|
+
# All subclasses of this class.
|
14
|
+
# @return [Array<PryTest::Test>]
|
15
|
+
def subclasses
|
16
|
+
@subclasses ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
# All individual tests defined in this class.
|
20
|
+
# @return [Array<PryTest::TestWrapper>]
|
21
|
+
def tests
|
22
|
+
@tests ||= []
|
23
|
+
end
|
24
|
+
|
25
|
+
# All files that define subclasses of this class.
|
26
|
+
# @note Primarily used in the context of PryTest::Test.
|
27
|
+
# @example Files are stored in a Hash with the following format.
|
28
|
+
# {
|
29
|
+
# "path/to/file1.rb" => ["line 1", "line 2", "line 3", ...],
|
30
|
+
# "path/to/file2.rb" => ["line 1", "line 2", "line 3", ...]
|
31
|
+
# }
|
32
|
+
# @return [Hash]
|
33
|
+
def files
|
34
|
+
@files ||= {}
|
35
|
+
end
|
36
|
+
|
37
|
+
# Resets the state in preparation for a new test run.
|
38
|
+
def reset
|
39
|
+
tests.each { |test| test.reset }
|
40
|
+
subclasses.each { |subclass| subclass.reset }
|
41
|
+
end
|
42
|
+
|
43
|
+
# A callback provided by Ruby that is invoked whenever a subclass is created.
|
44
|
+
def inherited(subclass)
|
45
|
+
file_path = caller[0][0, caller[0].index(/:[0-9]+:/)]
|
46
|
+
files[file_path] = File.open(file_path).readlines
|
47
|
+
subclasses << subclass
|
48
|
+
end
|
49
|
+
|
50
|
+
# Defines a setup method that will run before each individual test.
|
51
|
+
# @param [Symbol] what Deprecated but maintained for backwards compatibility.
|
52
|
+
# @yield A block of code that will serve as the setup method.
|
53
|
+
def before(what=nil, &block)
|
54
|
+
@before = block
|
55
|
+
end
|
56
|
+
|
57
|
+
# Defines a teardown method that will run after each individual test.
|
58
|
+
# @param [Symbol] what Deprecated but maintained for backwards compatibility.
|
59
|
+
# @yield A block of code that will serve as the teardown method.
|
60
|
+
def after(what=nil, &block)
|
61
|
+
@after = block
|
62
|
+
end
|
63
|
+
|
64
|
+
# Defines a test.
|
65
|
+
# Allows subclasses to define tests in their class definition.
|
66
|
+
#
|
67
|
+
# @param [String] desc A description for the test.
|
68
|
+
# @yield A block that defines the test code.
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# class SimpleTest < PryTest::Test
|
72
|
+
# test "common sense" do
|
73
|
+
# assert 1 > 0
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
def test(desc, &block)
|
77
|
+
wrapper = PryTest::TestWrapper.new(self, desc, &block)
|
78
|
+
wrapper.create_method(:before, &@before) if @before
|
79
|
+
wrapper.create_method(:after, &@after) if @after
|
80
|
+
tests << wrapper
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require "monitor"
|
2
|
+
|
3
|
+
module PryTest
|
4
|
+
|
5
|
+
# A wrapper class for individual tests.
|
6
|
+
# Exists for the purpose of isolating the test method so it can run in its own thread.
|
7
|
+
class TestWrapper
|
8
|
+
include MonitorMixin
|
9
|
+
attr_reader :test_class, :desc, :asserts
|
10
|
+
|
11
|
+
# Constructor.
|
12
|
+
# @param [PryTest::Test] test_class The test class that defines the test being wrapped.
|
13
|
+
# @param [String] desc The test description.
|
14
|
+
# @yield The block that defines the test code.
|
15
|
+
def initialize(test_class, desc, &block)
|
16
|
+
super() # inits MonitorMixin
|
17
|
+
@test_class = test_class
|
18
|
+
@desc = desc
|
19
|
+
create_method(:test, &block)
|
20
|
+
reset
|
21
|
+
end
|
22
|
+
|
23
|
+
# Creates a method on this instance.
|
24
|
+
# @param [Symbol] name The name of the method.
|
25
|
+
# @yield The block of code that will serve as the method's implementation.
|
26
|
+
def create_method(name, &block)
|
27
|
+
eigen = class << self; self; end
|
28
|
+
eigen.send(:define_method, name, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
# callback stubs
|
32
|
+
def before; end
|
33
|
+
def after; end
|
34
|
+
|
35
|
+
# Runs the test code.
|
36
|
+
# @formatter [PryTest::Formatter] The formatter to use.
|
37
|
+
# @options [Hash]
|
38
|
+
def invoke(formatter, options={})
|
39
|
+
reset
|
40
|
+
@formatter = formatter
|
41
|
+
@options = options
|
42
|
+
@formatter.before_test(self)
|
43
|
+
start = Time.now
|
44
|
+
before
|
45
|
+
test
|
46
|
+
@invoked = true
|
47
|
+
after
|
48
|
+
@duration = Time.now - start
|
49
|
+
@formatter.after_test(self)
|
50
|
+
end
|
51
|
+
|
52
|
+
# A basic assert method to be used within tests.
|
53
|
+
#
|
54
|
+
# @param [Object] value The value to assert.
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# class SimpleTest < PryTest::Test
|
58
|
+
# test "common sense" do
|
59
|
+
# assert 1 > 0
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
def assert(value)
|
63
|
+
@asserts << assert_info(caller).merge(:value => value)
|
64
|
+
|
65
|
+
if !value
|
66
|
+
binding.pry(:quiet => true) unless @options[:disable_pry]
|
67
|
+
|
68
|
+
# I don't really like the coupling to the runner here
|
69
|
+
PryTest::Runner.exit = true if @options[:fail_fast]
|
70
|
+
end
|
71
|
+
|
72
|
+
value
|
73
|
+
end
|
74
|
+
|
75
|
+
# Indicates if this test has finished running.
|
76
|
+
# @return [Boolean]
|
77
|
+
def finished?
|
78
|
+
!@duration.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
# Indicates if this test passed.
|
82
|
+
def passed?
|
83
|
+
return true if !@invoked || @asserts.empty?
|
84
|
+
return false if @asserts.empty?
|
85
|
+
@asserts.map{ |a| !!a[:value] }.uniq == [true]
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns a list of all failed asserts.
|
89
|
+
def failed_asserts
|
90
|
+
return [] if passed?
|
91
|
+
@asserts.select { |a| !a[:value] }
|
92
|
+
end
|
93
|
+
|
94
|
+
# Resets this test in preparation for a clean test run.
|
95
|
+
def reset
|
96
|
+
@invoked = false
|
97
|
+
@asserts = []
|
98
|
+
@duration = nil
|
99
|
+
end
|
100
|
+
|
101
|
+
# Rounded duration.
|
102
|
+
def duration
|
103
|
+
return nil if @duration.nil?
|
104
|
+
(@duration * 10**4).ceil.to_f / 10**4
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
# Builds a Hash of assert information for the given call stack.
|
110
|
+
#
|
111
|
+
# @param [Array<String>] stack The call stack to extract info from.
|
112
|
+
#
|
113
|
+
# @example
|
114
|
+
# {
|
115
|
+
# :file_path => "/path/to/test_file.rb",
|
116
|
+
# :line_num => 100,
|
117
|
+
# :line => " assert 'something' do"
|
118
|
+
# }
|
119
|
+
#
|
120
|
+
# @return [Hash]
|
121
|
+
def assert_info(stack)
|
122
|
+
file_path = stack[0][0, stack[0].index(/:[0-9]+:/)]
|
123
|
+
lines = PryTest::Test.files[file_path]
|
124
|
+
line_num = line_number(stack, 0)
|
125
|
+
line_index = line_num - 1
|
126
|
+
line = lines[line_index]
|
127
|
+
{
|
128
|
+
:file_path => file_path,
|
129
|
+
:lines => lines,
|
130
|
+
:line_num => line_num,
|
131
|
+
:line => line
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns a line number from a call stack.
|
136
|
+
# @param [Array<String>] stack The call stack to pull a path from.
|
137
|
+
# @param [Integer] index The index of the call stack entry to use.
|
138
|
+
# @return [String]
|
139
|
+
def line_number(stack, index)
|
140
|
+
stack[index].scan(/:[0-9]+:/).first.gsub(/:/, "").to_i
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
data/test/color_test.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
unless ENV["MT_DEMO"]
|
2
|
+
require_relative "test_helper"
|
3
|
+
|
4
|
+
class ColorTest < PryTest::Test
|
5
|
+
class Crayon
|
6
|
+
include PryTest::Color
|
7
|
+
end
|
8
|
+
CRAYON = Crayon.new
|
9
|
+
|
10
|
+
test "red" do
|
11
|
+
assert PryTest::Color.red("foo") == "\e[31mfoo\e[0m"
|
12
|
+
assert ColorTest::CRAYON.red("foo") == "\e[31mfoo\e[0m"
|
13
|
+
end
|
14
|
+
|
15
|
+
test "green" do
|
16
|
+
assert PryTest::Color.green("foo") == "\e[32mfoo\e[0m"
|
17
|
+
assert ColorTest::CRAYON.green("foo") == "\e[32mfoo\e[0m"
|
18
|
+
end
|
19
|
+
|
20
|
+
test "yellow" do
|
21
|
+
assert PryTest::Color.yellow("foo") == "\e[33mfoo\e[0m"
|
22
|
+
assert ColorTest::CRAYON.yellow("foo") == "\e[33mfoo\e[0m"
|
23
|
+
end
|
24
|
+
|
25
|
+
test "blue" do
|
26
|
+
assert PryTest::Color.blue("foo") == "\e[34mfoo\e[0m"
|
27
|
+
assert ColorTest::CRAYON.blue("foo") == "\e[34mfoo\e[0m"
|
28
|
+
end
|
29
|
+
|
30
|
+
test "magenta" do
|
31
|
+
assert PryTest::Color.magenta("foo") == "\e[35mfoo\e[0m"
|
32
|
+
assert ColorTest::CRAYON.magenta("foo") == "\e[35mfoo\e[0m"
|
33
|
+
end
|
34
|
+
|
35
|
+
test "cyan" do
|
36
|
+
assert PryTest::Color.cyan("foo") == "\e[36mfoo\e[0m"
|
37
|
+
assert ColorTest::CRAYON.cyan("foo") == "\e[36mfoo\e[0m"
|
38
|
+
end
|
39
|
+
|
40
|
+
test "white" do
|
41
|
+
assert PryTest::Color.white("foo") == "\e[37mfoo\e[0m"
|
42
|
+
assert ColorTest::CRAYON.white("foo") == "\e[37mfoo\e[0m"
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
if ENV["MT_DEMO"]
|
2
|
+
require_relative "test_helper"
|
3
|
+
|
4
|
+
class TestCPULatency < PryTest::Test
|
5
|
+
|
6
|
+
before do
|
7
|
+
@count = 35
|
8
|
+
end
|
9
|
+
|
10
|
+
test "fibonacci recursion 1" do
|
11
|
+
@count.times { |i| TestCPULatency.fib(i) }
|
12
|
+
assert true
|
13
|
+
end
|
14
|
+
|
15
|
+
test "fibonacci recursion 2" do
|
16
|
+
@count.times { |i| TestCPULatency.fib(i) }
|
17
|
+
assert true
|
18
|
+
end
|
19
|
+
|
20
|
+
test "fibonacci recursion 3" do
|
21
|
+
@count.times { |i| TestCPULatency.fib(i) }
|
22
|
+
assert true
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.fib(n)
|
26
|
+
n < 2 ? n : fib(n-1) + fib(n-2)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/test/fail_test.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
if ENV["MT_DEMO"]
|
2
|
+
require_relative "test_helper"
|
3
|
+
|
4
|
+
class Fail < PryTest::Test
|
5
|
+
|
6
|
+
before do
|
7
|
+
@var = "fubar"
|
8
|
+
end
|
9
|
+
|
10
|
+
test "fail on purpose" do
|
11
|
+
# Failing on purpose for the demo.
|
12
|
+
# Use pry to check out the current binding.
|
13
|
+
# For example, type @var.
|
14
|
+
assert false
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
if ENV["MT_DEMO"]
|
2
|
+
require_relative "test_helper"
|
3
|
+
|
4
|
+
class TestIOLatency < PryTest::Test
|
5
|
+
|
6
|
+
test "sleep 1 sec" do
|
7
|
+
sleep 1
|
8
|
+
assert true
|
9
|
+
end
|
10
|
+
|
11
|
+
test "sleep another 1 sec" do
|
12
|
+
sleep 1
|
13
|
+
assert true
|
14
|
+
end
|
15
|
+
|
16
|
+
test "sleep a third 1 sec" do
|
17
|
+
sleep 1
|
18
|
+
assert true
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/test/runner_test.rb
ADDED
data/test/test_helper.rb
ADDED
data/test/test_test.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
unless ENV["MT_DEMO"]
|
2
|
+
require_relative "test_helper"
|
3
|
+
|
4
|
+
class TestTest < PryTest::Test
|
5
|
+
|
6
|
+
before do
|
7
|
+
@test_test = TestTest.clone
|
8
|
+
@test_test.instance_eval { @subclasses = [] }
|
9
|
+
@test_test.instance_eval { @tests = [] }
|
10
|
+
@Example = Class.new(@test_test) do
|
11
|
+
before {}
|
12
|
+
after {}
|
13
|
+
test("truth") { assert true }
|
14
|
+
end
|
15
|
+
@before_callback = @Example.before
|
16
|
+
@after_callback = @Example.after
|
17
|
+
end
|
18
|
+
|
19
|
+
test "adds subclass" do
|
20
|
+
assert @test_test.subclasses.length == 1
|
21
|
+
assert @test_test.subclasses[0] == @Example
|
22
|
+
end
|
23
|
+
|
24
|
+
test "stores subclasses" do
|
25
|
+
assert @test_test.subclasses.is_a?(Array)
|
26
|
+
assert @test_test.subclasses.length == 1
|
27
|
+
assert @test_test.subclasses.first == @Example
|
28
|
+
end
|
29
|
+
|
30
|
+
test "stores tests" do
|
31
|
+
assert @Example.tests.is_a?(Array)
|
32
|
+
assert @Example.tests.length == 1
|
33
|
+
assert @Example.tests.first.is_a?(PryTest::TestWrapper)
|
34
|
+
end
|
35
|
+
|
36
|
+
test "stores files" do
|
37
|
+
file = __FILE__
|
38
|
+
assert @test_test.files[file].is_a?(Array)
|
39
|
+
assert @test_test.files[file].select{ |l| l.start_with?(" assert @test_test.files[file].select{ |l| l.start_with?(") }.length > 0
|
40
|
+
end
|
41
|
+
|
42
|
+
test ".reset" do
|
43
|
+
@Example.tests.first.instance_eval do
|
44
|
+
@asserts = nil
|
45
|
+
@duration = nil
|
46
|
+
end
|
47
|
+
@Example.reset
|
48
|
+
assert @Example.tests.length == 1
|
49
|
+
assert @Example.tests.first.asserts == []
|
50
|
+
assert @Example.tests.first.duration == nil
|
51
|
+
end
|
52
|
+
|
53
|
+
test ".before" do
|
54
|
+
assert @Example.instance_eval { @before } == @before_callback
|
55
|
+
end
|
56
|
+
|
57
|
+
test ".after" do
|
58
|
+
assert @Example.instance_eval { @after } == @after_callback
|
59
|
+
end
|
60
|
+
|
61
|
+
test "tests" do
|
62
|
+
t = lambda {}
|
63
|
+
@Example.send :test, :add_a_test, &t
|
64
|
+
assert @Example.tests.length == 2
|
65
|
+
assert @Example.tests.last.is_a?(PryTest::TestWrapper)
|
66
|
+
assert @Example.tests.last.desc == :add_a_test
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
unless ENV["MT_DEMO"]
|
2
|
+
require_relative "test_helper"
|
3
|
+
|
4
|
+
class TestWrapperTest < PryTest::Test
|
5
|
+
|
6
|
+
test ".new" do
|
7
|
+
desc = "test_#{rand(999**10)}"
|
8
|
+
meth = lambda { ".new" }
|
9
|
+
t = PryTest::TestWrapper.new(TestWrapperTest, desc, &meth)
|
10
|
+
assert t.desc == desc
|
11
|
+
assert t.test == ".new"
|
12
|
+
assert t.passed?
|
13
|
+
assert t.finished? == false
|
14
|
+
assert t.duration.nil?
|
15
|
+
assert t.asserts.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pry-test
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nathan Hopkins
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: os
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: coveralls
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: A testing framework that supports debugging test failures & errors as
|
56
|
+
they happen.
|
57
|
+
email:
|
58
|
+
- natehop@gmail.com
|
59
|
+
executables:
|
60
|
+
- pry-test
|
61
|
+
extensions:
|
62
|
+
- ext/mkrf_conf.rb
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- bin/pry-test
|
66
|
+
- ext/mkrf_conf.rb
|
67
|
+
- lib/pry-test.rb
|
68
|
+
- lib/pry-test/formatters/base_formatter.rb
|
69
|
+
- lib/pry-test/formatters/color.rb
|
70
|
+
- lib/pry-test/formatters/default_async_formatter.rb
|
71
|
+
- lib/pry-test/formatters/default_formatter.rb
|
72
|
+
- lib/pry-test/formatters/template.rb
|
73
|
+
- lib/pry-test/formatters/views/default/assert_fail.txt.erb
|
74
|
+
- lib/pry-test/formatters/views/default/class.txt.erb
|
75
|
+
- lib/pry-test/formatters/views/default/suite.txt.erb
|
76
|
+
- lib/pry-test/formatters/views/default/test_fail.txt.erb
|
77
|
+
- lib/pry-test/formatters/views/default/test_pass.txt.erb
|
78
|
+
- lib/pry-test/formatters/views/default_async/test.txt.erb
|
79
|
+
- lib/pry-test/runner.rb
|
80
|
+
- lib/pry-test/test.rb
|
81
|
+
- lib/pry-test/test_wrapper.rb
|
82
|
+
- lib/pry-test/version.rb
|
83
|
+
- test/color_test.rb
|
84
|
+
- test/cpu_latency_test.rb
|
85
|
+
- test/fail_test.rb
|
86
|
+
- test/io_latency_test.rb
|
87
|
+
- test/runner_test.rb
|
88
|
+
- test/test_helper.rb
|
89
|
+
- test/test_test.rb
|
90
|
+
- test/test_wrapper_test.rb
|
91
|
+
homepage: https://github.com/hopsoft/pry-test
|
92
|
+
licenses:
|
93
|
+
- MIT
|
94
|
+
metadata: {}
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.9.2
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
requirements: []
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 2.2.2
|
112
|
+
signing_key:
|
113
|
+
specification_version: 4
|
114
|
+
summary: A testing framework that supports debugging test failures & errors as they
|
115
|
+
happen.
|
116
|
+
test_files:
|
117
|
+
- test/color_test.rb
|
118
|
+
- test/cpu_latency_test.rb
|
119
|
+
- test/fail_test.rb
|
120
|
+
- test/io_latency_test.rb
|
121
|
+
- test/runner_test.rb
|
122
|
+
- test/test_helper.rb
|
123
|
+
- test/test_test.rb
|
124
|
+
- test/test_wrapper_test.rb
|