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
3 changes: 0 additions & 3 deletions src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
<PackageTags>upgrade,update,client</PackageTags>
<Version>10.0.0-preview</Version>
<TargetFramework>netstandard2.0</TargetFramework>
<!-- Trim readiness within netstandard2.0 constraints -->
<IsTrimmable>true</IsTrimmable>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>

<ItemGroup>
Expand Down
118 changes: 118 additions & 0 deletions tests/CoreTest/Event/EventListenerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System;
using GeneralUpdate.Core.Download;
using GeneralUpdate.Core.Download.Models;
using GeneralUpdate.Core.Event;
using Xunit;

namespace CoreTest.Event;

public class EventListenerTests
{
private class TestListener : IUpdateEventListener
{
public int AllDownloadCompletedCalls;
public int DownloadCompletedCalls;
public int DownloadErrorCalls;
public int DownloadStatisticsCalls;
public int UpdateInfoCalls;
public int ExceptionCalls;
public int ProgressCalls;

public void OnAllDownloadCompleted(MultiAllDownloadCompletedEventArgs args)
=> AllDownloadCompletedCalls++;

public void OnDownloadCompleted(MultiDownloadCompletedEventArgs args)
=> DownloadCompletedCalls++;

public void OnDownloadError(MultiDownloadErrorEventArgs args)
=> DownloadErrorCalls++;

public void OnDownloadStatistics(MultiDownloadStatisticsEventArgs args)
=> DownloadStatisticsCalls++;

public void OnUpdateInfo(UpdateInfoEventArgs args)
=> UpdateInfoCalls++;

public void OnException(ExceptionEventArgs args)
=> ExceptionCalls++;

public void OnProgress(DownloadProgress progress)
=> ProgressCalls++;
}

[Fact]
public void EventManager_AddListener_And_Dispatch()
{
var listener = new TestListener();
EventManager.Instance.AddListener<MultiAllDownloadCompletedEventArgs>((s, e) => listener.OnAllDownloadCompleted(e));

var args = new MultiAllDownloadCompletedEventArgs(true, Array.Empty<(object, string)>());
EventManager.Instance.Dispatch(this, args);

Assert.Equal(1, listener.AllDownloadCompletedCalls);
}

[Fact]
public void EventManager_RemoveListener_StopsDispatch()
{
var listener = new TestListener();
Action<object, MultiDownloadCompletedEventArgs> handler = (s, e) => listener.OnDownloadCompleted(e);

EventManager.Instance.AddListener(handler);
EventManager.Instance.RemoveListener(handler);

var args = new MultiDownloadCompletedEventArgs(new object(), true);
EventManager.Instance.Dispatch(this, args);

Assert.Equal(0, listener.DownloadCompletedCalls);
}

[Fact]
public void EventManager_MultipleListeners_AllCalled()
{
var listener1 = new TestListener();
var listener2 = new TestListener();

EventManager.Instance.AddListener<ExceptionEventArgs>((s, e) => listener1.OnException(e));
EventManager.Instance.AddListener<ExceptionEventArgs>((s, e) => listener2.OnException(e));

var args = new ExceptionEventArgs(new Exception("test"), "test message");
EventManager.Instance.Dispatch(this, args);

Assert.Equal(1, listener1.ExceptionCalls);
Assert.Equal(1, listener2.ExceptionCalls);
}

[Fact]
public void ProgressEventArgs_Constructor()
{
var progress = new DownloadProgress("asset.zip", 500, 1000, 50.0, DownloadStatus.Downloading);
var args = new ProgressEventArgs(progress);

Assert.Same(progress, args.Progress);
Assert.Equal("asset.zip", args.Progress.AssetName);
Assert.Equal(500, args.Progress.BytesDownloaded);
Assert.Equal(1000, args.Progress.TotalBytes);
Assert.Equal(50.0, args.Progress.Percentage);
Assert.Equal(DownloadStatus.Downloading, args.Progress.Status);
}

[Fact]
public void EventArgs_Types_Constructed()
{
var allDone = new MultiAllDownloadCompletedEventArgs(true, Array.Empty<(object, string)>());
Assert.True(allDone.IsAllDownloadCompleted);

var downloadDone = new MultiDownloadCompletedEventArgs(new object(), true);
Assert.NotNull(downloadDone.Version);
Assert.True(downloadDone.IsComplated);

var ex = new Exception("boom");
var err = new MultiDownloadErrorEventArgs(ex, new object());
Assert.Same(ex, err.Exception);

var stats = new MultiDownloadStatisticsEventArgs(new object(), TimeSpan.FromSeconds(1), "1MB/s", 1000, 500, 50.0);
Assert.Equal("1MB/s", stats.Speed);
Assert.Equal(1000, stats.TotalBytesToReceive);
}
}
94 changes: 94 additions & 0 deletions tests/CoreTest/FileSystem/BackupRestoreTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System;
using System.IO;
using System.Linq;
using GeneralUpdate.Core.FileSystem;
using Xunit;

