Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 12 additions & 16 deletions tests/OpenCode.Sdk.Tests/Common/Errors/DeclaredErrorTests.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,28 @@
using System.Globalization;
using System.Net;
using System.Text;
using System.Text.Json;
using OpenCode.Sdk.Models;
using OpenCode.Sdk.Tests.Common.Support;
using OpenCode.Sdk.Tests.Config;
using OpenCode.Sdk.Tests.Credentials;
using OpenCode.Sdk.Tests.Debug;
using OpenCode.Sdk.Tests.Experimental;
using OpenCode.Sdk.Tests.Forms;
using OpenCode.Sdk.Tests.Harness;
using OpenCode.Sdk.Tests.Support;
using OpenCode.Sdk.Tests.Worktrees;

namespace OpenCode.Sdk.Tests.Common.Errors;

public sealed class DeclaredErrorTests
{
public static IEnumerable<Func<DeclaredErrorCase>> EveryDoor() =>
[
static () => new(
"worktree.create:400:InvalidRequestError",
new DeclaredErrorDoor(
nameof(WorktreesClient.CreateWorktreeAsync),
"worktree.create",
"post",
"/api/worktree",
static async (client, options) => await client.Worktrees.CreateWorktreeAsync(
new WorktreeCreateRequest { ProjectId = "prj_1", Directory = "/repo/feature" }, options)),
HttpStatusCode.BadRequest,
WireBodyData.InvalidRequestError,
"InvalidRequestError",
typeof(InvalidRequestError),
"#/paths/~1api~1worktree/post/responses/400/content/application~1json/schema/anyOf/1"),
.. WorktreesDeclaredErrors.Rows(),
.. ConfigDeclaredErrors.Rows(),
.. CredentialsDeclaredErrors.Rows(),
.. DebugDeclaredErrors.Rows(),
.. ExperimentalDeclaredErrors.Rows(),
.. FormsDeclaredErrors.Rows(),
];

[Test]
Expand Down
52 changes: 0 additions & 52 deletions tests/OpenCode.Sdk.Tests/Config/ConfigClientContractTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,6 @@ public async Task GetShellsAsync_Should_Return_The_Bare_Typed_List()
await Assert.That(request.RequestUri).IsEqualTo(new Uri("http://localhost:4096/api/config/shell"));
}

[Test]
public async Task GetShellsAsync_Should_Throw_The_Declared_400_Error()
{
using var scenario = ContractScenario.Responding(HttpStatusCode.BadRequest, WireBodyData.InvalidRequestError);

var exception = await Assert
.That(async () => _ = await scenario.Client.Config.GetShellsAsync())
.Throws<OpenCodeApiException>();

await Assert.That(exception!.Status).IsEqualTo(400);
await Assert.That(exception.Error).IsTypeOf<InvalidRequestError>();
}

[Test]
public async Task GetShellsAsync_Should_Return_The_401_Error_On_The_NoThrow_Spine()
{
using var scenario = ContractScenario.Responding(HttpStatusCode.Unauthorized, WireBodyData.UnauthorizedError);

var response = await scenario.Client.Config.GetShellsAsync(OpenCodeRequestOptions.NoThrow);

await Assert.That(response.IsError).IsTrue();
await Assert.That(response.Status).IsEqualTo(401);
await Assert.That(response.Error).IsTypeOf<UnauthorizedError>();
}

[Test]
[Arguments("pwsh")]
[Arguments(null)]
Expand All @@ -69,31 +44,4 @@ public async Task UpdateConfigAsync_Should_Send_The_Required_Nullable_Shell(stri
await Assert.That(body.RootElement.EnumerateObject().Count()).IsEqualTo(1);
await Assert.That(body.RootElement.GetProperty("shell").GetString()).IsEqualTo(shell);
}

[Test]
public async Task UpdateConfigAsync_Should_Throw_The_Declared_400_Error()
{
using var scenario = ContractScenario.Responding(HttpStatusCode.BadRequest, WireBodyData.InvalidRequestError);

var exception = await Assert
.That(async () => _ = await scenario.Client.Experimental.UpdateConfigAsync(
new ExperimentalConfigUpdateRequest { Shell = null, }))
.Throws<OpenCodeApiException>();

await Assert.That(exception!.Status).IsEqualTo(400);
await Assert.That(exception.Error).IsTypeOf<InvalidRequestError>();
}

[Test]
public async Task UpdateConfigAsync_Should_Return_The_401_Error_On_The_NoThrow_Spine()
{
using var scenario = ContractScenario.Responding(HttpStatusCode.Unauthorized, WireBodyData.UnauthorizedError);

var response = await scenario.Client.Experimental.UpdateConfigAsync(
new ExperimentalConfigUpdateRequest { Shell = null, }, OpenCodeRequestOptions.NoThrow);

await Assert.That(response.IsError).IsTrue();
await Assert.That(response.Status).IsEqualTo(401);
await Assert.That(response.Error).IsTypeOf<UnauthorizedError>();
}
}
67 changes: 67 additions & 0 deletions tests/OpenCode.Sdk.Tests/Config/ConfigDeclaredErrors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System.Net;
using OpenCode.Sdk.Models;
using OpenCode.Sdk.Tests.Common.Support;
using OpenCode.Sdk.Tests.Support;

