Skip to content

Commit 0043c36

Browse files
Update .NET version to 10.0 and adjust related configurations
- Updated DOTNET_VERSION in workflows to 10.0 - Changed target framework in test project to net10.0 - Modified global.json to set SDK version to 10.0.100 - Updated PSBuild script for new test command syntax - Added CLAUDE.md for project guidance and build commands - Refactored assertions in tests for consistency and clarity
1 parent 95be4ce commit 0043c36

9 files changed

Lines changed: 139 additions & 49 deletions

File tree

.github/workflows/dotnet.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ concurrency:
2020
permissions: read-all
2121

2222
env:
23-
DOTNET_VERSION: "9.0" # Only needed for actions/setup-dotnet
23+
DOTNET_VERSION: "10.0" # Only needed for actions/setup-dotnet
2424

2525
jobs:
2626
build:
@@ -96,7 +96,7 @@ jobs:
9696
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
9797
shell: powershell
9898
run: |
99-
.\.sonar\scanner\dotnet-sonarscanner begin /k:"${{ github.repository_owner }}_${{ github.event.repository.name }}" /o:"${{ github.repository_owner }}" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="coverage/coverage.opencover.xml" /d:sonar.coverage.exclusions="**/*Test*.cs,**/*.Tests.cs,**/*.Tests/**/*,**/obj/**/*,**/*.dll" /d:sonar.cs.vstest.reportsPaths="coverage/TestResults/**/*.trx"
99+
.\.sonar\scanner\dotnet-sonarscanner begin /k:"${{ github.repository_owner }}_${{ github.event.repository.name }}" /o:"${{ github.repository_owner }}" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.vscoveragexml.reportsPaths="coverage/coverage.xml" /d:sonar.coverage.exclusions="**/*Test*.cs,**/*.Tests.cs,**/*.Tests/**/*,**/obj/**/*,**/*.dll" /d:sonar.cs.vstest.reportsPaths="coverage/TestResults/**/*.trx"
100100
101101
- name: Run PSBuild Pipeline
102102
id: pipeline

.github/workflows/update-sdks.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ concurrency:
1919
permissions: read-all
2020

2121
env:
22-
DOTNET_VERSION: "9.0"
22+
DOTNET_VERSION: "10.0"
2323

2424
jobs:
2525
update-sdks:
@@ -257,7 +257,7 @@ jobs:
257257

258258
- name: Run Tests
259259
if: steps.update_sdks.outputs.has_updates == 'true'
260-
run: dotnet test --no-build --configuration Release --logger trx --collect:"XPlat Code Coverage"
260+
run: dotnet test --no-build --configuration Release --report-trx
261261

262262
- name: Check for Changes
263263
if: steps.update_sdks.outputs.has_updates == 'true'

AppDataStorage.Test/AppDataStorage.Test.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44

55
<PropertyGroup>
66
<IsTestProject>true</IsTestProject>
7-
<TargetFramework>net9.0</TargetFramework>
7+
<TargetFramework>net10.0</TargetFramework>
88
<TargetFrameworks></TargetFrameworks>
99
<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
1010
<TestingPlatformShowTestsFailure>true</TestingPlatformShowTestsFailure>
1111
<TestingPlatformShowTestsFailureDetails>true</TestingPlatformShowTestsFailureDetails>
1212
</PropertyGroup>
1313

1414
<ItemGroup>
15-
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" />
1615
<ProjectReference Include="..\AppDataStorage\AppDataStorage.csproj" />
1716
<PackageReference Include="TestableIO.System.IO.Abstractions.TestingHelpers" />
1817
</ItemGroup>

AppDataStorage.Test/AppDataTests.cs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// All rights reserved.
33
// Licensed under the MIT license.
44

5+
[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
6+
57
namespace ktsu.AppDataStorage.Test;
68

79
using System;
@@ -158,7 +160,7 @@ private static void VerifyFileContent(AbsoluteFilePath filePath, string expected
158160
{
159161
Assert.IsTrue(AppData.FileSystem.File.Exists(filePath), "File should exist before reading content.");
160162
string actualContent = AppData.FileSystem.File.ReadAllText(filePath);
161-
Assert.IsTrue(actualContent.Contains(expectedContent), message);
163+
Assert.Contains(expectedContent, actualContent, message);
162164
}
163165

164166
[TestMethod]
@@ -262,7 +264,7 @@ public void TestQueueSaveSetsSaveQueuedTime()
262264

263265
appData.QueueSave();
264266

265-
Assert.IsTrue(appData.SaveQueuedTime >= beforeQueueTime, "SaveQueuedTime was not set correctly.");
267+
Assert.IsGreaterThanOrEqualTo(beforeQueueTime, appData.SaveQueuedTime, "SaveQueuedTime was not set correctly.");
266268
}
267269

268270
[TestMethod]
@@ -427,7 +429,7 @@ public void TestAppDataSerializationIncludesFields()
427429
using TestAppData appData = new();
428430
string json = JsonSerializer.Serialize(appData, AppData.JsonSerializerOptions);
429431

430-
Assert.IsTrue(json.Contains("\"Data\""), "Serialized JSON should include fields.");
432+
Assert.Contains("\"Data\"", json, "Serialized JSON should include fields.");
431433
}
432434