namespace CoreTest.Backup;

public class BackupRestoreTests
{
[Fact]
public void Backup_And_Restore_Roundtrip()
{
var tmpRoot = Path.Combine(Path.GetTempPath(), "CoreTest.Backup." + Guid.NewGuid().ToString("N"));
var sourceDir = Path.Combine(tmpRoot, "source");
var backupDir = Path.Combine(tmpRoot, "backup");
var restoreDir = Path.Combine(tmpRoot, "restored");

try
{
Directory.CreateDirectory(sourceDir);
File.WriteAllText(Path.Combine(sourceDir, "app.exe"), "v1.0");
File.WriteAllText(Path.Combine(sourceDir, "config.json"), "{}");
var subDir = Path.Combine(sourceDir, "data");
Directory.CreateDirectory(subDir);
File.WriteAllText(Path.Combine(subDir, "data.db"), "mydata");

StorageManager.Backup(sourceDir, backupDir, Array.Empty<string>());
Assert.True(Directory.Exists(backupDir));
Assert.True(File.Exists(Path.Combine(backupDir, "app.exe")));
Assert.True(File.Exists(Path.Combine(backupDir, "config.json")));

StorageManager.Restore(backupDir, restoreDir);
Assert.True(Directory.Exists(restoreDir));
Assert.Equal("v1.0", File.ReadAllText(Path.Combine(restoreDir, "app.exe")));
Assert.Equal("{}", File.ReadAllText(Path.Combine(restoreDir, "config.json")));
}
finally
{
if (Directory.Exists(tmpRoot)) Directory.Delete(tmpRoot, true);
}
}

[Fact]
public void CleanBackup_KeepsOnlyRecentVersions()
{
var installPath = Path.Combine(Path.GetTempPath(), "CoreTest.CleanBackup." + Guid.NewGuid().ToString("N"));
var backupRoot = Path.Combine(installPath, "__backups");
try
{
for (int i = 1; i <= 5; i++)
{
var verDir = Path.Combine(backupRoot, $"{i}.0.0");
Directory.CreateDirectory(verDir);
File.WriteAllText(Path.Combine(verDir, "app.exe"), $"v{i}");
}

StorageManager.CleanBackup(installPath, keepVersions: 3);

var remaining = Directory.GetDirectories(backupRoot);
Assert.Equal(3, remaining.Length);
var names = remaining.Select(Path.GetFileName).OrderBy(n => new Version(n!)).ToList();
Assert.Equal("3.0.0", names[0]);
Assert.Equal("4.0.0", names[1]);
Assert.Equal("5.0.0", names[2]);
}
finally
{
if (Directory.Exists(installPath)) Directory.Delete(installPath, true);
}
}

[Fact]
public void ListBackups_ReturnsMetadata()
{
var installPath = Path.Combine(Path.GetTempPath(), "CoreTest.ListBackups." + Guid.NewGuid().ToString("N"));
var backupRoot = Path.Combine(installPath, "__backups");
try
{
var verDir = Path.Combine(backupRoot, "1.0.0");
Directory.CreateDirectory(verDir);
File.WriteAllText(Path.Combine(verDir, "app.exe"), "v1");

var backups = StorageManager.ListBackups(installPath);
Assert.Single(backups);
Assert.Equal("1.0.0", backups[0].Version);
Assert.Contains("__backups", backups[0].Path);
}
finally
{
if (Directory.Exists(installPath)) Directory.Delete(installPath, true);
}
}
}
44 changes: 44 additions & 0 deletions tests/CoreTest/Hooks/HooksTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.Threading.Tasks;
using GeneralUpdate.Core.Hooks;
using Xunit;

