@@ -53,7 +53,7 @@ def test_parse_hostname_raises_on_invalid():
5353 """Ensure parse_hostname raises when URL has no hostname."""
5454 with pytest .raises (Exception , match = "unable to parse hostname" ):
5555 parse_hostname ("not-a-url" )
56-
56+
5757 with pytest .raises (Exception , match = "unable to parse hostname" ):
5858 parse_hostname ("file:///local/path" )
5959
@@ -69,7 +69,7 @@ def test_linknode_initialization():
6969 numbers = ["+14155551234" ],
7070 emails = ["test@example.com" ],
7171 )
72-
72+
7373 assert node .tag == "Test Page"
7474 assert node .identifier == "https://example.com"
7575 assert node .status == 200
@@ -89,14 +89,14 @@ def test_linktree_creates_root_node_with_title():
8989 </body>
9090 </html>
9191 """
92-
92+
9393 client = FakeClient ({
9494 "https://example.com" : FakeResponse ("https://example.com" , html , 200 ),
9595 })
96-
96+
9797 tree = LinkTree ("https://example.com" , depth = 0 , client = client )
9898 tree .load ()
99-
99+
100100 root = tree .get_node ("https://example.com" )
101101 assert root is not None
102102 assert root .tag == "Example Site"
@@ -106,14 +106,14 @@ def test_linktree_creates_root_node_with_title():
106106def test_linktree_creates_root_node_without_title ():
107107 """Test that LinkTree falls back to hostname when no <title> tag."""
108108 html = "<html><body><p>No title here</p></body></html>"
109-
109+
110110 client = FakeClient ({
111111 "https://test.onion" : FakeResponse ("https://test.onion" , html , 200 ),
112112 })
113-
113+
114114 tree = LinkTree ("https://test.onion" , depth = 0 , client = client )
115115 tree .load ()
116-
116+
117117 root = tree .get_node ("https://test.onion" )
118118 assert root is not None
119119 assert root .tag == "test.onion"
@@ -131,16 +131,16 @@ def test_linktree_extracts_contacts_from_page():
131131 </body>
132132 </html>
133133 """
134-
134+
135135 client = FakeClient ({
136136 "https://example.com/contact" : FakeResponse (
137137 "https://example.com/contact" , html , 200
138138 ),
139139 })
140-
140+
141141 tree = LinkTree ("https://example.com/contact" , depth = 0 , client = client )
142142 tree .load ()
143-
143+
144144 root = tree .get_node ("https://example.com/contact" )
145145 assert root is not None
146146 assert len (root .data .emails ) == 2
@@ -160,10 +160,10 @@ def test_linktree_builds_tree_to_depth_1():
160160 </body>
161161 </html>
162162 """
163-
163+
164164 child1_html = "<html><head><title>Child 1</title></head></html>"
165165 child2_html = "<html><head><title>Child 2</title></head></html>"
166-
166+
167167 client = FakeClient ({
168168 "https://example.com" : FakeResponse ("https://example.com" , root_html , 200 ),
169169 "https://example.com/child1" : FakeResponse (
@@ -173,22 +173,22 @@ def test_linktree_builds_tree_to_depth_1():
173173 "https://example.com/child2" , child2_html , 200
174174 ),
175175 })
176-
176+
177177 tree = LinkTree ("https://example.com" , depth = 1 , client = client )
178178 tree .load ()
179-
179+
180180 # Verify root exists
181181 root = tree .get_node ("https://example.com" )
182182 assert root is not None
183-
183+
184184 # Verify children exist
185185 child1 = tree .get_node ("https://example.com/child1" )
186186 child2 = tree .get_node ("https://example.com/child2" )
187187 assert child1 is not None
188188 assert child2 is not None
189189 assert child1 .tag == "Child 1"
190190 assert child2 .tag == "Child 2"
191-
191+
192192 # Verify tree structure
193193 assert tree .parent ("https://example.com/child1" ).identifier == "https://example.com"
194194 assert tree .parent ("https://example.com/child2" ).identifier == "https://example.com"
@@ -199,7 +199,7 @@ def test_linktree_respects_depth_limit():
199199 root_html = '<html><title>Root</title><a href="https://example.com/level1">L1</a></html>'
200200 level1_html = '<html><title>Level 1</title><a href="https://example.com/level2">L2</a></html>'
201201 level2_html = '<html><title>Level 2</title><a href="https://example.com/level3">L3</a></html>'
202-
202+
203203 client = FakeClient ({
204204 "https://example.com" : FakeResponse ("https://example.com" , root_html , 200 ),
205205 "https://example.com/level1" : FakeResponse (
@@ -212,16 +212,16 @@ def test_linktree_respects_depth_limit():
212212 "https://example.com/level3" , '<html><title>Level 3</title></html>' , 200
213213 ),
214214 })
215-
215+
216216 # Build tree with depth=2 (root + 2 levels)
217217 tree = LinkTree ("https://example.com" , depth = 2 , client = client )
218218 tree .load ()
219-
219+
220220 # Root and level1 and level2 should exist
221221 assert tree .get_node ("https://example.com" ) is not None
222222 assert tree .get_node ("https://example.com/level1" ) is not None
223223 assert tree .get_node ("https://example.com/level2" ) is not None
224-
224+
225225 # Level3 should NOT exist (depth limit)
226226 assert tree .get_node ("https://example.com/level3" ) is None
227227
@@ -236,10 +236,10 @@ def test_linktree_handles_duplicate_links():
236236 <a href="https://example.com/other">Other</a>
237237 </html>
238238 """
239-
239+
240240 page_html = "<html><title>Target Page</title></html>"
241241 other_html = "<html><title>Other Page</title></html>"
242-
242+
243243 client = FakeClient ({
244244 "https://example.com" : FakeResponse ("https://example.com" , html_with_dup , 200 ),
245245 "https://example.com/page" : FakeResponse (
@@ -249,14 +249,14 @@ def test_linktree_handles_duplicate_links():
249249 "https://example.com/other" , other_html , 200
250250 ),
251251 })
252-
252+
253253 tree = LinkTree ("https://example.com" , depth = 1 , client = client )
254254 tree .load ()
255-
255+
256256 # Should have 3 nodes total: root + 2 unique children
257257 all_nodes = tree .all_nodes ()
258258 assert len (all_nodes ) == 3
259-
259+
260260 # Duplicate should have been attempted once (first add), then skipped
261261 assert tree .get_node ("https://example.com/page" ) is not None
262262 assert tree .get_node ("https://example.com/other" ) is not None
@@ -265,23 +265,23 @@ def test_linktree_handles_duplicate_links():
265265def test_linktree_save_json_creates_file ():
266266 """Test saveJSON writes a valid JSON file with tree structure."""
267267 html = '<html><title>Test JSON Save</title></html>'
268-
268+
269269 client = FakeClient ({
270270 "https://example.com" : FakeResponse ("https://example.com" , html , 200 ),
271271 })
272-
272+
273273 tree = LinkTree ("https://example.com" , depth = 0 , client = client )
274274 tree .load ()
275-
275+
276276 with tempfile .TemporaryDirectory () as tmpdir :
277277 # Patch project_root_directory to use temp dir
278278 with patch ("torbot.modules.linktree.project_root_directory" , tmpdir ):
279279 tree .saveJSON ()
280-
280+
281281 # Check that JSON file was created
282282 json_files = list (Path (tmpdir ).glob ("*.json" ))
283283 assert len (json_files ) == 1
284-
284+
285285 # Verify JSON file is not empty and is valid JSON
286286 with open (json_files [0 ]) as f :
287287 content = f .read ()
@@ -295,39 +295,39 @@ def test_linktree_save_json_creates_file():
295295def test_linktree_save_text_creates_file ():
296296 """Test save creates a text file representation of the tree."""
297297 html = '<html><title>Test Text Save</title></html>'
298-
298+
299299 client = FakeClient ({
300300 "https://example.com" : FakeResponse ("https://example.com" , html , 200 ),
301301 })
302-
302+
303303 tree = LinkTree ("https://example.com" , depth = 0 , client = client )
304304 tree .load ()
305-
305+
306306 with tempfile .TemporaryDirectory () as tmpdir :
307307 with patch ("torbot.modules.linktree.project_root_directory" , tmpdir ):
308308 tree .save ()
309-
309+
310310 # Check that text file was created
311311 txt_files = list (Path (tmpdir ).glob ("*.txt" ))
312312 assert len (txt_files ) == 1
313-
313+
314314 # Verify file is not empty
315315 assert txt_files [0 ].stat ().st_size > 0
316316
317317
318318def test_linktree_handles_non_200_status ():
319319 """Verify LinkTree records non-200 status codes correctly."""
320320 html = '<html><title>Not Found</title></html>'
321-
321+
322322 client = FakeClient ({
323323 "https://example.com/missing" : FakeResponse (
324324 "https://example.com/missing" , html , 404
325325 ),
326326 })
327-
327+
328328 tree = LinkTree ("https://example.com/missing" , depth = 0 , client = client )
329329 tree .load ()
330-
330+
331331 root = tree .get_node ("https://example.com/missing" )
332332 assert root is not None
333333 assert root .data .status == 404
@@ -345,17 +345,17 @@ def test_linktree_filters_invalid_links():
345345 <a href="#fragment">Fragment</a>
346346 </html>
347347 """
348-
348+
349349 valid_html = '<html><title>Valid</title></html>'
350-
350+
351351 client = FakeClient ({
352352 "https://example.com" : FakeResponse ("https://example.com" , html , 200 ),
353353 "https://valid.com" : FakeResponse ("https://valid.com" , valid_html , 200 ),
354354 })
355-
355+
356356 tree = LinkTree ("https://example.com" , depth = 1 , client = client )
357357 tree .load ()
358-
358+
359359 # Should have 2 nodes: root + 1 valid child
360360 all_nodes = tree .all_nodes ()
361361 assert len (all_nodes ) == 2
0 commit comments