@@ -448,6 +448,101 @@ def test_text_renderer_normal_no_violations(runinfo):
448448 assert "✓ No violations" in text
449449
450450
451+ # ----------------------------
452+ # Tests: TextReportRenderer human-readable explanations (always enabled)
453+ # ----------------------------
454+
455+
456+ def test_text_renderer_shows_human_readable_explanation (runinfo ):
457+ from pacta .reporting .builder import DefaultReportBuilder
458+ from pacta .reporting .renderers .text import TextReportRenderer
459+
460+ violations = [
461+ {
462+ "rule" : {"id" : "r1" , "name" : "No domain -> infra" , "severity" : "error" },
463+ "message" : "Domain depends on Infra" ,
464+ "status" : "new" ,
465+ "context" : {
466+ "target" : "dependency" ,
467+ "dep_type" : "import" ,
468+ "src_fqname" : "app.domain.service" ,
469+ "dst_fqname" : "app.infra.database" ,
470+ "src_layer" : "domain" ,
471+ "dst_layer" : "infra" ,
472+ },
473+ }
474+ ]
475+ report = DefaultReportBuilder (tool = "pacta" , version = "0.1.0" ).build (run = runinfo , violations = violations )
476+ text = TextReportRenderer (verbosity = "normal" ).render (report )
477+
478+ # Should contain human-readable explanation by default
479+ assert "app.domain.service" in text
480+ assert "app.infra.database" in text
481+ assert "domain layer" in text
482+ assert "infra layer" in text
483+ assert "imports" in text
484+
485+
486+ def test_text_renderer_node_violation_shows_explanation (runinfo ):
487+ from pacta .reporting .builder import DefaultReportBuilder
488+ from pacta .reporting .renderers .text import TextReportRenderer
489+
490+ violations = [
491+ {
492+ "rule" : {"id" : "r2" , "name" : "No services in domain" , "severity" : "warning" },
493+ "message" : "Services should not be in domain layer" ,
494+ "status" : "new" ,
495+ "context" : {
496+ "target" : "node" ,
497+ "fqname" : "app.domain.BillingService" ,
498+ "kind" : "class" ,
499+ "layer" : "domain" ,
500+ "container" : "backend" ,
501+ },
502+ }
503+ ]
504+ report = DefaultReportBuilder (tool = "pacta" , version = "0.1.0" ).build (run = runinfo , violations = violations )
505+ text = TextReportRenderer (verbosity = "normal" ).render (report )
506+
507+ # Should contain human-readable node violation explanation
508+ assert "class" in text
509+ assert "app.domain.BillingService" in text
510+ assert "domain layer" in text
511+ assert "container backend" in text
512+
513+
514+ def test_text_renderer_explanation_works_with_all_verbosity_levels (runinfo ):
515+ from pacta .reporting .builder import DefaultReportBuilder
516+ from pacta .reporting .renderers .text import TextReportRenderer
517+
518+ violations = [
519+ {
520+ "rule" : {"id" : "r1" , "name" : "Test" , "severity" : "error" },
521+ "message" : "Test message" ,
522+ "status" : "new" ,
523+ "context" : {
524+ "target" : "dependency" ,
525+ "dep_type" : "import" ,
526+ "src_fqname" : "a.b" ,
527+ "dst_fqname" : "c.d" ,
528+ },
529+ }
530+ ]
531+ report = DefaultReportBuilder (tool = "pacta" , version = "0.1.0" ).build (run = runinfo , violations = violations )
532+
533+ # Test with normal verbosity - should show human-readable explanation
534+ text_normal = TextReportRenderer (verbosity = "normal" ).render (report )
535+ assert "imports" in text_normal
536+
537+ # Test with verbose verbosity - should also show explanation
538+ text_verbose = TextReportRenderer (verbosity = "verbose" ).render (report )
539+ assert "imports" in text_verbose
540+
541+ # quiet mode doesn't show violations
542+ text_quiet = TextReportRenderer (verbosity = "quiet" ).render (report )
543+ assert "imports" not in text_quiet # quiet mode only shows summary
544+
545+
451546# ----------------------------
452547# Edge-cases: normalization of partial locations
453548# ----------------------------
0 commit comments