Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
213 changes: 213 additions & 0 deletions stmx.tests/Commands/NetworkCommandTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
using Moq;
using stmx.Commands;
using stmx.Services;
using stmx.Utils;

namespace stmx.Tests;

public class NetworkCommandTests
{
private Mock<ISystemStatsService> _mockStats;
private Mock<IIconService> _mockIcons;
private NetworkCommand _cmd;

[SetUp]
public void SetUp()
{
_mockStats = new Mock<ISystemStatsService>();
_mockIcons = new Mock<IIconService>();

_mockStats.SetupGet(s => s.Options).Returns(new SystemStatsServiceOptions
{
DefaultNetworkDirection = NetworkDirection.Both,
DefaultNetworkUnit = NetworkUnits.Auto,
DefaultNetworkDelay = 1
});
_mockIcons.SetupGet(i => i.Options).Returns(new IconServiceOptions
{
NetworkDownload = "DOWN_ICON",
NetworkUpload = "UP_ICON"
});

_cmd = new NetworkCommand(_mockStats.Object, _mockIcons.Object);
}

private void SetupNetworkSpeed(double upload, double download, NetworkUnits unit = NetworkUnits.KiloBits)
{
_mockStats.Setup(s => s.GetNetworkSpeed(It.IsAny<NetworkUnits>(), It.IsAny<string>(), It.IsAny<int>()))
.ReturnsAsync((
new NetworkSpeed(upload, unit),
new NetworkSpeed(download, unit)
));
}

[Test]
public async Task TestNetworkCommand_PrintsBothDirections()
{
SetupNetworkSpeed(10.5, 20.3);
var consoleOut = new StringWriter();
Console.SetOut(consoleOut);

await _cmd.ExecuteAsync(
showUploadIcon: false, uploadIconValue: "",
showDownloadIcon: false, downloadIconValue: "",
direction: NetworkDirection.Both,
network: "wlo1", delay: 1, unit: NetworkUnits.KiloBits
);

Assert.That(consoleOut.ToString(), Is.EqualTo("20.30k 10.50k"));
}

[Test]
public async Task TestNetworkCommand_PrintsDownloadOnly()
{
SetupNetworkSpeed(10.5, 20.3);
var consoleOut = new StringWriter();
Console.SetOut(consoleOut);

await _cmd.ExecuteAsync(
showUploadIcon: false, uploadIconValue: "",
showDownloadIcon: false, downloadIconValue: "",
direction: NetworkDirection.Download,
network: "wlo1", delay: 1, unit: NetworkUnits.KiloBits
);

Assert.That(consoleOut.ToString(), Is.EqualTo("20.30k"));
}

[Test]
public async Task TestNetworkCommand_PrintsUploadOnly()
{
SetupNetworkSpeed(10.5, 20.3);
var consoleOut = new StringWriter();
Console.SetOut(consoleOut);

await _cmd.ExecuteAsync(
showUploadIcon: false, uploadIconValue: "",
showDownloadIcon: false, downloadIconValue: "",
direction: NetworkDirection.Upload,
network: "wlo1", delay: 1, unit: NetworkUnits.KiloBits
);

Assert.That(consoleOut.ToString(), Is.EqualTo("10.50k"));
}

[Test]
public async Task TestNetworkCommand_PrintsDefaultDownloadIcon()
{
SetupNetworkSpeed(10.5, 20.3);
var consoleOut = new StringWriter();
Console.SetOut(consoleOut);

await _cmd.ExecuteAsync(
showUploadIcon: false, uploadIconValue: "",
showDownloadIcon: true, downloadIconValue: "",
direction: NetworkDirection.Download,
network: "wlo1", delay: 1, unit: NetworkUnits.KiloBits
);

Assert.That(consoleOut.ToString(), Is.EqualTo("DOWN_ICON 20.30k"));
}

[Test]
public async Task TestNetworkCommand_PrintsDefaultUploadIcon()
{
SetupNetworkSpeed(10.5, 20.3);
var consoleOut = new StringWriter();
Console.SetOut(consoleOut);

await _cmd.ExecuteAsync(
showUploadIcon: true, uploadIconValue: "",
showDownloadIcon: false, downloadIconValue: "",
direction: NetworkDirection.Upload,
network: "wlo1", delay: 1, unit: NetworkUnits.KiloBits
);

Assert.That(consoleOut.ToString(), Is.EqualTo("UP_ICON 10.50k"));
}

[Test]
public async Task TestNetworkCommand_PrintsCustomDownloadIcon()
{
SetupNetworkSpeed(10.5, 20.3);
var consoleOut = new StringWriter();
Console.SetOut(consoleOut);

await _cmd.ExecuteAsync(
showUploadIcon: false, uploadIconValue: "",
showDownloadIcon: true, downloadIconValue: "↓",
direction: NetworkDirection.Download,
network: "wlo1", delay: 1, unit: NetworkUnits.KiloBits
);

Assert.That(consoleOut.ToString(), Is.EqualTo("↓ 20.30k"));
}

[Test]
public async Task TestNetworkCommand_PrintsCustomUploadIcon()
{
SetupNetworkSpeed(10.5, 20.3);
var consoleOut = new StringWriter();
Console.SetOut(consoleOut);

await _cmd.ExecuteAsync(
showUploadIcon: true, uploadIconValue: "↑",
showDownloadIcon: false, downloadIconValue: "",
direction: NetworkDirection.Upload,
network: "wlo1", delay: 1, unit: NetworkUnits.KiloBits
);

Assert.That(consoleOut.ToString(), Is.EqualTo("↑ 10.50k"));
}

[Test]
public async Task TestNetworkCommand_PrintsBothWithIcons()
{
SetupNetworkSpeed(10.5, 20.3);
var consoleOut = new StringWriter();
Console.SetOut(consoleOut);

await _cmd.ExecuteAsync(
showUploadIcon: true, uploadIconValue: "↑",
showDownloadIcon: true, downloadIconValue: "↓",
direction: NetworkDirection.Both,
network: "wlo1", delay: 1, unit: NetworkUnits.KiloBits
);

Assert.That(consoleOut.ToString(), Is.EqualTo("↓ 20.30k ↑ 10.50k"));
}

[Test]
public async Task TestNetworkCommand_FormatsToTwoDecimalPlaces()
{
SetupNetworkSpeed(10.1234, 20.5678);
var consoleOut = new StringWriter();
Console.SetOut(consoleOut);

await _cmd.ExecuteAsync(
showUploadIcon: false, uploadIconValue: "",
showDownloadIcon: false, downloadIconValue: "",
direction: NetworkDirection.Both,
network: "wlo1", delay: 1, unit: NetworkUnits.KiloBits
);

Assert.That(consoleOut.ToString(), Is.EqualTo("20.57k 10.12k"));
}

[Test]
public async Task TestNetworkCommand_UsesCorrectNetworkInterface()
{
SetupNetworkSpeed(0, 0);
var consoleOut = new StringWriter();
Console.SetOut(consoleOut);

await _cmd.ExecuteAsync(
showUploadIcon: false, uploadIconValue: "",
showDownloadIcon: false, downloadIconValue: "",
direction: NetworkDirection.Both,
network: "eth0", delay: 1, unit: NetworkUnits.KiloBits
);

_mockStats.Verify(s => s.GetNetworkSpeed(It.IsAny<NetworkUnits>(), "eth0", It.IsAny<int>()), Times.Once);
}
}
137 changes: 137 additions & 0 deletions stmx.tests/Services/LinuxSystemStatsServiceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,5 +265,142 @@ public async Task GetCpuUsagePercent_ReturnsNull_OnIOException()

