91 lines
3.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Text.Json;
using FluentAssertions;
using global::BuildFlow.Shared.Infrastructure.Serialization;
using Xunit;
namespace BuildFlow.Workflow.Tests.Serialization;
/// <summary>
/// 验证统一数据规范:DateTime / DateTimeOffset 序列化为 UTC 毫秒时间戳(long)。
/// 这是第二期"后端数据规范统一"的核心契约 —— 后端只输出毫秒时间戳,时区/格式化交给前端。
/// </summary>
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<SampleDto>(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<SampleDto>(json, BuildOptions())!;
dto.CreatedAt.Should().Be(new DateTime(2026, 6, 14, 3, 30, 0, DateTimeKind.Utc));
}
}