Spaces:
Running
Running
| // Copyright 2025 The Google AI Edge 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 not obtain a copy of the License at | |
| // | |
| // http://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. | |
| namespace { | |
| using ::litert::lm::ParseFcExpression; | |
| using ::testing::status::IsOkAndHolds; | |
| using ::testing::status::StatusIs; | |
| TEST(FcParserUtilsTest, ParseToolCall) { | |
| EXPECT_THAT(ParseFcExpression(R"(call:tool_name{x:1})"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "tool_name", | |
| "arguments": { | |
| "x": 1 | |
| } | |
| }])json"))); | |
| } | |
| TEST(FcParserUtilsTest, ParseToolCallWithStringArgument) { | |
| EXPECT_THAT( | |
| ParseFcExpression(R"(call:tool_name{text:<escape>hello world<escape>})"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "tool_name", | |
| "arguments": { | |
| "text": "hello world" | |
| } | |
| }])json"))); | |
| } | |
| TEST(FcParserUtilsTest, ParseToolCallNoArgumentsEmptyBraces) { | |
| EXPECT_THAT(ParseFcExpression(R"(call:tool_name{})"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "tool_name", | |
| "arguments": {} | |
| }])json"))); | |
| } | |
| TEST(FcParserUtilsTest, ParseToolCallNoArgumentsNoBraces) { | |
| EXPECT_THAT(ParseFcExpression(R"(call:tool_name)"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "tool_name", | |
| "arguments": {} | |
| }])json"))); | |
| } | |
| TEST(FcParserUtilsTest, ParseToolCallWithSingleQuotesInStringArgument) { | |
| EXPECT_THAT(ParseFcExpression( | |
| R"(call:tool_name{text:<escape>foo 'bar' baz<escape>})"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "tool_name", | |
| "arguments": { | |
| "text": "foo 'bar' baz" | |
| } | |
| }])json"))); | |
| } | |
| TEST(FcParserUtilsTest, ParseToolCallWithDoubleQuotesInStringArgument) { | |
| EXPECT_THAT(ParseFcExpression( | |
| R"(call:tool_name{text:<escape>foo "bar" baz<escape>})"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "tool_name", | |
| "arguments": { | |
| "text": "foo \"bar\" baz" | |
| } | |
| }])json"))); | |
| } | |
| TEST(FcParserUtilsTest, ParseToolCallWithBackslashInStringArgument) { | |
| EXPECT_THAT(ParseFcExpression( | |
| R"(call:tool_name{text:<escape>foo \b\a\r baz<escape>})"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "tool_name", | |
| "arguments": { | |
| "text": "foo \\b\\a\\r baz" | |
| } | |
| }])json"))); | |
| } | |
| TEST(FcParserUtilsTest, ParseToolCallWithNestedQuotesInStringArgument) { | |
| EXPECT_THAT(ParseFcExpression( | |
| R"(call:tool_name{text:<escape>"foo \"bar\" baz"<escape>})"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "tool_name", | |
| "arguments": { | |
| "text": "\"foo \\\"bar\\\" baz\"" | |
| } | |
| }])json"))); | |
| } | |
| TEST(FcParserUtilsTest, ParseEmptyArguments) { | |
| EXPECT_THAT(ParseFcExpression(R"(call:empty_args_func{})"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "empty_args_func", | |
| "arguments": {} | |
| }])json"))); | |
| } | |
| TEST(FcParserUtilsTest, ParseComplexArguments) { | |
| EXPECT_THAT(ParseFcExpression( | |
| R"(call:complex_func{ | |
| str_arg:<escape>value<escape>, | |
| int_arg:123, | |
| float_arg:-4.5, | |
| bool_arg:false, | |
| null_arg:null, | |
| list_arg:[1,<escape>two<escape>,true,null,{nested_key:<escape>nested_val<escape>}], | |
| obj_arg:{ | |
| nested_str:<escape>val1<escape>, | |
| nested_int:-678, | |
| nested_float:9.1, | |
| nested_bool:true, | |
| nested_null:null, | |
| nested_list:[10,20], | |
| nested_obj: { | |
| key:<escape>val<escape> | |
| } | |
| } | |
| })"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "complex_func", | |
| "arguments": { | |
| "str_arg": "value", | |
| "int_arg": 123, | |
| "float_arg": -4.5, | |
| "bool_arg": false, | |
| "null_arg": null, | |
| "list_arg": [ | |
| 1, | |
| "two", | |
| true, | |
| null, | |
| { | |
| "nested_key": "nested_val" | |
| } | |
| ], | |
| "obj_arg": { | |
| "nested_str": "val1", | |
| "nested_int": -678, | |
| "nested_float": 9.1, | |
| "nested_bool": true, | |
| "nested_null": null, | |
| "nested_list": [ | |
| 10, | |
| 20 | |
| ], | |
| "nested_obj": { | |
| "key": "val" | |
| } | |
| } | |
| } | |
| }])json"))); | |
| } | |
| TEST(FcParserUtilsTest, InvalidToolCallSyntax) { | |
| // Extra comma in the argument list. | |
| EXPECT_THAT(ParseFcExpression(R"(call:bad_tool_call{x:1,})"), | |
| StatusIs(absl::StatusCode::kInvalidArgument)); | |
| } | |
| TEST(FcParserUtilsTest, MissingToolName) { | |
| EXPECT_THAT(ParseFcExpression(R"(call:{x:1})"), | |
| StatusIs(absl::StatusCode::kInvalidArgument)); | |
| } | |
| TEST(FcParserUtilsTest, ArgumentsNotObject) { | |
| EXPECT_THAT(ParseFcExpression(R"(call:wrong_args[1,2,3])"), | |
| StatusIs(absl::StatusCode::kInvalidArgument)); | |
| } | |
| TEST(FcParserUtilsTest, MissingParameterKey) { | |
| EXPECT_THAT(ParseFcExpression(R"(call:{1})"), | |
| StatusIs(absl::StatusCode::kInvalidArgument)); | |
| } | |
| TEST(FcParserUtilsTest, EmptyInputString) { | |
| EXPECT_THAT(ParseFcExpression(""), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([])json"))); | |
| } | |
| TEST(FcParserUtilsTest, NoCallPrefix) { | |
| EXPECT_THAT(ParseFcExpression(R"(print{x:1})"), | |
| StatusIs(absl::StatusCode::kInvalidArgument)); | |
| } | |
| TEST(FcParserUtilsTest, UnescapedString) { | |
| EXPECT_THAT(ParseFcExpression(R"(call:print{text:"hello"})"), | |
| StatusIs(absl::StatusCode::kInvalidArgument)); | |
| } | |
| TEST(FcParserUtilsTest, DuplicateKeysInObject) { | |
| EXPECT_THAT(ParseFcExpression(R"(call:foo{a:1,b:2,a:3})"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "foo", | |
| "arguments": { | |
| "a": 1, | |
| "b": 2 | |
| } | |
| }])json"))); | |
| } | |
| TEST(FcParserUtilsTest, ToolNameWithDotsAndDashes) { | |
| EXPECT_THAT(ParseFcExpression(R"(call:tool.name-123{})"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "tool.name-123", | |
| "arguments": {} | |
| }])json"))); | |
| } | |
| TEST(FcParserUtilsTest, ParameterNameWithDotsAndDashes) { | |
| EXPECT_THAT(ParseFcExpression(R"(call:tool_name{param.name-123:1})"), | |
| IsOkAndHolds(nlohmann::ordered_json::parse(R"json([{ | |
| "name": "tool_name", | |
| "arguments": { | |
| "param.name-123": 1 | |
| } | |
| }])json"))); | |
| } | |
| } // namespace | |