From 06ea88312a1788734aed849da6f8a5050dee8dce Mon Sep 17 00:00:00 2001 From: Mark Pollack Date: Thu, 8 May 2025 12:46:06 -0400 Subject: [PATCH] Improve support for running tests on windows Signed-off-by: szarpul@users.noreply.github.com Signed-off-by: Mark Pollack --- .../ai/document/ContentFormatterTests.java | 21 +-- .../ai/document/TextBlockAssertion.java | 54 ++++++++ .../ai/converter/BeanOutputConverterTest.java | 122 +++++++++--------- .../ai/util/TextBlockAssertion.java | 54 ++++++++ 4 files changed, 182 insertions(+), 69 deletions(-) create mode 100644 spring-ai-commons/src/test/java/org/springframework/ai/document/TextBlockAssertion.java create mode 100644 spring-ai-model/src/test/java/org/springframework/ai/util/TextBlockAssertion.java diff --git a/spring-ai-commons/src/test/java/org/springframework/ai/document/ContentFormatterTests.java b/spring-ai-commons/src/test/java/org/springframework/ai/document/ContentFormatterTests.java index e71daba9a..3cc4e0a94 100644 --- a/spring-ai-commons/src/test/java/org/springframework/ai/document/ContentFormatterTests.java +++ b/spring-ai-commons/src/test/java/org/springframework/ai/document/ContentFormatterTests.java @@ -25,14 +25,14 @@ import static org.assertj.core.api.Assertions.assertThat; /** * @author Christian Tzolov */ -public class ContentFormatterTests { +class ContentFormatterTests { Document document = new Document("The World is Big and Salvation Lurks Around the Corner", Map.of("embedKey1", "value1", "embedKey2", "value2", "embedKey3", "value3", "llmKey2", "value4")); @Test - public void noExplicitlySetFormatter() { - assertThat(this.document.getText()).isEqualTo(""" + void noExplicitlySetFormatter() { + TextBlockAssertion.assertThat(this.document.getText()).isEqualTo(""" The World is Big and Salvation Lurks Around the Corner"""); assertThat(this.document.getFormattedContent()).isEqualTo(this.document.getFormattedContent(MetadataMode.ALL)); @@ -42,17 +42,18 @@ public class ContentFormatterTests { } @Test - public void defaultConfigTextFormatter() { + void defaultConfigTextFormatter() { DefaultContentFormatter defaultConfigFormatter = DefaultContentFormatter.defaultConfig(); - assertThat(this.document.getFormattedContent(defaultConfigFormatter, MetadataMode.ALL)).isEqualTo(""" - llmKey2: value4 - embedKey1: value1 - embedKey2: value2 - embedKey3: value3 + TextBlockAssertion.assertThat(this.document.getFormattedContent(defaultConfigFormatter, MetadataMode.ALL)) + .isEqualTo(""" + llmKey2: value4 + embedKey1: value1 + embedKey2: value2 + embedKey3: value3 - The World is Big and Salvation Lurks Around the Corner"""); + The World is Big and Salvation Lurks Around the Corner"""); assertThat(this.document.getFormattedContent(defaultConfigFormatter, MetadataMode.ALL)) .isEqualTo(this.document.getFormattedContent()); diff --git a/spring-ai-commons/src/test/java/org/springframework/ai/document/TextBlockAssertion.java b/spring-ai-commons/src/test/java/org/springframework/ai/document/TextBlockAssertion.java new file mode 100644 index 000000000..d85721426 --- /dev/null +++ b/spring-ai-commons/src/test/java/org/springframework/ai/document/TextBlockAssertion.java @@ -0,0 +1,54 @@ +/* + * Copyright 2024-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.document; + +import java.util.Arrays; + +import org.assertj.core.api.AbstractCharSequenceAssert; +import org.assertj.core.api.Assertions; + +public class TextBlockAssertion extends AbstractCharSequenceAssert { + + protected TextBlockAssertion(String string) { + super(string, TextBlockAssertion.class); + } + + public static TextBlockAssertion assertThat(String actual) { + return new TextBlockAssertion(actual); + } + + @Override + public TextBlockAssertion isEqualTo(Object expected) { + Assertions.assertThat(normalizedEOL(actual)).isEqualTo(normalizedEOL((String) expected)); + return this; + } + + @Override + public TextBlockAssertion contains(CharSequence... values) { + Assertions.assertThat(normalizedEOL(actual)).contains(normalizedEOL(values)); + return this; + } + + private String normalizedEOL(CharSequence... values) { + return Arrays.stream(values).map(CharSequence::toString).map(this::normalizedEOL).reduce("", (a, b) -> a + b); + } + + private String normalizedEOL(String line) { + return line.replaceAll("\r\n|\r|\n", System.lineSeparator()); + } + +} diff --git a/spring-ai-model/src/test/java/org/springframework/ai/converter/BeanOutputConverterTest.java b/spring-ai-model/src/test/java/org/springframework/ai/converter/BeanOutputConverterTest.java index b136ded49..498d07820 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/converter/BeanOutputConverterTest.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/converter/BeanOutputConverterTest.java @@ -38,6 +38,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.slf4j.LoggerFactory; +import org.springframework.ai.util.TextBlockAssertion; import org.springframework.core.ParameterizedTypeReference; import static org.assertj.core.api.Assertions.assertThat; @@ -246,24 +247,25 @@ class BeanOutputConverterTest { @Test void formatClassType() { var converter = new BeanOutputConverter<>(TestClass.class); - assertThat(converter.getFormat()).isEqualTo( - """ - Your response should be in JSON format. - Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation. - Do not include markdown code blocks in your response. - Remove the ```json markdown from the output. - Here is the JSON Schema instance your output must adhere to: - ```{ - "$schema" : "https://json-schema.org/draft/2020-12/schema", - "type" : "object", - "properties" : { - "someString" : { - "type" : "string" - } - }, - "additionalProperties" : false - }``` - """); + TextBlockAssertion.assertThat(converter.getFormat()) + .isEqualTo( + """ + Your response should be in JSON format. + Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation. + Do not include markdown code blocks in your response. + Remove the ```json markdown from the output. + Here is the JSON Schema instance your output must adhere to: + ```{ + "$schema" : "https://json-schema.org/draft/2020-12/schema", + "type" : "object", + "properties" : { + "someString" : { + "type" : "string" + } + }, + "additionalProperties" : false + }``` + """); } @Test @@ -271,24 +273,25 @@ class BeanOutputConverterTest { var converter = new BeanOutputConverter<>(new ParameterizedTypeReference() { }); - assertThat(converter.getFormat()).isEqualTo( - """ - Your response should be in JSON format. - Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation. - Do not include markdown code blocks in your response. - Remove the ```json markdown from the output. - Here is the JSON Schema instance your output must adhere to: - ```{ - "$schema" : "https://json-schema.org/draft/2020-12/schema", - "type" : "object", - "properties" : { - "someString" : { - "type" : "string" - } - }, - "additionalProperties" : false - }``` - """); + TextBlockAssertion.assertThat(converter.getFormat()) + .isEqualTo( + """ + Your response should be in JSON format. + Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation. + Do not include markdown code blocks in your response. + Remove the ```json markdown from the output. + Here is the JSON Schema instance your output must adhere to: + ```{ + "$schema" : "https://json-schema.org/draft/2020-12/schema", + "type" : "object", + "properties" : { + "someString" : { + "type" : "string" + } + }, + "additionalProperties" : false + }``` + """); } @Test @@ -296,33 +299,34 @@ class BeanOutputConverterTest { var converter = new BeanOutputConverter<>(new ParameterizedTypeReference>() { }); - assertThat(converter.getFormat()).isEqualTo( - """ - Your response should be in JSON format. - Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation. - Do not include markdown code blocks in your response. - Remove the ```json markdown from the output. - Here is the JSON Schema instance your output must adhere to: - ```{ - "$schema" : "https://json-schema.org/draft/2020-12/schema", - "type" : "array", - "items" : { - "type" : "object", - "properties" : { - "someString" : { - "type" : "string" - } - }, - "additionalProperties" : false - } - }``` - """); + TextBlockAssertion.assertThat(converter.getFormat()) + .isEqualTo( + """ + Your response should be in JSON format. + Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation. + Do not include markdown code blocks in your response. + Remove the ```json markdown from the output. + Here is the JSON Schema instance your output must adhere to: + ```{ + "$schema" : "https://json-schema.org/draft/2020-12/schema", + "type" : "array", + "items" : { + "type" : "object", + "properties" : { + "someString" : { + "type" : "string" + } + }, + "additionalProperties" : false + } + }``` + """); } @Test void formatClassTypeWithAnnotations() { var converter = new BeanOutputConverter<>(TestClassWithJsonAnnotations.class); - assertThat(converter.getFormat()).contains(""" + TextBlockAssertion.assertThat(converter.getFormat()).contains(""" ```{ "$schema" : "https://json-schema.org/draft/2020-12/schema", "type" : "object", @@ -342,7 +346,7 @@ class BeanOutputConverterTest { var converter = new BeanOutputConverter<>(new ParameterizedTypeReference() { }); - assertThat(converter.getFormat()).contains(""" + TextBlockAssertion.assertThat(converter.getFormat()).contains(""" ```{ "$schema" : "https://json-schema.org/draft/2020-12/schema", "type" : "object", diff --git a/spring-ai-model/src/test/java/org/springframework/ai/util/TextBlockAssertion.java b/spring-ai-model/src/test/java/org/springframework/ai/util/TextBlockAssertion.java new file mode 100644 index 000000000..7d6312142 --- /dev/null +++ b/spring-ai-model/src/test/java/org/springframework/ai/util/TextBlockAssertion.java @@ -0,0 +1,54 @@ +/* + * Copyright 2024-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.util; + +import java.util.Arrays; + +import org.assertj.core.api.AbstractCharSequenceAssert; +import org.assertj.core.api.Assertions; + +public class TextBlockAssertion extends AbstractCharSequenceAssert { + + protected TextBlockAssertion(String string) { + super(string, TextBlockAssertion.class); + } + + public static TextBlockAssertion assertThat(String actual) { + return new TextBlockAssertion(actual); + } + + @Override + public TextBlockAssertion isEqualTo(Object expected) { + Assertions.assertThat(normalizedEOL(actual)).isEqualTo(normalizedEOL((String) expected)); + return this; + } + + @Override + public TextBlockAssertion contains(CharSequence... values) { + Assertions.assertThat(normalizedEOL(actual)).contains(normalizedEOL(values)); + return this; + } + + private String normalizedEOL(CharSequence... values) { + return Arrays.stream(values).map(CharSequence::toString).map(this::normalizedEOL).reduce("", (a, b) -> a + b); + } + + private String normalizedEOL(String line) { + return line.replaceAll("\r\n|\r|\n", System.lineSeparator()); + } + +}