Assert.That(result, Is.Null);
}

[Test]
public void ReadNetworkSpeedFromSysFile_ParsesCorrectly()
{
_fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/wlo1")).Returns(true);
_fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny<string>()))
.Returns("1000") // tx_bytes
.Returns("2000"); // rx_bytes

var (upload, download) = _service.ReadNetworkSpeedFromSysFile("wlo1");

Assert.That(upload, Is.EqualTo(1000 * 8));
Assert.That(download, Is.EqualTo(2000 * 8));
}

[Test]
public void ReadNetworkSpeedFromSysFile_ThrowsIOException_WhenInterfaceNotFound()
{
_fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/eth99")).Returns(false);

Assert.Throws<IOException>(() => _service.ReadNetworkSpeedFromSysFile("eth99"));
}

[Test]
public async Task GetNetworkSpeed_ComputesCorrectBitsPerSecond()
{
_fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/wlo1")).Returns(true);

// First sample: 1000 tx, 2000 rx bytes
// Second sample: 4000 tx, 7000 rx bytes
// Over 1 second delay: upload = (4000-1000)*8 = 24000 bps, download = (7000-2000)*8 = 40000 bps
_fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny<string>()))
.Returns("1000")
.Returns("2000")
.Returns("4000")
.Returns("7000");

