Repository: ruby/debug (Ruby)

Issue:
Object inspection doesn't work inside Mocks that doesn't expect the `singleton_class` method called
**Your environment**

* `ruby -v`:  ruby 3.3.7 (2025-01-15 revision be31f993d7) [x86_64-linux]
* `rdbg -v`: rdbg 1.11.0

**Describe the bug**
Object inspection doesn't work inside Mocks that doesn't expect the `singleton_class` method called
`unmocked method :singleton_class`

**To Reproduce**
You can try to reproduce it using a minitest Mock
```ruby
mock = Minitest::Mock.new

mock.expect :call, true do |*passed_args, **passed_kwargs|
  debugger
end

mock.call(123)
```

Or make your own mock class from scratch (of course is not the same as minitest but mimics it)
```ruby
class Mock
  def initialize
    @expected = {}
  end

  def expect(name, return_value = nil, expected_args = nil, &block)
    @expected[name.to_sym] = [return_value, expected_args, block]
    self
  end

  def method_missing(name, *args, **kwargs, &blk)
    entry = @expected[name.to_sym]
    raise NoMethodError, "unmocked method #{name.inspect}, expected one of #{@expected.keys.inspect}" unless entry

    return_value , expected_args, stored_block = entry
    return stored_block.call(*args, **kwargs) if stored_block
    return_value 
  end

  def respond_to_missing?(name, include_private = false)
    @expected.key?(name.to_sym) || super
  end

  def singleton_class
    method_missing(:singleton_class)
  end
end

mock = Mock.new

mock.expect :call, true do |*passed_args, **passed_kwargs|
  debugger
end

mock.call(123)
```

**Expected behavior**
It should stop at the debugger, instead we get an error ``full_message': unmocked method :singleton_class, expected one of [:call] (NoMethodError)`

**Additional context**
I don't really know if this is a problem of MiniTest or from this gem, but `binding.pry` does not seem to fall into this error. Additionally i have identified that the code dies at `lib/debug/frame_info.rb:172` where `NoMethodError` is not captured, although after inside `safe_ispect` it is captured, i don't really understand the flow of the gem but maybe we can skip the `NoMethodError` before safe inspecting. Lastly, i was eager to do a PR but i can't test because i'm on wsl2 and have no fast way of switching to linux at the moment.



Discussion:

Patch:
diff --git a/lib/debug/frame_info.rb b/lib/debug/frame_info.rb
index 8fab332de..558f5466b 100644
--- a/lib/debug/frame_info.rb
+++ b/lib/debug/frame_info.rb
@@ -171,7 +171,7 @@ def parameters_info
 
     private def get_singleton_class obj
       obj.singleton_class # TODO: don't use it
-    rescue TypeError
+    rescue Exception
       nil
     end
 


Test patch:
diff --git a/test/console/backtrace_test.rb b/test/console/backtrace_test.rb
index 570d66c80..8c6056a6a 100644
--- a/test/console/backtrace_test.rb
+++ b/test/console/backtrace_test.rb
@@ -229,4 +229,31 @@ def test_backtrace_prints_without_hanging
       end
     end
   end
+
+  class BrokenSingletonMethodBacktraceTest < ConsoleTestCase
+    def program
+      <<~RUBY
+      1| class C
+      2|   def self.foo
+      3|     debugger
+      4|   end
+      5|   def singleton_class
+      6|     raise
+      7|   end
+      8|   def self.singleton_class
+      9|     eval(")") # SyntaxError
+     10|   end
+     11| end
+     12| C.foo
+      RUBY
+    end
+
+    def test_raise_exception
+      debug_code program do
+        type 'c'
+        assert_line_text(/foo/)
+        type 'c'
+      end
+    end
+  end
 end