Skip to content

Commit 95fd6ea

Browse files
CopilotJusterZhu
andcommitted
Convert DifferentialCore from singleton to static class
Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
1 parent 20b1426 commit 95fd6ea

File tree

6 files changed

+36
-114
lines changed

6 files changed

+36
-114
lines changed

src/c#/DifferentialTest/DifferentialCoreTests.cs

Lines changed: 24 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace DifferentialTest
1313
{
1414
/// <summary>
1515
/// Contains test cases for the DifferentialCore class.
16-
/// Tests the singleton pattern, Clean method (patch generation), and Dirty method (patch application).
16+
/// Tests the Clean method (patch generation) and Dirty method (patch application).
1717
/// </summary>
1818
public class DifferentialCoreTests : IDisposable
1919
{
@@ -53,67 +53,6 @@ public void Dispose()
5353
}
5454
}
5555

56-
#region Singleton Pattern Tests
57-
58-
/// <summary>
59-
/// Tests that DifferentialCore.Instance returns a non-null instance.
60-
/// </summary>
61-
[Fact]
62-
public void Instance_ReturnsNonNullInstance()
63-
{
64-
// Act
65-
var instance = DifferentialCore.Instance;
66-
67-
// Assert
68-
Assert.NotNull(instance);
69-
}
70-
71-
/// <summary>
72-
/// Tests that DifferentialCore.Instance always returns the same instance (singleton).
73-
/// </summary>
74-
[Fact]
75-
public void Instance_ReturnsSameInstanceOnMultipleCalls()
76-
{
77-
// Act
78-
var instance1 = DifferentialCore.Instance;
79-
var instance2 = DifferentialCore.Instance;
80-
81-
// Assert
82-
Assert.Same(instance1, instance2);
83-
}
84-
85-
/// <summary>
86-
/// Tests that DifferentialCore.Instance is thread-safe.
87-
/// </summary>
88-
[Fact]
89-
public void Instance_IsThreadSafe()
90-
{
91-
// Arrange
92-
var instances = new DifferentialCore[10];
93-
var tasks = new Task[10];
94-
95-
// Act
96-
for (int i = 0; i < 10; i++)
97-
{
98-
var index = i;
99-
tasks[i] = Task.Run(() =>
100-
{
101-
instances[index] = DifferentialCore.Instance;
102-
});
103-
}
104-
105-
Task.WaitAll(tasks);
106-
107-
// Assert
108-
var firstInstance = instances[0];
109-
foreach (var instance in instances)
110-
{
111-
Assert.Same(firstInstance, instance);
112-
}
113-
}
114-
115-
#endregion
116-
11756
#region Clean Method Tests
11857

11958
/// <summary>
@@ -130,7 +69,7 @@ public async Task Clean_WithModifiedFiles_GeneratesPatchFiles()
13069
File.WriteAllText(targetFile, "Modified content");
13170

13271
// Act
133-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
72+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
13473

13574
// Assert
13675
var patchFile = Path.Combine(_patchDirectory, "test.txt.patch");
@@ -148,7 +87,7 @@ public async Task Clean_WithNewFiles_CopiesFilesToPatchDirectory()
14887
File.WriteAllText(targetFile, "New file content");
14988

15089
// Act
151-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
90+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
15291

15392
// Assert
15493
var copiedFile = Path.Combine(_patchDirectory, "newfile.txt");
@@ -167,7 +106,7 @@ public async Task Clean_WithDeletedFiles_GeneratesDeleteList()
167106
File.WriteAllText(sourceFile, "File to be deleted");
168107

169108
// Act
170-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
109+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
171110

172111
// Assert
173112
var deleteListFile = Path.Combine(_patchDirectory, "generalupdate_delete_files.json");
@@ -196,7 +135,7 @@ public async Task Clean_WithSubdirectories_GeneratesPatchesInCorrectStructure()
196135
File.WriteAllText(targetFile, "Content in subdirectory");
197136

198137
// Act
199-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
138+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
200139

201140
// Assert
202141
var copiedFile = Path.Combine(_patchDirectory, "subfolder", "test.txt");
@@ -217,7 +156,7 @@ public async Task Clean_WithIdenticalFiles_DoesNotGeneratePatch()
217156
File.WriteAllText(targetFile, "Identical content");
218157

