@@ -253,3 +253,136 @@ def test_bootstrap_json_hides_scan_progress(self, mock_zpl_cls):
253253 assert result .exit_code == 0 , result .output
254254 assert "Probing" not in result .output
255255 assert "printers_found" in result .output
256+
257+
258+
259+ # ---------------------------------------------------------------------------
260+ # zday man — interactive documentation browser
261+ # ---------------------------------------------------------------------------
262+
263+
264+ class TestCLIManHelp :
265+ """Tests for zday man --help output."""
266+
267+ def test_man_help (self ):
268+ """Test man --help shows expected options."""
269+ result = runner .invoke (app , ["man" , "--help" ])
270+ assert result .exit_code == 0
271+ assert "Interactive documentation browser" in result .output
272+ assert "--search" in result .output
273+ assert "--list" in result .output
274+
275+ def test_man_in_main_help (self ):
276+ """man subcommand appears in top-level help."""
277+ result = runner .invoke (app , ["--help" ])
278+ assert result .exit_code == 0
279+ assert "man" in result .output
280+
281+
282+ class TestCLIManList :
283+ """Tests for zday man --list."""
284+
285+ def test_list_topics (self ):
286+ """--list shows the topic table."""
287+ result = runner .invoke (app , ["man" , "--list" ])
288+ assert result .exit_code == 0
289+ assert "Quickstart" in result .output
290+ assert "CLI Reference" in result .output
291+ assert "DynamoDB" in result .output
292+ assert "Troubleshooting" in result .output
293+
294+
295+ class TestCLIManTopics :
296+ """Tests for direct topic display."""
297+
298+ def test_quickstart (self ):
299+ """zday man quickstart renders content."""
300+ result = runner .invoke (app , ["man" , "quickstart" ])
301+ assert result .exit_code == 0
302+ assert "Quickstart" in result .output
303+
304+ def test_cli_reference (self ):
305+ """zday man cli renders content."""
306+ result = runner .invoke (app , ["man" , "cli" ])
307+ assert result .exit_code == 0
308+ assert "CLI Reference" in result .output
309+
310+ def test_gui (self ):
311+ """zday man gui renders the UI guide."""
312+ result = runner .invoke (app , ["man" , "gui" ])
313+ assert result .exit_code == 0
314+ assert "GUI Usage" in result .output
315+
316+ def test_https (self ):
317+ """zday man https renders HTTPS docs."""
318+ result = runner .invoke (app , ["man" , "https" ])
319+ assert result .exit_code == 0
320+ assert "HTTPS" in result .output
321+
322+ def test_hardware (self ):
323+ """zday man hardware renders hardware guide."""
324+ result = runner .invoke (app , ["man" , "hardware" ])
325+ assert result .exit_code == 0
326+ assert "Hardware" in result .output
327+
328+ def test_unknown_topic_exits_1 (self ):
329+ """Unknown topic prints error and exits 1."""
330+ result = runner .invoke (app , ["man" , "nonexistent_xyz" ])
331+ assert result .exit_code == 1
332+ assert "Unknown topic" in result .output
333+
334+ def test_partial_match (self ):
335+ """Partial topic slug resolves correctly."""
336+ result = runner .invoke (app , ["man" , "quick" ])
337+ assert result .exit_code == 0
338+ assert "Quickstart" in result .output
339+
340+ def test_numeric_topic (self ):
341+ """Numeric input resolves to topic by index."""
342+ result = runner .invoke (app , ["man" , "1" ])
343+ assert result .exit_code == 0
344+ assert "Overview" in result .output
345+
346+
347+ class TestCLIManSearch :
348+ """Tests for zday man --search."""
349+
350+ def test_search_finds_results (self ):
351+ """--search returns matching lines."""
352+ result = runner .invoke (app , ["man" , "--search" , "printer" ])
353+ assert result .exit_code == 0
354+ assert "matches" in result .output .lower () or "printer" in result .output .lower ()
355+
356+ def test_search_no_results (self ):
357+ """--search with nonsense term shows no results."""
358+ result = runner .invoke (app , ["man" , "--search" , "xyzzy_nonexistent_qwerty" ])
359+ assert result .exit_code == 0
360+ assert "No results" in result .output
361+
362+
363+ class TestCLIManGracefulDegradation :
364+ """Tests for graceful handling of missing doc files."""
365+
366+ def test_missing_file_shows_warning (self ):
367+ """A topic pointing to a missing file shows a warning, not a crash."""
368+ from zebra_day .cli .man import TOPICS , Topic , TopicSource , _get_topic_content
369+
370+ fake_topic = Topic (
371+ name = "Missing" ,
372+ description = "test" ,
373+ sources = [TopicSource ("does_not_exist.md" )],
374+ )
375+ content = _get_topic_content (fake_topic )
376+ assert "not found" in content .lower ()
377+
378+ def test_missing_section_shows_warning (self ):
379+ """A topic with a bad heading shows a warning, not a crash."""
380+ from zebra_day .cli .man import TOPICS , Topic , TopicSource , _get_topic_content
381+
382+ fake_topic = Topic (
383+ name = "BadSection" ,
384+ description = "test" ,
385+ sources = [TopicSource ("README.md" , "HEADING_THAT_DOES_NOT_EXIST_12345" )],
386+ )
387+ content = _get_topic_content (fake_topic )
388+ assert "not found" in content .lower ()
0 commit comments