diff --git a/test/feed_reader/remote_session_test.exs b/test/feed_reader/remote_session_test.exs
index 4d2a9d7..fc18dd6 100644
--- a/test/feed_reader/remote_session_test.exs
+++ b/test/feed_reader/remote_session_test.exs
@@ -63,6 +63,30 @@ defmodule FeedReader.RemoteSessionTest do
assert download_files() == before
end
+ test "verified downloads preserve unchanged outcomes and clean rejected feeds" do
+ url = "https://example.com/feed.xml"
+
+ assert {:ok, :not_modified} =
+ FeedReader.stream_verified(url, request_opts("", response: response([], [], 304)))
+
+ assert {:ok, :not_changed} =
+ FeedReader.stream_verified(
+ url,
+ request_opts(@xml, previous_checksum: checksum(@xml))
+ )
+
+ before = download_files()
+
+ assert {:error, :unknown} =
+ FeedReader.stream_verified(url, request_opts("", format: :invalid))
+
+ assert download_files() == before
+ end
+
+ test "verified stream validates its default-argument URL path" do
+ assert {:error, :invalid_url} = FeedReader.stream_verified(:invalid)
+ end
+
test "covers default options and closing a local session" do
assert {:error, :invalid_url} = FeedReader.stream(:invalid)
diff --git a/test/feed_reader/verified_parser_test.exs b/test/feed_reader/verified_parser_test.exs
new file mode 100644
index 0000000..1165f69
--- /dev/null
+++ b/test/feed_reader/verified_parser_test.exs
@@ -0,0 +1,72 @@
+defmodule FeedReader.VerifiedParserTest do
+ use ExUnit.Case, async: false
+
+ alias FeedReader.{Feed, Fetch, Item, Session}
+
+ @xml ~s(Verified- One
)
+
+ test "validates before returning a local event stream" do
+ path = write_temp(@xml)
+ on_exit(fn -> File.rm(path) end)
+
+ assert {:ok, %Session{fetch: nil, resource: nil, events: events}} =
+ FeedReader.stream_file_verified(path, max_parse_passes: 0)
+
+ assert [{:feed, %Feed{title: "Verified"}}, {:item, %Item{title: "One"}}] =
+ Enum.to_list(events)
+
+ assert File.read!(path) == @xml
+ end
+
+ test "does not return a session for malformed tails or an insufficient pass budget" do
+ path = write_temp(@xml <> " File.rm(path) end)
+
+ assert {:error, %Saxy.ParseError{}} = FeedReader.stream_file_verified(path)
+
+ valid_path = write_temp(@xml)
+ on_exit(fn -> File.rm(valid_path) end)
+
+ assert {:error, {:resource_limit, :max_parse_passes, 1}} =
+ FeedReader.stream_file_verified(valid_path, max_parse_passes: 1)
+ end
+
+ test "releases a remote verified source after enumeration or explicit close" do
+ assert {:ok, %Session{fetch: %Fetch{}, resource: %{path: path}} = session} =
+ FeedReader.stream_verified("https://example.com/feed.xml", remote_options())
+
+ assert [{:feed, %Feed{}}, {:item, %Item{}}] = Enum.to_list(session.events)
+ refute File.exists?(path)
+
+ assert {:ok, %Session{resource: %{path: path2}} = session2} =
+ FeedReader.stream_verified("https://example.com/feed.xml", remote_options())
+
+ assert File.exists?(path2)
+ assert :ok = FeedReader.close(session2)
+ refute File.exists?(path2)
+ end
+
+ defp remote_options do
+ [
+ http_client: FeedReader.TestSupport.TransportClient,
+ response: %{
+ status: 200,
+ headers: [],
+ final_url: "https://example.com/final.xml",
+ body: [@xml]
+ },
+ test_pid: self()
+ ]
+ end
+
+ defp write_temp(xml) do
+ path =
+ Path.join(
+ System.tmp_dir!(),
+ "feed_reader-verified-#{System.unique_integer([:positive])}.xml"
+ )
+
+ File.write!(path, xml)
+ path
+ end
+end