summaryrefslogtreecommitdiff
path: root/test/test_pp.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/test_pp.rb')
-rw-r--r--test/test_pp.rb378
1 files changed, 378 insertions, 0 deletions
diff --git a/test/test_pp.rb b/test/test_pp.rb
new file mode 100644
index 0000000000..922ed371af
--- /dev/null
+++ b/test/test_pp.rb
@@ -0,0 +1,378 @@
+# frozen_string_literal: true
+
+require 'pp'
+require 'delegate'
+require 'set'
+require 'test/unit'
+require 'ruby2_keywords'
+
+module PPTestModule
+
+SetPP = Set.instance_method(:pretty_print).source_location[0].end_with?("/pp.rb")
+
+class PPTest < Test::Unit::TestCase
+ def test_list0123_12
+ assert_equal("[0, 1, 2, 3]\n", PP.pp([0,1,2,3], ''.dup, 12))
+ end
+
+ def test_list0123_11
+ assert_equal("[0,\n 1,\n 2,\n 3]\n", PP.pp([0,1,2,3], ''.dup, 11))
+ end
+
+ def test_set
+ assert_equal("Set[0, 1, 2, 3]\n", PP.pp(Set[0,1,2,3], ''.dup, 16))
+ end if SetPP
+
+ OverriddenStruct = Struct.new("OverriddenStruct", :members, :class)
+ def test_struct_override_members # [ruby-core:7865]
+ a = OverriddenStruct.new(1,2)
+ assert_equal("#<struct Struct::OverriddenStruct members=1, class=2>\n", PP.pp(a, ''.dup))
+ end
+
+ def test_redefined_method
+ o = "".dup
+ def o.method
+ end
+ assert_equal(%(""\n), PP.pp(o, "".dup))
+ end
+
+ def test_range
+ assert_equal("0..1\n", PP.pp(0..1, "".dup))
+ assert_equal("0...1\n", PP.pp(0...1, "".dup))
+ assert_equal("0...\n", PP.pp(0..., "".dup))
+ assert_equal("...1\n", PP.pp(...1, "".dup))
+ assert_equal("..false\n", PP.pp(..false, "".dup))
+ assert_equal("false..\n", PP.pp(false.., "".dup))
+ assert_equal("false..false\n", PP.pp(false..false, "".dup))
+ assert_equal("nil..nil\n", PP.pp(nil..nil, "".dup))
+ end
+end
+
+class HasInspect
+ def initialize(a)
+ @a = a
+ end
+
+ def inspect
+ return "<inspect:#{@a.inspect}>"
+ end
+end
+
+class HasPrettyPrint
+ def initialize(a)
+ @a = a
+ end
+
+ def pretty_print(q)
+ q.text "<pretty_print:"
+ q.pp @a
+ q.text ">"
+ end
+end
+
+class HasBoth
+ def initialize(a)
+ @a = a
+ end
+
+ def inspect
+ return "<inspect:#{@a.inspect}>"
+ end
+
+ def pretty_print(q)
+ q.text "<pretty_print:"
+ q.pp @a
+ q.text ">"
+ end
+end
+
+class PrettyPrintInspect < HasPrettyPrint
+ alias inspect pretty_print_inspect
+end
+
+class PrettyPrintInspectWithoutPrettyPrint
+ alias inspect pretty_print_inspect
+end
+
+class PPInspectTest < Test::Unit::TestCase
+ def test_hasinspect
+ a = HasInspect.new(1)
+ assert_equal("<inspect:1>\n", PP.pp(a, ''.dup))
+ end
+
+ def test_hasprettyprint
+ a = HasPrettyPrint.new(1)
+ assert_equal("<pretty_print:1>\n", PP.pp(a, ''.dup))
+ end
+
+ def test_hasboth
+ a = HasBoth.new(1)
+ assert_equal("<pretty_print:1>\n", PP.pp(a, ''.dup))
+ end
+
+ def test_pretty_print_inspect
+ a = PrettyPrintInspect.new(1)
+ assert_equal("<pretty_print:1>", a.inspect)
+ a = PrettyPrintInspectWithoutPrettyPrint.new
+ assert_raise(RuntimeError) { a.inspect }
+ end
+
+ def test_proc
+ a = proc {1}
+ assert_equal("#{a.inspect}\n", PP.pp(a, ''.dup))
+ end
+
+ def test_to_s_with_iv
+ a = Object.new
+ def a.to_s() "aaa" end
+ a.instance_eval { @a = nil }
+ result = PP.pp(a, ''.dup)
+ assert_equal("#{a.inspect}\n", result)
+ end
+
+ def test_to_s_without_iv
+ a = Object.new
+ def a.to_s() "aaa" end
+ result = PP.pp(a, ''.dup)
+ assert_equal("#{a.inspect}\n", result)
+ end
+
+ def test_iv_hiding
+ a = Object.new
+ def a.pretty_print_instance_variables() [:@b] end
+ a.instance_eval { @a = "aaa"; @b = "bbb" }
+ assert_match(/\A#<Object:0x[\da-f]+ @b="bbb">\n\z/, PP.pp(a, ''.dup))
+ end
+
+ def test_iv_hiding_via_ruby
+ a = Object.new
+ a.singleton_class.class_eval do
+ private def instance_variables_to_inspect() [:@b] end
+ end
+ a.instance_eval { @a = "aaa"; @b = "bbb" }
+ assert_match(/\A#<Object:0x[\da-f]+ @b="bbb">\n\z/, PP.pp(a, ''.dup))
+ end
+
+ def test_basic_object
+ a = BasicObject.new
+ assert_match(/\A#<BasicObject:0x[\da-f]+>\n\z/, PP.pp(a, ''.dup))
+ end
+end
+
+class PPCycleTest < Test::Unit::TestCase
+ def test_array
+ a = []
+ a << a
+ assert_equal("[[...]]\n", PP.pp(a, ''.dup))
+ assert_equal("#{a.inspect}\n", PP.pp(a, ''.dup))
+ end
+
+ def test_hash
+ a = {}
+ a[0] = a
+ assert_equal("#{a.inspect}\n", PP.pp(a, ''.dup))
+ end
+
+ def test_set
+ s = Set[]
+ s.add s
+ assert_equal("Set[Set[...]]\n", PP.pp(s, ''.dup))
+ end if SetPP
+
+ S = Struct.new("S", :a, :b)
+ def test_struct
+ a = S.new(1,2)
+ a.b = a
+ assert_equal("#<struct Struct::S a=1, b=#<struct Struct::S:...>>\n", PP.pp(a, ''.dup))
+ assert_equal("#{a.inspect}\n", PP.pp(a, ''.dup)) unless RUBY_ENGINE == "truffleruby"
+ end
+
+ verbose, $VERBOSE = $VERBOSE, nil
+ begin
+ has_data_define = defined?(Data.define)
+ ensure
+ $VERBOSE = verbose
+ end
+
+ if has_data_define
+ D = Data.define(:aaa, :bbb)
+ def test_data
+ a = D.new("aaa", "bbb")
+ assert_equal("#<data PPTestModule::PPCycleTest::D\n aaa=\"aaa\",\n bbb=\"bbb\">\n", PP.pp(a, ''.dup, 20))
+ assert_equal("#{a.inspect}\n", PP.pp(a, ''.dup))
+
+ b = Data.define(:a).new(42)
+ assert_equal("#{b.inspect}\n", PP.pp(b, ''.dup))
+ end
+
+ D2 = Data.define(:aaa, :bbb) do
+ private :aaa
+ end
+ def test_data_private_member
+ a = D2.new("aaa", "bbb")
+ assert_equal("#<data PPTestModule::PPCycleTest::D2\n aaa=\"aaa\",\n bbb=\"bbb\">\n", PP.pp(a, ''.dup, 20))
+ end
+
+ D3 = Data.define(:aaa, :bbb) do
+ remove_method :aaa
+ end
+ def test_data_removed_member
+ a = D3.new("aaa", "bbb")
+ assert_equal("#<data PPTestModule::PPCycleTest::D3\n bbb=\"bbb\">\n", PP.pp(a, ''.dup, 20))
+ end
+ end
+
+ def test_object
+ a = Object.new
+ a.instance_eval {@a = a}
+ assert_equal(a.inspect + "\n", PP.pp(a, ''.dup))
+ end
+
+ def test_anonymous
+ a = Class.new.new
+ assert_equal(a.inspect + "\n", PP.pp(a, ''.dup))
+ end
+
+ def test_withinspect
+ omit if RUBY_ENGINE == "jruby" or RUBY_ENGINE == "truffleruby"
+ a = []
+ a << HasInspect.new(a)
+ assert_equal("[<inspect:[...]>]\n", PP.pp(a, ''.dup))
+ assert_equal("#{a.inspect}\n", PP.pp(a, ''.dup))
+ end
+
+ def test_share_nil
+ begin
+ PP.sharing_detection = true
+ a = [nil, nil]
+ assert_equal("[nil, nil]\n", PP.pp(a, ''.dup))
+ ensure
+ PP.sharing_detection = false
+ end
+ end
+end
+
+class PPSingleLineTest < Test::Unit::TestCase
+ def test_hash
+ assert_equal({1 => 1}.inspect, PP.singleline_pp({1 => 1}, ''.dup)) # [ruby-core:02699]
+ assert_equal("[1#{', 1'*99}]", PP.singleline_pp([1]*100, ''.dup))
+ end
+
+ def test_hash_symbol_colon_key
+ no_quote = "{a: 1, a!: 1, a?: 1}"
+ unicode_quote = "{\u{3042}: 1}"
+ quote0 = '{"": 1}'
+ quote1 = '{"0": 1, "!": 1, "%": 1, "&": 1, "*": 1, "+": 1, "-": 1, "/": 1, "<": 1, ">": 1, "^": 1, "`": 1, "|": 1, "~": 1}'
+ quote2 = '{"@a": 1, "$a": 1, "+@": 1, "a=": 1, "[]": 1}'
+ quote3 = '{"a\"b": 1, "@@a": 1, "<=>": 1, "===": 1, "[]=": 1}'
+ assert_equal(no_quote, PP.singleline_pp(eval(no_quote), ''.dup))
+ assert_equal({ "\u3042": 1 }.inspect, PP.singleline_pp(eval(unicode_quote), ''.dup))
+ assert_equal(quote0, PP.singleline_pp(eval(quote0), ''.dup))
+ assert_equal(quote1, PP.singleline_pp(eval(quote1), ''.dup))
+ assert_equal(quote2, PP.singleline_pp(eval(quote2), ''.dup))
+ assert_equal(quote3, PP.singleline_pp(eval(quote3), ''.dup))
+ end if RUBY_VERSION >= "3.4."
+
+ def test_hash_in_array
+ omit if RUBY_ENGINE == "jruby"
+ assert_equal("[{}]", passing_keywords {PP.singleline_pp([->(*a){a.last.clear}.ruby2_keywords.call(a: 1)], ''.dup)})
+ assert_equal("[{}]", passing_keywords {PP.singleline_pp([Hash.ruby2_keywords_hash({})], ''.dup)})
+ end
+
+ if RUBY_VERSION >= "3.0"
+ def passing_keywords(&_)
+ yield
+ end
+ else
+ def passing_keywords(&_)
+ verbose, $VERBOSE = $VERBOSE, nil
+ yield
+ ensure
+ $VERBOSE = verbose
+ end
+ end
+
+ def test_direct_pp
+ buffer = String.new
+
+ a = []
+ a << a
+
+ # Isolate the test from any existing Thread.current[:__recursive_key__][:inspect].
+ Thread.new do
+ q = PP::SingleLine.new(buffer)
+ q.pp(a)
+ q.flush
+ end.join
+
+ assert_equal("[[...]]", buffer)
+ end
+end
+
+class PPDelegateTest < Test::Unit::TestCase
+ class A < DelegateClass(Array); end
+
+ def test_delegate
+ assert_equal("[]\n", A.new([]).pretty_inspect, "[ruby-core:25804]")
+ end
+
+ def test_delegate_cycle
+ a = HasPrettyPrint.new nil
+
+ a.instance_eval {@a = a}
+ cycle_pretty_inspect = a.pretty_inspect
+
+ a.instance_eval {@a = SimpleDelegator.new(a)}
+ delegator_cycle_pretty_inspect = a.pretty_inspect
+
+ assert_equal(cycle_pretty_inspect, delegator_cycle_pretty_inspect)
+ end
+end
+
+class PPFileStatTest < Test::Unit::TestCase
+ def test_nothing_raised
+ assert_nothing_raised do
+ File.stat(__FILE__).pretty_inspect
+ end
+ end
+end
+
+if defined?(RubyVM)
+ class PPAbstractSyntaxTree < Test::Unit::TestCase
+ AST = RubyVM::AbstractSyntaxTree
+ def test_lasgn_literal
+ ast = AST.parse("_=1")
+ integer = RUBY_VERSION >= "3.4." ? "INTEGER" : "LIT"
+ expected = "(SCOPE@1:0-1:3 tbl: [:_] args: nil body: (LASGN@1:0-1:3 :_ (#{integer}@1:2-1:3 1)))"
+ assert_equal(expected, PP.singleline_pp(ast, ''.dup), ast)
+ end
+ end
+end
+
+class PPInheritedTest < Test::Unit::TestCase
+ class PPSymbolHash < PP
+ def pp_hash_pair(k, v)
+ case k
+ when Symbol
+ text k.inspect.delete_prefix(":").tr('"', "'")
+ text ":"
+ group(1) {
+ breakable
+ pp v
+ }
+ else
+ super
+ end
+ end
+ end
+
+ def test_hash_override
+ obj = {k: 1, "": :null, "0": :zero, 100 => :ten}
+ sep = RUBY_VERSION >= "3.4." ? " => " : "=>"
+ assert_equal <<~EXPECT, PPSymbolHash.pp(obj, "".dup)
+ {k: 1, '': :null, '0': :zero, 100#{sep}:ten}
+ EXPECT
+ end
+end
+
+end