namespace OpenCode.Sdk.Tests.Config;

public static class ConfigDeclaredErrors
{
public static IEnumerable<Func<DeclaredErrorCase>> Rows() =>
[
static () => new(
"config.shells:400:InvalidRequestError",
new DeclaredErrorDoor(
nameof(ConfigClient.GetShellsAsync),
"config.shells",
"get",
"/api/config/shell",
static async (client, options) => await client.Config.GetShellsAsync(options)),
HttpStatusCode.BadRequest,
WireBodyData.InvalidRequestError,
"InvalidRequestError",
typeof(InvalidRequestError),
"#/paths/~1api~1config~1shell/get/responses/400/content/application~1json/schema"),
static () => new(
"config.shells:401:UnauthorizedError",
new DeclaredErrorDoor(
nameof(ConfigClient.GetShellsAsync),
"config.shells",
"get",
"/api/config/shell",
static async (client, options) => await client.Config.GetShellsAsync(options)),
HttpStatusCode.Unauthorized,
WireBodyData.UnauthorizedError,
"UnauthorizedError",
typeof(UnauthorizedError),
"#/paths/~1api~1config~1shell/get/responses/401/content/application~1json/schema"),
static () => new(
"experimental.config.update:400:InvalidRequestError",
new DeclaredErrorDoor(
nameof(ExperimentalClient.UpdateConfigAsync),
"experimental.config.update",
"patch",
"/api/experimental/config",
static async (client, options) => await client.Experimental.UpdateConfigAsync(
new ExperimentalConfigUpdateRequest { Shell = null, }, options)),
HttpStatusCode.BadRequest,
WireBodyData.InvalidRequestError,
"InvalidRequestError",
typeof(InvalidRequestError),
"#/paths/~1api~1experimental~1config/patch/responses/400/content/application~1json/schema"),
static () => new(
"experimental.config.update:401:UnauthorizedError",
new DeclaredErrorDoor(
nameof(ExperimentalClient.UpdateConfigAsync),
"experimental.config.update",
"patch",
"/api/experimental/config",
static async (client, options) => await client.Experimental.UpdateConfigAsync(
new ExperimentalConfigUpdateRequest { Shell = null, }, options)),
HttpStatusCode.Unauthorized,
WireBodyData.UnauthorizedError,
"UnauthorizedError",
typeof(UnauthorizedError),
"#/paths/~1api~1experimental~1config/patch/responses/401/content/application~1json/schema"),
];
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,6 @@ await Assert.That(request.Body).IsEqualTo(
"{\"integrationID\":\"openai\",\"label\":\"work\",\"value\":{\"type\":\"key\",\"key\":\"sk-test\"},\"activate\":true}");
}

[Test]
public async Task CreateCredentialAsync_Should_Return_The_Declared_409_Error_On_The_NoThrow_Spine()
{
using var scenario = ContractScenario.Responding(HttpStatusCode.Conflict, WireBodyData.ConflictError);

var response = await scenario.Client.Credentials.CreateCredentialAsync(
new CredentialCreateRequest
{
Id = "cred_1",
IntegrationId = "openai",
Value = new CredentialKey { Key = "sk-test" },
},
OpenCodeRequestOptions.NoThrow);

await Assert.That(response.IsError).IsTrue();
await Assert.That(response.Status).IsEqualTo(409);
await Assert.That(response.Error).IsTypeOf<ConflictError>();
}

[Test]
public async Task CreateCredentialAsync_Should_Send_A_Caller_Chosen_Id()
{
Expand Down Expand Up @@ -96,19 +77,6 @@ public async Task ListCredentialsAsync_Should_Read_Both_Value_Arms()
await Assert.That(request.Body).IsNull();
}

[Test]
public async Task ListCredentialsAsync_Should_Throw_The_Declared_401_Error()
{
using var scenario = ContractScenario.Responding(HttpStatusCode.Unauthorized, WireBodyData.UnauthorizedError);

var exception = await Assert
.That(async () => _ = await scenario.Client.Credentials.ListCredentialsAsync())
.Throws<OpenCodeApiException>();

await Assert.That(exception!.Status).IsEqualTo(401);
await Assert.That(exception.Error).IsTypeOf<UnauthorizedError>();
}

[Test]
public async Task UpdateCredentialAsync_Should_Send_The_Patch_Body_On_The_Flat_Id_Route()
{
Expand Down Expand Up @@ -140,30 +108,4 @@ public async Task ActivateCredentialAsync_Should_Post_On_The_Flat_Id_Route()
await Assert.That(request.Method.Method).IsEqualTo("POST");
await Assert.That(request.RequestUri).IsEqualTo(new Uri("http://localhost:4096/api/credential/cred_1/activate"));
}

[Test]
public async Task ActivateCredentialAsync_Should_Throw_The_Declared_400_Error()
{
using var scenario = ContractScenario.Responding(HttpStatusCode.BadRequest, WireBodyData.InvalidRequestError);

var exception = await Assert
.That(async () => _ = await scenario.Client.Credentials.ActivateCredentialAsync("cred_1"))
.Throws<OpenCodeApiException>();

await Assert.That(exception!.Status).IsEqualTo(400);
await Assert.That(exception.Error).IsTypeOf<InvalidRequestError>();
}

