added unit tests
This commit is contained in:
@@ -0,0 +1 @@
|
||||
C:/Users/jasonross/.gemini/config/projects/5ff4f24c-d4a3-4a12-ba23-13f71a7b0b49.json
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0-windows10.0.19041.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
|
||||
<Platforms>x64</Platforms>
|
||||
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LibreHardwareMonitor.Windows.WinUI\LibreHardwareMonitor.Windows.WinUI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using LibreHardwareMonitor.Windows.WinUI.Services;
|
||||
using Windows.UI;
|
||||
using Xunit;
|
||||
|
||||
namespace LibreHardwareMonitor.Windows.WinUI.Tests.Services;
|
||||
|
||||
public class AppSettingsTests : IDisposable
|
||||
{
|
||||
private readonly AppSettings _settings;
|
||||
private readonly string _tempFile;
|
||||
|
||||
public AppSettingsTests()
|
||||
{
|
||||
_tempFile = Path.GetTempFileName();
|
||||
|
||||
// Use reflection to instantiate AppSettings with custom filename
|
||||
var ctor = typeof(AppSettings).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(string) }, null);
|
||||
_settings = (AppSettings)ctor.Invoke(new object[] { _tempFile });
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (File.Exists(_tempFile))
|
||||
{
|
||||
File.Delete(_tempFile);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FileName_ReturnsCorrectPath()
|
||||
{
|
||||
Assert.Equal(_tempFile, _settings.FileName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetAndGetString()
|
||||
{
|
||||
_settings.SetValue("testStr", "hello");
|
||||
Assert.True(_settings.Contains("testStr"));
|
||||
Assert.Equal("hello", _settings.GetValue("testStr", "default"));
|
||||
Assert.Equal("default", _settings.GetValue("missing", "default"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetAndGetInt()
|
||||
{
|
||||
_settings.SetValue("testInt", 42);
|
||||
Assert.Equal(42, _settings.GetValue("testInt", 0));
|
||||
Assert.Equal(10, _settings.GetValue("missing", 10));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetAndGetFloat()
|
||||
{
|
||||
_settings.SetValue("testFloat", 3.14f);
|
||||
Assert.Equal(3.14f, _settings.GetValue("testFloat", 0f));
|
||||
Assert.Equal(1.5f, _settings.GetValue("missing", 1.5f));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetAndGetDouble()
|
||||
{
|
||||
_settings.SetValue("testDouble", 3.14159);
|
||||
Assert.Equal(3.14159, _settings.GetValue("testDouble", 0d));
|
||||
Assert.Equal(1.5d, _settings.GetValue("missing", 1.5d));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetAndGetBool()
|
||||
{
|
||||
_settings.SetValue("testBool", true);
|
||||
Assert.True(_settings.GetValue("testBool", false));
|
||||
Assert.False(_settings.GetValue("missing", false));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetAndGetColor()
|
||||
{
|
||||
var color = Color.FromArgb(255, 100, 150, 200);
|
||||
_settings.SetValue("testColor", color);
|
||||
var retrievedColor = _settings.GetValue("testColor", Color.FromArgb(0, 0, 0, 0));
|
||||
|
||||
Assert.Equal(color.A, retrievedColor.A);
|
||||
Assert.Equal(color.R, retrievedColor.R);
|
||||
Assert.Equal(color.G, retrievedColor.G);
|
||||
Assert.Equal(color.B, retrievedColor.B);
|
||||
|
||||
var defaultColor = Color.FromArgb(10, 20, 30, 40);
|
||||
Assert.Equal(defaultColor, _settings.GetValue("missing", defaultColor));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Remove_DeletesKey()
|
||||
{
|
||||
_settings.SetValue("toRemove", "value");
|
||||
Assert.True(_settings.Contains("toRemove"));
|
||||
_settings.Remove("toRemove");
|
||||
Assert.False(_settings.Contains("toRemove"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SaveAndLoad_PersistsData()
|
||||
{
|
||||
_settings.SetValue("persistKey", "persistValue");
|
||||
_settings.Save();
|
||||
|
||||
// Create new instance pointing to same file
|
||||
var ctor = typeof(AppSettings).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(string) }, null);
|
||||
var loadedSettings = (AppSettings)ctor.Invoke(new object[] { _tempFile });
|
||||
|
||||
loadedSettings.Load();
|
||||
|
||||
Assert.Equal("persistValue", loadedSettings.GetValue("persistKey", ""));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using LibreHardwareMonitor.Hardware;
|
||||
using LibreHardwareMonitor.Windows.WinUI.Services;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace LibreHardwareMonitor.Windows.WinUI.Tests.Services;
|
||||
|
||||
public class LoggerTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SubscribesToComputerEvents()
|
||||
{
|
||||
var mockComputer = new Mock<IComputer>();
|
||||
|
||||
var logger = new Logger(mockComputer.Object);
|
||||
|
||||
// We can't directly test if the event was subscribed, but we can verify default properties
|
||||
Assert.Equal(LoggerFileRotation.PerSession, logger.FileRotationMethod);
|
||||
Assert.Equal(TimeSpan.FromSeconds(1), logger.LoggingInterval);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Properties_CanBeSet()
|
||||
{
|
||||
var mockComputer = new Mock<IComputer>();
|
||||
var logger = new Logger(mockComputer.Object)
|
||||
{
|
||||
FileRotationMethod = LoggerFileRotation.Daily,
|
||||
LoggingInterval = TimeSpan.FromMinutes(5)
|
||||
};
|
||||
|
||||
Assert.Equal(LoggerFileRotation.Daily, logger.FileRotationMethod);
|
||||
Assert.Equal(TimeSpan.FromMinutes(5), logger.LoggingInterval);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Log_DoesNotThrow_WhenNoSensors()
|
||||
{
|
||||
var mockComputer = new Mock<IComputer>();
|
||||
var logger = new Logger(mockComputer.Object);
|
||||
|
||||
// We can't fully mock the file system easily here without abstraction,
|
||||
// but if there are no sensors it will just create a basic CSV.
|
||||
// Actually, it tries to create a file in the app directory, which might throw in some environments.
|
||||
// Let's just assure it doesn't crash when interval hasn't passed.
|
||||
|
||||
logger.LoggingInterval = TimeSpan.FromHours(1);
|
||||
logger.Log(); // Should execute
|
||||
|
||||
// Calling again immediately should return early without doing anything
|
||||
logger.Log();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using LibreHardwareMonitor.Hardware;
|
||||
using LibreHardwareMonitor.Windows.WinUI.Services;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace LibreHardwareMonitor.Windows.WinUI.Tests.Services;
|
||||
|
||||
public class UpdateVisitorTests
|
||||
{
|
||||
[Fact]
|
||||
public void VisitComputer_CallsTraverse()
|
||||
{
|
||||
var mockComputer = new Mock<IComputer>();
|
||||
var visitor = new UpdateVisitor();
|
||||
|
||||
visitor.VisitComputer(mockComputer.Object);
|
||||
|
||||
mockComputer.Verify(c => c.Traverse(visitor), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VisitHardware_CallsUpdateAndAcceptsOnSubHardware()
|
||||
{
|
||||
var visitor = new UpdateVisitor();
|
||||
|
||||
var mockHardware = new Mock<IHardware>();
|
||||
var mockSubHardware1 = new Mock<IHardware>();
|
||||
var mockSubHardware2 = new Mock<IHardware>();
|
||||
|
||||
mockHardware.Setup(h => h.SubHardware).Returns(new[] { mockSubHardware1.Object, mockSubHardware2.Object });
|
||||
|
||||
visitor.VisitHardware(mockHardware.Object);
|
||||
|
||||
mockHardware.Verify(h => h.Update(), Times.Once);
|
||||
mockSubHardware1.Verify(h => h.Accept(visitor), Times.Once);
|
||||
mockSubHardware2.Verify(h => h.Accept(visitor), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VisitSensor_DoesNothing()
|
||||
{
|
||||
var visitor = new UpdateVisitor();
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
|
||||
visitor.VisitSensor(mockSensor.Object);
|
||||
// Assert it does not throw
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VisitParameter_DoesNothing()
|
||||
{
|
||||
var visitor = new UpdateVisitor();
|
||||
var mockParameter = new Mock<IParameter>();
|
||||
|
||||
visitor.VisitParameter(mockParameter.Object);
|
||||
// Assert it does not throw
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace LibreHardwareMonitor.Windows.WinUI.Tests;
|
||||
|
||||
public class UnitTest1
|
||||
{
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
using System;
|
||||
using LibreHardwareMonitor.Hardware;
|
||||
using LibreHardwareMonitor.Windows.WinUI.Utilities;
|
||||
using LibreHardwareMonitor.Windows.WinUI.ViewModels;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace LibreHardwareMonitor.Windows.WinUI.Tests.Utilities;
|
||||
|
||||
public class SensorFormatterTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetFormatString_ReturnsCorrectFormat_ForAllSensorTypes()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
|
||||
// Test a few specific types
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Voltage);
|
||||
Assert.Equal("{0:F3} V", SensorFormatter.GetFormatString(mockSensor.Object));
|
||||
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Load);
|
||||
Assert.Equal("{0:F1} %", SensorFormatter.GetFormatString(mockSensor.Object));
|
||||
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Temperature);
|
||||
Assert.Equal("{0:F1} \u00B0C", SensorFormatter.GetFormatString(mockSensor.Object));
|
||||
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Fan);
|
||||
Assert.Equal("{0:F0} RPM", SensorFormatter.GetFormatString(mockSensor.Object));
|
||||
|
||||
// Test default case
|
||||
mockSensor.Setup(s => s.SensorType).Returns((SensorType)999);
|
||||
Assert.Equal("{0:F1}", SensorFormatter.GetFormatString(mockSensor.Object));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatValue_NullValue_ReturnsDash()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
var result = SensorFormatter.FormatValue(mockSensor.Object, null, TemperatureUnit.Celsius);
|
||||
Assert.Equal("-", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatValue_Celsius_ReturnsCelsiusString()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Temperature);
|
||||
|
||||
var result = SensorFormatter.FormatValue(mockSensor.Object, 25.5f, TemperatureUnit.Celsius);
|
||||
Assert.Equal("25.5 \u00B0C", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatValue_Fahrenheit_ReturnsFahrenheitString()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Temperature);
|
||||
|
||||
var result = SensorFormatter.FormatValue(mockSensor.Object, 25.5f, TemperatureUnit.Fahrenheit);
|
||||
// 25.5 * 1.8 + 32 = 77.9
|
||||
Assert.Equal("77.9 \u00B0F", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatValue_Throughput_ReturnsCorrectString()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Throughput);
|
||||
mockSensor.Setup(s => s.Name).Returns("Other");
|
||||
|
||||
// Below 1MB
|
||||
var result1 = SensorFormatter.FormatValue(mockSensor.Object, 512f, TemperatureUnit.Celsius);
|
||||
Assert.Equal("0.5 KB/s", result1);
|
||||
|
||||
// Above 1MB
|
||||
var result2 = SensorFormatter.FormatValue(mockSensor.Object, 2097152f, TemperatureUnit.Celsius);
|
||||
Assert.Equal("2.0 MB/s", result2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatValue_Throughput_ConnectionSpeed_ReturnsCorrectString()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Throughput);
|
||||
mockSensor.Setup(s => s.Name).Returns("Connection Speed");
|
||||
|
||||
Assert.Equal("100Mbps", SensorFormatter.FormatValue(mockSensor.Object, 100000000f, TemperatureUnit.Celsius));
|
||||
Assert.Equal("1Gbps", SensorFormatter.FormatValue(mockSensor.Object, 1000000000f, TemperatureUnit.Celsius));
|
||||
Assert.Equal("500 bps", SensorFormatter.FormatValue(mockSensor.Object, 500f, TemperatureUnit.Celsius));
|
||||
Assert.Equal("2.0 Kbps", SensorFormatter.FormatValue(mockSensor.Object, 2048f, TemperatureUnit.Celsius));
|
||||
Assert.Equal("2.0 Mbps", SensorFormatter.FormatValue(mockSensor.Object, 2097152f, TemperatureUnit.Celsius));
|
||||
Assert.Equal("2.0 Gbps", SensorFormatter.FormatValue(mockSensor.Object, 2147483648f, TemperatureUnit.Celsius));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatValue_TimeSpan_ReturnsCorrectString()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.TimeSpan);
|
||||
|
||||
var result = SensorFormatter.FormatValue(mockSensor.Object, 3600f, TemperatureUnit.Celsius);
|
||||
Assert.Equal("1:00:00", result); // g format for 1 hour
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatValue_Default_ReturnsFormattedFloat()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.SensorType).Returns((SensorType)999);
|
||||
|
||||
var result = SensorFormatter.FormatValue(mockSensor.Object, 12.34f, TemperatureUnit.Celsius);
|
||||
Assert.Equal("12.3", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPlotValue_NullValue_ReturnsNull()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.Value).Returns((float?)null);
|
||||
|
||||
var result = SensorFormatter.GetPlotValue(mockSensor.Object, TemperatureUnit.Celsius);
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPlotValue_TemperatureFahrenheit_ReturnsConvertedValue()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.Value).Returns(25.5f);
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Temperature);
|
||||
|
||||
var result = SensorFormatter.GetPlotValue(mockSensor.Object, TemperatureUnit.Fahrenheit);
|
||||
Assert.Equal(77.9, result.Value, 1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPlotValue_OtherSensor_ReturnsRawValue()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.Value).Returns(25.5f);
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Voltage);
|
||||
|
||||
var result = SensorFormatter.GetPlotValue(mockSensor.Object, TemperatureUnit.Celsius);
|
||||
Assert.Equal(25.5f, result);
|
||||
}
|
||||
|
||||
// A mock interface combining ISensor and ICriticalSensorLimits for testing
|
||||
public interface ICriticalSensorMock : ISensor, ICriticalSensorLimits, ISensorLimits
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetToolTip_WithLimits_ReturnsFormattedToolTip()
|
||||
{
|
||||
var mockSensor = new Mock<ICriticalSensorMock>();
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Temperature);
|
||||
mockSensor.Setup(s => s.CriticalLowLimit).Returns(10f);
|
||||
mockSensor.Setup(s => s.CriticalHighLimit).Returns(90f);
|
||||
mockSensor.Setup(s => s.LowLimit).Returns(20f);
|
||||
mockSensor.Setup(s => s.HighLimit).Returns(80f);
|
||||
|
||||
var result = SensorFormatter.GetToolTip(mockSensor.Object, TemperatureUnit.Celsius);
|
||||
|
||||
Assert.Contains("Critical range: 10.0 \u00B0C to 90.0 \u00B0C.", result);
|
||||
Assert.Contains("Normal range: 20.0 \u00B0C to 80.0 \u00B0C.", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetToolTip_WithOnlyMinLimit_ReturnsFormattedToolTip()
|
||||
{
|
||||
var mockSensor = new Mock<ICriticalSensorMock>();
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Voltage);
|
||||
mockSensor.Setup(s => s.CriticalLowLimit).Returns(1.0f);
|
||||
mockSensor.Setup(s => s.CriticalHighLimit).Returns((float?)null);
|
||||
|
||||
var result = SensorFormatter.GetToolTip(mockSensor.Object, TemperatureUnit.Celsius);
|
||||
|
||||
Assert.Contains("Minimal critical value: 1.000 V.", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetToolTip_WithOnlyMaxLimit_ReturnsFormattedToolTip()
|
||||
{
|
||||
var mockSensor = new Mock<ICriticalSensorMock>();
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Voltage);
|
||||
mockSensor.Setup(s => s.CriticalLowLimit).Returns((float?)null);
|
||||
mockSensor.Setup(s => s.CriticalHighLimit).Returns(2.0f);
|
||||
|
||||
var result = SensorFormatter.GetToolTip(mockSensor.Object, TemperatureUnit.Celsius);
|
||||
|
||||
Assert.Contains("Maximal critical value: 2.000 V.", result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using LibreHardwareMonitor.Hardware;
|
||||
using LibreHardwareMonitor.Windows.WinUI.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace LibreHardwareMonitor.Windows.WinUI.Tests.Utilities;
|
||||
|
||||
public class SensorTypeDisplayTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetText_ReturnsCorrectString_ForAllKnownTypes()
|
||||
{
|
||||
Assert.Equal("Voltages", SensorTypeDisplay.GetText(SensorType.Voltage));
|
||||
Assert.Equal("Currents", SensorTypeDisplay.GetText(SensorType.Current));
|
||||
Assert.Equal("Clocks", SensorTypeDisplay.GetText(SensorType.Clock));
|
||||
Assert.Equal("Load", SensorTypeDisplay.GetText(SensorType.Load));
|
||||
Assert.Equal("Temperatures", SensorTypeDisplay.GetText(SensorType.Temperature));
|
||||
Assert.Equal("Fans", SensorTypeDisplay.GetText(SensorType.Fan));
|
||||
Assert.Equal("Flows", SensorTypeDisplay.GetText(SensorType.Flow));
|
||||
Assert.Equal("Controls", SensorTypeDisplay.GetText(SensorType.Control));
|
||||
Assert.Equal("Levels", SensorTypeDisplay.GetText(SensorType.Level));
|
||||
Assert.Equal("Powers", SensorTypeDisplay.GetText(SensorType.Power));
|
||||
Assert.Equal("Data", SensorTypeDisplay.GetText(SensorType.Data));
|
||||
Assert.Equal("Data", SensorTypeDisplay.GetText(SensorType.SmallData));
|
||||
Assert.Equal("Factors", SensorTypeDisplay.GetText(SensorType.Factor));
|
||||
Assert.Equal("Frequencies", SensorTypeDisplay.GetText(SensorType.Frequency));
|
||||
Assert.Equal("Throughput", SensorTypeDisplay.GetText(SensorType.Throughput));
|
||||
Assert.Equal("Times", SensorTypeDisplay.GetText(SensorType.TimeSpan));
|
||||
Assert.Equal("Timings", SensorTypeDisplay.GetText(SensorType.Timing));
|
||||
Assert.Equal("Capacities", SensorTypeDisplay.GetText(SensorType.Energy));
|
||||
Assert.Equal("Noise Levels", SensorTypeDisplay.GetText(SensorType.Noise));
|
||||
Assert.Equal("Conductivities", SensorTypeDisplay.GetText(SensorType.Conductivity));
|
||||
Assert.Equal("Humidity Levels", SensorTypeDisplay.GetText(SensorType.Humidity));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetText_ReturnsToString_ForUnknownType()
|
||||
{
|
||||
SensorType unknownType = (SensorType)999;
|
||||
Assert.Equal("999", SensorTypeDisplay.GetText(unknownType));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetGlyph_ReturnsCorrectGlyph_ForAllKnownTypes()
|
||||
{
|
||||
Assert.Equal("\uE945", SensorTypeDisplay.GetGlyph(SensorType.Voltage));
|
||||
Assert.Equal("\uE945", SensorTypeDisplay.GetGlyph(SensorType.Current));
|
||||
Assert.Equal("\uE916", SensorTypeDisplay.GetGlyph(SensorType.Clock));
|
||||
Assert.Equal("\uE9D9", SensorTypeDisplay.GetGlyph(SensorType.Load));
|
||||
Assert.Equal("\uE9CA", SensorTypeDisplay.GetGlyph(SensorType.Temperature));
|
||||
Assert.Equal("\uE9F3", SensorTypeDisplay.GetGlyph(SensorType.Fan));
|
||||
Assert.Equal("\uE9D5", SensorTypeDisplay.GetGlyph(SensorType.Flow));
|
||||
Assert.Equal("\uE713", SensorTypeDisplay.GetGlyph(SensorType.Control));
|
||||
Assert.Equal("\uE9D2", SensorTypeDisplay.GetGlyph(SensorType.Level));
|
||||
Assert.Equal("\uE7E8", SensorTypeDisplay.GetGlyph(SensorType.Power));
|
||||
Assert.Equal("\uE8AB", SensorTypeDisplay.GetGlyph(SensorType.Data));
|
||||
Assert.Equal("\uE8AB", SensorTypeDisplay.GetGlyph(SensorType.SmallData));
|
||||
Assert.Equal("\uE9D2", SensorTypeDisplay.GetGlyph(SensorType.Factor));
|
||||
Assert.Equal("\uE916", SensorTypeDisplay.GetGlyph(SensorType.Frequency));
|
||||
Assert.Equal("\uE9D5", SensorTypeDisplay.GetGlyph(SensorType.Throughput));
|
||||
Assert.Equal("\uE121", SensorTypeDisplay.GetGlyph(SensorType.TimeSpan));
|
||||
Assert.Equal("\uE121", SensorTypeDisplay.GetGlyph(SensorType.Timing));
|
||||
Assert.Equal("\uEBAA", SensorTypeDisplay.GetGlyph(SensorType.Energy));
|
||||
Assert.Equal("\uE767", SensorTypeDisplay.GetGlyph(SensorType.Noise));
|
||||
Assert.Equal("\uE945", SensorTypeDisplay.GetGlyph(SensorType.Conductivity));
|
||||
Assert.Equal("\uE9CA", SensorTypeDisplay.GetGlyph(SensorType.Humidity));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetGlyph_ReturnsDefault_ForUnknownType()
|
||||
{
|
||||
SensorType unknownType = (SensorType)999;
|
||||
Assert.Equal("\uE9D9", SensorTypeDisplay.GetGlyph(unknownType));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetHardwareGlyph_ReturnsCorrectGlyph_ForAllKnownTypes()
|
||||
{
|
||||
Assert.Equal("\uE950", SensorTypeDisplay.GetHardwareGlyph(HardwareType.Motherboard));
|
||||
Assert.Equal("\uE950", SensorTypeDisplay.GetHardwareGlyph(HardwareType.SuperIO));
|
||||
Assert.Equal("\uE950", SensorTypeDisplay.GetHardwareGlyph(HardwareType.Cpu));
|
||||
Assert.Equal("\uE8AB", SensorTypeDisplay.GetHardwareGlyph(HardwareType.Memory));
|
||||
Assert.Equal("\uE7F4", SensorTypeDisplay.GetHardwareGlyph(HardwareType.GpuNvidia));
|
||||
Assert.Equal("\uE7F4", SensorTypeDisplay.GetHardwareGlyph(HardwareType.GpuAmd));
|
||||
Assert.Equal("\uE7F4", SensorTypeDisplay.GetHardwareGlyph(HardwareType.GpuIntel));
|
||||
Assert.Equal("\uEDA2", SensorTypeDisplay.GetHardwareGlyph(HardwareType.Storage));
|
||||
Assert.Equal("\uE968", SensorTypeDisplay.GetHardwareGlyph(HardwareType.Network));
|
||||
Assert.Equal("\uE9F3", SensorTypeDisplay.GetHardwareGlyph(HardwareType.Cooler));
|
||||
Assert.Equal("\uE950", SensorTypeDisplay.GetHardwareGlyph(HardwareType.EmbeddedController));
|
||||
Assert.Equal("\uE7E8", SensorTypeDisplay.GetHardwareGlyph(HardwareType.Psu));
|
||||
Assert.Equal("\uEBAA", SensorTypeDisplay.GetHardwareGlyph(HardwareType.Battery));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetHardwareGlyph_ReturnsDefault_ForUnknownType()
|
||||
{
|
||||
HardwareType unknownType = (HardwareType)999;
|
||||
Assert.Equal("\uE950", SensorTypeDisplay.GetHardwareGlyph(unknownType));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using LibreHardwareMonitor.Hardware;
|
||||
using LibreHardwareMonitor.Windows.WinUI.Services;
|
||||
using LibreHardwareMonitor.Windows.WinUI.ViewModels;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.UI;
|
||||
|
||||
namespace LibreHardwareMonitor.Windows.WinUI.Tests.ViewModels;
|
||||
|
||||
public class SensorTreeItemViewModelTests
|
||||
{
|
||||
private AppSettings CreateMockSettings()
|
||||
{
|
||||
return AppSettings.LoadDefault();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateRoot_ReturnsRootKind()
|
||||
{
|
||||
var vm = SensorTreeItemViewModel.CreateRoot("Root Node");
|
||||
Assert.Equal(SensorTreeItemKind.Root, vm.Kind);
|
||||
Assert.Equal("Root Node", vm.Text);
|
||||
Assert.Null(vm.Sensor);
|
||||
Assert.Null(vm.Hardware);
|
||||
Assert.Equal("\uE7F4", vm.IconGlyph);
|
||||
Assert.True(vm.IsExpanded);
|
||||
Assert.Empty(vm.Children);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Text_CanBeSetForRoot()
|
||||
{
|
||||
var vm = SensorTreeItemViewModel.CreateRoot("Root");
|
||||
vm.Text = "New Root";
|
||||
Assert.Equal("New Root", vm.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FromHardware_CreatesHierarchy()
|
||||
{
|
||||
var mockHardware = new Mock<IHardware>();
|
||||
mockHardware.Setup(h => h.Name).Returns("My Hardware");
|
||||
mockHardware.Setup(h => h.HardwareType).Returns(HardwareType.Cpu);
|
||||
mockHardware.Setup(h => h.Identifier).Returns(new Identifier("cpu", "0"));
|
||||
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.Name).Returns("Core 0");
|
||||
mockSensor.Setup(s => s.SensorType).Returns(SensorType.Temperature);
|
||||
mockSensor.Setup(s => s.Index).Returns(0);
|
||||
mockSensor.Setup(s => s.Identifier).Returns(new Identifier("cpu", "0", "temperature", "0"));
|
||||
|
||||
mockHardware.Setup(h => h.Sensors).Returns(new[] { mockSensor.Object });
|
||||
mockHardware.Setup(h => h.SubHardware).Returns(Array.Empty<IHardware>());
|
||||
|
||||
var settings = CreateMockSettings();
|
||||
var vm = SensorTreeItemViewModel.FromHardware(mockHardware.Object, settings);
|
||||
|
||||
Assert.Equal(SensorTreeItemKind.Hardware, vm.Kind);
|
||||
Assert.Equal("My Hardware", vm.Text);
|
||||
Assert.Same(mockHardware.Object, vm.Hardware);
|
||||
Assert.Single(vm.Children); // One SensorType group
|
||||
|
||||
var typeGroup = vm.Children[0];
|
||||
Assert.Equal(SensorTreeItemKind.SensorType, typeGroup.Kind);
|
||||
Assert.Equal("Temperatures", typeGroup.Text);
|
||||
Assert.Single(typeGroup.Children); // One sensor
|
||||
|
||||
var sensorVm = typeGroup.Children[0];
|
||||
Assert.Equal(SensorTreeItemKind.Sensor, sensorVm.Kind);
|
||||
Assert.Equal("Core 0", sensorVm.Text);
|
||||
Assert.Same(mockSensor.Object, sensorVm.Sensor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Plot_SetsPlotPropertyAndSettings()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.Identifier).Returns(new Identifier("cpu", "0"));
|
||||
|
||||
var mockHardware = new Mock<IHardware>();
|
||||
mockHardware.Setup(h => h.Identifier).Returns(new Identifier("hw"));
|
||||
mockHardware.Setup(h => h.Sensors).Returns(new[] { mockSensor.Object });
|
||||
mockHardware.Setup(h => h.SubHardware).Returns(Array.Empty<IHardware>());
|
||||
|
||||
var settings = CreateMockSettings();
|
||||
var vm = SensorTreeItemViewModel.FromHardware(mockHardware.Object, settings);
|
||||
|
||||
// Root has no sensor, so Plot won't do anything
|
||||
vm.Plot = true;
|
||||
Assert.False(vm.Plot);
|
||||
|
||||
// Get SensorVM
|
||||
var sensorVm = vm.Children.First().Children.First();
|
||||
sensorVm.Plot = true;
|
||||
Assert.True(sensorVm.Plot);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PenColor_SetsPropertyAndSettings()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.Identifier).Returns(new Identifier("cpu", "0"));
|
||||
|
||||
var mockHardware = new Mock<IHardware>();
|
||||
mockHardware.Setup(h => h.Sensors).Returns(new[] { mockSensor.Object });
|
||||
mockHardware.Setup(h => h.Identifier).Returns(new Identifier("hw"));
|
||||
mockHardware.Setup(h => h.SubHardware).Returns(Array.Empty<IHardware>());
|
||||
|
||||
var settings = CreateMockSettings();
|
||||
var vm = SensorTreeItemViewModel.FromHardware(mockHardware.Object, settings);
|
||||
var sensorVm = vm.Children.First().Children.First();
|
||||
|
||||
Assert.Null(sensorVm.PenColor);
|
||||
|
||||
var color = Color.FromArgb(255, 100, 100, 100);
|
||||
sensorVm.PenColor = color;
|
||||
Assert.Equal(color, sensorVm.PenColor);
|
||||
|
||||
sensorVm.PenColor = null;
|
||||
Assert.Null(sensorVm.PenColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetShowHiddenSensors_UpdatesVisibility()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.Identifier).Returns(new Identifier("cpu", "0"));
|
||||
|
||||
var mockHardware = new Mock<IHardware>();
|
||||
mockHardware.Setup(h => h.Sensors).Returns(new[] { mockSensor.Object });
|
||||
mockHardware.Setup(h => h.Identifier).Returns(new Identifier("hw"));
|
||||
mockHardware.Setup(h => h.SubHardware).Returns(Array.Empty<IHardware>());
|
||||
|
||||
var settings = CreateMockSettings();
|
||||
var vm = SensorTreeItemViewModel.FromHardware(mockHardware.Object, settings);
|
||||
var typeGroup = vm.Children.First();
|
||||
var sensorVm = typeGroup.Children.First();
|
||||
|
||||
sensorVm.IsVisible = false;
|
||||
Assert.Equal(Visibility.Collapsed, sensorVm.RowVisibility);
|
||||
|
||||
// typeGroup doesn't update automatically in ViewModel when child changes, so skip assert
|
||||
|
||||
vm.SetShowHiddenSensors(true);
|
||||
|
||||
Assert.Equal(Visibility.Visible, sensorVm.RowVisibility);
|
||||
Assert.Equal(Visibility.Visible, typeGroup.RowVisibility);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetColumnVisibility_UpdatesAllChildren()
|
||||
{
|
||||
var root = SensorTreeItemViewModel.CreateRoot("Root");
|
||||
|
||||
root.SetColumnVisibility(false, true, true);
|
||||
|
||||
Assert.Equal(Visibility.Collapsed, root.ValueColumnVisibility);
|
||||
Assert.Equal(Visibility.Visible, root.MinColumnVisibility);
|
||||
Assert.Equal(Visibility.Visible, root.MaxColumnVisibility);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RefreshValues_UpdatesProperties()
|
||||
{
|
||||
var mockSensor = new Mock<ISensor>();
|
||||
mockSensor.Setup(s => s.Identifier).Returns(new Identifier("cpu", "0"));
|
||||
mockSensor.Setup(s => s.Value).Returns(50f);
|
||||
|
||||
var mockHardware = new Mock<IHardware>();
|
||||
mockHardware.Setup(h => h.Sensors).Returns(new[] { mockSensor.Object });
|
||||
mockHardware.Setup(h => h.Identifier).Returns(new Identifier("hw"));
|
||||
mockHardware.Setup(h => h.SubHardware).Returns(Array.Empty<IHardware>());
|
||||
|
||||
var vm = SensorTreeItemViewModel.FromHardware(mockHardware.Object, CreateMockSettings());
|
||||
var sensorVm = vm.Children.First().Children.First();
|
||||
|
||||
mockSensor.Setup(s => s.Value).Returns(60f); // change value
|
||||
sensorVm.RefreshValues(); // This triggers PropertyChanged
|
||||
|
||||
Assert.Contains("60.0", sensorVm.Value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Windows.UI;
|
||||
using LibreHardwareMonitor.Windows.WinUI.ViewModels;
|
||||
using Xunit;
|
||||
|
||||
namespace LibreHardwareMonitor.Windows.WinUI.Tests.ViewModels;
|
||||
|
||||
public class SimpleViewModelsTests
|
||||
{
|
||||
private class TestViewModel : ViewModelBase
|
||||
{
|
||||
private string _testProperty;
|
||||
public string TestProperty
|
||||
{
|
||||
get => _testProperty;
|
||||
set => SetProperty(ref _testProperty, value);
|
||||
}
|
||||
|
||||
public void TriggerPropertyChanged(string propertyName)
|
||||
{
|
||||
OnPropertyChanged(propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ViewModelBase_SetProperty_ChangesValueAndRaisesEvent()
|
||||
{
|
||||
var vm = new TestViewModel();
|
||||
string changedProperty = null;
|
||||
vm.PropertyChanged += (sender, args) => changedProperty = args.PropertyName;
|
||||
|
||||
// Change value
|
||||
vm.TestProperty = "NewValue";
|
||||
vm.TestProperty = "NewValue";
|
||||
|
||||
Assert.Equal("NewValue", vm.TestProperty);
|
||||
Assert.Equal(nameof(TestViewModel.TestProperty), changedProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ViewModelBase_SetProperty_SameValue_DoesNotRaiseEvent()
|
||||
{
|
||||
var vm = new TestViewModel();
|
||||
vm.TestProperty = "Value";
|
||||
|
||||
bool eventRaised = false;
|
||||
vm.PropertyChanged += (sender, args) => eventRaised = true;
|
||||
|
||||
vm.TestProperty = "Value"; // Set same value
|
||||
|
||||
Assert.False(eventRaised);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ViewModelBase_OnPropertyChanged_RaisesEvent()
|
||||
{
|
||||
var vm = new TestViewModel();
|
||||
string changedProperty = null;
|
||||
vm.PropertyChanged += (sender, args) => changedProperty = args.PropertyName;
|
||||
|
||||
vm.TriggerPropertyChanged("CustomProperty");
|
||||
|
||||
Assert.Equal("CustomProperty", changedProperty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlotPointViewModel_Constructor_SetsProperties()
|
||||
{
|
||||
var timestamp = new DateTime(2023, 1, 1);
|
||||
var vm = new PlotPointViewModel(timestamp, 42.5);
|
||||
|
||||
Assert.Equal(timestamp, vm.Timestamp);
|
||||
Assert.Equal(42.5, vm.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlotSeriesViewModel_Constructor_SetsProperties()
|
||||
{
|
||||
var color = Color.FromArgb(255, 255, 0, 0);
|
||||
var vm = new PlotSeriesViewModel("sensor1", "Sensor Name", color);
|
||||
|
||||
Assert.Equal("sensor1", vm.SensorIdentifier);
|
||||
Assert.Equal("Sensor Name", vm.Name);
|
||||
Assert.Equal(color, vm.Color);
|
||||
Assert.NotNull(vm.Points);
|
||||
Assert.Empty(vm.Points);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlotSeriesViewModel_SetColor_ChangesColor()
|
||||
{
|
||||
var color1 = Color.FromArgb(255, 255, 0, 0);
|
||||
var color2 = Color.FromArgb(255, 0, 255, 0);
|
||||
var vm = new PlotSeriesViewModel("sensor1", "Sensor Name", color1);
|
||||
|
||||
vm.Color = color2;
|
||||
|
||||
Assert.Equal(color2, vm.Color);
|
||||
}
|
||||
}
|
||||
+66
-30
@@ -3,12 +3,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 18
|
||||
VisualStudioVersion = 18.0.11018.127
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreHardwareMonitor.Windows.WinUI", "LibreHardwareMonitor.Windows.WinUI\LibreHardwareMonitor.Windows.WinUI.csproj", "{49D41E03-7028-4B28-9F5E-4558D0E26EA2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreHardwareMonitorLib", "LibreHardwareMonitorLib\LibreHardwareMonitorLib.csproj", "{B0397530-545A-471D-BB74-027AE456DF1A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreHardwareMonitor.Windows.Forms", "LibreHardwareMonitor.Windows.Forms\LibreHardwareMonitor.Windows.Forms.csproj", "{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreHardwareMonitor.Windows.WinUI", "LibreHardwareMonitor.Windows.WinUI\LibreHardwareMonitor.Windows.WinUI.csproj", "{49D41E03-7028-4B28-9F5E-4558D0E26EA2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreHardwareMonitorLib", "LibreHardwareMonitorLib\LibreHardwareMonitorLib.csproj", "{B0397530-545A-471D-BB74-027AE456DF1A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreHardwareMonitor.Windows.Forms", "LibreHardwareMonitor.Windows.Forms\LibreHardwareMonitor.Windows.Forms.csproj", "{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aga.Controls", "Aga.Controls\Aga.Controls.csproj", "{E73BB233-D88B-44A7-A98F-D71EE158381D}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Controls", "Controls", "{23F54DBD-8998-4E22-A4E4-60F4F77F9B65}"
|
||||
@@ -19,64 +19,100 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
Directory.Build.props = Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibreHardwareMonitorLib.Tests", "LibreHardwareMonitorLib.Tests\LibreHardwareMonitorLib.Tests.csproj", "{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|ARM64 = Release|ARM64
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|x64.Build.0 = Debug|x64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|x86.Build.0 = Debug|x86
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|x64.ActiveCfg = Release|x64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|x64.Build.0 = Release|x64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|x86.ActiveCfg = Release|x86
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|x86.Build.0 = Release|x86
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|x64.Build.0 = Debug|x64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|x86.Build.0 = Debug|x86
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|x64.ActiveCfg = Release|x64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|x64.Build.0 = Release|x64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|x86.ActiveCfg = Release|x86
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|x86.Build.0 = Release|x86
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Debug|x64.Build.0 = Debug|x64
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Debug|x86.Build.0 = Debug|x86
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Release|x64.ActiveCfg = Release|x64
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Release|x64.Build.0 = Release|x64
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Release|x86.ActiveCfg = Release|x86
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Release|x86.Build.0 = Release|x86
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{49D41E03-7028-4B28-9F5E-4558D0E26EA2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|x64.Build.0 = Debug|x64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|x86.Build.0 = Debug|x86
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|x64.ActiveCfg = Release|x64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|x64.Build.0 = Release|x64
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|x86.ActiveCfg = Release|x86
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|x86.Build.0 = Release|x86
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B0397530-545A-471D-BB74-027AE456DF1A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|x64.Build.0 = Debug|x64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|x86.Build.0 = Debug|x86
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|x64.ActiveCfg = Release|x64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|x64.Build.0 = Release|x64
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|x86.ActiveCfg = Release|x86
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|x86.Build.0 = Release|x86
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F5E0C1F7-9E9B-46F2-AC88-8C9C1C923880}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Debug|x64.Build.0 = Debug|x64
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Debug|x86.Build.0 = Debug|x86
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Release|x64.ActiveCfg = Release|x64
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Release|x64.Build.0 = Release|x64
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Release|x86.ActiveCfg = Release|x86
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Release|x86.Build.0 = Release|x86
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E73BB233-D88B-44A7-A98F-D71EE158381D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Release|x64.Build.0 = Release|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Release|x86.Build.0 = Release|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AF286D81-C1D0-47B2-AD60-9F60CAE602F9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using LibreHardwareMonitor.Hardware;
|
||||
using Xunit;
|
||||
|
||||
namespace LibreHardwareMonitorLib.Tests.Hardware;
|
||||
|
||||
public class ComputerTests
|
||||
{
|
||||
[Fact]
|
||||
public void OpenAndClose_WorksCorrectly_AndCompletesHardwareDiscoveryTask()
|
||||
{
|
||||
var computer = new Computer
|
||||
{
|
||||
IsCpuEnabled = false,
|
||||
IsGpuEnabled = false,
|
||||
IsMemoryEnabled = false,
|
||||
IsMotherboardEnabled = false,
|
||||
IsControllerEnabled = false,
|
||||
IsNetworkEnabled = false,
|
||||
IsStorageEnabled = false,
|
||||
IsBatteryEnabled = false,
|
||||
IsPsuEnabled = false,
|
||||
IsPowerMonitorEnabled = false
|
||||
};
|
||||
|
||||
// HardwareDiscoveryTask should be available
|
||||
Assert.NotNull(computer.HardwareDiscoveryTask);
|
||||
|
||||
// Open the computer
|
||||
computer.Open();
|
||||
|
||||
// HardwareDiscoveryTask should complete because all are disabled, so no long-running task
|
||||
Assert.True(computer.HardwareDiscoveryTask.IsCompleted);
|
||||
|
||||
// Close the computer
|
||||
computer.Close();
|
||||
|
||||
// Ensure it doesn't throw and remains in a good state
|
||||
Assert.True(computer.HardwareDiscoveryTask.IsCompleted);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenAsync_WorksCorrectly_AndCompletesHardwareDiscoveryTask()
|
||||
{
|
||||
var computer = new Computer
|
||||
{
|
||||
IsCpuEnabled = false,
|
||||
IsGpuEnabled = false,
|
||||
IsMemoryEnabled = false,
|
||||
IsMotherboardEnabled = false,
|
||||
IsControllerEnabled = false,
|
||||
IsNetworkEnabled = false,
|
||||
IsStorageEnabled = false,
|
||||
IsBatteryEnabled = false,
|
||||
IsPsuEnabled = false,
|
||||
IsPowerMonitorEnabled = false
|
||||
};
|
||||
|
||||
await computer.OpenAsync();
|
||||
|
||||
// The HardwareDiscoveryTask should complete successfully.
|
||||
Assert.True(computer.HardwareDiscoveryTask.IsCompletedSuccessfully);
|
||||
|
||||
computer.Close();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Reset_ClearsHardwareAndCompletesDiscovery()
|
||||
{
|
||||
var computer = new Computer
|
||||
{
|
||||
IsCpuEnabled = false
|
||||
};
|
||||
|
||||
computer.Open();
|
||||
Assert.True(computer.HardwareDiscoveryTask.IsCompleted);
|
||||
|
||||
computer.Reset();
|
||||
|
||||
Assert.Empty(computer.Hardware);
|
||||
Assert.True(computer.HardwareDiscoveryTask.IsCompleted);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LibreHardwareMonitorLib\LibreHardwareMonitorLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,4 +1,4 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
|
||||
@@ -68,7 +68,7 @@ public class Computer : IComputer
|
||||
private SMBios _smbios;
|
||||
private bool _storageEnabled;
|
||||
private CancellationTokenSource _deferredGroupCancellationTokenSource;
|
||||
private TaskCompletionSource _deferredGroupCompletionSource = CreateCompletedTaskCompletionSource();
|
||||
private TaskCompletionSource<object> _deferredGroupCompletionSource = CreateCompletedTaskCompletionSource();
|
||||
private List<Task> _deferredGroupTasks = [];
|
||||
|
||||
/// <summary>
|
||||
@@ -864,7 +864,7 @@ public class Computer : IComputer
|
||||
CancelDeferredGroupRun();
|
||||
lock (_deferredGroupLock)
|
||||
{
|
||||
_deferredGroupCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
_deferredGroupCompletionSource = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
_deferredGroupTasks = [];
|
||||
}
|
||||
|
||||
@@ -875,7 +875,7 @@ public class Computer : IComputer
|
||||
{
|
||||
CancellationTokenSource cancellationTokenSource = _deferredGroupCancellationTokenSource;
|
||||
_deferredGroupCancellationTokenSource = null;
|
||||
TaskCompletionSource completionSource;
|
||||
TaskCompletionSource<object> completionSource;
|
||||
|
||||
lock (_deferredGroupLock)
|
||||
{
|
||||
@@ -894,14 +894,14 @@ public class Computer : IComputer
|
||||
completionSource.TrySetCanceled();
|
||||
}
|
||||
|
||||
private static TaskCompletionSource CreateCompletedTaskCompletionSource()
|
||||
private static TaskCompletionSource<object> CreateCompletedTaskCompletionSource()
|
||||
{
|
||||
TaskCompletionSource completionSource = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
completionSource.SetResult();
|
||||
TaskCompletionSource<object> completionSource = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
completionSource.SetResult(null);
|
||||
return completionSource;
|
||||
}
|
||||
|
||||
private void CompleteDeferredGroupRun(TaskCompletionSource completionSource)
|
||||
private void CompleteDeferredGroupRun(TaskCompletionSource<object> completionSource)
|
||||
{
|
||||
bool completed;
|
||||
lock (_deferredGroupLock)
|
||||
@@ -909,7 +909,7 @@ public class Computer : IComputer
|
||||
if (!ReferenceEquals(completionSource, _deferredGroupCompletionSource))
|
||||
return;
|
||||
|
||||
completed = completionSource.TrySetResult();
|
||||
completed = completionSource.TrySetResult(null);
|
||||
}
|
||||
|
||||
if (completed)
|
||||
@@ -918,7 +918,7 @@ public class Computer : IComputer
|
||||
|
||||
private void CompleteDeferredGroupRunWhenRegistered()
|
||||
{
|
||||
TaskCompletionSource completionSource;
|
||||
TaskCompletionSource<object> completionSource;
|
||||
Task[] tasks;
|
||||
lock (_deferredGroupLock)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user