using System.Security.Cryptography; using System.Text.Json; using Microsoft.UI.Xaml.Automation.Peers; using Microsoft.UI.Xaml.Automation.Provider; using XFEEDToolBox.Controls; using XFEEDToolBox.Core.Models; using XFEEDToolBox.Views; namespace XFEEDToolBox; public partial class App { private static async Task RunMarketCacheSettingsProbeAsync(string directory) { var exercise=Environment.GetCommandLineArgs().Contains("--exercise-fixture-cache-clear"); var fixturePath=Path.GetFullPath(Path.Combine(directory,"isolated-data")); if(exercise&&(!ViewModel.OfflinePreview||!Path.GetFullPath(Runtime.DataDirectory).Equals(fixturePath,StringComparison.OrdinalIgnoreCase))) throw new InvalidOperationException("Cache cleanup acceptance may mutate only its explicit offline report-directory fixture."); await File.WriteAllTextAsync(Path.Combine(directory,"requirements.json"),JsonSerializer.Serialize(new{requirements=new[]{ new{id="identity",kind="behavior",description="清楚区分隔离清理夹具与真实数据目录,只在显式隔离夹具执行删除。"}, new{id="scope",kind="text",description="显示真实占用、默认500ly与可选中心的规则、旧存量与个人数据保留说明。"}, new{id="clear",kind="behavior",description="实际按钮清理夹具行情及旧备份,并显示结果;生产只读取图不据此声称大库已清理。"}, new{id="guard",kind="behavior",description="运行状态禁用清理,恢复可用后仅清除行情数据,设置、事件与交易记录字节保持。"}, new{id="layout",kind="layout",description="宽窗和窄窗中说明、占用、按钮及状态无重叠与不可访问裁切。"} }},new JsonSerializerOptions{WriteIndented=true})); var checks=new List();var captures=new List();var protectedFiles=new Dictionary(); void Check(string item,bool passed,string evidence) {checks.Add(new{item,passed,evidence});if(!passed)throw new InvalidOperationException(item+": "+evidence);} static string Hash(string path) { using var bytes=new FileStream(path,FileMode.Open,FileAccess.Read,FileShare.ReadWrite|FileShare.Delete); return Convert.ToHexStringLower(SHA256.HashData(bytes)); } var legacy=Path.Combine(Runtime.DataDirectory,"markets.db.verified.db"); const long fixtureStation=7000000000001; if(exercise) { Runtime.Settings.Save(Runtime.SettingsPath); var history=Path.Combine(Runtime.DataDirectory,"trade-ledgers");Directory.CreateDirectory(history); var sentinel=Path.Combine(history,"cache-probe-preserve.json");await File.WriteAllTextAsync(sentinel,"{\"fixture\":true}"); foreach(var file in new[]{Runtime.SettingsPath,Path.Combine(Runtime.DataDirectory,"game-events.db"),sentinel}) if(File.Exists(file))protectedFiles[file]=Hash(file); var now=DateTimeOffset.UtcNow; var station=new Station{MarketId=fixtureStation,Name="Cache fixture",SystemName="Isolated fixture",Position=new(0,0,0),UpdatedAt=now}; var seeded=await Runtime.Markets.SaveSnapshotAsync(new(station,[new CommodityQuote{MarketId=fixtureStation,Commodity="fixture",DisplayName="Cache fixture",BuyPrice=1,SellPrice=2,CollectedAt=now,Source=DataSource.Journal}],now,DataSource.Journal)); Check("the explicit local-market fixture was seeded",seeded&&Runtime.Markets.GetStation(fixtureStation) is not null,"This is synthetic offline cache data using the local-observation bypass, never a live Journal or game transaction."); await File.WriteAllBytesAsync(legacy,new byte[1024*1024]); } AppShellPage.Current!.Navigate(typeof(SettingPage));await Task.Delay(180); var page=(SettingPage)AppShellPage.Current.CurrentPage!; var data=(CommunityToolkit.WinUI.Controls.SettingsExpander)page.FindName("DataSettings");data.IsExpanded=true; await ViewModel.RefreshMarketCacheUsageCommand.ExecuteAsync(null);await Task.Delay(140);page.UpdateLayout(); var card=(FrameworkElement)page.FindName("MarketCacheCard"); var scroll=(ScrollViewer)page.FindName("SettingsScrollViewer"); var button=Descendants(page).OfType