var (upload, download) = await _service.GetNetworkSpeed(NetworkUnits.Bits, "wlo1", 1);

Assert.That(upload.Value, Is.EqualTo(24000));
Assert.That(download.Value, Is.EqualTo(40000));
Assert.That(upload.Unit, Is.EqualTo(NetworkUnits.Bits));
Assert.That(download.Unit, Is.EqualTo(NetworkUnits.Bits));
}

[Test]
public async Task GetNetworkSpeed_ConvertsToKiloBits()
{
_fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/wlo1")).Returns(true);

// upload = (4000-1000)*8 = 24000 bps = ~23.4375 kbps
// download = (7000-2000)*8 = 40000 bps = ~39.0625 kbps
_fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny<string>()))
.Returns("1000")
.Returns("2000")
.Returns("4000")
.Returns("7000");

var (upload, download) = await _service.GetNetworkSpeed(NetworkUnits.KiloBits, "wlo1", 1);

Assert.That(upload.Unit, Is.EqualTo(NetworkUnits.KiloBits));
Assert.That(download.Unit, Is.EqualTo(NetworkUnits.KiloBits));
Assert.That(upload.Value, Is.EqualTo(24000.0 / 1024).Within(0.001));
Assert.That(download.Value, Is.EqualTo(40000.0 / 1024).Within(0.001));
}

[Test]
public async Task GetNetworkSpeed_Auto_ReturnsKiloBitsAtMinimum()
{
_fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/wlo1")).Returns(true);

// Very low speed — should still return KiloBits not Bits
_fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny<string>()))
.Returns("1000")
.Returns("2000")
.Returns("1001")
.Returns("2001");

var (upload, download) = await _service.GetNetworkSpeed(NetworkUnits.Auto, "wlo1", 1);

Assert.That(upload.Unit, Is.EqualTo(NetworkUnits.KiloBits));
Assert.That(download.Unit, Is.EqualTo(NetworkUnits.KiloBits));
}

[Test]
public async Task GetNetworkSpeed_Auto_SelectsMegaBits_WhenSpeedIsHigh()
{
_fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/wlo1")).Returns(true);

// delta = 200_000 bytes = 1_600_000 bits > 1_048_576 → MegaBits
_fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny<string>()))
.Returns("0")
.Returns("0")
.Returns("200000")
.Returns("200000");

var (upload, download) = await _service.GetNetworkSpeed(NetworkUnits.Auto, "wlo1", 1);

Assert.That(upload.Unit, Is.EqualTo(NetworkUnits.MegaBits));
Assert.That(download.Unit, Is.EqualTo(NetworkUnits.MegaBits));
}

[Test]
public async Task GetNetworkSpeed_HandlesCounterReset_Gracefully()
{
_fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/wlo1")).Returns(true);

// Counter went backwards (interface reset)
_fileReaderMock.SetupSequence(f => f.ReadAllText(It.IsAny<string>()))
.Returns("5000")
.Returns("5000")
.Returns("100")
.Returns("100");

var (upload, download) = await _service.GetNetworkSpeed(NetworkUnits.Bits, "wlo1", 1);

// Should not be negative
Assert.That(upload.Value, Is.GreaterThanOrEqualTo(0));
Assert.That(download.Value, Is.GreaterThanOrEqualTo(0));
}

[Test]
public void ReadNetworkSpeedFromSysFile_UsesDefaultInterface_WhenPassedDefault()
{
string mockRoute = "Iface\tDestination\tGateway\n" +
"eth0\t00000000\t0101A8C0\n";

_fileSystemMock.Setup(fs => fs.DirectoryExists("/sys/class/net/eth0")).Returns(true);
_fileReaderMock.Setup(f => f.ReadAllText("/proc/net/route")).Returns(mockRoute);
_fileReaderMock.Setup(f => f.ReadAllText("/sys/class/net/eth0/statistics/tx_bytes")).Returns("1000");
_fileReaderMock.Setup(f => f.ReadAllText("/sys/class/net/eth0/statistics/rx_bytes")).Returns("2000");

var (upload, download) = _service.ReadNetworkSpeedFromSysFile("default");

Assert.That(upload, Is.EqualTo(1000 * 8));
Assert.That(download, Is.EqualTo(2000 * 8));
}
}

Loading