test(upserver): 归档存档迁移与玩法闭环回归工具

This commit is contained in:
Liubing\LB
2026-09-28 18:16:14 +08:00
parent c4ae02def9
commit a6f5e107f8
232 changed files with 12903 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
using game.PlayerDataStorage;
using Newtonsoft.Json;
static partial class Tests
{
static async Task RunBattlePassSchemaTests()
{
await Run("M11-battle-pass-two-layouts-conflict-and-ticks",() =>
{
var raw=new Dictionary<string,string> { ["BattlePassRecordTask"]="1|2|3|4|1|5,6|7,8#9:10|11:12|13,14|15|16" };
var state=PlayerKVSaveSchema.DecodeBattlePass(raw,SchemaSnapshot(),new());
var r=state.Record; var t=state.Task;
Check(r.ID==1 && r.Level==2 && r.Exp==3 && r.BuyVipToastIndex==4 && r.IsUnlockVip==1 &&
r.Normal.SequenceEqual(new[] { 5,6 }) && r.Vip.SequenceEqual(new[] { 7,8 }) && r.LastDrops.Count==0 && r.Inflation==0,"all compact record fields");
Check(t.Daily[9]==10 && t.Weekly[11]==12 && t.LoginDays.SequenceEqual(new[] { 13,14 }) &&
t.DailyEnd.Ticks==15 && t.WeeklyEnd.Ticks==16,"all compact task fields");
raw["BattlePassRecord"]=JsonConvert.SerializeObject(new { ID=1,Level=2,Exp=3,BuyVipToastIndex=4,IsUnlockVip=1,
NormalRewardGet=new[] { 5,6 },VipRewardGet=new[] { 7,8 },LastDropIDs=new[] { 99 },InflationRate=2.5f });
raw["BattleTask"]=JsonConvert.SerializeObject(new { dic_dailyTasks=new Dictionary<int,int> { [9]=10 },
dic_weeklyTasks=new Dictionary<int,int> { [11]=12 },loginDays=new[] { 13,14 },DailyTaskEndTime=new DateTime(15),WeeklyTaskEndTime=new DateTime(16) });
state=PlayerKVSaveSchema.DecodeBattlePass(raw,SchemaSnapshot(),new());
Check(state!=null && state.Record.LastDrops.Count==0,"new whole record with absent old-only fields");
var legacy=new Dictionary<string,string>(raw); legacy.Remove("BattlePassRecordTask");
state=PlayerKVSaveSchema.DecodeBattlePass(legacy,SchemaSnapshot(),new());
Check(state.Record.LastDrops.SequenceEqual(new[] { 99 }) && state.Record.Inflation==2.5f,"old-only fields retained when old selected");
raw["BattlePassRecordTask"]="1|2|3|4|1|5,6|7,8#9:99|11:12|13,14|15|16";
var e=new PlayerKVSchemaDiagnostics();
Check(PlayerKVSaveSchema.DecodeBattlePass(raw,SchemaSnapshot(),e)==null && e.Count(11,PlayerKVSchemaError.ConflictingRepresentations)==1,"task conflict");
foreach(var text in new[] { "1|2|3|4|1||#|||0|0#", "1|2|3|4|1|5,|#|||0|0", "1|2|3|4|1||#1:2,01:3|||0|0",
"1|2|3|4|1||#|||-1|0", "1|2|3|4|1||#|||3155378976000000000|0", "null" })
Check(PlayerKVSaveSchema.DecodeBattlePass(new Dictionary<string,string> { ["BattlePassRecordTask"]=text },SchemaSnapshot(),new())==null,"malformed compact/ticks reject");
raw["BattlePassRecordTask"]="1|2|3|4|1|5,6|7,8#9:10|11:12|13,14|15|16";
foreach(var key in new[] { "BattlePassRecord","BattleTask" })
{
var bad=new Dictionary<string,string>(raw) { [key]="null" };
Check(PlayerKVSaveSchema.DecodeBattlePass(bad,SchemaSnapshot(),new())==null,"bad old not hidden by new");
}
state=PlayerKVSaveSchema.DecodeBattlePass(new Dictionary<string,string>(),SchemaSnapshot(),new());
Check(state.Record.ID==0 && state.Record.Level==1 && state.Record.Normal.Count==0 && state.Record.Vip.Count==0 &&
state.Record.LastDrops.Count==0 && state.Task.Daily.Count==0 && state.Task.Weekly.Count==0 && state.Task.LoginDays.Count==0 &&
state.Task.DailyEnd==default && state.Task.WeeklyEnd==default,"missing constructor state");
return Task.CompletedTask;
});
}
}