From cb021d13ab4bcb2eae80e4b55b67fb89602b9ad7 Mon Sep 17 00:00:00 2001 From: st0012 Date: Sat, 4 Apr 2026 01:20:08 +0100 Subject: [PATCH 1/2] Fix page links returning 404 in server mode `TopLevel#parser=` was calling `update_parser_of_file` with `absolute_name`, but `@files_hash` is keyed by `relative_name`. The lookup always failed, so `@text_files_hash` was never populated and `find_text_page` always returned nil. --- lib/rdoc/code_object/top_level.rb | 2 +- lib/rdoc/store.rb | 8 ++++---- test/rdoc/rdoc_store_test.rb | 7 +++++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/rdoc/code_object/top_level.rb b/lib/rdoc/code_object/top_level.rb index 2bb2767c89..3a6976bbd8 100644 --- a/lib/rdoc/code_object/top_level.rb +++ b/lib/rdoc/code_object/top_level.rb @@ -66,7 +66,7 @@ def initialize(absolute_name, relative_name = absolute_name) def parser=(val) @parser = val - @store.update_parser_of_file(absolute_name, val) if @store + @store.update_parser_of_file(relative_name, val) if @store @parser end diff --git a/lib/rdoc/store.rb b/lib/rdoc/store.rb index bcba7ddabb..d91b293142 100644 --- a/lib/rdoc/store.rb +++ b/lib/rdoc/store.rb @@ -321,11 +321,11 @@ def resolve_c_superclasses end ## - # Sets the parser of +absolute_name+, unless it from a source code file. + # Sets the parser of +relative_name+, unless it from a source code file. - def update_parser_of_file(absolute_name, parser) - if top_level = @files_hash[absolute_name] then - @text_files_hash[absolute_name] = top_level if top_level.text? + def update_parser_of_file(relative_name, parser) + if top_level = @files_hash[relative_name] then + @text_files_hash[relative_name] = top_level if top_level.text? end end diff --git a/test/rdoc/rdoc_store_test.rb b/test/rdoc/rdoc_store_test.rb index 15492b1fb9..d9bb0bbbdb 100644 --- a/test/rdoc/rdoc_store_test.rb +++ b/test/rdoc/rdoc_store_test.rb @@ -348,6 +348,13 @@ def test_find_text_page assert_equal page, @store.find_text_page('PAGE.txt') end + def test_find_text_page_when_parser_set_after_add_file + page = @store.add_file '/absolute/path/to/PAGE.md', relative_name: 'PAGE.md' + page.parser = RDoc::Parser::Simple + + assert_equal page, @store.find_text_page('PAGE.md') + end + def test_friendly_path @orig_xdg_data_home = ENV.delete('XDG_DATA_HOME') From de0e72250fdc6e7e6a5e9ecd9095a77433bceed8 Mon Sep 17 00:00:00 2001 From: st0012 Date: Sat, 4 Apr 2026 12:46:45 +0100 Subject: [PATCH 2/2] Add integration tests for server page routing These tests exercise the full pipeline: parsing source files, then resolving page URLs through the server's route method. They verify that text pages (.md, .rdoc), class pages, the index, and 404s all work correctly. The text page tests would have caught the update_parser_of_file key mismatch bug. --- test/rdoc/rdoc_server_test.rb | 74 +++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 test/rdoc/rdoc_server_test.rb diff --git a/test/rdoc/rdoc_server_test.rb b/test/rdoc/rdoc_server_test.rb new file mode 100644 index 0000000000..bc141cabe7 --- /dev/null +++ b/test/rdoc/rdoc_server_test.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true +require_relative 'support/test_case' + +class RDocServerTest < RDoc::TestCase + + def setup + super + + @dir = Dir.mktmpdir("test_rdoc_server_") + + File.write File.join(@dir, "PAGE.md"), "# A Page\n\nSome content.\n" + File.write File.join(@dir, "NOTES.rdoc"), "= Notes\n\nSome notes.\n" + File.write File.join(@dir, "example.rb"), "# A class\nclass Example; end\n" + + @options.files = [@dir] + @options.op_dir = File.join(@dir, "_site") + @options.root = Pathname(@dir) + @options.verbosity = 0 + @options.finish + + @rdoc.options = @options + @rdoc.store = RDoc::Store.new(@options) + + capture_output do + @rdoc.parse_files @options.files + end + @rdoc.store.complete @options.visibility + + @server = RDoc::Server.new(@rdoc, 0) + end + + def teardown + FileUtils.rm_rf @dir + super + end + + def test_route_serves_text_page + status, content_type, body = @server.send(:route, '/PAGE_md.html') + + assert_equal 200, status + assert_equal 'text/html', content_type + assert_include body, 'A Page' + end + + def test_route_serves_rdoc_text_page + status, content_type, body = @server.send(:route, '/NOTES_rdoc.html') + + assert_equal 200, status + assert_equal 'text/html', content_type + assert_include body, 'Notes' + end + + def test_route_serves_class_page + status, content_type, body = @server.send(:route, '/Example.html') + + assert_equal 200, status + assert_equal 'text/html', content_type + assert_include body, 'Example' + end + + def test_route_serves_index + status, content_type, _body = @server.send(:route, '/') + + assert_equal 200, status + assert_equal 'text/html', content_type + end + + def test_route_returns_404_for_missing_page + status, content_type, _body = @server.send(:route, '/nonexistent.html') + + assert_equal 404, status + assert_equal 'text/html', content_type + end +end