Skip to content

Merge Fix/testcoverage into release/v2.0.0 #76

Merged
merged 5 commits into from
Apr 21, 2026
Merged
Show file tree
Hide file tree
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
6 changes: 3 additions & 3 deletions src/main/java/edu/group5/app/model/AppState.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class AppState {
private User currentUser;
private BigDecimal currentDonationAmount;
private Organization currentOrganization;
private String currentDonation;
private String currentPaymentMethod;

/**
* Gets the current user of the application.
Expand Down Expand Up @@ -73,14 +73,14 @@ public void setCurrentDonationAmount(BigDecimal amount) {
* @return the current payment method
*/
public String getCurrentPaymentMethod() {
return this.currentDonation;
return this.currentPaymentMethod;
}

/**
* Sets the current payment method.
* @param paymentMethod the payment method to set as the current payment method
*/
public void setCurrentPaymentMethod(String paymentMethod){
this.currentDonation = paymentMethod;
this.currentPaymentMethod = paymentMethod;
}
}
8 changes: 0 additions & 8 deletions src/main/java/edu/group5/app/model/Repository.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,4 @@ protected Repository(Map<K, V> content) {
ParameterValidator.objectChecker(content, "content");
this.content = content;
}

/**
* Gets the content of the repository.
* @return the content of the repository
*/
public Map<K, V> getContent() {
return content;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,38 +40,53 @@ public String fetchDescription(String pageUrl) {
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
.timeout(5000).get();

Element section = doc.selectFirst("section.information");
if (section != null) {
section.select("div.extra-info").remove();
section.select("a.read-more").remove();

// Extract all <p> tags and <div> elements as separate paragraphs
String description = section.select("p, div").stream()
.filter(el -> el.tagName().equals("p") || el.select("p").isEmpty())
.filter(el -> !el.hasClass("extra-info") && !el.hasClass("logo"))
.map(Element::text)
.map(text -> text.replace("Les mer", "").trim())
.filter(text -> !text.isBlank())
.collect(Collectors.joining("\n\n"));

// Fallback: if no paragraphs found, get all text from section
if (description.isBlank()) {
description = section.text().trim();
}
description = description.replace("Les mer", "").trim();

// Only cache and return if we found something meaningful
if (!description.isBlank()) {
descriptionCache.put(pageUrl, description);
return description;
}
String description = parseDescription(doc);
if (!description.isBlank()) {
descriptionCache.put(pageUrl, description);
return description;
}
} catch (Exception e) {
System.out.println("Could not get description for: " + pageUrl);
}
return null;
}

/**
* Parses the description from a Document by extracting text content
* from {@code <section class="information">}.
*
* @param doc the Document to parse
* @return the description text, or empty string if not found
*/
protected String parseDescription(Document doc) {
Element section = doc.selectFirst("section.information");
if (section != null) {
section.select("div.extra-info").remove();
section.select("a.read-more").remove();

// Extract all <p> tags and <div> elements as separate paragraphs
String description = section.select("p, div").stream()
.filter(el -> el.tagName().equals("p") || el.select("p").isEmpty())
.filter(el -> !el.hasClass("extra-info") && !el.hasClass("logo"))
.map(Element::text)
.map(text -> text.replace("Les mer", "").trim())
.filter(text -> !text.isBlank())
.collect(Collectors.joining("\n\n"));

// Fallback: if no paragraphs found, get all text from section
if (description.isBlank()) {
description = section.text().trim();
}
description = description.replace("Les mer", "").trim();

// Only return if we found something meaningful
if (!description.isBlank()) {
return description;
}
}
return "";
}

/**
* Fetches the logo URL for the given page by scraping the {@code div.logo img}
* element. Results are cached so each URL is only fetched once.
Expand All @@ -88,10 +103,9 @@ public String fetchLogoUrl(String pageUrl) {
Document doc = Jsoup.connect(pageUrl)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
.timeout(5000).get();
Element img = doc.selectFirst("div.logo img");

if (img != null) {
String logoUrl = img.absUrl("src");
String logoUrl = parseLogoUrl(doc);
if (!logoUrl.isBlank()) {
logoCache.put(pageUrl, logoUrl);
return logoUrl;
}
Expand All @@ -100,4 +114,20 @@ public String fetchLogoUrl(String pageUrl) {
}
return null;
}

/**
* Parses the logo URL from a Document by extracting the image src
* from {@code div.logo img}.
*
* @param doc the Document to parse
* @return the absolute logo URL, or empty string if not found
*/
protected String parseLogoUrl(Document doc) {
Element img = doc.selectFirst("div.logo img");
if (img != null) {
String logoUrl = img.absUrl("src");
return logoUrl.isBlank() ? "" : logoUrl;
}
return "";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private StackPane createImageContainer() {
// Load image in background thread to avoid blocking UI
new Thread(() -> {
try {
Image image = new Image(org.logoUrl(), 120, 120, true, true);
Image image = new Image(org.logoUrl(), 350, 350, true, true);
Platform.runLater(() -> {
ImageView logo = new ImageView(image);
logo.setId("logo");
Expand Down
69 changes: 69 additions & 0 deletions src/test/java/edu/group5/app/model/AppStateTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package edu.group5.app.model;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.math.BigDecimal;

import org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import edu.group5.app.model.organization.Organization;
import edu.group5.app.model.user.Customer;
import edu.group5.app.model.user.User;

public class AppStateTest {
private User nullUser;
private BigDecimal nullDonationAmount;
private Organization nullOrganization;
private String nullPaymentMethod;

private User currentTestUser;
private BigDecimal currentTestDonationAmount;
private Organization currentTestOrganization;
private String currentTestPaymentMethod;

@BeforeEach
void setUp() {
nullUser = null;
nullDonationAmount = null;
nullOrganization = null;
nullPaymentMethod = null;

currentTestUser = new Customer(1, "Bob",
"Builder", "testuser@example.com",
"password123");

currentTestDonationAmount = BigDecimal.ZERO;

currentTestOrganization = new Organization(1738, "TestOrg",
true, "https://testorg.example.com", true,
"A test organization", "https://testorg.example.com/logo.png");

currentTestPaymentMethod = "Credit Card";
}

@Test
void gettersAndSetters_WorkCorrectly() {
AppState appState = new AppState();

// Test current user
assertEquals(nullUser, appState.getCurrentUser());
appState.setCurrentUser(currentTestUser);
assertEquals(currentTestUser, appState.getCurrentUser());

// Test current donation amount
assertEquals(nullDonationAmount, appState.getCurrentDonationAmount());
appState.setCurrentDonationAmount(currentTestDonationAmount);
assertEquals(currentTestDonationAmount, appState.getCurrentDonationAmount());

// Test current organization
assertEquals(nullOrganization, appState.getCurrentOrganization());
appState.setCurrentOrganization(currentTestOrganization);
assertEquals(currentTestOrganization, appState.getCurrentOrganization());

// Test current payment method
assertEquals(nullPaymentMethod, appState.getCurrentPaymentMethod());
appState.setCurrentPaymentMethod(currentTestPaymentMethod);
assertEquals(currentTestPaymentMethod, appState.getCurrentPaymentMethod());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;

import java.util.Map;

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

Expand Down Expand Up @@ -61,6 +61,33 @@ void testConstructorThrowsIfOrganizationRepositoryIsNull() {
assertEquals("OrganizationRepository can't be null", exception.getMessage());
}

@Test
void getUserDonationsReturnsEmptyMapIfNoDonations() {
assertTrue(donationService.getUserDonations(customer.getUserId()).isEmpty());
}

@Test
void getOrganizationDonationsReturnsMapOfDonations() {
Donation donation1 = new Donation(1, customer.getUserId(),
101, new BigDecimal("20.00"), Timestamp.from(Instant.now()), "Card");
Donation donation2 = new Donation(2, customer.getUserId(),
101, new BigDecimal("30.00"), Timestamp.from(Instant.now()), "PayPal");
donationRepository.addContent(donation1);
donationRepository.addContent(donation2);

Map<Integer, Donation> donations = donationService.getOrganizationDonations(101);
assertEquals(2, donations.size());
assertTrue(donations.containsKey(1));
assertTrue(donations.containsKey(2));
assertEquals(donation1, donations.get(1));
assertEquals(donation2, donations.get(2));
}

@Test
void getOrganizationDonationsReturnsEmptyMapIfNoDonations() {
assertTrue(donationService.getOrganizationDonations(1).isEmpty());
}

@Test
void donateReturnsFalseIfCustomerNull() {
boolean result = donationService.donate(null,
Expand Down
12 changes: 10 additions & 2 deletions src/test/java/edu/group5/app/model/donation/DonationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,19 @@ void testIfThrowsExceptionWhenOrganizationIdIsNotPositive() {
amount1, date1, paymentMethod1);
}
@Test
void testIfThrowsExceptionWhenAmountIsNotPositive() {
void testIfThrowsExceptionWhenAmountIsNegative() {
expectedMessage = "Amount must be positive and not null";
exceptionTest(donationId1, userId1, organizationId1,
new BigDecimal("0.00"), date1, paymentMethod1);
new BigDecimal("-1.00"), date1, paymentMethod1);
}

@Test
void testIfThrowsExceptionWhenAmountIsNull() {
expectedMessage = "Amount must be positive and not null";
exceptionTest(donationId1, userId1, organizationId1,
null, date1, paymentMethod1);
}

@Test
void testIfThrowsExceptionWhenDateIsNull() {
expectedMessage = "Date must not be null";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,30 @@ void constructor_ThrowsWhenContentIsNull() {
constructorTest(null, "Input data can't be null");
}

@Test
void constructor_SkipsOrganizationWithMissingOrgNumber() {
Object[] content = new Object[] {
Map.of(
"name", "Good Org",
"status", "approved",
"url", "org.com",
"is_pre_approved", true
),
Map.of(
"org_number", "999",
"name", "Bad Org",
"status", "approved",
"url", "org.com",
"is_pre_approved", true
)
};

OrganizationRepository repo = new OrganizationRepository(content, scraper);

assertEquals(1, repo.findByOrgNumber(999) != null ? 1 : 0);
assertNull(repo.findByOrgNumber(1));
}

@Test
void constructor_ThrowsWhenScraperIsNull() {
Object[] content = new Object[] {
Expand Down
Loading