396 lines
12 KiB
C#
Executable File
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, < becomes &lt; because & is replaced after < and >
|
|
Assert.IsTrue(result.Contains("&lt;"));
|
|
Assert.IsTrue(result.Contains("&gt;"));
|
|
Assert.IsTrue(result.Contains("'"));
|
|
}
|
|
|
|
[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);
|
|
}
|
|
}
|
|
} |