using System.Net.Http.Json;
using System.Text.Json;
using DodoSSH.Contracts;
namespace DodoSSH.Api.Tests;
///
/// Sends and reads request bodies the way a real client does.
///
///
///
/// Not a convenience. PostAsJsonAsync's default options write an enum as a number, and the shared
/// contract writes it as a string. Tests that used the defaults therefore agreed with a server that had
/// also been left on the defaults, and the pair of them agreed on a wire form the specification never
/// described — so the entire sync surface was unreachable from the real client and every test passed.
///
///
/// Everything here goes through for that reason. If the server's JSON
/// configuration regresses, these tests are the ones that must fail.
///
///
internal static class ContractJson
{
private static JsonSerializerOptions Options => DodoSshJsonContext.ResponseOptions;
internal static Task PostContractAsync(
this HttpClient client,
string url,
T value)
{
ArgumentNullException.ThrowIfNull(client);
return client.PostAsJsonAsync(url, value, Options, TestContext.Current.CancellationToken);
}
///
/// The same options as , and here for the same reason rather than
/// for symmetry: a PUT that serialised its enums differently from a POST would let a wire form the
/// specification never described reach exactly the endpoints nothing else covers.
///
internal static Task PutContractAsync(
this HttpClient client,
string url,
T value)
{
ArgumentNullException.ThrowIfNull(client);
return client.PutAsJsonAsync(url, value, Options, TestContext.Current.CancellationToken);
}
internal static Task ReadContractAsync(this HttpContent content)
{
ArgumentNullException.ThrowIfNull(content);
return content.ReadFromJsonAsync(Options, TestContext.Current.CancellationToken);
}
/// Reads an RFC 9457 problem body.
///
/// Deliberately not through the contract options. Problem details are written by the framework
/// and are not part of 's source-generated set, so resolving them
/// against it fails outright — a source-generated context does not fall back to reflection. Reading
/// them with the ambient web options is correct rather than a shortcut: the shape is the RFC's, not
/// ours, and only the code extension belongs to us.
///
internal static Task ReadProblemAsync(this HttpContent content)
{
ArgumentNullException.ThrowIfNull(content);
return content.ReadFromJsonAsync(TestContext.Current.CancellationToken);
}
}