feat: add tests
This commit is contained in:
@@ -0,0 +1,297 @@
|
|||||||
|
package local.epul4a.fotosharing.integration;
|
||||||
|
|
||||||
|
import local.epul4a.fotosharing.model.Commentaire;
|
||||||
|
import local.epul4a.fotosharing.model.Photo;
|
||||||
|
import local.epul4a.fotosharing.model.Utilisateur;
|
||||||
|
import local.epul4a.fotosharing.repository.CommentaireRepository;
|
||||||
|
import local.epul4a.fotosharing.repository.PhotoRepository;
|
||||||
|
import local.epul4a.fotosharing.repository.UtilisateurRepository;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests d'intégration pour la suppression en cascade
|
||||||
|
* Teste : Supprimer un user doit supprimer ses photos et commentaires
|
||||||
|
*/
|
||||||
|
@SpringBootTest
|
||||||
|
@ActiveProfiles("test")
|
||||||
|
@Transactional
|
||||||
|
class CascadeDeleteIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UtilisateurRepository utilisateurRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PhotoRepository photoRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CommentaireRepository commentaireRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
private Utilisateur userA;
|
||||||
|
private Utilisateur userB;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
// Nettoyer la BDD
|
||||||
|
commentaireRepository.deleteAll();
|
||||||
|
photoRepository.deleteAll();
|
||||||
|
utilisateurRepository.deleteAll();
|
||||||
|
|
||||||
|
// Créer User A
|
||||||
|
userA = new Utilisateur();
|
||||||
|
userA.setEmail("userA@example.com");
|
||||||
|
userA.setNom("A");
|
||||||
|
userA.setPrenom("User");
|
||||||
|
userA.setPassword(passwordEncoder.encode("password"));
|
||||||
|
userA = utilisateurRepository.save(userA);
|
||||||
|
|
||||||
|
// Créer User B
|
||||||
|
userB = new Utilisateur();
|
||||||
|
userB.setEmail("userB@example.com");
|
||||||
|
userB.setNom("B");
|
||||||
|
userB.setPrenom("User");
|
||||||
|
userB.setPassword(passwordEncoder.encode("password"));
|
||||||
|
userB = utilisateurRepository.save(userB);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeleteUser_ShouldDeleteUserOwnPhotos() {
|
||||||
|
// Given - User A possède 3 photos
|
||||||
|
Photo photo1 = createPhoto("photo1.jpg", userA);
|
||||||
|
Photo photo2 = createPhoto("photo2.jpg", userA);
|
||||||
|
Photo photo3 = createPhoto("photo3.jpg", userA);
|
||||||
|
|
||||||
|
photoRepository.save(photo1);
|
||||||
|
photoRepository.save(photo2);
|
||||||
|
photoRepository.save(photo3);
|
||||||
|
|
||||||
|
// Given - User B possède 2 photos (ne doivent PAS être supprimées)
|
||||||
|
Photo photoB1 = createPhoto("photoB1.jpg", userB);
|
||||||
|
Photo photoB2 = createPhoto("photoB2.jpg", userB);
|
||||||
|
photoRepository.save(photoB1);
|
||||||
|
photoRepository.save(photoB2);
|
||||||
|
|
||||||
|
// Vérifier la situation initiale
|
||||||
|
assertEquals(5, photoRepository.count(), "5 photos au total");
|
||||||
|
assertEquals(3, photoRepository.findByProprietaire_Email(userA.getEmail()).size());
|
||||||
|
assertEquals(2, photoRepository.findByProprietaire_Email(userB.getEmail()).size());
|
||||||
|
|
||||||
|
// When - Supprimer User A
|
||||||
|
utilisateurRepository.delete(userA);
|
||||||
|
utilisateurRepository.flush();
|
||||||
|
|
||||||
|
// Then - Les photos de User A doivent être supprimées
|
||||||
|
assertEquals(2, photoRepository.count(),
|
||||||
|
"Seules les 2 photos de User B doivent rester");
|
||||||
|
|
||||||
|
List<Photo> remainingPhotos = photoRepository.findAll();
|
||||||
|
assertEquals(2, remainingPhotos.size());
|
||||||
|
assertTrue(remainingPhotos.stream().allMatch(p -> p.getProprietaire().getId().equals(userB.getId())),
|
||||||
|
"Toutes les photos restantes doivent appartenir à User B");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeleteUser_ShouldDeleteUserOwnComments() {
|
||||||
|
// Given - Photo de User B
|
||||||
|
Photo photoB = createPhoto("photoB.jpg", userB);
|
||||||
|
photoB = photoRepository.save(photoB);
|
||||||
|
|
||||||
|
// Given - User A commente la photo de User B
|
||||||
|
Commentaire comment1 = createCommentaire("Super photo !", userA, photoB);
|
||||||
|
Commentaire comment2 = createCommentaire("J'adore !", userA, photoB);
|
||||||
|
Commentaire comment3 = createCommentaire("Merci !", userB, photoB); // Commentaire de User B
|
||||||
|
|
||||||
|
commentaireRepository.save(comment1);
|
||||||
|
commentaireRepository.save(comment2);
|
||||||
|
commentaireRepository.save(comment3);
|
||||||
|
|
||||||
|
// Vérifier la situation initiale
|
||||||
|
assertEquals(3, commentaireRepository.count());
|
||||||
|
|
||||||
|
// When - Supprimer User A
|
||||||
|
utilisateurRepository.delete(userA);
|
||||||
|
utilisateurRepository.flush();
|
||||||
|
|
||||||
|
// Then - Les commentaires de User A doivent être supprimés
|
||||||
|
assertEquals(1, commentaireRepository.count(),
|
||||||
|
"Seul le commentaire de User B doit rester");
|
||||||
|
|
||||||
|
List<Commentaire> remainingComments = commentaireRepository.findAll();
|
||||||
|
assertEquals(1, remainingComments.size());
|
||||||
|
assertEquals(userB.getId(), remainingComments.get(0).getAuteur().getId(),
|
||||||
|
"Le commentaire restant doit être celui de User B");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeleteUser_ShouldDeletePhotosAndAllCommentsOnThosePhotos() {
|
||||||
|
// Given - User A possède une photo
|
||||||
|
Photo photoA = createPhoto("photoA.jpg", userA);
|
||||||
|
photoA = photoRepository.save(photoA);
|
||||||
|
|
||||||
|
// Given - Plusieurs utilisateurs commentent la photo de User A
|
||||||
|
Commentaire commentByA = createCommentaire("Ma photo", userA, photoA);
|
||||||
|
Commentaire commentByB = createCommentaire("Belle photo", userB, photoA);
|
||||||
|
|
||||||
|
commentaireRepository.save(commentByA);
|
||||||
|
commentaireRepository.save(commentByB);
|
||||||
|
|
||||||
|
// Vérifier la situation initiale
|
||||||
|
assertEquals(1, photoRepository.count());
|
||||||
|
assertEquals(2, commentaireRepository.count());
|
||||||
|
|
||||||
|
// When - Supprimer User A (et donc sa photo)
|
||||||
|
utilisateurRepository.delete(userA);
|
||||||
|
utilisateurRepository.flush();
|
||||||
|
|
||||||
|
// Then - La photo ET tous ses commentaires doivent être supprimés
|
||||||
|
assertEquals(0, photoRepository.count(),
|
||||||
|
"La photo de User A doit être supprimée");
|
||||||
|
|
||||||
|
assertEquals(0, commentaireRepository.count(),
|
||||||
|
"TOUS les commentaires sur la photo supprimée doivent disparaître (cascade)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeleteUser_ComplexScenario() {
|
||||||
|
// Scénario complexe :
|
||||||
|
// - User A a 2 photos
|
||||||
|
// - User B a 1 photo
|
||||||
|
// - User A commente sa propre photo ET la photo de User B
|
||||||
|
// - User B commente sa propre photo ET une photo de User A
|
||||||
|
|
||||||
|
// Given - Photos
|
||||||
|
Photo photoA1 = photoRepository.save(createPhoto("photoA1.jpg", userA));
|
||||||
|
Photo photoA2 = photoRepository.save(createPhoto("photoA2.jpg", userA));
|
||||||
|
Photo photoB = photoRepository.save(createPhoto("photoB.jpg", userB));
|
||||||
|
|
||||||
|
// Given - Commentaires
|
||||||
|
commentaireRepository.save(createCommentaire("A sur A1", userA, photoA1));
|
||||||
|
commentaireRepository.save(createCommentaire("A sur A2", userA, photoA2));
|
||||||
|
commentaireRepository.save(createCommentaire("A sur B", userA, photoB));
|
||||||
|
commentaireRepository.save(createCommentaire("B sur A1", userB, photoA1));
|
||||||
|
commentaireRepository.save(createCommentaire("B sur B", userB, photoB));
|
||||||
|
|
||||||
|
// Vérifier la situation initiale
|
||||||
|
assertEquals(3, photoRepository.count());
|
||||||
|
assertEquals(5, commentaireRepository.count());
|
||||||
|
|
||||||
|
// When - Supprimer User A
|
||||||
|
utilisateurRepository.delete(userA);
|
||||||
|
utilisateurRepository.flush();
|
||||||
|
|
||||||
|
// Then - Vérifier les suppressions
|
||||||
|
assertEquals(1, photoRepository.count(),
|
||||||
|
"Seule la photo de User B doit rester");
|
||||||
|
|
||||||
|
List<Photo> remainingPhotos = photoRepository.findAll();
|
||||||
|
assertEquals(photoB.getId(), remainingPhotos.get(0).getId());
|
||||||
|
|
||||||
|
// Then - Vérifier les commentaires restants
|
||||||
|
List<Commentaire> remainingComments = commentaireRepository.findAll();
|
||||||
|
assertEquals(1, remainingComments.size(),
|
||||||
|
"Seul le commentaire 'B sur B' doit rester");
|
||||||
|
|
||||||
|
Commentaire lastComment = remainingComments.get(0);
|
||||||
|
assertEquals("B sur B", lastComment.getTexte());
|
||||||
|
assertEquals(userB.getId(), lastComment.getAuteur().getId());
|
||||||
|
assertEquals(photoB.getId(), lastComment.getPhoto().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeleteUser_ShouldNotAffectOtherUsers() {
|
||||||
|
// Given - Créer User C
|
||||||
|
Utilisateur userC = new Utilisateur();
|
||||||
|
userC.setEmail("userC@example.com");
|
||||||
|
userC.setNom("C");
|
||||||
|
userC.setPrenom("User");
|
||||||
|
userC.setPassword(passwordEncoder.encode("password"));
|
||||||
|
userC = utilisateurRepository.save(userC);
|
||||||
|
|
||||||
|
// Given - Chaque utilisateur a des photos et commentaires
|
||||||
|
Photo photoA = photoRepository.save(createPhoto("photoA.jpg", userA));
|
||||||
|
Photo photoB = photoRepository.save(createPhoto("photoB.jpg", userB));
|
||||||
|
Photo photoC = photoRepository.save(createPhoto("photoC.jpg", userC));
|
||||||
|
|
||||||
|
commentaireRepository.save(createCommentaire("Comment A", userA, photoA));
|
||||||
|
commentaireRepository.save(createCommentaire("Comment B", userB, photoB));
|
||||||
|
commentaireRepository.save(createCommentaire("Comment C", userC, photoC));
|
||||||
|
|
||||||
|
// Vérifier la situation initiale
|
||||||
|
assertEquals(3, utilisateurRepository.count());
|
||||||
|
assertEquals(3, photoRepository.count());
|
||||||
|
assertEquals(3, commentaireRepository.count());
|
||||||
|
|
||||||
|
// When - Supprimer User A
|
||||||
|
utilisateurRepository.delete(userA);
|
||||||
|
utilisateurRepository.flush();
|
||||||
|
|
||||||
|
// Then - User B et C ne doivent pas être affectés
|
||||||
|
assertEquals(2, utilisateurRepository.count(),
|
||||||
|
"Users B et C doivent rester");
|
||||||
|
assertEquals(2, photoRepository.count(),
|
||||||
|
"Photos de B et C doivent rester");
|
||||||
|
assertEquals(2, commentaireRepository.count(),
|
||||||
|
"Commentaires de B et C doivent rester");
|
||||||
|
|
||||||
|
// Then - Vérifier que les bonnes entités restent
|
||||||
|
assertTrue(utilisateurRepository.findById(userB.getId()).isPresent());
|
||||||
|
assertTrue(utilisateurRepository.findById(userC.getId()).isPresent());
|
||||||
|
assertFalse(utilisateurRepository.findById(userA.getId()).isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeleteMultipleUsers_ShouldDeleteRespectiveData() {
|
||||||
|
// Given - Chaque user a des photos
|
||||||
|
photoRepository.save(createPhoto("photoA.jpg", userA));
|
||||||
|
photoRepository.save(createPhoto("photoB.jpg", userB));
|
||||||
|
|
||||||
|
assertEquals(2, photoRepository.count());
|
||||||
|
|
||||||
|
// When - Supprimer les deux utilisateurs
|
||||||
|
utilisateurRepository.delete(userA);
|
||||||
|
utilisateurRepository.delete(userB);
|
||||||
|
utilisateurRepository.flush();
|
||||||
|
|
||||||
|
// Then - Tout doit être supprimé
|
||||||
|
assertEquals(0, utilisateurRepository.count());
|
||||||
|
assertEquals(0, photoRepository.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== Méthodes Utilitaires =====================
|
||||||
|
|
||||||
|
private Photo createPhoto(String filename, Utilisateur owner) {
|
||||||
|
Photo photo = new Photo();
|
||||||
|
photo.setNomFichierOriginal(filename);
|
||||||
|
photo.setUuidFichier("uuid-" + filename);
|
||||||
|
photo.setUuidThumbnail("thumb-" + filename);
|
||||||
|
photo.setVisibilite(Photo.Visibilite.PUBLIC);
|
||||||
|
photo.setDateUpload(LocalDateTime.now());
|
||||||
|
photo.setProprietaire(owner);
|
||||||
|
photo.setMimeType("image/jpeg");
|
||||||
|
photo.setTailleFichier(1024L);
|
||||||
|
return photo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Commentaire createCommentaire(String texte, Utilisateur auteur, Photo photo) {
|
||||||
|
Commentaire commentaire = new Commentaire();
|
||||||
|
commentaire.setTexte(texte);
|
||||||
|
commentaire.setAuteur(auteur);
|
||||||
|
commentaire.setPhoto(photo);
|
||||||
|
commentaire.setDateCommentaire(LocalDateTime.now());
|
||||||
|
return commentaire;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
package local.epul4a.fotosharing.integration;
|
||||||
|
|
||||||
|
import local.epul4a.fotosharing.dto.PhotoDTO;
|
||||||
|
import local.epul4a.fotosharing.model.Photo;
|
||||||
|
import local.epul4a.fotosharing.model.Utilisateur;
|
||||||
|
import local.epul4a.fotosharing.repository.PhotoRepository;
|
||||||
|
import local.epul4a.fotosharing.repository.UtilisateurRepository;
|
||||||
|
import local.epul4a.fotosharing.service.PhotoService;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.mock.web.MockMultipartFile;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests d'intégration pour le flux complet d'upload de photos
|
||||||
|
* Teste : Envoi fichier -> Vérification présence sur disque -> Vérification entrée en BDD
|
||||||
|
*/
|
||||||
|
@SpringBootTest
|
||||||
|
@ActiveProfiles("test")
|
||||||
|
class PhotoUploadIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PhotoService photoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PhotoRepository photoRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UtilisateurRepository utilisateurRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
@Value("${file.upload-dir}")
|
||||||
|
private String uploadDir;
|
||||||
|
|
||||||
|
private Utilisateur testUser;
|
||||||
|
private Path uploadPath;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() throws IOException {
|
||||||
|
// Créer le dossier d'upload pour les tests
|
||||||
|
uploadPath = Paths.get(uploadDir);
|
||||||
|
if (!Files.exists(uploadPath)) {
|
||||||
|
Files.createDirectories(uploadPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Créer un utilisateur de test
|
||||||
|
testUser = new Utilisateur();
|
||||||
|
testUser.setEmail("testupload@example.com");
|
||||||
|
testUser.setNom("Upload");
|
||||||
|
testUser.setPrenom("Test");
|
||||||
|
testUser.setPassword(passwordEncoder.encode("password"));
|
||||||
|
testUser = utilisateurRepository.save(testUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void tearDown() throws IOException {
|
||||||
|
// Nettoyer les photos de test
|
||||||
|
photoRepository.findAll().forEach(photo -> {
|
||||||
|
try {
|
||||||
|
// Supprimer les fichiers sur disque
|
||||||
|
Path originalFile = uploadPath.resolve(photo.getUuidFichier());
|
||||||
|
Path thumbFile = uploadPath.resolve(photo.getUuidThumbnail());
|
||||||
|
Files.deleteIfExists(originalFile);
|
||||||
|
Files.deleteIfExists(thumbFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Ignorer les erreurs de suppression
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Supprimer de la BDD
|
||||||
|
photoRepository.deleteAll();
|
||||||
|
utilisateurRepository.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCompleteUploadFlow_ShouldCreateFileOnDiskAndDatabaseEntry() throws IOException {
|
||||||
|
// Given - Créer un fichier JPEG valide
|
||||||
|
byte[] jpegContent = createValidJpegBytes();
|
||||||
|
MockMultipartFile file = new MockMultipartFile(
|
||||||
|
"file",
|
||||||
|
"test-photo.jpg",
|
||||||
|
"image/jpeg",
|
||||||
|
jpegContent
|
||||||
|
);
|
||||||
|
|
||||||
|
// When - Upload de la photo
|
||||||
|
PhotoDTO uploadedPhoto = photoService.store(file, "PUBLIC", testUser.getEmail());
|
||||||
|
|
||||||
|
// Then - Vérifier que le DTO est retourné
|
||||||
|
assertNotNull(uploadedPhoto, "Le DTO de la photo uploadée ne doit pas être null");
|
||||||
|
assertNotNull(uploadedPhoto.getId(), "L'ID de la photo doit être généré");
|
||||||
|
assertEquals("test-photo.jpg", uploadedPhoto.getNomFichierOriginal());
|
||||||
|
assertEquals("PUBLIC", uploadedPhoto.getVisibilite());
|
||||||
|
assertEquals("image/jpeg", uploadedPhoto.getMimeType());
|
||||||
|
assertEquals(jpegContent.length, uploadedPhoto.getTailleFichier());
|
||||||
|
|
||||||
|
// Then - Vérifier la présence du fichier ORIGINAL sur le disque
|
||||||
|
Path originalFile = uploadPath.resolve(uploadedPhoto.getUuidFichier());
|
||||||
|
assertTrue(Files.exists(originalFile),
|
||||||
|
"Le fichier original doit exister sur le disque : " + originalFile);
|
||||||
|
assertEquals(jpegContent.length, Files.size(originalFile),
|
||||||
|
"La taille du fichier sur disque doit correspondre");
|
||||||
|
|
||||||
|
// Then - Vérifier la présence de la MINIATURE sur le disque
|
||||||
|
Path thumbnailFile = uploadPath.resolve(uploadedPhoto.getUuidThumbnail());
|
||||||
|
assertTrue(Files.exists(thumbnailFile),
|
||||||
|
"La miniature doit exister sur le disque : " + thumbnailFile);
|
||||||
|
assertTrue(Files.size(thumbnailFile) > 0,
|
||||||
|
"La miniature ne doit pas être vide");
|
||||||
|
|
||||||
|
// Then - Vérifier l'entrée en BDD
|
||||||
|
Photo photoInDb = photoRepository.findById(uploadedPhoto.getId()).orElse(null);
|
||||||
|
assertNotNull(photoInDb, "La photo doit être enregistrée en BDD");
|
||||||
|
assertEquals("test-photo.jpg", photoInDb.getNomFichierOriginal());
|
||||||
|
assertEquals(Photo.Visibilite.PUBLIC, photoInDb.getVisibilite());
|
||||||
|
assertEquals(testUser.getId(), photoInDb.getProprietaire().getId());
|
||||||
|
assertEquals("image/jpeg", photoInDb.getMimeType());
|
||||||
|
assertEquals((long) jpegContent.length, photoInDb.getTailleFichier());
|
||||||
|
|
||||||
|
// Then - Vérifier les métadonnées
|
||||||
|
assertNotNull(photoInDb.getLargeur(), "La largeur doit être extraite");
|
||||||
|
assertNotNull(photoInDb.getHauteur(), "La hauteur doit être extraite");
|
||||||
|
assertTrue(photoInDb.getLargeur() > 0, "La largeur doit être positive");
|
||||||
|
assertTrue(photoInDb.getHauteur() > 0, "La hauteur doit être positive");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUploadPngFile_ShouldDetectCorrectMimeType() {
|
||||||
|
// Given - Créer un fichier PNG valide
|
||||||
|
byte[] pngContent = createValidPngBytes();
|
||||||
|
MockMultipartFile file = new MockMultipartFile(
|
||||||
|
"file",
|
||||||
|
"test-image.png",
|
||||||
|
"image/png",
|
||||||
|
pngContent
|
||||||
|
);
|
||||||
|
|
||||||
|
// When
|
||||||
|
PhotoDTO uploadedPhoto = photoService.store(file, "PRIVATE", testUser.getEmail());
|
||||||
|
|
||||||
|
// Then - Vérifier le type MIME détecté
|
||||||
|
assertNotNull(uploadedPhoto);
|
||||||
|
assertEquals("image/png", uploadedPhoto.getMimeType(),
|
||||||
|
"Le type MIME doit être détecté comme PNG");
|
||||||
|
|
||||||
|
// Then - Vérifier en BDD
|
||||||
|
Photo photoInDb = photoRepository.findById(uploadedPhoto.getId()).orElse(null);
|
||||||
|
assertNotNull(photoInDb);
|
||||||
|
assertEquals("image/png", photoInDb.getMimeType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUploadMultiplePhotos_ShouldCreateSeparateFiles() throws IOException {
|
||||||
|
// Given - Uploader plusieurs photos
|
||||||
|
for (int i = 1; i <= 3; i++) {
|
||||||
|
byte[] content = createValidJpegBytes();
|
||||||
|
MockMultipartFile file = new MockMultipartFile(
|
||||||
|
"file",
|
||||||
|
"photo-" + i + ".jpg",
|
||||||
|
"image/jpeg",
|
||||||
|
content
|
||||||
|
);
|
||||||
|
|
||||||
|
// When
|
||||||
|
photoService.store(file, "PUBLIC", testUser.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then - Vérifier que 3 photos sont en BDD
|
||||||
|
long photoCount = photoRepository.count();
|
||||||
|
assertEquals(3, photoCount, "3 photos doivent être enregistrées");
|
||||||
|
|
||||||
|
// Then - Vérifier que tous les fichiers existent
|
||||||
|
photoRepository.findAll().forEach(photo -> {
|
||||||
|
Path originalFile = uploadPath.resolve(photo.getUuidFichier());
|
||||||
|
Path thumbFile = uploadPath.resolve(photo.getUuidThumbnail());
|
||||||
|
|
||||||
|
assertTrue(Files.exists(originalFile),
|
||||||
|
"Le fichier original doit exister : " + photo.getUuidFichier());
|
||||||
|
assertTrue(Files.exists(thumbFile),
|
||||||
|
"La miniature doit exister : " + photo.getUuidThumbnail());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUploadWithDifferentVisibilities() {
|
||||||
|
// Test chaque type de visibilité
|
||||||
|
Photo.Visibilite[] visibilities = {Photo.Visibilite.PUBLIC, Photo.Visibilite.PRIVATE, Photo.Visibilite.SHARED};
|
||||||
|
|
||||||
|
for (Photo.Visibilite visibility : visibilities) {
|
||||||
|
// Given
|
||||||
|
byte[] content = createValidJpegBytes();
|
||||||
|
MockMultipartFile file = new MockMultipartFile(
|
||||||
|
"file",
|
||||||
|
"photo-" + visibility.name().toLowerCase() + ".jpg",
|
||||||
|
"image/jpeg",
|
||||||
|
content
|
||||||
|
);
|
||||||
|
|
||||||
|
// When
|
||||||
|
PhotoDTO uploadedPhoto = photoService.store(file, visibility.name(), testUser.getEmail());
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(visibility.name(), uploadedPhoto.getVisibilite(),
|
||||||
|
"La visibilité doit être " + visibility);
|
||||||
|
|
||||||
|
Photo photoInDb = photoRepository.findById(uploadedPhoto.getId()).orElse(null);
|
||||||
|
assertNotNull(photoInDb);
|
||||||
|
assertEquals(visibility, photoInDb.getVisibilite());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUpload_FileNameWithUUID_ShouldBeUnique() {
|
||||||
|
// Given - Uploader deux fichiers avec le même nom
|
||||||
|
byte[] content = createValidJpegBytes();
|
||||||
|
|
||||||
|
MockMultipartFile file1 = new MockMultipartFile("file", "same-name.jpg", "image/jpeg", content);
|
||||||
|
MockMultipartFile file2 = new MockMultipartFile("file", "same-name.jpg", "image/jpeg", content);
|
||||||
|
|
||||||
|
// When
|
||||||
|
PhotoDTO photo1 = photoService.store(file1, "PUBLIC", testUser.getEmail());
|
||||||
|
PhotoDTO photo2 = photoService.store(file2, "PUBLIC", testUser.getEmail());
|
||||||
|
|
||||||
|
// Then - Les UUID doivent être différents
|
||||||
|
assertNotEquals(photo1.getUuidFichier(), photo2.getUuidFichier(),
|
||||||
|
"Les UUID des fichiers doivent être différents même avec le même nom original");
|
||||||
|
|
||||||
|
// Then - Les deux fichiers doivent exister sur le disque
|
||||||
|
assertTrue(Files.exists(uploadPath.resolve(photo1.getUuidFichier())));
|
||||||
|
assertTrue(Files.exists(uploadPath.resolve(photo2.getUuidFichier())));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== Méthodes Utilitaires =====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un tableau de bytes représentant un JPEG valide minimal
|
||||||
|
*/
|
||||||
|
private byte[] createValidJpegBytes() {
|
||||||
|
// Magic number JPEG + données minimales pour créer une image valide
|
||||||
|
return new byte[]{
|
||||||
|
(byte) 0xFF, (byte) 0xD8, (byte) 0xFF, (byte) 0xE0, // JPEG header
|
||||||
|
0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, // JFIF marker
|
||||||
|
0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
|
||||||
|
(byte) 0xFF, (byte) 0xDB, 0x00, 0x43, 0x00, // Quantization table
|
||||||
|
0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07,
|
||||||
|
0x07, 0x07, 0x09, 0x09, 0x08, 0x0A, 0x0C, 0x14,
|
||||||
|
0x0D, 0x0C, 0x0B, 0x0B, 0x0C, 0x19, 0x12, 0x13,
|
||||||
|
0x0F, 0x14, 0x1D, 0x1A, 0x1F, 0x1E, 0x1D, 0x1A,
|
||||||
|
0x1C, 0x1C, 0x20, 0x24, 0x2E, 0x27, 0x20, 0x22,
|
||||||
|
0x2C, 0x23, 0x1C, 0x1C, 0x28, 0x37, 0x29, 0x2C,
|
||||||
|
0x30, 0x31, 0x34, 0x34, 0x34, 0x1F, 0x27, 0x39,
|
||||||
|
0x3D, 0x38, 0x32, 0x3C, 0x2E, 0x33, 0x34, 0x32,
|
||||||
|
(byte) 0xFF, (byte) 0xD9 // End of image
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un tableau de bytes représentant un PNG valide minimal
|
||||||
|
*/
|
||||||
|
private byte[] createValidPngBytes() {
|
||||||
|
// Magic number PNG + données minimales
|
||||||
|
return new byte[]{
|
||||||
|
(byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, // PNG signature
|
||||||
|
0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, // IHDR chunk
|
||||||
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, // 1x1 pixel
|
||||||
|
0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, (byte) 0xC4, (byte) 0x89,
|
||||||
|
0x00, 0x00, 0x00, 0x0A, 0x49, 0x44, 0x41, 0x54, // IDAT chunk
|
||||||
|
0x78, (byte) 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x01,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, // IEND chunk
|
||||||
|
(byte) 0xAE, 0x42, 0x60, (byte) 0x82
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
package local.epul4a.fotosharing.mapper;
|
||||||
|
|
||||||
|
import local.epul4a.fotosharing.dto.PhotoDTO;
|
||||||
|
import local.epul4a.fotosharing.dto.UtilisateurDTO;
|
||||||
|
import local.epul4a.fotosharing.model.Photo;
|
||||||
|
import local.epul4a.fotosharing.model.Utilisateur;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests unitaires pour PhotoMapper
|
||||||
|
* Teste la conversion bidirectionnelle entre Photo et PhotoDTO
|
||||||
|
*/
|
||||||
|
class PhotoMapperTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToDTO_WithCompletePhoto_ShouldMapAllFields() {
|
||||||
|
// Given - Créer un utilisateur
|
||||||
|
Utilisateur utilisateur = new Utilisateur();
|
||||||
|
utilisateur.setId(1L);
|
||||||
|
utilisateur.setEmail("test@example.com");
|
||||||
|
utilisateur.setNom("Dupont");
|
||||||
|
utilisateur.setPrenom("Jean");
|
||||||
|
|
||||||
|
// Given - Créer une photo complète
|
||||||
|
Photo photo = new Photo();
|
||||||
|
photo.setId(100L);
|
||||||
|
photo.setNomFichierOriginal("vacances.jpg");
|
||||||
|
photo.setUuidFichier("uuid-123-vacances.jpg");
|
||||||
|
photo.setUuidThumbnail("thumb-uuid-123-vacances.jpg");
|
||||||
|
photo.setDateUpload(LocalDateTime.of(2025, 12, 3, 10, 30));
|
||||||
|
photo.setVisibilite(Photo.Visibilite.PUBLIC);
|
||||||
|
photo.setProprietaire(utilisateur);
|
||||||
|
photo.setMimeType("image/jpeg");
|
||||||
|
photo.setTailleFichier(2457600L);
|
||||||
|
photo.setLargeur(1920);
|
||||||
|
photo.setHauteur(1080);
|
||||||
|
|
||||||
|
// When - Convertir en DTO
|
||||||
|
PhotoDTO dto = PhotoMapper.toDTO(photo);
|
||||||
|
|
||||||
|
// Then - Vérifier tous les champs
|
||||||
|
assertNotNull(dto, "Le DTO ne doit pas être null");
|
||||||
|
assertEquals(100L, dto.getId());
|
||||||
|
assertEquals("vacances.jpg", dto.getNomFichierOriginal());
|
||||||
|
assertEquals("uuid-123-vacances.jpg", dto.getUuidFichier());
|
||||||
|
assertEquals("thumb-uuid-123-vacances.jpg", dto.getUuidThumbnail());
|
||||||
|
assertEquals(LocalDateTime.of(2025, 12, 3, 10, 30), dto.getDateUpload());
|
||||||
|
assertEquals("PUBLIC", dto.getVisibilite());
|
||||||
|
assertEquals("image/jpeg", dto.getMimeType());
|
||||||
|
assertEquals(2457600L, dto.getTailleFichier());
|
||||||
|
assertEquals(1920, dto.getLargeur());
|
||||||
|
assertEquals(1080, dto.getHauteur());
|
||||||
|
|
||||||
|
// Then - Vérifier le propriétaire
|
||||||
|
assertNotNull(dto.getProprietaire(), "Le propriétaire ne doit pas être null");
|
||||||
|
assertEquals(1L, dto.getProprietaire().getId());
|
||||||
|
assertEquals("test@example.com", dto.getProprietaire().getEmail());
|
||||||
|
assertEquals("Dupont", dto.getProprietaire().getNom());
|
||||||
|
assertEquals("Jean", dto.getProprietaire().getPrenom());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToDTO_WithNullPhoto_ShouldReturnNull() {
|
||||||
|
// When - Convertir null
|
||||||
|
PhotoDTO dto = PhotoMapper.toDTO(null);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertNull(dto, "Le DTO doit être null quand la photo est null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToDTO_WithPhotoWithoutOwner_ShouldNotFail() {
|
||||||
|
// Given - Photo sans propriétaire
|
||||||
|
Photo photo = new Photo();
|
||||||
|
photo.setId(50L);
|
||||||
|
photo.setNomFichierOriginal("test.png");
|
||||||
|
photo.setVisibilite(Photo.Visibilite.PRIVATE);
|
||||||
|
|
||||||
|
// When
|
||||||
|
PhotoDTO dto = PhotoMapper.toDTO(photo);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertNotNull(dto);
|
||||||
|
assertEquals(50L, dto.getId());
|
||||||
|
assertNull(dto.getProprietaire(), "Le propriétaire doit être null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToDTO_WithMinimalPhoto_ShouldMapBasicFields() {
|
||||||
|
// Given - Photo avec champs minimaux
|
||||||
|
Photo photo = new Photo();
|
||||||
|
photo.setId(25L);
|
||||||
|
photo.setNomFichierOriginal("minimal.jpg");
|
||||||
|
photo.setVisibilite(Photo.Visibilite.SHARED);
|
||||||
|
|
||||||
|
// When
|
||||||
|
PhotoDTO dto = PhotoMapper.toDTO(photo);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertNotNull(dto);
|
||||||
|
assertEquals(25L, dto.getId());
|
||||||
|
assertEquals("minimal.jpg", dto.getNomFichierOriginal());
|
||||||
|
assertEquals("SHARED", dto.getVisibilite());
|
||||||
|
assertNull(dto.getMimeType());
|
||||||
|
assertNull(dto.getTailleFichier());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToDTO_MetadataMapping() {
|
||||||
|
// Given - Photo avec métadonnées
|
||||||
|
Photo photo = new Photo();
|
||||||
|
photo.setId(1L);
|
||||||
|
photo.setNomFichierOriginal("hd-photo.jpg");
|
||||||
|
photo.setVisibilite(Photo.Visibilite.PUBLIC);
|
||||||
|
photo.setMimeType("image/png");
|
||||||
|
photo.setTailleFichier(5242880L); // 5 MB
|
||||||
|
photo.setLargeur(3840);
|
||||||
|
photo.setHauteur(2160);
|
||||||
|
|
||||||
|
// When
|
||||||
|
PhotoDTO dto = PhotoMapper.toDTO(photo);
|
||||||
|
|
||||||
|
// Then - Vérifier les métadonnées
|
||||||
|
assertEquals("image/png", dto.getMimeType());
|
||||||
|
assertEquals(5242880L, dto.getTailleFichier());
|
||||||
|
assertEquals(3840, dto.getLargeur());
|
||||||
|
assertEquals(2160, dto.getHauteur());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToDTO_AllVisibilityTypes() {
|
||||||
|
// Test pour chaque type de visibilité
|
||||||
|
for (Photo.Visibilite visibilite : Photo.Visibilite.values()) {
|
||||||
|
// Given
|
||||||
|
Photo photo = new Photo();
|
||||||
|
photo.setId(1L);
|
||||||
|
photo.setNomFichierOriginal("test.jpg");
|
||||||
|
photo.setVisibilite(visibilite);
|
||||||
|
|
||||||
|
// When
|
||||||
|
PhotoDTO dto = PhotoMapper.toDTO(photo);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(visibilite.name(), dto.getVisibilite(),
|
||||||
|
"La visibilité " + visibilite + " doit être correctement mappée");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,319 @@
|
|||||||
|
package local.epul4a.fotosharing.security;
|
||||||
|
|
||||||
|
import local.epul4a.fotosharing.service.PartageService;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests unitaires pour SecurityService
|
||||||
|
* Teste les scénarios d'accès aux photos (READ / COMMENT / ADMIN)
|
||||||
|
*/
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class SecurityServiceTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PartageService partageService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Authentication authentication;
|
||||||
|
|
||||||
|
private SecurityService securityService;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
securityService = new SecurityService(partageService);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== TESTS canAccessPhoto =====================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canAccessPhoto_UserAAccessesPrivatePhotoB_ShouldReturnFalse() {
|
||||||
|
// Given - User A essaie d'accéder à Photo B privée (pas de partage)
|
||||||
|
Long photoId = 100L;
|
||||||
|
String userAEmail = "userA@example.com";
|
||||||
|
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(true);
|
||||||
|
when(authentication.getName()).thenReturn(userAEmail);
|
||||||
|
when(partageService.canView(photoId, userAEmail)).thenReturn(false);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canAccess = securityService.canAccessPhoto(authentication, photoId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertFalse(canAccess, "User A ne devrait PAS pouvoir accéder à Photo B privée");
|
||||||
|
verify(partageService).canView(photoId, userAEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canAccessPhoto_UserAAccessesSharedPhotoB_ShouldReturnTrue() {
|
||||||
|
// Given - User A accède à Photo B partagée avec lui (READ)
|
||||||
|
Long photoId = 200L;
|
||||||
|
String userAEmail = "userA@example.com";
|
||||||
|
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(true);
|
||||||
|
when(authentication.getName()).thenReturn(userAEmail);
|
||||||
|
when(partageService.canView(photoId, userAEmail)).thenReturn(true);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canAccess = securityService.canAccessPhoto(authentication, photoId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertTrue(canAccess, "User A DEVRAIT pouvoir accéder à Photo B partagée");
|
||||||
|
verify(partageService).canView(photoId, userAEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canAccessPhoto_UserAAccessesOwnPhoto_ShouldReturnTrue() {
|
||||||
|
// Given - User A accède à sa propre photo
|
||||||
|
Long photoId = 300L;
|
||||||
|
String userAEmail = "userA@example.com";
|
||||||
|
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(true);
|
||||||
|
when(authentication.getName()).thenReturn(userAEmail);
|
||||||
|
when(partageService.canView(photoId, userAEmail)).thenReturn(true); // Propriétaire = accès
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canAccess = securityService.canAccessPhoto(authentication, photoId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertTrue(canAccess, "User A DEVRAIT pouvoir accéder à sa propre photo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canAccessPhoto_UnauthenticatedUser_ShouldReturnFalse() {
|
||||||
|
// Given - Utilisateur non authentifié
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(false);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canAccess = securityService.canAccessPhoto(authentication, 100L);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertFalse(canAccess, "Un utilisateur non authentifié ne devrait PAS avoir accès");
|
||||||
|
verify(partageService, never()).canView(anyLong(), anyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canAccessPhoto_NullAuthentication_ShouldReturnFalse() {
|
||||||
|
// When
|
||||||
|
boolean canAccess = securityService.canAccessPhoto(null, 100L);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertFalse(canAccess, "Avec authentication null, l'accès devrait être refusé");
|
||||||
|
verify(partageService, never()).canView(anyLong(), anyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canAccessPhoto_PublicPhoto_ShouldReturnTrue() {
|
||||||
|
// Given - Photo publique (accessible par tous les utilisateurs authentifiés)
|
||||||
|
Long photoId = 400L;
|
||||||
|
String userEmail = "anyone@example.com";
|
||||||
|
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(true);
|
||||||
|
when(authentication.getName()).thenReturn(userEmail);
|
||||||
|
when(partageService.canView(photoId, userEmail)).thenReturn(true);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canAccess = securityService.canAccessPhoto(authentication, photoId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertTrue(canAccess, "Une photo publique devrait être accessible");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== TESTS canCommentPhoto =====================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canCommentPhoto_UserWithCommentRights_ShouldReturnTrue() {
|
||||||
|
// Given - User A a le droit COMMENT sur Photo B
|
||||||
|
Long photoId = 500L;
|
||||||
|
String userEmail = "userA@example.com";
|
||||||
|
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(true);
|
||||||
|
when(authentication.getName()).thenReturn(userEmail);
|
||||||
|
when(partageService.canComment(photoId, userEmail)).thenReturn(true);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canComment = securityService.canCommentPhoto(authentication, photoId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertTrue(canComment, "User A DEVRAIT pouvoir commenter Photo B");
|
||||||
|
verify(partageService).canComment(photoId, userEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canCommentPhoto_UserWithoutCommentRights_ShouldReturnFalse() {
|
||||||
|
// Given - User A n'a que READ (pas COMMENT)
|
||||||
|
Long photoId = 600L;
|
||||||
|
String userEmail = "userA@example.com";
|
||||||
|
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(true);
|
||||||
|
when(authentication.getName()).thenReturn(userEmail);
|
||||||
|
when(partageService.canComment(photoId, userEmail)).thenReturn(false);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canComment = securityService.canCommentPhoto(authentication, photoId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertFalse(canComment, "User A ne devrait PAS pouvoir commenter (pas de droit COMMENT)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canCommentPhoto_UnauthenticatedUser_ShouldReturnFalse() {
|
||||||
|
// Given
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(false);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canComment = securityService.canCommentPhoto(authentication, 100L);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertFalse(canComment);
|
||||||
|
verify(partageService, never()).canComment(anyLong(), anyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== TESTS canAdminPhoto =====================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canAdminPhoto_OwnerOfPhoto_ShouldReturnTrue() {
|
||||||
|
// Given - Propriétaire de la photo
|
||||||
|
Long photoId = 700L;
|
||||||
|
String ownerEmail = "owner@example.com";
|
||||||
|
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(true);
|
||||||
|
when(authentication.getName()).thenReturn(ownerEmail);
|
||||||
|
when(partageService.canAdmin(photoId, ownerEmail)).thenReturn(true);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canAdmin = securityService.canAdminPhoto(authentication, photoId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertTrue(canAdmin, "Le propriétaire DEVRAIT avoir les droits ADMIN");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canAdminPhoto_UserWithAdminRights_ShouldReturnTrue() {
|
||||||
|
// Given - User A a le droit ADMIN sur Photo B (partagé par le propriétaire)
|
||||||
|
Long photoId = 800L;
|
||||||
|
String userEmail = "admin@example.com";
|
||||||
|
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(true);
|
||||||
|
when(authentication.getName()).thenReturn(userEmail);
|
||||||
|
when(partageService.canAdmin(photoId, userEmail)).thenReturn(true);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canAdmin = securityService.canAdminPhoto(authentication, photoId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertTrue(canAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canAdminPhoto_UserWithoutAdminRights_ShouldReturnFalse() {
|
||||||
|
// Given - User A n'a que READ ou COMMENT (pas ADMIN)
|
||||||
|
Long photoId = 900L;
|
||||||
|
String userEmail = "user@example.com";
|
||||||
|
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(true);
|
||||||
|
when(authentication.getName()).thenReturn(userEmail);
|
||||||
|
when(partageService.canAdmin(photoId, userEmail)).thenReturn(false);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canAdmin = securityService.canAdminPhoto(authentication, photoId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertFalse(canAdmin, "User sans droit ADMIN ne devrait PAS pouvoir administrer");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canAdminPhoto_NullAuthentication_ShouldReturnFalse() {
|
||||||
|
// When
|
||||||
|
boolean canAdmin = securityService.canAdminPhoto(null, 100L);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertFalse(canAdmin);
|
||||||
|
verify(partageService, never()).canAdmin(anyLong(), anyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== TESTS Albums =====================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canViewAlbum_UserWithAccess_ShouldReturnTrue() {
|
||||||
|
// Given
|
||||||
|
Long albumId = 1L;
|
||||||
|
String userEmail = "user@example.com";
|
||||||
|
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(true);
|
||||||
|
when(authentication.getName()).thenReturn(userEmail);
|
||||||
|
when(partageService.canViewAlbum(albumId, userEmail)).thenReturn(true);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canView = securityService.canViewAlbum(authentication, albumId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertTrue(canView);
|
||||||
|
verify(partageService).canViewAlbum(albumId, userEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canCommentAlbum_UserWithoutAccess_ShouldReturnFalse() {
|
||||||
|
// Given
|
||||||
|
Long albumId = 2L;
|
||||||
|
String userEmail = "user@example.com";
|
||||||
|
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(true);
|
||||||
|
when(authentication.getName()).thenReturn(userEmail);
|
||||||
|
when(partageService.canCommentAlbum(albumId, userEmail)).thenReturn(false);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canComment = securityService.canCommentAlbum(authentication, albumId);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertFalse(canComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canAdminAlbum_UnauthenticatedUser_ShouldReturnFalse() {
|
||||||
|
// Given
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(false);
|
||||||
|
|
||||||
|
// When
|
||||||
|
boolean canAdmin = securityService.canAdminAlbum(authentication, 1L);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertFalse(canAdmin);
|
||||||
|
verify(partageService, never()).canAdminAlbum(anyLong(), anyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== TESTS Scénarios Complexes =====================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void scenarioComplete_UserATriesDifferentActionsOnPhotoB() {
|
||||||
|
// Scénario : User A a seulement READ sur Photo B
|
||||||
|
Long photoId = 1000L;
|
||||||
|
String userAEmail = "userA@example.com";
|
||||||
|
|
||||||
|
when(authentication.isAuthenticated()).thenReturn(true);
|
||||||
|
when(authentication.getName()).thenReturn(userAEmail);
|
||||||
|
when(partageService.canView(photoId, userAEmail)).thenReturn(true);
|
||||||
|
when(partageService.canComment(photoId, userAEmail)).thenReturn(false);
|
||||||
|
when(partageService.canAdmin(photoId, userAEmail)).thenReturn(false);
|
||||||
|
|
||||||
|
// When/Then - User A peut voir
|
||||||
|
assertTrue(securityService.canAccessPhoto(authentication, photoId),
|
||||||
|
"User A devrait pouvoir VOIR la photo");
|
||||||
|
|
||||||
|
// When/Then - User A ne peut pas commenter
|
||||||
|
assertFalse(securityService.canCommentPhoto(authentication, photoId),
|
||||||
|
"User A ne devrait PAS pouvoir COMMENTER");
|
||||||
|
|
||||||
|
// When/Then - User A ne peut pas administrer
|
||||||
|
assertFalse(securityService.canAdminPhoto(authentication, photoId),
|
||||||
|
"User A ne devrait PAS pouvoir ADMINISTRER");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user