From 9b0ef1a5d54e7ec32de12f135e093f6efe9dfea8 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sun, 13 Sep 2026 21:39:27 +0200 Subject: [PATCH] test: cover StaticCacheTest, test_weak_validators_are_size_and_mtime --- test/test_static_cache.rb | 100 ++++++++++++++++++++++++++++++++++++ test/test_streaming_body.rb | 52 +++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 test/test_static_cache.rb create mode 100644 test/test_streaming_body.rb diff --git a/test/test_static_cache.rb b/test/test_static_cache.rb new file mode 100644 index 0000000..d4b3f2f --- /dev/null +++ b/test/test_static_cache.rb @@ -0,0 +1,100 @@ +require 'minitest/autorun' +require 'prism' + +class StaticCacheTest < Minitest::Test + def test_weak_validators_are_size_and_mtime + mtime = Time.at(1_700_000_000) + etag, last_modified = Prism::StaticCache.weak_validators(42, mtime) + + assert_equal 'W/"42-1700000000"', etag + assert_equal mtime.utc.httpdate, last_modified + end + + def test_strong_etag_is_quoted_hash + assert_equal '"deadbeef"', Prism::StaticCache.strong_etag('deadbeef') + end + + def test_not_modified_true_when_if_none_match_matches + env = { 'HTTP_IF_NONE_MATCH' => '"abc"' } + assert Prism::StaticCache.not_modified?(env, '"abc"', nil) + end + + def test_not_modified_true_on_wildcard_if_none_match + env = { 'HTTP_IF_NONE_MATCH' => '*' } + assert Prism::StaticCache.not_modified?(env, '"anything"', nil) + end + + def test_not_modified_false_when_etag_differs + env = { 'HTTP_IF_NONE_MATCH' => '"abc"' } + refute Prism::StaticCache.not_modified?(env, '"xyz"', nil) + end + + def test_not_modified_true_when_if_modified_since_not_older + last_modified = Time.at(1_700_000_000).utc.httpdate + env = { 'HTTP_IF_MODIFIED_SINCE' => last_modified } + assert Prism::StaticCache.not_modified?(env, nil, last_modified) + end + + def test_not_modified_false_when_if_modified_since_is_older + env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(1_000).utc.httpdate } + refute Prism::StaticCache.not_modified?(env, nil, Time.at(2_000_000_000).utc.httpdate) + end + + def test_not_modified_false_when_neither_header_present + refute Prism::StaticCache.not_modified?({}, '"abc"', 'whatever') + end + + def test_not_modified_requires_both_conditions_when_both_given + last_modified = Time.at(1_700_000_000).utc.httpdate + env = { 'HTTP_IF_NONE_MATCH' => '"abc"', 'HTTP_IF_MODIFIED_SINCE' => Time.at(0).utc.httpdate } + refute Prism::StaticCache.not_modified?(env, '"abc"', last_modified) + end + + def test_not_modified_ignores_malformed_if_modified_since + refute Prism::StaticCache.not_modified?({ 'HTTP_IF_MODIFIED_SINCE' => 'not a date' }, nil, Time.now.utc.httpdate) + end + + def test_range_applicable_true_when_no_if_range + assert Prism::StaticCache.range_applicable?({}, 'W/"1-2"', nil) + end + + def test_range_applicable_true_for_strong_etag_exact_match + env = { 'HTTP_IF_RANGE' => '"deadbeef"' } + assert Prism::StaticCache.range_applicable?(env, '"deadbeef"', nil) + end + + def test_range_applicable_false_when_strong_etag_differs + env = { 'HTTP_IF_RANGE' => '"deadbeef"' } + refute Prism::StaticCache.range_applicable?(env, '"cafebabe"', nil) + end + + def test_range_applicable_false_when_current_etag_is_weak + env = { 'HTTP_IF_RANGE' => '"1-2"' } + refute Prism::StaticCache.range_applicable?(env, 'W/"1-2"', nil) + end + + def test_range_applicable_false_when_client_sends_weak_validator + env = { 'HTTP_IF_RANGE' => 'W/"deadbeef"' } + refute Prism::StaticCache.range_applicable?(env, '"deadbeef"', nil) + end + + def test_range_applicable_true_for_exact_date_match + last_modified = Time.at(1_700_000_000).utc.httpdate + env = { 'HTTP_IF_RANGE' => last_modified } + assert Prism::StaticCache.range_applicable?(env, nil, last_modified) + end + + def test_range_applicable_false_when_date_is_newer_than_last_modified + env = { 'HTTP_IF_RANGE' => Time.at(2_000_000_000).utc.httpdate } + refute Prism::StaticCache.range_applicable?(env, nil, Time.at(1_700_000_000).utc.httpdate) + end + + def test_range_applicable_false_when_date_is_older_than_last_modified + env = { 'HTTP_IF_RANGE' => Time.at(1_000).utc.httpdate } + refute Prism::StaticCache.range_applicable?(env, nil, Time.at(1_700_000_000).utc.httpdate) + end + + def test_range_applicable_ignores_malformed_if_range_date + refute Prism::StaticCache.range_applicable?({ 'HTTP_IF_RANGE' => 'garbage' }, nil, Time.now.utc.httpdate) + end +end diff --git a/test/test_streaming_body.rb b/test/test_streaming_body.rb new file mode 100644 index 0000000..30f7fdf --- /dev/null +++ b/test/test_streaming_body.rb @@ -0,0 +1,52 @@ +require 'minitest/autorun' +require 'prism' + +class StreamingBodyTest < Minitest::Test + def test_each_yields_chunks_in_write_order + body = Prism::StreamingBody.new do |out| + out.write('a') + out.write('b') + out << 'c' + end + + collected = [] + body.each { |chunk| collected << chunk } + assert_equal %w[a b c], collected + end + + def test_write_coerces_non_string_chunks_to_string + body = Prism::StreamingBody.new { |out| out.write(42) } + + collected = [] + body.each { |chunk| collected << chunk } + assert_equal ['42'], collected + assert collected.first.is_a?(String) + end + + # The producer block must not run just because a StreamingBody was + # created - only #each (whatever eventually sends the response) triggers + # it, exactly like an ordinary Array body is not "used" until iterated. + def test_producer_block_does_not_run_until_each_is_called + ran = false + body = Prism::StreamingBody.new { ran = true } + refute ran + body.each { |_chunk| nil } + assert ran + end + + def test_each_can_be_called_more_than_once_and_reruns_the_producer + calls = 0 + body = Prism::StreamingBody.new do |out| + calls += 1 + out.write("call-#{calls}") + end + + first = [] + body.each { |chunk| first << chunk } + second = [] + body.each { |chunk| second << chunk } + + assert_equal ['call-1'], first + assert_equal ['call-2'], second + end +end