qwen-coder-api / test_web_search.py
3v324v23's picture
Harden OpenClaude tool compatibility
56f6a56
Raw
History Blame Contribute Delete
9.49 kB
"""Unit tests for the fixed-source local web-search parser."""
from __future__ import annotations
import unittest
from unittest.mock import patch
import httpx
import web_search
from web_search import (
SearchUnavailable,
parse_bing_rss,
parse_duckduckgo_lite,
parse_google_news_rss,
search_web,
)
class FakeClient:
def __enter__(self) -> "FakeClient":
return self
def __exit__(self, *_args: object) -> None:
return None
class WebSearchParserTests(unittest.TestCase):
def test_duckduckgo_lite_results_and_redirects(self) -> None:
payload = """
<html><body>
<a class="result-link"
href="//duckduckgo.com/l/?uddg=https%3A%2F%2Fexample.com%2Fdocs&amp;rut=x">
Example &amp; docs
</a>
<td class="result-snippet">A <b>useful</b> result.</td>
</body></html>
"""
self.assertEqual(
parse_duckduckgo_lite(payload),
[
{
"title": "Example & docs",
"url": "https://example.com/docs",
"description": "A useful result.",
"source": "example.com",
}
],
)
def test_bing_rss_results(self) -> None:
payload = """<?xml version="1.0"?>
<rss><channel><item>
<title>Projeto</title>
<link>https://example.org/project</link>
<description>Uma &lt;b&gt;descrição&lt;/b&gt;.</description>
</item></channel></rss>
"""
self.assertEqual(
parse_bing_rss(payload),
[
{
"title": "Projeto",
"url": "https://example.org/project",
"description": "Uma descrição.",
"source": "example.org",
}
],
)
def test_google_news_rss_parses_date_and_source(self) -> None:
payload = """<?xml version="1.0" encoding="UTF-8"?>
<rss><channel><item>
<title>Operação acontece no Rio de Janeiro</title>
<link>https://news.google.com/rss/articles/example</link>
<description><![CDATA[
<a href="https://example.com/rj">Operação acontece no Rio de Janeiro</a>
<p>Forças de segurança divulgaram o balanço.</p>
<font>O GLOBO</font>
]]></description>
<pubDate>Tue, 04 Aug 2026 17:11:11 GMT</pubDate>
<source url="https://oglobo.globo.com">O GLOBO</source>
</item></channel></rss>
"""
self.assertEqual(
parse_google_news_rss(payload),
[
{
"title": "Operação acontece no Rio de Janeiro",
"url": "https://news.google.com/rss/articles/example",
"description": (
"Publicado em 04/08/2026 17:11 UTC — Fonte: O GLOBO. "
"Forças de segurança divulgaram o balanço."
),
"source": "O GLOBO",
}
],
)
def test_google_news_rss_rejects_unsafe_link(self) -> None:
payload = """<rss><channel><item>
<title>Resultado inseguro</title>
<link>javascript:alert(1)</link>
<pubDate>Tue, 04 Aug 2026 17:11:11 GMT</pubDate>
<source>Fonte</source>
</item></channel></rss>"""
self.assertEqual(parse_google_news_rss(payload), [])
def test_invalid_result_scheme_is_rejected(self) -> None:
payload = """
<a class="result-link" href="javascript:alert(1)">Inseguro</a>
<td class="result-snippet">Não deve aparecer.</td>
"""
self.assertEqual(parse_duckduckgo_lite(payload), [])
def test_invalid_result_does_not_replace_previous_snippet(self) -> None:
payload = """
<a class="result-link" href="https://example.com/valid">Valido</a>
<td class="result-snippet">Descricao valida.</td>
<a class="result-link" href="javascript:alert(1)">Inseguro</a>
<td class="result-snippet">Descricao insegura.</td>
"""
self.assertEqual(
parse_duckduckgo_lite(payload),
[
{
"title": "Valido",
"url": "https://example.com/valid",
"description": "Descricao valida.",
"source": "example.com",
}
],
)
class WebSearchAggregationTests(unittest.TestCase):
def test_recent_news_aggregates_and_prioritizes_rio_de_janeiro(self) -> None:
google_results = [
{
"title": "Agenda cultural em Porto Alegre, RS",
"url": "https://gauchazh.clicrbs.com.br/porto-alegre/noticia",
"description": "Publicado em 04/08/2026 17:00 UTC — Fonte: GZH.",
"source": "GZH",
},
{
"title": "Prefeitura do Rio de Janeiro anuncia medida",
"url": "https://example.com/rj/prefeitura",
"description": "Publicado em 04/08/2026 16:00 UTC — Fonte: Jornal RJ.",
"source": "Jornal RJ",
},
]
duck_results = [
{
"title": "Prefeitura do Rio de Janeiro anuncia medida",
"url": "https://duplicate.example/noticia",
"description": "Resultado duplicado vindo de outro provedor.",
"source": "duplicate.example",
},
{
"title": "Trânsito no RJ tem alteração nesta terça",
"url": "https://example.org/noticias/rj/transito",
"description": "Mudança afeta vias da capital fluminense.",
"source": "example.org",
},
]
with (
patch("web_search.httpx.Client", return_value=FakeClient()),
patch(
"web_search._google_news_rss",
return_value=google_results,
) as google,
patch(
"web_search._duckduckgo_lite",
return_value=duck_results,
) as duck,
patch("web_search._bing_rss") as bing,
):
result = search_web("últimas notícias do RJ hoje")
self.assertEqual(result["provider"], "google-news+duckduckgo-lite")
self.assertEqual(
[item["title"] for item in result["results"]],
[
"Prefeitura do Rio de Janeiro anuncia medida",
"Trânsito no RJ tem alteração nesta terça",
"Agenda cultural em Porto Alegre, RS",
],
)
google.assert_called_once()
duck.assert_called_once()
bing.assert_not_called()
def test_recent_news_falls_back_when_primary_providers_fail(self) -> None:
bing_result = {
"title": "Notícia do Rio de Janeiro",
"url": "https://example.net/rj/noticia",
"description": "Informação atualizada.",
"source": "example.net",
}
network_error = httpx.ConnectError("offline")
with (
patch("web_search.httpx.Client", return_value=FakeClient()),
patch("web_search._google_news_rss", side_effect=network_error),
patch("web_search._duckduckgo_lite", return_value=[]),
patch("web_search._bing_rss", return_value=[bing_result]),
):
result = search_web("notícias recentes do Rio de Janeiro")
self.assertEqual(result["provider"], "bing-rss")
self.assertEqual(result["results"], [bing_result])
def test_general_search_aggregates_existing_providers(self) -> None:
duck_result = {
"title": "Documentação do projeto",
"url": "https://example.com/docs",
"description": "Guia principal.",
"source": "example.com",
}
bing_result = {
"title": "Repositório do projeto",
"url": "https://github.com/example/project",
"description": "Código fonte.",
"source": "github.com",
}
with (
patch("web_search.httpx.Client", return_value=FakeClient()),
patch("web_search._duckduckgo_lite", return_value=[duck_result]),
patch("web_search._bing_rss", return_value=[bing_result]),
patch("web_search._wikipedia") as wikipedia,
patch("web_search._google_news_rss") as google_news,
):
result = search_web("documentação projeto")
self.assertEqual(result["provider"], "duckduckgo-lite+bing-rss")
self.assertEqual(len(result["results"]), 2)
wikipedia.assert_not_called()
google_news.assert_not_called()
def test_all_providers_unavailable_preserves_search_error(self) -> None:
network_error = httpx.ConnectError("offline")
with (
patch("web_search.httpx.Client", return_value=FakeClient()),
patch("web_search._google_news_rss", side_effect=network_error),
patch("web_search._duckduckgo_lite", return_value=[]),
patch("web_search._bing_rss", side_effect=network_error),
):
with self.assertRaisesRegex(SearchUnavailable, "google-news"):
search_web("últimas notícias")
if __name__ == "__main__":
unittest.main()