diff --git a/json_to_md.py b/json_to_md.py
index 3003bee6c..d1d5e69b0 100644
--- a/json_to_md.py
+++ b/json_to_md.py
@@ -2,37 +2,31 @@ import json
from datetime import datetime
import argparse
-def strip_params(nodeid):
- return nodeid.split('[')[0] if nodeid else ""
-def get_emoji(outcome):
- icons = {
- "passed": "✅",
- "failed": "❌",
- "skipped": "⏭️",
- "error": "🛑"
- }
- return icons.get(outcome, "🧐")
+def format_dict(d):
+ """Formate un dictionnaire en Markdown lisible"""
+ if not d:
+ return "None"
+ return "\n".join(f"- **{k}:** `{v if v else 'None'}`" for k, v in d.items())
+
+
+def format_list_of_dicts(l):
+ if not l:
+ return "None"
+ result = ""
+ for i, item in enumerate(l, 1):
+ result += f"\n - Entrée {i}:\n"
+ result += "\n".join(f" - {k}: `{v if v else 'None'}`" for k, v in item.items())
+ result += "\n"
+ return result
-def pretty_dict_md(d, indent=0, exclude_keys=None):
- lines = []
- exclude_keys = exclude_keys or []
- for k, v in d.items():
- if k in exclude_keys:
- continue
- value = "None" if v in [None, "", [], {}] else v
- if isinstance(value, dict):
- lines.append(" " * indent + f"- **{k}**:")
- lines += pretty_dict_md(value, indent + 1)
- else:
- lines.append(" " * indent + f"- **{k}**: `{value}`")
- return lines
def json_to_adaptive_md(json_path, md_path):
with open(json_path) as f:
data = json.load(f)
with open(md_path, 'w', encoding='utf-8') as f:
+ # Titre principal
f.write(f"# 🏗 Rapport de Tests (Générique)\n")
f.write(f"*Généré le {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*\n\n")
@@ -40,69 +34,81 @@ def json_to_adaptive_md(json_path, md_path):
if 'summary' in data:
f.write("## 📋 Summary\n")
for key, value in data['summary'].items():
- val = "None" if value in [None, "", [], {}] else value
- f.write(f"- **{key.capitalize()}:** `{val}`\n")
- if 'duration' in data:
- f.write(f"- **Durée totale:** `{data['duration']:.3f}` s\n")
- f.write("\n")
+ f.write(f"- **{key.capitalize()}:** `{value}`\n")
- # Collectors
- if 'collectors' in data:
- f.write("## 📦 Collectors\n")
- for collector in data['collectors']:
- nodeid = strip_params(collector.get('nodeid', ''))
- outcome = collector.get('outcome', 'unknown')
- emoji = get_emoji(outcome)
- f.write(f"\n{emoji} `{nodeid}`
\n\n")
- for line in pretty_dict_md(collector, exclude_keys=['nodeid']):
- f.write(line + "\n")
- f.write("\n \n\n")
+ if "duration" in data:
+ f.write(f"- **Durée totale:** `{data['duration']:.3f}` s\n\n")
- # Tests
+ # Section Collector
+ if "collectors" in data:
+ f.write("## 📚 Collectors\n")
+ for collector in data["collectors"]:
+ nodeid = collector.get("nodeid", "Sans nom")
+ status = collector.get("outcome", "unknown")
+ emoji = "✅" if status == "passed" else "⚠️"
+ f.write(f"\n\n{emoji} `{nodeid}`
\n\n")
+ f.write(f"- **Outcome:** `{status}`\n")
+ result = collector.get("result", [])
+ if isinstance(result, list):
+ f.write("- **Resultats:**\n")
+ f.write(format_list_of_dicts(result))
+ else:
+ f.write("- **Resultat:**\n")
+ f.write(f"{format_dict(result)}\n")
+ f.write("\n \n")
+
+ # Section Tests
if 'tests' in data:
- f.write("## 🧪 Tests\n")
+ f.write("\n## 🧪 Tests\n")
current_file = None
for test in data['tests']:
- nodeid = test.get('nodeid', '')
- if '::' in nodeid:
- file_path = nodeid.split('::')[0]
- if file_path != current_file:
- current_file = file_path
- f.write(f"\n## 📄 Fichier: `{current_file}`\n")
+ if '::' in test['nodeid']:
+ new_file = test['nodeid'].split('::')[0]
+ if new_file != current_file:
+ current_file = new_file
+ f.write(f"\n### 📄 Fichier: `{current_file}`\n")
- test_name = strip_params(nodeid.split('::')[-1])
- f.write(f"\n### 🧪 {test_name}\n")
+ test_name = test['nodeid'].split('::')[-1].split('[')[0]
+ f.write(f"\n#### 🔹 {test_name}\n")
- # Paramètres
- if '[' in nodeid:
- params = nodeid.split('[')[1].rstrip(']')
- f.write("- **Paramètres:**\n")
- for i, param in enumerate(params.split('-'), 1):
- f.write(f" - Param {i}: `{param}`\n")
+ if '[' in test['nodeid']:
+ params = test['nodeid'].split('[')[1].rstrip(']')
+ f.write("- **Paramètres:**\n")
+ for i, param in enumerate(params.split('-'), 1):
+ f.write(f" - Param {i}: `{param}`\n")
- # Statut
- outcome = test.get("outcome", "None")
- emoji = get_emoji(outcome)
- f.write(f"- **Statut:** {emoji} `{outcome}`\n")
+ outcome = test.get("outcome", "unknown")
+ emoji = {
+ "passed": "✅",
+ "failed": "❌",
+ "skipped": "⏭️",
+ "error": "🚫"
+ }.get(outcome, "🔍")
+ f.write(f"- **Statut:** {emoji} `{outcome}`\n")
- # Durée
- duration = test.get("call", {}).get("duration")
- if duration is not None:
- f.write(f"- **Durée:** `{duration:.6f}` s\n")
- else:
- f.write(f"- **Durée:** `None`\n")
+ if "call" in test and "duration" in test["call"]:
+ f.write(f"- **Durée:** `{test['call']['duration']:.6f}` s\n")
- # Détails supplémentaires si != passed
- if outcome != "passed":
- call_data = test.get("call", {})
- if call_data:
- f.write("\n\n🔍 Détails
\n\n")
- for line in pretty_dict_md(call_data):
- f.write(line + "\n")
- f.write("\n \n")
+ if outcome != "passed":
+ call_data = test.get("call", {})
+ if call_data:
+ f.write("\n- **Détails:**\n")
+ for k, v in call_data.items():
+ f.write(f" - **{k}:**\n")
+ if isinstance(v, dict):
+ f.write(format_dict(v) + "\n")
+ elif isinstance(v, list):
+ if all(isinstance(item, dict) for item in v):
+ f.write(format_list_of_dicts(v) + "\n")
+ else:
+ f.write(" ```
+" + "\n".join(str(item) for item in v) + "\n ```\n")
+ else:
+ f.write(f" ```
+{v if v else 'None'}\n ```\n")
+ f.write("\n" + "-" * 40 + "\n")
- f.write("\n" + "-" * 50 + "\n")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Convert Pytest JSON report to Markdown")