Skip to content

Commit

Permalink
test[JUnit]: add Mockito dependency and more JUnit tests ensuring gre…
Browse files Browse the repository at this point in the history
…ater test coverage
  • Loading branch information
Fredrik Marjoni committed Apr 21, 2026
1 parent 0372fd4 commit 4927aca
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 49 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
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 @@ -2,8 +2,15 @@

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.mockito.MockedStatic;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.times;

class OrganizationScraperTest {

Expand All @@ -15,23 +22,23 @@ void setUp() {
}

@Test
void fetchDescription_ReturnsNullWhenUrlIsNull() {
void fetchDescriptionReturnsNullWhenUrlIsNull() {
assertNull(scraper.fetchDescription(null));
}

@Test
void fetchDescription_ReturnsNullWhenUrlIsBlank() {
void fetchDescriptionReturnsNullWhenUrlIsBlank() {
assertNull(scraper.fetchDescription(""));
}

@Test
void fetchDescription_ReturnsNullWhenUrlIsInvalid() {
void fetchDescriptionReturnsNullWhenUrlIsInvalid() {
String result = scraper.fetchDescription("https://invalid-url-that-does-not-exist-xyz123.com");
assertNull(result);
}

@Test
void fetchDescription_CachesResultOnSecondCall() {
void fetchDescriptionCachesResultOnSecondCall() {
// Mock URLs won't work, but cache still works with null returns
scraper.fetchDescription("https://example.com");
scraper.fetchDescription("https://example.com");
Expand All @@ -40,23 +47,23 @@ void fetchDescription_CachesResultOnSecondCall() {
}

@Test
void fetchLogoUrl_ReturnsNullWhenUrlIsNull() {
void fetchLogoUrlReturnsNullWhenUrlIsNull() {
assertNull(scraper.fetchLogoUrl(null));
}

@Test
void fetchLogoUrl_ReturnsNullWhenUrlIsBlank() {
void fetchLogoUrlReturnsNullWhenUrlIsBlank() {
assertNull(scraper.fetchLogoUrl(""));
}

@Test
void fetchLogoUrl_ReturnsNullWhenUrlIsInvalid() {
void fetchLogoUrlReturnsNullWhenUrlIsInvalid() {
String result = scraper.fetchLogoUrl("https://invalid-url-that-does-not-exist-xyz123.com");
assertNull(result);
}

@Test
void fetchLogoUrl_CachesResultOnSecondCall() {
void fetchLogoUrlCachesResultOnSecondCall() {
// Mock URLs won't work, but cache still works with null returns
scraper.fetchLogoUrl("https://example.com");
scraper.fetchLogoUrl("https://example.com");
Expand All @@ -65,7 +72,7 @@ void fetchLogoUrl_CachesResultOnSecondCall() {
}

@Test
void fetchDescription_ReturnsCachedValue() {
void fetchDescriptionReturnsCachedValue() {
OrganizationScraper scraper = new OrganizationScraper();

// First call - caches (but makes real request)
Expand All @@ -76,4 +83,68 @@ void fetchDescription_ReturnsCachedValue() {

assertEquals(result1, result2); // Same object = cached
}
}

@Test
void fetchDescriptionHandlesExceptionGracefully() {
String result = scraper.fetchDescription("https://invalid-domain-xyz.test");
assertNull(result);
}

@Test
void fetchLogoUrlHandlesExceptionGracefully() {
String result = scraper.fetchLogoUrl("https://invalid-domain-xyz.test");
assertNull(result);
}

@Test
void parseDescriptionExtractsParagraphs() {
String html = "<section class=\"information\"><p>First paragraph</p><p>Second paragraph</p></section>";
Document doc = Jsoup.parse(html);
assertTrue(scraper.parseDescription(doc).contains("First paragraph"));
}

@Test
void parseDescriptionUsesFallbackWhenNoParagraphs() {
String html = "<section class=\"information\">Fallback text without paragraph tags</section>";
Document doc = Jsoup.parse(html);
assertEquals("Fallback text without paragraph tags", scraper.parseDescription(doc));
}

@Test
void parseDescriptionRemovesExtraInfoDivs() {
String html = "<section class=\"information\"><p>Keep this</p><div class=\"extra-info\">Remove this</div></section>";
Document doc = Jsoup.parse(html);
String result = scraper.parseDescription(doc);
assertTrue(result.contains("Keep this"));
assertFalse(result.contains("Remove this"));
}

@Test
void parseDescriptionFiltersOutLesMer() {
String html = "<section class=\"information\"><p>Some text Les mer More text</p></section>";
Document doc = Jsoup.parse(html);
assertFalse(scraper.parseDescription(doc).contains("Les mer"));
}

@Test
void parseDescriptionReturnsEmptyStringWhenNoSection() {
String html = "<div>No section here</div>";
Document doc = Jsoup.parse(html);
assertEquals("", scraper.parseDescription(doc));
}

@Test
void parseLogoUrlExtractsImageUrl() {
String html = "<div class=\"logo\"><img src=\"/logo.png\"></div>";
Document doc = Jsoup.parse(html);
doc.setBaseUri("https://example.com");
assertTrue(scraper.parseLogoUrl(doc).contains("logo.png"));
}

@Test
void parseLogoUrlReturnsEmptyWhenNoImage() {
String html = "<div class=\"logo\"></div>";
Document doc = Jsoup.parse(html);
assertEquals("", scraper.parseLogoUrl(doc));
}
}
6 changes: 3 additions & 3 deletions src/test/java/edu/group5/app/model/user/UserServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ void registerUserInvalidInputsReturnFalse() {
}

@Test
void registerUserDuplicateEmailAllowedInCurrentCode() {
void registerUserDuplicateEmailNotAllowedInCurrentCode() {
boolean result = service.registerUser("Customer", "John", "Cena",
"john.cena@example.com", "$2a$10$hashed");
assertTrue(result);
assertEquals(3, repo.getUsers().size());
assertFalse(result);
assertEquals(2, repo.getUsers().size());
}

@Test
Expand Down

0 comments on commit 4927aca

Please sign in to comment.