219158
// Act
220-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
159+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
221160

222161
// Assert
223162
var patchFile = Path.Combine(_patchDirectory, "same.txt.patch");
@@ -238,7 +177,7 @@ public async Task Clean_WithEmptySourceDirectory_CopiesAllTargetFiles()
238177
File.WriteAllText(targetFile2, "File 2 content");
239178

240179
// Act
241-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
180+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
242181

243182
// Assert
244183
Assert.True(File.Exists(Path.Combine(_patchDirectory, "file1.txt")));
@@ -259,7 +198,7 @@ public async Task Clean_WithEmptyTargetDirectory_GeneratesDeleteList()
259198
File.WriteAllText(sourceFile2, "File 2 content");
260199

261200
// Act
262-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
201+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
263202

264203
// Assert
265204
var deleteListFile = Path.Combine(_patchDirectory, "generalupdate_delete_files.json");
@@ -295,7 +234,7 @@ public async Task Clean_WithMixedOperations_HandlesAllCorrectly()
295234
File.WriteAllText(Path.Combine(_targetDirectory, "unchanged.txt"), "Same");
296235

297236
// Act
298-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
237+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
299238

300239
// Assert
301240
// Check patch file for modified
@@ -333,7 +272,7 @@ public async Task Clean_WithBinaryFiles_GeneratesPatchFiles()
333272
File.WriteAllBytes(targetFile, new byte[] { 0x00, 0x01, 0x03 });
334273

335274
// Act
336-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
275+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
337276

338277
// Assert
339278
var patchFile = Path.Combine(_patchDirectory, "binary.bin.patch");
@@ -354,7 +293,7 @@ public async Task Dirty_WithNonExistentAppPath_ReturnsWithoutError()
354293
var nonExistentPath = Path.Combine(_testDirectory, "nonexistent");
355294

356295
// Act & Assert (should not throw)
357-
await DifferentialCore.Instance.Dirty(nonExistentPath, _patchDirectory);
296+
await DifferentialCore.Dirty(nonExistentPath, _patchDirectory);
358297
}
359298

360299
/// <summary>
@@ -367,7 +306,7 @@ public async Task Dirty_WithNonExistentPatchPath_ReturnsWithoutError()
367306
var nonExistentPath = Path.Combine(_testDirectory, "nonexistent");
368307

369308
// Act & Assert (should not throw)
370-
await DifferentialCore.Instance.Dirty(_appDirectory, nonExistentPath);
309+
await DifferentialCore.Dirty(_appDirectory, nonExistentPath);
371310
}
372311

373312
/// <summary>
@@ -385,13 +324,13 @@ public async Task Dirty_WithPatchFiles_AppliesPatches()
385324
File.WriteAllText(targetFile, "Modified content");
386325

387326
// Generate patch
388-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
327+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
389328

390329
// Copy source to app directory to simulate the application
391330
File.Copy(sourceFile, appFile);
392331

393332
// Act - Apply patch
394-
await DifferentialCore.Instance.Dirty(_appDirectory, _patchDirectory);
333+
await DifferentialCore.Dirty(_appDirectory, _patchDirectory);
395334

396335
// Assert
397336
var appliedContent = File.ReadAllText(appFile);
@@ -409,7 +348,7 @@ public async Task Dirty_WithNewFiles_CopiesFilesToApp()
409348
File.WriteAllText(patchFile, "New file content");
410349

411350
// Act
412-
await DifferentialCore.Instance.Dirty(_appDirectory, _patchDirectory);
351+
await DifferentialCore.Dirty(_appDirectory, _patchDirectory);
413352

414353
// Assert
415354
var appFile = Path.Combine(_appDirectory, "newfile.txt");
@@ -443,7 +382,7 @@ public async Task Dirty_WithDeleteList_DeletesFiles()
443382
File.WriteAllText(deleteListFile, JsonSerializer.Serialize(deleteList, FileNodesJsonContext.Default.ListFileNode));
444383

445384
// Act
446-
await DifferentialCore.Instance.Dirty(_appDirectory, _patchDirectory);
385+
await DifferentialCore.Dirty(_appDirectory, _patchDirectory);
447386

