1 # frozen_string_literal: false
5 require 'rubygems' if defined?(Gem)
8 class TestContext < Test::Unit::TestCase
9 class TestInputMethod < ::IRB::InputMethod
10 attr_reader :list, :line_no
12 def initialize(list = [])
19 @list[@line_no]&.tap {@line_no += 1}
23 @line_no >= @list.size
27 Encoding.default_external
41 IRB.conf[:USE_SINGLELINE] = false
42 IRB.conf[:VERBOSE] = false
43 workspace = IRB::WorkSpace.new(Object.new)
44 @context = IRB::Context.new(nil, workspace, TestInputMethod.new)
46 @get_screen_size = Reline.method(:get_screen_size)
47 Reline.instance_eval { undef :get_screen_size }
48 def Reline.get_screen_size
54 Reline.instance_eval { undef :get_screen_size }
55 Reline.define_singleton_method(:get_screen_size, @get_screen_size)
59 assert_nil(@context.last_value)
60 assert_nil(@context.evaluate('_', 1))
62 @context.set_last_value(obj)
63 assert_same(obj, @context.last_value)
64 assert_same(obj, @context.evaluate('_', 1))
67 def test_evaluate_with_exception
68 assert_nil(@context.evaluate("$!", 1))
69 e = assert_raise_with_message(RuntimeError, 'foo') {
70 @context.evaluate("raise 'foo'", 1)
72 assert_equal('foo', e.message)
73 assert_same(e, @context.evaluate('$!', 1, exception: e))
74 e = assert_raise(SyntaxError) {
75 @context.evaluate("1,2,3", 1, exception: e)
77 assert_match(/\A\(irb\):1:/, e.message)
78 assert_not_match(/rescue _\.class/, e.message)
81 def test_evaluate_with_encoding_error_without_lineno
82 pend if RUBY_ENGINE == 'truffleruby'
83 assert_raise_with_message(EncodingError, /invalid symbol/) {
84 @context.evaluate(%q[{"\xAE": 1}], 1)
85 # The backtrace of this invalid encoding hash doesn't contain lineno.
89 def test_evaluate_with_onigmo_warning
90 pend if RUBY_ENGINE == 'truffleruby'
91 assert_warning("(irb):1: warning: character class has duplicated range: /[aa]/\n") do
92 @context.evaluate('/[aa]/', 1)
97 pend if RUBY_ENGINE == 'truffleruby'
98 verbose, $VERBOSE = $VERBOSE, nil
99 input = TestInputMethod.new([
105 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
106 out, err = capture_output do
110 assert_pattern_list([:*, /\(irb\):1:in `<main>': Foo \(RuntimeError\)\n/,
111 :*, /#<RuntimeError: Foo>\n/,
119 def test_eval_input_raise2x
120 pend if RUBY_ENGINE == 'truffleruby'
121 input = TestInputMethod.new([
126 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
127 out, err = capture_output do
131 assert_pattern_list([
132 :*, /\(irb\):1:in `<main>': Foo \(RuntimeError\)\n/,
133 :*, /\(irb\):2:in `<main>': Bar \(RuntimeError\)\n/,
134 :*, /#<RuntimeError: Bar>\n/,
138 def test_eval_object_without_inspect_method
139 verbose, $VERBOSE = $VERBOSE, nil
140 all_assertions do |all|
141 IRB::Inspector::INSPECTORS.invert.each_value do |mode|
143 input = TestInputMethod.new([
144 "[BasicObject.new, Class.new]\n",
146 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
147 irb.context.inspect_mode = mode
148 out, err = capture_output do
152 assert_match(/\(Object doesn't support #inspect\)\n(=> )?\n/, out)
160 def test_default_config
161 assert_equal(true, @context.use_colorize?)
162 assert_equal(true, @context.use_autocomplete?)
165 def test_assignment_expression
166 input = TestInputMethod.new
167 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
185 "foo; foo = bar; ;\n ;",
189 irb.assignment_expression?(exp),
190 "#{exp.inspect}: should be an assignment expression"
202 irb.assignment_expression?(exp),
203 "#{exp.inspect}: should not be an assignment expression"
208 def test_echo_on_assignment
209 input = TestInputMethod.new([
218 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
219 irb.context.return_format = "=> %s\n"
222 irb.context.echo = true
223 irb.context.echo_on_assignment = false
224 out, err = capture_output do
228 assert_equal("=> 1\n=> 2\n=> 3\n=> 4\n", out)
230 # Everything is output, like before echo_on_assignment was introduced
232 irb.context.echo = true
233 irb.context.echo_on_assignment = true
234 out, err = capture_output do
238 assert_equal("=> 1\n=> 1\n=> [2, 3]\n=> 2\n=> 3\n=> 4\n=> 4\n", out)
240 # Nothing is output when echo is false
242 irb.context.echo = false
243 irb.context.echo_on_assignment = false
244 out, err = capture_output do
248 assert_equal("", out)
250 # Nothing is output when echo is false even if echo_on_assignment is true
252 irb.context.echo = false
253 irb.context.echo_on_assignment = true
254 out, err = capture_output do
258 assert_equal("", out)
261 def test_omit_on_assignment
262 IRB.conf[:USE_COLORIZE] = false
263 input = TestInputMethod.new([
268 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
269 irb.context.return_format = "=> %s\n"
271 irb.context.echo = true
272 irb.context.echo_on_assignment = false
273 out, err = capture_output do
277 assert_equal("=> \n#{value.pretty_inspect}", out)
280 irb.context.echo = true
281 irb.context.echo_on_assignment = :truncate
282 out, err = capture_output do
286 assert_equal("=> \n#{value.pretty_inspect[0..3]}...\n=> \n#{value.pretty_inspect}", out)
289 irb.context.echo = true
290 irb.context.echo_on_assignment = true
291 out, err = capture_output do
295 assert_equal("=> \n#{value.pretty_inspect}=> \n#{value.pretty_inspect}", out)
298 irb.context.echo = false
299 irb.context.echo_on_assignment = false
300 out, err = capture_output do
304 assert_equal("", out)
307 irb.context.echo = false
308 irb.context.echo_on_assignment = :truncate
309 out, err = capture_output do
313 assert_equal("", out)
316 irb.context.echo = false
317 irb.context.echo_on_assignment = true
318 out, err = capture_output do
322 assert_equal("", out)
325 def test_omit_multiline_on_assignment
326 IRB.conf[:USE_COLORIZE] = false
327 input = TestInputMethod.new([
328 "class A; def inspect; ([?* * 1000] * 3).join(%{\\n}); end; end; a = A.new\n",
331 value = ([?* * 1000] * 3).join(%{\n})
332 value_first_line = (?* * 1000).to_s
333 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
334 irb.context.return_format = "=> %s\n"
336 irb.context.echo = true
337 irb.context.echo_on_assignment = false
338 out, err = capture_output do
342 assert_equal("=> \n#{value}\n", out)
343 irb.context.evaluate('A.remove_method(:inspect)', 0)
346 irb.context.echo = true
347 irb.context.echo_on_assignment = :truncate
348 out, err = capture_output do
352 assert_equal("=> #{value_first_line[0..(input.winsize.last - 9)]}...\n=> \n#{value}\n", out)
353 irb.context.evaluate('A.remove_method(:inspect)', 0)
356 irb.context.echo = true
357 irb.context.echo_on_assignment = true
358 out, err = capture_output do
362 assert_equal("=> \n#{value}\n=> \n#{value}\n", out)
363 irb.context.evaluate('A.remove_method(:inspect)', 0)
366 irb.context.echo = false
367 irb.context.echo_on_assignment = false
368 out, err = capture_output do
372 assert_equal("", out)
373 irb.context.evaluate('A.remove_method(:inspect)', 0)
376 irb.context.echo = false
377 irb.context.echo_on_assignment = :truncate
378 out, err = capture_output do
382 assert_equal("", out)
383 irb.context.evaluate('A.remove_method(:inspect)', 0)
386 irb.context.echo = false
387 irb.context.echo_on_assignment = true
388 out, err = capture_output do
392 assert_equal("", out)
393 irb.context.evaluate('A.remove_method(:inspect)', 0)
396 def test_echo_on_assignment_conf
398 IRB.conf[:ECHO] = nil
399 IRB.conf[:ECHO_ON_ASSIGNMENT] = nil
400 IRB.conf[:USE_COLORIZE] = false
401 input = TestInputMethod.new()
402 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
404 assert(irb.context.echo?, "echo? should be true by default")
405 assert_equal(:truncate, irb.context.echo_on_assignment?, "echo_on_assignment? should be :truncate by default")
407 # Explicitly set :ECHO to false
408 IRB.conf[:ECHO] = false
409 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
411 refute(irb.context.echo?, "echo? should be false when IRB.conf[:ECHO] is set to false")
412 assert_equal(:truncate, irb.context.echo_on_assignment?, "echo_on_assignment? should be :truncate by default")
414 # Explicitly set :ECHO_ON_ASSIGNMENT to true
415 IRB.conf[:ECHO] = nil
416 IRB.conf[:ECHO_ON_ASSIGNMENT] = false
417 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
419 assert(irb.context.echo?, "echo? should be true by default")
420 refute(irb.context.echo_on_assignment?, "echo_on_assignment? should be false when IRB.conf[:ECHO_ON_ASSIGNMENT] is set to false")
423 def test_multiline_output_on_default_inspector
428 IRB.conf[:USE_COLORIZE] = false
429 input = TestInputMethod.new([
432 irb = IRB::Irb.new(IRB::WorkSpace.new(main), input)
433 irb.context.return_format = "=> %s\n"
436 irb.context.newline_before_multiline_output = true
437 out, err = capture_output do
441 assert_equal("=> \nabc\ndef\n",
444 # No newline before multiline output
446 irb.context.newline_before_multiline_output = false
447 out, err = capture_output do
451 assert_equal("=> abc\ndef\n",
455 def test_default_return_format
456 IRB.conf[:PROMPT][:MY_PROMPT] = {
457 :PROMPT_I => "%03n> ",
458 :PROMPT_N => "%03n> ",
459 :PROMPT_S => "%03n> ",
460 :PROMPT_C => "%03n> "
464 IRB.conf[:PROMPT_MODE] = :MY_PROMPT
465 input = TestInputMethod.new([
468 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
469 out, err = capture_output do
477 def test_eval_input_with_exception
478 pend if RUBY_ENGINE == 'truffleruby'
479 verbose, $VERBOSE = $VERBOSE, nil
480 input = TestInputMethod.new([
481 "def hoge() fuga; end; def fuga() raise; end; hoge\n",
483 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
484 out, err = capture_output do
488 if '2.5.0' <= RUBY_VERSION && RUBY_VERSION < '3.0.0' && STDOUT.tty?
490 :*, /Traceback \(most recent call last\):\n/,
491 :*, /\t 2: from \(irb\):1:in `<main>'\n/,
492 :*, /\t 1: from \(irb\):1:in `hoge'\n/,
493 :*, /\(irb\):1:in `fuga': unhandled exception\n/,
497 :*, /\(irb\):1:in `fuga': unhandled exception\n/,
498 :*, /\tfrom \(irb\):1:in `hoge'\n/,
499 :*, /\tfrom \(irb\):1:in `<main>'\n/,
503 assert_pattern_list(expected, out)
508 def test_eval_input_with_invalid_byte_sequence_exception
509 pend if RUBY_ENGINE == 'truffleruby'
510 verbose, $VERBOSE = $VERBOSE, nil
511 input = TestInputMethod.new([
512 %Q{def hoge() fuga; end; def fuga() raise "A\\xF3B"; end; hoge\n},
514 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
515 out, err = capture_output do
519 if '2.5.0' <= RUBY_VERSION && RUBY_VERSION < '3.0.0' && STDOUT.tty?
521 :*, /Traceback \(most recent call last\):\n/,
522 :*, /\t 2: from \(irb\):1:in `<main>'\n/,
523 :*, /\t 1: from \(irb\):1:in `hoge'\n/,
524 :*, /\(irb\):1:in `fuga': A\\xF3B \(RuntimeError\)\n/,
528 :*, /\(irb\):1:in `fuga': A\\xF3B \(RuntimeError\)\n/,
529 :*, /\tfrom \(irb\):1:in `hoge'\n/,
530 :*, /\tfrom \(irb\):1:in `<main>'\n/,
534 assert_pattern_list(expected, out)
539 def test_eval_input_with_long_exception
540 pend if RUBY_ENGINE == 'truffleruby'
541 verbose, $VERBOSE = $VERBOSE, nil
545 generated_code << "def a#{i}() a#{i + 1}; end; "
547 generated_code << "def a#{nesting}() raise; end; a0\n"
548 input = TestInputMethod.new([
551 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
552 out, err = capture_output do
556 if '2.5.0' <= RUBY_VERSION && RUBY_VERSION < '3.0.0' && STDOUT.tty?
558 :*, /Traceback \(most recent call last\):\n/,
559 :*, /\t... \d+ levels...\n/,
560 :*, /\t16: from \(irb\):1:in `a4'\n/,
561 :*, /\t15: from \(irb\):1:in `a5'\n/,
562 :*, /\t14: from \(irb\):1:in `a6'\n/,
563 :*, /\t13: from \(irb\):1:in `a7'\n/,
564 :*, /\t12: from \(irb\):1:in `a8'\n/,
565 :*, /\t11: from \(irb\):1:in `a9'\n/,
566 :*, /\t10: from \(irb\):1:in `a10'\n/,
567 :*, /\t 9: from \(irb\):1:in `a11'\n/,
568 :*, /\t 8: from \(irb\):1:in `a12'\n/,
569 :*, /\t 7: from \(irb\):1:in `a13'\n/,
570 :*, /\t 6: from \(irb\):1:in `a14'\n/,
571 :*, /\t 5: from \(irb\):1:in `a15'\n/,
572 :*, /\t 4: from \(irb\):1:in `a16'\n/,
573 :*, /\t 3: from \(irb\):1:in `a17'\n/,
574 :*, /\t 2: from \(irb\):1:in `a18'\n/,
575 :*, /\t 1: from \(irb\):1:in `a19'\n/,
576 :*, /\(irb\):1:in `a20': unhandled exception\n/,
580 :*, /\(irb\):1:in `a20': unhandled exception\n/,
581 :*, /\tfrom \(irb\):1:in `a19'\n/,
582 :*, /\tfrom \(irb\):1:in `a18'\n/,
583 :*, /\tfrom \(irb\):1:in `a17'\n/,
584 :*, /\tfrom \(irb\):1:in `a16'\n/,
585 :*, /\tfrom \(irb\):1:in `a15'\n/,
586 :*, /\tfrom \(irb\):1:in `a14'\n/,
587 :*, /\tfrom \(irb\):1:in `a13'\n/,
588 :*, /\tfrom \(irb\):1:in `a12'\n/,
589 :*, /\tfrom \(irb\):1:in `a11'\n/,
590 :*, /\tfrom \(irb\):1:in `a10'\n/,
591 :*, /\tfrom \(irb\):1:in `a9'\n/,
592 :*, /\tfrom \(irb\):1:in `a8'\n/,
593 :*, /\tfrom \(irb\):1:in `a7'\n/,
594 :*, /\tfrom \(irb\):1:in `a6'\n/,
595 :*, /\tfrom \(irb\):1:in `a5'\n/,
596 :*, /\tfrom \(irb\):1:in `a4'\n/,
597 :*, /\t... \d+ levels...\n/,
600 assert_pattern_list(expected, out)
606 input = TestInputMethod.new([
614 irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
615 out, err = capture_output do
619 assert_pattern_list([