using System.Reflection;
using DodoSSH.Contracts;
namespace DodoSSH.Contracts.Tests;
///
/// Problem codes are part of the public wire contract: the client switches on them.
///
public sealed class ProblemCodesTests
{
private static IReadOnlyList CodeFields =>
[.. typeof(ProblemCodes)
.GetFields(BindingFlags.Public | BindingFlags.Static)
.Where(f => f.IsLiteral && f.FieldType == typeof(string))
.Where(f => !string.Equals(f.Name, nameof(ProblemCodes.TypeBaseUri), StringComparison.Ordinal))];
[Fact]
public void AllCodes_AreUnique()
{
// A duplicated value would make two distinct failures indistinguishable to the
// client, which is the whole point of having codes rather than parsing messages.
var values = CodeFields.Select(f => (string)f.GetRawConstantValue()!).ToList();
values.Distinct(StringComparer.Ordinal).Count().ShouldBe(values.Count);
}
[Fact]
public void AllCodes_AreKebabCase()
{
// Codes are appended to TypeBaseUri to form the ProblemDetails type URI, so they
// must be URL-safe and stylistically consistent.
foreach (var field in CodeFields)
{
var value = (string)field.GetRawConstantValue()!;
value.ShouldMatch("^[a-z][a-z0-9]*(-[a-z0-9]+)*$", $"{field.Name} is not kebab-case");
}
}
[Fact]
public void TypeBaseUri_IsAnAbsoluteHttpsUriEndingInSlash()
{
Uri.TryCreate(ProblemCodes.TypeBaseUri, UriKind.Absolute, out var uri).ShouldBeTrue();
uri!.Scheme.ShouldBe(Uri.UriSchemeHttps);
ProblemCodes.TypeBaseUri.ShouldEndWith("/");
}
}