[Test]
public async Task ActivateCredentialAsync_Should_Return_The_401_Error_On_The_NoThrow_Spine()
{
using var scenario = ContractScenario.Responding(HttpStatusCode.Unauthorized, WireBodyData.UnauthorizedError);

var response = await scenario.Client.Credentials.ActivateCredentialAsync(
"cred_1", requestOptions: OpenCodeRequestOptions.NoThrow);

await Assert.That(response.IsError).IsTrue();
await Assert.That(response.Status).IsEqualTo(401);
await Assert.That(response.Error).IsTypeOf<UnauthorizedError>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System.Net;
using OpenCode.Sdk.Models;
using OpenCode.Sdk.Tests.Common.Support;
using OpenCode.Sdk.Tests.Support;

namespace OpenCode.Sdk.Tests.Credentials;

public static class CredentialsDeclaredErrors
{
public static IEnumerable<Func<DeclaredErrorCase>> Rows() =>
[
static () => new(
"credential.create:409:ConflictError",
new DeclaredErrorDoor(
nameof(CredentialsClient.CreateCredentialAsync),
"credential.create",
"post",
"/api/credential",
static async (client, options) => await client.Credentials.CreateCredentialAsync(
new CredentialCreateRequest
{
Id = "cred_1",
IntegrationId = "openai",
Value = new CredentialKey { Key = "sk-test" },
}, options)),
HttpStatusCode.Conflict,
WireBodyData.ConflictError,
"ConflictError",
typeof(ConflictError),
"#/paths/~1api~1credential/post/responses/409/content/application~1json/schema"),
static () => new(
"credential.list:401:UnauthorizedError",
new DeclaredErrorDoor(
nameof(CredentialsClient.ListCredentialsAsync),
"credential.list",
"get",
"/api/credential",
static async (client, options) => await client.Credentials.ListCredentialsAsync(options)),
HttpStatusCode.Unauthorized,
WireBodyData.UnauthorizedError,
"UnauthorizedError",
typeof(UnauthorizedError),
"#/paths/~1api~1credential/get/responses/401/content/application~1json/schema"),
static () => new(
"credential.activate:400:InvalidRequestError",
new DeclaredErrorDoor(
nameof(CredentialsClient.ActivateCredentialAsync),
"credential.activate",
"post",
"/api/credential/{credentialID}/activate",
static async (client, options) => await client.Credentials.ActivateCredentialAsync("cred_1", options)),
HttpStatusCode.BadRequest,
WireBodyData.InvalidRequestError,
"InvalidRequestError",
typeof(InvalidRequestError),
"#/paths/~1api~1credential~1{credentialID}~1activate/post/responses/400/content/application~1json/schema"),
static () => new(
"credential.activate:401:UnauthorizedError",
new DeclaredErrorDoor(
nameof(CredentialsClient.ActivateCredentialAsync),
"credential.activate",
"post",
"/api/credential/{credentialID}/activate",
static async (client, options) => await client.Credentials.ActivateCredentialAsync("cred_1", options)),
HttpStatusCode.Unauthorized,
WireBodyData.UnauthorizedError,
"UnauthorizedError",
typeof(UnauthorizedError),
"#/paths/~1api~1credential~1{credentialID}~1activate/post/responses/401/content/application~1json/schema"),
];
}
26 changes: 0 additions & 26 deletions tests/OpenCode.Sdk.Tests/Debug/DebugClientContractTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Net;
using OpenCode.Sdk.Models;
using OpenCode.Sdk.Tests.Support;

namespace OpenCode.Sdk.Tests.Debug;
Expand Down Expand Up @@ -30,29 +29,4 @@ public async Task ListLocationsAsync_Should_Return_An_Empty_List()

await Assert.That(response.Locations).IsEmpty();
}

[Test]
public async Task ListLocationsAsync_Should_Throw_The_Declared_400_Error()
{
using var scenario = ContractScenario.Responding(HttpStatusCode.BadRequest, WireBodyData.InvalidRequestError);

var exception = await Assert
.That(async () => _ = await scenario.Client.Debug.ListLocationsAsync())
.Throws<OpenCodeApiException>();

await Assert.That(exception!.Status).IsEqualTo(400);
await Assert.That(exception.Error).IsTypeOf<InvalidRequestError>();
}

[Test]
public async Task ListLocationsAsync_Should_Return_The_401_Error_On_The_NoThrow_Spine()
{
using var scenario = ContractScenario.Responding(HttpStatusCode.Unauthorized, WireBodyData.UnauthorizedError);

var response = await scenario.Client.Debug.ListLocationsAsync(requestOptions: OpenCodeRequestOptions.NoThrow);

await Assert.That(response.IsError).IsTrue();
await Assert.That(response.Status).IsEqualTo(401);
await Assert.That(response.Error).IsTypeOf<UnauthorizedError>();
}
}
Loading
Loading