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 { ["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 { [9]=10 }, dic_weeklyTasks=new Dictionary { [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(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 { ["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(raw) { [key]="null" }; Check(PlayerKVSaveSchema.DecodeBattlePass(bad,SchemaSnapshot(),new())==null,"bad old not hidden by new"); } state=PlayerKVSaveSchema.DecodeBattlePass(new Dictionary(),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; }); } }