diff --git a/test/feed_reader/recovery/recovery_test.exs b/test/feed_reader/recovery/recovery_test.exs
new file mode 100644
index 0000000..78fec75
--- /dev/null
+++ b/test/feed_reader/recovery/recovery_test.exs
@@ -0,0 +1,54 @@
+defmodule FeedReader.RecoveryTest do
+ use ExUnit.Case, async: true
+
+ alias FeedReader.Recovery
+
+ describe "declared_encoding/1" do
+ test "defaults to UTF-8 when no declaration is present" do
+ assert Recovery.declared_encoding("") == :utf8
+ end
+
+ test "recognizes common Latin-1 aliases case-insensitively" do
+ assert Recovery.declared_encoding(~s()) == :latin1
+ assert Recovery.declared_encoding(~s()) == :latin1
+ end
+
+ test "recognizes US-ASCII and leaves other declarations UTF-8" do
+ assert Recovery.declared_encoding(~s()) == :ascii
+ assert Recovery.declared_encoding(~s()) == :utf8
+ assert Recovery.declared_encoding(~s()) == :utf8
+ end
+
+ test "finds declarations after XML declaration attributes" do
+ prefix = ~s()
+
+ assert Recovery.declared_encoding(prefix) == :latin1
+ end
+ end
+
+ test "normalizes all recovery stages across chunk boundaries" do
+ chunks = [
+ <<0xEF>>,
+ <<0xBB, 0xBF>>,
+ " \n",
+ ~s(- caf),
+ <<0xE9>>,
+ " & B
"
+ ]
+
+ assert normalize(chunks, :latin1) ==
+ ~s(- café & B
)
+ end
+
+ test "preserves CDATA and comments while repairing surrounding text" do
+ chunks = [
+ "E & F"
+ ]
+
+ assert normalize(chunks, :utf8) ==
+ "E & F"
+ end
+
+ defp normalize(chunks, encoding), do: chunks |> Recovery.normalize(encoding) |> Enum.join()
+end