Skip to content

test: Add comprehensive Document class validation and functionality tests #4174

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@

package org.springframework.ai.document;

import java.util.HashMap;
import java.util.Map;

import org.junit.jupiter.api.Test;
import org.springframework.ai.document.id.IdGenerator;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
* @author Christian Tzolov
Expand Down Expand Up @@ -62,4 +67,196 @@ void defaultConfigTextFormatter() {
.isEqualTo(defaultConfigFormatter.format(this.document, MetadataMode.ALL));
}

@Test
void shouldThrowWhenIdIsNull() {
assertThatThrownBy(() -> new Document(null, "text", new HashMap<>()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("id cannot be null or empty");
}

@Test
void shouldThrowWhenIdIsEmpty() {
assertThatThrownBy(() -> new Document("", "text", new HashMap<>())).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("id cannot be null or empty");
}

@Test
void shouldThrowWhenMetadataIsNull() {
assertThatThrownBy(() -> new Document("Sample text", null)).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("metadata cannot be null");
}

@Test
void shouldThrowWhenMetadataHasNullKey() {
Map<String, Object> metadata = new HashMap<>();
metadata.put(null, "value");

assertThatThrownBy(() -> new Document("Sample text", metadata)).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("metadata cannot have null keys");
}

@Test
void shouldThrowWhenMetadataHasNullValue() {
Map<String, Object> metadata = new HashMap<>();
metadata.put("key", null);

assertThatThrownBy(() -> new Document("Sample text", metadata)).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("metadata cannot have null values");
}

@Test
void shouldThrowWhenNeitherTextNorMediaAreSet() {
assertThatThrownBy(() -> Document.builder().id("test-id").metadata("key", "value").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("exactly one of text or media must be specified");
}

@Test
void builderWithCustomIdGenerator() {
IdGenerator mockGenerator = mock(IdGenerator.class);
when(mockGenerator.generateId("test text", Map.of("key", "value"))).thenReturn("generated-id");

Document document = Document.builder()
.idGenerator(mockGenerator)
.text("test text")
.metadata("key", "value")
.build();

assertThat(document.getId()).isEqualTo("generated-id");
}

@Test
void builderShouldThrowWhenIdGeneratorIsNull() {
assertThatThrownBy(() -> Document.builder().idGenerator(null)).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("idGenerator cannot be null");
}

@Test
void builderShouldThrowWhenMetadataKeyIsNull() {
assertThatThrownBy(() -> Document.builder().metadata(null, "value"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("metadata key cannot be null");
}

@Test
void builderShouldThrowWhenMetadataValueIsNull() {
assertThatThrownBy(() -> Document.builder().metadata("key", null)).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("metadata value cannot be null");
}

@Test
void setCustomContentFormatter() {
Document document = new Document("Sample text", Map.of());
ContentFormatter customFormatter = mock(ContentFormatter.class);
when(customFormatter.format(document, MetadataMode.ALL)).thenReturn("Custom formatted content");

document.setContentFormatter(customFormatter);

assertThat(document.getContentFormatter()).isEqualTo(customFormatter);
assertThat(document.getFormattedContent()).isEqualTo("Custom formatted content");
}

@Test
void shouldThrowWhenFormatterIsNull() {
Document document = new Document("Sample text", Map.of());

assertThatThrownBy(() -> document.getFormattedContent(null, MetadataMode.ALL))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("formatter must not be null");
}

@Test
void shouldThrowWhenMetadataModeIsNull() {
Document document = new Document("Sample text", Map.of());

assertThatThrownBy(() -> document.getFormattedContent(null)).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Metadata mode must not be null");
}

@Test
void mutateTextDocument() {
Document original = new Document("id", "original text", Map.of("key", "value"));

Document mutated = original.mutate().text("modified text").metadata("newKey", "newValue").score(0.9).build();

assertThat(mutated.getId()).isEqualTo("id");
assertThat(mutated.getText()).isEqualTo("modified text");
assertThat(mutated.getMetadata()).containsEntry("newKey", "newValue");
assertThat(mutated.getScore()).isEqualTo(0.9);

// Original should be unchanged
assertThat(original.getText()).isEqualTo("original text");
assertThat(original.getScore()).isNull();
}

@Test
void equalDocuments() {
Map<String, Object> metadata = Map.of("key", "value");
Document doc1 = new Document("id", "text", metadata);
Document doc2 = new Document("id", "text", metadata);

assertThat(doc1).isEqualTo(doc2);
assertThat(doc1.hashCode()).isEqualTo(doc2.hashCode());
}

@Test
void differentIds() {
Map<String, Object> metadata = Map.of("key", "value");
Document doc1 = new Document("id1", "text", metadata);
Document doc2 = new Document("id2", "text", metadata);

assertThat(doc1).isNotEqualTo(doc2);
}

@Test
void differentText() {
Map<String, Object> metadata = Map.of("key", "value");
Document doc1 = new Document("id", "text1", metadata);
Document doc2 = new Document("id", "text2", metadata);

assertThat(doc1).isNotEqualTo(doc2);
}

@Test
void isTextReturnsTrueForTextDocument() {
Document document = new Document("Sample text", Map.of());
assertThat(document.isText()).isTrue();
assertThat(document.getText()).isNotNull();
assertThat(document.getMedia()).isNull();
}

@Test
void scoreHandling() {
Document document = Document.builder().text("test").score(0.85).build();

assertThat(document.getScore()).isEqualTo(0.85);

Document documentWithoutScore = new Document("test");
assertThat(documentWithoutScore.getScore()).isNull();
}

@Test
void metadataImmutability() {
Map<String, Object> originalMetadata = new HashMap<>();
originalMetadata.put("key", "value");

Document document = new Document("test", originalMetadata);

// Modify original map
originalMetadata.put("newKey", "newValue");

// Document's metadata should not be affected
assertThat(document.getMetadata()).hasSize(1);
assertThat(document.getMetadata()).containsEntry("key", "value");
assertThat(document.getMetadata()).doesNotContainKey("newKey");
}

@Test
void builderWithMetadataMap() {
Map<String, Object> metadata = Map.of("key1", "value1", "key2", 1);
Document document = Document.builder().text("test").metadata(metadata).build();

assertThat(document.getMetadata()).containsExactlyInAnyOrderEntriesOf(metadata);
}

}