mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-22 22:48:11 +02:00
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>
This commit is contained in:
1 parent
53d23418e9
commit
a7587235c6
5 files changed
+447
No files matched your search
@@ -0,0 +1,96 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user