diff --git a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/client/AnthropicChatClientMethodFunctionCallbackIT.java b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/client/AnthropicChatClientMethodFunctionCallbackIT.java index d0ac06c50..cf8688cb8 100644 --- a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/client/AnthropicChatClientMethodFunctionCallbackIT.java +++ b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/client/AnthropicChatClientMethodFunctionCallbackIT.java @@ -36,7 +36,7 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.util.ReflectionUtils; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertThrows; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; @SpringBootTest(classes = AnthropicTestConfiguration.class, properties = "spring.ai.retry.on-http-codes=429") @EnabledIfEnvironmentVariable(named = "ANTHROPIC_API_KEY", matches = ".+") @@ -47,6 +47,156 @@ class AnthropicChatClientMethodFunctionCallbackIT { public static Map arguments = new ConcurrentHashMap<>(); + @BeforeEach + void beforeEach() { + arguments.clear(); + } + + @Test + void methodGetWeatherStatic() { + + var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherStatic", String.class, Unit.class); + // @formatter:off + String response = ChatClient.create(this.chatModel).prompt() + .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") + .functions(MethodFunctionCallback.builder() + .method(method) + .description("Get the weather in location") + .build()) + .call() + .content(); + // @formatter:on + + logger.info("Response: {}", response); + + assertThat(response).contains("30", "10", "15"); + } + + @Test + void methodTurnLightNoResponse() { + + TestFunctionClass targetObject = new TestFunctionClass(); + + var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLight", String.class, boolean.class); + + // @formatter:off + String response = ChatClient.create(this.chatModel).prompt() + .user("Turn light on in the living room.") + .functions(MethodFunctionCallback.builder() + .functionObject(targetObject) + .method(method) + .description("Can turn lights on or off by room name") + .build()) + .call() + .content(); + // @formatter:on + + logger.info("Response: {}", response); + + assertThat(arguments).containsEntry("roomName", "living room"); + assertThat(arguments).containsEntry("on", true); + } + + @Test + void methodGetWeatherNonStatic() { + + TestFunctionClass targetObject = new TestFunctionClass(); + + var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class, + Unit.class); + + // @formatter:off + String response = ChatClient.create(this.chatModel).prompt() + .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") + .functions(MethodFunctionCallback.builder() + .functionObject(targetObject) + .method(method) + .description("Get the weather in location") + .build()) + .call() + .content(); + // @formatter:on + + logger.info("Response: {}", response); + + assertThat(response).contains("30", "10", "15"); + } + + @Test + void methodGetWeatherToolContext() { + + TestFunctionClass targetObject = new TestFunctionClass(); + + var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherWithContext", String.class, + Unit.class, ToolContext.class); + + // @formatter:off + String response = ChatClient.create(this.chatModel).prompt() + .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") + .functions(MethodFunctionCallback.builder() + .functionObject(targetObject) + .method(method) + .description("Get the weather in location") + .build()) + .toolContext(Map.of("tool", "value")) + .call() + .content(); + // @formatter:on + + logger.info("Response: {}", response); + + assertThat(response).contains("30", "10", "15"); + assertThat(arguments).containsEntry("tool", "value"); + } + + @Test + void methodGetWeatherToolContextButNonContextMethod() { + + TestFunctionClass targetObject = new TestFunctionClass(); + + var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class, + Unit.class); + + // @formatter:off + assertThatThrownBy(() -> ChatClient.create(this.chatModel).prompt() + .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") + .functions(MethodFunctionCallback.builder() + .functionObject(targetObject) + .method(method) + .description("Get the weather in location") + .build()) + .toolContext(Map.of("tool", "value")) + .call() + .content()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Configured method does not accept ToolContext as input parameter!"); + // @formatter:on + } + + @Test + void methodNoParameters() { + + TestFunctionClass targetObject = new TestFunctionClass(); + + var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLivingRoomLightOn"); + + // @formatter:off + String response = ChatClient.create(this.chatModel).prompt() + .user("Turn light on in the living room.") + .functions(MethodFunctionCallback.builder() + .functionObject(targetObject) + .method(method) + .description("Can turn lights on in the Living Room") + .build()) + .call() + .content(); + // @formatter:on + + logger.info("Response: {}", response); + + assertThat(arguments).containsEntry("turnLivingRoomLightOn", true); + } + @Autowired ChatModel chatModel; @@ -107,154 +257,4 @@ class AnthropicChatClientMethodFunctionCallbackIT { } - @BeforeEach - void beforeEach() { - arguments.clear(); - } - - @Test - void methodGetWeatherStatic() { - - var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherStatic", String.class, Unit.class); - // @formatter:off - String response = ChatClient.create(this.chatModel).prompt() - .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") - .functions(MethodFunctionCallback.builder() - .method(method) - .description("Get the weather in location") - .build()) - .call() - .content(); - // @formatter:on - - logger.info("Response: {}", response); - - assertThat(response).contains("30", "10", "15"); - } - - @Test - void methodTurnLightNoResponse() { - - TestFunctionClass targetObject = new TestFunctionClass(); - - var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLight", String.class, boolean.class); - - // @formatter:off - String response = ChatClient.create(this.chatModel).prompt() - .user("Turn light on in the living room.") - .functions(MethodFunctionCallback.builder() - .functionObject(targetObject) - .method(method) - .description("Can turn lights on or off by room name") - .build()) - .call() - .content(); - // @formatter:on - - logger.info("Response: {}", response); - - assertThat(arguments).containsEntry("roomName", "living room"); - assertThat(arguments).containsEntry("on", true); - } - - @Test - void methodGetWeatherNonStatic() { - - TestFunctionClass targetObject = new TestFunctionClass(); - - var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class, - Unit.class); - - // @formatter:off - String response = ChatClient.create(this.chatModel).prompt() - .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") - .functions(MethodFunctionCallback.builder() - .functionObject(targetObject) - .method(method) - .description("Get the weather in location") - .build()) - .call() - .content(); - // @formatter:on - - logger.info("Response: {}", response); - - assertThat(response).contains("30", "10", "15"); - } - - @Test - void methodGetWeatherToolContext() { - - TestFunctionClass targetObject = new TestFunctionClass(); - - var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherWithContext", String.class, - Unit.class, ToolContext.class); - - // @formatter:off - String response = ChatClient.create(this.chatModel).prompt() - .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") - .functions(MethodFunctionCallback.builder() - .functionObject(targetObject) - .method(method) - .description("Get the weather in location") - .build()) - .toolContext(Map.of("tool", "value")) - .call() - .content(); - // @formatter:on - - logger.info("Response: {}", response); - - assertThat(response).contains("30", "10", "15"); - assertThat(arguments).containsEntry("tool", "value"); - } - - @Test - void methodGetWeatherToolContextButNonContextMethod() { - - TestFunctionClass targetObject = new TestFunctionClass(); - - var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class, - Unit.class); - - // @formatter:off - assertThrows("Configured method does not accept ToolContext as input parameter!",IllegalArgumentException.class, () -> { - ChatClient.create(this.chatModel).prompt() - .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") - .functions(MethodFunctionCallback.builder() - .functionObject(targetObject) - .method(method) - .description("Get the weather in location") - .build()) - .toolContext(Map.of("tool", "value")) - .call() - .content(); - }); - // @formatter:on - } - - @Test - void methodNoParameters() { - - TestFunctionClass targetObject = new TestFunctionClass(); - - var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLivingRoomLightOn"); - - // @formatter:off - String response = ChatClient.create(this.chatModel).prompt() - .user("Turn light on in the living room.") - .functions(MethodFunctionCallback.builder() - .functionObject(targetObject) - .method(method) - .description("Can turn lights on in the Living Room") - .build()) - .call() - .content(); - // @formatter:on - - logger.info("Response: {}", response); - - assertThat(arguments).containsEntry("turnLivingRoomLightOn", true); - } - } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMethodFunctionCallbackIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMethodFunctionCallbackIT.java index 9537ac593..feed9add8 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMethodFunctionCallbackIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/client/OpenAiChatClientMethodFunctionCallbackIT.java @@ -36,7 +36,7 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.util.ReflectionUtils; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertThrows; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; @SpringBootTest(classes = OpenAiTestConfiguration.class) @EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".+") @@ -50,6 +50,156 @@ class OpenAiChatClientMethodFunctionCallbackIT { @Autowired ChatModel chatModel; + @BeforeEach + void beforeEach() { + arguments.clear(); + } + + @Test + void methodGetWeatherStatic() { + + var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherStatic", String.class, Unit.class); + // @formatter:off + String response = ChatClient.create(this.chatModel).prompt() + .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") + .functions(MethodFunctionCallback.builder() + .method(method) + .description("Get the weather in location") + .build()) + .call() + .content(); + // @formatter:on + + logger.info("Response: {}", response); + + assertThat(response).contains("30", "10", "15"); + } + + @Test + void methodTurnLightNoResponse() { + + TestFunctionClass targetObject = new TestFunctionClass(); + + var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLight", String.class, boolean.class); + + // @formatter:off + String response = ChatClient.create(this.chatModel).prompt() + .user("Turn light on in the living room.") + .functions(MethodFunctionCallback.builder() + .functionObject(targetObject) + .method(method) + .description("Can turn lights on or off by room name") + .build()) + .call() + .content(); + // @formatter:on + + logger.info("Response: {}", response); + + assertThat(arguments).containsEntry("roomName", "living room"); + assertThat(arguments).containsEntry("on", true); + } + + @Test + void methodGetWeatherNonStatic() { + + TestFunctionClass targetObject = new TestFunctionClass(); + + var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class, + Unit.class); + + // @formatter:off + String response = ChatClient.create(this.chatModel).prompt() + .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") + .functions(MethodFunctionCallback.builder() + .functionObject(targetObject) + .method(method) + .description("Get the weather in location") + .build()) + .call() + .content(); + // @formatter:on + + logger.info("Response: {}", response); + + assertThat(response).contains("30", "10", "15"); + } + + @Test + void methodGetWeatherToolContext() { + + TestFunctionClass targetObject = new TestFunctionClass(); + + var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherWithContext", String.class, + Unit.class, ToolContext.class); + + // @formatter:off + String response = ChatClient.create(this.chatModel).prompt() + .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") + .functions(MethodFunctionCallback.builder() + .functionObject(targetObject) + .method(method) + .description("Get the weather in location") + .build()) + .toolContext(Map.of("tool", "value")) + .call() + .content(); + // @formatter:on + + logger.info("Response: {}", response); + + assertThat(response).contains("30", "10", "15"); + assertThat(arguments).containsEntry("tool", "value"); + } + + @Test + void methodGetWeatherToolContextButNonContextMethod() { + + TestFunctionClass targetObject = new TestFunctionClass(); + + var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class, + Unit.class); + + // @formatter:off + assertThatThrownBy(() -> ChatClient.create(this.chatModel).prompt() + .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") + .functions(MethodFunctionCallback.builder() + .functionObject(targetObject) + .method(method) + .description("Get the weather in location") + .build()) + .toolContext(Map.of("tool", "value")) + .call() + .content()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Configured method does not accept ToolContext as input parameter!"); + // @formatter:on + } + + @Test + void methodNoParameters() { + + TestFunctionClass targetObject = new TestFunctionClass(); + + var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLivingRoomLightOn"); + + // @formatter:off + String response = ChatClient.create(this.chatModel).prompt() + .user("Turn light on in the living room.") + .functions(MethodFunctionCallback.builder() + .functionObject(targetObject) + .method(method) + .description("Can turn lights on in the Living Room") + .build()) + .call() + .content(); + // @formatter:on + + logger.info("Response: {}", response); + + assertThat(arguments).containsEntry("turnLivingRoomLightOn", true); + } + record MyRecord(String foo, String bar) { } @@ -107,154 +257,4 @@ class OpenAiChatClientMethodFunctionCallbackIT { } - @BeforeEach - void beforeEach() { - arguments.clear(); - } - - @Test - void methodGetWeatherStatic() { - - var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherStatic", String.class, Unit.class); - // @formatter:off - String response = ChatClient.create(this.chatModel).prompt() - .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") - .functions(MethodFunctionCallback.builder() - .method(method) - .description("Get the weather in location") - .build()) - .call() - .content(); - // @formatter:on - - logger.info("Response: {}", response); - - assertThat(response).contains("30", "10", "15"); - } - - @Test - void methodTurnLightNoResponse() { - - TestFunctionClass targetObject = new TestFunctionClass(); - - var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLight", String.class, boolean.class); - - // @formatter:off - String response = ChatClient.create(this.chatModel).prompt() - .user("Turn light on in the living room.") - .functions(MethodFunctionCallback.builder() - .functionObject(targetObject) - .method(method) - .description("Can turn lights on or off by room name") - .build()) - .call() - .content(); - // @formatter:on - - logger.info("Response: {}", response); - - assertThat(arguments).containsEntry("roomName", "living room"); - assertThat(arguments).containsEntry("on", true); - } - - @Test - void methodGetWeatherNonStatic() { - - TestFunctionClass targetObject = new TestFunctionClass(); - - var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class, - Unit.class); - - // @formatter:off - String response = ChatClient.create(this.chatModel).prompt() - .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") - .functions(MethodFunctionCallback.builder() - .functionObject(targetObject) - .method(method) - .description("Get the weather in location") - .build()) - .call() - .content(); - // @formatter:on - - logger.info("Response: {}", response); - - assertThat(response).contains("30", "10", "15"); - } - - @Test - void methodGetWeatherToolContext() { - - TestFunctionClass targetObject = new TestFunctionClass(); - - var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherWithContext", String.class, - Unit.class, ToolContext.class); - - // @formatter:off - String response = ChatClient.create(this.chatModel).prompt() - .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") - .functions(MethodFunctionCallback.builder() - .functionObject(targetObject) - .method(method) - .description("Get the weather in location") - .build()) - .toolContext(Map.of("tool", "value")) - .call() - .content(); - // @formatter:on - - logger.info("Response: {}", response); - - assertThat(response).contains("30", "10", "15"); - assertThat(arguments).containsEntry("tool", "value"); - } - - @Test - void methodGetWeatherToolContextButNonContextMethod() { - - TestFunctionClass targetObject = new TestFunctionClass(); - - var method = ReflectionUtils.findMethod(TestFunctionClass.class, "getWeatherNonStatic", String.class, - Unit.class); - - // @formatter:off - assertThrows("Configured method does not accept ToolContext as input parameter!",IllegalArgumentException.class, () -> { - ChatClient.create(this.chatModel).prompt() - .user("What's the weather like in San Francisco, Tokyo, and Paris? Use Celsius.") - .functions(MethodFunctionCallback.builder() - .functionObject(targetObject) - .method(method) - .description("Get the weather in location") - .build()) - .toolContext(Map.of("tool", "value")) - .call() - .content(); - }); - // @formatter:on - } - - @Test - void methodNoParameters() { - - TestFunctionClass targetObject = new TestFunctionClass(); - - var method = ReflectionUtils.findMethod(TestFunctionClass.class, "turnLivingRoomLightOn"); - - // @formatter:off - String response = ChatClient.create(this.chatModel).prompt() - .user("Turn light on in the living room.") - .functions(MethodFunctionCallback.builder() - .functionObject(targetObject) - .method(method) - .description("Can turn lights on in the Living Room") - .build()) - .call() - .content(); - // @formatter:on - - logger.info("Response: {}", response); - - assertThat(arguments).containsEntry("turnLivingRoomLightOn", true); - } - } diff --git a/spring-ai-core/src/test/java/org/springframework/ai/model/function/MethodFunctionCallbackTests.java b/spring-ai-core/src/test/java/org/springframework/ai/model/function/MethodFunctionCallbackTests.java index e5da4187e..59aede715 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/model/function/MethodFunctionCallbackTests.java +++ b/spring-ai-core/src/test/java/org/springframework/ai/model/function/MethodFunctionCallbackTests.java @@ -1,18 +1,19 @@ /* -* Copyright 2024 - 2024 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. -*/ + * Copyright 2023-2024 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.model.function; import java.lang.reflect.Method; @@ -33,9 +34,102 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Christian Tzolov * @since 1.0.0 */ - public class MethodFunctionCallbackTests { + private static final Map arguments = new ConcurrentHashMap<>(); + + String value = """ + { + "unit": "CELSIUS", + "city": "Barcelona", + "intNumber": 123, + "record": { + "foo": "foo", + "bar": "bar" + }, + "intList": [1, 2, 3] + } + """; + + @BeforeEach + public void beforeEach() { + arguments.clear(); + } + + @Test + public void staticMethod() throws NoSuchMethodException, SecurityException { + + Method method = ReflectionUtils.findMethod(TestClassWithFunctionMethods.class, "myStaticMethod", String.class, + Unit.class, int.class, MyRecord.class, List.class); + + assertThat(method).isNotNull(); + assertThat(Modifier.isStatic(method.getModifiers())).isTrue(); + + var functionCallback = MethodFunctionCallback.builder() + .method(method) + .description("weather at location") + .mapper(new ObjectMapper()) + .build(); + + String response = functionCallback.call(this.value); + + assertThat(response).isEqualTo("23"); + + assertThat(arguments).hasSize(5); + assertThat(arguments.get("city")).isEqualTo("Barcelona"); + assertThat(arguments.get("unit")).isEqualTo(Unit.CELSIUS); + assertThat(arguments.get("intNumber")).isEqualTo(123); + assertThat(arguments.get("record")).isEqualTo(new MyRecord("foo", "bar")); + assertThat(arguments.get("intList")).isEqualTo(List.of(1, 2, 3)); + } + + @Test + public void nonStaticMethod() throws NoSuchMethodException, SecurityException { + + Method method = TestClassWithFunctionMethods.class.getMethod("myNonStaticMethod", String.class, Unit.class, + int.class, MyRecord.class, List.class); + + assertThat(Modifier.isStatic(method.getModifiers())).isFalse(); + + var functionCallback = MethodFunctionCallback.builder() + .functionObject(new TestClassWithFunctionMethods()) + .method(method) + .description("weather at location") + .mapper(new ObjectMapper()) + .build(); + + String response = functionCallback.call(this.value); + + assertThat(response).isEqualTo("23"); + + assertThat(arguments).hasSize(5); + assertThat(arguments.get("city")).isEqualTo("Barcelona"); + assertThat(arguments.get("unit")).isEqualTo(Unit.CELSIUS); + assertThat(arguments.get("intNumber")).isEqualTo(123); + assertThat(arguments.get("record")).isEqualTo(new MyRecord("foo", "bar")); + assertThat(arguments.get("intList")).isEqualTo(List.of(1, 2, 3)); + } + + @Test + public void noArgsNoReturnMethod() throws NoSuchMethodException, SecurityException { + + Method method = TestClassWithFunctionMethods.class.getMethod("argumentLessReturnVoid"); + + assertThat(Modifier.isStatic(method.getModifiers())).isTrue(); + + var functionCallback = MethodFunctionCallback.builder() + .method(method) + .description("weather at location") + .mapper(new ObjectMapper()) + .build(); + + String response = functionCallback.call(this.value); + + assertThat(response).isEqualTo("Done"); + + assertThat(arguments.get("method called")).isEqualTo("argumentLessReturnVoid"); + } + record MyRecord(String foo, String bar) { } @@ -80,98 +174,4 @@ public class MethodFunctionCallbackTests { } - public static Map arguments = new ConcurrentHashMap<>(); - - @BeforeEach - public void beforeEach() { - arguments.clear(); - } - - String value = """ - { - "unit": "CELSIUS", - "city": "Barcelona", - "intNumber": 123, - "record": { - "foo": "foo", - "bar": "bar" - }, - "intList": [1, 2, 3] - } - """; - - @Test - public void staticMethod() throws NoSuchMethodException, SecurityException { - - Method method = ReflectionUtils.findMethod(TestClassWithFunctionMethods.class, "myStaticMethod", String.class, - Unit.class, int.class, MyRecord.class, List.class); - - assertThat(method).isNotNull(); - assertThat(Modifier.isStatic(method.getModifiers())).isTrue(); - - var functionCallback = MethodFunctionCallback.builder() - .method(method) - .description("weather at location") - .mapper(new ObjectMapper()) - .build(); - - String response = functionCallback.call(value); - - assertThat(response).isEqualTo("23"); - - assertThat(arguments).hasSize(5); - assertThat(arguments.get("city")).isEqualTo("Barcelona"); - assertThat(arguments.get("unit")).isEqualTo(Unit.CELSIUS); - assertThat(arguments.get("intNumber")).isEqualTo(123); - assertThat(arguments.get("record")).isEqualTo(new MyRecord("foo", "bar")); - assertThat(arguments.get("intList")).isEqualTo(List.of(1, 2, 3)); - } - - @Test - public void nonStaticMethod() throws NoSuchMethodException, SecurityException { - - Method method = TestClassWithFunctionMethods.class.getMethod("myNonStaticMethod", String.class, Unit.class, - int.class, MyRecord.class, List.class); - - assertThat(Modifier.isStatic(method.getModifiers())).isFalse(); - - var functionCallback = MethodFunctionCallback.builder() - .functionObject(new TestClassWithFunctionMethods()) - .method(method) - .description("weather at location") - .mapper(new ObjectMapper()) - .build(); - - String response = functionCallback.call(value); - - assertThat(response).isEqualTo("23"); - - assertThat(arguments).hasSize(5); - assertThat(arguments.get("city")).isEqualTo("Barcelona"); - assertThat(arguments.get("unit")).isEqualTo(Unit.CELSIUS); - assertThat(arguments.get("intNumber")).isEqualTo(123); - assertThat(arguments.get("record")).isEqualTo(new MyRecord("foo", "bar")); - assertThat(arguments.get("intList")).isEqualTo(List.of(1, 2, 3)); - } - - @Test - public void noArgsNoReturnMethod() throws NoSuchMethodException, SecurityException { - - Method method = TestClassWithFunctionMethods.class.getMethod("argumentLessReturnVoid"); - - assertThat(Modifier.isStatic(method.getModifiers())).isTrue(); - - var functionCallback = MethodFunctionCallback.builder() - .method(method) - .description("weather at location") - .mapper(new ObjectMapper()) - .build(); - - String response = functionCallback.call(value); - - assertThat(response).isEqualTo("Done"); - - assertThat(arguments.get("method called")).isEqualTo("argumentLessReturnVoid"); - } - } diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index 85c9cf865..8bd052e9c 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -31,5 +31,6 @@ +