191 lines
9.7 KiB
C#
191 lines
9.7 KiB
C#
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 test = new PowerTest(new FixedPowerSupply()) { 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); // 通流电流来自 Modbus(Iin = 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.5, row.PowerLossW, 6);
|
||
Assert.Equal(91.666667, row.EfficiencyPct, 5);
|
||
});
|
||
Assert.Equal(24, sspc.TurnOffCount);
|
||
Assert.Equal(0, sspc.ReadMeasurementCount);
|
||
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 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) => throw new InvalidOperationException();
|
||
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 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) => throw new InvalidOperationException();
|
||
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
|