433435
[TestMethod]
@@ -641,7 +643,7 @@ public void TestQueueSaveStaticMethod()
641643
TestAppData.QueueSave();
642644

643645
TestAppData appData = TestAppData.Get();
644-
Assert.IsTrue(appData.SaveQueuedTime >= beforeQueueTime, "SaveQueuedTime was not set correctly.");
646+
Assert.IsGreaterThanOrEqualTo(beforeQueueTime, appData.SaveQueuedTime, "SaveQueuedTime was not set correctly.");
645647
}
646648

647649
[TestMethod]
@@ -726,7 +728,7 @@ public void TestJsonSerializerOptionsConfiguration()
726728
Assert.IsTrue(options.WriteIndented, "Should have WriteIndented set to true");
727729
Assert.IsTrue(options.IncludeFields, "Should have IncludeFields set to true");
728730
Assert.IsNotNull(options.ReferenceHandler, "Should have ReferenceHandler configured");
729-
Assert.IsTrue(options.Converters.Count > 0, "Should have converters configured");
731+
Assert.IsNotEmpty(options.Converters, "Should have converters configured");
730732
}
731733

732734
[TestMethod]
@@ -751,7 +753,7 @@ public void TestBackupFileRecoveryWithTimestamp()
751753

752754
// Check that a timestamped backup exists
753755
string[] timestampedBackups = AppData.FileSystem.Directory.GetFiles(appData.FilePath.DirectoryPath.ToString(), "*.bk.*");
754-
Assert.IsTrue(timestampedBackups.Length > 0, "Should have created a timestamped backup");
756+
Assert.IsNotEmpty(timestampedBackups, "Should have created a timestamped backup");
755757
}
756758

757759
[TestMethod]
@@ -801,8 +803,8 @@ public void TestMultipleInstancesWithDifferentFileNames()
801803
appData2.Save();
802804

803805
Assert.AreNotEqual(appData1.FilePath, appData2.FilePath, "Instances should have different file paths");
804-
Assert.IsTrue(appData1.FilePath.ToString().Contains("file1.json"), "First instance should use custom filename");
805-
Assert.IsTrue(appData2.FilePath.ToString().Contains("file2.json"), "Second instance should use custom filename");
806+
Assert.Contains("file1.json", appData1.FilePath.ToString(), "First instance should use custom filename");
807+
Assert.Contains("file2.json", appData2.FilePath.ToString(), "Second instance should use custom filename");
806808
}
807809

808810
[TestMethod]
@@ -879,7 +881,7 @@ public void TestConcurrentAccess()
879881
thread.Join(TimeSpan.FromSeconds(30)); // Timeout after 30 seconds
880882
}
881883

882-
Assert.AreEqual(0, exceptions.Count, $"No exceptions should occur during concurrent access. Exceptions: {string.Join(", ", exceptions.Select(e => e.Message))}");
884+
Assert.IsEmpty(exceptions, $"No exceptions should occur during concurrent access. Exceptions: {string.Join(", ", exceptions.Select(e => e.Message))}");
883885
}
884886

885887
[TestMethod]
@@ -986,7 +988,7 @@ public void TestFileSystemPropertyThreadSafety()
986988
thread.Join();
987989
}
988990

989-
Assert.AreEqual(3, fileSystemInstances.Count, "Each thread should access FileSystem");
991+
Assert.HasCount(3, fileSystemInstances, "Each thread should access FileSystem");
990992
}
991993

992994
[TestMethod]
@@ -1079,8 +1081,8 @@ public void TestSaveUpdatesLastSaveTime()
10791081
appData.Save();
10801082

