mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Java: Fix TimeSkill unit test (#1882)
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: John Oliver <[email protected]> Co-authored-by: Milder Hernandez <[email protected]> Co-authored-by: GitHub <[email protected]> Co-authored-by: Derek Keeler <[email protected]> Co-authored-by: Devis Lucato <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Craig Presti <[email protected]> Co-authored-by: Craig Presti <[email protected]> Co-authored-by: Shawn Callegari <[email protected]> Co-authored-by: Mark Wallace <[email protected]> Co-authored-by: Teresa Hoang <[email protected]> Co-authored-by: Abby Harrison <[email protected]> Co-authored-by: Tao Chen <[email protected]> Co-authored-by: Aman Sachan <[email protected]> Co-authored-by: cschadewitz <[email protected]> Co-authored-by: Dmytro Struk <[email protected]> Co-authored-by: Abby Harrison <[email protected]> Co-authored-by: Desmond Howard <[email protected]> Co-authored-by: Jean-Sylvain Boige <[email protected]> Co-authored-by: Dave Arlin <[email protected]> Co-authored-by: Gina Triolo <[email protected]> Co-authored-by: Ben Thomas <[email protected]> Co-authored-by: Ben Thomas <[email protected]> Co-authored-by: Sebastian Santoyo <[email protected]> Co-authored-by: sneha <[email protected]> Co-authored-by: Alisha Maddy <[email protected]> Co-authored-by: Alisha Maddy <[email protected]> Co-authored-by: Sneha <[email protected]> Co-authored-by: Joe Braley <[email protected]> Co-authored-by: joebraley <[email protected]> Co-authored-by: Luigi Montoya <[email protected]> Co-authored-by: Luigi96 <[email protected]> Co-authored-by: David Grieve <[email protected]>
This commit is contained in:
co-authored by
John Oliver
Milder Hernandez
GitHub
Derek Keeler
Devis Lucato
dependabot[bot]
Craig Presti
Craig Presti
Shawn Callegari
Mark Wallace
Teresa Hoang
Abby Harrison
Tao Chen
Aman Sachan
cschadewitz
Dmytro Struk
Abby Harrison
Desmond Howard
Jean-Sylvain Boige
Dave Arlin
Gina Triolo
Ben Thomas
Ben Thomas
Sebastian Santoyo
sneha
Alisha Maddy
Alisha Maddy
Sneha
Joe Braley
joebraley
Luigi Montoya
Luigi96
David Grieve
parent
f3c407ece0
commit
bde13ee2e1
+6
@@ -19,5 +19,11 @@ public @interface SKFunctionParameters {
|
||||
|
||||
String defaultValue() default NO_DEFAULT_VALUE;
|
||||
|
||||
/**
|
||||
* If required is false, no value is set, and no default value is provided, null will be passed
|
||||
* as this argument.
|
||||
*/
|
||||
boolean required() default true;
|
||||
|
||||
Class<?> type() default String.class;
|
||||
}
|
||||
|
||||
+169
-39
@@ -2,6 +2,9 @@
|
||||
package com.microsoft.semantickernel.coreskills;
|
||||
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.DefineSKFunction;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionInputAttribute;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionParameters;
|
||||
import com.microsoft.semantickernel.util.LocaleParser;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
@@ -57,6 +60,15 @@ public class TimeSkill {
|
||||
|
||||
public static final String DAY_MONTH_DAY_YEAR = "EEEE, MMMM d, yyyy";
|
||||
|
||||
/**
|
||||
* Get the current date and time for the system default timezone.
|
||||
*
|
||||
* @return a ZonedDateTime object with the current date and time.
|
||||
*/
|
||||
public ZonedDateTime now() {
|
||||
return ZonedDateTime.now(ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current date.
|
||||
*
|
||||
@@ -65,9 +77,16 @@ public class TimeSkill {
|
||||
* @return The current date.
|
||||
*/
|
||||
@DefineSKFunction(name = "date", description = "Get the current date")
|
||||
public String date() {
|
||||
public String date(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
// Example: Sunday, 12 January, 2025
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR).format(ZonedDateTime.now());
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR)
|
||||
.withLocale(parseLocale(locale))
|
||||
.format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,9 +97,16 @@ public class TimeSkill {
|
||||
* @return The current time.
|
||||
*/
|
||||
@DefineSKFunction(name = "time", description = "Get the current time")
|
||||
public String time() {
|
||||
public String time(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
// Example: 09:15:07 PM
|
||||
return DateTimeFormatter.ofPattern("hh:mm:ss a").format(ZonedDateTime.now());
|
||||
return DateTimeFormatter.ofPattern("hh:mm:ss a")
|
||||
.withLocale(parseLocale(locale))
|
||||
.format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,9 +117,15 @@ public class TimeSkill {
|
||||
* @return The current UTC date and time.
|
||||
*/
|
||||
@DefineSKFunction(name = "utcNow", description = "Get the current UTC date and time")
|
||||
public String utcNow() {
|
||||
public String utcNow(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR + " h:mm a")
|
||||
.format(ZonedDateTime.now().withZoneSameInstant(ZoneOffset.UTC));
|
||||
.withLocale(parseLocale(locale))
|
||||
.format(now().withZoneSameInstant(ZoneOffset.UTC));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,8 +136,13 @@ public class TimeSkill {
|
||||
* @return The current date.
|
||||
*/
|
||||
@DefineSKFunction(name = "today", description = "Get the current date")
|
||||
public String today() {
|
||||
return date();
|
||||
public String today(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return date(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,9 +155,15 @@ public class TimeSkill {
|
||||
@DefineSKFunction(
|
||||
name = "now",
|
||||
description = "Get the current date and time in the local time zone")
|
||||
public String now() {
|
||||
public String now(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR + " h:mm a")
|
||||
.format(ZonedDateTime.now());
|
||||
.withLocale(parseLocale(locale))
|
||||
.format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,8 +174,13 @@ public class TimeSkill {
|
||||
* @return The current year.
|
||||
*/
|
||||
@DefineSKFunction(name = "year", description = "Get the current year")
|
||||
public String year() {
|
||||
return DateTimeFormatter.ofPattern("yyyy").format(ZonedDateTime.now());
|
||||
public String year(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return DateTimeFormatter.ofPattern("yyyy").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,8 +191,13 @@ public class TimeSkill {
|
||||
* @return The current month name.
|
||||
*/
|
||||
@DefineSKFunction(name = "month", description = "Get the current month name")
|
||||
public String month() {
|
||||
return DateTimeFormatter.ofPattern("MMMM").format(ZonedDateTime.now());
|
||||
public String month(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return DateTimeFormatter.ofPattern("MMMM").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,8 +208,13 @@ public class TimeSkill {
|
||||
* @return The current month number.
|
||||
*/
|
||||
@DefineSKFunction(name = "monthNumber", description = "Get the current month number")
|
||||
public String monthNumber() {
|
||||
return DateTimeFormatter.ofPattern("MM").format(ZonedDateTime.now());
|
||||
public String monthNumber(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return DateTimeFormatter.ofPattern("MM").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,8 +225,13 @@ public class TimeSkill {
|
||||
* @return The current day of the month.
|
||||
*/
|
||||
@DefineSKFunction(name = "day", description = "Get the current day of the month")
|
||||
public String day() {
|
||||
return DateTimeFormatter.ofPattern("d").format(ZonedDateTime.now());
|
||||
public String day(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return DateTimeFormatter.ofPattern("d").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,8 +242,13 @@ public class TimeSkill {
|
||||
* @return The current day of the week.
|
||||
*/
|
||||
@DefineSKFunction(name = "dayOfWeek", description = "Get the current day of the week")
|
||||
public String dayOfWeek() {
|
||||
return DateTimeFormatter.ofPattern("EEEE").format(ZonedDateTime.now());
|
||||
public String dayOfWeek(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return DateTimeFormatter.ofPattern("EEEE").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,8 +259,13 @@ public class TimeSkill {
|
||||
* @return The current clock hour.
|
||||
*/
|
||||
@DefineSKFunction(name = "hour", description = "Get the current clock hour")
|
||||
public String hour() {
|
||||
return DateTimeFormatter.ofPattern("h a").format(ZonedDateTime.now());
|
||||
public String hour(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return DateTimeFormatter.ofPattern("h a").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,8 +276,13 @@ public class TimeSkill {
|
||||
* @return The current clock 24-hour number.
|
||||
*/
|
||||
@DefineSKFunction(name = "hourNumber", description = "Get the current clock 24-hour number")
|
||||
public String hourNumber() {
|
||||
return DateTimeFormatter.ofPattern("HH").format(ZonedDateTime.now());
|
||||
public String hourNumber(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return DateTimeFormatter.ofPattern("HH").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,10 +297,21 @@ public class TimeSkill {
|
||||
@DefineSKFunction(
|
||||
name = "daysAgo",
|
||||
description = "Get the date of offset from today by a provided number of days")
|
||||
public static String daysAgo(String days) {
|
||||
public String daysAgo(
|
||||
@SKFunctionInputAttribute
|
||||
@SKFunctionParameters(
|
||||
name = "input",
|
||||
description = "Number of days to offset from today.")
|
||||
String days,
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
int offsetDays = Integer.parseInt(days);
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR)
|
||||
.format(ZonedDateTime.now().minusDays(offsetDays));
|
||||
.withLocale(parseLocale(locale))
|
||||
.format(now().minusDays(offsetDays));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,16 +325,25 @@ public class TimeSkill {
|
||||
@DefineSKFunction(
|
||||
name = "dateMatchingLastDayName",
|
||||
description = "Get the date of the last day matching the supplied week day name")
|
||||
public static String dateMatchingLastDayName(String dayName) {
|
||||
ZonedDateTime currentDate = ZonedDateTime.now();
|
||||
Locale systemLocale = Locale.getDefault();
|
||||
public String dateMatchingLastDayName(
|
||||
@SKFunctionInputAttribute
|
||||
@SKFunctionParameters(name = "input", description = "Week name day.")
|
||||
String dayName,
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
ZonedDateTime currentDate = now();
|
||||
for (int i = 1; i <= 7; i++) {
|
||||
currentDate = currentDate.minusDays(1);
|
||||
String currentDayName =
|
||||
currentDate.getDayOfWeek().getDisplayName(TextStyle.FULL, systemLocale);
|
||||
currentDate.getDayOfWeek().getDisplayName(TextStyle.FULL, parseLocale(locale));
|
||||
|
||||
if (currentDayName.equalsIgnoreCase(dayName)) {
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR).format(currentDate);
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR)
|
||||
.withLocale(parseLocale(locale))
|
||||
.format(currentDate);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("dayName is not recognized");
|
||||
@@ -259,8 +357,13 @@ public class TimeSkill {
|
||||
* @return The minutes on the current hour.
|
||||
*/
|
||||
@DefineSKFunction(name = "minute", description = "Get the minutes on the current hour")
|
||||
public String minute() {
|
||||
return DateTimeFormatter.ofPattern("mm").format(ZonedDateTime.now());
|
||||
public String minute(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return DateTimeFormatter.ofPattern("mm").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,8 +374,13 @@ public class TimeSkill {
|
||||
* @return The seconds on the current minute.
|
||||
*/
|
||||
@DefineSKFunction(name = "second", description = "Get the seconds on the current minute")
|
||||
public String second() {
|
||||
return DateTimeFormatter.ofPattern("ss").format(ZonedDateTime.now());
|
||||
public String second(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return DateTimeFormatter.ofPattern("ss").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,8 +393,13 @@ public class TimeSkill {
|
||||
@DefineSKFunction(
|
||||
name = "timeZoneOffset",
|
||||
description = "Get the local time zone offset from UTC")
|
||||
public String timeZoneOffset() {
|
||||
return DateTimeFormatter.ofPattern("XXX").format(ZonedDateTime.now());
|
||||
public String timeZoneOffset(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
return DateTimeFormatter.ofPattern("XXX").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,8 +410,25 @@ public class TimeSkill {
|
||||
* @return The local time zone name.
|
||||
*/
|
||||
@DefineSKFunction(name = "timeZoneName", description = "Get the local time zone name")
|
||||
public String timeZoneName() {
|
||||
public String timeZoneName(
|
||||
@SKFunctionParameters(
|
||||
name = "locale",
|
||||
description = "Locale to use when formatting the date",
|
||||
required = false)
|
||||
String locale) {
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
return zoneId.getDisplayName(TextStyle.FULL, Locale.getDefault());
|
||||
return zoneId.getDisplayName(TextStyle.FULL, parseLocale(locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the locale string into a Locale object.
|
||||
*
|
||||
* <p>By default, it parses using the LocaleParser utility class.
|
||||
*
|
||||
* @param locale string
|
||||
* @return a locale object
|
||||
*/
|
||||
protected Locale parseLocale(String locale) {
|
||||
return LocaleParser.parseLocale(locale);
|
||||
}
|
||||
}
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.util;
|
||||
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionParameters;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Locale parser to support Java 8 and Java 9+ due to JEP 252.
|
||||
*
|
||||
* <p>Supports parsing strings containing languageCode_countryCode and languageCode-countryCode
|
||||
* styles.
|
||||
*/
|
||||
public final class LocaleParser {
|
||||
|
||||
private LocaleParser() {}
|
||||
|
||||
/**
|
||||
* Parses the locale. If the input is "en-US", it will return a Locale based on the language
|
||||
* tag. If the input is "en_US", it will return a Locale based on the language and country code.
|
||||
* Otherwise, it will return a Locale based on the input.
|
||||
*
|
||||
* <p>'en' 'US' used as example above.
|
||||
*
|
||||
* @param locale the locale in String text.
|
||||
* @return
|
||||
*/
|
||||
public static final Locale parseLocale(String locale) {
|
||||
Locale parsedLocale = null;
|
||||
|
||||
if (locale == null
|
||||
|| "".equals(locale.trim())
|
||||
|| SKFunctionParameters.NO_DEFAULT_VALUE.equals(locale)) {
|
||||
return Locale.getDefault();
|
||||
} else if (locale.indexOf("-") > -1) {
|
||||
parsedLocale = Locale.forLanguageTag(locale);
|
||||
} else if (locale.indexOf("_") > -1) {
|
||||
String[] parts = locale.split("_");
|
||||
parsedLocale = new Locale(parts[0], parts[1]);
|
||||
} else {
|
||||
parsedLocale = new Locale(locale);
|
||||
}
|
||||
|
||||
return parsedLocale;
|
||||
}
|
||||
}
|
||||
+83
-159
@@ -5,8 +5,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
@@ -14,209 +14,133 @@ import java.util.Locale;
|
||||
|
||||
@SuppressWarnings("ReturnValueIgnored")
|
||||
public class TimeSkillTest {
|
||||
|
||||
private static final String defaultLocale = "en-US";
|
||||
|
||||
private static final ZonedDateTime mockDateTime;
|
||||
|
||||
static {
|
||||
mockDateTime = ZonedDateTime.of(2025, 1, 12, 9, 15, 7, 0, ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
private TimeSkill timeSkill;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
timeSkill = spy(new TimeSkill());
|
||||
when(timeSkill.now()).thenReturn(mockDateTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDate() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.date();
|
||||
assertEquals("Sunday, January 12, 2025", result);
|
||||
}
|
||||
String result = timeSkill.date(defaultLocale);
|
||||
assertEquals("Sunday, January 12, 2025", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTime() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.time();
|
||||
assertEqualsIgnoreCase("09:15:07 AM", result);
|
||||
}
|
||||
String result = timeSkill.time(defaultLocale);
|
||||
assertEqualsIgnoreCase("09:15:07 AM", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToday() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.today();
|
||||
assertEquals("Sunday, January 12, 2025", result);
|
||||
}
|
||||
String result = timeSkill.today(defaultLocale);
|
||||
assertEquals("Sunday, January 12, 2025", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNow() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.now();
|
||||
assertEqualsIgnoreCase("Sunday, January 12, 2025 9:15 AM", result);
|
||||
}
|
||||
String result = timeSkill.now(defaultLocale);
|
||||
assertEqualsIgnoreCase("Sunday, January 12, 2025 9:15 AM", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testYear() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.year();
|
||||
assertEquals("2025", result);
|
||||
}
|
||||
String result = timeSkill.year(defaultLocale);
|
||||
assertEquals("2025", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMonth() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.month();
|
||||
assertEquals("January", result);
|
||||
}
|
||||
String result = timeSkill.month(defaultLocale);
|
||||
assertEquals("January", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMonthNumber() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.monthNumber();
|
||||
assertEquals("01", result);
|
||||
}
|
||||
String result = timeSkill.monthNumber(defaultLocale);
|
||||
assertEquals("01", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDay() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.day();
|
||||
assertEquals("12", result);
|
||||
}
|
||||
String result = timeSkill.day(defaultLocale);
|
||||
assertEquals("12", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDayOfWeek() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
String result = timeSkill.dayOfWeek(defaultLocale);
|
||||
assertEquals("Sunday", result);
|
||||
}
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
@Test
|
||||
public void testHour() {
|
||||
String result = timeSkill.hour(defaultLocale);
|
||||
assertEqualsIgnoreCase("9 AM", result);
|
||||
}
|
||||
|
||||
String result = timeSkill.dayOfWeek();
|
||||
assertEquals("Sunday", result);
|
||||
}
|
||||
@Test
|
||||
public void testHourNumber() {
|
||||
String result = timeSkill.hourNumber(defaultLocale);
|
||||
assertEquals("09", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinute() {
|
||||
String result = timeSkill.minute(defaultLocale);
|
||||
assertEquals("15", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecond() {
|
||||
String result = timeSkill.second(defaultLocale);
|
||||
assertEquals("07", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void daysAgo() {
|
||||
assertEquals("Thursday, January 9, 2025", timeSkill.daysAgo("3", defaultLocale));
|
||||
assertEquals("Tuesday, January 7, 2025", timeSkill.daysAgo("5", defaultLocale));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateMatchingLastDayName() {
|
||||
assertEquals(
|
||||
"Sunday, January 5, 2025",
|
||||
timeSkill.dateMatchingLastDayName("Sunday", defaultLocale));
|
||||
assertEquals(
|
||||
"Monday, January 6, 2025",
|
||||
timeSkill.dateMatchingLastDayName("Monday", defaultLocale));
|
||||
assertEquals(
|
||||
"Tuesday, January 7, 2025",
|
||||
timeSkill.dateMatchingLastDayName("Tuesday", defaultLocale));
|
||||
assertEquals(
|
||||
"Wednesday, January 8, 2025",
|
||||
timeSkill.dateMatchingLastDayName("wednesday", defaultLocale));
|
||||
assertEquals(
|
||||
"Thursday, January 9, 2025",
|
||||
timeSkill.dateMatchingLastDayName("thursday", defaultLocale));
|
||||
assertEquals(
|
||||
"Friday, January 10, 2025",
|
||||
timeSkill.dateMatchingLastDayName("Friday", defaultLocale));
|
||||
assertEquals(
|
||||
"Saturday, January 11, 2025",
|
||||
timeSkill.dateMatchingLastDayName("Saturday", defaultLocale));
|
||||
}
|
||||
|
||||
public void assertEqualsIgnoreCase(String a, String b) {
|
||||
Assertions.assertEquals(a.toUpperCase(Locale.ROOT), b.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHour() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.hour();
|
||||
assertEqualsIgnoreCase("9 AM", result);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHourNumber() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.hourNumber();
|
||||
assertEquals("09", result);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinute() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.minute();
|
||||
assertEquals("15", result);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecond() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
|
||||
try (MockedStatic<ZonedDateTime> mocked = mockStatic(ZonedDateTime.class)) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.second();
|
||||
assertEquals("07", result);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void daysAgo() {
|
||||
try (MockedStatic<ZonedDateTime> mocked =
|
||||
mockStatic(
|
||||
ZonedDateTime.class,
|
||||
withSettings()
|
||||
.useConstructor()
|
||||
.outerInstance(mockDateTime)
|
||||
.defaultAnswer(CALLS_REAL_METHODS))) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
assertEquals("Thursday, January 9, 2025", TimeSkill.daysAgo("3"));
|
||||
assertEquals("Tuesday, January 7, 2025", TimeSkill.daysAgo("5"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateMatchingLastDayName() {
|
||||
try (MockedStatic<ZonedDateTime> mocked =
|
||||
mockStatic(
|
||||
ZonedDateTime.class,
|
||||
withSettings()
|
||||
.useConstructor()
|
||||
.outerInstance(mockDateTime)
|
||||
.defaultAnswer(CALLS_REAL_METHODS))) {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
assertEquals("Sunday, January 5, 2025", TimeSkill.dateMatchingLastDayName("Sunday"));
|
||||
assertEquals("Monday, January 6, 2025", TimeSkill.dateMatchingLastDayName("Monday"));
|
||||
assertEquals("Tuesday, January 7, 2025", TimeSkill.dateMatchingLastDayName("Tuesday"));
|
||||
assertEquals(
|
||||
"Wednesday, January 8, 2025", TimeSkill.dateMatchingLastDayName("wednesday"));
|
||||
assertEquals(
|
||||
"Thursday, January 9, 2025", TimeSkill.dateMatchingLastDayName("thursday"));
|
||||
assertEquals("Friday, January 10, 2025", TimeSkill.dateMatchingLastDayName("Friday"));
|
||||
assertEquals(
|
||||
"Saturday, January 11, 2025", TimeSkill.dateMatchingLastDayName("Saturday"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+82
-52
@@ -23,6 +23,9 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@@ -210,26 +213,7 @@ public class NativeSKFunction extends AbstractSkFunction<Void> {
|
||||
try {
|
||||
List<Object> args =
|
||||
Arrays.stream(method.getParameters())
|
||||
.map(
|
||||
parameter -> {
|
||||
if (SKContext.class.isAssignableFrom(
|
||||
parameter.getType())) {
|
||||
return context; // .copy();
|
||||
} else {
|
||||
String value =
|
||||
getArgumentValue(
|
||||
method, context, parameter,
|
||||
inputArgs);
|
||||
if (value != null) {
|
||||
return value;
|
||||
} else {
|
||||
throw new AIException(
|
||||
AIException.ErrorCodes
|
||||
.InvalidConfiguration,
|
||||
"Unknown arg " + parameter.getName());
|
||||
}
|
||||
}
|
||||
})
|
||||
.map(getParameters(method, context, inputArgs))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Mono mono;
|
||||
@@ -240,26 +224,7 @@ public class NativeSKFunction extends AbstractSkFunction<Void> {
|
||||
return Mono.error(e);
|
||||
}
|
||||
} else {
|
||||
mono =
|
||||
Mono.defer(
|
||||
() -> {
|
||||
return Mono.fromCallable(
|
||||
() -> {
|
||||
try {
|
||||
Object result =
|
||||
method.invoke(
|
||||
instance,
|
||||
args.toArray());
|
||||
|
||||
return result;
|
||||
} catch (IllegalAccessException
|
||||
| InvocationTargetException e) {
|
||||
throw new RuntimeException(
|
||||
e.getCause());
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.boundedElastic());
|
||||
});
|
||||
mono = invokeAsyncFunction(method, instance, args);
|
||||
}
|
||||
|
||||
return mono.map(
|
||||
@@ -276,6 +241,56 @@ public class NativeSKFunction extends AbstractSkFunction<Void> {
|
||||
};
|
||||
}
|
||||
|
||||
private static Mono<Object> invokeAsyncFunction(
|
||||
Method method, Object instance, List<Object> args) {
|
||||
return Mono.defer(
|
||||
() ->
|
||||
Mono.fromCallable(
|
||||
() -> {
|
||||
try {
|
||||
Object result =
|
||||
method.invoke(instance, args.toArray());
|
||||
|
||||
return result;
|
||||
} catch (IllegalAccessException
|
||||
| InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.boundedElastic()));
|
||||
}
|
||||
|
||||
private static Function<Parameter, Object> getParameters(
|
||||
Method method, SKContext context, Set<Parameter> inputArgs) {
|
||||
return parameter -> {
|
||||
if (SKContext.class.isAssignableFrom(parameter.getType())) {
|
||||
return context;
|
||||
} else {
|
||||
return getArgumentValue(method, context, parameter, inputArgs);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static String formErrorMessage(Method method, Parameter parameter) {
|
||||
Matcher matcher = Pattern.compile("arg(\\d)").matcher(parameter.getName());
|
||||
matcher.find();
|
||||
return "For the function "
|
||||
+ method.getDeclaringClass().getName()
|
||||
+ "."
|
||||
+ method.getName()
|
||||
+ ", the unknown parameter"
|
||||
+ " name was detected as \""
|
||||
+ parameter.getName()
|
||||
+ "\" this is argument"
|
||||
+ " number "
|
||||
+ matcher.group(1)
|
||||
+ " to the function, this indicates that the argument name for this function was"
|
||||
+ " removed during compilation and semantic-kernel is unable to determine the name"
|
||||
+ " of the parameter. To support this function the argument must be annotated with"
|
||||
+ " @SKFunctionParameters or @SKFunctionInputAttribute. Alternatively the function"
|
||||
+ " was invoked with a required context variable missing and no default value.";
|
||||
}
|
||||
|
||||
private static String getArgumentValue(
|
||||
Method method, SKContext context, Parameter parameter, Set<Parameter> inputArgs) {
|
||||
String variableName = getGetVariableName(parameter);
|
||||
@@ -295,26 +310,41 @@ public class NativeSKFunction extends AbstractSkFunction<Void> {
|
||||
parameter.getAnnotation(SKFunctionParameters.class);
|
||||
if (annotation != null) {
|
||||
arg = annotation.defaultValue();
|
||||
|
||||
if (NO_DEFAULT_VALUE.equals(arg)) {
|
||||
if (!annotation.required()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new AIException(
|
||||
AIException.ErrorCodes.InvalidConfiguration,
|
||||
"Attempted to invoke function "
|
||||
+ method.getDeclaringClass().getName()
|
||||
+ "."
|
||||
+ method.getName()
|
||||
+ ". The context variable \""
|
||||
+ variableName
|
||||
+ "\" has not been set, and no default value is"
|
||||
+ " specified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (arg == null && variableName.matches("arg\\d")) {
|
||||
LOGGER.warn(
|
||||
"For the function "
|
||||
+ method.getDeclaringClass().getName()
|
||||
+ "."
|
||||
+ method.getName()
|
||||
+ ", the parameter argument name was detected as \""
|
||||
+ variableName
|
||||
+ "\" this indicates that the argument name for this function was"
|
||||
+ " removed during compilation. To support this function its arguments"
|
||||
+ " must be annotated with @SKFunctionParameters with the name defined,"
|
||||
+ " or @SKFunctionInputAttribute.");
|
||||
LOGGER.warn(formErrorMessage(method, parameter));
|
||||
}
|
||||
|
||||
if (NO_DEFAULT_VALUE.equals(arg)) {
|
||||
return null;
|
||||
if (parameter.getName().matches("arg\\d")) {
|
||||
throw new AIException(
|
||||
AIException.ErrorCodes.InvalidConfiguration,
|
||||
formErrorMessage(method, parameter));
|
||||
} else {
|
||||
throw new AIException(
|
||||
AIException.ErrorCodes.InvalidConfiguration,
|
||||
"Unknown arg " + parameter.getName());
|
||||
}
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
+3
-1
@@ -65,8 +65,10 @@ public class Example06TemplateLanguageTest {
|
||||
|
||||
Mono<String> renderedPrompt = promptRenderer.renderAsync(skContext);
|
||||
|
||||
String renderedText = renderedPrompt.block();
|
||||
|
||||
// Check that it has been rendered
|
||||
Assertions.assertTrue(!renderedPrompt.block().contains("time.Date"));
|
||||
Assertions.assertTrue(!renderedText.contains("time.Date"));
|
||||
|
||||
// Run the prompt / semantic function
|
||||
CompletionSKFunction kindOfDay =
|
||||
|
||||
Reference in New Issue
Block a user