VEU.WathBody/3-app/2-cli/Server.WatchBody.Web.Tests/UnitTests.cs

111 lines
3.9 KiB
C#

using System.Text;
using Server.WatchBody.Web.Config;
using Server.WatchBody.Web.Dto;
using Xunit;
namespace Server.WatchBody.Web.Tests;
/// <summary>Юнит-тесты: валидация конфига и парсер пакета sync (без БД).</summary>
public class UnitTests
{
private static ServerConfig Valid() => new()
{
ApiKey = "owner",
DbConnectionString = "Host=x",
Athletes = [new ConfigAthlete { Name = "A", ApiKey = "k1" }],
};
[Fact]
public void Config_EmptyApiKey_IsError()
{
var config = Valid();
config.ApiKey = "";
Assert.Contains(config.Validate(), e => e.Contains("Api.Key"));
}
[Fact]
public void Config_DuplicateAthleteKeys_IsError()
{
var config = Valid();
config.Athletes.Add(new ConfigAthlete { Name = "B", ApiKey = "k1" });
Assert.Contains(config.Validate(), e => e.Contains("дубликат"));
}
[Fact]
public void Config_AthleteKeyEqualsOwnerKey_IsError()
{
var config = Valid();
config.Athletes[0].ApiKey = "owner";
Assert.NotEmpty(config.Validate());
}
[Fact]
public void Config_Valid_NoErrors() => Assert.Empty(Valid().Validate());
[Fact]
public void Parser_NotArray_Rejected()
{
Assert.Throws<SyncException>(() => SyncItemParser.Parse("""{"client_guid":"..."}"""));
}
[Fact]
public void Parser_UnknownEntity_Rejected()
{
Assert.Throws<SyncException>(() => SyncItemParser.Parse(
"""[{"client_guid":"0b8f6e2a-1111-4222-8333-444455556666","entity":"nonsense","op":"upsert","data":{}}]"""));
}
[Fact]
public void Parser_BadOp_Rejected()
{
Assert.Throws<SyncException>(() => SyncItemParser.Parse(
"""[{"client_guid":"0b8f6e2a-1111-4222-8333-444455556666","entity":"daily_log","op":"delete","data":{}}]"""));
}
[Fact]
public void Parser_PackageOver50_Rejected()
{
var sb = new StringBuilder("[");
for (var i = 0; i < 51; i++)
{
if (i > 0) sb.Append(',');
sb.Append($$"""{"client_guid":"0b8f6e2a-0000-4000-8000-{{i:D12}}","entity":"daily_log","op":"upsert","data":{"date":"2026-10-17" } }""");
}
sb.Append(']');
Assert.Throws<SyncException>(() => SyncItemParser.Parse(sb.ToString()));
}
[Fact]
public void Parser_BreakSourceAuto_Rejected()
{
Assert.Throws<SyncException>(() => SyncItemParser.Parse(
"""[{"client_guid":"0b8f6e2a-1111-4222-8333-444455556666","entity":"break","op":"upsert","data":{"started_on":"2026-10-01","source":"auto"}}]"""));
}
[Fact]
public void Parser_RpeOutOfRange_Rejected()
{
Assert.Throws<SyncException>(() => SyncItemParser.Parse(
"""[{"client_guid":"0b8f6e2a-1111-4222-8333-444455556666","entity":"workout_set","op":"upsert","data":{"workout_id":"0b8f6e2a-1111-4222-8333-444455557777","seq":1,"weight_kg":50,"reps":10,"done_at":"2026-10-17T10:05:00Z","source":"voice","in_plan":true,"rpe":11}}]"""));
}
[Fact]
public void Parser_MissingRequiredField_Rejected()
{
Assert.Throws<SyncException>(() => SyncItemParser.Parse(
"""[{"client_guid":"0b8f6e2a-1111-4222-8333-444455556666","entity":"workout","op":"upsert","data":{"status":"active"}}]"""));
}
[Fact]
public void Parser_ValidPackage_Parses()
{
var items = SyncItemParser.Parse(
"""[{"client_guid":"0b8f6e2a-1111-4222-8333-444455556666","entity":"profile","op":"upsert","data":{"sex":"m","birth_year":1980,"weight_kg":85.5,"hr_max":185}}]""");
var item = Assert.Single(items);
Assert.Equal("profile", item.Entity);
Assert.Equal("m", SyncItemParser.StringOrNull(item.Data, "sex"));
Assert.Equal(1980, SyncItemParser.IntOrNull(item.Data, "birth_year"));
Assert.Equal(85.5m, SyncItemParser.DecimalOrNull(item.Data, "weight_kg"));
}
}