448387
// Assert
449388
Assert.False(File.Exists(appFile), "File should be deleted");
@@ -463,7 +402,7 @@ public async Task Dirty_WithSubdirectories_CopiesFilesWithStructure()
463402
File.WriteAllText(patchFile, "Content in subdirectory");
464403

465404
// Act
466-
await DifferentialCore.Instance.Dirty(_appDirectory, _patchDirectory);
405+
await DifferentialCore.Dirty(_appDirectory, _patchDirectory);
467406

468407
// Assert
469408
var appFile = Path.Combine(_appDirectory, "subfolder", "test.txt");
@@ -482,7 +421,7 @@ public async Task Dirty_AfterApplying_RemovesPatchDirectory()
482421
File.WriteAllText(patchFile, "Test content");
483422

484423
// Act
485-
await DifferentialCore.Instance.Dirty(_appDirectory, _patchDirectory);
424+
await DifferentialCore.Dirty(_appDirectory, _patchDirectory);
486425

487426
// Assert
488427
Assert.False(Directory.Exists(_patchDirectory), "Patch directory should be removed after applying");
@@ -506,13 +445,13 @@ public async Task Dirty_WithBinaryFiles_AppliesPatchesCorrectly()
506445
File.WriteAllBytes(targetFile, targetBytes);
507446

508447
// Generate patch
509-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
448+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
510449

511450
// Copy source to app directory
512451
File.Copy(sourceFile, appFile);
513452

514453
// Act
515-
await DifferentialCore.Instance.Dirty(_appDirectory, _patchDirectory);
454+
await DifferentialCore.Dirty(_appDirectory, _patchDirectory);
516455

517456
// Assert
518457
var appliedBytes = File.ReadAllBytes(appFile);
@@ -547,10 +486,10 @@ public async Task CleanAndDirty_FullCycle_UpdatesApplicationCorrectly()
547486
}
548487

549488
// Act - Generate patches
550-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
489+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
551490

552491
// Apply patches
553-
await DifferentialCore.Instance.Dirty(_appDirectory, _patchDirectory);
492+
await DifferentialCore.Dirty(_appDirectory, _patchDirectory);
554493

555494
// Assert
556495
// Modified file should be updated
@@ -589,8 +528,8 @@ public async Task CleanAndDirty_WithComplexStructure_UpdatesCorrectly()
589528
File.Copy(Path.Combine(sourceSubDir, "nested.txt"), Path.Combine(appSubDir, "nested.txt"));
590529

591530
// Act
592-
await DifferentialCore.Instance.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
593-
await DifferentialCore.Instance.Dirty(_appDirectory, _patchDirectory);
531+
await DifferentialCore.Clean(_sourceDirectory, _targetDirectory, _patchDirectory);
532+
await DifferentialCore.Dirty(_appDirectory, _patchDirectory);
594533

595534
// Assert
596535
Assert.Equal("Modified nested", File.ReadAllText(Path.Combine(appSubDir, "nested.txt")));

src/c#/DifferentialTest/Matchers/MatcherTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ public async Task Clean_WithCustomMatcher_UsesCustomMatchingLogic()
297297
var customMatcher = new AlwaysNewFileMatcher();
298298

299299
// Act
300-
await DifferentialCore.Instance.Clean(sourceDir, targetDir, patchDir, customMatcher);
300+
await DifferentialCore.Clean(sourceDir, targetDir, patchDir, customMatcher);
301301

302302
// Assert: file should be copied directly (not patched) because the custom matcher returns null
303303
Assert.True(File.Exists(Path.Combine(patchDir, "file.txt")));
@@ -320,7 +320,7 @@ public async Task Dirty_WithCustomMatcher_UsesCustomMatchingLogic()
320320
var customMatcher = new NeverMatchDirtyMatcher();
321321

322322
// Act – should not throw even though a patch file exists, because the custom matcher skips it
323-
await DifferentialCore.Instance.Dirty(appDir, patchDir, customMatcher);
323+
await DifferentialCore.Dirty(appDir, patchDir, customMatcher);
324324

325325
// Assert: original file is unchanged
326326
Assert.Equal("original", File.ReadAllText(Path.Combine(appDir, "app.exe")));

