debugger2 1.0.0.beta1
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 +12 -0
- data/.travis.yml +3 -0
- data/AUTHORS +10 -0
- data/CHANGELOG.md +65 -0
- data/CONTRIBUTING.md +1 -0
- data/Gemfile +3 -0
- data/LICENSE +23 -0
- data/OLDER_CHANGELOG +334 -0
- data/OLD_CHANGELOG +5655 -0
- data/OLD_README +122 -0
- data/README.md +108 -0
- data/Rakefile +78 -0
- data/bin/rdebug +397 -0
- data/debugger2.gemspec +29 -0
- data/doc/.cvsignore +42 -0
- data/doc/Makefile.am +63 -0
- data/doc/emacs-notes.txt +38 -0
- data/doc/hanoi.rb +35 -0
- data/doc/primes.rb +28 -0
- data/doc/rdebug-emacs.texi +1030 -0
- data/doc/ruby-debug.texi +3791 -0
- data/doc/test-tri2.rb +18 -0
- data/doc/tri3.rb +8 -0
- data/doc/triangle.rb +12 -0
- data/emacs/Makefile.am +130 -0
- data/emacs/rdebug-annotate.el +385 -0
- data/emacs/rdebug-breaks.el +407 -0
- data/emacs/rdebug-cmd.el +92 -0
- data/emacs/rdebug-core.el +502 -0
- data/emacs/rdebug-dbg.el +62 -0
- data/emacs/rdebug-error.el +79 -0
- data/emacs/rdebug-fns.el +111 -0
- data/emacs/rdebug-frames.el +230 -0
- data/emacs/rdebug-gud.el +242 -0
- data/emacs/rdebug-help.el +104 -0
- data/emacs/rdebug-info.el +83 -0
- data/emacs/rdebug-layouts.el +180 -0
- data/emacs/rdebug-locring.el +118 -0
- data/emacs/rdebug-output.el +106 -0
- data/emacs/rdebug-regexp.el +118 -0
- data/emacs/rdebug-secondary.el +260 -0
- data/emacs/rdebug-shortkey.el +175 -0
- data/emacs/rdebug-source.el +568 -0
- data/emacs/rdebug-track.el +392 -0
- data/emacs/rdebug-varbuf.el +150 -0
- data/emacs/rdebug-vars.el +125 -0
- data/emacs/rdebug-watch.el +132 -0
- data/emacs/rdebug.el +326 -0
- data/emacs/test/elk-test.el +242 -0
- data/emacs/test/test-annotate.el +103 -0
- data/emacs/test/test-cmd.el +116 -0
- data/emacs/test/test-core.el +104 -0
- data/emacs/test/test-fns.el +65 -0
- data/emacs/test/test-frames.el +62 -0
- data/emacs/test/test-gud.el +35 -0
- data/emacs/test/test-indent.el +58 -0
- data/emacs/test/test-regexp.el +144 -0
- data/emacs/test/test-shortkey.el +61 -0
- data/ext/ruby_debug/breakpoint.c +630 -0
- data/ext/ruby_debug/extconf.rb +11 -0
- data/ext/ruby_debug/ruby_debug.c +2203 -0
- data/ext/ruby_debug/ruby_debug.h +151 -0
- data/lib/debugger.rb +5 -0
- data/lib/debugger/version.rb +5 -0
- data/lib/debugger2.rb +6 -0
- data/lib/ruby-debug-base.rb +307 -0
- data/lib/ruby-debug.rb +176 -0
- data/lib/ruby-debug/command.rb +227 -0
- data/lib/ruby-debug/commands/breakpoints.rb +153 -0
- data/lib/ruby-debug/commands/catchpoint.rb +55 -0
- data/lib/ruby-debug/commands/condition.rb +49 -0
- data/lib/ruby-debug/commands/continue.rb +38 -0
- data/lib/ruby-debug/commands/control.rb +107 -0
- data/lib/ruby-debug/commands/display.rb +120 -0
- data/lib/ruby-debug/commands/edit.rb +48 -0
- data/lib/ruby-debug/commands/enable.rb +202 -0
- data/lib/ruby-debug/commands/eval.rb +176 -0
- data/lib/ruby-debug/commands/finish.rb +42 -0
- data/lib/ruby-debug/commands/frame.rb +301 -0
- data/lib/ruby-debug/commands/help.rb +56 -0
- data/lib/ruby-debug/commands/info.rb +467 -0
- data/lib/ruby-debug/commands/irb.rb +123 -0
- data/lib/ruby-debug/commands/jump.rb +66 -0
- data/lib/ruby-debug/commands/kill.rb +51 -0
- data/lib/ruby-debug/commands/list.rb +94 -0
- data/lib/ruby-debug/commands/method.rb +84 -0
- data/lib/ruby-debug/commands/quit.rb +39 -0
- data/lib/ruby-debug/commands/reload.rb +40 -0
- data/lib/ruby-debug/commands/save.rb +90 -0
- data/lib/ruby-debug/commands/set.rb +223 -0
- data/lib/ruby-debug/commands/show.rb +247 -0
- data/lib/ruby-debug/commands/skip.rb +35 -0
- data/lib/ruby-debug/commands/source.rb +36 -0
- data/lib/ruby-debug/commands/stepping.rb +81 -0
- data/lib/ruby-debug/commands/threads.rb +189 -0
- data/lib/ruby-debug/commands/tmate.rb +36 -0
- data/lib/ruby-debug/commands/trace.rb +57 -0
- data/lib/ruby-debug/commands/variables.rb +199 -0
- data/lib/ruby-debug/debugger.rb +5 -0
- data/lib/ruby-debug/helper.rb +69 -0
- data/lib/ruby-debug/interface.rb +232 -0
- data/lib/ruby-debug/processor.rb +474 -0
- data/man/rdebug.1 +241 -0
- data/old_scripts/Makefile.am +14 -0
- data/old_scripts/README.md +2 -0
- data/old_scripts/autogen.sh +4 -0
- data/old_scripts/configure.ac +12 -0
- data/old_scripts/rdbg.rb +33 -0
- data/old_scripts/runner.sh +7 -0
- data/old_scripts/svn2cl_usermap +3 -0
- data/test/.cvsignore +1 -0
- data/test/breakpoints_test.rb +366 -0
- data/test/conditions_test.rb +77 -0
- data/test/continue_test.rb +28 -0
- data/test/display_test.rb +143 -0
- data/test/edit_test.rb +55 -0
- data/test/eval_test.rb +94 -0
- data/test/examples/breakpoint1.rb +15 -0
- data/test/examples/breakpoint2.rb +7 -0
- data/test/examples/conditions.rb +4 -0
- data/test/examples/continue.rb +4 -0
- data/test/examples/display.rb +5 -0
- data/test/examples/edit.rb +3 -0
- data/test/examples/edit2.rb +3 -0
- data/test/examples/eval.rb +4 -0
- data/test/examples/finish.rb +20 -0
- data/test/examples/frame.rb +31 -0
- data/test/examples/help.rb +2 -0
- data/test/examples/info.rb +48 -0
- data/test/examples/info2.rb +3 -0
- data/test/examples/irb.rb +6 -0
- data/test/examples/jump.rb +14 -0
- data/test/examples/kill.rb +2 -0
- data/test/examples/list.rb +12 -0
- data/test/examples/method.rb +15 -0
- data/test/examples/post_mortem.rb +19 -0
- data/test/examples/quit.rb +2 -0
- data/test/examples/reload.rb +6 -0
- data/test/examples/restart.rb +6 -0
- data/test/examples/save.rb +3 -0
- data/test/examples/set.rb +3 -0
- data/test/examples/set_annotate.rb +12 -0
- data/test/examples/settings.rb +1 -0
- data/test/examples/show.rb +2 -0
- data/test/examples/source.rb +3 -0
- data/test/examples/stepping.rb +21 -0
- data/test/examples/thread.rb +32 -0
- data/test/examples/tmate.rb +10 -0
- data/test/examples/trace.rb +7 -0
- data/test/examples/trace_threads.rb +20 -0
- data/test/examples/variables.rb +26 -0
- data/test/finish_test.rb +49 -0
- data/test/frame_test.rb +140 -0
- data/test/help_test.rb +51 -0
- data/test/info_test.rb +326 -0
- data/test/irb_test.rb +82 -0
- data/test/jump_test.rb +70 -0
- data/test/kill_test.rb +49 -0
- data/test/list_test.rb +147 -0
- data/test/method_test.rb +72 -0
- data/test/post_mortem_test.rb +25 -0
- data/test/quit_test.rb +56 -0
- data/test/reload_test.rb +47 -0
- data/test/restart_test.rb +145 -0
- data/test/save_test.rb +94 -0
- data/test/set_test.rb +183 -0
- data/test/show_test.rb +294 -0
- data/test/source_test.rb +46 -0
- data/test/stepping_test.rb +122 -0
- data/test/support/breakpoint.rb +12 -0
- data/test/support/context.rb +14 -0
- data/test/support/matchers.rb +67 -0
- data/test/support/mocha_extensions.rb +71 -0
- data/test/support/processor.rb +7 -0
- data/test/support/test_dsl.rb +206 -0
- data/test/support/test_interface.rb +66 -0
- data/test/test_helper.rb +9 -0
- data/test/thread_test.rb +124 -0
- data/test/tmate_test.rb +45 -0
- data/test/trace_test.rb +156 -0
- data/test/variables_test.rb +116 -0
- metadata +319 -0
data/test/source_test.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
describe "Source Command" do
|
4
|
+
include TestDsl
|
5
|
+
|
6
|
+
let(:filename) { 'source_example.txt' }
|
7
|
+
before do
|
8
|
+
File.open(filename, 'w') do |f|
|
9
|
+
f.puts 'break 2'
|
10
|
+
f.puts 'break 3 if true'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
after do
|
14
|
+
FileUtils.rm(filename)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "must run commands from file" do
|
18
|
+
enter "source #{filename}"
|
19
|
+
debug_file 'source' do
|
20
|
+
Debugger.breakpoints[0].pos.must_equal 2
|
21
|
+
Debugger.breakpoints[1].pos.must_equal 3
|
22
|
+
Debugger.breakpoints[1].expr.must_equal "true"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "must be able to use shortcut" do
|
27
|
+
enter "so #{filename}"
|
28
|
+
debug_file('source') { Debugger.breakpoints[0].pos.must_equal 2 }
|
29
|
+
end
|
30
|
+
|
31
|
+
it "must show an error if file is not found" do
|
32
|
+
enter "source blabla"
|
33
|
+
debug_file 'source'
|
34
|
+
check_output_includes /Command file '.*blabla' is not found/, interface.error_queue
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "Post Mortem" do
|
38
|
+
it "must work in post-mortem mode"
|
39
|
+
|
40
|
+
0.times do
|
41
|
+
enter 'cont', "so #{filename}"
|
42
|
+
debug_file('post_mortem') { Debugger.breakpoints[0].pos.must_equal 3 }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
describe "Stepping Commands" do
|
4
|
+
include TestDsl
|
5
|
+
|
6
|
+
describe "Next Command" do
|
7
|
+
describe "Usual mode" do
|
8
|
+
before { enter 'break 10', 'cont' }
|
9
|
+
|
10
|
+
it "must go to the next line if forced by a setting" do
|
11
|
+
temporary_change_hash_value(Debugger::Command.settings, :force_stepping, true) do
|
12
|
+
enter 'next'
|
13
|
+
debug_file('stepping') { state.line.must_equal 11 }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "must go to the next line by shortcut" do
|
18
|
+
temporary_change_hash_value(Debugger::Command.settings, :force_stepping, true) do
|
19
|
+
enter 'n'
|
20
|
+
debug_file('stepping') { state.line.must_equal 11 }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "must leave on the same line if forced by a setting" do
|
25
|
+
temporary_change_hash_value(Debugger::Command.settings, :force_stepping, false) do
|
26
|
+
enter 'next'
|
27
|
+
debug_file('stepping') { state.line.must_equal 10 }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "must go to the specified number of lines forward by default" do
|
32
|
+
temporary_change_hash_value(Debugger::Command.settings, :force_stepping, true) do
|
33
|
+
enter 'next 2'
|
34
|
+
debug_file('stepping') { state.line.must_equal 21 }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it "must go to the next line if forced to do that by 'plus' sign" do
|
39
|
+
enter 'next+'
|
40
|
+
debug_file('stepping') { state.line.must_equal 11 }
|
41
|
+
end
|
42
|
+
|
43
|
+
it "must leave on the same line if forced to do that by 'minus' sign" do
|
44
|
+
enter 'next-'
|
45
|
+
debug_file('stepping') { state.line.must_equal 10 }
|
46
|
+
end
|
47
|
+
|
48
|
+
it "must ignore the setting if 'minus' is specified" do
|
49
|
+
enter 'next-'
|
50
|
+
debug_file('stepping') { state.line.must_equal 10 }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "Post Mortem" do
|
55
|
+
temporary_change_hash_value(Debugger::Command.settings, :autoeval, false)
|
56
|
+
it "must not work in post-mortem mode"
|
57
|
+
|
58
|
+
0.times do
|
59
|
+
enter 'cont', "next"
|
60
|
+
debug_file('post_mortem')
|
61
|
+
check_output_includes 'Unknown command: "next". Try "help".', interface.error_queue
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
describe "Step Command" do
|
68
|
+
describe "Usual mode" do
|
69
|
+
before { enter 'break 10', 'cont' }
|
70
|
+
|
71
|
+
it "must go to the step line if forced by a setting" do
|
72
|
+
temporary_change_hash_value(Debugger::Command.settings, :force_stepping, true) do
|
73
|
+
enter 'step'
|
74
|
+
debug_file('stepping') { state.line.must_equal 11 }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it "must go to the next line by shortcut" do
|
79
|
+
temporary_change_hash_value(Debugger::Command.settings, :force_stepping, true) do
|
80
|
+
enter 's'
|
81
|
+
debug_file('stepping') { state.line.must_equal 11 }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "must leave on the same line if forced by a setting" do
|
86
|
+
temporary_change_hash_value(Debugger::Command.settings, :force_stepping, false) do
|
87
|
+
enter 'step'
|
88
|
+
debug_file('stepping') { state.line.must_equal 10 }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it "must go to the specified number of lines forward by default" do
|
93
|
+
temporary_change_hash_value(Debugger::Command.settings, :force_stepping, true) do
|
94
|
+
enter 'step 2'
|
95
|
+
debug_file('stepping') { state.line.must_equal 15 }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
it "must go to the step line if forced to do that by 'plus' sign" do
|
100
|
+
enter 'step+'
|
101
|
+
debug_file('stepping') { state.line.must_equal 11 }
|
102
|
+
end
|
103
|
+
|
104
|
+
it "must leave on the same line if forced to do that by 'minus' sign" do
|
105
|
+
enter 'step-'
|
106
|
+
debug_file('stepping') { state.line.must_equal 10 }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "Post Mortem" do
|
111
|
+
temporary_change_hash_value(Debugger::Command.settings, :autoeval, false)
|
112
|
+
it "must not work in post-mortem mode"
|
113
|
+
|
114
|
+
0.times do
|
115
|
+
enter 'cont', "step"
|
116
|
+
debug_file('post_mortem')
|
117
|
+
check_output_includes 'Unknown command: "step". Try "help".', interface.error_queue
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Debugger
|
2
|
+
class Context
|
3
|
+
|
4
|
+
def inspect
|
5
|
+
values = %w{
|
6
|
+
thread thnum stop_reason suspended? tracing ignored? stack_size dead? frame_line frame_file frame_self
|
7
|
+
}.map do |field|
|
8
|
+
"#{field}: #{send(field)}"
|
9
|
+
end.join(", ")
|
10
|
+
"#<Debugger::Context #{values}>"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module MiniTest::Assertions
|
2
|
+
|
3
|
+
# This matcher checks that given collection is included into the original collection,
|
4
|
+
# and in correct order. It accepts both strings and regexps.
|
5
|
+
#
|
6
|
+
# Examples:
|
7
|
+
#
|
8
|
+
# assert_includes_in_order(%w{1 2 3 4 5}, %w{1 3 5}) # => pass
|
9
|
+
# assert_includes_in_order(%w{1 2 3 4 5}, %w{1 5 3}) # => fail
|
10
|
+
# assert_includes_in_order(w{1 2 3 4 5}, ["1", /\d+/, "5"]) # => pass
|
11
|
+
# assert_includes_in_order(w{1 2 3 4 5}, ["1", /\[a-z]+/, "5"]) # => fail
|
12
|
+
#
|
13
|
+
def assert_includes_in_order(given_collection, original_collection, msg = nil)
|
14
|
+
msg = message(msg) do
|
15
|
+
"Expected #{mu_pp(original_collection)} to include #{mu_pp(given_collection)} in order"
|
16
|
+
end
|
17
|
+
assert includes_in_order_result(original_collection, given_collection), msg
|
18
|
+
end
|
19
|
+
|
20
|
+
def refute_includes_in_order(given_collection, original_collection, msg = nil)
|
21
|
+
msg = message(msg) do
|
22
|
+
"Expected #{mu_pp(original_collection)} to not include #{mu_pp(given_collection)} in order"
|
23
|
+
end
|
24
|
+
refute includes_in_order_result(original_collection, given_collection), msg
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def includes_in_order_result(original_collection, given_collection)
|
31
|
+
result = true
|
32
|
+
given_collection.each do |given_item|
|
33
|
+
result &&= case given_item
|
34
|
+
when String
|
35
|
+
index = original_collection.index(given_item)
|
36
|
+
if index
|
37
|
+
original_collection = original_collection[(index + 1)..-1]
|
38
|
+
true
|
39
|
+
else
|
40
|
+
false
|
41
|
+
end
|
42
|
+
when Regexp
|
43
|
+
index = nil
|
44
|
+
original_collection.each_with_index do |original_item, i|
|
45
|
+
if original_item =~ given_item
|
46
|
+
index = i
|
47
|
+
break
|
48
|
+
end
|
49
|
+
end
|
50
|
+
if index
|
51
|
+
original_collection = original_collection[(index + 1)..-1]
|
52
|
+
true
|
53
|
+
else
|
54
|
+
false
|
55
|
+
end
|
56
|
+
else
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
result
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module MiniTest::Expectations
|
65
|
+
infect_an_assertion :assert_includes_in_order, :must_include_in_order
|
66
|
+
infect_an_assertion :refute_includes_in_order, :wont_include_in_order
|
67
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Mocha
|
2
|
+
class Expectation
|
3
|
+
|
4
|
+
# Allows to specify a block to execute when expectation will be matched.
|
5
|
+
# This way, we can specify dynamic values to return or just make some side effects
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# foo.expects(:bar).with('bla').calls { 2 + 3 }
|
10
|
+
# foo.bar('bla') # => 5
|
11
|
+
#
|
12
|
+
def calls(&block)
|
13
|
+
@calls ||= Call.new
|
14
|
+
@calls += Call.new(block)
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def invoke_with_calls(arguments, &block)
|
19
|
+
invoke_without_calls(&block) || (@calls.next(arguments, &block) if @calls)
|
20
|
+
end
|
21
|
+
alias_method :invoke_without_calls, :invoke
|
22
|
+
alias_method :invoke, :invoke_with_calls
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class Mock
|
27
|
+
|
28
|
+
# We monkey-patch that method to be able to pass arguments to Expectation#invoke method
|
29
|
+
def method_missing(symbol, *arguments, &block)
|
30
|
+
if @responder and not @responder.respond_to?(symbol)
|
31
|
+
raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
|
32
|
+
end
|
33
|
+
if matching_expectation_allowing_invocation = @expectations.match_allowing_invocation(symbol, *arguments)
|
34
|
+
# We change this line - added arguments
|
35
|
+
matching_expectation_allowing_invocation.invoke(arguments, &block)
|
36
|
+
else
|
37
|
+
if (matching_expectation = @expectations.match(symbol, *arguments)) || (!matching_expectation && !@everything_stubbed)
|
38
|
+
# We change this line - added arguments
|
39
|
+
matching_expectation.invoke(arguments, &block) if matching_expectation
|
40
|
+
message = UnexpectedInvocation.new(self, symbol, *arguments).to_s
|
41
|
+
require 'mocha/mockery'
|
42
|
+
message << Mockery.instance.mocha_inspect
|
43
|
+
raise ExpectationError.new(message, caller)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
class Call
|
51
|
+
|
52
|
+
attr_reader :blocks
|
53
|
+
|
54
|
+
def initialize(*blocks)
|
55
|
+
@blocks = [ *blocks ]
|
56
|
+
end
|
57
|
+
|
58
|
+
def next(arguments, &block)
|
59
|
+
case @blocks.length
|
60
|
+
when 0 then nil
|
61
|
+
when 1 then @blocks.first.call(*arguments, &block)
|
62
|
+
else @blocks.shift.call(*arguments, &block)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def +(other)
|
67
|
+
self.class.new(*(@blocks + other.blocks))
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
module TestDsl
|
2
|
+
module Shared
|
3
|
+
def fullpath(filename)
|
4
|
+
(Pathname.new(__FILE__) + "../../examples/#{filename}.rb").cleanpath.to_s
|
5
|
+
end
|
6
|
+
end
|
7
|
+
include Shared
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
extend ClassMethods
|
12
|
+
|
13
|
+
#before do
|
14
|
+
Debugger.interface = TestInterface.new
|
15
|
+
Debugger.handler.display.clear
|
16
|
+
#end
|
17
|
+
after do
|
18
|
+
Debugger.handler.display.clear
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Adds commands to the input queue, so they will be retrieved by Processor later.
|
24
|
+
# I.e. it emulates user's input.
|
25
|
+
#
|
26
|
+
# If a command is a Proc object, it will be executed before retrieving by Processor.
|
27
|
+
# May be handy when you need build a command depending on the current context/state.
|
28
|
+
#
|
29
|
+
# Usage:
|
30
|
+
#
|
31
|
+
# enter 'b 12'
|
32
|
+
# enter 'b 12', 'cont'
|
33
|
+
# enter ['b 12', 'cont']
|
34
|
+
# enter 'b 12', ->{"disable #{breakpoint.id}"}, 'cont'
|
35
|
+
#
|
36
|
+
def enter(*messages)
|
37
|
+
messages = messages.first.is_a?(Array) ? messages.first : messages
|
38
|
+
interface.input_queue.concat(messages)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Runs a debugger with the provided basename for a file. The file should be placed
|
42
|
+
# to the test/new/examples dir.
|
43
|
+
#
|
44
|
+
# You also can specify block, which will be executed when Processor extracts all the
|
45
|
+
# commands from the input queue. You can use it e.g. for making asserts for the current
|
46
|
+
# test. If you specified the block, and it never was executed, the test will fail.
|
47
|
+
#
|
48
|
+
# Usage:
|
49
|
+
#
|
50
|
+
# debug "ex1" # ex1 should be placed in test/new/examples/ex1.rb
|
51
|
+
#
|
52
|
+
# enter 'b 4', 'cont'
|
53
|
+
# debug("ex1") { state.line.must_equal 4 } # It will be executed after running 'cont' and stopping at the breakpoint
|
54
|
+
#
|
55
|
+
def debug_file(filename, &block)
|
56
|
+
is_test_block_called = false
|
57
|
+
debug_completed = false
|
58
|
+
exception = nil
|
59
|
+
Debugger.stubs(:run_init_script)
|
60
|
+
if block
|
61
|
+
interface.test_block = lambda do
|
62
|
+
is_test_block_called = true
|
63
|
+
# We need to store exception and reraise it after completing debugging, because
|
64
|
+
# Debugger will swallow any exceptions, so e.g. our failed assertions will be ignored
|
65
|
+
begin
|
66
|
+
block.call
|
67
|
+
rescue Exception => e
|
68
|
+
exception = e
|
69
|
+
raise e
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
Debugger.start do
|
74
|
+
load fullpath(filename)
|
75
|
+
debug_completed = true
|
76
|
+
end
|
77
|
+
flunk "Debug block was not completed" unless debug_completed
|
78
|
+
flunk "test block is provided, but not called" if block && !is_test_block_called
|
79
|
+
raise exception if exception
|
80
|
+
end
|
81
|
+
|
82
|
+
# Checks the output of the debugger. By default it checks output queue of the current interface,
|
83
|
+
# but you can check again any queue by providing it as a second argument.
|
84
|
+
#
|
85
|
+
# Usage:
|
86
|
+
#
|
87
|
+
# enter 'break 4', 'cont'
|
88
|
+
# debug("ex1")
|
89
|
+
# check_output "Breakpoint 1 at #{fullpath('ex1')}:4"
|
90
|
+
#
|
91
|
+
def check_output(check_method, *args)
|
92
|
+
queue = args.last.is_a?(String) || args.last.is_a?(Regexp) ? interface.output_queue : args.pop
|
93
|
+
queue_messages = queue.map(&:strip)
|
94
|
+
messages = Array(args).map { |msg| msg.is_a?(String) ? msg.strip : msg }
|
95
|
+
queue_messages.send(check_method, messages)
|
96
|
+
end
|
97
|
+
|
98
|
+
def check_output_includes(*args)
|
99
|
+
check_output :must_include_in_order, *args
|
100
|
+
end
|
101
|
+
|
102
|
+
def check_output_doesnt_include(*args)
|
103
|
+
check_output :wont_include_in_order, *args
|
104
|
+
end
|
105
|
+
|
106
|
+
def interface
|
107
|
+
Debugger.handler.interface
|
108
|
+
end
|
109
|
+
|
110
|
+
def state
|
111
|
+
$rdebug_state
|
112
|
+
end
|
113
|
+
|
114
|
+
def context
|
115
|
+
state.context
|
116
|
+
end
|
117
|
+
|
118
|
+
def breakpoint
|
119
|
+
Debugger.breakpoints.first
|
120
|
+
end
|
121
|
+
|
122
|
+
def force_set_const(klass, const, value)
|
123
|
+
klass.send(:remove_const, const) if klass.const_defined?(const)
|
124
|
+
klass.const_set(const, value)
|
125
|
+
end
|
126
|
+
|
127
|
+
def change_line_in_file(file, line, new_line_content)
|
128
|
+
old_content = File.read(file)
|
129
|
+
new_content = old_content.split("\n").tap { |c| c[line - 1] = new_line_content }.join("\n")
|
130
|
+
File.open(file, 'w') { |f| f.write(new_content) }
|
131
|
+
end
|
132
|
+
|
133
|
+
def temporary_change_method_value(item, method, value)
|
134
|
+
old = item.send(method)
|
135
|
+
item.send("#{method}=", value)
|
136
|
+
yield
|
137
|
+
ensure
|
138
|
+
item.send("#{method}=", old)
|
139
|
+
end
|
140
|
+
|
141
|
+
def temporary_change_hash_value(item, key, value)
|
142
|
+
old_value = item[key]
|
143
|
+
begin
|
144
|
+
item[key] = value
|
145
|
+
yield
|
146
|
+
ensure
|
147
|
+
item[key] = old_value
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def temporary_set_const(klass, const, value)
|
152
|
+
old_value = klass.const_defined?(const) ? klass.const_get(const) : :__undefined__
|
153
|
+
begin
|
154
|
+
force_set_const(klass, const, value)
|
155
|
+
yield
|
156
|
+
ensure
|
157
|
+
if old_value == :__undefined__
|
158
|
+
klass.send(:remove_const, const)
|
159
|
+
else
|
160
|
+
force_set_const(klass, const, old_value)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
module ClassMethods
|
166
|
+
include Shared
|
167
|
+
|
168
|
+
def temporary_change_method_value(item, method, value)
|
169
|
+
old_value = nil
|
170
|
+
before do
|
171
|
+
old_value = item.send(method)
|
172
|
+
item.send("#{method}=", value)
|
173
|
+
end
|
174
|
+
after do
|
175
|
+
item.send("#{method}=", old_value)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def temporary_change_hash_value(item, key, value)
|
180
|
+
old_value = nil
|
181
|
+
before do
|
182
|
+
old_value = item[key]
|
183
|
+
item[key] = value
|
184
|
+
end
|
185
|
+
after do
|
186
|
+
item[key] = old_value
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def temporary_set_const(klass, const, value)
|
191
|
+
old_value = nil
|
192
|
+
before do
|
193
|
+
old_value = klass.const_defined?(const) ? klass.const_get(const) : :__undefined__
|
194
|
+
force_set_const(klass, const, value)
|
195
|
+
end
|
196
|
+
after do
|
197
|
+
if old_value == :__undefined__
|
198
|
+
klass.send(:remove_const, const)
|
199
|
+
else
|
200
|
+
force_set_const(klass, const, old_value)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|