File: Commands\ProjectNameValidatorTests.cs
Web Access
Project: src\tests\Aspire.Cli.Tests\Aspire.Cli.Tests.csproj (Aspire.Cli.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Aspire.Cli.Commands;
 
namespace Aspire.Cli.Tests.Commands;
 
public class ProjectNameValidatorTests
{
    [Theory]
    [InlineData("项目1", true)]  // Chinese
    [InlineData("Проект1", true)]  // Cyrillic
    [InlineData("プロジェクト1", true)]  // Japanese
    [InlineData("مشروع1", true)]  // Arabic
    [InlineData("Project_1", true)]  // Latin with underscore
    [InlineData("Project-1", true)]  // Latin with dash
    [InlineData("Project.1", true)]  // Latin with dot
    [InlineData("MyApp", true)]  // Simple ASCII
    [InlineData("A", true)]  // Single character
    [InlineData("1", true)]  // Single number
    [InlineData("プ", true)]  // Single Unicode character
    [InlineData("Test123", true)]  // Mixed letters and numbers
    [InlineData("My_Cool-Project.v2", true)]  // Complex valid name
    [InlineData("Project:1", true)]  // Colon (now allowed)
    [InlineData("Project*1", true)]  // Asterisk (now allowed)
    [InlineData("Project?1", true)]  // Question mark (now allowed)
    [InlineData("Project\"1", true)]  // Quote (now allowed)
    [InlineData("Project<1", true)]  // Less than (now allowed)
    [InlineData("Project>1", true)]  // Greater than (now allowed)
    [InlineData("Project|1", true)]  // Pipe (now allowed)
    [InlineData("Project ", true)]  // Ends with space (now allowed)
    [InlineData(" Project", true)]  // Starts with space (now allowed)
    [InlineData("Pro ject", true)]  // Space in middle (now allowed)
    [InlineData("-Project", true)]  // Starts with dash (now allowed)
    [InlineData("Project-", true)]  // Ends with dash (now allowed)
    [InlineData(".Project", true)]  // Starts with dot (now allowed)
    [InlineData("Project.", true)]  // Ends with dot (now allowed)
    [InlineData("_Project", true)]  // Starts with underscore (now allowed)
    [InlineData("Project_", true)]  // Ends with underscore (now allowed)
    public void IsProjectNameValid_ValidNames_ReturnsTrue(string projectName, bool expected)
    {
        // Act
        var result = ProjectNameValidator.IsProjectNameValid(projectName);
 
        // Assert
        Assert.Equal(expected, result);
    }
 
    [Theory]
    [InlineData("Project/1", false)]  // Forward slash (path separator)
    [InlineData("Project\\1", false)]  // Backslash (path separator)
    [InlineData("", false)]  // Empty string
    [InlineData(" ", false)]  // Space only
    [InlineData("   ", false)]  // Multiple spaces only
    [InlineData("\t", false)]  // Tab only
    [InlineData("\n", false)]  // Newline only
    public void IsProjectNameValid_InvalidNames_ReturnsFalse(string projectName, bool expected)
    {
        // Act
        var result = ProjectNameValidator.IsProjectNameValid(projectName);
 
        // Assert
        Assert.Equal(expected, result);
    }
 
    [Fact]
    public void IsProjectNameValid_MaxLength254_ReturnsTrue()
    {
        // Arrange
        var projectName = new string('A', 254);
 
        // Act
        var result = ProjectNameValidator.IsProjectNameValid(projectName);
 
        // Assert
        Assert.True(result);
    }
 
    [Fact]
    public void IsProjectNameValid_Length255_ReturnsFalse()
    {
        // Arrange
        var projectName = new string('A', 255);
 
        // Act
        var result = ProjectNameValidator.IsProjectNameValid(projectName);
 
        // Assert
        Assert.False(result);
    }
 
    [Theory]
    [InlineData("项目测试名称很长的中文项目名称")]  // Long Chinese name
    [InlineData("очень_длинное_русское_имя_проекта")]  // Long Russian name
    [InlineData("とても長い日本語のプロジェクト名")]  // Long Japanese name
    [InlineData("اسم_مشروع_طويل_جدا_بالعربية")]  // Long Arabic name
    public void IsProjectNameValid_LongUnicodeNames_ReturnsTrue(string projectName)
    {
        // Act
        var result = ProjectNameValidator.IsProjectNameValid(projectName);
 
        // Assert
        Assert.True(result, $"Unicode project name should be valid: {projectName}");
    }
 
    [Theory]
    [InlineData("Ελληνικά", true)]  // Greek
    [InlineData("עברית", true)]  // Hebrew
    [InlineData("हिन्दी", true)]  // Hindi
    [InlineData("ไทย", true)]  // Thai
    [InlineData("한국어", true)]  // Korean
    [InlineData("Türkçe", true)]  // Turkish
    [InlineData("Português", true)]  // Portuguese with accent
    [InlineData("Français", true)]  // French with accent
    [InlineData("Español", true)]  // Spanish with accent
    [InlineData("Deutsch", true)]  // German
    public void IsProjectNameValid_VariousLanguages_ReturnsTrue(string projectName, bool expected)
    {
        // Act
        var result = ProjectNameValidator.IsProjectNameValid(projectName);
 
        // Assert
        Assert.Equal(expected, result);
    }
 
    [Theory]
    [InlineData("Test123-Project_Name.v2")]  // Complex valid with all allowed characters
    [InlineData("A1-B2_C3.D4")]  // Mixed with separators
    [InlineData("项目-测试_版本.1")]  // Unicode with separators
    public void IsProjectNameValid_ComplexValidNames_ReturnsTrue(string projectName)
    {
        // Act
        var result = ProjectNameValidator.IsProjectNameValid(projectName);
 
        // Assert
        Assert.True(result, $"Complex valid project name should be valid: {projectName}");
    }
 
    [Theory]
    [InlineData("Test..Name")]  // Double dot
    [InlineData("Test--Name")]  // Double dash
    [InlineData("Test__Name")]  // Double underscore
    public void IsProjectNameValid_ConsecutiveSpecialChars_ReturnsTrue(string projectName)
    {
        // These should be valid as the spec doesn't prohibit consecutive allowed characters
        // Act
        var result = ProjectNameValidator.IsProjectNameValid(projectName);
 
        // Assert
        Assert.True(result, $"Consecutive allowed characters should be valid: {projectName}");
    }
 
    [Theory]
    [InlineData("My/Project")]  // Forward slash in middle
    [InlineData("/MyProject")]  // Forward slash at start
    [InlineData("MyProject/")]  // Forward slash at end
    [InlineData("My\\Project")]  // Backslash in middle
    [InlineData("\\MyProject")]  // Backslash at start
    [InlineData("MyProject\\")]  // Backslash at end
    [InlineData("My/Project/Name")]  // Multiple forward slashes
    [InlineData("My\\Project\\Name")]  // Multiple backslashes
    [InlineData("My/Project\\Name")]  // Mixed path separators
    public void IsProjectNameValid_PathSeparators_ReturnsFalse(string projectName)
    {
        // Act
        var result = ProjectNameValidator.IsProjectNameValid(projectName);
 
        // Assert
        Assert.False(result, $"Project name with path separators should be invalid: {projectName}");
    }
}