SSPC-Tester/SSPCTester.Tests/InterfacePowerTests.cs
2026-07-03 14:16:15 +08:00

204 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.Extensions.Options;
using SSPCTester.Devices.Config;
using SSPCTester.Devices.Interfaces;
using SSPCTester.Logic.Models;
using SSPCTester.Logic.Testing;
namespace SSPCTester.Tests;
#pragma warning disable CS0067
public sealed class InterfacePowerTests
{
[Fact]
public async Task PowerTest_UsesUdpInputAndIt8702pOutputPower()
{
var project = new Project();
var sspc = new MeasuringSspc();
var forbiddenPower = new ForbiddenPowerSupply();
var load = new MeasuringLoad();
var daq = new MeasuringDaq();
var options = Options.Create(new DeviceOptions
{
Daq = new DaqOptions
{
ChannelCount = 1,
Channels = new List<DaqChannelOptions>
{
new() { PhysicalChannel = 0, Role = nameof(DaqChannelRole.OutputVoltage), IsCalibrated = true },
}
}
});
var power = new FixedPowerSupply();
var test = new PowerTest(power) { SamplesPerChannel = 1, IntervalMs = 0 };
var context = new TestContext(project, sspc, forbiddenPower, load, daq);
await test.RunAsync(context, new Progress<TestProgress>(), CancellationToken.None);
Assert.Equal(24, project.PowerResults.Count);
Assert.All(project.PowerResults, row =>
{
Assert.Equal(TestStatus.Measured, row.Status);
Assert.Equal(30.0, row.Vin, 6); // 输入端电压来自高速采集卡
Assert.Equal(1.0, row.Iin, 6); // 通流电流来自 ModbusIin = Iout
Assert.Equal(28.0, row.Vout, 6); // 输出端电压来自 Modbus
Assert.Equal(1.0, row.Iout, 6);
Assert.Equal(27.5, row.MeasuredPowerOut.GetValueOrDefault(), 6);
Assert.Equal(2.0, row.PowerLossW, 6);
Assert.Equal(93.333333, row.EfficiencyPct, 5);
});
Assert.Equal(0, sspc.TurnOffCount);
Assert.Equal(0, sspc.ReadMeasurementCount);
Assert.Equal(1, power.OutputOnCount);
Assert.Equal(1, load.InputOnCount);
Assert.Equal(24, load.ReadPowerCount);
Assert.Equal(0, daq.ReadInstantCount);
}
[Fact]
public void PowerLossRow_FallsBackToCalculatedOutputPower()
{
var row = new PowerLossRow { Vin = 30, Iin = 1, Vout = 28, Iout = 1 };
Assert.Equal(28, row.PowerOut, 6);
Assert.Equal(2, row.PowerLossW, 6);
}
private sealed class MeasuringSspc : ISspc
{
public int TurnOffCount { get; private set; }
public int ReadMeasurementCount { get; private set; }
public int ChannelCount => 24;
public bool IsConnected => true;
public string DisplayName => "test";
public event EventHandler<bool>? ConnectionChanged;
public Task<bool> ConnectAsync(CancellationToken ct = default) => Task.FromResult(true);
public Task DisconnectAsync() => Task.CompletedTask;
public Task TurnOnAsync(int physicalSlot, CancellationToken ct = default) => Task.CompletedTask;
public Task TurnOffAsync(int physicalSlot, CancellationToken ct = default) { TurnOffCount++; return Task.CompletedTask; }
public Task FlashAsync(int physicalSlot, int milliseconds, CancellationToken ct = default) => Task.CompletedTask;
public Task<bool> GetChannelStateAsync(int physicalSlot, CancellationToken ct = default) => Task.FromResult(true);
public Task<ChannelMeasurement> ReadMeasurementAsync(int physicalSlot, CancellationToken ct = default)
{
ReadMeasurementCount++;
return Task.FromResult(new ChannelMeasurement { PhysicalSlot = physicalSlot, Voltage = 28.0, Current = 1.0 });
}
public Task<IReadOnlyList<ChannelMeasurement>> ReadMeasurementsAsync(CancellationToken ct = default) =>
Task.FromResult<IReadOnlyList<ChannelMeasurement>>(Array.Empty<ChannelMeasurement>());
}
private sealed class MeasuringDaq : IDaq
{
public int ReadInstantCount { get; private set; }
public bool IsConnected { get; private set; }
public string DisplayName => "daq";
public event EventHandler<bool>? ConnectionChanged;
public event EventHandler<CurveSample>? SampleReceived;
public Task<bool> ConnectAsync(CancellationToken ct = default)
{
IsConnected = true;
ConnectionChanged?.Invoke(this, true);
return Task.FromResult(true);
}
public Task DisconnectAsync()
{
IsConnected = false;
ConnectionChanged?.Invoke(this, false);
return Task.CompletedTask;
}
public Task<IReadOnlyList<DaqDeviceDescriptor>> EnumerateDevicesAsync(CancellationToken ct = default) =>
Task.FromResult<IReadOnlyList<DaqDeviceDescriptor>>(Array.Empty<DaqDeviceDescriptor>());
public Task<CurveData> CaptureAsync(int[] channels, int sampleRateHz, double durationSec, CancellationToken ct = default) =>
throw new InvalidOperationException();
public Task<double[]> ReadInstantAsync(int[] channels, CancellationToken ct = default)
{
ReadInstantCount++;
// 采集卡输入端电压固定返回 30V。
var values = channels.Select(ch => ch == 0 ? 30.0 : double.NaN).ToArray();
return Task.FromResult(values);
}
public Task<CurveData> CaptureAroundActionAsync(DaqActionCaptureRequest request, Func<CancellationToken, Task> action, CancellationToken ct = default) =>
throw new InvalidOperationException();
}
private sealed class MeasuringLoad : ILoad
{
public int ReadPowerCount { get; private set; }
public int InputOnCount { get; private set; }
public bool IsConnected => true;
public string DisplayName => "it8702p";
public event EventHandler<bool>? ConnectionChanged;
public Task<bool> ConnectAsync(CancellationToken ct = default) => Task.FromResult(true);
public Task DisconnectAsync() => Task.CompletedTask;
public Task SetModeAsync(LoadMode mode, CancellationToken ct = default) => throw new InvalidOperationException();
public Task SetValueAsync(double value, CancellationToken ct = default) => throw new InvalidOperationException();
public Task InputAsync(bool on, CancellationToken ct = default)
{
if (on) InputOnCount++;
return Task.CompletedTask;
}
public Task<(double volts, double amps)> ReadAsync(CancellationToken ct = default) => Task.FromResult((28.0, 1.0));
public Task<PowerReading> ReadPowerAsync(CancellationToken ct = default)
{
ReadPowerCount++;
return Task.FromResult(new PowerReading(28.0, 1.0, 27.5));
}
public Task<string> QueryIdentityAsync(CancellationToken ct = default) => Task.FromResult("it8702p");
}
private sealed class FixedPowerSupply : IPowerSupply
{
public int OutputOnCount { get; private set; }
public bool IsConnected => true;
public string DisplayName => "fixed power";
public event EventHandler<bool>? ConnectionChanged;
public Task<bool> ConnectAsync(CancellationToken ct = default) => Task.FromResult(true);
public Task DisconnectAsync() => Task.CompletedTask;
public Task SetVoltageAsync(double volts, CancellationToken ct = default) => throw new InvalidOperationException();
public Task SetCurrentLimitAsync(double amps, CancellationToken ct = default) => throw new InvalidOperationException();
public Task OutputAsync(bool on, CancellationToken ct = default)
{
if (on) OutputOnCount++;
return Task.CompletedTask;
}
public Task<(double volts, double amps)> ReadAsync(CancellationToken ct = default) => Task.FromResult((30.0, 1.0));
public Task<string> QueryIdentityAsync(CancellationToken ct = default) => Task.FromResult("fixed");
}
private sealed class ForbiddenPowerSupply : IPowerSupply
{
public bool IsConnected => false;
public string DisplayName => "forbidden";
public event EventHandler<bool>? ConnectionChanged;
public Task<bool> ConnectAsync(CancellationToken ct = default) => throw new InvalidOperationException();
public Task DisconnectAsync() => Task.CompletedTask;
public Task SetVoltageAsync(double volts, CancellationToken ct = default) => throw new InvalidOperationException();
public Task SetCurrentLimitAsync(double amps, CancellationToken ct = default) => throw new InvalidOperationException();
public Task OutputAsync(bool on, CancellationToken ct = default) => throw new InvalidOperationException();
public Task<(double volts, double amps)> ReadAsync(CancellationToken ct = default) => throw new InvalidOperationException();
public Task<string> QueryIdentityAsync(CancellationToken ct = default) => throw new InvalidOperationException();
}
private sealed class ForbiddenLoad : ILoad
{
public bool IsConnected => false;
public string DisplayName => "forbidden";
public event EventHandler<bool>? ConnectionChanged;
public Task<bool> ConnectAsync(CancellationToken ct = default) => throw new InvalidOperationException();
public Task DisconnectAsync() => Task.CompletedTask;
public Task SetModeAsync(LoadMode mode, CancellationToken ct = default) => throw new InvalidOperationException();
public Task SetValueAsync(double value, CancellationToken ct = default) => throw new InvalidOperationException();
public Task InputAsync(bool on, CancellationToken ct = default) => throw new InvalidOperationException();
public Task<(double volts, double amps)> ReadAsync(CancellationToken ct = default) => throw new InvalidOperationException();
public Task<PowerReading> ReadPowerAsync(CancellationToken ct = default) => throw new InvalidOperationException();
public Task<string> QueryIdentityAsync(CancellationToken ct = default) => throw new InvalidOperationException();
}
}
#pragma warning restore CS0067