Skip to content

Commit 142b06a

Browse files
committed
Add integration tests
1 parent d9a88b6 commit 142b06a

File tree

1 file changed

+103
-7
lines changed

1 file changed

+103
-7
lines changed

FirebaseAI/Tests/TestApp/Tests/Integration/SchemaTests.swift

Lines changed: 103 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct SchemaTests {
3535
SafetySetting(harmCategory: .dangerousContent, threshold: .blockLowAndAbove),
3636
SafetySetting(harmCategory: .civicIntegrity, threshold: .blockLowAndAbove),
3737
]
38+
let generationConfig = GenerationConfig(temperature: 0.0, topP: 0.0, topK: 1)
3839

3940
@Test(
4041
arguments: testConfigs(
@@ -72,6 +73,31 @@ struct SchemaTests {
7273
#expect(decodedJSON.count <= 5, "Expected at most 5 cities, but got \(decodedJSON.count)")
7374
}
7475

76+
struct CityList: Decodable, SchemaConstraintsProvider {
77+
let cities: [String]
78+
79+
static var schemaConstraints: [AnyHashable: SchemaConstraint] {
80+
[CodingKeys.cities: .array(minItems: 3, maxItems: 5, description: "A list of city names")]
81+
}
82+
}
83+
84+
@Test(arguments: InstanceConfig.allConfigs)
85+
func generateObjectItemsSchema(_ config: InstanceConfig) async throws {
86+
let model = FirebaseAI.componentInstance(config).generativeModel(
87+
modelName: ModelNames.gemini2_5_FlashLite,
88+
generationConfig: generationConfig,
89+
safetySettings: safetySettings
90+
)
91+
let prompt = "What are the biggest cities in Canada?"
92+
93+
let response = try await model.generateObject(CityList.self, prompt: prompt)
94+
let cityList = try #require(try response.getObject())
95+
96+
let cities = cityList.cities
97+
#expect(cities.count >= 3, "Expected at least 3 cities, but got \(cities.count)")
98+
#expect(cities.count <= 5, "Expected at most 5 cities, but got \(cities.count)")
99+
}
100+
75101
@Test(arguments: testConfigs(
76102
instanceConfigs: InstanceConfig.allConfigs,
77103
openAPISchema: .integer(
@@ -102,6 +128,22 @@ struct SchemaTests {
102128
#expect(decodedNumber <= 120.0, "Expected a number <= 120, but got \(decodedNumber)")
103129
}
104130

131+
struct ProductInfo: Decodable, SchemaConstraintsProvider {
132+
let productName: String
133+
let rating: Int
134+
let price: Double
135+
let salePrice: Float
136+
137+
static var schemaConstraints: [AnyHashable: SchemaConstraint] {
138+
[
139+
CodingKeys.productName: .string(description: "The name of the product"),
140+
CodingKeys.rating: .integer(1 ... 5, description: "A rating"),
141+
CodingKeys.price: .number(min: 10.00, max: 120.00, description: "A price"),
142+
CodingKeys.salePrice: .number(min: 5.00, max: 90.00, description: "A sale price"),
143+
]
144+
}
145+
}
146+
105147
@Test(arguments: testConfigs(
106148
instanceConfigs: InstanceConfig.allConfigs,
107149
openAPISchema: .object(
@@ -169,13 +211,6 @@ struct SchemaTests {
169211
))
170212
func generateContentSchemaNumberRangeMultiType(_ config: InstanceConfig,
171213
_ schema: SchemaType) async throws {
172-
struct ProductInfo: Codable {
173-
let productName: String
174-
let rating: Int
175-
let price: Double
176-
let salePrice: Float
177-
}
178-
179214
let model = FirebaseAI.componentInstance(config).generativeModel(
180215
modelName: ModelNames.gemini2_5_FlashLite,
181216
generationConfig: SchemaTests.generationConfig(schema: schema),
@@ -197,6 +232,29 @@ struct SchemaTests {
197232
#expect(rating <= 5, "Expected a rating <= 5, but got \(rating)")
198233
}
199234

235+
@Test(arguments: InstanceConfig.allConfigs)
236+
func generateObjectSchemaNumberRangeMultiType(_ config: InstanceConfig) async throws {
237+
let model = FirebaseAI.componentInstance(config).generativeModel(
238+
modelName: ModelNames.gemini2_5_FlashLite,
239+
generationConfig: generationConfig,
240+
safetySettings: safetySettings
241+
)
242+
let prompt = "Describe a premium wireless headphone, including a user rating and price."
243+
244+
let response = try await model.generateObject(ProductInfo.self, prompt: prompt)
245+
let productInfo = try #require(try response.getObject())
246+
247+
let price = productInfo.price
248+
let salePrice = productInfo.salePrice
249+
let rating = productInfo.rating
250+
#expect(price >= 10.0, "Expected a price >= 10.00, but got \(price)")
251+
#expect(price <= 120.0, "Expected a price <= 120.00, but got \(price)")
252+
#expect(salePrice >= 5.0, "Expected a salePrice >= 5.00, but got \(salePrice)")
253+
#expect(salePrice <= 90.0, "Expected a salePrice <= 90.00, but got \(salePrice)")
254+
#expect(rating >= 1, "Expected a rating >= 1, but got \(rating)")
255+
#expect(rating <= 5, "Expected a rating <= 5, but got \(rating)")
256+
}
257+
200258
fileprivate struct MailingAddress {
201259
enum PostalInfo {
202260
struct Canada: Decodable {
@@ -354,6 +412,44 @@ struct SchemaTests {
354412
}
355413
}
356414

415+
struct Catalog: Decodable {
416+
let name: String
417+
let categories: [Category]
418+
419+
struct Category: Decodable {
420+
let title: String
421+
let items: [Item]
422+
423+
struct Item: Decodable {
424+
let name: String
425+
let price: Double
426+
}
427+
}
428+
}
429+
430+
@Test(arguments: InstanceConfig.allConfigs)
431+
func generateObjectSchemaNestedTypes(_ config: InstanceConfig) async throws {
432+
let model = FirebaseAI.componentInstance(config).generativeModel(
433+
modelName: ModelNames.gemini2_5_FlashLite,
434+
generationConfig: generationConfig,
435+
safetySettings: safetySettings
436+
)
437+
let prompt = """
438+
Create a catalog named 'Tech' with a category 'Computers' containing an item 'Laptop' for \
439+
$999.99.
440+
"""
441+
442+
let response = try await model.generateObject(Catalog.self, prompt: prompt)
443+
let catalog = try #require(try response.getObject())
444+
445+
#expect(catalog.name == "Tech")
446+
#expect(catalog.categories.count == 1)
447+
#expect(catalog.categories[0].title == "Computers")
448+
#expect(catalog.categories[0].items.count == 1)
449+
#expect(catalog.categories[0].items[0].name == "Laptop")
450+
#expect(catalog.categories[0].items[0].price == 999.99)
451+
}
452+
357453
enum SchemaType: CustomTestStringConvertible {
358454
case openAPI(Schema)
359455
case json(JSONObject)

0 commit comments

Comments
 (0)