Skip to content

Commit

Permalink
added files tests
Browse files Browse the repository at this point in the history
  • Loading branch information
NatashaTheRobot committed Dec 21, 2024
1 parent 3316f3d commit c975cb0
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,13 @@ extension _Gemini.APISpecification {
public let name: _Gemini.File.Name
}

public struct FileListInput: Codable {
// Maximum number of Files to return per page. If unspecified, defaults to 10. Maximum pageSize is 100.
public let pageSize: Int?
// A page token from a previous files.list call.
public let pageToken: String?
}

// Fine Tuning

public struct CreateTunedModel: Codable {
Expand Down
17 changes: 17 additions & 0 deletions Sources/_Gemini/Intramodular/API/_Gemini.APISpecification.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,23 @@ extension _Gemini {
})
var getFile = Endpoint<RequestBodies.FileStatusInput, _Gemini.File, Void>()

@GET
@Path("/v1beta/files")
@Query({ context -> [String : String] in
var parameters: [String : String] = [:]
if let pageSize = context.input.pageSize {
parameters["pageSize"] = String(pageSize)
}
if let pageToken = context.input.pageToken {
parameters["pageToken"] = pageToken
}
return parameters
})
var listFiles = Endpoint<RequestBodies.FileListInput, _Gemini.FileList, Void>()

// Delete File endpoint
@DELETE
@Path({ context -> String in
Expand Down
7 changes: 7 additions & 0 deletions Sources/_Gemini/Intramodular/Models/_Gemini.File.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import Foundation

extension _Gemini {

public struct File: Codable {
public let createTime: String?
public let expirationTime: String?
Expand All @@ -29,6 +30,12 @@ extension _Gemini {
public let videoDuration: String
}
}

public struct FileList: Codable {
public let files: [_Gemini.File]
// A token that can be sent as a pageToken into a subsequent files.list call.
public let nextPageToken: String
}
}

extension _Gemini.File {
Expand Down
16 changes: 16 additions & 0 deletions Sources/_Gemini/Intramodular/_Gemini.Client+Files.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import NetworkKit
import Swallow

extension _Gemini.Client {

public func uploadFile(
fileData: Data,
mimeType: HTTPMediaType,
Expand Down Expand Up @@ -48,6 +49,21 @@ extension _Gemini.Client {
}
}

public func listFiles(
pageSize: Int? = nil,
pageToken: String? = nil
) async throws -> _Gemini.FileList {
do {
let input = _Gemini.APISpecification.RequestBodies.FileListInput(
pageSize: pageSize,
pageToken: pageToken
)
return try await run(\.listFiles, with: input)
} catch {
throw _Gemini.APIError.unknown(message: "Failed to get file status: \(error.localizedDescription)")
}
}

public func deleteFile(
fileURL: URL
) async throws {
Expand Down
100 changes: 100 additions & 0 deletions Tests/_Gemini/Intramodular/_GeminiTests+Files.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// _GeminiTests+Files.swift
// AI
//
// Created by Natasha Murashev on 12/21/24.
//

import Testing
import Foundation
import _Gemini

@Suite struct GeminiFileTests {

private let fileURL = URL(string: "https://upload.wikimedia.org/wikipedia/en/7/77/EricCartman.png")!
private var fileData: Data? = nil
private var fileName: _Gemini.File.Name? = nil

@Test mutating func testUploadFile() async throws {
let file: _Gemini.File = try await uploadFile()

print(file)
#expect(file.name.isNotNil)
#expect(((file.name?.rawValue.starts(with: "files/")) == true))
}

@Test mutating func testGetFile() async throws {

if fileName == nil {
fileName = try await uploadFile().name
}

guard let fileName = fileName else {
#expect(Bool(false), "The file name is invalid")
return
}

let file: _Gemini.File = try await client.getFile(name: fileName)
#expect(file.name?.rawValue == fileName.rawValue)
}

@Test mutating func testListFiles() async throws {
let file = try await uploadFile()
let fileList: _Gemini.FileList = try await client.listFiles()
let files: [_Gemini.File] = fileList.files

guard let fileName = file.name else {
#expect(Bool(false), "The uploaded file has no valid name.")
return
}

let uploadedFileIsPresent = files.contains { $0.name! == fileName }
#expect(uploadedFileIsPresent, "Expected the newly uploaded file to be in the returned file list.")
}

@Test mutating func testDeleteFile() async throws {
let uploadedFile = try await uploadFile()
let file: _Gemini.File = try await client.getFile(name: uploadedFile.name!)

try await client.deleteFile(fileURL: file.uri)
do {
let _ = try await client.getFile(name: uploadedFile.name!)
#expect(Bool(false), "Expected getFile to throw when fetching a deleted file, but it succeeded.")
} catch {
#expect(Bool(true), "getFile threw an error, as expected, when trying to retrieve a deleted file.")
}
}
}

extension GeminiFileTests {

private mutating func uploadFile() async throws -> _Gemini.File {
let data = try await downloadFile(from: fileURL)

let file = try await client.uploadFile(
fileData: data,
mimeType: .custom("image/png"),
displayName: UUID().uuidString
)

self.fileName = file.name

return file
}

private func downloadFile(from url: URL) async throws -> Data {
if let data = fileData {
return data
}

let (data, response) = try await URLSession.shared.data(from: url)

guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw _Gemini.APIError.unknown(message: "Failed to download file from URL")
}

return data
}
}

0 comments on commit c975cb0

Please sign in to comment.