using Common.ExpandFun;
namespace Common.Test;
///
/// StringExpand 字符串扩展方法测试
/// 展示字符串相关的实用扩展方法
///
[TestClass]
public class StringExpandTests
{
#region IsValidUrl 测试
///
/// 测试:有效的 HTTP URL
///
[TestMethod]
public void IsValidUrl_ValidHttpUrl_ReturnsTrue()
{
// Arrange
var url = "http://www.example.com";
// Act
var isValid = url.IsValidUrl();
// Assert
Assert.IsTrue(isValid);
}
///
/// 测试:有效的 HTTPS URL
///
[TestMethod]
public void IsValidUrl_ValidHttpsUrl_ReturnsTrue()
{
// Arrange
var url = "https://www.example.com/path/to/resource?query=value";
// Act
var isValid = url.IsValidUrl();
// Assert
Assert.IsTrue(isValid);
}
///
/// 测试:有效的 FTP URL
///
[TestMethod]
public void IsValidUrl_ValidFtpUrl_ReturnsTrue()
{
// Arrange
var url = "ftp://ftp.example.com/file.txt";
// Act
var isValid = url.IsValidUrl();
// Assert
Assert.IsTrue(isValid);
}
///
/// 测试:无效的 URL
///
[TestMethod]
public void IsValidUrl_InvalidUrl_ReturnsFalse()
{
// Arrange
var invalidUrls = new[]
{
"not a url",
"example.com", // 缺少协议
"http://", // 不完整
"", // 空字符串
"://invalid" // 无效格式
};
// Act & Assert
foreach (var url in invalidUrls) Assert.IsFalse(url.IsValidUrl(), $"'{url}' should be invalid");
}
#endregion
#region ToInt 和 TryToInt 测试
///
/// 测试:有效的整数字符串转换
///
[TestMethod]
public void ToInt_ValidIntegerString_ReturnsInteger()
{
// Arrange & Act & Assert
Assert.AreEqual(123, "123".ToInt());
Assert.AreEqual(-456, "-456".ToInt());
Assert.AreEqual(0, "0".ToInt());
}
///
/// 测试:无效字符串返回默认值
///
[TestMethod]
public void ToInt_InvalidString_ReturnsDefault()
{
// Arrange & Act & Assert
Assert.AreEqual(0, "invalid".ToInt());
Assert.AreEqual(0, "12.34".ToInt());
Assert.AreEqual(999, "abc".ToInt(999));
}
///
/// 测试:空字符串和 null 返回默认值
///
[TestMethod]
public void ToInt_NullOrEmpty_ReturnsDefault()
{
// Arrange & Act & Assert
Assert.AreEqual(0, ((string)null!).ToInt());
Assert.AreEqual(0, "".ToInt());
Assert.AreEqual(0, " ".ToInt());
Assert.AreEqual(100, ((string)null!).ToInt(100));
}
///
/// 测试:TryToInt 成功转换
///
[TestMethod]
public void TryToInt_ValidString_ReturnsValue()
{
// Arrange & Act
var result = "42".TryToInt();
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(42, result.Value);
}
///
/// 测试:TryToInt 转换失败返回 null
///
[TestMethod]
public void TryToInt_InvalidString_ReturnsNull()
{
// Arrange & Act
var result1 = "invalid".TryToInt();
var result2 = ((string)null!).TryToInt();
var result3 = "".TryToInt();
// Assert
Assert.IsNull(result1);
Assert.IsNull(result2);
Assert.IsNull(result3);
}
///
/// 测试:整数溢出
///
[TestMethod]
public void ToInt_Overflow_ReturnsDefault()
{
// Arrange: int.MaxValue + 1
var overflowString = "2147483648";
// Act
var result = overflowString.ToInt(-1);
// Assert: 溢出应该返回默认值
Assert.AreEqual(-1, result);
}
#endregion
#region ToDouble 和 TryToDouble 测试
///
/// 测试:有效的浮点数字符串转换
///
[TestMethod]
public void ToDouble_ValidDoubleString_ReturnsDouble()
{
// Arrange & Act & Assert
Assert.AreEqual(123.456, "123.456".ToDouble());
Assert.AreEqual(-789.12, "-789.12".ToDouble());
Assert.AreEqual(0.0, "0".ToDouble());
Assert.AreEqual(3.14, "3.14".ToDouble());
}
///
/// 测试:整数字符串也能转换为 double
///
[TestMethod]
public void ToDouble_IntegerString_ReturnsDouble()
{
// Arrange & Act
var result = "42".ToDouble();
// Assert
Assert.AreEqual(42.0, result);
}
///
/// 测试:无效字符串返回默认值
///
[TestMethod]
public void ToDouble_InvalidString_ReturnsDefault()
{
// Arrange & Act & Assert
Assert.AreEqual(0.0, "invalid".ToDouble());
Assert.AreEqual(999.9, "abc".ToDouble(999.9));
}
///
/// 测试:空字符串和 null 返回默认值
///
[TestMethod]
public void ToDouble_NullOrEmpty_ReturnsDefault()
{
// Arrange & Act & Assert
Assert.AreEqual(0.0, ((string)null!).ToDouble());
Assert.AreEqual(0.0, "".ToDouble());
Assert.AreEqual(0.0, " ".ToDouble());
Assert.AreEqual(100.5, ((string)null!).ToDouble(100.5));
}
///
/// 测试:TryToDouble 成功转换
///
[TestMethod]
public void TryToDouble_ValidString_ReturnsValue()
{
// Arrange & Act
var result = "3.14159".TryToDouble();
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(3.14159, result.Value);
}
///
/// 测试:TryToDouble 转换失败返回 null
///
[TestMethod]
public void TryToDouble_InvalidString_ReturnsNull()
{
// Arrange & Act
var result1 = "invalid".TryToDouble();
var result2 = ((string)null!).TryToDouble();
var result3 = "".TryToDouble();
// Assert
Assert.IsNull(result1);
Assert.IsNull(result2);
Assert.IsNull(result3);
}
///
/// 测试:科学计数法
///
[TestMethod]
public void ToDouble_ScientificNotation_ConvertsCorrectly()
{
// Arrange & Act & Assert
Assert.AreEqual(1.23e5, "1.23e5".ToDouble());
Assert.AreEqual(1.23e-5, "1.23e-5".ToDouble());
}
#endregion
#region 实际应用场景测试
///
/// 场景测试:解析配置文件值
///
[TestMethod]
public void Scenario_ParseConfigurationValues()
{
// Arrange: 模拟从配置文件读取的字符串值
var config = new Dictionary
{
["Port"] = "8080",
["Timeout"] = "30",
["MaxRetries"] = "invalid", // 无效值
["Price"] = "99.99",
["Discount"] = "0.15"
};
// Act: 解析配置值
var port = config["Port"].ToInt(80); // 默认 80
var timeout = config["Timeout"].ToInt(60); // 默认 60
var maxRetries = config["MaxRetries"].ToInt(3); // 无效值,使用默认 3
var price = config["Price"].ToDouble(0.0);
var discount = config["Discount"].ToDouble(0.0);
// Assert
Assert.AreEqual(8080, port);
Assert.AreEqual(30, timeout);
Assert.AreEqual(3, maxRetries); // 使用了默认值
Assert.AreEqual(99.99, price);
Assert.AreEqual(0.15, discount);
}
///
/// 场景测试:验证用户输入的 URL
///
[TestMethod]
public void Scenario_ValidateUserInputUrl()
{
// Arrange: 模拟用户输入
var userInputs = new[]
{
"https://www.google.com",
"not a url",
"ftp://files.example.com",
"example.com"
};
// Act: 验证 URL
var validUrls = userInputs.Where(url => url.IsValidUrl()).ToList();
// Assert
Assert.AreEqual(2, validUrls.Count);
Assert.IsTrue(validUrls.Contains("https://www.google.com"));
Assert.IsTrue(validUrls.Contains("ftp://files.example.com"));
}
///
/// 场景测试:安全地解析用户输入的数字
///
[TestMethod]
public void Scenario_SafelyParseUserInput()
{
// Arrange: 模拟用户输入(可能无效)
var userAgeInput = "25";
var userWeightInput = "invalid";
string? userHeightInput = null;
// Act: 安全解析
var age = userAgeInput.TryToInt();
var weight = userWeightInput.TryToDouble();
var height = userHeightInput.TryToDouble();
// Assert
Assert.IsNotNull(age);
Assert.AreEqual(25, age.Value);
Assert.IsNull(weight); // 无效输入
Assert.IsNull(height); // null 输入
// 使用默认值的版本
var ageWithDefault = userAgeInput.ToInt(18);
var weightWithDefault = userWeightInput.ToDouble(70.0);
var heightWithDefault = userHeightInput.ToDouble(170.0);
Assert.AreEqual(25, ageWithDefault);
Assert.AreEqual(70.0, weightWithDefault); // 使用默认值
Assert.AreEqual(170.0, heightWithDefault); // 使用默认值
}
///
/// 场景测试:处理来自外部 API 的数据
///
[TestMethod]
public void Scenario_ParseApiResponse()
{
// Arrange: 模拟 API 返回的字符串数据
var apiData = new
{
UserId = "12345",
Score = "95.5",
ProfileUrl = "https://api.example.com/users/12345",
InvalidUrl = "not-a-url",
MissingValue = (string)null!
};
// Act: 解析数据
var userId = apiData.UserId.ToInt();
var score = apiData.Score.ToDouble();
var isValidProfileUrl = apiData.ProfileUrl.IsValidUrl();
var isValidInvalidUrl = apiData.InvalidUrl.IsValidUrl();
var missingValue = apiData.MissingValue.ToInt(-1);
// Assert
Assert.AreEqual(12345, userId);
Assert.AreEqual(95.5, score);
Assert.IsTrue(isValidProfileUrl);
Assert.IsFalse(isValidInvalidUrl);
Assert.AreEqual(-1, missingValue);
}
#endregion
}