From dfb01adab80d60023e613b032e5b6a08f2df1564 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..0cc98c0469 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&.cache_text_file(relative_name) @parser end diff --git a/lib/rdoc/store.rb b/lib/rdoc/store.rb index bcba7ddabb..379d2f2246 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. + # Caches +relative_name+ in the text files hash, if it is a text 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 cache_text_file(relative_name) + if top_level = @files_hash[relative_name] + @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 3d15b9ddb940a84eeb698ba010889ebbd00a0a7e 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