tests/SboxSuperuser.Contracts.Tests/NativeBindingTests.cs

Unit tests for native setting bindings and serialization in the SboxSuperuser project. Tests validate name restrictions, value normalization, descriptor constraint enforcement, persistence/serialization round trips, and handling of missing or corrupt stored state.

using SboxSuperuser.Engine.NativeSettings;
using Xunit;

namespace SboxSuperuser.Contracts.Tests;

public sealed class NativeBindingTests
{
	private static NativeSettingDescriptor Number( string nativeName = "game_capacity" ) => new(
		"capacity", nativeName, "Player capacity", "game.capacity", CommandArgumentKind.Integer, "8",
		NativePersistence.Framework, minimum: 1, maximum: 32 );

	private static AuditIntent[] Intents() => new[]
	{
		new AuditIntent( Guid.NewGuid(), Guid.NewGuid(), ActorKind.InternalService, "test.settings",
			CommandOrigin.InternalService, "settings.set.capacity", DateTimeOffset.UtcNow )
	};

	[Theory]
	[InlineData( "game_capacity;quit" )]
	[InlineData( "game_capacity 3" )]
	[InlineData( "game_capacity\nquit" )]
	[InlineData( "GameCapacity" )]
	public void NativeNameCannotContainConsoleSyntax( string name ) => Assert.Throws<ArgumentException>( () => Number( name ) );

	[Theory]
	[InlineData( "0" )]
	[InlineData( "33" )]
	[InlineData( "1.5" )]
	[InlineData( "NaN" )]
	[InlineData( "9223372036854775808" )]
	public void InvalidSettingValuesNeverNormalize( string value ) => Assert.Null( NativeValue.Normalize( Number(), value ) );

	[Fact]
	public void ResetDefaultMustRespectDeclaredConstraints() => Assert.Throws<ArgumentException>( () => new NativeSettingDescriptor(
		"capacity", "game_capacity", "Player capacity", "game.capacity", CommandArgumentKind.Integer, "0", minimum: 1 ) );

	[Fact]
	public void PendingStateCannotCompeteWithEnginePersistence() => Assert.Throws<ArgumentException>( () => new NativeSettingDescriptor(
		"capacity", "game_capacity", "Player capacity", "game.capacity", CommandArgumentKind.Integer, "8", NativePersistence.Engine, requiresRestart: true ) );

	[Fact]
	public void CanonicalValuesAndExplicitEnumChoicesRoundTrip()
	{
		Assert.Equal( "8", NativeValue.Normalize( Number(), "008" ) );
		var choice = new NativeSettingDescriptor( "mode", "game_mode", "Mode", "game.mode", CommandArgumentKind.Enum,
			"friendly", choices: new[] { "friendly", "strict" } );
		Assert.Equal( "strict", NativeValue.Normalize( choice, "STRICT" ) );
		Assert.Null( NativeValue.Normalize( choice, "unknown" ) );
	}

	[Fact]
	public void PersistedValueRequiresTheSameNativeContract()
	{
		var binding = Number();
		var transaction = new PolicyTransaction( NativeSettingState.Serialize( binding, "12" ), Intents() );
		var stored = new StoreReadResult( StoreReadStatus.Found, transaction.CreateWriteRequest( new StoreKey( "test", "setting" ), 0 ).Document );
		Assert.Equal( new NativeSettingState( 1, "12" ), NativeSettingState.Read( binding, stored ) );
		Assert.Throws<InvalidOperationException>( () => NativeSettingState.Read( Number( "different_native" ), stored ) );
	}

	[Fact]
	public void CorruptionCannotBecomeFirstRunDefaults()
	{
		Assert.Equal( new NativeSettingState( 0, null ), NativeSettingState.Read( Number(), new StoreReadResult( StoreReadStatus.Missing ) ) );
		Assert.Throws<InvalidOperationException>( () => NativeSettingState.Read( Number(), new StoreReadResult( StoreReadStatus.Corrupt ) ) );
		var transaction = new PolicyTransaction( NativeSettingState.Serialize( Number(), "999" ), Intents() );
		var stored = new StoreReadResult( StoreReadStatus.Found, transaction.CreateWriteRequest( new StoreKey( "test", "setting" ), 0 ).Document );
		Assert.Throws<InvalidOperationException>( () => NativeSettingState.Read( Number(), stored ) );
	}
}