diff --git a/out/production/infrastructureLogicielleClient/opinion/Book.class b/out/production/infrastructureLogicielleClient/opinion/Book.class index dbdc2cd776a1d7fb9146f3653746c2aa23291368..d090638588fb800270805a9a52c290a1398613ea 100644 Binary files a/out/production/infrastructureLogicielleClient/opinion/Book.class and b/out/production/infrastructureLogicielleClient/opinion/Book.class differ diff --git a/out/production/infrastructureLogicielleClient/opinion/SocialNetwork.class b/out/production/infrastructureLogicielleClient/opinion/SocialNetwork.class index f72caf53502252cc68a317e97eb5f24e42b6d421..2fa5842a0df30e57043402766fb26b3dd70f2198 100644 Binary files a/out/production/infrastructureLogicielleClient/opinion/SocialNetwork.class and b/out/production/infrastructureLogicielleClient/opinion/SocialNetwork.class differ diff --git a/out/production/infrastructureLogicielleClient/tests/AddMemberTest.class b/out/production/infrastructureLogicielleClient/tests/AddMemberTest.class index 428db0695063dcca3c3a0991857b6b6341ad027e..b1d6375ffa627f698c13550ef3e0df492265dab6 100644 Binary files a/out/production/infrastructureLogicielleClient/tests/AddMemberTest.class and b/out/production/infrastructureLogicielleClient/tests/AddMemberTest.class differ diff --git a/src/opinion/Book.java b/src/opinion/Book.java index bc3c4a6902bae07ca41408087c16e64934753158..4ac8218fc20b26400bbef747a4523d616f11a65b 100644 --- a/src/opinion/Book.java +++ b/src/opinion/Book.java @@ -10,15 +10,15 @@ import java.util.LinkedList; * @version 1.0 * @since 1.0 */ -public class Book { +public class Book extends Item{ /** * Declaration of private class variables : book title, kind and author */ - private String title, kind, author, comment; + private String author, comment; private int nbPages; - private LinkedList<Review> reviews = new LinkedList<>(); + /** * <b>Initialization of private variables with constructor</b> @@ -29,14 +29,13 @@ public class Book { * @param nbPages The number of pages of the book */ public Book(String title, String kind, String author, int nbPages) { - this.title = title; - this.kind = kind; - this.author = author; + super(title, kind); + this.author = author.trim(); this.nbPages = nbPages; } /** - * <b>Return the title of the book</b> + * Return the title of the book * * @return book's title */ @@ -45,7 +44,7 @@ public class Book { } /** - * <b>Return the kind of the book</b> + * Return the kind of the book * * @return book's kind */ @@ -54,7 +53,7 @@ public class Book { } /** - * <b>Retrieve the author of the book</b> + * Return the author of the book * * @return book's author */ @@ -63,7 +62,7 @@ public class Book { } /** - * <b>Return the number of pages of the book</b> + * Return the number of pages of the book * * @return book's page number */ @@ -71,48 +70,20 @@ public class Book { return this.nbPages; } - /** - * <b>Identify if the current book's <i>title</i> is similar as another book</b> - * - * @param title2 other's book's title - * @return true if same, false if different - */ - public boolean compareTitle(String title2) { - String formattedTitle = this.title.toUpperCase().trim(); - String formattedTitle2 = title2.toUpperCase().trim(); - return formattedTitle.equals(formattedTitle2); - } - public void addOrUpdateReview(String login, float mark, String comment) { - for (Review r : reviews) { - if (r.getReviewerLogin().equalsIgnoreCase(login)) { - r.setMark(mark); - r.setComment(comment); - return; - } - } - reviews.add(new Review(login, mark, comment)); - } - public float getAverageMark() { - if (reviews.isEmpty()) return 0f; - float total = 0f; - for (Review r : reviews) { - total += r.getMark(); - } - return total / reviews.size(); - } + /** - * <b>String function to display the details of a book</b> + * String function to display the details of a book * * @return the book's details */ public String toString() { String text = "Book : " + getTitle() + "\nKind : " + getKind() + "\nAuthor : " + getAuthor() + "\nNumber of pages : " + getNbPages()+"\nOverall note: "+getAverageMark() +"\nReviews"; - int counter = 1; - for (Review r : reviews) { - text += counter + ". " + r.getReviewerLogin() + "\t" + r.getMark() + "\t" + r.getComment(); - counter++; - } + //int counter = 1; + //for (Review r : reviews) { + // text += counter + ". " + r.getReviewerLogin() + "\t" + r.getMark() + "\t" + r.getComment(); + // counter++; + //} return text; } } diff --git a/src/opinion/Film.java b/src/opinion/Film.java new file mode 100644 index 0000000000000000000000000000000000000000..6dd31b12ce3be43b8df82378af03cacf31bbab6c --- /dev/null +++ b/src/opinion/Film.java @@ -0,0 +1,32 @@ +package opinion; + +public class Film extends Item { + private String director; + private String scenarist; + private int duration; + + public Film(String title, String kind, String director, String scenarist, int duration) { + super(title, kind); + this.director = director.trim(); + this.scenarist = scenarist.trim(); + this.duration = duration; + } + + public String getDirector() { + return director; + } + + public String getScenarist() { + return scenarist; + } + + public int getDuration() { + return duration; + } + + @Override + public String toString() { + return "Film Title: " + title + "\nKind: " + kind + "\nDirector: " + director + + "\nScenarist: " + scenarist + "\nDuration: " + duration + " minutes"; + } +} diff --git a/src/opinion/Item.java b/src/opinion/Item.java new file mode 100644 index 0000000000000000000000000000000000000000..ceaeba516f2027dffdf9ce3c9f84e37066ed8273 --- /dev/null +++ b/src/opinion/Item.java @@ -0,0 +1,60 @@ +package opinion; + +import java.util.LinkedList; + +public abstract class Item { + protected String title; + protected String kind; + + private LinkedList<Review> reviews = new LinkedList<>(); + + public Item(String title, String kind) { + this.title = title.trim(); + this.kind = kind.trim(); + this.reviews = new LinkedList<>(); + } + + public String getTitle() { + return title; + } + + public String getKind() { + return kind; + } + + public LinkedList<Review> getReviews() { + return reviews; + } + + public void addReview(Review review) { + reviews.add(review); + } + + public abstract String toString(); + + public boolean compareTitle(String title2) { + if (this.title == null || title2 == null) return false; + String formattedTitle = this.title.trim().toUpperCase(); + String formattedTitle2 = title2.trim().toUpperCase(); + return formattedTitle.equals(formattedTitle2); + } + public void addOrUpdateReview(String login, float mark, String comment) { + for (Review r : reviews) { + if (r.getReviewerLogin().equalsIgnoreCase(login)) { + r.setMark(mark); + r.setComment(comment); + return; + } + } + reviews.add(new Review(login, mark, comment)); + } + public float getAverageMark() { + if (reviews.isEmpty()) return 0f; + float total = 0f; + for (Review r : reviews) { + total += r.getMark(); + } + return total / reviews.size(); + } +} + diff --git a/src/opinion/SocialNetwork.java b/src/opinion/SocialNetwork.java index 7a5ba3fce88bd6c3c704944a38e57b1f5e2895fb..eb49d9e71c09fb6cdf01a40a912966712b973fc0 100644 --- a/src/opinion/SocialNetwork.java +++ b/src/opinion/SocialNetwork.java @@ -19,7 +19,8 @@ public class SocialNetwork implements ISocialNetwork { private int nbmembers, nbbooks; private LinkedList<Book> listBook; private Book book; - + private LinkedList<Film> listFilm; + private int nbfilms; /** * Constructs new SocialNetwork instance with empty member list. @@ -27,8 +28,10 @@ public class SocialNetwork implements ISocialNetwork { public SocialNetwork() { listMember = new LinkedList<Member>(); listBook = new LinkedList<Book>(); + listFilm = new LinkedList<Film>(); nbmembers = 0; nbbooks = 0; + nbfilms = 0; } /** @@ -41,16 +44,8 @@ public class SocialNetwork implements ISocialNetwork { return nbmembers; } - /** - * Returns number of films. - * - * @return 0 - */ - @Override - public int nbFilms() { - // TODO Auto-generated method stub - return 0; - } + + /** * Returns number of books. @@ -155,9 +150,66 @@ public class SocialNetwork implements ISocialNetwork { nbmembers++; } + @Override public void addItemFilm(String login, String password, String title, String kind, String director, String scriptwriter, int duration) throws BadEntryException, NotMemberException, ItemFilmAlreadyExistsException { + + validateUser(login, password); + + if (title == null || title.trim().isEmpty()) + throw new BadEntryException("Error: Title is null or empty"); + if (kind == null || kind.trim().isEmpty()) + throw new BadEntryException("Error: Kind is null or empty"); + if (director == null || director.trim().isEmpty()) + throw new BadEntryException("Error: Director is null or empty"); + if (scriptwriter == null || scriptwriter.trim().isEmpty()) + throw new BadEntryException("Error: Scriptwriter is null or empty"); + if (duration <= 0) + throw new BadEntryException("Error: Duration must be > 0"); + if (!authenticateUser(login, password)) + throw new NotMemberException("Error: Invalid login or password"); + + for (Film f : listFilm) { + if (f.compareTitle(title)) { + throw new ItemFilmAlreadyExistsException(); + } + } + + Film film = new Film(title.trim(), kind.trim(), director.trim(), scriptwriter.trim(), duration); + listFilm.add(film); + nbfilms++; + } + /** + * Returns number of films. + * + * @return 0 + */ + @Override + public int nbFilms() { + return nbfilms; + } + + @Override + public float reviewItemFilm(String login, String password, String title, float mark, String comment) + throws BadEntryException, NotMemberException, NotItemException { + + validateUser(login, password); + if (comment == null) + throw new BadEntryException("Error: Comment is null"); + if (mark < 0.0f || mark > 5.0f) + throw new BadEntryException("Error: Mark must be between 0.0 and 5.0"); + if (!authenticateUser(login, password)) + throw new NotMemberException("Error: Invalid login or password"); + + for (Film f : listFilm) { + if (f.compareTitle(title)) { + f.addOrUpdateReview(login.trim(), mark, comment); + return f.getAverageMark(); + } + } + + throw new NotItemException("Error: Film not found"); } /** @@ -196,12 +248,7 @@ public class SocialNetwork implements ISocialNetwork { nbbooks++; } - @Override - public float reviewItemFilm(String login, String password, String title, float mark, String comment) - throws BadEntryException, NotMemberException, NotItemException { - // TODO Auto-generated method stub - return 0; - } + /** * @@ -257,13 +304,24 @@ public class SocialNetwork implements ISocialNetwork { if (title == null || title.trim().length() <= 1) { throw new BadEntryException("Error: Title is null or too short"); } + String formattedTitle = title.trim().toLowerCase(); LinkedList<String> result = new LinkedList<>(); + for (Book b : listBook) { if (b.getTitle().toLowerCase().contains(formattedTitle)) { result.add(b.toString()); } } + + for (Film f : listFilm) { + if (f.getTitle().toLowerCase().contains(formattedTitle) + || f.getDirector().toLowerCase().contains(formattedTitle) + || f.getScenarist().toLowerCase().contains(formattedTitle)) { + result.add(f.toString()); + } + } + return result; } diff --git a/src/tests/AddItemBookTest.java b/src/tests/AddItemBookTest.java index 07dc4b9c15e3d872b6cc30a4e119164352c8f3f5..bbc9aa0e6873a8ba42297efe973af99ac37bb2f5 100644 --- a/src/tests/AddItemBookTest.java +++ b/src/tests/AddItemBookTest.java @@ -1,12 +1,8 @@ package tests; +import exceptions.*; import opinion.ISocialNetwork; import opinion.SocialNetwork; -import exceptions.BadEntryException; -import exceptions.MemberAlreadyExistsException; -import exceptions.NotMemberException; -import exceptions.ItemBookAlreadyExistsException; -import exceptions.NotTestReportException; /** * Tests for the SocialNetwork.<i>addItemBook()</i> method. diff --git a/src/tests/AddItemFilmTest.java b/src/tests/AddItemFilmTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2b5722c4e381d9e6594080ef935f73732c1ddc76 --- /dev/null +++ b/src/tests/AddItemFilmTest.java @@ -0,0 +1,138 @@ +package tests; + +import exceptions.BadEntryException; +import exceptions.ItemFilmAlreadyExistsException; +import exceptions.MemberAlreadyExistsException; +import exceptions.NotTestReportException; +import opinion.ISocialNetwork; +import opinion.SocialNetwork; + +/** + * Tests for the SocialNetwork.<i>addItemFilm()</i> method. + */ +public class AddItemFilmTest { + + /** + * Check that the method addItemFilm() throws the expected exception. + * + * @param sn the <i>ISocialNetwork</i> to test + * @param login login of the member + * @param password password of the member + * @param title title of the film + * @param kind kind of the film + * @param director director of the film + * @param scenarist scenarist of the film + * @param duration duration of the film (in minutes) + * @param testId id of the test + * @param expectedException error message to display if test fails + * @return 0 if the exception was correctly thrown, 1 otherwise + */ + private static int checkAddItemFilmException(ISocialNetwork sn, String login, String password, String title, String kind, String director, String scenarist, int duration, String testId, Class<?> expectedException) { + try { + sn.addItemFilm(login, password, title, kind, director, scenarist, duration); + System.out.println("Err " + testId + " : Expected exception " + expectedException.getSimpleName() + " was not thrown"); + return 1; + } catch (Exception e) { + if (e.getClass().equals(expectedException)) { + return 0; + } else { + System.out.println("Err " + testId + " : Unexpected exception " + e); + e.printStackTrace(); + return 1; + } + } + + } + + /** + * Check that the method addItemFilm() works in a nominal case. + * + * @param sn the <i>ISocialNetwork</i> to test + * @param login login of the member + * @param password password of the member + * @param title title of the film + * @param kind kind of the film + * @param director director of the film + * @param scenarist scenarist of the film + * @param duration duration of the film (in minutes) + * @param testId id of the test + * @return 0 if film was correctly added, 1 otherwise + */ + private static int checkAddItemFilmSuccess(ISocialNetwork sn, String login, String password, String title, + String kind, String director, String scenarist, int duration, + String testId) { + try { + sn.addItemFilm(login, password, title, kind, director, scenarist, duration); + return 0; + } catch (Exception e) { + System.out.println("Err " + testId + " : Unexpected exception " + e); + return 1; + } + } + + /** + * Main test for addItemFilm: + * Checks if the method throws BadEntryException or itemFilmAlreadyExistsException in non-nominal conditions + * Checks if the method works correctly in nominal conditions + * + * @return a summary of the performed tests + */ + public static TestReport test() { + + ISocialNetwork sn = new SocialNetwork(); + int nbTests = 0; + int nbErrors = 0; + + try { + sn.addMember("taylorSwift", "password", "profile2"); + } catch (BadEntryException | MemberAlreadyExistsException e) { + System.out.println("Err : Unexpected exception " + e); + e.printStackTrace(); + } + + // Non-nominal scenarios except 4.5 + + // Test 4.1: Login is null + nbTests++; + nbErrors += checkAddItemFilmException(sn, null, "password", "Inception", "Sci-Fi", "Nolan", "Nolan", 120, + "4.1", BadEntryException.class); + + // Test 4.2: Password is too short + nbTests++; + nbErrors += checkAddItemFilmException(sn, "taylorSwift", "123", "Inception", "Sci-Fi", "Nolan", "Nolan", 120, + "4.2", BadEntryException.class); + + // Test 4.3: Title is null + nbTests++; + nbErrors += checkAddItemFilmException(sn, "taylorSwift", "password", null, "Sci-Fi", "Nolan", "Nolan", 120, + "4.3", BadEntryException.class); + + // Test 4.4: Duration is negative + nbTests++; + nbErrors += checkAddItemFilmException(sn, "taylorSwift", "password", "Inception", "Sci-Fi", "Nolan", "Nolan", -10, + "4.4", BadEntryException.class); + + // Test 4.5: Valid film creation (Nominal) + nbTests++; + nbErrors += checkAddItemFilmSuccess(sn, "taylorSwift", "password", "Inception", "Sci-Fi", "Nolan", "Nolan", 120, + "4.5"); + + // Test 4.6: Duplicate film creation + nbTests++; + nbErrors += checkAddItemFilmException(sn, "taylorSwift", "password", "Inception", "Sci-Fi", "Nolan", "Nolan", 120, + "4.6", ItemFilmAlreadyExistsException.class); + + try { + TestReport tr = new TestReport(nbTests, nbErrors); + System.out.println("AddItemBookTest : " + tr); + return tr; + } catch (NotTestReportException e) { + System.out.println("Unexpected error in AddItemBookTest test code - Can't return valuable test results"); + return null; + } + } + + public static void main(String[] args) { + test(); + } +} \ No newline at end of file diff --git a/src/tests/ConsultItemFilmTest.java b/src/tests/ConsultItemFilmTest.java new file mode 100644 index 0000000000000000000000000000000000000000..59bb273ce08851a7741864f3fbaf709deb7b2b5a --- /dev/null +++ b/src/tests/ConsultItemFilmTest.java @@ -0,0 +1,75 @@ +package tests; + +import exceptions.*; +import opinion.ISocialNetwork; +import opinion.SocialNetwork; + +import java.util.LinkedList; + +public class ConsultItemFilmTest { + + private static int checkConsultItemFilmException(ISocialNetwork sn, String title, Class<?> expectedException, String testId) { + try { + sn.consultItems(title); + System.out.println("Err " + testId + " : Expected exception " + expectedException.getSimpleName() + " was not thrown"); + return 1; + } catch (Exception e) { + if (e.getClass().equals(expectedException)) { + System.out.println("Test " + testId + " passed (caught expected " + expectedException.getSimpleName() + ")"); + return 0; + } else { + System.out.println("Err " + testId + " : Unexpected exception " + e); + e.printStackTrace(); + return 1; + } + } + } + + private static int checkConsultItemFilmResult(ISocialNetwork sn, String title, int expectedSize, String testId) { + try { + LinkedList<String> results = sn.consultItems(title); + if (results.size() == expectedSize) { + System.out.println("Test " + testId + " passed."); + return 0; + } else { + System.out.println("Err " + testId + " : Expected " + expectedSize + " result(s) but got " + results.size()); + return 1; + } + } catch (Exception e) { + System.out.println("Err " + testId + " : Unexpected exception " + e); + e.printStackTrace(); + return 1; + } + } + + public static void main(String[] args) { + ISocialNetwork sn = new SocialNetwork(); + int nbTests = 0; + int nbErrors = 0; + + try { + sn.addMember("cinefan", "securepass", "film fan"); + sn.addItemFilm("cinefan", "securepass", "Interstellar", "Sci-Fi", "Christopher Nolan", "Jonathan Nolan", 169); + sn.addItemFilm("cinefan", "securepass", "Inception", "Thriller", "Christopher Nolan", "Christopher Nolan", 148); + } catch (Exception e) { + System.out.println("Setup failed: " + e); + return; + } + + // Nominal tests + nbTests++; + nbErrors += checkConsultItemFilmResult(sn, "Inception", 1, "3.1"); + + nbTests++; + nbErrors += checkConsultItemFilmResult(sn, "nolan", 2, "3.2"); + + nbTests++; + nbErrors += checkConsultItemFilmResult(sn, "Unknown Film", 0, "3.3"); + + // Non-nominal test (expects exception) + nbTests++; + nbErrors += checkConsultItemFilmException(sn, "", BadEntryException.class, "3.4"); + + System.out.println("\nConsultItemFilmTest summary: " + nbErrors + " error(s) out of " + nbTests + " test(s)."); + } +} diff --git a/src/tests/ReviewItemFilmTest.java b/src/tests/ReviewItemFilmTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c54a6c4d94ab8799ffa46172a6edec04d612a69c --- /dev/null +++ b/src/tests/ReviewItemFilmTest.java @@ -0,0 +1,124 @@ +package tests; + +import exceptions.BadEntryException; +import exceptions.NotItemException; +import exceptions.NotMemberException; +import exceptions.NotTestReportException; +import opinion.ISocialNetwork; +import opinion.SocialNetwork; + +/** + * Tests for the SocialNetwork.<i>reviewItemFilm()</i> method. + */ +public class ReviewItemFilmTest { + + /** + * Checks that reviewItemFilm() returns the expected average after adding a review. + */ + private static int checkReviewItemFilmAverage(ISocialNetwork sn, String login, String password, String title, + float mark, String comment, float expectedAverage, String testId) { + try { + float avg = sn.reviewItemFilm(login, password, title, mark, comment); + if (Math.abs(avg - expectedAverage) < 0.01) { + return 0; + } else { + System.out.println("Err " + testId + " : Expected average " + expectedAverage + " but got " + avg); + return 1; + } + } catch (Exception e) { + System.out.println("Err " + testId + " : Unexpected exception " + e); + e.printStackTrace(); + return 1; + } + } + + /** + * Checks that reviewItemFilm() throws the expected exception. + */ + private static int checkReviewItemFilmException(ISocialNetwork sn, String login, String password, String title, + float mark, String comment, Class<?> expectedException, String testId) { + try { + sn.reviewItemFilm(login, password, title, mark, comment); + System.out.println("Err " + testId + " : Expected exception " + expectedException.getSimpleName() + " was not thrown"); + return 1; + } catch (Exception e) { + if (e.getClass().equals(expectedException)) { + return 0; + } else { + System.out.println("Err " + testId + " : Unexpected exception " + e); + e.printStackTrace(); + return 1; + } + } + } + + /** + * Launch all tests for reviewItemFilm(). + */ + private static TestReport test() { + ISocialNetwork sn = new SocialNetwork(); + int nbTests = 0; + int nbErrors = 0; + + try { + sn.addMember("Neva", "pass123", "casual reader"); + sn.addMember("Maryam", "1234pass", "fantasy reader"); + sn.addItemFilm("Neva", "pass123", "Inception", "Sci-Fi", "Nolan", "Nolan", 120); + } catch (Exception e) { + System.out.println("Setup failed: " + e); + e.printStackTrace(); + return null; + } + + System.out.println("Testing reviewItemFilm()"); + + // Test 4.7: login is null + nbTests++; + nbErrors += checkReviewItemFilmException(sn, null, "pass123", "Inception", 4.0f, "Great!", + BadEntryException.class, "4.7"); + + // Test 4.8: password is too short + nbTests++; + nbErrors += checkReviewItemFilmException(sn, "Maryam", "12", "Inception", 4.0f, "Nice!", + BadEntryException.class, "4.8"); + + // Test 4.9: title is null + nbTests++; + nbErrors += checkReviewItemFilmException(sn, "Maryam", "1234pass", null, 4.0f, "Awesome!", + NotItemException.class, "4.9"); + + // Test 4.10: member does not exist + nbTests++; + nbErrors += checkReviewItemFilmException(sn, "unknown", "password", "Inception", 4.0f, "Not bad", + NotMemberException.class, "4.10"); + + // Test 4.11: item does not exist + nbTests++; + nbErrors += checkReviewItemFilmException(sn, "Maryam", "1234pass", "Unknown Film", 4.0f, "Great!", + NotItemException.class, "4.11"); + + // Test 4.12: first valid review, expect average 4.0 + nbTests++; + nbErrors += checkReviewItemFilmAverage(sn, "Maryam", "1234pass", "Inception", 4.0f, "Great film!", + 4.0f, "4.12"); + + // Test 4.13: second review, expect average 3.0 + nbTests++; + nbErrors += checkReviewItemFilmAverage(sn, "Neva", "pass123", "Inception", 2.0f, "Okay film", + 3.0f, "4.13"); + + // Print a summary of the tests and return test results + try { + TestReport report = new TestReport(nbTests, nbErrors); + System.out.println("ReviewItemBookTest : " + report); + return report; + } catch (NotTestReportException e) { + System.out.println("Failed to create TestReport"); + return null; + } + } + + public static void main(String[] args) { + test(); + } +}