byebug 0.0.1
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.
- data/.gitignore +10 -0
- data/.travis.yml +8 -0
- data/AUTHORS +10 -0
- data/CHANGELOG.md +2 -0
- data/CONTRIBUTING.md +1 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +5 -0
- data/Rakefile +28 -0
- data/bin/byebug +395 -0
- data/byebug.gemspec +29 -0
- data/doc/hanoi.rb +35 -0
- data/doc/primes.rb +28 -0
- data/doc/rdebug-emacs.texi +1030 -0
- data/doc/test-tri2.rb +18 -0
- data/doc/tri3.rb +8 -0
- data/doc/triangle.rb +12 -0
- data/ext/byebug/breakpoint.c +476 -0
- data/ext/byebug/byebug.c +512 -0
- data/ext/byebug/byebug.h +131 -0
- data/ext/byebug/context.c +424 -0
- data/ext/byebug/extconf.rb +21 -0
- data/ext/byebug/locker.c +53 -0
- data/lib/byebug.rb +404 -0
- data/lib/byebug/command.rb +232 -0
- data/lib/byebug/commands/breakpoints.rb +153 -0
- data/lib/byebug/commands/catchpoint.rb +56 -0
- data/lib/byebug/commands/condition.rb +49 -0
- data/lib/byebug/commands/continue.rb +38 -0
- data/lib/byebug/commands/control.rb +110 -0
- data/lib/byebug/commands/display.rb +122 -0
- data/lib/byebug/commands/edit.rb +48 -0
- data/lib/byebug/commands/enable.rb +202 -0
- data/lib/byebug/commands/eval.rb +176 -0
- data/lib/byebug/commands/finish.rb +43 -0
- data/lib/byebug/commands/frame.rb +303 -0
- data/lib/byebug/commands/help.rb +56 -0
- data/lib/byebug/commands/info.rb +462 -0
- data/lib/byebug/commands/irb.rb +123 -0
- data/lib/byebug/commands/jump.rb +66 -0
- data/lib/byebug/commands/kill.rb +51 -0
- data/lib/byebug/commands/list.rb +94 -0
- data/lib/byebug/commands/method.rb +84 -0
- data/lib/byebug/commands/quit.rb +39 -0
- data/lib/byebug/commands/reload.rb +40 -0
- data/lib/byebug/commands/save.rb +90 -0
- data/lib/byebug/commands/set.rb +210 -0
- data/lib/byebug/commands/show.rb +246 -0
- data/lib/byebug/commands/skip.rb +35 -0
- data/lib/byebug/commands/source.rb +36 -0
- data/lib/byebug/commands/stepping.rb +83 -0
- data/lib/byebug/commands/threads.rb +189 -0
- data/lib/byebug/commands/tmate.rb +36 -0
- data/lib/byebug/commands/trace.rb +56 -0
- data/lib/byebug/commands/variables.rb +199 -0
- data/lib/byebug/context.rb +58 -0
- data/lib/byebug/helper.rb +69 -0
- data/lib/byebug/interface.rb +223 -0
- data/lib/byebug/processor.rb +468 -0
- data/lib/byebug/version.rb +3 -0
- data/man/rdebug.1 +241 -0
- data/test/breakpoints_test.rb +357 -0
- data/test/conditions_test.rb +77 -0
- data/test/continue_test.rb +44 -0
- data/test/display_test.rb +141 -0
- data/test/edit_test.rb +56 -0
- data/test/eval_test.rb +92 -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 +20 -0
- data/test/examples/frame_threads.rb +31 -0
- data/test/examples/help.rb +2 -0
- data/test/examples/info.rb +38 -0
- data/test/examples/info2.rb +3 -0
- data/test/examples/info_threads.rb +48 -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 +48 -0
- data/test/frame_test.rb +143 -0
- data/test/help_test.rb +50 -0
- data/test/info_test.rb +313 -0
- data/test/irb_test.rb +81 -0
- data/test/jump_test.rb +70 -0
- data/test/kill_test.rb +48 -0
- data/test/list_test.rb +145 -0
- data/test/method_test.rb +70 -0
- data/test/post_mortem_test.rb +27 -0
- data/test/quit_test.rb +56 -0
- data/test/reload_test.rb +44 -0
- data/test/restart_test.rb +164 -0
- data/test/save_test.rb +92 -0
- data/test/set_test.rb +177 -0
- data/test/show_test.rb +293 -0
- data/test/source_test.rb +45 -0
- data/test/stepping_test.rb +130 -0
- data/test/support/breakpoint.rb +13 -0
- data/test/support/context.rb +14 -0
- data/test/support/matchers.rb +67 -0
- data/test/support/mocha_extensions.rb +72 -0
- data/test/support/processor.rb +7 -0
- data/test/support/test_dsl.rb +206 -0
- data/test/support/test_interface.rb +68 -0
- data/test/test_helper.rb +10 -0
- data/test/tmate_test.rb +44 -0
- data/test/trace_test.rb +159 -0
- data/test/variables_test.rb +119 -0
- metadata +265 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
module Byebug
|
2
|
+
class Context
|
3
|
+
|
4
|
+
def inspect
|
5
|
+
values = %w{
|
6
|
+
thread thnum stop_reason tracing ignored? stack_size dead? frame_line frame_file frame_self
|
7
|
+
}.map do |field|
|
8
|
+
"#{field}: #{send(field)}"
|
9
|
+
end.join(", ")
|
10
|
+
"#<Byebug::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,72 @@
|
|
1
|
+
module Mocha
|
2
|
+
|
3
|
+
class Expectation
|
4
|
+
|
5
|
+
# Allows to specify a block to execute when expectation will be matched.
|
6
|
+
# This way, we can specify dynamic values to return or just make some side effects
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# foo.expects(:bar).with('bla').calls { 2 + 3 }
|
11
|
+
# foo.bar('bla') # => 5
|
12
|
+
#
|
13
|
+
def calls(&block)
|
14
|
+
@calls ||= Call.new
|
15
|
+
@calls += Call.new(block)
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def invoke_with_calls(arguments, &block)
|
20
|
+
invoke_without_calls(&block) || (@calls.next(arguments, &block) if @calls)
|
21
|
+
end
|
22
|
+
alias_method :invoke_without_calls, :invoke
|
23
|
+
alias_method :invoke, :invoke_with_calls
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
class Mock
|
28
|
+
|
29
|
+
# We monkey-patch that method to be able to pass arguments to Expectation#invoke method
|
30
|
+
def method_missing(symbol, *arguments, &block)
|
31
|
+
if @responder and not @responder.respond_to?(symbol)
|
32
|
+
raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
|
33
|
+
end
|
34
|
+
if matching_expectation_allowing_invocation = @expectations.match_allowing_invocation(symbol, *arguments)
|
35
|
+
# We change this line - added arguments
|
36
|
+
matching_expectation_allowing_invocation.invoke(arguments, &block)
|
37
|
+
else
|
38
|
+
if (matching_expectation = @expectations.match(symbol, *arguments)) || (!matching_expectation && !@everything_stubbed)
|
39
|
+
# We change this line - added arguments
|
40
|
+
matching_expectation.invoke(arguments, &block) if matching_expectation
|
41
|
+
message = UnexpectedInvocation.new(self, symbol, *arguments).to_s
|
42
|
+
require 'mocha/mockery'
|
43
|
+
message << Mockery.instance.mocha_inspect
|
44
|
+
raise ExpectationError.new(message, caller)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
class Call
|
52
|
+
|
53
|
+
attr_reader :blocks
|
54
|
+
|
55
|
+
def initialize(*blocks)
|
56
|
+
@blocks = [ *blocks ]
|
57
|
+
end
|
58
|
+
|
59
|
+
def next(arguments, &block)
|
60
|
+
case @blocks.length
|
61
|
+
when 0 then nil
|
62
|
+
when 1 then @blocks.first.call(*arguments, &block)
|
63
|
+
else @blocks.shift.call(*arguments, &block)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def +(other)
|
68
|
+
self.class.new(*(@blocks + other.blocks))
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
module TestDsl
|
2
|
+
|
3
|
+
module Shared
|
4
|
+
def fullpath(filename)
|
5
|
+
(Pathname.new(__FILE__) + "../../examples/#{filename}.rb").cleanpath.to_s
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
include Shared
|
10
|
+
|
11
|
+
def self.included(base)
|
12
|
+
base.class_eval do
|
13
|
+
extend ClassMethods
|
14
|
+
before do
|
15
|
+
Byebug.interface = TestInterface.new
|
16
|
+
Byebug.handler.display.clear
|
17
|
+
end
|
18
|
+
after do
|
19
|
+
Byebug.handler.display.clear
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Adds commands to the input queue, so they will be later retrieved by
|
25
|
+
# Processor, i.e. it emulates user's input.
|
26
|
+
#
|
27
|
+
# If a command is a Proc object, it will be executed before retrieving by
|
28
|
+
# Processor. May be handy when you need build a command depending on the
|
29
|
+
# current context/state.
|
30
|
+
#
|
31
|
+
# Usage:
|
32
|
+
# enter 'b 12'
|
33
|
+
# enter 'b 12', 'cont'
|
34
|
+
# enter ['b 12', 'cont']
|
35
|
+
# enter 'b 12', ->{"disable #{breakpoint.id}"}, 'cont'
|
36
|
+
#
|
37
|
+
def enter(*messages)
|
38
|
+
messages = messages.first.is_a?(Array) ? messages.first : messages
|
39
|
+
interface.input_queue.concat(messages)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Runs a byebug with the provided basename for a file. The file should be
|
43
|
+
# placed in the test/examples dir.
|
44
|
+
#
|
45
|
+
# You also can specify a block, which will be executed when Processor extracts
|
46
|
+
# all the commands from the input queue. You can use it e.g. for making
|
47
|
+
# asserts for the current test. If you specified the block, and it never was
|
48
|
+
# executed, the test will fail.
|
49
|
+
#
|
50
|
+
# Usage:
|
51
|
+
# debug "ex1" # ex1 should be placed in test/examples/ex1.rb
|
52
|
+
#
|
53
|
+
# enter 'b 4', 'cont'
|
54
|
+
# debug("ex1") { state.line.must_equal 4 }
|
55
|
+
#
|
56
|
+
def debug_file(filename, &block)
|
57
|
+
is_test_block_called = false
|
58
|
+
debug_completed = false
|
59
|
+
exception = nil
|
60
|
+
Byebug.stubs(:run_init_script)
|
61
|
+
if block
|
62
|
+
interface.test_block= lambda do
|
63
|
+
is_test_block_called = true
|
64
|
+
# We need to store exception and reraise it after completing debugging,
|
65
|
+
# because Byebug will swallow any exceptions, so e.g. our failed
|
66
|
+
# assertions will be ignored
|
67
|
+
begin
|
68
|
+
block.call
|
69
|
+
rescue Exception => e
|
70
|
+
exception = e
|
71
|
+
raise e
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
Byebug.start do
|
76
|
+
load fullpath(filename)
|
77
|
+
debug_completed = true
|
78
|
+
end
|
79
|
+
flunk "Debug block was not completed" unless debug_completed
|
80
|
+
flunk "Test block was provided, but not called" if block && !is_test_block_called
|
81
|
+
raise exception if exception
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# Checks the output of byebug. By default it checks output queue of the current
|
86
|
+
# interface, but you can check again any queue by providing it as a second
|
87
|
+
# argument.
|
88
|
+
#
|
89
|
+
# Usage:
|
90
|
+
# enter 'break 4', 'cont'
|
91
|
+
# debug("ex1")
|
92
|
+
# check_output "Breakpoint 1 at #{fullpath('ex1')}:4"
|
93
|
+
#
|
94
|
+
def check_output(check_method, *args)
|
95
|
+
queue = args.last.is_a?(String) || args.last.is_a?(Regexp) ? interface.output_queue : args.pop
|
96
|
+
queue_messages = queue.map(&:strip)
|
97
|
+
messages = Array(args).map { |msg| msg.is_a?(String) ? msg.strip : msg }
|
98
|
+
queue_messages.send(check_method, messages)
|
99
|
+
end
|
100
|
+
|
101
|
+
def check_output_includes(*args)
|
102
|
+
check_output :must_include_in_order, *args
|
103
|
+
end
|
104
|
+
|
105
|
+
def check_output_doesnt_include(*args)
|
106
|
+
check_output :wont_include_in_order, *args
|
107
|
+
end
|
108
|
+
|
109
|
+
def interface
|
110
|
+
Byebug.handler.interface
|
111
|
+
end
|
112
|
+
|
113
|
+
def state
|
114
|
+
$rdebug_state
|
115
|
+
end
|
116
|
+
|
117
|
+
def context
|
118
|
+
state.context
|
119
|
+
end
|
120
|
+
|
121
|
+
def breakpoint
|
122
|
+
Byebug.breakpoints.first
|
123
|
+
end
|
124
|
+
|
125
|
+
def force_set_const(klass, const, value)
|
126
|
+
klass.send(:remove_const, const) if klass.const_defined?(const)
|
127
|
+
klass.const_set(const, value)
|
128
|
+
end
|
129
|
+
|
130
|
+
def change_line_in_file(file, line, new_line_content)
|
131
|
+
old_content = File.read(file)
|
132
|
+
new_content = old_content.split("\n").tap { |c| c[line - 1] = new_line_content }.join("\n")
|
133
|
+
File.open(file, 'w') { |f| f.write(new_content) }
|
134
|
+
end
|
135
|
+
|
136
|
+
def temporary_change_method_value(item, method, value)
|
137
|
+
old = item.send(method)
|
138
|
+
item.send("#{method}=", value)
|
139
|
+
yield
|
140
|
+
ensure
|
141
|
+
item.send("#{method}=", old)
|
142
|
+
end
|
143
|
+
|
144
|
+
def temporary_change_hash_value(item, key, value)
|
145
|
+
old_value = item[key]
|
146
|
+
item[key] = value
|
147
|
+
yield
|
148
|
+
ensure
|
149
|
+
item[key] = old_value
|
150
|
+
end
|
151
|
+
|
152
|
+
def temporary_set_const(klass, const, value)
|
153
|
+
old_value = klass.const_defined?(const) ? klass.const_get(const) : :__undefined__
|
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
|
+
|
164
|
+
module ClassMethods
|
165
|
+
|
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
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class TestInterface < Byebug::Interface
|
2
|
+
attr_reader :input_queue, :output_queue, :error_queue, :confirm_queue
|
3
|
+
|
4
|
+
attr_accessor :command_queue, :histfile, :history_length, :history_save
|
5
|
+
attr_accessor :print_queue, :readline_support, :restart_file, :test_block
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@input_queue = []
|
9
|
+
@output_queue = []
|
10
|
+
@error_queue = []
|
11
|
+
@confirm_queue = []
|
12
|
+
@command_queue = []
|
13
|
+
@print_queue = []
|
14
|
+
@readline_support = false
|
15
|
+
end
|
16
|
+
|
17
|
+
def errmsg(*args)
|
18
|
+
@error_queue << format(args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def read_command(*args)
|
22
|
+
if @input_queue.empty? && test_block
|
23
|
+
test_block.call
|
24
|
+
self.test_block = nil
|
25
|
+
end
|
26
|
+
result = @input_queue.shift
|
27
|
+
result.is_a?(Proc) ? result.call : result
|
28
|
+
end
|
29
|
+
|
30
|
+
def print(*args)
|
31
|
+
@output_queue << format(args)
|
32
|
+
end
|
33
|
+
|
34
|
+
def confirm(message)
|
35
|
+
@confirm_queue << message
|
36
|
+
read_command message
|
37
|
+
end
|
38
|
+
|
39
|
+
def readline_support?
|
40
|
+
@readline_support
|
41
|
+
end
|
42
|
+
|
43
|
+
def finalize
|
44
|
+
end
|
45
|
+
|
46
|
+
def close
|
47
|
+
end
|
48
|
+
|
49
|
+
def inspect
|
50
|
+
[
|
51
|
+
"input_queue: #{input_queue.inspect}",
|
52
|
+
"output_queue: #{output_queue.inspect}",
|
53
|
+
"error_queue: #{error_queue.inspect}",
|
54
|
+
"confirm_queue: #{confirm_queue.inspect}",
|
55
|
+
"print_queue: #{print_queue.inspect}"
|
56
|
+
].join("\n")
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def format(args)
|
62
|
+
if args.size > 1
|
63
|
+
args.first % args[1..-1]
|
64
|
+
else
|
65
|
+
args.first
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|