Files
Loki/internal/loki/web_files_zip_test.go
T
MichaelandClaude Opus 5 a7587235c6 Panneau Fichiers : toute la discussion en une archive .zip
Bouton « .zip » dans le pied du panneau : la discussion entière — dossiers
et sous-dossiers compris — part en une archive, nommée d'après le titre de
la discussion. Même danse en trois temps que le téléchargement de fichier
(meta → brut, ou tranches base64 derrière le tunnel chiffré), liens
symboliques ignorés, parcours borné comme le calcul de taille du panneau.
Le scope « hors discussion » a son propre zip, sans le dossier des
discussions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:48:11 +02:00

97 lines
2.5 KiB
Go

package loki
import (
"archive/zip"
"os"
"path/filepath"
"testing"
)
// L'archive embarque TOUT l'arbre — fichiers, dossiers, sous-dossiers — avec
// des chemins relatifs en avant-slash.
func TestZipToutLArbre(t *testing.T) {
ws := withWorkspace(t)
writeFile(t, filepath.Join(ws, "racine.txt"), "a")
writeFile(t, filepath.Join(ws, "docs", "note.md"), "b")
writeFile(t, filepath.Join(ws, "src", "sub", "deep", "main.go"), "c")
dest := filepath.Join(t.TempDir(), "out.zip")
n, err := buildZip(ws, dest, false)
if err != nil {
t.Fatal(err)
}
if n != 3 {
t.Fatalf("%d fichiers archivés, attendu 3", n)
}
zr, err := zip.OpenReader(dest)
if err != nil {
t.Fatal(err)
}
defer zr.Close()
got := map[string]bool{}
for _, f := range zr.File {
got[f.Name] = true
}
for _, want := range []string{"racine.txt", "docs/note.md", "src/sub/deep/main.go"} {
if !got[want] {
t.Errorf("%s absent de l'archive (contenu : %v)", want, got)
}
}
}
// Le scope hors-discussion n'aspire pas le dossier des discussions.
func TestZipLegacyExclutDiscussions(t *testing.T) {
ws := withWorkspace(t)
root := agentWorkspace()
writeFile(t, filepath.Join(root, "orphelin.txt"), "x")
writeFile(t, filepath.Join(ws, "dans-discussion.txt"), "y") // sous discussions/
dest := filepath.Join(t.TempDir(), "out.zip")
n, err := buildZip(root, dest, true)
if err != nil {
t.Fatal(err)
}
zr, err := zip.OpenReader(dest)
if err != nil {
t.Fatal(err)
}
defer zr.Close()
for _, f := range zr.File {
if f.Name == "discussions/"+filepath.Base(ws)+"/dans-discussion.txt" || filepath.Dir(f.Name) != "." && f.Name[:12] == "discussions/" {
t.Errorf("le dossier des discussions a fuité dans l'archive : %s", f.Name)
}
}
if n < 1 {
t.Fatal("orphelin.txt manquant")
}
}
// Une discussion vide : 404 propre, pas d'archive fantôme.
func TestZipVide(t *testing.T) {
ws := withWorkspace(t)
dest := filepath.Join(t.TempDir(), "out.zip")
n, err := buildZip(ws, dest, false)
if err != nil {
t.Fatal(err)
}
if n != 0 {
t.Fatalf("%d fichiers dans une discussion vide", n)
}
_ = os.Remove(dest)
}
// slugify : titres réels → noms de fichiers sûrs.
func TestSlugify(t *testing.T) {
cases := map[string]string{
"Corrige le bug d'auth": "corrige-le-bug-dauth",
" Déjà vu ! ": "dj-vu",
"": "",
"UPPER case.and.dots": "upper-case-and-dots",
}
for in, want := range cases {
if got := slugify(in); got != want {
t.Errorf("slugify(%q) = %q, attendu %q", in, got, want)
}
}
}