Phase 0 WP-0.2–0.9: Implement Commons (types, entities, interfaces, messages, protocol, tests)

- WP-0.2: Namespace/folder skeleton (26 directories)
- WP-0.3: Shared data types (6 enums, RetryPolicy, Result<T>)
- WP-0.4: 24 domain entity POCOs across 10 domain areas
- WP-0.5: 7 repository interfaces with full CRUD signatures
- WP-0.6: IAuditService cross-cutting interface
- WP-0.7: 26 message contract records across 8 concern areas
- WP-0.8: IDataConnection protocol abstraction with batch ops
- WP-0.9: 8 architectural constraint enforcement tests
All 40 tests pass, zero warnings.
This commit is contained in:
Joseph Doherty
2026-03-16 18:48:24 -04:00
parent fed5f5a82c
commit 22e1eba58a
78 changed files with 1530 additions and 16 deletions

View File

@@ -0,0 +1,36 @@
using ScadaLink.Commons.Types.Enums;
namespace ScadaLink.Commons.Tests.Types;
public class EnumTests
{
[Theory]
[InlineData(typeof(DataType), new[] { "Boolean", "Int32", "Float", "Double", "String", "DateTime", "Binary" })]
[InlineData(typeof(InstanceState), new[] { "Enabled", "Disabled" })]
[InlineData(typeof(DeploymentStatus), new[] { "Pending", "InProgress", "Success", "Failed" })]
[InlineData(typeof(AlarmState), new[] { "Active", "Normal" })]
[InlineData(typeof(AlarmTriggerType), new[] { "ValueMatch", "RangeViolation", "RateOfChange" })]
[InlineData(typeof(ConnectionHealth), new[] { "Connected", "Disconnected", "Connecting", "Error" })]
public void Enum_ShouldHaveExpectedValues(Type enumType, string[] expectedNames)
{
var actualNames = Enum.GetNames(enumType);
Assert.Equal(expectedNames, actualNames);
}
[Theory]
[InlineData(typeof(DataType))]
[InlineData(typeof(InstanceState))]
[InlineData(typeof(DeploymentStatus))]
[InlineData(typeof(AlarmState))]
[InlineData(typeof(AlarmTriggerType))]
[InlineData(typeof(ConnectionHealth))]
public void Enum_ShouldBeSingularNamed(Type enumType)
{
// Singular names should not end with 's' (except 'Status' which is singular)
var name = enumType.Name;
Assert.False(name.EndsWith("es") && !name.EndsWith("Status"),
$"Enum {name} appears to be plural (ends with 'es').");
Assert.False(name.EndsWith("s") && !name.EndsWith("ss") && !name.EndsWith("us"),
$"Enum {name} appears to be plural (ends with 's').");
}
}

View File

@@ -0,0 +1,75 @@
using ScadaLink.Commons.Types;
namespace ScadaLink.Commons.Tests.Types;
public class ResultTests
{
[Fact]
public void Success_ShouldCreateSuccessfulResult()
{
var result = Result<int>.Success(42);
Assert.True(result.IsSuccess);
Assert.False(result.IsFailure);
Assert.Equal(42, result.Value);
}
[Fact]
public void Failure_ShouldCreateFailedResult()
{
var result = Result<int>.Failure("something went wrong");
Assert.True(result.IsFailure);
Assert.False(result.IsSuccess);
Assert.Equal("something went wrong", result.Error);
}
[Fact]
public void Value_OnFailure_ShouldThrow()
{
var result = Result<int>.Failure("error");
Assert.Throws<InvalidOperationException>(() => result.Value);
}
[Fact]
public void Error_OnSuccess_ShouldThrow()
{
var result = Result<int>.Success(42);
Assert.Throws<InvalidOperationException>(() => result.Error);
}
[Fact]
public void Match_OnSuccess_ShouldCallOnSuccess()
{
var result = Result<int>.Success(42);
var output = result.Match(
v => $"value={v}",
e => $"error={e}");
Assert.Equal("value=42", output);
}
[Fact]
public void Match_OnFailure_ShouldCallOnFailure()
{
var result = Result<int>.Failure("bad");
var output = result.Match(
v => $"value={v}",
e => $"error={e}");
Assert.Equal("error=bad", output);
}
[Fact]
public void Success_WithNullableReferenceType_ShouldWork()
{
var result = Result<string>.Success("hello");
Assert.True(result.IsSuccess);
Assert.Equal("hello", result.Value);
}
}

View File

@@ -0,0 +1,35 @@
using ScadaLink.Commons.Types;
namespace ScadaLink.Commons.Tests.Types;
public class RetryPolicyTests
{
[Fact]
public void RetryPolicy_ShouldBeImmutableRecord()
{
var policy = new RetryPolicy(3, TimeSpan.FromSeconds(5));
Assert.Equal(3, policy.MaxRetries);
Assert.Equal(TimeSpan.FromSeconds(5), policy.Delay);
}
[Fact]
public void RetryPolicy_WithExpression_ShouldCreateNewInstance()
{
var original = new RetryPolicy(3, TimeSpan.FromSeconds(5));
var modified = original with { MaxRetries = 5 };
Assert.Equal(3, original.MaxRetries);
Assert.Equal(5, modified.MaxRetries);
Assert.Equal(original.Delay, modified.Delay);
}
[Fact]
public void RetryPolicy_EqualValues_ShouldBeEqual()
{
var a = new RetryPolicy(3, TimeSpan.FromSeconds(5));
var b = new RetryPolicy(3, TimeSpan.FromSeconds(5));
Assert.Equal(a, b);
}
}