10811083
DateTime afterSave = DateTime.UtcNow;
1082-
Assert.IsTrue(appData.LastSaveTime >= beforeSave, "LastSaveTime should be updated after save");
1083-
Assert.IsTrue(appData.LastSaveTime <= afterSave, "LastSaveTime should not be in the future");
1084+
Assert.IsGreaterThanOrEqualTo(beforeSave, appData.LastSaveTime, "LastSaveTime should be updated after save");
1085+
Assert.IsLessThanOrEqualTo(afterSave, appData.LastSaveTime, "LastSaveTime should not be in the future");
10841086
}
10851087

10861088
[TestMethod]
@@ -1136,7 +1138,7 @@ public void TestTimestampedBackupWithMultipleCollisions()
11361138

11371139
// Verify that a uniquely timestamped backup was created
11381140
List<string> backupFiles = [.. (AppData.FileSystem as MockFileSystem)?.AllFiles.Where(f => f.Contains(".bk.")) ?? []];
1139-
Assert.IsTrue(backupFiles.Count > 3, "Should create a unique timestamped backup");
1141+
Assert.IsGreaterThan(3, backupFiles.Count, "Should create a unique timestamped backup");
11401142
}
11411143

11421144
[TestMethod]
@@ -1308,8 +1310,7 @@ public void TestFileSystemEdgeCaseEmptyPaths()
13081310
AppData.EnsureDirectoryExists(AbsoluteFilePath.Create(string.Empty));
13091311
AppData.EnsureDirectoryExists(AbsoluteDirectoryPath.Create(string.Empty));
13101312

1311-
// Should not throw and handle gracefully
1312-
Assert.IsTrue(true); // If we get here, the method handled empty paths correctly
1313+
// Should not throw and handle gracefully - if we get here, the method handled empty paths correctly
13131314
}
13141315

13151316
[TestMethod]
@@ -1325,8 +1326,8 @@ public void TestFileNameGenerationEdgeCases()
13251326
// Test with complex class names
13261327
using VeryLongComplexClassNameForTestingAppData appData = new();
13271328
string fileName = appData.FileName.ToString();
1328-
Assert.IsTrue(fileName.Contains("very_long_complex_class_name_for_testing_app_data"));
1329-
Assert.IsTrue(fileName.EndsWith(".json"));
1329+
Assert.Contains("very_long_complex_class_name_for_testing_app_data", fileName);
1330+
Assert.EndsWith(".json", fileName);
13301331
}
13311332

13321333
[TestMethod]
@@ -1340,8 +1341,7 @@ public void TestDisposeMultipleTimesWithSaveQueued()
13401341
appData.Dispose();
13411342
appData.Dispose();
13421343

1343-
// Should handle multiple disposes gracefully
1344-
Assert.IsTrue(true);
1344+
// Should handle multiple disposes gracefully - if we get here, the method succeeded
13451345
}
13461346

13471347
[TestMethod]
@@ -1370,9 +1370,9 @@ public void TestComplexDirectoryNestingWithSpecialCharacters()
13701370
appData.Data = "Complex path test";
13711371
appData.Save();
13721372

1373-
Assert.IsTrue(appData.FilePath.ToString().Contains("level1"));
1374-
Assert.IsTrue(appData.FilePath.ToString().Contains("level4_with_underscores"));
1375-
Assert.IsTrue(appData.FilePath.ToString().Contains("file with spaces & special chars.json"));
1373+
Assert.Contains("level1", appData.FilePath.ToString());
1374+
Assert.Contains("level4_with_underscores", appData.FilePath.ToString());
1375+
Assert.Contains("file with spaces & special chars.json", appData.FilePath.ToString());
13761376
}
13771377

13781378
[TestMethod]
@@ -1400,10 +1400,10 @@ public void TestAppDomainPathGeneration()
14001400
string appDataPath = AppData.AppDataPath.ToString();
14011401
string fullPath = AppData.Path.ToString();
14021402

1403-
Assert.IsFalse(string.IsNullOrEmpty(appDomain));
1404-
Assert.IsFalse(string.IsNullOrEmpty(appDataPath));
1405-
Assert.IsTrue(fullPath.Contains(appDomain));
1406-
Assert.IsTrue(fullPath.Contains(appDataPath));
1403+
Assert.IsNotEmpty(appDomain);
1404+
Assert.IsNotEmpty(appDataPath);
1405+
Assert.Contains(appDomain, fullPath);
1406+
Assert.Contains(appDataPath, fullPath);
14071407
}
14081408
}
14091409

AppDataStorage/AppData.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
// All rights reserved.
33
// Licensed under the MIT license.
44

5+
using System.Runtime.CompilerServices;
6+
7+
[assembly: InternalsVisibleTo("ktsu.AppDataStorage.Test")]
8+
59
namespace ktsu.AppDataStorage;
610

