using System.Text.Json;
using FluentAssertions;
using Workflow.Api.Serialization;
using Xunit;
namespace Workflow.Tests.Serialization;
///
/// 验证统一数据规范:DateTime / DateTimeOffset 序列化为 UTC 毫秒时间戳(long)。
/// 这是第二期"后端数据规范统一"的核心契约 —— 后端只输出毫秒时间戳,时区/格式化交给前端。
///
public class TimestampJsonConverterTests
{
private static JsonSerializerOptions BuildOptions() => new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters = { new TimestampDateTimeConverter(), new TimestampDateTimeOffsetConverter() }
};
private class SampleDto
{
public Guid Id { get; set; }
public DateTime CreatedAt { get; set; }
public DateTimeOffset? UpdatedAt { get; set; }
}
[Fact]
public void DateTime_serializes_to_millisecond_epoch_number()
{
// 固定时刻:2026-06-14T03:30:00Z
var utc = new DateTime(2026, 6, 14, 3, 30, 0, DateTimeKind.Utc);
var expectedMs = new DateTimeOffset(utc, TimeSpan.Zero).ToUnixTimeMilliseconds();
var dto = new SampleDto { Id = Guid.NewGuid(), CreatedAt = utc };
var json = JsonSerializer.Serialize(dto, BuildOptions());
using var doc = JsonDocument.Parse(json);
doc.RootElement.GetProperty("createdAt").ValueKind.Should().Be(JsonValueKind.Number);
doc.RootElement.GetProperty("createdAt").GetInt64().Should().Be(expectedMs);
}
[Fact]
public void DateTimeOffset_serializes_to_millisecond_epoch_number()
{
var dto = new DateTimeOffset(2026, 1, 2, 3, 4, 5, TimeSpan.Zero);
var expectedMs = dto.ToUnixTimeMilliseconds();
var json = JsonSerializer.Serialize(new { t = dto }, BuildOptions());
using var doc = JsonDocument.Parse(json);
doc.RootElement.GetProperty("t").GetInt64().Should().Be(expectedMs);
}
[Fact]
public void Guid_serializes_as_string()
{
// 验证 ID 统一为字符串(Guid 天然序列化为字符串,无需额外转换器)
var id = Guid.NewGuid();
var dto = new SampleDto { Id = id };
var json = JsonSerializer.Serialize(dto, BuildOptions());
using var doc = JsonDocument.Parse(json);
doc.RootElement.GetProperty("id").ValueKind.Should().Be(JsonValueKind.String);
doc.RootElement.GetProperty("id").GetGuid().Should().Be(id);
}
[Fact]
public void Deserializes_epoch_number_back_to_utc_dateTime()
{
var utc = new DateTime(2026, 6, 14, 3, 30, 0, DateTimeKind.Utc);
var ms = new DateTimeOffset(utc, TimeSpan.Zero).ToUnixTimeMilliseconds();
var json = $$"""{"id":"00000000-0000-0000-0000-000000000000","createdAt":{{ms}}}""";
var dto = JsonSerializer.Deserialize(json, BuildOptions())!;
dto.CreatedAt.Should().Be(utc);
dto.CreatedAt.Kind.Should().Be(DateTimeKind.Utc);
}
[Fact]
public void Deserializes_legacy_iso_string_for_backward_compatibility()
{
// 旧客户端/旧数据可能仍是 ISO 字符串,必须能读回(向后兼容)
var json = """{"id":"00000000-0000-0000-0000-000000000000","createdAt":"2026-06-14T03:30:00Z"}""";
var dto = JsonSerializer.Deserialize(json, BuildOptions())!;
dto.CreatedAt.Should().Be(new DateTime(2026, 6, 14, 3, 30, 0, DateTimeKind.Utc));
}
}