feat(skills): add chart-to-chat skill for dbt-charts and quickchart
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Unit and integration tests for chart.py
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
# Add scripts directory to path
|
||||
SCRIPTS_DIR = Path(__file__).resolve().parent
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
from chart import parse_input_data
|
||||
|
||||
|
||||
class TestChartParser(unittest.TestCase):
|
||||
def test_list_of_dicts(self):
|
||||
raw = json.dumps([
|
||||
{"day": "Mo", "temp": 18},
|
||||
{"day": "Di", "temp": 22},
|
||||
{"day": "Mi", "temp": 19},
|
||||
])
|
||||
cols, rows, x, y = parse_input_data(raw)
|
||||
self.assertEqual(cols, ["day", "temp"])
|
||||
self.assertEqual(len(rows), 3)
|
||||
self.assertEqual(x, "day")
|
||||
self.assertEqual(y, "temp")
|
||||
|
||||
def test_dict_key_value(self):
|
||||
raw = json.dumps({"Bier": 4.5, "Pizza": 12.0, "Kaffee": 3.2})
|
||||
cols, rows, x, y = parse_input_data(raw)
|
||||
self.assertEqual(cols, ["category", "value"])
|
||||
self.assertEqual(len(rows), 3)
|
||||
self.assertEqual(x, "category")
|
||||
self.assertEqual(y, "value")
|
||||
|
||||
def test_explicit_columns_values(self):
|
||||
raw = json.dumps({
|
||||
"columns": ["Monat", "Umsatz"],
|
||||
"values": [["Jan", 100], ["Feb", 150]]
|
||||
})
|
||||
cols, rows, x, y = parse_input_data(raw)
|
||||
self.assertEqual(cols, ["Monat", "Umsatz"])
|
||||
self.assertEqual(len(rows), 2)
|
||||
self.assertEqual(x, "Monat")
|
||||
self.assertEqual(y, "Umsatz")
|
||||
|
||||
|
||||
class TestChartCLI(unittest.TestCase):
|
||||
def run_cli(self, args, stdin_input=None):
|
||||
cmd = [sys.executable, str(SCRIPTS_DIR / "chart.py")] + args
|
||||
res = subprocess.run(
|
||||
cmd,
|
||||
input=stdin_input,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30,
|
||||
)
|
||||
return res
|
||||
|
||||
def test_bar_chart_generation(self):
|
||||
data = json.dumps([
|
||||
{"label": "Projekt A", "stunden": 14},
|
||||
{"label": "Projekt B", "stunden": 28},
|
||||
{"label": "Projekt C", "stunden": 8},
|
||||
])
|
||||
out_path = Path("/tmp/charts/test_bar.png")
|
||||
if out_path.exists():
|
||||
out_path.unlink()
|
||||
|
||||
res = self.run_cli(["--type", "bar", "--title", "Projektstunden", "--data", data, "--output", str(out_path)])
|
||||
self.assertEqual(res.returncode, 0, f"Stderr: {res.stderr}")
|
||||
self.assertTrue(res.stdout.strip().startswith("MEDIA:"))
|
||||
self.assertTrue(out_path.exists())
|
||||
self.assertGreater(out_path.stat().st_size, 1000)
|
||||
|
||||
def test_line_chart_stdin(self):
|
||||
data = json.dumps([
|
||||
{"datum": "2026-09-10", "puls": 62},
|
||||
{"datum": "2026-09-11", "puls": 58},
|
||||
{"datum": "2026-09-12", "puls": 65},
|
||||
{"datum": "2026-09-13", "puls": 59},
|
||||
])
|
||||
out_path = Path("/tmp/charts/test_line.png")
|
||||
if out_path.exists():
|
||||
out_path.unlink()
|
||||
|
||||
res = self.run_cli(["--type", "line", "--title", "Ruhepuls Verlauf", "--data", "-", "--output", str(out_path)], stdin_input=data)
|
||||
self.assertEqual(res.returncode, 0, f"Stderr: {res.stderr}")
|
||||
self.assertTrue(res.stdout.strip().startswith("MEDIA:"))
|
||||
self.assertTrue(out_path.exists())
|
||||
self.assertGreater(out_path.stat().st_size, 1000)
|
||||
|
||||
def test_donut_chart(self):
|
||||
data = json.dumps([
|
||||
{"bereich": "Wohnen", "kosten": 950},
|
||||
{"bereich": "Essen", "kosten": 450},
|
||||
{"bereich": "Mobilität", "kosten": 120},
|
||||
{"bereich": "Freizeit", "kosten": 200},
|
||||
])
|
||||
out_path = Path("/tmp/charts/test_donut.png")
|
||||
if out_path.exists():
|
||||
out_path.unlink()
|
||||
|
||||
res = self.run_cli(["--type", "donut", "--title", "Ausgaben", "--data", data, "--output", str(out_path)])
|
||||
self.assertEqual(res.returncode, 0, f"Stderr: {res.stderr}")
|
||||
self.assertTrue(res.stdout.strip().startswith("MEDIA:"))
|
||||
self.assertTrue(out_path.exists())
|
||||
self.assertGreater(out_path.stat().st_size, 1000)
|
||||
|
||||
def test_quickchart_fallback_engine(self):
|
||||
data = json.dumps([
|
||||
{"fach": "Mathe", "note": 1.7},
|
||||
{"fach": "Physik", "note": 2.0},
|
||||
{"fach": "Informatik", "note": 1.0},
|
||||
])
|
||||
out_path = Path("/tmp/charts/test_quickchart.png")
|
||||
if out_path.exists():
|
||||
out_path.unlink()
|
||||
|
||||
res = self.run_cli(["--engine", "quickchart", "--type", "bar", "--title", "Notenspiegel", "--data", data, "--output", str(out_path)])
|
||||
self.assertEqual(res.returncode, 0, f"Stderr: {res.stderr}")
|
||||
self.assertTrue(res.stdout.strip().startswith("MEDIA:"))
|
||||
self.assertTrue(out_path.exists())
|
||||
self.assertGreater(out_path.stat().st_size, 1000)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user