|
| 1 | +import os |
| 2 | +import unittest |
| 3 | + |
| 4 | +from iclaw import web_search |
| 5 | + |
| 6 | + |
| 7 | +class TestTavilySearchIntegration(unittest.TestCase): |
| 8 | + def setUp(self): |
| 9 | + self.api_key = os.environ.get("TAVILY_API_KEY") |
| 10 | + if not self.api_key: |
| 11 | + self.skipTest("TAVILY_API_KEY environment variable not set") |
| 12 | + |
| 13 | + def test_tavily_search_returns_results(self): |
| 14 | + results = web_search.search_tavily("Python programming language", num_results=3) |
| 15 | + self.assertIsInstance(results, list) |
| 16 | + self.assertGreater(len(results), 0, "Tavily should return at least one result") |
| 17 | + for r in results: |
| 18 | + self.assertIn("title", r) |
| 19 | + self.assertIn("url", r) |
| 20 | + self.assertIn("content", r) |
| 21 | + self.assertTrue(r["url"].startswith("http")) |
| 22 | + print(f"✅ Tavily returned {len(results)} results") |
| 23 | + |
| 24 | + def test_tavily_via_web_search_function(self): |
| 25 | + output = web_search.web_search( |
| 26 | + "latest news today", num_results=3, provider="tavily" |
| 27 | + ) |
| 28 | + self.assertIsInstance(output, str) |
| 29 | + self.assertNotEqual(output, "No results found.") |
| 30 | + self.assertIn("### Source 1", output) |
| 31 | + self.assertIn("**Title:**", output) |
| 32 | + print( |
| 33 | + f"✅ Tavily via web_search() returned formatted output ({len(output)} chars)" |
| 34 | + ) |
| 35 | + |
| 36 | + def test_tavily_missing_api_key(self): |
| 37 | + original_key = os.environ.pop("TAVILY_API_KEY", None) |
| 38 | + try: |
| 39 | + results = web_search.search_tavily("test query") |
| 40 | + self.assertEqual(results, []) |
| 41 | + finally: |
| 42 | + if original_key: |
| 43 | + os.environ["TAVILY_API_KEY"] = original_key |
| 44 | + |
| 45 | + |
| 46 | +class TestDuckDuckGoSearchIntegration(unittest.TestCase): |
| 47 | + def test_ddg_search_returns_results(self): |
| 48 | + results = web_search.search_ddg("Python programming", num_results=5) |
| 49 | + self.assertIsInstance(results, list) |
| 50 | + self.assertGreater(len(results), 0, "DDG should return at least one result") |
| 51 | + for r in results: |
| 52 | + self.assertIn("title", r) |
| 53 | + self.assertIn("url", r) |
| 54 | + self.assertTrue(r["url"].startswith("http")) |
| 55 | + print(f"✅ DuckDuckGo returned {len(results)} results") |
| 56 | + |
| 57 | + def test_ddg_via_web_search_function(self): |
| 58 | + output = web_search.web_search( |
| 59 | + "Python programming", num_results=3, provider="duckduckgo" |
| 60 | + ) |
| 61 | + self.assertIsInstance(output, str) |
| 62 | + self.assertNotEqual(output, "No results found.") |
| 63 | + self.assertIn("### Source 1", output) |
| 64 | + print( |
| 65 | + f"✅ DDG via web_search() returned formatted output ({len(output)} chars)" |
| 66 | + ) |
| 67 | + |
| 68 | + |
| 69 | +class TestBingSearchIntegration(unittest.TestCase): |
| 70 | + def test_bing_search_returns_results(self): |
| 71 | + results = web_search.search_bing("Python programming", num_results=5) |
| 72 | + self.assertIsInstance(results, list) |
| 73 | + # Bing may fail due to geo/proxy, so just check structure if results exist |
| 74 | + if results: |
| 75 | + for r in results: |
| 76 | + self.assertIn("title", r) |
| 77 | + self.assertIn("url", r) |
| 78 | + print(f"✅ Bing returned {len(results)} results") |
| 79 | + else: |
| 80 | + print("⚠️ Bing returned no results (may be blocked by proxy/geo)") |
| 81 | + |
| 82 | + def test_bing_via_web_search_function(self): |
| 83 | + output = web_search.web_search( |
| 84 | + "Python programming", num_results=3, provider="bing" |
| 85 | + ) |
| 86 | + self.assertIsInstance(output, str) |
| 87 | + print(f"✅ Bing via web_search() returned output ({len(output)} chars)") |
| 88 | + |
| 89 | + |
| 90 | +class TestStartpageSearchIntegration(unittest.TestCase): |
| 91 | + def test_startpage_search_returns_results(self): |
| 92 | + results = web_search.search_startpage("Python programming", num_results=5) |
| 93 | + self.assertIsInstance(results, list) |
| 94 | + if results: |
| 95 | + for r in results: |
| 96 | + self.assertIn("title", r) |
| 97 | + self.assertIn("url", r) |
| 98 | + print(f"✅ Startpage returned {len(results)} results") |
| 99 | + else: |
| 100 | + print("⚠️ Startpage returned no results (may be blocked by proxy/geo)") |
| 101 | + |
| 102 | + |
| 103 | +class TestContentExtractionIntegration(unittest.TestCase): |
| 104 | + def test_extract_text_from_wikipedia(self): |
| 105 | + text = web_search.extract_text_from_url( |
| 106 | + "https://en.wikipedia.org/wiki/Python_(programming_language)" |
| 107 | + ) |
| 108 | + self.assertIsInstance(text, str) |
| 109 | + self.assertGreater(len(text), 100, "Should extract meaningful content") |
| 110 | + self.assertNotIn("Error", text) |
| 111 | + print(f"✅ Wikipedia extraction: {len(text)} chars") |
| 112 | + |
| 113 | + def test_extract_text_from_github(self): |
| 114 | + text = web_search.extract_text_from_url("https://github.com/python/cpython") |
| 115 | + self.assertIsInstance(text, str) |
| 116 | + self.assertGreater(len(text), 50) |
| 117 | + print(f"✅ GitHub extraction: {len(text)} chars") |
| 118 | + |
| 119 | + |
| 120 | +class TestWebSearchProviderDispatch(unittest.TestCase): |
| 121 | + """Test that web_search() correctly dispatches to different providers.""" |
| 122 | + |
| 123 | + def test_default_provider_is_ddg(self): |
| 124 | + output = web_search.web_search("test query", num_results=2) |
| 125 | + self.assertIsInstance(output, str) |
| 126 | + |
| 127 | + def test_invalid_provider_falls_back_to_ddg(self): |
| 128 | + # Unknown provider should fall through to DDG (the else branch) |
| 129 | + output = web_search.web_search( |
| 130 | + "test query", num_results=2, provider="nonexistent" |
| 131 | + ) |
| 132 | + self.assertIsInstance(output, str) |
| 133 | + |
| 134 | + |
| 135 | +if __name__ == "__main__": |
| 136 | + unittest.main() |
0 commit comments