2026-08-17 09:24:57 +08:00
|
|
|
|
namespace Gpulse.WCT.DataAnalyzer.Tests.Commands;
|
|
|
|
|
|
|
|
|
|
|
|
[TestFixture]
|
|
|
|
|
|
public class AnalyzeCommandTests : CommandTestBase
|
|
|
|
|
|
{
|
|
|
|
|
|
[Test]
|
|
|
|
|
|
public async Task Analyze_NoType_ReturnsValidationError()
|
|
|
|
|
|
{
|
|
|
|
|
|
var (code, stdout, stderr) = await Analyze().RunCaptureAsync();
|
|
|
|
|
|
|
|
|
|
|
|
Assert.Multiple(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
Assert.That(code, Is.EqualTo(1));
|
|
|
|
|
|
Assert.That(stdout + stderr, Does.Contain("--type"));
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
|
public async Task Analyze_UnknownType_PrintsMessage()
|
|
|
|
|
|
{
|
|
|
|
|
|
var (code, stdout, _) = await Analyze().RunCaptureAsync("--type", "foo");
|
|
|
|
|
|
|
|
|
|
|
|
Assert.Multiple(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
Assert.That(code, Is.EqualTo(0));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("Unknown type: foo. Use 'ploss' or 'qfod'."));
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
|
public async Task Analyze_Ploss_MissingFile_PrintsPrompt()
|
|
|
|
|
|
{
|
|
|
|
|
|
var (_, stdout, _) = await Analyze().RunCaptureAsync("--type", "ploss");
|
|
|
|
|
|
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("Please specify --file for Ploss analysis"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
|
public async Task Analyze_Ploss_ValidTwoLineFile_ReportsSummary()
|
|
|
|
|
|
{
|
|
|
|
|
|
var dir = NewDir();
|
|
|
|
|
|
var file = TestFixtures.WritePlossLog(dir, TestFixtures.PlossFileName,
|
|
|
|
|
|
// 正常两行:margin = 3000-500 = 2500 > 2000,恒等式成立
|
|
|
|
|
|
new TestFixtures.PlossTwoLineRow(),
|
|
|
|
|
|
// FOD 两行:ploss=2500 threshold=3000 margin=500,恒等式成立,delta_p'=2500+2001+2500-3000=4001
|
|
|
|
|
|
new TestFixtures.PlossTwoLineRow(Field5: 8000, Field9: 2500, Field10: 3000, Field12: 1));
|
|
|
|
|
|
|
|
|
|
|
|
var (code, stdout, _) = await Analyze().RunCaptureAsync("--type", "ploss", "--file", file);
|
|
|
|
|
|
|
|
|
|
|
|
Assert.Multiple(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
Assert.That(code, Is.EqualTo(0));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("=== Ploss Analysis:"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("Total: 2 (TwoLine: 2, Legacy: 0), FOD: 1, Errors: 0"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("Normal margin>2000: 1/1 (100.0%)"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("FOD margin>2000: 0/1 (0.0%)"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("Identity (delta_p = Tx - Rx - pow_loss - ploss): 2/2"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("delta_p'=4001"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("rewrite: pow_loss = 2200, delta_p = 4001"));
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
|
public async Task Analyze_Ploss_LegacyFile_CountsLegacyRows()
|
|
|
|
|
|
{
|
|
|
|
|
|
var dir = NewDir();
|
|
|
|
|
|
var file = TestFixtures.WriteLegacyPlossLog(
|
|
|
|
|
|
dir, "singleMold-v1.0-hex2_1-iPhone15-ploss_legacy-20260710-1.log",
|
|
|
|
|
|
(500, 3000, 0), (2500, 3000, 1));
|
|
|
|
|
|
|
|
|
|
|
|
var (code, stdout, _) = await Analyze().RunCaptureAsync("--type", "ploss", "--file", file);
|
|
|
|
|
|
|
|
|
|
|
|
Assert.Multiple(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
Assert.That(code, Is.EqualTo(0));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("Total: 2 (TwoLine: 0, Legacy: 2), FOD: 1, Errors: 0"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("Normal margin>2000: 1/1 (100.0%)"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("FOD margin>2000: 0/1 (0.0%)"));
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
|
public async Task Analyze_Qfod_MissingArgs_PrintsPrompt()
|
|
|
|
|
|
{
|
|
|
|
|
|
var (_, stdout, _) = await Analyze().RunCaptureAsync("--type", "qfod");
|
|
|
|
|
|
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("Please specify --pure and --foreign for Qfod calibration"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-17 10:47:33 +08:00
|
|
|
|
[Test]
|
|
|
|
|
|
public async Task Analyze_Ploss_LegacyFile_HexField1_DecodedCorrectly()
|
|
|
|
|
|
{
|
|
|
|
|
|
var dir = NewDir();
|
|
|
|
|
|
// 旧单行格式 Field1=0C (十六进制) 应被解析为十进制 12
|
|
|
|
|
|
var file = TestFixtures.WriteLegacyPlossLog(
|
|
|
|
|
|
dir,
|
|
|
|
|
|
"singleMold-v1.0-hex2_1-iPhone15-ploss_legacy-20260710-1.log",
|
|
|
|
|
|
new (int, int, int)[] { (500, 3000, 0) },
|
|
|
|
|
|
field1Hex: "0C");
|
|
|
|
|
|
|
|
|
|
|
|
var (code, stdout, _) = await Analyze().RunCaptureAsync("--type", "ploss", "--file", file);
|
|
|
|
|
|
|
|
|
|
|
|
Assert.Multiple(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
Assert.That(code, Is.EqualTo(0));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("Total: 1 (TwoLine: 0, Legacy: 1), FOD: 0, Errors: 0"));
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-17 09:24:57 +08:00
|
|
|
|
[Test]
|
|
|
|
|
|
public async Task Analyze_Qfod_ValidFiles_ReportsThreshold()
|
|
|
|
|
|
{
|
|
|
|
|
|
var dir = NewDir();
|
|
|
|
|
|
var pure = TestFixtures.WriteQfodLog(
|
|
|
|
|
|
dir, "singleMold-v1.0-hex2_1-iPhone15-qfod_pure-20260710-1.log", 20, 25, 21);
|
|
|
|
|
|
var foreign = TestFixtures.WriteQfodLog(
|
|
|
|
|
|
dir, "singleMold-v1.0-hex2_1-iPhone15-qfod_foreign-20260710-1.log", 42, 40, 45);
|
|
|
|
|
|
|
|
|
|
|
|
var (code, stdout, _) = await Analyze().RunCaptureAsync("--type", "qfod", "--pure", pure, "--foreign", foreign);
|
|
|
|
|
|
|
|
|
|
|
|
Assert.Multiple(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
Assert.That(code, Is.EqualTo(0));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("=== Qfod Calibration ==="));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("Pure phone"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("Foreign object"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("count=3 min=20 max=25 avg=22.0"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("count=3 min=40 max=45 avg=42.3"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("Threshold = (pureMax + foreignMin) / 2 = (25 + 40) / 2 = 32"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("pureMax - threshold = -7"));
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("foreignMin - threshold = 8"));
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
|
public async Task Analyze_Qfod_MissingFile_ReportsFailure()
|
|
|
|
|
|
{
|
|
|
|
|
|
var dir = NewDir();
|
|
|
|
|
|
var foreign = TestFixtures.WriteQfodLog(
|
|
|
|
|
|
dir, "singleMold-v1.0-hex2_1-iPhone15-qfod_foreign-20260710-1.log", 42, 40);
|
|
|
|
|
|
|
|
|
|
|
|
var (_, stdout, _) = await Analyze().RunCaptureAsync(
|
|
|
|
|
|
"--type", "qfod",
|
|
|
|
|
|
"--pure", Path.Combine(dir, "nope.log"),
|
|
|
|
|
|
"--foreign", foreign);
|
|
|
|
|
|
|
|
|
|
|
|
Assert.That(stdout, Does.Contain("FAILED"));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|