Build-Fehler durch JaCoCo korrigiert und Jenkins-Pipeline gegen
Fehlarchivierung gehärtet
This commit is contained in:
@@ -74,6 +74,16 @@
|
||||
<goals>
|
||||
<goal>report-aggregate</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- The pitest aggregation is conditionally skipped when running
|
||||
in isolation (without upstream modules in the reactor).
|
||||
This module is designed to be run as part of the full multi-module build.
|
||||
In a normal Maven reactor build, all upstream modules execute first,
|
||||
so aggregation data will be available. If this module is run alone
|
||||
(e.g., via -pl), the aggregation will fail silently without breaking
|
||||
the overall build. -->
|
||||
<skip>${pitest.aggregate.skip}</skip>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
package de.gecheckt.pdf.umbenenner.domain.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AiRawResponse} value object.
|
||||
* <p>
|
||||
* Verifies immutability, value semantics, and correct handling of raw AI responses.
|
||||
*/
|
||||
class AiRawResponseTest {
|
||||
|
||||
private static final String VALID_JSON_RESPONSE = "{\"date\": \"2026-03-05\", \"title\": \"Stromabrechnung\", \"reasoning\": \"...\"}";
|
||||
private static final String MALFORMED_JSON = "{invalid json}";
|
||||
private static final String EMPTY_RESPONSE = "";
|
||||
private static final String WHITESPACE_RESPONSE = " ";
|
||||
|
||||
@Test
|
||||
void constructor_createsAiRawResponseWithValidContent() {
|
||||
AiRawResponse response = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
assertNotNull(response);
|
||||
assertEquals(VALID_JSON_RESPONSE, response.content());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsNullPointerExceptionWhenContentIsNull() {
|
||||
assertThrows(NullPointerException.class, () -> new AiRawResponse(null),
|
||||
"Constructor should throw NullPointerException for null content");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsEmptyContent() {
|
||||
AiRawResponse response = new AiRawResponse(EMPTY_RESPONSE);
|
||||
assertEquals(EMPTY_RESPONSE, response.content());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsMalformedJsonContent() {
|
||||
AiRawResponse response = new AiRawResponse(MALFORMED_JSON);
|
||||
assertEquals(MALFORMED_JSON, response.content());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsWhitespaceOnlyContent() {
|
||||
AiRawResponse response = new AiRawResponse(WHITESPACE_RESPONSE);
|
||||
assertEquals(WHITESPACE_RESPONSE, response.content());
|
||||
}
|
||||
|
||||
@Test
|
||||
void content_returnsTheConstructorValue() {
|
||||
AiRawResponse response = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
assertEquals(VALID_JSON_RESPONSE, response.content());
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsTrueForIdenticalContent() {
|
||||
AiRawResponse response1 = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
AiRawResponse response2 = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
assertEquals(response1, response2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseForDifferentContent() {
|
||||
AiRawResponse response1 = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
AiRawResponse response2 = new AiRawResponse(MALFORMED_JSON);
|
||||
assertNotEquals(response1, response2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseWhenComparedWithNull() {
|
||||
AiRawResponse response = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
assertNotEquals(null, response);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseWhenComparedWithDifferentType() {
|
||||
AiRawResponse response = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
assertNotEquals(VALID_JSON_RESPONSE, response);
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashCode_isSameForIdenticalContent() {
|
||||
AiRawResponse response1 = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
AiRawResponse response2 = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
assertEquals(response1.hashCode(), response2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashCode_isDifferentForDifferentContent() {
|
||||
AiRawResponse response1 = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
AiRawResponse response2 = new AiRawResponse(MALFORMED_JSON);
|
||||
assertNotEquals(response1.hashCode(), response2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void toString_containsTheContent() {
|
||||
AiRawResponse response = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
assertTrue(response.toString().contains(VALID_JSON_RESPONSE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void aiRawResponseCanBeUsedAsMapKey() {
|
||||
AiRawResponse response1 = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
AiRawResponse response2 = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
AiRawResponse response3 = new AiRawResponse(MALFORMED_JSON);
|
||||
|
||||
var map = new java.util.HashMap<AiRawResponse, String>();
|
||||
map.put(response1, "first");
|
||||
map.put(response2, "second"); // Should overwrite
|
||||
map.put(response3, "third");
|
||||
|
||||
assertEquals(2, map.size());
|
||||
assertEquals("second", map.get(response1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void aiRawResponseCanBeUsedInSets() {
|
||||
AiRawResponse response1 = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
AiRawResponse response2 = new AiRawResponse(VALID_JSON_RESPONSE);
|
||||
AiRawResponse response3 = new AiRawResponse(MALFORMED_JSON);
|
||||
|
||||
var set = new java.util.HashSet<AiRawResponse>();
|
||||
set.add(response1);
|
||||
set.add(response2); // Should not add duplicate
|
||||
set.add(response3);
|
||||
|
||||
assertEquals(2, set.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_preservesExactContentWithSpecialCharacters() {
|
||||
String contentWithSpecialChars = "{\"text\": \"Special chars: äöü€\\n\\t\"}";
|
||||
AiRawResponse response = new AiRawResponse(contentWithSpecialChars);
|
||||
assertEquals(contentWithSpecialChars, response.content());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_preservesVeryLongContent() {
|
||||
String longContent = "x".repeat(10000);
|
||||
AiRawResponse response = new AiRawResponse(longContent);
|
||||
assertEquals(longContent, response.content());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package de.gecheckt.pdf.umbenenner.domain.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DocumentFingerprint} value object.
|
||||
* <p>
|
||||
* Verifies immutability, value semantics, validation, and correct behavior
|
||||
* as the stable identity for a document based on its content hash.
|
||||
*/
|
||||
class DocumentFingerprintTest {
|
||||
|
||||
private static final String VALID_SHA256 = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
private static final String VALID_SHA256_2 = "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3";
|
||||
private static final String VALID_SHA256_3 = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
|
||||
|
||||
@Test
|
||||
void constructor_createsDocumentFingerprintWithValidSha256() {
|
||||
DocumentFingerprint fingerprint = new DocumentFingerprint(VALID_SHA256);
|
||||
assertNotNull(fingerprint);
|
||||
assertEquals(VALID_SHA256, fingerprint.sha256Hex());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsNullPointerExceptionWhenSha256IsNull() {
|
||||
assertThrows(NullPointerException.class, () -> new DocumentFingerprint(null),
|
||||
"Constructor should throw NullPointerException for null sha256Hex");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsIllegalArgumentExceptionWhenSha256IsTooShort() {
|
||||
String tooShort = "356a192b7913b04c54574d18c28d46e6395428a"; // 39 chars
|
||||
assertThrows(IllegalArgumentException.class, () -> new DocumentFingerprint(tooShort),
|
||||
"Constructor should throw IllegalArgumentException for sha256Hex that is too short");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsIllegalArgumentExceptionWhenSha256IsTooLong() {
|
||||
String tooLong = "356a192b7913b04c54574d18c28d46e6395428abXX"; // 66 chars
|
||||
assertThrows(IllegalArgumentException.class, () -> new DocumentFingerprint(tooLong),
|
||||
"Constructor should throw IllegalArgumentException for sha256Hex that is too long");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsIllegalArgumentExceptionWhenSha256ContainsInvalidCharacters() {
|
||||
String invalid = "356a192b7913b04c54574d18c28d46e6395428ab" + "ZZZZZZZZZZZZZZZZZZZZZZ"; // Has uppercase letters
|
||||
assertThrows(IllegalArgumentException.class, () -> new DocumentFingerprint(invalid),
|
||||
"Constructor should throw IllegalArgumentException for sha256Hex with non-hex characters");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsIllegalArgumentExceptionWhenSha256HasUppercaseLetters() {
|
||||
String uppercase = "356A192B7913B04C54574D18C28D46E6395428AB";
|
||||
assertThrows(IllegalArgumentException.class, () -> new DocumentFingerprint(uppercase),
|
||||
"Constructor should throw IllegalArgumentException for sha256Hex with uppercase letters");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsValidLowercaseHexadecimal() {
|
||||
DocumentFingerprint fingerprint1 = new DocumentFingerprint(VALID_SHA256);
|
||||
DocumentFingerprint fingerprint2 = new DocumentFingerprint(VALID_SHA256_2);
|
||||
DocumentFingerprint fingerprint3 = new DocumentFingerprint(VALID_SHA256_3);
|
||||
|
||||
assertEquals(VALID_SHA256, fingerprint1.sha256Hex());
|
||||
assertEquals(VALID_SHA256_2, fingerprint2.sha256Hex());
|
||||
assertEquals(VALID_SHA256_3, fingerprint3.sha256Hex());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsAllHexDigits() {
|
||||
String allDigits = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
|
||||
DocumentFingerprint fingerprint = new DocumentFingerprint(allDigits);
|
||||
assertEquals(allDigits, fingerprint.sha256Hex());
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsTrueForIdenticalSha256Values() {
|
||||
DocumentFingerprint fingerprint1 = new DocumentFingerprint(VALID_SHA256);
|
||||
DocumentFingerprint fingerprint2 = new DocumentFingerprint(VALID_SHA256);
|
||||
assertEquals(fingerprint1, fingerprint2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseForDifferentSha256Values() {
|
||||
DocumentFingerprint fingerprint1 = new DocumentFingerprint(VALID_SHA256);
|
||||
DocumentFingerprint fingerprint2 = new DocumentFingerprint(VALID_SHA256_2);
|
||||
assertNotEquals(fingerprint1, fingerprint2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseWhenComparedWithNull() {
|
||||
DocumentFingerprint fingerprint = new DocumentFingerprint(VALID_SHA256);
|
||||
assertNotEquals(null, fingerprint);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseWhenComparedWithDifferentType() {
|
||||
DocumentFingerprint fingerprint = new DocumentFingerprint(VALID_SHA256);
|
||||
assertNotEquals(VALID_SHA256, fingerprint);
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashCode_isSameForIdenticalValues() {
|
||||
DocumentFingerprint fingerprint1 = new DocumentFingerprint(VALID_SHA256);
|
||||
DocumentFingerprint fingerprint2 = new DocumentFingerprint(VALID_SHA256);
|
||||
assertEquals(fingerprint1.hashCode(), fingerprint2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashCode_isDifferentForDifferentValues() {
|
||||
DocumentFingerprint fingerprint1 = new DocumentFingerprint(VALID_SHA256);
|
||||
DocumentFingerprint fingerprint2 = new DocumentFingerprint(VALID_SHA256_2);
|
||||
assertNotEquals(fingerprint1.hashCode(), fingerprint2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void toString_containsTheSha256HexValue() {
|
||||
DocumentFingerprint fingerprint = new DocumentFingerprint(VALID_SHA256);
|
||||
assertTrue(fingerprint.toString().contains(VALID_SHA256));
|
||||
}
|
||||
|
||||
@Test
|
||||
void documentFingerprintCanBeUsedAsMapKey() {
|
||||
DocumentFingerprint fingerprint1 = new DocumentFingerprint(VALID_SHA256);
|
||||
DocumentFingerprint fingerprint2 = new DocumentFingerprint(VALID_SHA256);
|
||||
DocumentFingerprint fingerprint3 = new DocumentFingerprint(VALID_SHA256_2);
|
||||
|
||||
var map = new java.util.HashMap<DocumentFingerprint, String>();
|
||||
map.put(fingerprint1, "file1");
|
||||
map.put(fingerprint2, "file2"); // Should overwrite since equal
|
||||
map.put(fingerprint3, "file3");
|
||||
|
||||
assertEquals(2, map.size());
|
||||
assertEquals("file2", map.get(fingerprint1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void documentFingerprintCanBeUsedInSets() {
|
||||
DocumentFingerprint fingerprint1 = new DocumentFingerprint(VALID_SHA256);
|
||||
DocumentFingerprint fingerprint2 = new DocumentFingerprint(VALID_SHA256);
|
||||
DocumentFingerprint fingerprint3 = new DocumentFingerprint(VALID_SHA256_2);
|
||||
|
||||
var set = new java.util.HashSet<DocumentFingerprint>();
|
||||
set.add(fingerprint1);
|
||||
set.add(fingerprint2); // Should not add duplicate
|
||||
set.add(fingerprint3);
|
||||
|
||||
assertEquals(2, set.size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
package de.gecheckt.pdf.umbenenner.domain.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link NamingProposal} value object.
|
||||
* <p>
|
||||
* Verifies immutability, value semantics, and correct validation of naming proposals.
|
||||
*/
|
||||
class NamingProposalTest {
|
||||
|
||||
private static final LocalDate SAMPLE_DATE = LocalDate.of(2026, 3, 31);
|
||||
private static final LocalDate DIFFERENT_DATE = LocalDate.of(2025, 12, 25);
|
||||
private static final String SAMPLE_TITLE = "Stromabrechnung";
|
||||
private static final String DIFFERENT_TITLE = "Gasabrechnung";
|
||||
private static final String SAMPLE_REASONING = "Found electricity bill dated 2026-03-31 in document text.";
|
||||
private static final String EMPTY_REASONING = "";
|
||||
|
||||
@Test
|
||||
void constructor_createsNamingProposalWithValidValues() {
|
||||
NamingProposal proposal = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertNotNull(proposal);
|
||||
assertEquals(SAMPLE_DATE, proposal.resolvedDate());
|
||||
assertEquals(DateSource.AI_PROVIDED, proposal.dateSource());
|
||||
assertEquals(SAMPLE_TITLE, proposal.validatedTitle());
|
||||
assertEquals(SAMPLE_REASONING, proposal.aiReasoning());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsNullPointerExceptionWhenResolvedDateIsNull() {
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> new NamingProposal(null, DateSource.AI_PROVIDED, SAMPLE_TITLE, SAMPLE_REASONING),
|
||||
"Constructor should throw NullPointerException for null resolvedDate");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsNullPointerExceptionWhenDateSourceIsNull() {
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> new NamingProposal(SAMPLE_DATE, null, SAMPLE_TITLE, SAMPLE_REASONING),
|
||||
"Constructor should throw NullPointerException for null dateSource");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsNullPointerExceptionWhenValidatedTitleIsNull() {
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> new NamingProposal(SAMPLE_DATE, DateSource.AI_PROVIDED, null, SAMPLE_REASONING),
|
||||
"Constructor should throw NullPointerException for null validatedTitle");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsIllegalArgumentExceptionWhenValidatedTitleIsEmpty() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new NamingProposal(SAMPLE_DATE, DateSource.AI_PROVIDED, "", SAMPLE_REASONING),
|
||||
"Constructor should throw IllegalArgumentException for empty validatedTitle");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsNullPointerExceptionWhenAiReasoningIsNull() {
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> new NamingProposal(SAMPLE_DATE, DateSource.AI_PROVIDED, SAMPLE_TITLE, null),
|
||||
"Constructor should throw NullPointerException for null aiReasoning");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsEmptyAiReasoning() {
|
||||
NamingProposal proposal = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.FALLBACK_CURRENT,
|
||||
SAMPLE_TITLE,
|
||||
EMPTY_REASONING);
|
||||
|
||||
assertEquals(EMPTY_REASONING, proposal.aiReasoning());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsFallbackCurrentDateSource() {
|
||||
NamingProposal proposal = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.FALLBACK_CURRENT,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertEquals(DateSource.FALLBACK_CURRENT, proposal.dateSource());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolvedDate_returnsTheConstructorValue() {
|
||||
NamingProposal proposal = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertEquals(SAMPLE_DATE, proposal.resolvedDate());
|
||||
}
|
||||
|
||||
@Test
|
||||
void dateSource_returnsTheConstructorValue() {
|
||||
NamingProposal proposal = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.FALLBACK_CURRENT,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertEquals(DateSource.FALLBACK_CURRENT, proposal.dateSource());
|
||||
}
|
||||
|
||||
@Test
|
||||
void validatedTitle_returnsTheConstructorValue() {
|
||||
NamingProposal proposal = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertEquals(SAMPLE_TITLE, proposal.validatedTitle());
|
||||
}
|
||||
|
||||
@Test
|
||||
void aiReasoning_returnsTheConstructorValue() {
|
||||
NamingProposal proposal = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertEquals(SAMPLE_REASONING, proposal.aiReasoning());
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsTrueForIdenticalValues() {
|
||||
NamingProposal proposal1 = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
NamingProposal proposal2 = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertEquals(proposal1, proposal2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseForDifferentDates() {
|
||||
NamingProposal proposal1 = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
NamingProposal proposal2 = new NamingProposal(
|
||||
DIFFERENT_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertNotEquals(proposal1, proposal2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseForDifferentDateSources() {
|
||||
NamingProposal proposal1 = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
NamingProposal proposal2 = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.FALLBACK_CURRENT,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertNotEquals(proposal1, proposal2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseForDifferentTitles() {
|
||||
NamingProposal proposal1 = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
NamingProposal proposal2 = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
DIFFERENT_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertNotEquals(proposal1, proposal2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseForDifferentReasoning() {
|
||||
NamingProposal proposal1 = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
NamingProposal proposal2 = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
"Different reasoning");
|
||||
|
||||
assertNotEquals(proposal1, proposal2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseWhenComparedWithNull() {
|
||||
NamingProposal proposal = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertNotEquals(null, proposal);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseWhenComparedWithDifferentType() {
|
||||
NamingProposal proposal = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertNotEquals(SAMPLE_TITLE, proposal);
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashCode_isSameForIdenticalValues() {
|
||||
NamingProposal proposal1 = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
NamingProposal proposal2 = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertEquals(proposal1.hashCode(), proposal2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashCode_isDifferentForDifferentValues() {
|
||||
NamingProposal proposal1 = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
NamingProposal proposal2 = new NamingProposal(
|
||||
DIFFERENT_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertNotEquals(proposal1.hashCode(), proposal2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void toString_containsAllFields() {
|
||||
NamingProposal proposal = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
SAMPLE_TITLE,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
String str = proposal.toString();
|
||||
assertNotNull(str);
|
||||
assertFalse(str.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsTitleWithSpecialCharacters() {
|
||||
String titleWithUmlauts = "Stromabrechnung Üben";
|
||||
NamingProposal proposal = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
titleWithUmlauts,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertEquals(titleWithUmlauts, proposal.validatedTitle());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsTitleWithSpaces() {
|
||||
String titleWithSpaces = "Rechnung für März";
|
||||
NamingProposal proposal = new NamingProposal(
|
||||
SAMPLE_DATE,
|
||||
DateSource.AI_PROVIDED,
|
||||
titleWithSpaces,
|
||||
SAMPLE_REASONING);
|
||||
|
||||
assertEquals(titleWithSpaces, proposal.validatedTitle());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package de.gecheckt.pdf.umbenenner.domain.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PromptIdentifier} value object.
|
||||
* <p>
|
||||
* Verifies immutability, value semantics, and correct handling of prompt identifiers.
|
||||
*/
|
||||
class PromptIdentifierTest {
|
||||
|
||||
private static final String VALID_IDENTIFIER_1 = "prompt_de_v1.txt";
|
||||
private static final String VALID_IDENTIFIER_2 = "2026-03-v2";
|
||||
private static final String VALID_IDENTIFIER_3 = "sha256:abc123def456";
|
||||
|
||||
@Test
|
||||
void constructor_createsPromptIdentifierWithValidIdentifier() {
|
||||
PromptIdentifier identifier = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
assertNotNull(identifier);
|
||||
assertEquals(VALID_IDENTIFIER_1, identifier.identifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsNullPointerExceptionWhenIdentifierIsNull() {
|
||||
assertThrows(NullPointerException.class, () -> new PromptIdentifier(null),
|
||||
"Constructor should throw NullPointerException for null identifier");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsEmptyIdentifier() {
|
||||
PromptIdentifier identifier = new PromptIdentifier("");
|
||||
assertEquals("", identifier.identifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsVariousIdentifierFormats() {
|
||||
PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_2);
|
||||
PromptIdentifier id3 = new PromptIdentifier(VALID_IDENTIFIER_3);
|
||||
|
||||
assertEquals(VALID_IDENTIFIER_1, id1.identifier());
|
||||
assertEquals(VALID_IDENTIFIER_2, id2.identifier());
|
||||
assertEquals(VALID_IDENTIFIER_3, id3.identifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
void identifier_returnsTheConstructorValue() {
|
||||
PromptIdentifier identifier = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
assertEquals(VALID_IDENTIFIER_1, identifier.identifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsTrueForIdenticalIdentifiers() {
|
||||
PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
assertEquals(id1, id2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseForDifferentIdentifiers() {
|
||||
PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_2);
|
||||
assertNotEquals(id1, id2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseWhenComparedWithNull() {
|
||||
PromptIdentifier identifier = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
assertNotEquals(null, identifier);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseWhenComparedWithDifferentType() {
|
||||
PromptIdentifier identifier = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
assertNotEquals(VALID_IDENTIFIER_1, identifier);
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashCode_isSameForIdenticalIdentifiers() {
|
||||
PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
assertEquals(id1.hashCode(), id2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashCode_isDifferentForDifferentIdentifiers() {
|
||||
PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_2);
|
||||
assertNotEquals(id1.hashCode(), id2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void toString_containsTheIdentifier() {
|
||||
PromptIdentifier identifier = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
assertTrue(identifier.toString().contains(VALID_IDENTIFIER_1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void promptIdentifierCanBeUsedAsMapKey() {
|
||||
PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
PromptIdentifier id3 = new PromptIdentifier(VALID_IDENTIFIER_2);
|
||||
|
||||
var map = new java.util.HashMap<PromptIdentifier, String>();
|
||||
map.put(id1, "first");
|
||||
map.put(id2, "second"); // Should overwrite
|
||||
map.put(id3, "third");
|
||||
|
||||
assertEquals(2, map.size());
|
||||
assertEquals("second", map.get(id1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void promptIdentifierCanBeUsedInSets() {
|
||||
PromptIdentifier id1 = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
PromptIdentifier id2 = new PromptIdentifier(VALID_IDENTIFIER_1);
|
||||
PromptIdentifier id3 = new PromptIdentifier(VALID_IDENTIFIER_2);
|
||||
|
||||
var set = new java.util.HashSet<PromptIdentifier>();
|
||||
set.add(id1);
|
||||
set.add(id2); // Should not add duplicate
|
||||
set.add(id3);
|
||||
|
||||
assertEquals(2, set.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsIdentifierWithSpecialCharacters() {
|
||||
String specialIdentifier = "prompt-de_v1.2.3@stable";
|
||||
PromptIdentifier identifier = new PromptIdentifier(specialIdentifier);
|
||||
assertEquals(specialIdentifier, identifier.identifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsVeryLongIdentifier() {
|
||||
String longIdentifier = "x".repeat(1000);
|
||||
PromptIdentifier identifier = new PromptIdentifier(longIdentifier);
|
||||
assertEquals(longIdentifier, identifier.identifier());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
package de.gecheckt.pdf.umbenenner.domain.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SourceDocumentCandidate} value object.
|
||||
* <p>
|
||||
* Verifies immutability, value semantics, and correct validation of source document candidates.
|
||||
*/
|
||||
class SourceDocumentCandidateTest {
|
||||
|
||||
private static final String VALID_IDENTIFIER = "document.pdf";
|
||||
private static final String VALID_IDENTIFIER_2 = "another_file.PDF";
|
||||
private static final long VALID_FILE_SIZE = 1024L;
|
||||
private static final long ZERO_FILE_SIZE = 0L;
|
||||
private static final String VALID_LOCATOR_VALUE = "/home/user/docs/document.pdf";
|
||||
|
||||
@Test
|
||||
void constructor_createsSourceDocumentCandidateWithValidValues() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentCandidate candidate = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
|
||||
assertNotNull(candidate);
|
||||
assertEquals(VALID_IDENTIFIER, candidate.uniqueIdentifier());
|
||||
assertEquals(VALID_FILE_SIZE, candidate.fileSizeBytes());
|
||||
assertEquals(locator, candidate.locator());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsNullPointerExceptionWhenUniqueIdentifierIsNull() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> new SourceDocumentCandidate(null, VALID_FILE_SIZE, locator),
|
||||
"Constructor should throw NullPointerException for null uniqueIdentifier");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsIllegalArgumentExceptionWhenUniqueIdentifierIsEmpty() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new SourceDocumentCandidate("", VALID_FILE_SIZE, locator),
|
||||
"Constructor should throw IllegalArgumentException for empty uniqueIdentifier");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsIllegalArgumentExceptionWhenFileSizeIsNegative() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new SourceDocumentCandidate(VALID_IDENTIFIER, -1L, locator),
|
||||
"Constructor should throw IllegalArgumentException for negative fileSizeBytes");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsNullPointerExceptionWhenLocatorIsNull() {
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> new SourceDocumentCandidate(VALID_IDENTIFIER, VALID_FILE_SIZE, null),
|
||||
"Constructor should throw NullPointerException for null locator");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsZeroFileSize() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentCandidate candidate = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
ZERO_FILE_SIZE,
|
||||
locator);
|
||||
|
||||
assertEquals(ZERO_FILE_SIZE, candidate.fileSizeBytes());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsVeryLargeFileSize() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
long largeSize = Long.MAX_VALUE;
|
||||
SourceDocumentCandidate candidate = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
largeSize,
|
||||
locator);
|
||||
|
||||
assertEquals(largeSize, candidate.fileSizeBytes());
|
||||
}
|
||||
|
||||
@Test
|
||||
void uniqueIdentifier_returnsTheConstructorValue() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentCandidate candidate = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
|
||||
assertEquals(VALID_IDENTIFIER, candidate.uniqueIdentifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
void fileSizeBytes_returnsTheConstructorValue() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentCandidate candidate = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
|
||||
assertEquals(VALID_FILE_SIZE, candidate.fileSizeBytes());
|
||||
}
|
||||
|
||||
@Test
|
||||
void locator_returnsTheConstructorValue() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentCandidate candidate = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
|
||||
assertEquals(locator, candidate.locator());
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsTrueForIdenticalValues() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentCandidate candidate1 = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
SourceDocumentCandidate candidate2 = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
|
||||
assertEquals(candidate1, candidate2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseForDifferentUniqueIdentifiers() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentCandidate candidate1 = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
SourceDocumentCandidate candidate2 = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER_2,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
|
||||
assertNotEquals(candidate1, candidate2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseForDifferentFileSizes() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentCandidate candidate1 = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
SourceDocumentCandidate candidate2 = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
2048L,
|
||||
locator);
|
||||
|
||||
assertNotEquals(candidate1, candidate2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseForDifferentLocators() {
|
||||
SourceDocumentLocator locator1 = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentLocator locator2 = new SourceDocumentLocator("/other/path/document.pdf");
|
||||
SourceDocumentCandidate candidate1 = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator1);
|
||||
SourceDocumentCandidate candidate2 = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator2);
|
||||
|
||||
assertNotEquals(candidate1, candidate2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseWhenComparedWithNull() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentCandidate candidate = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
|
||||
assertNotEquals(null, candidate);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseWhenComparedWithDifferentType() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentCandidate candidate = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
|
||||
assertNotEquals(VALID_IDENTIFIER, candidate);
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashCode_isSameForIdenticalValues() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentCandidate candidate1 = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
SourceDocumentCandidate candidate2 = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
|
||||
assertEquals(candidate1.hashCode(), candidate2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashCode_isDifferentForDifferentValues() {
|
||||
SourceDocumentLocator locator1 = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentLocator locator2 = new SourceDocumentLocator("/other/path/document.pdf");
|
||||
SourceDocumentCandidate candidate1 = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator1);
|
||||
SourceDocumentCandidate candidate2 = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator2);
|
||||
|
||||
assertNotEquals(candidate1.hashCode(), candidate2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void toString_containsAllFields() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentCandidate candidate = new SourceDocumentCandidate(
|
||||
VALID_IDENTIFIER,
|
||||
VALID_FILE_SIZE,
|
||||
locator);
|
||||
|
||||
String str = candidate.toString();
|
||||
assertNotNull(str);
|
||||
assertFalse(str.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void sourceDocumentCandidateCanBeUsedInCollections() {
|
||||
SourceDocumentLocator locator1 = new SourceDocumentLocator(VALID_LOCATOR_VALUE);
|
||||
SourceDocumentLocator locator2 = new SourceDocumentLocator("/other/path/document.pdf");
|
||||
|
||||
SourceDocumentCandidate candidate1 = new SourceDocumentCandidate(VALID_IDENTIFIER, VALID_FILE_SIZE, locator1);
|
||||
SourceDocumentCandidate candidate2 = new SourceDocumentCandidate(VALID_IDENTIFIER, VALID_FILE_SIZE, locator1);
|
||||
SourceDocumentCandidate candidate3 = new SourceDocumentCandidate(VALID_IDENTIFIER_2, VALID_FILE_SIZE, locator2);
|
||||
|
||||
var set = new java.util.HashSet<SourceDocumentCandidate>();
|
||||
set.add(candidate1);
|
||||
set.add(candidate2); // Should not add duplicate
|
||||
set.add(candidate3);
|
||||
|
||||
assertEquals(2, set.size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package de.gecheckt.pdf.umbenenner.domain.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SourceDocumentLocator} value object.
|
||||
* <p>
|
||||
* Verifies immutability, value semantics, and validation of the opaque document locator.
|
||||
*/
|
||||
class SourceDocumentLocatorTest {
|
||||
|
||||
private static final String VALID_LOCATOR = "C:\\Users\\test\\documents\\file.pdf";
|
||||
private static final String VALID_LOCATOR_2 = "/home/user/documents/another.pdf";
|
||||
private static final String VALID_LOCATOR_3 = "relative/path/to/document.pdf";
|
||||
|
||||
@Test
|
||||
void constructor_createsSourceDocumentLocatorWithValidValue() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
assertNotNull(locator);
|
||||
assertEquals(VALID_LOCATOR, locator.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsNullPointerExceptionWhenValueIsNull() {
|
||||
assertThrows(NullPointerException.class, () -> new SourceDocumentLocator(null),
|
||||
"Constructor should throw NullPointerException for null value");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_throwsIllegalArgumentExceptionWhenValueIsEmpty() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new SourceDocumentLocator(""),
|
||||
"Constructor should throw IllegalArgumentException for empty value");
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsValidPaths() {
|
||||
SourceDocumentLocator locator1 = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
SourceDocumentLocator locator2 = new SourceDocumentLocator(VALID_LOCATOR_2);
|
||||
SourceDocumentLocator locator3 = new SourceDocumentLocator(VALID_LOCATOR_3);
|
||||
|
||||
assertEquals(VALID_LOCATOR, locator1.value());
|
||||
assertEquals(VALID_LOCATOR_2, locator2.value());
|
||||
assertEquals(VALID_LOCATOR_3, locator3.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsOpaqueValue() {
|
||||
// The locator is intentionally opaque - it can contain any non-empty string
|
||||
String opaqueValue = "adapter-internal-encoding:12345:abcdef";
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(opaqueValue);
|
||||
assertEquals(opaqueValue, locator.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void value_returnsTheConstructorValue() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
assertEquals(VALID_LOCATOR, locator.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsTrueForIdenticalValues() {
|
||||
SourceDocumentLocator locator1 = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
SourceDocumentLocator locator2 = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
assertEquals(locator1, locator2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseForDifferentValues() {
|
||||
SourceDocumentLocator locator1 = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
SourceDocumentLocator locator2 = new SourceDocumentLocator(VALID_LOCATOR_2);
|
||||
assertNotEquals(locator1, locator2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseWhenComparedWithNull() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
assertNotEquals(null, locator);
|
||||
}
|
||||
|
||||
@Test
|
||||
void equals_returnsFalseWhenComparedWithDifferentType() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
assertNotEquals(VALID_LOCATOR, locator);
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashCode_isSameForIdenticalValues() {
|
||||
SourceDocumentLocator locator1 = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
SourceDocumentLocator locator2 = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
assertEquals(locator1.hashCode(), locator2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashCode_isDifferentForDifferentValues() {
|
||||
SourceDocumentLocator locator1 = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
SourceDocumentLocator locator2 = new SourceDocumentLocator(VALID_LOCATOR_2);
|
||||
assertNotEquals(locator1.hashCode(), locator2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void toString_containsTheValue() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
assertTrue(locator.toString().contains(VALID_LOCATOR));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sourceDocumentLocatorCanBeUsedAsMapKey() {
|
||||
SourceDocumentLocator locator1 = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
SourceDocumentLocator locator2 = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
SourceDocumentLocator locator3 = new SourceDocumentLocator(VALID_LOCATOR_2);
|
||||
|
||||
var map = new java.util.HashMap<SourceDocumentLocator, String>();
|
||||
map.put(locator1, "file1");
|
||||
map.put(locator2, "file2"); // Should overwrite
|
||||
map.put(locator3, "file3");
|
||||
|
||||
assertEquals(2, map.size());
|
||||
assertEquals("file2", map.get(locator1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sourceDocumentLocatorCanBeUsedInSets() {
|
||||
SourceDocumentLocator locator1 = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
SourceDocumentLocator locator2 = new SourceDocumentLocator(VALID_LOCATOR);
|
||||
SourceDocumentLocator locator3 = new SourceDocumentLocator(VALID_LOCATOR_2);
|
||||
|
||||
var set = new java.util.HashSet<SourceDocumentLocator>();
|
||||
set.add(locator1);
|
||||
set.add(locator2); // Should not add duplicate
|
||||
set.add(locator3);
|
||||
|
||||
assertEquals(2, set.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsWhitespaceInValue() {
|
||||
String valueWithWhitespace = "path with spaces/to/file.pdf";
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator(valueWithWhitespace);
|
||||
assertEquals(valueWithWhitespace, locator.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructor_acceptsSingleCharacterValue() {
|
||||
SourceDocumentLocator locator = new SourceDocumentLocator("a");
|
||||
assertEquals("a", locator.value());
|
||||
}
|
||||
}
|
||||
5
pom.xml
5
pom.xml
@@ -19,6 +19,11 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.release>21</maven.compiler.release>
|
||||
|
||||
<!-- Build and reporting configuration -->
|
||||
<!-- PIT aggregation skip flag: set to true when running coverage module in isolation,
|
||||
false (default) when running as part of the full multi-module build. -->
|
||||
<pitest.aggregate.skip>false</pitest.aggregate.skip>
|
||||
|
||||
<!-- Library versions -->
|
||||
<log4j.version>2.23.1</log4j.version>
|
||||
<pdfbox.version>3.0.2</pdfbox.version>
|
||||
|
||||
Reference in New Issue
Block a user