@testable import ForgejoKit import Foundation import Testing struct RepositoryServiceURLTests { /// Creates a client with dummy credentials for URL construction tests. private func makeClient() -> ForgejoClient { ForgejoClient(serverURL: "https://forgejo.example.com", username: "user", password: "pass") } // MARK: - fetchContents URL construction @Test func makeURLContentsWithoutRef() throws { let client = makeClient() let url = try client.makeURL(path: "/api/v1/repos/owner/repo/contents") #expect(url.absoluteString == "https://forgejo.example.com/api/v1/repos/owner/repo/contents") } @Test func makeURLContentsWithRef() throws { let client = makeClient() let queryItems = [URLQueryItem(name: "ref", value: "develop")] let url = try client.makeURL(path: "/api/v1/repos/owner/repo/contents", queryItems: queryItems) #expect(url.absoluteString == "https://forgejo.example.com/api/v1/repos/owner/repo/contents?ref=develop") } @Test func makeURLContentsWithRefAndSubpath() throws { let client = makeClient() let queryItems = [URLQueryItem(name: "ref", value: "feature/login")] let url = try client.makeURL(path: "/api/v1/repos/owner/repo/contents/src/main.py", queryItems: queryItems) #expect(url.query?.contains("ref=feature/login") == true) #expect(url.path == "/api/v1/repos/owner/repo/contents/src/main.py") } @Test func makeURLFileContentWithRef() throws { let client = makeClient() let queryItems = [URLQueryItem(name: "ref", value: "v1.0")] let url = try client.makeURL(path: "/api/v1/repos/owner/repo/contents/README.md", queryItems: queryItems) #expect(url.absoluteString == "https://forgejo.example.com/api/v1/repos/owner/repo/contents/README.md?ref=v1.0") } @Test func makeURLWithEmptyQueryItems() throws { let client = makeClient() let url = try client.makeURL(path: "/api/v1/repos/owner/repo/contents", queryItems: []) #expect(url.query == nil) } // MARK: - ref parameter nil-coalescence (same pattern used by fetchContents and fetchFileContent) @Test func optionalRefProducesEmptyQueryItems() { let ref: String? = nil let queryItems = ref.map { [URLQueryItem(name: "ref", value: $0)] } ?? [] #expect(queryItems.isEmpty) } @Test func presentRefProducesQueryItem() { let ref: String? = "main" let queryItems = ref.map { [URLQueryItem(name: "ref", value: $0)] } ?? [] #expect(queryItems.count == 1) #expect(queryItems.first?.name == "ref") #expect(queryItems.first?.value == "main") } // MARK: - createRepository URL @Test func createRepositoryURL() throws { let client = makeClient() let url = try client.makeURL(path: "/api/v1/user/repos") #expect(url.absoluteString == "https://forgejo.example.com/api/v1/user/repos") } // MARK: - editRepository URL @Test func editRepositoryURL() throws { let client = makeClient() let url = try client.makeRepoURL(owner: "owner", repo: "repo", path: "") #expect(url.absoluteString == "https://forgejo.example.com/api/v1/repos/owner/repo") } // MARK: - createLabel URL @Test func createLabelURL() throws { let client = makeClient() let url = try client.makeRepoURL(owner: "owner", repo: "repo", path: "/labels") #expect(url.absoluteString == "https://forgejo.example.com/api/v1/repos/owner/repo/labels") } // MARK: - createMilestone URL @Test func createMilestoneURL() throws { let client = makeClient() let url = try client.makeRepoURL(owner: "owner", repo: "repo", path: "/milestones") #expect(url.absoluteString == "https://forgejo.example.com/api/v1/repos/owner/repo/milestones") } // MARK: - addCollaborator URL @Test func addCollaboratorURL() throws { let client = makeClient() let encoded = ForgejoClient.encodedPathSegment("testbot") let url = try client.makeRepoURL(owner: "owner", repo: "repo", path: "/collaborators/\(encoded)") #expect(url.absoluteString == "https://forgejo.example.com/api/v1/repos/owner/repo/collaborators/testbot") } // MARK: - createFile URL @Test func createFileURL() throws { let client = makeClient() let url = try client.makeRepoURL(owner: "owner", repo: "repo", path: "/contents/hello.py") #expect(url.absoluteString == "https://forgejo.example.com/api/v1/repos/owner/repo/contents/hello.py") } // MARK: - Payload encoding @Test func createRepositoryPayloadEncoding() throws { let payload: [String: Any] = [ "name": "test-repo", "description": "A test repo", "private": false, "auto_init": true, ] let data = try JSONSerialization.data(withJSONObject: payload) let dict = try #require(JSONSerialization.jsonObject(with: data) as? [String: Any]) #expect(dict["name"] as? String == "test-repo") #expect(dict["auto_init"] as? Bool == true) #expect(dict["private"] as? Bool == false) } @Test func createFilePayloadEncoding() throws { let payload: [String: Any] = [ "content": "base64content", "message": "Add file", "new_branch": "feature-branch", ] let data = try JSONSerialization.data(withJSONObject: payload) let dict = try #require(JSONSerialization.jsonObject(with: data) as? [String: Any]) #expect(dict["content"] as? String == "base64content") #expect(dict["message"] as? String == "Add file") #expect(dict["new_branch"] as? String == "feature-branch") } }