namespace CoreTest.Hooks;

public class HooksTests
{
[Fact]
public async Task NoOpUpdateHooks_AllMethods_ReturnDefaults()
{
var hooks = new NoOpUpdateHooks();
var ctx = new UpdateContext("test", "/tmp", "1.0", "2.0", 1);

Assert.True(await hooks.OnBeforeUpdateAsync(ctx));
await hooks.OnDownloadCompletedAsync(new("a", "1.0", 100, TimeSpan.Zero, null, true));
await hooks.OnAfterUpdateAsync(ctx);
await hooks.OnUpdateErrorAsync(ctx, new Exception("test"));
await hooks.OnBeforeStartAppAsync(ctx);
}

[Fact]
public void UpdateContext_RecordEquality_Works()
{
var a = new UpdateContext("app", "/path", "1.0", "2.0", 1);
var b = new UpdateContext("app", "/path", "1.0", "2.0", 1);
var c = new UpdateContext("app2", "/path", "1.0", "2.0", 1);

Assert.Equal(a, b);
Assert.NotEqual(a, c);
}

[Fact]
public void DownloadContext_RecordEquality_Works()
{
var a = new DownloadContext("asset", "1.0", 100, TimeSpan.FromSeconds(1), "/tmp/a.zip", true);
var b = new DownloadContext("asset", "1.0", 100, TimeSpan.FromSeconds(1), "/tmp/a.zip", true);
var c = a with { AssetName = "other" };

Assert.Equal(a, b);
Assert.NotEqual(a, c);
}
}
77 changes: 77 additions & 0 deletions tests/CoreTest/Ipc/ProcessInfoProviderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using GeneralUpdate.Core.Configuration;
using GeneralUpdate.Core.Ipc;
using Xunit;

namespace CoreTest.Ipc;

public class ProcessInfoProviderTests
{
[Fact]
public async Task EncryptedFileProvider_SendReceive_RoundTrips()
{
var tmpDir = Path.Combine(Path.GetTempPath(), "CoreTest.Ipc", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(tmpDir);
try
{
var provider = new EncryptedFileProcessInfoProvider(tmpDir);
var info = new ProcessInfo(
appName: "test-app",
installPath: Path.GetTempPath(),
currentVersion: "1.0.0",
lastVersion: "2.0.0",
updateLogUrl: "https://example.com/log",
compressEncoding: System.Text.Encoding.UTF8,
compressFormat: "ZIP",
downloadTimeOut: 30,
appSecretKey: "secret",
updateVersions: new List<VersionInfo> { new() { Version = "1.0.0", Name = "test" } },
reportUrl: "https://example.com/report",
backupDirectory: "/tmp/backup",
bowl: "",
scheme: "",
token: "",
script: "",
driverDirectory: "",
blackFileFormats: new List<string> { ".pdb" },
blackFiles: new List<string> { "test.dll" },
skipDirectories: new List<string> { "logs" }
);

await provider.SendAsync(info);
var result = await provider.ReceiveAsync();

Assert.NotNull(result);
Assert.Equal("test-app", result!.AppName);
Assert.Equal("1.0.0", result.CurrentVersion);
Assert.NotEmpty(result.BlackFileFormats);

Assert.False(Directory.GetFiles(tmpDir, "*.enc").Length > 0,
"Encrypted file should be deleted after ReceiveAsync");
}
finally
{
if (Directory.Exists(tmpDir)) Directory.Delete(tmpDir, true);
}
}

[Fact]
public async Task EncryptedFileProvider_NoFile_ReturnsNull()
{
var tmpDir = Path.Combine(Path.GetTempPath(), "CoreTest.Ipc.Empty." + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(tmpDir);
try
{
var provider = new EncryptedFileProcessInfoProvider(tmpDir);
var result = await provider.ReceiveAsync();
Assert.Null(result);
}
finally
{
if (Directory.Exists(tmpDir)) Directory.Delete(tmpDir, true);
}
}
}
Loading