From f4a634c7734014bd497a8f919a29a867e907bbbd Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 16 Feb 2026 13:43:14 +0000
Subject: [PATCH 1/7] Initial plan
From 6ed754d853adc22a27f5536b47ba5b4bef4c6a4d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 16 Feb 2026 13:50:36 +0000
Subject: [PATCH 2/7] Implement ConfiginfoBuilder refactoring: add JSON config
loading, update defaults, make constructor private
Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
---
.../CoreTest/Shared/ConfiginfoBuilderTests.cs | 142 +++++++-----------
.../Shared/Object/BaseConfigInfo.cs | 7 +-
.../Object/ConfiginfoBuilder-Example.cs | 17 ++-
.../Shared/Object/ConfiginfoBuilder.cs | 97 +++++++++++-
4 files changed, 165 insertions(+), 98 deletions(-)
diff --git a/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs b/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs
index 1c31817c..1f677047 100644
--- a/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs
+++ b/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs
@@ -18,19 +18,6 @@ public class ConfiginfoBuilderTests
#region Constructor Tests
- ///
- /// Tests that the constructor properly initializes with valid parameters.
- ///
- [Fact]
- public void Constructor_WithValidParameters_CreatesInstance()
- {
- // Act
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
-
- // Assert
- Assert.NotNull(builder);
- }
-
///
/// Tests that the Create factory method properly initializes with valid parameters.
///
@@ -45,85 +32,84 @@ public void Create_WithValidParameters_CreatesInstance()
}
///
- /// Tests that Create factory method produces same result as constructor.
+ /// Tests that Create factory method produces consistent results.
///
[Fact]
- public void Create_ProducesSameResultAsConstructor()
+ public void Create_ProducesConsistentResults()
{
// Act
- var config1 = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme).Build();
+ var config1 = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme).Build();
var config2 = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme).Build();
// Assert
Assert.Equal(config1.UpdateUrl, config2.UpdateUrl);
Assert.Equal(config1.Token, config2.Token);
Assert.Equal(config1.Scheme, config2.Scheme);
- Assert.Equal(config1.InstallPath, config2.InstallPath);
Assert.Equal(config1.AppName, config2.AppName);
}
///
- /// Tests that the constructor throws ArgumentException when UpdateUrl is null.
+ /// Tests that the Create method throws ArgumentException when UpdateUrl is null.
///
[Fact]
- public void Constructor_WithNullUpdateUrl_ThrowsArgumentException()
+ public void Create_WithNullUpdateUrl_ThrowsArgumentException()
{
// Act & Assert
var exception = Assert.Throws(() =>
- new ConfiginfoBuilder(null, TestToken, TestScheme));
+ ConfiginfoBuilder.Create(null, TestToken, TestScheme));
Assert.Contains("UpdateUrl", exception.Message);
}
///
- /// Tests that the constructor throws ArgumentException when UpdateUrl is empty.
+ /// Tests that the Create method throws ArgumentException when UpdateUrl is empty.
///
[Fact]
- public void Constructor_WithEmptyUpdateUrl_ThrowsArgumentException()
+ public void Create_WithEmptyUpdateUrl_ThrowsArgumentException()
{
// Act & Assert
var exception = Assert.Throws(() =>
- new ConfiginfoBuilder("", TestToken, TestScheme));
+ ConfiginfoBuilder.Create("", TestToken, TestScheme));
Assert.Contains("UpdateUrl", exception.Message);
}
///
- /// Tests that the constructor throws ArgumentException when UpdateUrl is not a valid URI.
+ /// Tests that the Create method throws ArgumentException when UpdateUrl is not a valid URI.
///
[Fact]
- public void Constructor_WithInvalidUpdateUrl_ThrowsArgumentException()
+ public void Create_WithInvalidUpdateUrl_ThrowsArgumentException()
{
// Act & Assert
var exception = Assert.Throws(() =>
- new ConfiginfoBuilder("not-a-valid-url", TestToken, TestScheme));
+ ConfiginfoBuilder.Create("not-a-valid-url", TestToken, TestScheme));
Assert.Contains("UpdateUrl", exception.Message);
Assert.Contains("valid absolute URI", exception.Message);
}
///
- /// Tests that the constructor throws ArgumentException when Token is null.
+ /// Tests that the Create method throws ArgumentException when Token is null.
///
[Fact]
- public void Constructor_WithNullToken_ThrowsArgumentException()
+ public void Create_WithNullToken_ThrowsArgumentException()
{
// Act & Assert
var exception = Assert.Throws(() =>
- new ConfiginfoBuilder(TestUpdateUrl, null, TestScheme));
+ ConfiginfoBuilder.Create(TestUpdateUrl, null, TestScheme));
Assert.Contains("Token", exception.Message);
}
///
- /// Tests that the constructor throws ArgumentException when Scheme is null.
+ /// Tests that the Create method throws ArgumentException when Scheme is null.
///
[Fact]
- public void Constructor_WithNullScheme_ThrowsArgumentException()
+ public void Create_WithNullScheme_ThrowsArgumentException()
{
// Act & Assert
var exception = Assert.Throws(() =>
- new ConfiginfoBuilder(TestUpdateUrl, TestToken, null));
+ ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, null));
Assert.Contains("Scheme", exception.Message);
}
@@ -139,7 +125,7 @@ public void Constructor_WithNullScheme_ThrowsArgumentException()
public void Build_WithMinimalParameters_ReturnsValidConfiginfo()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
// Act
var config = builder.Build();
@@ -163,7 +149,7 @@ public void Build_WithMinimalParameters_ReturnsValidConfiginfo()
public void Build_GeneratesPlatformSpecificDefaults()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
// Act
var config = builder.Build();
@@ -174,21 +160,8 @@ public void Build_GeneratesPlatformSpecificDefaults()
// InstallPath should be the current application's base directory
Assert.Equal(AppDomain.CurrentDomain.BaseDirectory, config.InstallPath);
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- // Windows-specific assertions
- Assert.Contains("App.exe", config.AppName);
- }
- else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
- {
- // Linux-specific assertions
- Assert.DoesNotContain(".exe", config.AppName);
- }
- else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
- {
- // macOS-specific assertions
- Assert.DoesNotContain(".exe", config.AppName);
- }
+ // According to requirements, AppName default is "Update.exe" regardless of platform
+ Assert.Equal("Update.exe", config.AppName);
}
///
@@ -198,7 +171,7 @@ public void Build_GeneratesPlatformSpecificDefaults()
public void Build_InitializesCollectionProperties()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
// Act
var config = builder.Build();
@@ -222,7 +195,7 @@ public void Build_InitializesCollectionProperties()
public void SetAppName_WithValidValue_SetsAppName()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var customAppName = "CustomApp.exe";
// Act
@@ -239,7 +212,7 @@ public void SetAppName_WithValidValue_SetsAppName()
public void SetAppName_ReturnsBuilder_ForMethodChaining()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
// Act
var result = builder.SetAppName("Test.exe");
@@ -255,7 +228,7 @@ public void SetAppName_ReturnsBuilder_ForMethodChaining()
public void SetAppName_WithNullValue_ThrowsArgumentException()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
// Act & Assert
var exception = Assert.Throws(() => builder.SetAppName(null));
@@ -269,7 +242,7 @@ public void SetAppName_WithNullValue_ThrowsArgumentException()
public void SetMainAppName_WithValidValue_SetsMainAppName()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var customMainAppName = "MainApp.exe";
// Act
@@ -286,7 +259,7 @@ public void SetMainAppName_WithValidValue_SetsMainAppName()
public void SetClientVersion_WithValidValue_SetsClientVersion()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var customVersion = "2.5.1";
// Act
@@ -303,7 +276,7 @@ public void SetClientVersion_WithValidValue_SetsClientVersion()
public void SetUpgradeClientVersion_WithValidValue_SetsUpgradeClientVersion()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var customVersion = "3.0.0";
// Act
@@ -320,7 +293,7 @@ public void SetUpgradeClientVersion_WithValidValue_SetsUpgradeClientVersion()
public void SetAppSecretKey_WithValidValue_SetsAppSecretKey()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var customSecretKey = "my-secret-key-123";
// Act
@@ -337,7 +310,7 @@ public void SetAppSecretKey_WithValidValue_SetsAppSecretKey()
public void SetProductId_WithValidValue_SetsProductId()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var customProductId = "product-xyz-789";
// Act
@@ -354,7 +327,7 @@ public void SetProductId_WithValidValue_SetsProductId()
public void SetInstallPath_WithValidValue_SetsInstallPath()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var customPath = "/custom/install/path";
// Act
@@ -371,7 +344,7 @@ public void SetInstallPath_WithValidValue_SetsInstallPath()
public void SetUpdateLogUrl_WithValidUrl_SetsUpdateLogUrl()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var logUrl = "https://example.com/changelog";
// Act
@@ -388,7 +361,7 @@ public void SetUpdateLogUrl_WithValidUrl_SetsUpdateLogUrl()
public void SetUpdateLogUrl_WithInvalidUrl_ThrowsArgumentException()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
// Act & Assert
var exception = Assert.Throws(() =>
@@ -404,7 +377,7 @@ public void SetUpdateLogUrl_WithInvalidUrl_ThrowsArgumentException()
public void SetReportUrl_WithValidUrl_SetsReportUrl()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var reportUrl = "https://example.com/report";
// Act
@@ -421,7 +394,7 @@ public void SetReportUrl_WithValidUrl_SetsReportUrl()
public void SetBowl_WithValidValue_SetsBowl()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var bowlProcess = "Bowl.exe";
// Act
@@ -438,7 +411,7 @@ public void SetBowl_WithValidValue_SetsBowl()
public void SetScript_WithValidValue_SetsScript()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var customScript = "#!/bin/bash\necho 'Hello'";
// Act
@@ -455,7 +428,7 @@ public void SetScript_WithValidValue_SetsScript()
public void SetDriverDirectory_WithValidValue_SetsDriverDirectory()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var driverDir = "/path/to/drivers";
// Act
@@ -472,7 +445,7 @@ public void SetDriverDirectory_WithValidValue_SetsDriverDirectory()
public void SetBlackFiles_WithValidList_SetsBlackFiles()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var blackFiles = new List { "file1.txt", "file2.dat" };
// Act
@@ -489,7 +462,7 @@ public void SetBlackFiles_WithValidList_SetsBlackFiles()
public void SetBlackFormats_WithValidList_SetsBlackFormats()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var blackFormats = new List { ".bak", ".old" };
// Act
@@ -506,7 +479,7 @@ public void SetBlackFormats_WithValidList_SetsBlackFormats()
public void SetSkipDirectorys_WithValidList_SetsSkipDirectorys()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
var skipDirs = new List { "/temp", "/cache" };
// Act
@@ -527,7 +500,7 @@ public void SetSkipDirectorys_WithValidList_SetsSkipDirectorys()
public void BuilderPattern_SupportsMethodChaining()
{
// Arrange & Act
- var config = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme)
+ var config = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme)
.SetAppName("CustomApp.exe")
.SetMainAppName("MainCustomApp.exe")
.SetClientVersion("2.0.0")
@@ -560,17 +533,16 @@ public void Build_OnWindows_GeneratesWindowsDefaults()
}
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
// Act
var config = builder.Build();
// Assert
- Assert.Contains("App.exe", config.AppName);
+ // According to requirements, AppName default is "Update.exe" regardless of platform
+ Assert.Equal("Update.exe", config.AppName);
// Should use the current application's base directory
Assert.Equal(AppDomain.CurrentDomain.BaseDirectory, config.InstallPath);
- // Windows script should be empty
- Assert.Empty(config.Script);
}
///
@@ -586,18 +558,16 @@ public void Build_OnLinux_GeneratesLinuxDefaults()
}
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
// Act
var config = builder.Build();
// Assert
- Assert.DoesNotContain(".exe", config.AppName);
+ // According to requirements, AppName default is "Update.exe" regardless of platform
+ Assert.Equal("Update.exe", config.AppName);
// Should use the current application's base directory
Assert.Equal(AppDomain.CurrentDomain.BaseDirectory, config.InstallPath);
- // Linux should have a default permission script
- Assert.NotEmpty(config.Script);
- Assert.Contains("chmod", config.Script);
}
///
@@ -613,18 +583,16 @@ public void Build_OnMacOS_GeneratesMacOSDefaults()
}
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
// Act
var config = builder.Build();
// Assert
- Assert.DoesNotContain(".exe", config.AppName);
+ // According to requirements, AppName default is "Update.exe" regardless of platform
+ Assert.Equal("Update.exe", config.AppName);
// Should use the current application's base directory
Assert.Equal(AppDomain.CurrentDomain.BaseDirectory, config.InstallPath);
- // macOS should have a default permission script
- Assert.NotEmpty(config.Script);
- Assert.Contains("chmod", config.Script);
}
#endregion
@@ -638,7 +606,7 @@ public void Build_OnMacOS_GeneratesMacOSDefaults()
public void Build_ReturnsConfiginfoThatPassesValidation()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
// Act
var config = builder.Build();
@@ -656,7 +624,7 @@ public void Build_ReturnsConfiginfoThatPassesValidation()
public void Build_AttemptsToExtractAppNameFromProject()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
// Act
var config = builder.Build();
@@ -682,7 +650,7 @@ public void Build_AttemptsToExtractAppNameFromProject()
public void Build_AttemptsToExtractProjectMetadata()
{
// Arrange
- var builder = new ConfiginfoBuilder(TestUpdateUrl, TestToken, TestScheme);
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
// Act
var config = builder.Build();
@@ -710,7 +678,7 @@ public void CompleteScenario_BuildsValidConfiginfo()
var scheme = "https";
// Act
- var config = new ConfiginfoBuilder(updateUrl, token, scheme)
+ var config = ConfiginfoBuilder.Create(updateUrl, token, scheme)
.SetAppName("MyApplication.exe")
.SetMainAppName("MyApplication.exe")
.SetClientVersion("1.5.2")
diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/BaseConfigInfo.cs b/src/c#/GeneralUpdate.Common/Shared/Object/BaseConfigInfo.cs
index 3bce46f2..681c6096 100644
--- a/src/c#/GeneralUpdate.Common/Shared/Object/BaseConfigInfo.cs
+++ b/src/c#/GeneralUpdate.Common/Shared/Object/BaseConfigInfo.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
namespace GeneralUpdate.Common.Shared.Object
@@ -12,8 +13,9 @@ public abstract class BaseConfigInfo
///
/// The name of the application that needs to be started after update.
/// This is the executable name without extension (e.g., "MyApp" for MyApp.exe).
+ /// Default value is "Update.exe".
///
- public string AppName { get; set; }
+ public string AppName { get; set; } = "Update.exe";
///
/// The name of the main application without file extension.
@@ -24,8 +26,9 @@ public abstract class BaseConfigInfo
///
/// The installation path where application files are located.
/// This is the root directory used for update file operations.
+ /// Default value is the current program's running directory.
///
- public string InstallPath { get; set; }
+ public string InstallPath { get; set; } = AppDomain.CurrentDomain.BaseDirectory;
///
/// The URL address for the update log webpage.
diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Example.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Example.cs
index f22d1db9..ef80f24f 100644
--- a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Example.cs
+++ b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Example.cs
@@ -28,8 +28,8 @@ static void Main(string[] args)
Console.WriteLine();
// Example 2: Custom configuration with method chaining
- Console.WriteLine("Example 2: Custom Configuration - Using Constructor");
- var customConfig = new ConfiginfoBuilder(
+ Console.WriteLine("Example 2: Custom Configuration - Using Create Method");
+ var customConfig = ConfiginfoBuilder.Create(
"https://api.example.com/updates",
"Bearer abc123xyz",
"https"
@@ -49,7 +49,7 @@ static void Main(string[] args)
// Example 3: Configuration with file filters
Console.WriteLine("Example 3: With File Filters");
- var filteredConfig = new ConfiginfoBuilder(
+ var filteredConfig = ConfiginfoBuilder.Create(
"https://api.example.com/updates",
"token123",
"https"
@@ -66,7 +66,7 @@ static void Main(string[] args)
// Example 4: Complete configuration
Console.WriteLine("Example 4: Complete Configuration");
- var completeConfig = new ConfiginfoBuilder(
+ var completeConfig = ConfiginfoBuilder.Create(
updateUrl: "https://api.example.com/updates",
token: "Bearer xyz789",
scheme: "https"
@@ -94,7 +94,10 @@ static void Main(string[] args)
Console.WriteLine("Example 5: Error Handling");
try
{
- var invalidConfig = new ConfiginfoBuilder(
+ // Note: Create method loads from config file if available
+ // For demonstration, we'll show that invalid params would fail
+ // if no config file exists
+ var invalidConfig = ConfiginfoBuilder.Create(
null, // Invalid: null URL
"token",
"https"
@@ -107,7 +110,7 @@ static void Main(string[] args)
try
{
- var invalidConfig2 = new ConfiginfoBuilder(
+ var invalidConfig2 = ConfiginfoBuilder.Create(
"not-a-url", // Invalid: malformed URL
"token",
"https"
@@ -121,7 +124,7 @@ static void Main(string[] args)
// Example 6: Validate configuration
Console.WriteLine("Example 6: Configuration Validation");
- var validConfig = new ConfiginfoBuilder(
+ var validConfig = ConfiginfoBuilder.Create(
"https://api.example.com/updates",
"token",
"https"
diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs
index d0d295b5..dfb2c306 100644
--- a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs
+++ b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
+using System.IO;
+using System.Text.Json;
namespace GeneralUpdate.Common.Shared.Object
{
@@ -16,11 +18,18 @@ public class ConfiginfoBuilder
///
public static readonly string[] DefaultBlackFormats;
+ static ConfiginfoBuilder()
+ {
+ DefaultBlackFormats = new[] { ".log", ".tmp", ".cache", ".bak" };
+ }
+
private readonly string _updateUrl;
private readonly string _token;
private readonly string _scheme;
// Configurable default values
+ // Note: AppName and InstallPath defaults are set in Configinfo class itself
+ // These are ConfiginfoBuilder-specific defaults to support the builder pattern
private string _appName = "Update.exe";
private string _mainAppName = "App.exe";
private string _clientVersion = "1.0.0";
@@ -40,6 +49,7 @@ public class ConfiginfoBuilder
///
/// Creates a new ConfiginfoBuilder instance using the specified update URL, authentication token, and scheme.
/// This is the primary factory method for creating a builder with zero-configuration defaults.
+ /// If update_config.json exists in the running directory, it will be loaded with highest priority.
/// All other configuration properties will be automatically initialized with platform-appropriate defaults.
///
/// The API endpoint URL for checking available updates. Must be a valid absolute URI.
@@ -49,18 +59,98 @@ public class ConfiginfoBuilder
/// Thrown when any required parameter is null, empty, or invalid.
public static ConfiginfoBuilder Create(string updateUrl, string token, string scheme)
{
+ // Try to load from configuration file first
+ var configFromFile = LoadFromConfigFile();
+ if (configFromFile != null)
+ {
+ // Configuration file has highest priority, return directly
+ return configFromFile;
+ }
+
return new ConfiginfoBuilder(updateUrl, token, scheme);
}
+ ///
+ /// Loads configuration from update_config.json file in the running directory.
+ ///
+ /// ConfiginfoBuilder with settings from file, or null if file doesn't exist or is invalid.
+ private static ConfiginfoBuilder LoadFromConfigFile()
+ {
+ try
+ {
+ var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json");
+ if (!File.Exists(configPath))
+ {
+ return null;
+ }
+
+ var json = File.ReadAllText(configPath);
+ var config = JsonSerializer.Deserialize(json, new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true
+ });
+
+ if (config == null)
+ {
+ return null;
+ }
+
+ // Create a builder with the loaded configuration
+ var builder = new ConfiginfoBuilder(
+ config.UpdateUrl ?? string.Empty,
+ config.Token ?? string.Empty,
+ config.Scheme ?? string.Empty);
+
+ // Apply all loaded settings
+ if (!string.IsNullOrWhiteSpace(config.AppName))
+ builder.SetAppName(config.AppName);
+ if (!string.IsNullOrWhiteSpace(config.MainAppName))
+ builder.SetMainAppName(config.MainAppName);
+ if (!string.IsNullOrWhiteSpace(config.ClientVersion))
+ builder.SetClientVersion(config.ClientVersion);
+ if (!string.IsNullOrWhiteSpace(config.UpgradeClientVersion))
+ builder.SetUpgradeClientVersion(config.UpgradeClientVersion);
+ if (!string.IsNullOrWhiteSpace(config.AppSecretKey))
+ builder.SetAppSecretKey(config.AppSecretKey);
+ if (!string.IsNullOrWhiteSpace(config.ProductId))
+ builder.SetProductId(config.ProductId);
+ if (!string.IsNullOrWhiteSpace(config.InstallPath))
+ builder.SetInstallPath(config.InstallPath);
+ if (!string.IsNullOrWhiteSpace(config.UpdateLogUrl))
+ builder.SetUpdateLogUrl(config.UpdateLogUrl);
+ if (!string.IsNullOrWhiteSpace(config.ReportUrl))
+ builder.SetReportUrl(config.ReportUrl);
+ if (!string.IsNullOrWhiteSpace(config.Bowl))
+ builder.SetBowl(config.Bowl);
+ if (!string.IsNullOrWhiteSpace(config.Script))
+ builder.SetScript(config.Script);
+ if (!string.IsNullOrWhiteSpace(config.DriverDirectory))
+ builder.SetDriverDirectory(config.DriverDirectory);
+ if (config.BlackFiles != null)
+ builder.SetBlackFiles(config.BlackFiles);
+ if (config.BlackFormats != null)
+ builder.SetBlackFormats(config.BlackFormats);
+ if (config.SkipDirectorys != null)
+ builder.SetSkipDirectorys(config.SkipDirectorys);
+
+ return builder;
+ }
+ catch
+ {
+ // If there's any error reading or parsing the file, return null
+ return null;
+ }
+ }
+
///
/// Initializes a new instance of the ConfiginfoBuilder with required parameters.
- /// Consider using for a more fluent API.
+ /// This constructor is private. Use for creating instances.
///
/// The API endpoint URL for checking available updates. Must be a valid absolute URI.
/// The authentication token used for API requests.
/// The URL scheme used for update requests (e.g., "http" or "https").
/// Thrown when any required parameter is null, empty, or invalid.
- public ConfiginfoBuilder(string updateUrl, string token, string scheme)
+ private ConfiginfoBuilder(string updateUrl, string token, string scheme)
{
// Validate required parameters
if (string.IsNullOrWhiteSpace(updateUrl))
@@ -92,6 +182,9 @@ private void InitializePlatformDefaults()
_blackFiles = new List();
_blackFormats = new List(DefaultBlackFormats);
_skipDirectorys = new List();
+
+ // Set default InstallPath to current program running directory
+ _installPath = AppDomain.CurrentDomain.BaseDirectory;
}
///
From 2229b5bb5b84e87e156f6feb67b8f5ec21798ea6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 16 Feb 2026 13:51:36 +0000
Subject: [PATCH 3/7] Add tests for JSON configuration file loading
functionality
Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
---
.../CoreTest/Shared/ConfiginfoBuilderTests.cs | 117 ++++++++++++++++++
1 file changed, 117 insertions(+)
diff --git a/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs b/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs
index 1f677047..09df289d 100644
--- a/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs
+++ b/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Runtime.InteropServices;
using GeneralUpdate.Common.Shared.Object;
using Xunit;
@@ -705,5 +706,121 @@ public void CompleteScenario_BuildsValidConfiginfo()
}
#endregion
+
+ #region JSON Configuration File Tests
+
+ ///
+ /// Tests that ConfiginfoBuilder loads configuration from update_config.json file if present.
+ ///
+ [Fact]
+ public void Create_WithConfigFile_LoadsFromFile()
+ {
+ // Arrange - Create a test config file
+ var configFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json");
+ var testConfig = new
+ {
+ UpdateUrl = "https://config-file.example.com/updates",
+ Token = "config-file-token",
+ Scheme = "https",
+ AppName = "ConfigFileApp.exe",
+ MainAppName = "ConfigFileMain.exe",
+ ClientVersion = "9.9.9",
+ InstallPath = "/config/file/path"
+ };
+
+ try
+ {
+ // Write test config file
+ File.WriteAllText(configFilePath, System.Text.Json.JsonSerializer.Serialize(testConfig));
+
+ // Act - Create should load from file instead of using parameters
+ var config = ConfiginfoBuilder.Create(
+ "https://should-be-ignored.com/updates",
+ "should-be-ignored-token",
+ "http"
+ ).Build();
+
+ // Assert - Values should come from config file, not parameters
+ Assert.Equal("https://config-file.example.com/updates", config.UpdateUrl);
+ Assert.Equal("config-file-token", config.Token);
+ Assert.Equal("https", config.Scheme);
+ Assert.Equal("ConfigFileApp.exe", config.AppName);
+ Assert.Equal("ConfigFileMain.exe", config.MainAppName);
+ Assert.Equal("9.9.9", config.ClientVersion);
+ Assert.Equal("/config/file/path", config.InstallPath);
+ }
+ finally
+ {
+ // Cleanup - Delete test config file
+ if (File.Exists(configFilePath))
+ {
+ File.Delete(configFilePath);
+ }
+ }
+ }
+
+ ///
+ /// Tests that ConfiginfoBuilder uses parameters when no config file exists.
+ ///
+ [Fact]
+ public void Create_WithoutConfigFile_UsesParameters()
+ {
+ // Arrange - Ensure no config file exists
+ var configFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json");
+ if (File.Exists(configFilePath))
+ {
+ File.Delete(configFilePath);
+ }
+
+ try
+ {
+ // Act - Create should use parameters
+ var config = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme).Build();
+
+ // Assert - Values should come from parameters and defaults
+ Assert.Equal(TestUpdateUrl, config.UpdateUrl);
+ Assert.Equal(TestToken, config.Token);
+ Assert.Equal(TestScheme, config.Scheme);
+ Assert.Equal("Update.exe", config.AppName); // Default value
+ }
+ finally
+ {
+ // No cleanup needed since we're ensuring file doesn't exist
+ }
+ }
+
+ ///
+ /// Tests that ConfiginfoBuilder handles invalid JSON gracefully.
+ ///
+ [Fact]
+ public void Create_WithInvalidConfigFile_FallsBackToParameters()
+ {
+ // Arrange - Create an invalid config file
+ var configFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json");
+
+ try
+ {
+ // Write invalid JSON
+ File.WriteAllText(configFilePath, "{ invalid json content !!!");
+
+ // Act - Create should fall back to parameters
+ var config = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme).Build();
+
+ // Assert - Values should come from parameters (fallback)
+ Assert.Equal(TestUpdateUrl, config.UpdateUrl);
+ Assert.Equal(TestToken, config.Token);
+ Assert.Equal(TestScheme, config.Scheme);
+ }
+ finally
+ {
+ // Cleanup - Delete test config file
+ if (File.Exists(configFilePath))
+ {
+ File.Delete(configFilePath);
+ }
+ }
+ }
+
+ #endregion
}
}
From 39ac0d94eb5ede219f2c61ff89cf20e5dcf8351c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 16 Feb 2026 13:53:30 +0000
Subject: [PATCH 4/7] Add JSON configuration example and update documentation
Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
---
.../Shared/Object/ConfiginfoBuilder-Usage.md | 41 +++++-
.../Shared/Object/README-ConfiginfoBuilder.md | 127 +++++++++++++++---
.../Shared/Object/update_config.example.json | 31 +++++
3 files changed, 178 insertions(+), 21 deletions(-)
create mode 100644 src/c#/GeneralUpdate.Common/Shared/Object/update_config.example.json
diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Usage.md b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Usage.md
index f7de72a5..9e8a0dfc 100644
--- a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Usage.md
+++ b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Usage.md
@@ -1,9 +1,48 @@
# ConfiginfoBuilder Usage Guide
-The `ConfiginfoBuilder` class provides a simple and convenient way to create `Configinfo` objects for the GeneralUpdate system. It only requires three essential parameters while automatically generating platform-appropriate defaults for all other configuration items.
+The `ConfiginfoBuilder` class provides a simple and convenient way to create `Configinfo` objects for the GeneralUpdate system. It supports both JSON-based configuration and programmatic configuration.
**Design Philosophy**: Inspired by zero-configuration patterns from projects like [Velopack](https://github.com/velopack/velopack), this builder minimizes required configuration while maintaining flexibility through optional fluent setters.
+## Configuration Methods
+
+There are two main ways to configure the update system:
+
+### 1. JSON Configuration File (Recommended)
+
+Place an `update_config.json` file in your application's running directory. When this file exists, ConfiginfoBuilder automatically loads all settings from it, giving the configuration file the highest priority.
+
+**Example `update_config.json`:**
+```json
+{
+ "UpdateUrl": "https://api.example.com/updates",
+ "Token": "your-authentication-token",
+ "Scheme": "https",
+ "AppName": "Update.exe",
+ "MainAppName": "MyApplication.exe",
+ "ClientVersion": "1.0.0",
+ "InstallPath": "/path/to/installation",
+ "BlackFormats": [".log", ".tmp", ".cache"],
+ "SkipDirectorys": ["/temp", "/logs"]
+}
+```
+
+See [update_config.example.json](update_config.example.json) for a complete example with all available options.
+
+**Usage:**
+```csharp
+// The Create method will automatically load from update_config.json if it exists
+var config = ConfiginfoBuilder
+ .Create("fallback-url", "fallback-token", "https")
+ .Build();
+// If update_config.json exists, all values come from the file
+// Parameters are only used as fallback if file doesn't exist
+```
+
+### 2. Programmatic Configuration
+
+Configure the update system entirely through code using the fluent API:
+
## Automatic Configuration Detection
The ConfiginfoBuilder implements intelligent zero-configuration by automatically extracting information from your project:
diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/README-ConfiginfoBuilder.md b/src/c#/GeneralUpdate.Common/Shared/Object/README-ConfiginfoBuilder.md
index 8992cd0b..83790f6d 100644
--- a/src/c#/GeneralUpdate.Common/Shared/Object/README-ConfiginfoBuilder.md
+++ b/src/c#/GeneralUpdate.Common/Shared/Object/README-ConfiginfoBuilder.md
@@ -4,8 +4,37 @@
The `ConfiginfoBuilder` class provides a simple, fluent API for creating `Configinfo` objects with minimal effort. It automatically handles platform-specific defaults and only requires three essential parameters.
+**NEW**: ConfiginfoBuilder now supports loading configuration from a JSON file (`update_config.json`) placed in the running directory. When this file exists, it takes the highest priority, overriding any parameters passed to the builder.
+
**Design Inspiration**: The zero-configuration approach is inspired by projects like [Velopack](https://github.com/velopack/velopack), focusing on sensible defaults extracted from the running application with minimal user input required.
+## Configuration Priority
+
+The ConfiginfoBuilder follows this priority order:
+
+1. **JSON Configuration File** (`update_config.json`) - **HIGHEST PRIORITY**
+2. **Builder Setter Methods** (via `.SetXXX()` methods)
+3. **Default Values** (platform-specific defaults)
+
+## JSON Configuration File Support
+
+Place an `update_config.json` file in your application's running directory to configure all update settings. When this file is present, ConfiginfoBuilder will automatically load settings from it, ignoring parameters passed to the `Create()` method.
+
+**Example `update_config.json`:**
+```json
+{
+ "UpdateUrl": "https://api.example.com/updates",
+ "Token": "your-authentication-token",
+ "Scheme": "https",
+ "AppName": "Update.exe",
+ "MainAppName": "MyApplication.exe",
+ "ClientVersion": "1.0.0",
+ "InstallPath": "/path/to/installation"
+}
+```
+
+See [update_config.example.json](update_config.example.json) for a complete example with all available options.
+
## Auto-Configuration Features
🔍 **Application Name Detection**: Automatically reads `` from `.csproj`
@@ -19,30 +48,36 @@ The `ConfiginfoBuilder` class provides a simple, fluent API for creating `Config
```csharp
using GeneralUpdate.Common.Shared.Object;
-// Method 1: Direct constructor
-var config = new ConfiginfoBuilder(
- updateUrl: "https://api.example.com/updates",
- token: "your-auth-token",
- scheme: "https"
-).Build();
+// Method 1: With JSON configuration file (RECOMMENDED)
+// Place update_config.json in your app's running directory
+// The Create method will automatically load from the file
+var config = ConfiginfoBuilder
+ .Create("https://fallback.com/updates", "fallback-token", "https")
+ .Build();
+// If update_config.json exists, those values are used instead of the parameters
-// Method 2: Factory method (recommended)
+// Method 2: Using code configuration only (no JSON file)
var config2 = ConfiginfoBuilder
.Create("https://api.example.com/updates", "your-auth-token", "https")
.Build();
-// That's it! Application name, version, and all defaults are set automatically!
+// Method 3: Code configuration with custom overrides
+var config3 = ConfiginfoBuilder
+ .Create("https://api.example.com/updates", "your-auth-token", "https")
+ .SetAppName("MyApp.exe")
+ .SetInstallPath("/custom/path")
+ .Build();
```
## Key Features
+✅ **JSON Configuration Support**: Load settings from `update_config.json` with highest priority
✅ **Minimal Parameters**: Only 3 required parameters (UpdateUrl, Token, Scheme)
✅ **Cross-Platform**: Automatically detects and adapts to Windows/Linux/macOS
✅ **Smart Defaults**: Platform-appropriate paths, separators, and configurations
-✅ **Auto-Discovery**: Reads application name, version, and publisher from project file (.csproj)
✅ **Fluent API**: Clean, readable method chaining
✅ **Type-Safe**: Compile-time parameter validation
-✅ **Well-Tested**: 37 comprehensive unit tests
+✅ **Well-Tested**: 39 comprehensive unit tests including JSON configuration scenarios
## Platform Detection
@@ -62,14 +97,35 @@ The builder automatically adapts based on your runtime environment:
## Examples
-### Basic Usage
+### Using JSON Configuration File
```csharp
-var config = new ConfiginfoBuilder(updateUrl, token, scheme).Build();
+// Create update_config.json in your app directory:
+// {
+// "UpdateUrl": "https://api.example.com/updates",
+// "Token": "my-token",
+// "Scheme": "https",
+// "AppName": "MyApp.exe",
+// "ClientVersion": "2.0.0"
+// }
+
+// The builder will automatically load from the file
+var config = ConfiginfoBuilder
+ .Create("ignored", "ignored", "ignored")
+ .Build();
+// Values come from update_config.json!
+```
+
+### Basic Usage (No JSON File)
+```csharp
+var config = ConfiginfoBuilder
+ .Create(updateUrl, token, scheme)
+ .Build();
```
### Custom Configuration
```csharp
-var config = new ConfiginfoBuilder(updateUrl, token, scheme)
+var config = ConfiginfoBuilder
+ .Create(updateUrl, token, scheme)
.SetAppName("MyApp.exe")
.SetClientVersion("2.0.0")
.SetInstallPath("/opt/myapp")
@@ -78,7 +134,8 @@ var config = new ConfiginfoBuilder(updateUrl, token, scheme)
### With File Filters
```csharp
-var config = new ConfiginfoBuilder(updateUrl, token, scheme)
+var config = ConfiginfoBuilder
+ .Create(updateUrl, token, scheme)
.SetBlackFormats(new List { ".log", ".tmp", ".cache" })
.SetSkipDirectorys(new List { "/temp", "/logs" })
.Build();
@@ -86,17 +143,26 @@ var config = new ConfiginfoBuilder(updateUrl, token, scheme)
## Default Values
-The builder provides these defaults automatically:
+The builder and `Configinfo` class provide these defaults:
+
+### Configinfo Class Defaults (Property Initializers)
+- **AppName**: "Update.exe"
+- **InstallPath**: Current program's running directory (`AppDomain.CurrentDomain.BaseDirectory`)
+### ConfiginfoBuilder Defaults (for Builder Pattern)
- **ClientVersion**: "1.0.0"
- **UpgradeClientVersion**: "1.0.0"
- **AppSecretKey**: "default-secret-key"
- **ProductId**: "default-product-id"
-- **BlackFormats**: `.log`, `.tmp` (via `ConfiginfoBuilder.DefaultBlackFormats`)
+- **MainAppName**: "App.exe"
+- **BlackFormats**: `.log`, `.tmp`, `.cache`, `.bak` (via `ConfiginfoBuilder.DefaultBlackFormats`)
- **BlackFiles**: Empty list
- **SkipDirectorys**: Empty list
-All defaults can be overridden using the setter methods.
+All defaults can be overridden using:
+1. JSON configuration file (`update_config.json`) - highest priority
+2. Builder setter methods (`.SetXXX()`)
+3. Direct property assignment on `Configinfo` objects
## Error Handling
@@ -117,12 +183,14 @@ try {
## Testing
-The implementation includes 32 comprehensive unit tests covering:
+The implementation includes 39 comprehensive unit tests covering:
- Constructor validation
- Default value generation
- Platform-specific behavior
- Method chaining
- Error handling
+- JSON configuration file loading
+- Fallback behavior when JSON is invalid
- Complete integration scenarios
Run tests with:
@@ -158,9 +226,28 @@ var config = new Configinfo
};
```
-**After:**
+**After (with JSON configuration):**
+```json
+// update_config.json
+{
+ "UpdateUrl": "https://api.example.com/updates",
+ "Token": "my-token",
+ "Scheme": "https",
+ "AppName": "MyApp.exe",
+ "ClientVersion": "1.0.0"
+}
+```
+```csharp
+var config = ConfiginfoBuilder
+ .Create("fallback", "fallback", "https")
+ .Build();
+```
+
+**After (with code only):**
```csharp
-var config = new ConfiginfoBuilder(url, token, scheme).Build();
+var config = ConfiginfoBuilder
+ .Create(url, token, scheme)
+ .Build();
```
## Contributing
diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/update_config.example.json b/src/c#/GeneralUpdate.Common/Shared/Object/update_config.example.json
new file mode 100644
index 00000000..ce6b7797
--- /dev/null
+++ b/src/c#/GeneralUpdate.Common/Shared/Object/update_config.example.json
@@ -0,0 +1,31 @@
+{
+ "UpdateUrl": "https://api.example.com/updates",
+ "Token": "your-authentication-token-here",
+ "Scheme": "https",
+ "AppName": "Update.exe",
+ "MainAppName": "MyApplication.exe",
+ "ClientVersion": "1.0.0",
+ "UpgradeClientVersion": "1.0.0",
+ "AppSecretKey": "your-secret-key-here",
+ "ProductId": "your-product-id",
+ "InstallPath": "/path/to/installation",
+ "UpdateLogUrl": "https://example.com/changelog",
+ "ReportUrl": "https://api.example.com/report",
+ "Bowl": "Bowl.exe",
+ "Script": "#!/bin/bash\nchmod +x *",
+ "DriverDirectory": "/path/to/drivers",
+ "BlackFiles": [
+ "config.json",
+ "user.dat"
+ ],
+ "BlackFormats": [
+ ".log",
+ ".tmp",
+ ".cache",
+ ".bak"
+ ],
+ "SkipDirectorys": [
+ "/temp",
+ "/logs"
+ ]
+}
From 55bc4b0a32cdc758dc5eb6c9909f448276f7d2b9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 16 Feb 2026 13:55:15 +0000
Subject: [PATCH 5/7] Address code review: improve exception handling with
specific catch blocks
Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
---
.../Shared/Object/ConfiginfoBuilder.cs | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs
index dfb2c306..0fe57a99 100644
--- a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs
+++ b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs
@@ -135,9 +135,24 @@ private static ConfiginfoBuilder LoadFromConfigFile()
return builder;
}
+ catch (System.Text.Json.JsonException)
+ {
+ // Invalid JSON format, fall back to parameters
+ return null;
+ }
+ catch (IOException)
+ {
+ // File read error, fall back to parameters
+ return null;
+ }
+ catch (UnauthorizedAccessException)
+ {
+ // Permission denied, fall back to parameters
+ return null;
+ }
catch
{
- // If there's any error reading or parsing the file, return null
+ // Any other unexpected error, fall back to parameters
return null;
}
}
@@ -184,6 +199,8 @@ private void InitializePlatformDefaults()
_skipDirectorys = new List();
// Set default InstallPath to current program running directory
+ // This is set here to ensure the builder has a consistent default
+ // even though BaseConfigInfo also has this default via property initializer
_installPath = AppDomain.CurrentDomain.BaseDirectory;
}
From 6917e7bb5a7637dfea2684f909cfef1d18330001 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 16 Feb 2026 14:07:31 +0000
Subject: [PATCH 6/7] Address reviewer feedback: remove default values, add
parameterless Create() method
- Removed default values from DefaultBlackFormats (now empty array)
- Removed default values from _mainAppName, _clientVersion, _upgradeClientVersion, _appSecretKey, _productId
- Added parameterless Create() method that loads from update_config.json only
- Kept parameterized Create(url, token, scheme) for programmatic configuration
- Updated all tests to set required fields explicitly
- Updated example code to demonstrate JSON-based configuration
All 39 tests pass.
Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
---
.../CoreTest/Shared/ConfiginfoBuilderTests.cs | 110 +++++-----
.../Object/ConfiginfoBuilder-Example.cs | 192 ++++++++----------
.../Shared/Object/ConfiginfoBuilder.cs | 47 +++--
3 files changed, 172 insertions(+), 177 deletions(-)
diff --git a/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs b/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs
index 09df289d..c5255f5e 100644
--- a/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs
+++ b/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs
@@ -17,6 +17,18 @@ public class ConfiginfoBuilderTests
private const string TestToken = "test-token-12345";
private const string TestScheme = "https";
+ ///
+ /// Helper method to create a builder with all required fields set for testing.
+ /// Since defaults were removed per requirements, tests must explicitly set required fields.
+ ///
+ private ConfiginfoBuilder CreateBuilderWithRequiredFields()
+ {
+ return ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme)
+ .SetMainAppName("TestApp.exe")
+ .SetClientVersion("1.0.0")
+ .SetAppSecretKey("test-secret-key");
+ }
+
#region Constructor Tests
///
@@ -26,7 +38,7 @@ public class ConfiginfoBuilderTests
public void Create_WithValidParameters_CreatesInstance()
{
// Act
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
// Assert
Assert.NotNull(builder);
@@ -39,8 +51,8 @@ public void Create_WithValidParameters_CreatesInstance()
public void Create_ProducesConsistentResults()
{
// Act
- var config1 = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme).Build();
- var config2 = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme).Build();
+ var config1 = CreateBuilderWithRequiredFields().Build();
+ var config2 = CreateBuilderWithRequiredFields().Build();
// Assert
Assert.Equal(config1.UpdateUrl, config2.UpdateUrl);
@@ -120,13 +132,16 @@ public void Create_WithNullScheme_ThrowsArgumentException()
#region Build Method Tests
///
- /// Tests that Build() creates a valid Configinfo object with default values.
+ /// Tests that Build() creates a valid Configinfo object when all required fields are set.
///
[Fact]
public void Build_WithMinimalParameters_ReturnsValidConfiginfo()
{
- // Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ // Arrange - Now that defaults are removed, we must set all required fields
+ var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme)
+ .SetMainAppName("TestApp.exe")
+ .SetClientVersion("1.0.0")
+ .SetAppSecretKey("test-secret-key");
// Act
var config = builder.Build();
@@ -150,7 +165,7 @@ public void Build_WithMinimalParameters_ReturnsValidConfiginfo()
public void Build_GeneratesPlatformSpecificDefaults()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
// Act
var config = builder.Build();
@@ -172,7 +187,7 @@ public void Build_GeneratesPlatformSpecificDefaults()
public void Build_InitializesCollectionProperties()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
// Act
var config = builder.Build();
@@ -181,8 +196,8 @@ public void Build_InitializesCollectionProperties()
Assert.NotNull(config.BlackFiles);
Assert.NotNull(config.BlackFormats);
Assert.NotNull(config.SkipDirectorys);
- Assert.Contains(".log", config.BlackFormats);
- Assert.Contains(".tmp", config.BlackFormats);
+ // DefaultBlackFormats is now empty per requirements
+ Assert.Empty(config.BlackFormats);
}
#endregion
@@ -196,7 +211,7 @@ public void Build_InitializesCollectionProperties()
public void SetAppName_WithValidValue_SetsAppName()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var customAppName = "CustomApp.exe";
// Act
@@ -213,7 +228,7 @@ public void SetAppName_WithValidValue_SetsAppName()
public void SetAppName_ReturnsBuilder_ForMethodChaining()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
// Act
var result = builder.SetAppName("Test.exe");
@@ -229,7 +244,7 @@ public void SetAppName_ReturnsBuilder_ForMethodChaining()
public void SetAppName_WithNullValue_ThrowsArgumentException()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
// Act & Assert
var exception = Assert.Throws(() => builder.SetAppName(null));
@@ -243,7 +258,7 @@ public void SetAppName_WithNullValue_ThrowsArgumentException()
public void SetMainAppName_WithValidValue_SetsMainAppName()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var customMainAppName = "MainApp.exe";
// Act
@@ -260,7 +275,7 @@ public void SetMainAppName_WithValidValue_SetsMainAppName()
public void SetClientVersion_WithValidValue_SetsClientVersion()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var customVersion = "2.5.1";
// Act
@@ -277,7 +292,7 @@ public void SetClientVersion_WithValidValue_SetsClientVersion()
public void SetUpgradeClientVersion_WithValidValue_SetsUpgradeClientVersion()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var customVersion = "3.0.0";
// Act
@@ -294,7 +309,7 @@ public void SetUpgradeClientVersion_WithValidValue_SetsUpgradeClientVersion()
public void SetAppSecretKey_WithValidValue_SetsAppSecretKey()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var customSecretKey = "my-secret-key-123";
// Act
@@ -311,7 +326,7 @@ public void SetAppSecretKey_WithValidValue_SetsAppSecretKey()
public void SetProductId_WithValidValue_SetsProductId()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var customProductId = "product-xyz-789";
// Act
@@ -328,7 +343,7 @@ public void SetProductId_WithValidValue_SetsProductId()
public void SetInstallPath_WithValidValue_SetsInstallPath()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var customPath = "/custom/install/path";
// Act
@@ -345,7 +360,7 @@ public void SetInstallPath_WithValidValue_SetsInstallPath()
public void SetUpdateLogUrl_WithValidUrl_SetsUpdateLogUrl()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var logUrl = "https://example.com/changelog";
// Act
@@ -362,7 +377,7 @@ public void SetUpdateLogUrl_WithValidUrl_SetsUpdateLogUrl()
public void SetUpdateLogUrl_WithInvalidUrl_ThrowsArgumentException()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
// Act & Assert
var exception = Assert.Throws(() =>
@@ -378,7 +393,7 @@ public void SetUpdateLogUrl_WithInvalidUrl_ThrowsArgumentException()
public void SetReportUrl_WithValidUrl_SetsReportUrl()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var reportUrl = "https://example.com/report";
// Act
@@ -395,7 +410,7 @@ public void SetReportUrl_WithValidUrl_SetsReportUrl()
public void SetBowl_WithValidValue_SetsBowl()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var bowlProcess = "Bowl.exe";
// Act
@@ -412,7 +427,7 @@ public void SetBowl_WithValidValue_SetsBowl()
public void SetScript_WithValidValue_SetsScript()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var customScript = "#!/bin/bash\necho 'Hello'";
// Act
@@ -429,7 +444,7 @@ public void SetScript_WithValidValue_SetsScript()
public void SetDriverDirectory_WithValidValue_SetsDriverDirectory()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var driverDir = "/path/to/drivers";
// Act
@@ -446,7 +461,7 @@ public void SetDriverDirectory_WithValidValue_SetsDriverDirectory()
public void SetBlackFiles_WithValidList_SetsBlackFiles()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var blackFiles = new List { "file1.txt", "file2.dat" };
// Act
@@ -463,7 +478,7 @@ public void SetBlackFiles_WithValidList_SetsBlackFiles()
public void SetBlackFormats_WithValidList_SetsBlackFormats()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var blackFormats = new List { ".bak", ".old" };
// Act
@@ -480,7 +495,7 @@ public void SetBlackFormats_WithValidList_SetsBlackFormats()
public void SetSkipDirectorys_WithValidList_SetsSkipDirectorys()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
var skipDirs = new List { "/temp", "/cache" };
// Act
@@ -534,7 +549,7 @@ public void Build_OnWindows_GeneratesWindowsDefaults()
}
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
// Act
var config = builder.Build();
@@ -559,7 +574,7 @@ public void Build_OnLinux_GeneratesLinuxDefaults()
}
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
// Act
var config = builder.Build();
@@ -584,7 +599,7 @@ public void Build_OnMacOS_GeneratesMacOSDefaults()
}
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
// Act
var config = builder.Build();
@@ -607,7 +622,7 @@ public void Build_OnMacOS_GeneratesMacOSDefaults()
public void Build_ReturnsConfiginfoThatPassesValidation()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
// Act
var config = builder.Build();
@@ -625,7 +640,7 @@ public void Build_ReturnsConfiginfoThatPassesValidation()
public void Build_AttemptsToExtractAppNameFromProject()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields();
// Act
var config = builder.Build();
@@ -644,27 +659,25 @@ public void Build_AttemptsToExtractAppNameFromProject()
}
///
- /// Tests that project metadata (version, company, etc.) is extracted from csproj when available.
- /// The builder should attempt to extract Version and Company/Authors fields.
+ /// Tests that project metadata fields can be set and retrieved.
+ /// Since defaults were removed per requirements, fields are null unless explicitly set.
///
[Fact]
public void Build_AttemptsToExtractProjectMetadata()
{
// Arrange
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme);
+ var builder = CreateBuilderWithRequiredFields()
+ .SetProductId("test-product-id");
// Act
var config = builder.Build();
- // Assert - Core fields should always be set (either extracted or defaults)
+ // Assert - Core fields should be set if explicitly provided
Assert.NotNull(config.ClientVersion);
Assert.NotEmpty(config.ClientVersion);
Assert.NotNull(config.ProductId);
Assert.NotEmpty(config.ProductId);
-
- // Version should follow a reasonable format if extracted (e.g., "1.0.0" or similar)
- // If extracted from project file, it might have proper semantic versioning
- // If using default, it should still be a valid string
+ Assert.Equal("test-product-id", config.ProductId);
}
///
@@ -725,6 +738,7 @@ public void Create_WithConfigFile_LoadsFromFile()
AppName = "ConfigFileApp.exe",
MainAppName = "ConfigFileMain.exe",
ClientVersion = "9.9.9",
+ AppSecretKey = "config-file-secret",
InstallPath = "/config/file/path"
};
@@ -733,14 +747,10 @@ public void Create_WithConfigFile_LoadsFromFile()
// Write test config file
File.WriteAllText(configFilePath, System.Text.Json.JsonSerializer.Serialize(testConfig));
- // Act - Create should load from file instead of using parameters
- var config = ConfiginfoBuilder.Create(
- "https://should-be-ignored.com/updates",
- "should-be-ignored-token",
- "http"
- ).Build();
+ // Act - Use parameterless Create() to load from file
+ var config = ConfiginfoBuilder.Create().Build();
- // Assert - Values should come from config file, not parameters
+ // Assert - Values should come from config file
Assert.Equal("https://config-file.example.com/updates", config.UpdateUrl);
Assert.Equal("config-file-token", config.Token);
Assert.Equal("https", config.Scheme);
@@ -775,7 +785,7 @@ public void Create_WithoutConfigFile_UsesParameters()
try
{
// Act - Create should use parameters
- var config = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme).Build();
+ var config = CreateBuilderWithRequiredFields().Build();
// Assert - Values should come from parameters and defaults
Assert.Equal(TestUpdateUrl, config.UpdateUrl);
@@ -804,7 +814,7 @@ public void Create_WithInvalidConfigFile_FallsBackToParameters()
File.WriteAllText(configFilePath, "{ invalid json content !!!");
// Act - Create should fall back to parameters
- var config = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme).Build();
+ var config = CreateBuilderWithRequiredFields().Build();
// Assert - Values should come from parameters (fallback)
Assert.Equal(TestUpdateUrl, config.UpdateUrl);
diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Example.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Example.cs
index ef80f24f..bda8fac9 100644
--- a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Example.cs
+++ b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Example.cs
@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
+using System.IO;
using GeneralUpdate.Common.Shared.Object;
namespace ConfiginfoBuilderExample
{
///
- /// Example demonstrating the ConfiginfoBuilder usage
+ /// Example demonstrating the ConfiginfoBuilder usage with JSON configuration
///
class Program
{
@@ -13,134 +14,105 @@ static void Main(string[] args)
{
Console.WriteLine("=== ConfiginfoBuilder Usage Examples ===\n");
- // Example 1: Minimal configuration (recommended for most cases)
- Console.WriteLine("Example 1: Minimal Configuration - Using Factory Method");
- var minimalConfig = ConfiginfoBuilder
- .Create("https://api.example.com/updates", "your-auth-token", "https")
- .Build();
+ // Example 1: Load configuration from JSON file (recommended)
+ Console.WriteLine("Example 1: Loading from update_config.json file");
+ Console.WriteLine("This example requires an update_config.json file in the running directory.");
+ Console.WriteLine("The configuration file has the highest priority and must contain all required settings.\n");
- Console.WriteLine($" UpdateUrl: {minimalConfig.UpdateUrl}");
- Console.WriteLine($" Token: {minimalConfig.Token}");
- Console.WriteLine($" Scheme: {minimalConfig.Scheme}");
- Console.WriteLine($" InstallPath: {minimalConfig.InstallPath}");
- Console.WriteLine($" AppName: {minimalConfig.AppName}");
- Console.WriteLine($" Default Black Formats: {string.Join(", ", ConfiginfoBuilder.DefaultBlackFormats)}");
- Console.WriteLine();
-
- // Example 2: Custom configuration with method chaining
- Console.WriteLine("Example 2: Custom Configuration - Using Create Method");
- var customConfig = ConfiginfoBuilder.Create(
- "https://api.example.com/updates",
- "Bearer abc123xyz",
- "https"
- )
- .SetAppName("MyApplication.exe")
- .SetMainAppName("MyApplication.exe")
- .SetClientVersion("2.1.0")
- .SetInstallPath("/opt/myapp")
- .SetAppSecretKey("super-secret-key-789")
- .Build();
-
- Console.WriteLine($" AppName: {customConfig.AppName}");
- Console.WriteLine($" ClientVersion: {customConfig.ClientVersion}");
- Console.WriteLine($" InstallPath: {customConfig.InstallPath}");
- Console.WriteLine($" AppSecretKey: {customConfig.AppSecretKey}");
- Console.WriteLine();
-
- // Example 3: Configuration with file filters
- Console.WriteLine("Example 3: With File Filters");
- var filteredConfig = ConfiginfoBuilder.Create(
- "https://api.example.com/updates",
- "token123",
- "https"
- )
- .SetBlackFiles(new List { "config.json", "user.dat" })
- .SetBlackFormats(new List { ".log", ".tmp", ".cache", ".bak" })
- .SetSkipDirectorys(new List { "/temp", "/logs" })
- .Build();
-
- Console.WriteLine($" Black Files: {string.Join(", ", filteredConfig.BlackFiles)}");
- Console.WriteLine($" Black Formats: {string.Join(", ", filteredConfig.BlackFormats)}");
- Console.WriteLine($" Skip Directories: {string.Join(", ", filteredConfig.SkipDirectorys)}");
- Console.WriteLine();
-
- // Example 4: Complete configuration
- Console.WriteLine("Example 4: Complete Configuration");
- var completeConfig = ConfiginfoBuilder.Create(
- updateUrl: "https://api.example.com/updates",
- token: "Bearer xyz789",
- scheme: "https"
- )
- .SetAppName("MyApp.exe")
- .SetMainAppName("MyApp.exe")
- .SetClientVersion("3.0.0")
- .SetUpgradeClientVersion("1.5.0")
- .SetProductId("myapp-001")
- .SetAppSecretKey("secret-key-456")
- .SetInstallPath("/opt/myapp")
- .SetUpdateLogUrl("https://myapp.example.com/changelog")
- .SetReportUrl("https://api.example.com/report")
- .SetBowl("Bowl.exe")
- .SetDriverDirectory("/opt/myapp/drivers")
- .Build();
-
- Console.WriteLine($" ProductId: {completeConfig.ProductId}");
- Console.WriteLine($" UpdateLogUrl: {completeConfig.UpdateLogUrl}");
- Console.WriteLine($" ReportUrl: {completeConfig.ReportUrl}");
- Console.WriteLine($" Bowl: {completeConfig.Bowl}");
- Console.WriteLine();
-
- // Example 5: Error handling
- Console.WriteLine("Example 5: Error Handling");
try
{
- // Note: Create method loads from config file if available
- // For demonstration, we'll show that invalid params would fail
- // if no config file exists
- var invalidConfig = ConfiginfoBuilder.Create(
- null, // Invalid: null URL
- "token",
- "https"
- );
+ // Create update_config.json for demonstration
+ CreateExampleConfigFile();
+
+ // Simply call Create() with no parameters - it loads from update_config.json
+ var config = ConfiginfoBuilder.Create().Build();
+
+ Console.WriteLine($" UpdateUrl: {config.UpdateUrl}");
+ Console.WriteLine($" Token: {config.Token}");
+ Console.WriteLine($" Scheme: {config.Scheme}");
+ Console.WriteLine($" InstallPath: {config.InstallPath}");
+ Console.WriteLine($" AppName: {config.AppName}");
+ Console.WriteLine($" ClientVersion: {config.ClientVersion}");
+ Console.WriteLine();
}
- catch (ArgumentException ex)
+ catch (FileNotFoundException ex)
{
- Console.WriteLine($" Caught expected error: {ex.Message}");
+ Console.WriteLine($" Error: {ex.Message}");
+ Console.WriteLine(" Please create update_config.json in the running directory.");
+ Console.WriteLine();
+ }
+ finally
+ {
+ CleanupExampleConfigFile();
}
+ // Example 2: Customizing configuration after loading from file
+ Console.WriteLine("Example 2: Loading from JSON and customizing with method chaining");
try
{
- var invalidConfig2 = ConfiginfoBuilder.Create(
- "not-a-url", // Invalid: malformed URL
- "token",
- "https"
- );
+ CreateExampleConfigFile();
+
+ var customConfig = ConfiginfoBuilder.Create()
+ .SetAppName("CustomApp.exe")
+ .SetInstallPath("/custom/path")
+ .Build();
+
+ Console.WriteLine($" AppName: {customConfig.AppName}");
+ Console.WriteLine($" InstallPath: {customConfig.InstallPath}");
+ Console.WriteLine();
}
- catch (ArgumentException ex)
+ catch (FileNotFoundException ex)
{
- Console.WriteLine($" Caught expected error: {ex.Message}");
+ Console.WriteLine($" Error: {ex.Message}");
+ Console.WriteLine();
+ }
+ finally
+ {
+ CleanupExampleConfigFile();
}
- Console.WriteLine();
- // Example 6: Validate configuration
- Console.WriteLine("Example 6: Configuration Validation");
- var validConfig = ConfiginfoBuilder.Create(
- "https://api.example.com/updates",
- "token",
- "https"
- ).Build();
-
+ // Example 3: Error handling when config file is missing
+ Console.WriteLine("Example 3: Error Handling - Missing Configuration File");
try
{
- validConfig.Validate();
- Console.WriteLine(" Configuration is valid!");
+ var config = ConfiginfoBuilder.Create().Build();
}
- catch (ArgumentException ex)
+ catch (FileNotFoundException ex)
{
- Console.WriteLine($" Validation failed: {ex.Message}");
+ Console.WriteLine($" Caught expected error: {ex.Message}");
+ Console.WriteLine(" This is expected when update_config.json doesn't exist.");
}
+ Console.WriteLine();
+
+ Console.WriteLine("\n=== All Examples Completed! ===");
+ Console.WriteLine("\nNote: ConfiginfoBuilder now requires update_config.json file.");
+ Console.WriteLine("See update_config.example.json for a complete example.");
+ }
+
+ private static void CreateExampleConfigFile()
+ {
+ var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json");
+ var exampleConfig = @"{
+ ""UpdateUrl"": ""https://api.example.com/updates"",
+ ""Token"": ""example-auth-token"",
+ ""Scheme"": ""https"",
+ ""AppName"": ""Update.exe"",
+ ""MainAppName"": ""MyApplication.exe"",
+ ""ClientVersion"": ""1.0.0"",
+ ""UpgradeClientVersion"": ""1.0.0"",
+ ""AppSecretKey"": ""example-secret-key"",
+ ""ProductId"": ""example-product-id""
+}";
+ File.WriteAllText(configPath, exampleConfig);
+ }
- Console.WriteLine("\n=== All Examples Completed Successfully! ===");
+ private static void CleanupExampleConfigFile()
+ {
+ var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json");
+ if (File.Exists(configPath))
+ {
+ File.Delete(configPath);
+ }
}
}
}
diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs
index 0fe57a99..5ff78b6c 100644
--- a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs
+++ b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs
@@ -20,7 +20,7 @@ public class ConfiginfoBuilder
static ConfiginfoBuilder()
{
- DefaultBlackFormats = new[] { ".log", ".tmp", ".cache", ".bak" };
+ DefaultBlackFormats = new string[0];
}
private readonly string _updateUrl;
@@ -31,11 +31,11 @@ static ConfiginfoBuilder()
// Note: AppName and InstallPath defaults are set in Configinfo class itself
// These are ConfiginfoBuilder-specific defaults to support the builder pattern
private string _appName = "Update.exe";
- private string _mainAppName = "App.exe";
- private string _clientVersion = "1.0.0";
- private string _upgradeClientVersion = "1.0.0";
- private string _appSecretKey = "default-secret-key";
- private string _productId = "default-product-id";
+ private string _mainAppName;
+ private string _clientVersion;
+ private string _upgradeClientVersion;
+ private string _appSecretKey;
+ private string _productId;
private string _installPath;
private string _updateLogUrl;
private string _reportUrl;
@@ -46,11 +46,32 @@ static ConfiginfoBuilder()
private List _blackFormats;
private List _skipDirectorys;
+ ///
+ /// Creates a new ConfiginfoBuilder instance by loading configuration from update_config.json file.
+ /// The configuration file must exist in the running directory and contain all required settings.
+ /// This method has the highest priority - configuration file settings override any code-based settings.
+ ///
+ /// A new ConfiginfoBuilder instance with settings loaded from the configuration file.
+ /// Thrown when update_config.json is not found.
+ /// Thrown when the configuration file is invalid or cannot be loaded.
+ public static ConfiginfoBuilder Create()
+ {
+ // Try to load from configuration file
+ var configFromFile = LoadFromConfigFile();
+ if (configFromFile != null)
+ {
+ // Configuration file loaded successfully
+ return configFromFile;
+ }
+
+ // If no config file exists, throw an exception
+ throw new FileNotFoundException("Configuration file 'update_config.json' not found in the running directory. Please create this file with the required settings.");
+ }
+
///
/// Creates a new ConfiginfoBuilder instance using the specified update URL, authentication token, and scheme.
- /// This is the primary factory method for creating a builder with zero-configuration defaults.
- /// If update_config.json exists in the running directory, it will be loaded with highest priority.
- /// All other configuration properties will be automatically initialized with platform-appropriate defaults.
+ /// This method is provided for programmatic configuration when not using a JSON configuration file.
+ /// Note: If update_config.json exists, use the parameterless Create() method instead as it has higher priority.
///
/// The API endpoint URL for checking available updates. Must be a valid absolute URI.
/// The authentication token used for API requests.
@@ -59,14 +80,6 @@ static ConfiginfoBuilder()
/// Thrown when any required parameter is null, empty, or invalid.
public static ConfiginfoBuilder Create(string updateUrl, string token, string scheme)
{
- // Try to load from configuration file first
- var configFromFile = LoadFromConfigFile();
- if (configFromFile != null)
- {
- // Configuration file has highest priority, return directly
- return configFromFile;
- }
-
return new ConfiginfoBuilder(updateUrl, token, scheme);
}
From 8c1cabdbff5f4945ae7cc179acbc08a79dffe723 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 16 Feb 2026 14:20:34 +0000
Subject: [PATCH 7/7] Remove parameterized Create() method - JSON config file
only
- Removed Create(url, token, scheme) overload per reviewer feedback
- Only parameterless Create() method remains, which loads exclusively from update_config.json
- Updated all tests to create JSON config files instead of using parameterized Create
- Added helper methods CreateTestConfigFile() and CleanupTestConfigFile() for tests
- All 37 ConfiginfoBuilder tests passing
Configuration must now be done through JSON file - highest priority per requirements.
Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com>
---
.../CoreTest/Shared/ConfiginfoBuilderTests.cs | 394 +++++++++++-------
.../Shared/Object/ConfiginfoBuilder.cs | 17 +-
2 files changed, 244 insertions(+), 167 deletions(-)
diff --git a/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs b/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs
index c5255f5e..5d855e9e 100644
--- a/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs
+++ b/src/c#/CoreTest/Shared/ConfiginfoBuilderTests.cs
@@ -18,113 +18,166 @@ public class ConfiginfoBuilderTests
private const string TestScheme = "https";
///
- /// Helper method to create a builder with all required fields set for testing.
- /// Since defaults were removed per requirements, tests must explicitly set required fields.
+ /// Helper method to create a test config file with all required fields.
///
- private ConfiginfoBuilder CreateBuilderWithRequiredFields()
+ private void CreateTestConfigFile()
{
- return ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme)
- .SetMainAppName("TestApp.exe")
- .SetClientVersion("1.0.0")
- .SetAppSecretKey("test-secret-key");
+ var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json");
+ var testConfig = new
+ {
+ UpdateUrl = TestUpdateUrl,
+ Token = TestToken,
+ Scheme = TestScheme,
+ AppName = "Update.exe",
+ MainAppName = "TestApp.exe",
+ ClientVersion = "1.0.0",
+ AppSecretKey = "test-secret-key",
+ InstallPath = AppDomain.CurrentDomain.BaseDirectory
+ };
+ File.WriteAllText(configPath, System.Text.Json.JsonSerializer.Serialize(testConfig));
}
- #region Constructor Tests
-
///
- /// Tests that the Create factory method properly initializes with valid parameters.
+ /// Helper method to clean up test config file.
///
- [Fact]
- public void Create_WithValidParameters_CreatesInstance()
+ private void CleanupTestConfigFile()
{
- // Act
- var builder = CreateBuilderWithRequiredFields();
-
- // Assert
- Assert.NotNull(builder);
+ var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json");
+ if (File.Exists(configPath))
+ {
+ File.Delete(configPath);
+ }
}
///
- /// Tests that Create factory method produces consistent results.
+ /// Helper method to create a builder with all required fields set for testing.
+ /// Creates a config file, loads it, and returns the builder.
///
- [Fact]
- public void Create_ProducesConsistentResults()
+ private ConfiginfoBuilder CreateBuilderWithRequiredFields()
{
- // Act
- var config1 = CreateBuilderWithRequiredFields().Build();
- var config2 = CreateBuilderWithRequiredFields().Build();
-
- // Assert
- Assert.Equal(config1.UpdateUrl, config2.UpdateUrl);
- Assert.Equal(config1.Token, config2.Token);
- Assert.Equal(config1.Scheme, config2.Scheme);
- Assert.Equal(config1.AppName, config2.AppName);
+ CreateTestConfigFile();
+ return ConfiginfoBuilder.Create();
}
+ #region Constructor Tests
+
///
- /// Tests that the Create method throws ArgumentException when UpdateUrl is null.
+ /// Tests that the Create factory method properly initializes from config file.
///
[Fact]
- public void Create_WithNullUpdateUrl_ThrowsArgumentException()
+ public void Create_WithValidConfigFile_CreatesInstance()
{
- // Act & Assert
- var exception = Assert.Throws(() =>
- ConfiginfoBuilder.Create(null, TestToken, TestScheme));
-
- Assert.Contains("UpdateUrl", exception.Message);
+ try
+ {
+ // Arrange
+ CreateTestConfigFile();
+
+ // Act
+ var builder = ConfiginfoBuilder.Create();
+
+ // Assert
+ Assert.NotNull(builder);
+ }
+ finally
+ {
+ CleanupTestConfigFile();
+ }
}
///
- /// Tests that the Create method throws ArgumentException when UpdateUrl is empty.
+ /// Tests that Create factory method produces consistent results.
///
[Fact]
- public void Create_WithEmptyUpdateUrl_ThrowsArgumentException()
+ public void Create_ProducesConsistentResults()
{
- // Act & Assert
- var exception = Assert.Throws(() =>
- ConfiginfoBuilder.Create("", TestToken, TestScheme));
-
- Assert.Contains("UpdateUrl", exception.Message);
+ try
+ {
+ // Arrange
+ CreateTestConfigFile();
+
+ // Act
+ var config1 = ConfiginfoBuilder.Create().Build();
+ var config2 = ConfiginfoBuilder.Create().Build();
+
+ // Assert
+ Assert.Equal(config1.UpdateUrl, config2.UpdateUrl);
+ Assert.Equal(config1.Token, config2.Token);
+ Assert.Equal(config1.Scheme, config2.Scheme);
+ Assert.Equal(config1.AppName, config2.AppName);
+ }
+ finally
+ {
+ CleanupTestConfigFile();
+ }
}
///
- /// Tests that the Create method throws ArgumentException when UpdateUrl is not a valid URI.
+ /// Tests that the Create method throws FileNotFoundException when config file is missing.
///
[Fact]
- public void Create_WithInvalidUpdateUrl_ThrowsArgumentException()
+ public void Create_WithoutConfigFile_ThrowsFileNotFoundException()
{
+ // Arrange - ensure no config file exists
+ CleanupTestConfigFile();
+
// Act & Assert
- var exception = Assert.Throws(() =>
- ConfiginfoBuilder.Create("not-a-valid-url", TestToken, TestScheme));
+ var exception = Assert.Throws(() =>
+ ConfiginfoBuilder.Create());
- Assert.Contains("UpdateUrl", exception.Message);
- Assert.Contains("valid absolute URI", exception.Message);
+ Assert.Contains("update_config.json", exception.Message);
}
///
- /// Tests that the Create method throws ArgumentException when Token is null.
+ /// Tests that the Create method handles invalid JSON gracefully.
///
[Fact]
- public void Create_WithNullToken_ThrowsArgumentException()
+ public void Create_WithInvalidJson_ThrowsFileNotFoundException()
{
- // Act & Assert
- var exception = Assert.Throws(() =>
- ConfiginfoBuilder.Create(TestUpdateUrl, null, TestScheme));
-
- Assert.Contains("Token", exception.Message);
+ try
+ {
+ // Arrange - create invalid JSON file
+ var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json");
+ File.WriteAllText(configPath, "{ invalid json content");
+
+ // Act & Assert
+ var exception = Assert.Throws(() =>
+ ConfiginfoBuilder.Create());
+
+ Assert.Contains("update_config.json", exception.Message);
+ }
+ finally
+ {
+ CleanupTestConfigFile();
+ }
}
///
- /// Tests that the Create method throws ArgumentException when Scheme is null.
+ /// Tests that the Create method validates required fields from config file.
///
[Fact]
- public void Create_WithNullScheme_ThrowsArgumentException()
+ public void Create_WithIncompleteConfig_ThrowsOnBuild()
{
- // Act & Assert
- var exception = Assert.Throws(() =>
- ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, null));
-
- Assert.Contains("Scheme", exception.Message);
+ try
+ {
+ // Arrange - create config with missing required fields
+ var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json");
+ var incompleteConfig = new
+ {
+ UpdateUrl = TestUpdateUrl,
+ Token = TestToken,
+ Scheme = TestScheme
+ // Missing MainAppName, ClientVersion, AppSecretKey
+ };
+ File.WriteAllText(configPath, System.Text.Json.JsonSerializer.Serialize(incompleteConfig));
+
+ // Act & Assert
+ var builder = ConfiginfoBuilder.Create();
+ Assert.Throws(() => builder.Build());
+ }
+ finally
+ {
+ CleanupTestConfigFile();
+ }
}
#endregion
@@ -137,25 +190,30 @@ public void Create_WithNullScheme_ThrowsArgumentException()
[Fact]
public void Build_WithMinimalParameters_ReturnsValidConfiginfo()
{
- // Arrange - Now that defaults are removed, we must set all required fields
- var builder = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme)
- .SetMainAppName("TestApp.exe")
- .SetClientVersion("1.0.0")
- .SetAppSecretKey("test-secret-key");
+ try
+ {
+ // Arrange - Now that defaults are removed, we must set all required fields via config file
+ CreateTestConfigFile();
+ var builder = ConfiginfoBuilder.Create();
- // Act
- var config = builder.Build();
+ // Act
+ var config = builder.Build();
- // Assert
- Assert.NotNull(config);
- Assert.Equal(TestUpdateUrl, config.UpdateUrl);
- Assert.Equal(TestToken, config.Token);
- Assert.Equal(TestScheme, config.Scheme);
- Assert.NotNull(config.AppName);
- Assert.NotNull(config.MainAppName);
- Assert.NotNull(config.ClientVersion);
- Assert.NotNull(config.InstallPath);
- Assert.NotNull(config.AppSecretKey);
+ // Assert
+ Assert.NotNull(config);
+ Assert.Equal(TestUpdateUrl, config.UpdateUrl);
+ Assert.Equal(TestToken, config.Token);
+ Assert.Equal(TestScheme, config.Scheme);
+ Assert.NotNull(config.AppName);
+ Assert.NotNull(config.MainAppName);
+ Assert.NotNull(config.ClientVersion);
+ Assert.NotNull(config.InstallPath);
+ Assert.NotNull(config.AppSecretKey);
+ }
+ finally
+ {
+ CleanupTestConfigFile();
+ }
}
///
@@ -164,20 +222,27 @@ public void Build_WithMinimalParameters_ReturnsValidConfiginfo()
[Fact]
public void Build_GeneratesPlatformSpecificDefaults()
{
- // Arrange
- var builder = CreateBuilderWithRequiredFields();
-
- // Act
- var config = builder.Build();
-
- // Assert
- Assert.NotNull(config.InstallPath);
-
- // InstallPath should be the current application's base directory
- Assert.Equal(AppDomain.CurrentDomain.BaseDirectory, config.InstallPath);
-
- // According to requirements, AppName default is "Update.exe" regardless of platform
- Assert.Equal("Update.exe", config.AppName);
+ try
+ {
+ // Arrange
+ var builder = CreateBuilderWithRequiredFields();
+
+ // Act
+ var config = builder.Build();
+
+ // Assert
+ Assert.NotNull(config.InstallPath);
+
+ // InstallPath should be the current application's base directory
+ Assert.Equal(AppDomain.CurrentDomain.BaseDirectory, config.InstallPath);
+
+ // According to requirements, AppName default is "Update.exe" regardless of platform
+ Assert.Equal("Update.exe", config.AppName);
+ }
+ finally
+ {
+ CleanupTestConfigFile();
+ }
}
///
@@ -186,18 +251,25 @@ public void Build_GeneratesPlatformSpecificDefaults()
[Fact]
public void Build_InitializesCollectionProperties()
{
- // Arrange
- var builder = CreateBuilderWithRequiredFields();
-
- // Act
- var config = builder.Build();
-
- // Assert
- Assert.NotNull(config.BlackFiles);
- Assert.NotNull(config.BlackFormats);
- Assert.NotNull(config.SkipDirectorys);
- // DefaultBlackFormats is now empty per requirements
- Assert.Empty(config.BlackFormats);
+ try
+ {
+ // Arrange
+ var builder = CreateBuilderWithRequiredFields();
+
+ // Act
+ var config = builder.Build();
+
+ // Assert
+ Assert.NotNull(config.BlackFiles);
+ Assert.NotNull(config.BlackFormats);
+ Assert.NotNull(config.SkipDirectorys);
+ // DefaultBlackFormats is now empty per requirements
+ Assert.Empty(config.BlackFormats);
+ }
+ finally
+ {
+ CleanupTestConfigFile();
+ }
}
#endregion
@@ -515,21 +587,29 @@ public void SetSkipDirectorys_WithValidList_SetsSkipDirectorys()
[Fact]
public void BuilderPattern_SupportsMethodChaining()
{
- // Arrange & Act
- var config = ConfiginfoBuilder.Create(TestUpdateUrl, TestToken, TestScheme)
- .SetAppName("CustomApp.exe")
- .SetMainAppName("MainCustomApp.exe")
- .SetClientVersion("2.0.0")
- .SetInstallPath("/custom/path")
- .SetAppSecretKey("custom-secret")
- .Build();
-
- // Assert
- Assert.Equal("CustomApp.exe", config.AppName);
- Assert.Equal("MainCustomApp.exe", config.MainAppName);
- Assert.Equal("2.0.0", config.ClientVersion);
- Assert.Equal("/custom/path", config.InstallPath);
- Assert.Equal("custom-secret", config.AppSecretKey);
+ try
+ {
+ // Arrange & Act
+ CreateTestConfigFile();
+ var config = ConfiginfoBuilder.Create()
+ .SetAppName("CustomApp.exe")
+ .SetMainAppName("MainCustomApp.exe")
+ .SetClientVersion("2.0.0")
+ .SetInstallPath("/custom/path")
+ .SetAppSecretKey("custom-secret")
+ .Build();
+
+ // Assert
+ Assert.Equal("CustomApp.exe", config.AppName);
+ Assert.Equal("MainCustomApp.exe", config.MainAppName);
+ Assert.Equal("2.0.0", config.ClientVersion);
+ Assert.Equal("/custom/path", config.InstallPath);
+ Assert.Equal("custom-secret", config.AppSecretKey);
+ }
+ finally
+ {
+ CleanupTestConfigFile();
+ }
}
#endregion
@@ -686,36 +766,48 @@ public void Build_AttemptsToExtractProjectMetadata()
[Fact]
public void CompleteScenario_BuildsValidConfiginfo()
{
- // Arrange
- var updateUrl = "https://api.example.com/updates";
- var token = "Bearer abc123xyz";
- var scheme = "https";
-
- // Act
- var config = ConfiginfoBuilder.Create(updateUrl, token, scheme)
- .SetAppName("MyApplication.exe")
- .SetMainAppName("MyApplication.exe")
- .SetClientVersion("1.5.2")
- .SetUpgradeClientVersion("1.0.0")
- .SetAppSecretKey("super-secret-key-456")
- .SetProductId("my-product-001")
- .SetInstallPath("/opt/myapp")
- .SetUpdateLogUrl("https://example.com/changelog")
- .SetReportUrl("https://api.example.com/report")
- .SetBlackFormats(new List { ".log", ".tmp", ".cache" })
- .Build();
-
- // Assert
- Assert.NotNull(config);
- Assert.Equal(updateUrl, config.UpdateUrl);
- Assert.Equal(token, config.Token);
- Assert.Equal(scheme, config.Scheme);
- Assert.Equal("MyApplication.exe", config.AppName);
- Assert.Equal("1.5.2", config.ClientVersion);
- Assert.Equal("/opt/myapp", config.InstallPath);
-
- // Should pass validation
- config.Validate();
+ try
+ {
+ // Arrange
+ var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json");
+ var completeConfig = new
+ {
+ UpdateUrl = "https://api.example.com/updates",
+ Token = "Bearer abc123xyz",
+ Scheme = "https",
+ AppName = "MyApplication.exe",
+ MainAppName = "MyApplication.exe",
+ ClientVersion = "1.5.2",
+ UpgradeClientVersion = "1.0.0",
+ AppSecretKey = "super-secret-key-456",
+ ProductId = "my-product-001",
+ InstallPath = "/opt/myapp",
+ UpdateLogUrl = "https://example.com/changelog",
+ ReportUrl = "https://api.example.com/report",
+ BlackFormats = new[] { ".log", ".tmp", ".cache" }
+ };
+ File.WriteAllText(configPath, System.Text.Json.JsonSerializer.Serialize(completeConfig));
+
+ // Act
+ var config = ConfiginfoBuilder.Create()
+ .Build();
+
+ // Assert
+ Assert.NotNull(config);
+ Assert.Equal("https://api.example.com/updates", config.UpdateUrl);
+ Assert.Equal("Bearer abc123xyz", config.Token);
+ Assert.Equal("https", config.Scheme);
+ Assert.Equal("MyApplication.exe", config.AppName);
+ Assert.Equal("1.5.2", config.ClientVersion);
+ Assert.Equal("/opt/myapp", config.InstallPath);
+
+ // Should pass validation
+ config.Validate();
+ }
+ finally
+ {
+ CleanupTestConfigFile();
+ }
}
#endregion
diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs
index 5ff78b6c..3051988c 100644
--- a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs
+++ b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs
@@ -49,7 +49,7 @@ static ConfiginfoBuilder()
///
/// Creates a new ConfiginfoBuilder instance by loading configuration from update_config.json file.
/// The configuration file must exist in the running directory and contain all required settings.
- /// This method has the highest priority - configuration file settings override any code-based settings.
+ /// Configuration file has the highest priority - all settings must be specified in the JSON file.
///
/// A new ConfiginfoBuilder instance with settings loaded from the configuration file.
/// Thrown when update_config.json is not found.
@@ -68,21 +68,6 @@ public static ConfiginfoBuilder Create()
throw new FileNotFoundException("Configuration file 'update_config.json' not found in the running directory. Please create this file with the required settings.");
}
- ///
- /// Creates a new ConfiginfoBuilder instance using the specified update URL, authentication token, and scheme.
- /// This method is provided for programmatic configuration when not using a JSON configuration file.
- /// Note: If update_config.json exists, use the parameterless Create() method instead as it has higher priority.
- ///
- /// The API endpoint URL for checking available updates. Must be a valid absolute URI.
- /// The authentication token used for API requests.
- /// The URL scheme used for update requests (e.g., "http" or "https").
- /// A new ConfiginfoBuilder instance with all defaults initialized.
- /// Thrown when any required parameter is null, empty, or invalid.
- public static ConfiginfoBuilder Create(string updateUrl, string token, string scheme)
- {
- return new ConfiginfoBuilder(updateUrl, token, scheme);
- }
-
///
/// Loads configuration from update_config.json file in the running directory.
///