1414
1515
1616import json
17- from unittest .mock import MagicMock
18- from unittest .mock import patch
17+ from unittest .mock import MagicMock , patch
1918
20- from fastapi .openapi .models import MediaType
21- from fastapi .openapi .models import Operation
19+ from fastapi .openapi .models import MediaType , Operation
2220from fastapi .openapi .models import Parameter as OpenAPIParameter
2321from fastapi .openapi .models import RequestBody
2422from fastapi .openapi .models import Schema as OpenAPISchema
2725from google .adk .tools .openapi_tool .common .common import ApiParameter
2826from google .adk .tools .openapi_tool .openapi_spec_parser .openapi_spec_parser import OperationEndpoint
2927from google .adk .tools .openapi_tool .openapi_spec_parser .operation_parser import OperationParser
30- from google .adk .tools .openapi_tool .openapi_spec_parser .rest_api_tool import RestApiTool
31- from google .adk .tools .openapi_tool .openapi_spec_parser .rest_api_tool import snake_to_lower_camel
32- from google .adk .tools .openapi_tool .openapi_spec_parser .rest_api_tool import to_gemini_schema
28+ from google .adk .tools .openapi_tool .openapi_spec_parser .rest_api_tool import (
29+ RestApiTool ,
30+ snake_to_lower_camel ,
31+ to_gemini_schema ,
32+ )
3333from google .adk .tools .tool_context import ToolContext
34- from google .genai .types import FunctionDeclaration
35- from google .genai .types import Schema
36- from google .genai .types import Type
34+ from google .genai .types import FunctionDeclaration , Schema , Type
3735import pytest
3836
3937
@@ -790,13 +788,13 @@ def test_to_gemini_schema_empty_dict(self):
790788 result = to_gemini_schema ({})
791789 assert isinstance (result , Schema )
792790 assert result .type == Type .OBJECT
793- assert result .properties == { "dummy_DO_NOT_GENERATE" : Schema ( type = "string" )}
791+ assert result .properties is None
794792
795793 def test_to_gemini_schema_dict_with_only_object_type (self ):
796794 result = to_gemini_schema ({"type" : "object" })
797795 assert isinstance (result , Schema )
798796 assert result .type == Type .OBJECT
799- assert result .properties == { "dummy_DO_NOT_GENERATE" : Schema ( type = "string" )}
797+ assert result .properties is None
800798
801799 def test_to_gemini_schema_basic_types (self ):
802800 openapi_schema = {
@@ -814,6 +812,42 @@ def test_to_gemini_schema_basic_types(self):
814812 assert gemini_schema .properties ["age" ].type == Type .INTEGER
815813 assert gemini_schema .properties ["is_active" ].type == Type .BOOLEAN
816814
815+ def test_to_gemini_schema_array_string_types (self ):
816+ openapi_schema = {
817+ "type" : "object" ,
818+ "properties" : {
819+ "boolean_field" : {"type" : "boolean" },
820+ "nonnullable_string" : {"type" : ["string" ]},
821+ "nullable_string" : {"type" : ["string" , "null" ]},
822+ "nullable_number" : {"type" : ["null" , "integer" ]},
823+ "object_nullable" : {"type" : "null" },
824+ "multi_types_nullable" : {"type" : ["string" , "null" , "integer" ]},
825+ "empty_default_object" : {},
826+ },
827+ }
828+ gemini_schema = to_gemini_schema (openapi_schema )
829+ assert isinstance (gemini_schema , Schema )
830+ assert gemini_schema .type == Type .OBJECT
831+ assert gemini_schema .properties ["boolean_field" ].type == Type .BOOLEAN
832+
833+ assert gemini_schema .properties ["nonnullable_string" ].type == Type .STRING
834+ assert not gemini_schema .properties ["nonnullable_string" ].nullable
835+
836+ assert gemini_schema .properties ["nullable_string" ].type == Type .STRING
837+ assert gemini_schema .properties ["nullable_string" ].nullable
838+
839+ assert gemini_schema .properties ["nullable_number" ].type == Type .INTEGER
840+ assert gemini_schema .properties ["nullable_number" ].nullable
841+
842+ assert gemini_schema .properties ["object_nullable" ].type == Type .OBJECT
843+ assert gemini_schema .properties ["object_nullable" ].nullable
844+
845+ assert gemini_schema .properties ["multi_types_nullable" ].type == Type .STRING
846+ assert gemini_schema .properties ["multi_types_nullable" ].nullable
847+
848+ assert gemini_schema .properties ["empty_default_object" ].type == Type .OBJECT
849+ assert not gemini_schema .properties ["empty_default_object" ].nullable
850+
817851 def test_to_gemini_schema_nested_objects (self ):
818852 openapi_schema = {
819853 "type" : "object" ,
@@ -895,17 +929,31 @@ def test_to_gemini_schema_required(self):
895929 def test_to_gemini_schema_nested_dict (self ):
896930 openapi_schema = {
897931 "type" : "object" ,
898- "properties" : {"metadata" : {"key1" : "value1" , "key2" : 123 }},
932+ "properties" : {
933+ "metadata" : {
934+ "type" : "object" ,
935+ "properties" : {
936+ "key1" : {"type" : "object" },
937+ "key2" : {"type" : "string" },
938+ },
939+ }
940+ },
899941 }
900942 gemini_schema = to_gemini_schema (openapi_schema )
901943 # Since metadata is not properties nor item, it will call to_gemini_schema recursively.
902944 assert isinstance (gemini_schema .properties ["metadata" ], Schema )
903945 assert (
904946 gemini_schema .properties ["metadata" ].type == Type .OBJECT
905947 ) # add object type by default
906- assert gemini_schema .properties ["metadata" ].properties == {
907- "dummy_DO_NOT_GENERATE" : Schema (type = "string" )
908- }
948+ assert len (gemini_schema .properties ["metadata" ].properties ) == 2
949+ assert (
950+ gemini_schema .properties ["metadata" ].properties ["key1" ].type
951+ == Type .OBJECT
952+ )
953+ assert (
954+ gemini_schema .properties ["metadata" ].properties ["key2" ].type
955+ == Type .STRING
956+ )
909957
910958 def test_to_gemini_schema_ignore_title_default_format (self ):
911959 openapi_schema = {
0 commit comments