MarketAlly.AIPlugin.Extensions/MarketAlly.AIPlugin.Analysis/Tests/Infrastructure/InputValidatorTests.cs

396 lines
12 KiB
C#
Executable File

using MarketAlly.AIPlugin.Analysis.Infrastructure;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.IO;
namespace MarketAlly.AIPlugin.Analysis.Tests.Infrastructure
{
[TestClass]
public class InputValidatorTests
{
private InputValidator _validator = null!;
[TestInitialize]
public void Setup()
{
_validator = new InputValidator();
}
[TestMethod]
public void ValidateFilePath_ValidPath_ShouldReturnSuccess()
{
// Arrange
var validPath = "test.cs";
// Act
var result = _validator.ValidateFilePath(validPath);
// Assert
Assert.IsTrue(result.IsValid);
Assert.IsNull(result.ErrorMessage);
Assert.IsNotNull(result.SanitizedValue);
}
[TestMethod]
public void ValidateFilePath_NullPath_ShouldReturnFailure()
{
// Act
var result = _validator.ValidateFilePath(null);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.AreEqual("File path cannot be null or empty", result.ErrorMessage);
}
[TestMethod]
public void ValidateFilePath_EmptyPath_ShouldReturnFailure()
{
// Act
var result = _validator.ValidateFilePath(string.Empty);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.AreEqual("File path cannot be null or empty", result.ErrorMessage);
}
[TestMethod]
public void ValidateFilePath_PathWithDangerousPatterns_ShouldReturnFailure()
{
// Arrange
var dangerousPath = "../../../secret.txt";
// Act
var result = _validator.ValidateFilePath(dangerousPath);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.IsTrue(result.ErrorMessage!.Contains("dangerous patterns"));
}
[TestMethod]
public void ValidateFilePath_PathWithInvalidCharacters_ShouldReturnFailure()
{
// Arrange
var invalidPath = "test<script>alert('xss')</script>.cs";
// Act
var result = _validator.ValidateFilePath(invalidPath);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.IsTrue(result.ErrorMessage!.Contains("dangerous patterns"));
}
[TestMethod]
public void ValidateFilePath_InvalidFileExtension_ShouldReturnFailure()
{
// Arrange - Use an extension that's actually not in the allowed list
var invalidPath = "malicious.bat";
// Act
var result = _validator.ValidateFilePath(invalidPath);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.IsTrue(result.ErrorMessage!.Contains("not allowed"));
}
[TestMethod]
public void ValidateFilePath_AllowedFileExtensions_ShouldReturnSuccess()
{
// Arrange - Use the actual allowed extensions from the implementation
var allowedExtensions = new[] { ".cs", ".csproj", ".sln", ".json", ".xml", ".config", ".md", ".txt", ".dll", ".exe", ".pdb", ".nuspec", ".props", ".targets" };
foreach (var extension in allowedExtensions)
{
var path = $"test{extension}";
// Act
var result = _validator.ValidateFilePath(path);
// Assert
Assert.IsTrue(result.IsValid, $"Extension {extension} should be allowed");
}
}
[TestMethod]
public void ValidatePluginParameters_NullParameters_ShouldReturnSuccess()
{
// Act
var result = _validator.ValidatePluginParameters(null);
// Assert
Assert.IsTrue(result.IsValid);
}
[TestMethod]
public void ValidatePluginParameters_EmptyParameters_ShouldReturnSuccess()
{
// Arrange
var parameters = new Dictionary<string, object>();
// Act
var result = _validator.ValidatePluginParameters(parameters);
// Assert
Assert.IsTrue(result.IsValid);
}
[TestMethod]
public void ValidatePluginParameters_ValidParameters_ShouldReturnSuccess()
{
// Arrange
var parameters = new Dictionary<string, object>
{
["validParam"] = "validValue",
["numberParam"] = 42,
["boolParam"] = true
};
// Act
var result = _validator.ValidatePluginParameters(parameters);
// Assert
Assert.IsTrue(result.IsValid);
}
[TestMethod]
public void ValidatePluginParameters_InvalidParameterName_ShouldReturnFailure()
{
// Arrange
var parameters = new Dictionary<string, object>
{
["invalid-param-name!"] = "value"
};
// Act
var result = _validator.ValidatePluginParameters(parameters);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.IsTrue(result.ErrorMessage!.Contains("Invalid parameter name"));
}
[TestMethod]
public void ValidatePluginParameters_ParameterValueTooLong_ShouldReturnFailure()
{
// Arrange
var longValue = new string('x', 10001); // Exceeds 10000 character limit
var parameters = new Dictionary<string, object>
{
["validParam"] = longValue
};
// Act
var result = _validator.ValidatePluginParameters(parameters);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.IsTrue(result.ErrorMessage!.Contains("exceeds maximum length"));
}
[TestMethod]
public void ValidatePluginParameters_DangerousStringValue_ShouldReturnFailure()
{
// Arrange
var parameters = new Dictionary<string, object>
{
["param"] = "<script>alert('xss')</script>"
};
// Act
var result = _validator.ValidatePluginParameters(parameters);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.IsTrue(result.ErrorMessage!.Contains("dangerous content"));
}
[TestMethod]
public void ValidateConfiguration_ValidConfiguration_ShouldReturnSuccess()
{
// Arrange
var config = new AnalysisConfiguration
{
DefaultTimeout = TimeSpan.FromMinutes(5),
MaxConcurrentAnalyses = 4,
CacheExpirationTime = TimeSpan.FromHours(1),
AllowDynamicPluginLoading = false
};
// Act
var result = _validator.ValidateConfiguration(config);
// Assert
Assert.IsTrue(result.IsValid);
}
[TestMethod]
public void ValidateConfiguration_NullConfiguration_ShouldReturnFailure()
{
// Act
var result = _validator.ValidateConfiguration(null);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.AreEqual("Configuration cannot be null", result.ErrorMessage);
}
[TestMethod]
public void ValidateConfiguration_InvalidTimeout_ShouldReturnFailure()
{
// Arrange
var config = new AnalysisConfiguration
{
DefaultTimeout = TimeSpan.FromHours(2) // Too long
};
// Act
var result = _validator.ValidateConfiguration(config);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.IsTrue(result.ErrorMessage!.Contains("timeout"));
}
[TestMethod]
public void ValidateConfiguration_InvalidConcurrency_ShouldReturnFailure()
{
// Arrange
var config = new AnalysisConfiguration
{
MaxConcurrentAnalyses = Environment.ProcessorCount * 10 // Too high
};
// Act
var result = _validator.ValidateConfiguration(config);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.IsTrue(result.ErrorMessage!.Contains("concurrent analyses"));
}
[TestMethod]
public void ValidateConfiguration_DynamicLoadingWithoutTrustedDirectory_ShouldReturnFailure()
{
// Arrange
var config = new AnalysisConfiguration
{
AllowDynamicPluginLoading = true,
TrustedPluginDirectory = string.Empty
};
// Act
var result = _validator.ValidateConfiguration(config);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.IsTrue(result.ErrorMessage!.Contains("Trusted plugin directory"));
}
[TestMethod]
public void SanitizeInput_NullInput_ShouldReturnEmpty()
{
// Act
var result = _validator.SanitizeInput(null);
// Assert
Assert.AreEqual(string.Empty, result);
}
[TestMethod]
public void SanitizeInput_EmptyInput_ShouldReturnEmpty()
{
// Act
var result = _validator.SanitizeInput(string.Empty);
// Assert
Assert.AreEqual(string.Empty, result);
}
[TestMethod]
public void SanitizeInput_DangerousCharacters_ShouldEscapeThem()
{
// Arrange
var input = "<script>alert('xss')</script>";
// Act
var result = _validator.SanitizeInput(input);
// Assert
Assert.IsFalse(result.Contains("<script>"));
// Due to the order of replacements, &lt; becomes &amp;lt; because & is replaced after < and >
Assert.IsTrue(result.Contains("&amp;lt;"));
Assert.IsTrue(result.Contains("&amp;gt;"));
Assert.IsTrue(result.Contains("&#x27;"));
}
[TestMethod]
public void SanitizeInput_ControlCharacters_ShouldRemoveThem()
{
// Arrange
var input = "test\0\x01\x02string";
// Act
var result = _validator.SanitizeInput(input);
// Assert
Assert.AreEqual("teststring", result);
}
[TestMethod]
public void ValidateDirectoryPath_NonExistentDirectory_ShouldReturnFailure()
{
// Arrange
var nonExistentPath = "/non/existent/directory";
// Act
var result = _validator.ValidateDirectoryPath(nonExistentPath);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsNotNull(result.ErrorMessage);
Assert.IsTrue(result.ErrorMessage!.Contains("does not exist"));
}
[TestMethod]
public void ValidationResult_Success_ShouldHaveCorrectProperties()
{
// Act
var result = ValidationResult.Success("sanitized");
// Assert
Assert.IsTrue(result.IsValid);
Assert.IsNull(result.ErrorMessage);
Assert.AreEqual("sanitized", result.SanitizedValue);
}
[TestMethod]
public void ValidationResult_Failure_ShouldHaveCorrectProperties()
{
// Arrange
var errorMessage = "Test error";
// Act
var result = ValidationResult.Failure(errorMessage);
// Assert
Assert.IsFalse(result.IsValid);
Assert.AreEqual(errorMessage, result.ErrorMessage);
Assert.IsNull(result.SanitizedValue);
}
}
}