119 lines
3.5 KiB
C#
119 lines
3.5 KiB
C#
namespace ScadaLink.InboundAPI.Tests;
|
|
|
|
/// <summary>
|
|
/// InboundAPI-014: tests for return-value validation against a method's
|
|
/// <c>ReturnDefinition</c>. Previously the script's return value was serialized
|
|
/// verbatim with no checking against the declared return structure.
|
|
/// </summary>
|
|
public class ReturnValueValidatorTests
|
|
{
|
|
// --- No definition → no validation (backward compatible) ---
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void NoReturnDefinition_AnythingIsValid(string? returnDefinition)
|
|
{
|
|
var result = ReturnValueValidator.Validate("{\"anything\":1}", returnDefinition);
|
|
Assert.True(result.IsValid);
|
|
}
|
|
|
|
[Fact]
|
|
public void NoReturnDefinition_NullResult_IsValid()
|
|
{
|
|
var result = ReturnValueValidator.Validate(null, null);
|
|
Assert.True(result.IsValid);
|
|
}
|
|
|
|
// --- Happy path: result matches the declared field shape ---
|
|
|
|
[Fact]
|
|
public void ResultMatchingDefinition_IsValid()
|
|
{
|
|
const string def = """[{"name":"siteName","type":"String"},{"name":"totalUnits","type":"Integer"}]""";
|
|
const string json = """{"siteName":"Site Alpha","totalUnits":14250}""";
|
|
|
|
var result = ReturnValueValidator.Validate(json, def);
|
|
|
|
Assert.True(result.IsValid);
|
|
}
|
|
|
|
[Fact]
|
|
public void ResultWithListField_ShapeChecked_IsValid()
|
|
{
|
|
const string def = """[{"name":"lines","type":"List"}]""";
|
|
const string json = """{"lines":[{"lineName":"Line-1","units":8200}]}""";
|
|
|
|
var result = ReturnValueValidator.Validate(json, def);
|
|
|
|
Assert.True(result.IsValid);
|
|
}
|
|
|
|
// --- Mismatches must be reported ---
|
|
|
|
[Fact]
|
|
public void ResultMissingDeclaredField_IsInvalid()
|
|
{
|
|
const string def = """[{"name":"siteName","type":"String"},{"name":"totalUnits","type":"Integer"}]""";
|
|
const string json = """{"siteName":"Site Alpha"}""";
|
|
|
|
var result = ReturnValueValidator.Validate(json, def);
|
|
|
|
Assert.False(result.IsValid);
|
|
Assert.Contains("totalUnits", result.ErrorMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public void ResultFieldWrongType_IsInvalid()
|
|
{
|
|
const string def = """[{"name":"totalUnits","type":"Integer"}]""";
|
|
const string json = """{"totalUnits":"not-a-number"}""";
|
|
|
|
var result = ReturnValueValidator.Validate(json, def);
|
|
|
|
Assert.False(result.IsValid);
|
|
Assert.Contains("totalUnits", result.ErrorMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public void NullResultWhenStructureRequired_IsInvalid()
|
|
{
|
|
const string def = """[{"name":"siteName","type":"String"}]""";
|
|
|
|
var result = ReturnValueValidator.Validate(null, def);
|
|
|
|
Assert.False(result.IsValid);
|
|
}
|
|
|
|
[Fact]
|
|
public void NonObjectResultWhenStructureRequired_IsInvalid()
|
|
{
|
|
const string def = """[{"name":"siteName","type":"String"}]""";
|
|
|
|
var result = ReturnValueValidator.Validate("42", def);
|
|
|
|
Assert.False(result.IsValid);
|
|
}
|
|
|
|
[Fact]
|
|
public void ListFieldGivenNonArray_IsInvalid()
|
|
{
|
|
const string def = """[{"name":"lines","type":"List"}]""";
|
|
const string json = """{"lines":"not-a-list"}""";
|
|
|
|
var result = ReturnValueValidator.Validate(json, def);
|
|
|
|
Assert.False(result.IsValid);
|
|
Assert.Contains("lines", result.ErrorMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public void MalformedReturnDefinition_IsInvalid()
|
|
{
|
|
var result = ReturnValueValidator.Validate("{\"x\":1}", "%%% not json %%%");
|
|
|
|
Assert.False(result.IsValid);
|
|
}
|
|
}
|