Files
Denso/srcs/RobotNet10/Commons/RobotNet10.CustomConfiguration/Validators/ConfigValidator.cs
2026-07-03 16:31:37 +07:00

199 lines
7.3 KiB
C#

using RobotNet10.CustomConfiguration.Models;
using System.Globalization;
namespace RobotNet10.CustomConfiguration.Validators;
/// <summary>
/// Validator cho config files và variables
/// </summary>
public static class ConfigValidator
{
/// <summary>
/// Validate một config file
/// </summary>
public static ValidationResult ValidateConfig(ConfigFile config)
{
var errors = new List<string>();
// Validate ConfigType
if (string.IsNullOrWhiteSpace(config.ConfigType))
{
errors.Add("ConfigType cannot be empty");
}
// Validate Variables
if (config.Variables != null && config.Variables.Count > 0)
{
foreach (var variable in config.Variables)
{
var variableErrors = ValidateVariable(variable);
errors.AddRange(variableErrors);
}
}
return new ValidationResult
{
IsValid = errors.Count == 0,
Errors = errors
};
}
/// <summary>
/// Validate một variable
/// </summary>
public static List<string> ValidateVariable(ConfigVariable variable)
{
var errors = new List<string>();
// Validate Name
if (string.IsNullOrWhiteSpace(variable.Name))
{
errors.Add("Variable name cannot be empty");
}
// Validate Type
if (!Enum.IsDefined(variable.Type))
{
errors.Add($"Invalid variable type: {variable.Type}");
}
// Validate Value theo Type
if (variable.Value == null)
{
errors.Add($"Variable '{variable.Name}' value cannot be null");
}
else
{
var valueErrors = ValidateValueByType(variable.Name, variable.Type, variable.Value, variable.Min, variable.Max, variable);
errors.AddRange(valueErrors);
}
return errors;
}
/// <summary>
/// Validate value theo type và Min/Max constraints
/// </summary>
private static List<string> ValidateValueByType(string variableName, ConfigVariableType type, object value, double? min, double? max, ConfigVariable? variable = null)
{
var errors = new List<string>();
switch (type)
{
case ConfigVariableType.Int:
// Try parse
if (int.TryParse(value.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedInt))
{
if (min.HasValue && parsedInt < min.Value)
errors.Add($"Variable '{variableName}' value {parsedInt} is less than Min {min.Value}");
if (max.HasValue && parsedInt > max.Value)
errors.Add($"Variable '{variableName}' value {parsedInt} is greater than Max {max.Value}");
}
else
{
errors.Add($"Variable '{variableName}' must be an integer");
}
break;
case ConfigVariableType.Double:
// Try parse
if (double.TryParse(value.ToString(), NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var parsedDouble))
{
if (min.HasValue && parsedDouble < min.Value)
errors.Add($"Variable '{variableName}' value {parsedDouble} is less than Min {min.Value}");
if (max.HasValue && parsedDouble > max.Value)
errors.Add($"Variable '{variableName}' value {parsedDouble} is greater than Max {max.Value}");
}
else
{
errors.Add($"Variable '{variableName}' must be a double");
}
break;
case ConfigVariableType.Bool:
if (!bool.TryParse(value.ToString(), out _))
{
errors.Add($"Variable '{variableName}' must be a boolean");
}
break;
case ConfigVariableType.Object:
// Object có thể là Dictionary<string, object> hoặc JsonElement
if (value is not Dictionary<string, object> &&
value is not System.Text.Json.JsonElement)
{
// Try parse as JSON object
try
{
var jsonString = value.ToString();
if (jsonString != null)
{
using var doc = System.Text.Json.JsonDocument.Parse(jsonString);
if (doc.RootElement.ValueKind != System.Text.Json.JsonValueKind.Object)
{
errors.Add($"Variable '{variableName}' must be a JSON object");
}
}
}
catch (System.Text.Json.JsonException)
{
errors.Add($"Variable '{variableName}' must be a valid JSON object");
}
}
break;
case ConfigVariableType.Array:
// Array có thể là List<object> hoặc JsonElement
if (value is not List<object> &&
value is not System.Text.Json.JsonElement)
{
// Try parse as JSON array
try
{
var jsonString = value.ToString();
if (jsonString != null)
{
using var doc = System.Text.Json.JsonDocument.Parse(jsonString);
if (doc.RootElement.ValueKind != System.Text.Json.JsonValueKind.Array)
{
errors.Add($"Variable '{variableName}' must be a JSON array");
}
}
}
catch (System.Text.Json.JsonException)
{
errors.Add($"Variable '{variableName}' must be a valid JSON array");
}
}
break;
case ConfigVariableType.Enum:
if (variable == null || variable.EnumValues == null || variable.EnumValues.Count == 0)
{
errors.Add($"Variable '{variableName}' of type Enum must have EnumValues defined");
}
else
{
var valueStr = value?.ToString();
if (string.IsNullOrEmpty(valueStr) || !variable.EnumValues.Contains(valueStr))
{
errors.Add($"Variable '{variableName}' value '{valueStr}' is not in allowed enum values: {string.Join(", ", variable.EnumValues)}");
}
}
break;
}
return errors;
}
}
/// <summary>
/// Kết quả validation
/// </summary>
public class ValidationResult
{
public bool IsValid { get; set; }
public List<string> Errors { get; set; } = [];
}