Skip to content
Snippets Groups Projects
Commit 69652de4 authored by BINTI TENGKU MASRULHISHAM Tengku Maryam Naqeesha's avatar BINTI TENGKU MASRULHISHAM Tengku Maryam Naqeesha
Browse files

Documentation Iteration 4

parent 7fea9973
Branches
Tags
2 merge requests!15Initial fix for addItem based on cross test results,!12Documentation Iteration 4
# fip112-2025-g41 # 📚🎬 SocialNetwork Java Application
This project implements a **social network** platform where users can review and consult books and films. It features a robust backend structure with custom exception handling and extensive testing for all core functionalities.
---
## Getting started ## 🏗️ Project Structure
To make it easy for you to get started with GitLab, here's a list of recommended next steps. ├── opinion/
│ ├── SocialNetwork.java # Main class managing all functionality
│ ├── ISocialNetwork.java # Interface defining public methods
│ ├── Member.java # Represents a registered user
│ ├── Item.java # Abstract base class for Book and Film
│ ├── Book.java # Book implementation
│ └── Film.java # Film implementation
├── tests/
│ ├── AddItemBookTest.java
│ ├── AddItemFilmTest.java
│ ├── ReviewItemBookTest.java
│ ├── ReviewItemFilmTest.java
│ ├── ConsultItemBookTest.java
│ └── ConsultItemFilmTest.java
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files ---
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files ## 🚀 Main Functionalities
- [ ] [Add files using the command line](https://docs.gitlab.com/topics/git/add_files/#add-files-to-a-git-repository) or push an existing Git repository with the following command:
``` ### ✅ Member Management
cd existing_repo - `addMember(String login, String password, String profile)`
git remote add origin https://gitlab-df.imt-atlantique.fr/t24binti/fip112-2025-g41.git - Adds a new member to the network
git branch -M main - Validates credentials (non-null, password ≥ 4 characters)
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](https://gitlab-df.imt-atlantique.fr/t24binti/fip112-2025-g41/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Set auto-merge](https://docs.gitlab.com/user/project/merge_requests/auto_merge/)
## Test and Deploy ### 📘 Item Management
- `addItemBook(...)` / `addItemFilm(...)`
- Adds a book or film
- Only members can add items
- Rejects duplicate titles (case-insensitive and whitespace-trimmed)
Use the built-in continuous integration in GitLab. ### ✍️ Reviews
- `reviewItemBook(...)` / `reviewItemFilm(...)`
- Members can rate and review an item
- Automatically updates the average rating if a review is updated
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/) ### 🔍 Item Consultation
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) - `consultItems(String keyword)`
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) - Searches items (books or films) by partial match
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) - Case-insensitive
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) - Returns a list of formatted strings containing item details
*** ---
# Editing this README ## 🧪 Testing
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template. The project includes **multiple unit tests** covering all features:
## Suggestions for a good README ### 🔎 Test Categories
- Add book/film with valid and invalid inputs
- Duplicate item handling
- Review creation, update, and average calculation
- Error handling for null/empty inputs
- Case-insensitive search for item consultation
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. Each test:
- Is labeled with a **test ID** (`3.x` for books, `4.x` for films)
- Prints clear **OK** / **Err** messages
- Is grouped as **nominal** or **non-nominal**
## Name ---
Choose a self-explaining name for your project.
## Description ## 📊 Sample Test Results Table
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges | No | Identification du test | Résultat | Gravité |
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. |------|------------------------------------------------------------------------------------------------------------------|----------|---------|
| 4.1 | Utilisation de addItemFilm avec un login null | OK | |
| 4.6 | Utilisation de addItemFilm pour créer un film déjà existant | OK | |
| 4.13 | Utilisation de reviewItemFilm par un deuxième utilisateur pour vérifier la mise à jour de la moyenne | OK | |
| 4.18 | Utilisation de consultItems avec un titre vide | OK | |
## Visuals ---
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation ## 🛠️ Running the Tests
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage To run the tests:
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support ```bash
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. # Compile the source
javac opinion/*.java tests/*.java
## Roadmap # Run any test class
If you have ideas for releases in the future, it is a good idea to list them in the README. java tests.ReviewItemFilmTest
java tests.ConsultItemFilmTest
## Contributing ```
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. ---
## Authors and acknowledgment ## Authors and acknowledgment
Show your appreciation to those who have contributed to the project. - Developed by : Maryam TENGKU (Developer), Neva MASSY (Developer)
- Course : INF112
- Institution : IMT Atlantique, France
## License ---
For open source projects, say how it is licensed.
## Project status ## License
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. This project is intended for academic and educational use.
\ No newline at end of file
...@@ -7,7 +7,7 @@ import opinion.SocialNetwork; ...@@ -7,7 +7,7 @@ import opinion.SocialNetwork;
import java.util.LinkedList; import java.util.LinkedList;
/** /**
* Tests for the <i>consultItems()</i> method. * Tests for the <i>consultItems()</i> method applied to books.
*/ */
public class ConsultItemBookTest { public class ConsultItemBookTest {
...@@ -85,7 +85,7 @@ public class ConsultItemBookTest { ...@@ -85,7 +85,7 @@ public class ConsultItemBookTest {
return null; return null;
} }
System.out.println("Testing consultItems()"); System.out.println("Testing consultItems() for books");
// Non-nominal scenarios // Non-nominal scenarios
...@@ -107,7 +107,7 @@ public class ConsultItemBookTest { ...@@ -107,7 +107,7 @@ public class ConsultItemBookTest {
nbTests++; nbTests++;
nbErrors += checkConsultItemBookResult(sn, "princip", 2, "3.14"); nbErrors += checkConsultItemBookResult(sn, "princip", 2, "3.14");
// Test 3.15 : Matches "Don Quijote" case-insensitively // Test 3.15 : Matches "Don Quijote" case insensitively
nbTests++; nbTests++;
nbErrors += checkConsultItemBookResult(sn, "DON", 1, "3.15"); nbErrors += checkConsultItemBookResult(sn, "DON", 1, "3.15");
......
...@@ -6,8 +6,20 @@ import opinion.SocialNetwork; ...@@ -6,8 +6,20 @@ import opinion.SocialNetwork;
import java.util.LinkedList; import java.util.LinkedList;
/**
* Tests for the <i>consultItems()</i> method applied to films.
*/
public class ConsultItemFilmTest { public class ConsultItemFilmTest {
/**
* Checks that consultItems() throws the expected exception.
*
* @param sn the social network
* @param title the title to consult
* @param expectedException the expected exception class
* @param testId the test identifier
* @return 0 if test is OK, 1 if not OK
*/
private static int checkConsultItemFilmException(ISocialNetwork sn, String title, Class<?> expectedException, String testId) { private static int checkConsultItemFilmException(ISocialNetwork sn, String title, Class<?> expectedException, String testId) {
try { try {
sn.consultItems(title); sn.consultItems(title);
...@@ -15,7 +27,6 @@ public class ConsultItemFilmTest { ...@@ -15,7 +27,6 @@ public class ConsultItemFilmTest {
return 1; return 1;
} catch (Exception e) { } catch (Exception e) {
if (e.getClass().equals(expectedException)) { if (e.getClass().equals(expectedException)) {
System.out.println("Test " + testId + " passed (caught expected " + expectedException.getSimpleName() + ")");
return 0; return 0;
} else { } else {
System.out.println("Err " + testId + " : Unexpected exception " + e); System.out.println("Err " + testId + " : Unexpected exception " + e);
...@@ -25,11 +36,19 @@ public class ConsultItemFilmTest { ...@@ -25,11 +36,19 @@ public class ConsultItemFilmTest {
} }
} }
/**
* Checks that consultItems() returns the expected number of results.
*
* @param sn the social network
* @param title the search keyword
* @param expectedSize number of expected items in result
* @param testId the test identifier
* @return 0 if test is OK, 1 if not OK
*/
private static int checkConsultItemFilmResult(ISocialNetwork sn, String title, int expectedSize, String testId) { private static int checkConsultItemFilmResult(ISocialNetwork sn, String title, int expectedSize, String testId) {
try { try {
LinkedList<String> results = sn.consultItems(title); LinkedList<String> results = sn.consultItems(title);
if (results.size() == expectedSize) { if (results.size() == expectedSize) {
System.out.println("Test " + testId + " passed.");
return 0; return 0;
} else { } else {
System.out.println("Err " + testId + " : Expected " + expectedSize + " result(s) but got " + results.size()); System.out.println("Err " + testId + " : Expected " + expectedSize + " result(s) but got " + results.size());
...@@ -42,7 +61,14 @@ public class ConsultItemFilmTest { ...@@ -42,7 +61,14 @@ public class ConsultItemFilmTest {
} }
} }
public static void main(String[] args) { /**
* Main test method for consultItems() with films:
* Checks if the method throws BadEntryException 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(); ISocialNetwork sn = new SocialNetwork();
int nbTests = 0; int nbTests = 0;
int nbErrors = 0; int nbErrors = 0;
...@@ -51,25 +77,50 @@ public class ConsultItemFilmTest { ...@@ -51,25 +77,50 @@ public class ConsultItemFilmTest {
sn.addMember("cinefan", "securepass", "film fan"); sn.addMember("cinefan", "securepass", "film fan");
sn.addItemFilm("cinefan", "securepass", "Interstellar", "Sci-Fi", "Christopher Nolan", "Jonathan Nolan", 169); sn.addItemFilm("cinefan", "securepass", "Interstellar", "Sci-Fi", "Christopher Nolan", "Jonathan Nolan", 169);
sn.addItemFilm("cinefan", "securepass", "Inception", "Thriller", "Christopher Nolan", "Christopher Nolan", 148); sn.addItemFilm("cinefan", "securepass", "Inception", "Thriller", "Christopher Nolan", "Christopher Nolan", 148);
} catch (Exception e) { } catch (BadEntryException | MemberAlreadyExistsException | NotMemberException | ItemFilmAlreadyExistsException e) {
System.out.println("Setup failed: " + e); System.out.println("Setup failed: " + e);
return; e.printStackTrace();
return null;
} }
// Nominal tests System.out.println("Testing consultItems() for films");
// Nominal scenarios
// Test 4.14 : Matches "Inception"
nbTests++; nbTests++;
nbErrors += checkConsultItemFilmResult(sn, "Inception", 1, "3.1"); nbErrors += checkConsultItemFilmResult(sn, "Inception", 1, "4.14");
// Test 4.15 : Matches "Cristopher Nolan" case insensitively
nbTests++; nbTests++;
nbErrors += checkConsultItemFilmResult(sn, "nolan", 2, "3.2"); nbErrors += checkConsultItemFilmResult(sn, "nolan", 2, "4.15");
// Test 4.16 : No matches
nbTests++; nbTests++;
nbErrors += checkConsultItemFilmResult(sn, "Unknown Film", 0, "3.3"); nbErrors += checkConsultItemFilmResult(sn, "Unknown Film", 0, "4.16");
// Non-nominal scenarios
// Non-nominal test (expects exception) // Test 4.17 : Uninstantiated title
nbTests++; nbTests++;
nbErrors += checkConsultItemFilmException(sn, "", BadEntryException.class, "3.4"); nbErrors += checkConsultItemFilmException(sn, null, BadEntryException.class, "4.17");
System.out.println("\nConsultItemFilmTest summary: " + nbErrors + " error(s) out of " + nbTests + " test(s)."); // Test 4.18 : Invalid title (empty)
nbTests++;
nbErrors += checkConsultItemFilmException(sn, "", BadEntryException.class, "4.18");
// Print a summary of the tests and return test results
try {
TestReport tr = new TestReport(nbTests, nbErrors);
System.out.println("ConsultItemFilmTest : " + tr);
return tr;
} catch (NotTestReportException e) {
System.out.println("Unexpected error in ConsultItemFilmTest test code - Can't return valuable test results");
return null;
}
}
public static void main(String[] args) {
test();
} }
} }
\ No newline at end of file
package tests; package tests;
import exceptions.BadEntryException; import exceptions.*;
import exceptions.NotItemException;
import exceptions.NotMemberException;
import exceptions.NotTestReportException;
import opinion.ISocialNetwork; import opinion.ISocialNetwork;
import opinion.SocialNetwork; import opinion.SocialNetwork;
......
...@@ -14,6 +14,16 @@ public class ReviewItemFilmTest { ...@@ -14,6 +14,16 @@ public class ReviewItemFilmTest {
/** /**
* Checks that reviewItemFilm() returns the expected average after adding a review. * Checks that reviewItemFilm() returns the expected average after adding a review.
*
* @param sn the social network
* @param login the login of the reviewing member
* @param password the password of the reviewing member
* @param title the title of the book
* @param mark the rating given
* @param comment the comment provided
* @param expectedAverage the expected average rating
* @param testId the test identifier
* @return 0 if test is OK, 1 if not OK
*/ */
private static int checkReviewItemFilmAverage(ISocialNetwork sn, String login, String password, String title, private static int checkReviewItemFilmAverage(ISocialNetwork sn, String login, String password, String title,
float mark, String comment, float expectedAverage, String testId) { float mark, String comment, float expectedAverage, String testId) {
...@@ -33,7 +43,17 @@ public class ReviewItemFilmTest { ...@@ -33,7 +43,17 @@ public class ReviewItemFilmTest {
} }
/** /**
* Checks that reviewItemFilm() throws the expected exception. * Checks that reviewItemFilm() throws the expected exception in invalid situations.
*
* @param sn the social network
* @param login the login of the reviewer
* @param password the reviewer's password
* @param title the book's title
* @param mark the rating
* @param comment the review comment
* @param expectedException the expected exception class
* @param testId the test identifier
* @return 0 if test is OK, 1 if not OK
*/ */
private static int checkReviewItemFilmException(ISocialNetwork sn, String login, String password, String title, private static int checkReviewItemFilmException(ISocialNetwork sn, String login, String password, String title,
float mark, String comment, Class<?> expectedException, String testId) { float mark, String comment, Class<?> expectedException, String testId) {
...@@ -53,7 +73,10 @@ public class ReviewItemFilmTest { ...@@ -53,7 +73,10 @@ public class ReviewItemFilmTest {
} }
/** /**
* Launch all tests for reviewItemFilm(). * Main test method for reviewItemFilm:
* Tests both nominal and non-nominal scenarios.
*
* @return a summary of the performed tests
*/ */
private static TestReport test() { private static TestReport test() {
ISocialNetwork sn = new SocialNetwork(); ISocialNetwork sn = new SocialNetwork();
...@@ -72,37 +95,37 @@ public class ReviewItemFilmTest { ...@@ -72,37 +95,37 @@ public class ReviewItemFilmTest {
System.out.println("Testing reviewItemFilm()"); System.out.println("Testing reviewItemFilm()");
// Test 4.7: login is null // Test 4.7: Login is null
nbTests++; nbTests++;
nbErrors += checkReviewItemFilmException(sn, null, "pass123", "Inception", 4.0f, "Great!", nbErrors += checkReviewItemFilmException(sn, null, "pass123", "Inception", 4.0f, "Great!",
BadEntryException.class, "4.7"); BadEntryException.class, "4.7");
// Test 4.8: password is too short // Test 4.8: Password is too short
nbTests++; nbTests++;
nbErrors += checkReviewItemFilmException(sn, "Maryam", "12", "Inception", 4.0f, "Nice!", nbErrors += checkReviewItemFilmException(sn, "Maryam", "12", "Inception", 4.0f, "Nice!",
BadEntryException.class, "4.8"); BadEntryException.class, "4.8");
// Test 4.9: title is null // Test 4.9: Title is null
nbTests++; nbTests++;
nbErrors += checkReviewItemFilmException(sn, "Maryam", "1234pass", null, 4.0f, "Awesome!", nbErrors += checkReviewItemFilmException(sn, "Maryam", "1234pass", null, 4.0f, "Awesome!",
NotItemException.class, "4.9"); NotItemException.class, "4.9");
// Test 4.10: member does not exist // Test 4.10: Member does not exist
nbTests++; nbTests++;
nbErrors += checkReviewItemFilmException(sn, "unknown", "password", "Inception", 4.0f, "Not bad", nbErrors += checkReviewItemFilmException(sn, "unknown", "password", "Inception", 4.0f, "Not bad",
NotMemberException.class, "4.10"); NotMemberException.class, "4.10");
// Test 4.11: item does not exist // Test 4.11: Item does not exist
nbTests++; nbTests++;
nbErrors += checkReviewItemFilmException(sn, "Maryam", "1234pass", "Unknown Film", 4.0f, "Great!", nbErrors += checkReviewItemFilmException(sn, "Maryam", "1234pass", "Unknown Film", 4.0f, "Great!",
NotItemException.class, "4.11"); NotItemException.class, "4.11");
// Test 4.12: first valid review, expect average 4.0 // Test 4.12: First valid review, expect average 4.0
nbTests++; nbTests++;
nbErrors += checkReviewItemFilmAverage(sn, "Maryam", "1234pass", "Inception", 4.0f, "Great film!", nbErrors += checkReviewItemFilmAverage(sn, "Maryam", "1234pass", "Inception", 4.0f, "Great film!",
4.0f, "4.12"); 4.0f, "4.12");
// Test 4.13: second review, expect average 3.0 // Test 4.13: Second review, expect average 3.0
nbTests++; nbTests++;
nbErrors += checkReviewItemFilmAverage(sn, "Neva", "pass123", "Inception", 2.0f, "Okay film", nbErrors += checkReviewItemFilmAverage(sn, "Neva", "pass123", "Inception", 2.0f, "Okay film",
3.0f, "4.13"); 3.0f, "4.13");
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment