Files
yunhai.netcore.tool/BasePlatformDotnet/tests/Yh.Platform.Abstractions.Tests/ModelSerializationTests.cs
T
2026-09-02 09:38:45 +08:00

131 lines
4.9 KiB
C#

using System.IO;
using System.Text.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using JsonSerializer = System.Text.Json.JsonSerializer;
using Xunit;
using Yh.Platform.Abstractions;
namespace Yh.Platform.Abstractions.Tests;
public class ModelSerializationTests
{
private static JObject LoadFixtureBareData()
{
var path = Path.Combine(AppContext.BaseDirectory, "fixtures", "envelope-success.json");
return JObject.Parse(File.ReadAllText(path))["bareData"]!.Value<JObject>()!;
}
private static JObject LoadFixtureWrapped()
{
var path = Path.Combine(AppContext.BaseDirectory, "fixtures", "envelope-success.json");
return JObject.Parse(File.ReadAllText(path))["wrappedData"]!.Value<JObject>()!;
}
[Fact]
public void Newtonsoft_反序列化fixture_含currentRole嵌套()
{
var user = LoadFixtureBareData().ToObject<BoaUser>(new Newtonsoft.Json.JsonSerializer
{
// net5 消费方形态:ASP.NET Core AddNewtonsoftJson 默认大小写不敏感、保留属性名
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(),
});
Assert.Equal(1001, user!.Id);
Assert.Equal("zhangsan", user.Account);
Assert.Equal("张三", user.Name);
Assert.Equal(2, user.School!.Id);
Assert.Equal("云海第一中学", user.School.Name);
Assert.Equal(3, user.CurrentRole!.RoleId);
Assert.Equal("教师", user.CurrentRole.RoleName);
Assert.Equal("云海第一中学", user.CurrentRole.SchName);
Assert.Equal(21, user.CurrentRole.ChildId);
Assert.Equal(2, user.Schools!.Count);
Assert.Equal(new List<int> { 3, 5 }, user.RoleIds);
Assert.Equal(3, user.Groups!.Count);
}
[Fact]
public void Newtonsoft_默认设置_大小写不敏感匹配camelCase()
{
var user = LoadFixtureBareData().ToObject<BoaUser>();
Assert.Equal("zhangsan", user!.Account);
Assert.Equal("教师", user.CurrentRole!.RoleName);
}
[Fact]
public void SystemTextJson_Web序列化_与fixture逐节点一致()
{
var user = LoadFixtureBareData().ToObject<BoaUser>();
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web)
{
// 对齐 Java 侧 NON_NULL 语义
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
};
var json = JsonSerializer.Serialize(user, options);
// 语义等价:键序无关、null 节点差异容忍(fixture 中显式 null 与省略 null 视为一致)
Assert.True(JToken.DeepEquals(JObject.Parse(json), StripNulls(LoadFixtureBareData())),
"STJ 序列化结果应与 fixture 语义一致\n" + json);
}
private static JObject StripNulls(JObject obj)
{
var clone = (JObject)obj.DeepClone();
var toRemove = new List<JProperty>();
CollectNullProps(clone, toRemove);
foreach (var p in toRemove)
{
p.Remove();
}
return clone;
}
private static void CollectNullProps(JToken token, List<JProperty> collected)
{
foreach (var child in token.Children())
{
if (child is JProperty p)
{
if (p.Value.Type == JTokenType.Null)
{
collected.Add(p);
continue;
}
CollectNullProps(p.Value, collected);
}
else if (child.Type is JTokenType.Object or JTokenType.Array)
{
CollectNullProps(child, collected);
}
}
}
[Fact]
public void SystemTextJson_反序列化信封包裹成功样例()
{
var wrapped = LoadFixtureWrapped();
var envelope = wrapped.ToObject<ApiEnvelope<BoaUser>>(new Newtonsoft.Json.JsonSerializer
{
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(),
});
Assert.True(envelope!.IsSuccess);
Assert.Equal(0, envelope.Code);
Assert.Equal(1001, envelope.Data!.Id);
}
[Fact]
public void BoaApp_Models_双序列化往返()
{
var app = new BoaApp { Id = 7, Name = "作业提交", Clients = (int)ClientEnum.PcBrowser | (int)ClientEnum.MobileApp, IsPublic = false, BuiltInTag = 0 };
var stj = JsonSerializer.Deserialize<BoaApp>(JsonSerializer.Serialize(app, new JsonSerializerOptions(JsonSerializerDefaults.Web)), new JsonSerializerOptions(JsonSerializerDefaults.Web));
var nf = JObject.Parse(JsonConvert.SerializeObject(app, new JsonSerializerSettings { ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() })).ToObject<BoaApp>();
Assert.Equal(app.Name, stj!.Name);
Assert.Equal(app.Clients, stj.Clients);
Assert.Equal(app.Name, nf!.Name);
Assert.Equal(false, nf.IsPublic);
}
}