src/c#/GeneralUpdate.Client/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ static async Task Main(string[] args)
8686
var target = @"D:\packet\release";
8787
var patch = @"D:\packet\patch";
8888
89-
await DifferentialCore.Instance?.Clean(source, target, patch);
90-
await DifferentialCore.Instance?.Dirty(source, patch);
89+
await DifferentialCore.Clean(source, target, patch);
90+
await DifferentialCore.Dirty(source, patch);
9191
});*/
9292

9393
while (true)

src/c#/GeneralUpdate.ClientCore/Pipeline/PatchMiddleware.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ public async Task InvokeAsync(PipelineContext context)
1010
{
1111
var sourcePath = context.Get<string>("SourcePath");
1212
var targetPath = context.Get<string>("PatchPath");
13-
await DifferentialCore.Instance.Dirty(sourcePath, targetPath);
13+
await DifferentialCore.Dirty(sourcePath, targetPath);
1414
}
1515
}

src/c#/GeneralUpdate.Core/Pipeline/PatchMiddleware.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ public async Task InvokeAsync(PipelineContext context)
1010
{
1111
var sourcePath = context.Get<string>("SourcePath");
1212
var targetPath = context.Get<string>("PatchPath");
13-
await DifferentialCore.Instance?.Dirty(sourcePath, targetPath);
13+
await DifferentialCore.Dirty(sourcePath, targetPath);
1414
}
1515
}

src/c#/GeneralUpdate.Differential/DifferentialCore.cs

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,12 @@
1212

1313
namespace GeneralUpdate.Differential
1414
{
15-
public sealed class DifferentialCore
15+
public static class DifferentialCore
1616
{
17-
private static readonly object _lockObj = new ();
18-
private static DifferentialCore? _instance;
1917
private const string PATCH_FORMAT = ".patch";
2018
private const string DELETE_FILES_NAME = "generalupdate_delete_files.json";
2119

22-
public static DifferentialCore Instance
23-
{
24-
get
25-
{
26-
if (_instance == null)
27-
{
28-
lock (_lockObj)
29-
{
30-
_instance ??= new DifferentialCore();
31-
}
32-
}
33-
return _instance;
34-
}
35-
}
36-
37-
public async Task Clean(string sourcePath, string targetPath, string patchPath, ICleanMatcher? matcher = null)
20+
public static async Task Clean(string sourcePath, string targetPath, string patchPath, ICleanMatcher? matcher = null)
3821
{
3922
matcher ??= new DefaultCleanMatcher();
4023
var comparisonResult = matcher.Compare(sourcePath, targetPath);
@@ -67,7 +50,7 @@ public async Task Clean(string sourcePath, string targetPath, string patchPath,
6750
}
6851
}
6952

70-
public async Task Dirty(string appPath, string patchPath, IDirtyMatcher? matcher = null)
53+
public static async Task Dirty(string appPath, string patchPath, IDirtyMatcher? matcher = null)
7154
{
7255
if (!Directory.Exists(appPath) || !Directory.Exists(patchPath)) return;
7356

@@ -100,7 +83,7 @@ private static string GetTempDirectory(FileNode file, string targetPath, string
10083
return tempDir;
10184
}
10285

103-
private void HandleDeleteList(IEnumerable<FileInfo> patchFiles, IEnumerable<FileInfo> oldFiles)
86+
private static void HandleDeleteList(IEnumerable<FileInfo> patchFiles, IEnumerable<FileInfo> oldFiles)
10487
{
10588
var json = patchFiles.FirstOrDefault(i => i.Name.Equals(DELETE_FILES_NAME));
10689
if (json == null)
@@ -123,7 +106,7 @@ private void HandleDeleteList(IEnumerable<FileInfo> patchFiles, IEnumerable<File
123106
}
124107
}
125108

126-
private async Task DirtyPatch(string appPath, string patchPath)
109+
private static async Task DirtyPatch(string appPath, string patchPath)
127110
{
128111
if (!File.Exists(appPath) || !File.Exists(patchPath))
129112
return;
@@ -132,7 +115,7 @@ private async Task DirtyPatch(string appPath, string patchPath)
132115
await new BinaryHandler().Dirty(appPath, newPath, patchPath);
133116
}
134117

135-
private async Task DirtyUnknow(string appPath, string patchPath)
118+
private static async Task DirtyUnknow(string appPath, string patchPath)
136119
{
137120
await Task.Run(() =>
138121
{

0 commit comments

Comments
 (0)