711
using System.IO.Abstractions;
@@ -86,7 +90,7 @@ internal static IFileSystem FileSystem
8690
/// <summary>
8791
/// The default file system implementation used when no thread-local override is set.
8892
/// </summary>
89-
private static readonly IFileSystem DefaultFileSystem = new FileSystem();
93+
private static IFileSystem DefaultFileSystem { get; } = new FileSystem();
9094

9195
/// <summary>
9296
/// Ensures that the directory for the specified file path exists.
@@ -143,8 +147,8 @@ internal static void EnsureDirectoryExists(AbsoluteDirectoryPath path)
143147
/// <exception cref="ArgumentNullException">Thrown when <paramref name="appData"/> or <paramref name="text"/> is null.</exception>
144148
public static void WriteText<T>(T appData, string text) where T : AppData<T>, new()
145149
{
146-
Guard.NotNull(appData);
147-
Guard.NotNull(text);
150+
Ensure.NotNull(appData);
151+
Ensure.NotNull(text);
148152

149153
lock (AppData<T>.Lock)
150154
{
@@ -177,7 +181,7 @@ internal static void EnsureDirectoryExists(AbsoluteDirectoryPath path)
177181
/// <exception cref="ArgumentNullException">Thrown when <paramref name="appData"/> is null.</exception>
178182
public static string ReadText<T>(T appData) where T : AppData<T>, new()
179183
{
180-
Guard.NotNull(appData);
184+
Ensure.NotNull(appData);
181185

182186
lock (AppData<T>.Lock)
183187
{
@@ -220,7 +224,7 @@ internal static void EnsureDirectoryExists(AbsoluteDirectoryPath path)
220224
/// <exception cref="ArgumentNullException">Thrown when <paramref name="appData"/> is null.</exception>
221225
public static void QueueSave<T>(this T appData) where T : AppData<T>, new()
222226
{
223-
Guard.NotNull(appData);
227+
Ensure.NotNull(appData);
224228

225229
lock (AppData<T>.Lock)
226230
{
@@ -237,7 +241,7 @@ internal static void EnsureDirectoryExists(AbsoluteDirectoryPath path)
237241
/// <exception cref="ArgumentNullException">Thrown when <paramref name="appData"/> is null.</exception>
238242
public static void SaveIfRequired<T>(this T appData) where T : AppData<T>, new()
239243
{
240-
Guard.NotNull(appData);
244+
Ensure.NotNull(appData);
241245

242246
lock (AppData<T>.Lock)
243247
{
@@ -270,7 +274,7 @@ internal static void EnsureDirectoryExists(AbsoluteDirectoryPath path)
270274
/// </example>
271275
public static void ConfigureForTesting(Func<IFileSystem> fileSystemFactory)
272276
{
273-
Guard.NotNull(fileSystemFactory);
277+
Ensure.NotNull(fileSystemFactory);
274278

275279
// Validate that the factory produces mock/test file systems by testing it once
276280
IFileSystem testInstance = fileSystemFactory();
@@ -290,7 +294,7 @@ public static void ConfigureForTesting(Func<IFileSystem> fileSystemFactory)
290294
/// <returns>True if the file system is a test/mock implementation; otherwise, false.</returns>
291295
private static bool IsTestFileSystem(IFileSystem fileSystem)
292296
{
293-
Guard.NotNull(fileSystem);
297+
Ensure.NotNull(fileSystem);
294298

295299
Type fileSystemType = fileSystem.GetType();
296300

AppDataStorage/AppDataStorage.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
<Sdk Name="Microsoft.NET.Sdk" />
33
<Sdk Name="ktsu.Sdk" />
44
<PropertyGroup>
5-
<TargetFrameworks>net9.0;net8.0;net7.0;netstandard2.0;netstandard2.1</TargetFrameworks>
5+
<TargetFrameworks>net10.0;net9.0;net8.0;net7.0;netstandard2.0;netstandard2.1</TargetFrameworks>
66
</PropertyGroup>
77
<ItemGroup>
88
<PackageReference Include="ktsu.CaseConverter" />
99
<PackageReference Include="ktsu.RoundTripStringJsonConverter" />
1010
<PackageReference Include="ktsu.Semantics.Paths" />
11-
<PackageReference Include="Polyfill" />
11+
<PackageReference Include="Polyfill" />
1212
<PackageReference Include="TestableIO.System.IO.Abstractions" />
1313
<PackageReference Include="TestableIO.System.IO.Abstractions.Wrappers" />
1414
</ItemGroup>

0 commit comments

Comments
 (0)