ci / verifier-pack (push) Successful in 1m29s
- packs/essentiels : 20 prompts en 4 catégories (Général, Écriture, Code, Analyse), en-têtes conformes au parseur, variables déclarées = utilisées - tests/run_tests.ahk : suites Frontmatter, Variables, JSON, Recherche, encodage UTF-8 (à exécuter sous Windows avec AutoHotkey v2) - scripts/check_pack.py + .gitea/workflows/ci.yml : cohérence du pack - build.ps1 : tests puis compilation Ahk2Exe et zip portable - docs : document d'architecture et de conception v1.0
138 lines
5.3 KiB
AutoHotkey
138 lines
5.3 KiB
AutoHotkey
#Requires AutoHotkey v2.0
|
|
; Tests autonomes de PromptKey (architecture §22) — à lancer sous Windows :
|
|
; AutoHotkey64.exe tests\run_tests.ahk
|
|
; Sortie : lignes OK / ÉCHEC sur la console (ou dans le fichier passé en premier argument),
|
|
; code de sortie 0 si tout passe, 1 sinon. Aucune GUI, aucune injection.
|
|
#SingleInstance Off
|
|
|
|
#Include ..\lib\Util.ahk
|
|
#Include ..\lib\Json.ahk
|
|
#Include ..\lib\Frontmatter.ahk
|
|
#Include ..\lib\VariableEngine.ahk
|
|
#Include ..\lib\PromptStore.ahk
|
|
#Include ..\lib\Search.ahk
|
|
|
|
global failures := 0
|
|
global outFile := A_Args.Length > 0 ? A_Args[1] : ""
|
|
|
|
Report(ok, name, detail := "") {
|
|
global failures, outFile
|
|
if (!ok)
|
|
failures++
|
|
line := (ok ? "OK " : "ÉCHEC") " " name (detail != "" ? " — " detail : "") "`n"
|
|
if (outFile != "")
|
|
FileAppend(line, outFile, "UTF-8")
|
|
else
|
|
FileAppend(line, "*")
|
|
}
|
|
|
|
Check(cond, name, detail := "") {
|
|
Report(cond, name, detail)
|
|
}
|
|
|
|
; ---------- Util : normalisation ----------
|
|
Check(Util.Normalize("Résumé ÉÉ") = "resume ee", "Normalize accents")
|
|
Check(Util.Slugify("Revue de code !") = "revue-de-code", "Slugify")
|
|
|
|
; ---------- Frontmatter : analyse ----------
|
|
sample := "
|
|
(
|
|
---
|
|
id: test-id-1
|
|
title: Résumer en 5 points
|
|
tags: [résumé, synthèse, court]
|
|
favorite: true
|
|
pinned: 2
|
|
variables:
|
|
- name: ton
|
|
label: Ton de la réponse
|
|
type: enum
|
|
choices: [neutre, formel, amical]
|
|
default: neutre
|
|
---
|
|
|
|
Résume avec un ton {{ton}}.
|
|
|
|
Texte :
|
|
{{selection}}
|
|
)"
|
|
parsed := Frontmatter.Parse(sample)
|
|
Check(parsed["errors"].Length = 0, "Frontmatter sans erreur", parsed["errors"].Length ? parsed["errors"][1] : "")
|
|
Check(parsed["meta"]["title"] = "Résumer en 5 points", "Frontmatter title")
|
|
Check(parsed["meta"]["tags"].Length = 3, "Frontmatter tags (3)")
|
|
Check(parsed["meta"]["favorite"] = 1, "Frontmatter favorite booléen")
|
|
Check(parsed["meta"]["variables"].Length = 1, "Frontmatter 1 variable")
|
|
Check(parsed["meta"]["variables"][1]["choices"].Length = 3, "Frontmatter choices (3)")
|
|
Check(InStr(parsed["body"], "{{selection}}") > 0, "Frontmatter corps conservé")
|
|
|
|
; Fichier sans en-tête : accepté, corps = tout.
|
|
plain := Frontmatter.Parse("Juste un texte.")
|
|
Check(plain["hasHeader"] = false && plain["body"] = "Juste un texte.", "Sans en-tête accepté")
|
|
|
|
; Erreur : en-tête jamais fermé.
|
|
bad := Frontmatter.Parse("---`nid: x`ntitle: y`ncorps sans fermeture")
|
|
Check(bad["errors"].Length > 0, "En-tête non fermé = erreur signalée")
|
|
|
|
; Aller-retour sérialisation.
|
|
item := PromptItem("test.md", "Général", parsed)
|
|
ser := Frontmatter.Serialize(item.Meta, item.Body)
|
|
reparsed := Frontmatter.Parse(ser)
|
|
Check(reparsed["errors"].Length = 0 && reparsed["meta"]["title"] = "Résumer en 5 points", "Aller-retour Serialize/Parse")
|
|
|
|
; ---------- Variables ----------
|
|
ctx := Map("selection", "TEXTE SÉLECTIONNÉ", "clipboardText", "PRESSE", "process", "chrome.exe")
|
|
defs := VariableEngine.ManualVars(item)
|
|
Check(defs.Length = 1 && defs[1]["name"] = "ton", "ManualVars : ton seulement (selection est automatique)")
|
|
resolved := VariableEngine.Resolve(item.Body, Map("ton", "formel"), ctx)
|
|
Check(InStr(resolved["text"], "ton formel") > 0, "Resolve remplace {{ton}}")
|
|
Check(InStr(resolved["text"], "TEXTE SÉLECTIONNÉ") > 0, "Resolve remplace {{selection}}")
|
|
Check(resolved["unresolved"].Length = 0, "Resolve sans non-résolue")
|
|
withCursor := VariableEngine.Resolve("Début {{cursor}} fin", Map(), ctx)
|
|
Check(withCursor["cursorFromEnd"] = 4 && withCursor["text"] = "Début fin", "Marqueur cursor : position et retrait")
|
|
|
|
; ---------- JSON ----------
|
|
obj := Json.Parse('{"a": 1, "b": [1, 2, "trois"], "c": {"d": "x\ny"}}')
|
|
Check(obj["a"] = 1 && obj["b"].Length = 3 && obj["c"]["d"] = "x`ny", "JSON parse imbriqué")
|
|
round := Json.Parse(Json.Stringify(obj))
|
|
Check(round["b"][3] = "trois", "JSON aller-retour")
|
|
|
|
; ---------- Recherche ----------
|
|
class FakePrompt {
|
|
__New(title, cat, tags, body) {
|
|
this.Id := title
|
|
this.Title := title
|
|
this.Category := cat
|
|
this.Tags := tags
|
|
this.Body := body
|
|
this.Pinned := 0
|
|
this.Favorite := 0
|
|
}
|
|
}
|
|
prompts := [
|
|
FakePrompt("Résumer en 5 points", "Général", ["résumé"], "Résume le texte"),
|
|
FakePrompt("Revue de code", "Code", ["code"], "Relis ce code"),
|
|
FakePrompt("Traduire en anglais", "Écriture", ["traduction"], "Traduis")]
|
|
found := Search.Filter(prompts, "resu", Map())
|
|
Check(found.Length = 1 && found[1].Title = "Résumer en 5 points", "Recherche 'resu' trouve 'Résumer' (accents)")
|
|
found2 := Search.Filter(prompts, "code", Map())
|
|
Check(found2.Length >= 1 && found2[1].Title = "Revue de code", "Recherche 'code' classe la revue en premier")
|
|
all := Search.Filter(prompts, "", Map())
|
|
Check(all.Length = 3, "Recherche vide : toute la bibliothèque")
|
|
|
|
; ---------- Encodage : aller-retour UTF-8 bit à bit (§19.4) ----------
|
|
tmpFile := A_Temp "\promptkey-test-encodage.md"
|
|
tricky := "é à — ‘’ « » 😀`r`n{{variable}} deuxième ligne"
|
|
f := FileOpen(tmpFile, "w", "UTF-8")
|
|
f.Write(tricky)
|
|
f.Close()
|
|
back := FileRead(tmpFile, "UTF-8")
|
|
Check(back = tricky, "UTF-8 aller-retour identique")
|
|
FileDelete(tmpFile)
|
|
|
|
; ---------- Bilan ----------
|
|
if (outFile != "")
|
|
FileAppend("----`n" (failures = 0 ? "TOUS LES TESTS PASSENT" : failures " ÉCHEC(S)") "`n", outFile, "UTF-8")
|
|
else
|
|
FileAppend("----`n" (failures = 0 ? "TOUS LES TESTS PASSENT" : failures " ÉCHEC(S)") "`n", "*")
|
|
ExitApp(failures = 0 ? 0 : 1)
|