fixtures: replay a request body with its final newline
The replay chomped a body's CRLF along with the file's last line break,
so an extracted card came back shorter than the client's bytes, a quiet mistake.
Now only the file's own newline goes, and the body keeps its end;
every fixture here ended bare, so not one replay had to bend.
Assisted-by: Claude Opus 5 via Claude Code
diff --git a/test/fixtures/macos-exchange/README.md b/test/fixtures/macos-exchange/README.md
index 2fa432e..87abba6 100644
--- a/test/fixtures/macos-exchange/README.md
+++ b/test/fixtures/macos-exchange/README.md
@@ -13,7 +13,8 @@ Each step directory holds:
- `request` — the request line, the headers that affect routing
(`Brief`, `Content-Type`, `Depth`, `If-Match`, `If-None-Match`,
- `Prefer`), a blank line, then the exact body. `Authorization`, `Host`, `User-Agent`, and
+ `Prefer`), a blank line, then the exact body, then a newline that
+ ends the file and is not part of the body. `Authorization`, `Host`, `User-Agent`, and
the `Tailscale-*` / `X-Forwarded-*` / `X-Mme-Client-Info` headers
were stripped: they identify the tailnet and user, and the app
ignores them.
diff --git a/test/pro_tacts/exchange_fixtures.rb b/test/pro_tacts/exchange_fixtures.rb
index ec41766..d66e4cf 100644
--- a/test/pro_tacts/exchange_fixtures.rb
+++ b/test/pro_tacts/exchange_fixtures.rb
@@ -48,7 +48,7 @@ class ExchangeFixtures < Data.define(:directory)
request_line, *headers = head
kept, dropped = headers.partition { REQUEST_HEADERS.include?(it.split(": ", 2).first) }
step.mkpath
- (step / "request").binwrite([request_line, *kept].join("\n") + "\n\n" + body)
+ (step / "request").binwrite([request_line, *kept].join("\n") + "\n\n" + body + "\n")
dropped.map { it.split(": ", 2).first }
end
@@ -99,10 +99,12 @@ class ExchangeFixtures < Data.define(:directory)
File.read(directory / name / file)
end
+ # The newline that ends the file is not the body's. Only that one
+ # goes: a body's own CRLF is part of what the client sent.
def split_message(raw)
head, body = raw.split("\n\n", 2)
lines = head.split("\n")
- [lines.first, lines.drop(1), body.to_s.chomp]
+ [lines.first, lines.drop(1), body.to_s.delete_suffix("\n")]
end
def parse_headers(lines)
diff --git a/test/tasks/test_fixtures.rb b/test/tasks/test_fixtures.rb
index 3f4dce8..edb11c9 100644
--- a/test/tasks/test_fixtures.rb
+++ b/test/tasks/test_fixtures.rb
@@ -6,6 +6,7 @@ require "rake"
require "tmpdir"
require "pro_tacts/exchange_log"
+require_relative "../pro_tacts/exchange_fixtures"
class FixturesTasksTest < Minitest::Test
include Rack::Test::Methods
@@ -32,10 +33,18 @@ class FixturesTasksTest < Minitest::Test
extract(exchange, @root / "07-put")
- assert_equal "PUT /dav/addressbook/new.vcf HTTP/1.0\nContent-Type: text/vcard\nIf-Match: \"abc\"\n\n#{CARD}",
+ assert_equal "PUT /dav/addressbook/new.vcf HTTP/1.0\nContent-Type: text/vcard\nIf-Match: \"abc\"\n\n#{CARD}\n",
(@root / "07-put" / "request").binread
end
+ def test_the_step_replays_the_body_the_client_sent
+ put "/dav/addressbook/new.vcf", CARD
+
+ extract(exchange, @root / "07-put")
+
+ assert_equal CARD, ExchangeFixtures.new(@root).parse_request("07-put").fetch(:body)
+ end
+
def test_a_request_file_already_there_is_left_alone
put "/dav/addressbook/new.vcf", CARD
step = @root / "07-put"