Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
385 changes: 385 additions & 0 deletions src/test/java/tg/cyberlabmanager/pdf/PdfExporterTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,385 @@
package tg.cyberlabmanager.pdf;

import tg.cyberlabmanager.model.*;

import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
* Tests unitaires de PdfExporter.
* Chaque test génère un vrai fichier PDF temporaire puis le supprime.
* On ne teste pas le contenu visuel mais les comportements : création,
* taille, gestion des cas limites, robustesse.
*/
class PdfExporterTest {

private PdfExporter exporter;
private String tempDir;

@BeforeEach
void setUp() {
exporter = new PdfExporter();
tempDir = System.getProperty("java.io.tmpdir");
}

// Utilitaires

/** Crée un labo de test avec les champs remplis. */
private Lab makeLab(String title, String category, String description) {
Lab lab = new Lab();
lab.setTitle(title);
lab.setCategory(category);
lab.setDescription(description);
return lab;
}

/** Crée une VM de test. */
private VirtualMachine makeVM(String name, String uuid, VMStatus status) {
VirtualMachine vm = new VirtualMachine();
vm.setName(name);
vm.setUuid(uuid);
vm.setStatus(status);
return vm;
}

/** Crée un snapshot de test. */
private Snapshot makeSnapshot(String name, boolean online) {
Snapshot s = new Snapshot();
s.setName(name);
s.setCreatedAt(LocalDateTime.of(2026, 6, 1, 10, 0));
s.setDescription("Description du snapshot");
s.setOnline(online);
return s;
}

/** Crée une entrée de journal de test. */
private JournalEntry makeJournalEntry(String content) {
JournalEntry e = new JournalEntry();
e.setTimestamp(LocalDateTime.of(2026, 6, 1, 14, 30));
e.setContent(content);
return e;
}

/** Retourne un chemin de fichier PDF temporaire unique. */
private String tempPdf(String name) {
return tempDir + File.separator + "cyberlab_test_" + name + "_" +
System.currentTimeMillis() + ".pdf";
}

/** Supprime un fichier si il existe. */
private void cleanup(String path) {
File f = new File(path);
if (f.exists()) f.delete();
}

// Tests de création de fichier

@Test
@DisplayName("exportLabToPdf : crée bien un fichier PDF sur le disque")
void testFileIsCreated() throws IOException {
String path = tempPdf("creation");
try {
Lab lab = makeLab("Labo Malware", "malware", "Test de création");
exporter.exportLabToPdf(lab, List.of(), List.of(), List.of(), path);

assertTrue(new File(path).exists(), "Le fichier PDF doit exister");
} finally {
cleanup(path);
}
}

@Test
@DisplayName("exportLabToPdf : le fichier PDF n'est pas vide")
void testFileIsNotEmpty() throws IOException {
String path = tempPdf("notempty");
try {
Lab lab = makeLab("Labo Test", "pentest", null);
exporter.exportLabToPdf(lab, List.of(), List.of(), List.of(), path);

long size = new File(path).length();
assertTrue(size > 0, "Le fichier PDF ne doit pas être vide, taille : " + size);
} finally {
cleanup(path);
}
}

@Test
@DisplayName("exportLabToPdf : le fichier commence par la signature PDF (%PDF)")
void testFileIsPdf() throws IOException {
String path = tempPdf("signature");
try {
Lab lab = makeLab("Labo Réseau", "réseau", null);
exporter.exportLabToPdf(lab, List.of(), List.of(), List.of(), path);

byte[] header = Files.readAllBytes(new File(path).toPath());
// Un PDF valide commence toujours par "%PDF"
String start = new String(header, 0, Math.min(4, header.length));
assertEquals("%PDF", start, "Le fichier doit commencer par %PDF");
} finally {
cleanup(path);
}
}

// Tests avec données réelles

@Test
@DisplayName("exportLabToPdf : fonctionne avec une VM, un snapshot et une note")
void testWithFullData() throws IOException {
String path = tempPdf("fulldata");
try {
Lab lab = makeLab("Labo Pentest", "pentest", "Tests d'intrusion réseau");

VirtualMachine vm = makeVM("Kali-Linux", "uuid-kali-001", VMStatus.RUNNING);
vm.setDocumentationUrl("https://kali.org");

Snapshot snap = makeSnapshot("Etat initial", false);
JournalEntry entry = makeJournalEntry("Scan réseau effectué — ports 22, 80, 443 ouverts");

exporter.exportLabToPdf(
lab,
List.of(vm),
List.of(snap),
List.of(entry),
path
);

assertTrue(new File(path).exists());
assertTrue(new File(path).length() > 1000,
"Le PDF avec données doit être plus grand que 1Ko");
} finally {
cleanup(path);
}
}

@Test
@DisplayName("exportLabToPdf : fonctionne avec plusieurs VMs")
void testWithMultipleVMs() throws IOException {
String path = tempPdf("multivms");
try {
Lab lab = makeLab("Labo Multi", "malware", null);

List<VirtualMachine> vms = List.of(
makeVM("Windows-10", "uuid-win-001", VMStatus.POWERED_OFF),
makeVM("Ubuntu-22", "uuid-ubuntu-001", VMStatus.RUNNING),
makeVM("Kali-2024", "uuid-kali-002", VMStatus.SAVED)
);

exporter.exportLabToPdf(lab, vms, List.of(), List.of(), path);

assertTrue(new File(path).exists());
} finally {
cleanup(path);
}
}

@Test
@DisplayName("exportLabToPdf : fonctionne avec plusieurs snapshots")
void testWithMultipleSnapshots() throws IOException {
String path = tempPdf("multisnaps");
try {
Lab lab = makeLab("Labo Snap", "réseau", null);
VirtualMachine vm = makeVM("VM-Test", "uuid-test", VMStatus.POWERED_OFF);

List<Snapshot> snaps = List.of(
makeSnapshot("Snap initial", false),
makeSnapshot("Snap après config", false),
makeSnapshot("Snap VM allumée", true)
);

exporter.exportLabToPdf(lab, List.of(vm), snaps, List.of(), path);

assertTrue(new File(path).exists());
} finally {
cleanup(path);
}
}

@Test
@DisplayName("exportLabToPdf : fonctionne avec plusieurs entrées de journal")
void testWithMultipleJournalEntries() throws IOException {
String path = tempPdf("multijournal");
try {
Lab lab = makeLab("Labo Journal", "malware", null);

List<JournalEntry> entries = List.of(
makeJournalEntry("Première observation : comportement suspect détecté"),
makeJournalEntry("Deuxième observation : connexions réseau anormales vers 192.168.1.100"),
makeJournalEntry("Troisième observation : fichiers chiffrés dans le répertoire Documents")
);

exporter.exportLabToPdf(lab, List.of(), List.of(), entries, path);

assertTrue(new File(path).exists());
} finally {
cleanup(path);
}
}

// Tests des cas limites

@Test
@DisplayName("exportLabToPdf : labo sans description ne plante pas")
void testLabWithoutDescription() throws IOException {
String path = tempPdf("nodesc");
try {
Lab lab = makeLab("Labo Sans Description", "pentest", null);
assertDoesNotThrow(() ->
exporter.exportLabToPdf(lab, List.of(), List.of(), List.of(), path)
);
} finally {
cleanup(path);
}
}

@Test
@DisplayName("exportLabToPdf : VM sans statut ne plante pas")
void testVMWithoutStatus() throws IOException {
String path = tempPdf("nostatus");
try {
Lab lab = makeLab("Labo", "malware", null);
VirtualMachine vm = new VirtualMachine();
vm.setName("VM sans statut");
vm.setUuid("uuid-nostatus");
// status non défini — reste UNKNOWN par défaut

assertDoesNotThrow(() ->
exporter.exportLabToPdf(lab, List.of(vm), List.of(), List.of(), path)
);
} finally {
cleanup(path);
}
}

@Test
@DisplayName("exportLabToPdf : VM sans documentationUrl ne plante pas")
void testVMWithoutDocUrl() throws IOException {
String path = tempPdf("nodocurl");
try {
Lab lab = makeLab("Labo", "réseau", null);
VirtualMachine vm = makeVM("VM-Test", "uuid-nodoc", VMStatus.RUNNING);
// documentationUrl non défini

assertDoesNotThrow(() ->
exporter.exportLabToPdf(lab, List.of(vm), List.of(), List.of(), path)
);
} finally {
cleanup(path);
}
}

@Test
@DisplayName("exportLabToPdf : snapshot sans date ne plante pas")
void testSnapshotWithoutDate() throws IOException {
String path = tempPdf("nodate");
try {
Lab lab = makeLab("Labo", "malware", null);
Snapshot snap = new Snapshot();
snap.setName("Snap sans date");
// createdAt null

assertDoesNotThrow(() ->
exporter.exportLabToPdf(lab, List.of(), List.of(snap), List.of(), path)
);
} finally {
cleanup(path);
}
}

@Test
@DisplayName("exportLabToPdf : journal entry sans timestamp ne plante pas")
void testJournalEntryWithoutTimestamp() throws IOException {
String path = tempPdf("notimestamp");
try {
Lab lab = makeLab("Labo", "pentest", null);
JournalEntry entry = new JournalEntry();
entry.setContent("Note sans horodatage");
// timestamp null

assertDoesNotThrow(() ->
exporter.exportLabToPdf(lab, List.of(), List.of(), List.of(entry), path)
);
} finally {
cleanup(path);
}
}

@Test
@DisplayName("exportLabToPdf : note longue est gérée sans planter")
void testLongJournalEntry() throws IOException {
String path = tempPdf("longnote");
try {
Lab lab = makeLab("Labo", "malware", null);
// Texte très long qui devrait déclencher le wrapping
String longContent = "Analyse détaillée : ".repeat(20) +
"comportement suspect détecté avec connexions réseau anormales " +
"vers plusieurs adresses IP externes non reconnues dans la liste blanche.";

JournalEntry entry = makeJournalEntry(longContent);

assertDoesNotThrow(() ->
exporter.exportLabToPdf(lab, List.of(), List.of(), List.of(entry), path)
);
} finally {
cleanup(path);
}
}

// Test de saut de page

@Test
@DisplayName("exportLabToPdf : beaucoup de données génèrent un PDF multi-pages")
void testMultiplePages() throws IOException {
String path = tempPdf("multipages");
try {
Lab lab = makeLab("Grand Labo", "pentest", "Labo avec beaucoup de contenu");

// 10 VMs
List<VirtualMachine> vms = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
vms.add(makeVM("VM-" + i, "uuid-" + i, VMStatus.POWERED_OFF));
}

// 10 snapshots
List<Snapshot> snaps = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
snaps.add(makeSnapshot("Snapshot-" + i, i % 2 == 0));
}

// 10 notes de journal
List<JournalEntry> entries = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
entries.add(makeJournalEntry(
"Note d'analyse numéro " + i + " : observations détaillées sur le comportement de la VM."
));
}

exporter.exportLabToPdf(lab, vms, snaps, entries, path);

// Un PDF multi-pages est plus grand qu'un PDF d'une page
assertTrue(new File(path).length() > 1000,
"Un PDF avec beaucoup de données doit être suffisamment grand");
} finally {
cleanup(path);
}
}

// Test d'erreur

@Test
@DisplayName("exportLabToPdf : lève IOException si le chemin est invalide")
void testInvalidPathThrowsIOException() {
Lab lab = makeLab("Labo", "malware", null);
String invalidPath = "/chemin/qui/nexiste/pas/rapport.pdf";

assertThrows(IOException.class, () ->
exporter.exportLabToPdf(lab, List.of(), List.of(), List.of(), invalidPath)
);
}
}
Loading