Skip to content

Commit bef42b5

Browse files
committed
feat: add unit tests for Early Access update handling
1 parent fe91ee6 commit bef42b5

File tree

3 files changed

+282
-0
lines changed

3 files changed

+282
-0
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
using Microsoft.Extensions.Logging;
2+
using NSubstitute;
3+
using StabilityMatrix.Avalonia.Services;
4+
using StabilityMatrix.Avalonia.ViewModels.Base;
5+
using StabilityMatrix.Avalonia.ViewModels.CheckpointManager;
6+
using StabilityMatrix.Core.Models;
7+
using StabilityMatrix.Core.Models.Api;
8+
using StabilityMatrix.Core.Models.Database;
9+
using StabilityMatrix.Core.Models.Settings;
10+
using StabilityMatrix.Core.Services;
11+
12+
namespace StabilityMatrix.Tests.Avalonia;
13+
14+
[TestClass]
15+
public class CheckpointFileViewModelTests
16+
{
17+
[TestMethod]
18+
public void HasStandardUpdate_IsFalse_WhenUpdateIsEarlyAccessOnly()
19+
{
20+
var vm = CreateViewModel(CreateCheckpointFile(hasUpdate: true, hasEarlyAccessUpdateOnly: true));
21+
22+
Assert.IsTrue(vm.HasEarlyAccessUpdateOnly);
23+
Assert.IsFalse(vm.HasStandardUpdate);
24+
}
25+
26+
[TestMethod]
27+
public void CheckpointFile_Setter_RaisesDerivedUpdatePropertyNotifications()
28+
{
29+
var vm = CreateViewModel(CreateCheckpointFile(hasUpdate: true, hasEarlyAccessUpdateOnly: true));
30+
var changed = new List<string>();
31+
32+
vm.PropertyChanged += (_, e) =>
33+
{
34+
if (!string.IsNullOrWhiteSpace(e.PropertyName))
35+
{
36+
changed.Add(e.PropertyName!);
37+
}
38+
};
39+
40+
vm.CheckpointFile = CreateCheckpointFile(hasUpdate: true, hasEarlyAccessUpdateOnly: false);
41+
42+
Assert.IsFalse(vm.HasEarlyAccessUpdateOnly);
43+
Assert.IsTrue(vm.HasStandardUpdate);
44+
CollectionAssert.Contains(changed, nameof(CheckpointFileViewModel.HasEarlyAccessUpdateOnly));
45+
CollectionAssert.Contains(changed, nameof(CheckpointFileViewModel.HasStandardUpdate));
46+
}
47+
48+
private static CheckpointFileViewModel CreateViewModel(LocalModelFile checkpointFile)
49+
{
50+
var settingsManager = Substitute.For<ISettingsManager>();
51+
settingsManager.Settings.Returns(new Settings { ShowNsfwInCheckpointsPage = true });
52+
settingsManager.IsLibraryDirSet.Returns(false);
53+
54+
return new CheckpointFileViewModel(
55+
settingsManager,
56+
Substitute.For<IModelIndexService>(),
57+
Substitute.For<INotificationService>(),
58+
Substitute.For<IDownloadService>(),
59+
Substitute.For<IServiceManager<ViewModelBase>>(),
60+
Substitute.For<ILogger>(),
61+
checkpointFile
62+
);
63+
}
64+
65+
private static LocalModelFile CreateCheckpointFile(bool hasUpdate, bool hasEarlyAccessUpdateOnly)
66+
{
67+
return new LocalModelFile
68+
{
69+
RelativePath = "StableDiffusion/test-vm.safetensors",
70+
SharedFolderType = SharedFolderType.StableDiffusion,
71+
HasUpdate = hasUpdate,
72+
HasEarlyAccessUpdateOnly = hasEarlyAccessUpdateOnly,
73+
ConnectedModelInfo = new ConnectedModelInfo
74+
{
75+
ModelId = 77,
76+
VersionId = 700,
77+
Source = ConnectedModelSource.Civitai,
78+
ModelName = "VM Test Model",
79+
ModelDescription = string.Empty,
80+
VersionName = "v700",
81+
Tags = [],
82+
Hashes = new CivitFileHashes(),
83+
},
84+
};
85+
}
86+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
using System.Reflection;
2+
using StabilityMatrix.Core.Models;
3+
using StabilityMatrix.Core.Models.Api;
4+
using StabilityMatrix.Core.Models.Database;
5+
using StabilityMatrix.Core.Services;
6+
7+
namespace StabilityMatrix.Tests.Core;
8+
9+
[TestClass]
10+
public class ModelIndexServiceTests
11+
{
12+
[TestMethod]
13+
public void GetHasEarlyAccessUpdateOnly_ReturnsTrue_WhenAllNewerVersionsAreEarlyAccess()
14+
{
15+
var model = CreateLocalModel(installedVersionId: 100, hasUpdate: true);
16+
var remoteModel = CreateRemoteModel(
17+
CreateVersion(id: 300, isEarlyAccess: true),
18+
CreateVersion(id: 200, isEarlyAccess: true),
19+
CreateVersion(id: 100, isEarlyAccess: false)
20+
);
21+
22+
var result = InvokeGetHasEarlyAccessUpdateOnly(model, remoteModel);
23+
24+
Assert.IsTrue(result);
25+
}
26+
27+
[TestMethod]
28+
public void GetHasEarlyAccessUpdateOnly_ReturnsFalse_WhenAnyNewerVersionIsPublic()
29+
{
30+
var model = CreateLocalModel(installedVersionId: 100, hasUpdate: true);
31+
var remoteModel = CreateRemoteModel(
32+
CreateVersion(id: 300, isEarlyAccess: true),
33+
CreateVersion(id: 200, isEarlyAccess: false),
34+
CreateVersion(id: 100, isEarlyAccess: false)
35+
);
36+
37+
var result = InvokeGetHasEarlyAccessUpdateOnly(model, remoteModel);
38+
39+
Assert.IsFalse(result);
40+
}
41+
42+
[TestMethod]
43+
public void GetHasEarlyAccessUpdateOnly_ReturnsFalse_WhenInstalledVersionIsLatest()
44+
{
45+
var model = CreateLocalModel(installedVersionId: 100, hasUpdate: true);
46+
var remoteModel = CreateRemoteModel(
47+
CreateVersion(id: 100, isEarlyAccess: false),
48+
CreateVersion(id: 90, isEarlyAccess: true)
49+
);
50+
51+
var result = InvokeGetHasEarlyAccessUpdateOnly(model, remoteModel);
52+
53+
Assert.IsFalse(result);
54+
}
55+
56+
[TestMethod]
57+
public void GetHasEarlyAccessUpdateOnly_ReturnsFalse_WhenModelHasNoUpdate()
58+
{
59+
var model = CreateLocalModel(installedVersionId: 100, hasUpdate: false);
60+
var remoteModel = CreateRemoteModel(
61+
CreateVersion(id: 300, isEarlyAccess: true),
62+
CreateVersion(id: 200, isEarlyAccess: true),
63+
CreateVersion(id: 100, isEarlyAccess: false)
64+
);
65+
66+
var result = InvokeGetHasEarlyAccessUpdateOnly(model, remoteModel);
67+
68+
Assert.IsFalse(result);
69+
}
70+
71+
private static bool InvokeGetHasEarlyAccessUpdateOnly(LocalModelFile model, CivitModel? remoteModel)
72+
{
73+
var method = typeof(ModelIndexService).GetMethod(
74+
"GetHasEarlyAccessUpdateOnly",
75+
BindingFlags.NonPublic | BindingFlags.Static
76+
);
77+
78+
Assert.IsNotNull(method);
79+
80+
var result = method.Invoke(null, [model, remoteModel]);
81+
82+
Assert.IsNotNull(result);
83+
84+
return (bool)result;
85+
}
86+
87+
private static LocalModelFile CreateLocalModel(int installedVersionId, bool hasUpdate)
88+
{
89+
return new LocalModelFile
90+
{
91+
RelativePath = "StableDiffusion/test-model.safetensors",
92+
SharedFolderType = SharedFolderType.StableDiffusion,
93+
HasUpdate = hasUpdate,
94+
ConnectedModelInfo = new ConnectedModelInfo
95+
{
96+
ModelId = 123,
97+
VersionId = installedVersionId,
98+
Source = ConnectedModelSource.Civitai,
99+
ModelName = "Test Model",
100+
ModelDescription = string.Empty,
101+
VersionName = $"v{installedVersionId}",
102+
Tags = [],
103+
Hashes = new CivitFileHashes(),
104+
},
105+
};
106+
}
107+
108+
private static CivitModel CreateRemoteModel(params CivitModelVersion[] versions)
109+
{
110+
return new CivitModel
111+
{
112+
Id = 123,
113+
Name = "Test Model",
114+
Description = string.Empty,
115+
Type = CivitModelType.Unknown,
116+
Tags = [],
117+
Stats = new CivitModelStats(),
118+
ModelVersions = versions.ToList(),
119+
};
120+
}
121+
122+
private static CivitModelVersion CreateVersion(int id, bool isEarlyAccess)
123+
{
124+
return new CivitModelVersion
125+
{
126+
Id = id,
127+
Name = $"v{id}",
128+
Description = string.Empty,
129+
DownloadUrl = string.Empty,
130+
TrainedWords = [],
131+
Availability = isEarlyAccess ? "EarlyAccess" : "Public",
132+
Stats = new CivitModelStats(),
133+
};
134+
}
135+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using StabilityMatrix.Core.Models;
2+
using StabilityMatrix.Core.Models.Api;
3+
using StabilityMatrix.Core.Models.Database;
4+
5+
namespace StabilityMatrix.Tests.Models;
6+
7+
[TestClass]
8+
public class LocalModelFileTests
9+
{
10+
[TestMethod]
11+
public void Equals_ReturnsFalse_WhenEarlyAccessOnlyFlagDiffers()
12+
{
13+
var standardUpdateModel = CreateLocalModelFile(hasEarlyAccessUpdateOnly: false);
14+
var earlyAccessOnlyModel = standardUpdateModel with { HasEarlyAccessUpdateOnly = true };
15+
16+
Assert.IsFalse(standardUpdateModel.Equals(earlyAccessOnlyModel));
17+
Assert.IsFalse(
18+
LocalModelFile.RelativePathConnectedModelInfoComparer.Equals(
19+
standardUpdateModel,
20+
earlyAccessOnlyModel
21+
)
22+
);
23+
}
24+
25+
[TestMethod]
26+
public void RelativePathConnectedModelInfoComparer_TreatsEarlyAccessFlagAsDistinct()
27+
{
28+
var standardUpdateModel = CreateLocalModelFile(hasEarlyAccessUpdateOnly: false);
29+
var earlyAccessOnlyModel = standardUpdateModel with { HasEarlyAccessUpdateOnly = true };
30+
31+
var set = new HashSet<LocalModelFile>(LocalModelFile.RelativePathConnectedModelInfoComparer)
32+
{
33+
standardUpdateModel,
34+
earlyAccessOnlyModel,
35+
};
36+
37+
Assert.AreEqual(2, set.Count);
38+
}
39+
40+
private static LocalModelFile CreateLocalModelFile(bool hasEarlyAccessUpdateOnly)
41+
{
42+
return new LocalModelFile
43+
{
44+
RelativePath = "StableDiffusion/model-a.safetensors",
45+
SharedFolderType = SharedFolderType.StableDiffusion,
46+
HasUpdate = true,
47+
HasEarlyAccessUpdateOnly = hasEarlyAccessUpdateOnly,
48+
ConnectedModelInfo = new ConnectedModelInfo
49+
{
50+
ModelId = 123,
51+
VersionId = 101,
52+
Source = ConnectedModelSource.Civitai,
53+
ModelName = "Model A",
54+
ModelDescription = string.Empty,
55+
VersionName = "v101",
56+
Tags = [],
57+
Hashes = new CivitFileHashes(),
58+
},
59+
};
60+
}
61+
}

0 commit comments

Comments
 (0)