File: Projects\DefaultLanguageDiscoveryTests.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 Microsoft.AspNetCore.InternalTesting;
using Aspire.Cli.Configuration;
using Aspire.Cli.Projects;
 
namespace Aspire.Cli.Tests.Projects;
 
public class DefaultLanguageDiscoveryTests
{
    [Fact]
    public async Task GetAvailableLanguagesAsync_ReturnsCSharpLanguage()
    {
        var discovery = new DefaultLanguageDiscovery(new TestFeatures());
 
        var languages = await discovery.GetAvailableLanguagesAsync().DefaultTimeout();
 
        var csharp = languages.FirstOrDefault(l => l.LanguageId.Value == KnownLanguageId.CSharp);
        Assert.NotNull(csharp);
        Assert.Equal(KnownLanguageId.CSharpDisplayName, csharp.DisplayName);
    }
 
    [Theory]
    [InlineData("*.csproj")]
    [InlineData("*.fsproj")]
    [InlineData("*.vbproj")]
    [InlineData("apphost.cs")]
    public async Task GetAvailableLanguagesAsync_CSharpLanguageHasExpectedDetectionPatterns(string expectedPattern)
    {
        var discovery = new DefaultLanguageDiscovery(new TestFeatures());
 
        var languages = await discovery.GetAvailableLanguagesAsync().DefaultTimeout();
 
        var csharp = languages.First(l => l.LanguageId.Value == KnownLanguageId.CSharp);
        Assert.Contains(expectedPattern, csharp.DetectionPatterns);
    }
 
    [Fact]
    public async Task GetAvailableLanguagesAsync_ReturnsTypeScriptLanguage()
    {
        var discovery = new DefaultLanguageDiscovery(new TestFeatures());
 
        var languages = await discovery.GetAvailableLanguagesAsync().DefaultTimeout();
 
        var typescript = languages.FirstOrDefault(l => l.LanguageId.Value == "typescript/nodejs");
        Assert.NotNull(typescript);
        Assert.Equal("TypeScript (Node.js)", typescript.DisplayName);
        Assert.Contains("apphost.ts", typescript.DetectionPatterns);
    }
 
    [Fact]
    public async Task GetAvailableLanguagesAsync_ReturnsPythonLanguage()
    {
        var features = new TestFeatures();
        features.SetFeature(KnownFeatures.ExperimentalPolyglotPython, true);
        var discovery = new DefaultLanguageDiscovery(features);
 
        var languages = await discovery.GetAvailableLanguagesAsync().DefaultTimeout();
 
        var python = languages.FirstOrDefault(l => l.LanguageId.Value == KnownLanguageId.Python);
        Assert.NotNull(python);
        Assert.Equal(KnownLanguageId.PythonDisplayName, python.DisplayName);
        Assert.Contains("apphost.py", python.DetectionPatterns);
    }
 
    [Fact]
    public async Task GetAvailableLanguagesAsync_ExcludesExperimentalLanguagesByDefault()
    {
        var discovery = new DefaultLanguageDiscovery(new TestFeatures());
 
        var languages = (await discovery.GetAvailableLanguagesAsync().DefaultTimeout()).ToList();
 
        Assert.Null(languages.FirstOrDefault(l => l.LanguageId.Value == KnownLanguageId.Python));
        Assert.Null(languages.FirstOrDefault(l => l.LanguageId.Value == KnownLanguageId.Go));
        Assert.Null(languages.FirstOrDefault(l => l.LanguageId.Value == KnownLanguageId.Java));
        Assert.Null(languages.FirstOrDefault(l => l.LanguageId.Value == KnownLanguageId.Rust));
    }
 
    [Theory]
    [InlineData(KnownLanguageId.Python, "experimentalPolyglot:python")]
    [InlineData(KnownLanguageId.Go, "experimentalPolyglot:go")]
    [InlineData(KnownLanguageId.Java, "experimentalPolyglot:java")]
    [InlineData(KnownLanguageId.Rust, "experimentalPolyglot:rust")]
    public async Task GetAvailableLanguagesAsync_IncludesExperimentalLanguageWhenFlagEnabled(string languageId, string featureFlag)
    {
        var features = new TestFeatures();
        features.SetFeature(featureFlag, true);
        var discovery = new DefaultLanguageDiscovery(features);
 
        var languages = (await discovery.GetAvailableLanguagesAsync().DefaultTimeout()).ToList();
 
        Assert.NotNull(languages.FirstOrDefault(l => l.LanguageId.Value == languageId));
    }
 
    [Theory]
    [InlineData("test.csproj", KnownLanguageId.CSharp)]
    [InlineData("Test.csproj", KnownLanguageId.CSharp)]
    [InlineData("test.fsproj", KnownLanguageId.CSharp)]
    [InlineData("test.vbproj", KnownLanguageId.CSharp)]
    [InlineData("apphost.cs", KnownLanguageId.CSharp)]
    [InlineData("AppHost.cs", KnownLanguageId.CSharp)]
    [InlineData("APPHOST.CS", KnownLanguageId.CSharp)]
    [InlineData("apphost.ts", "typescript/nodejs")]
    [InlineData("AppHost.ts", "typescript/nodejs")]
    public void GetLanguageByFile_ReturnsCorrectLanguage(string fileName, string expectedLanguageId)
    {
        var discovery = new DefaultLanguageDiscovery(new TestFeatures());
        var file = new FileInfo(Path.Combine(Path.GetTempPath(), fileName));
 
        var language = discovery.GetLanguageByFile(file);
 
        Assert.NotNull(language);
        Assert.Equal(expectedLanguageId, language.LanguageId.Value);
    }
 
    [Theory]
    [InlineData("test.txt")]
    [InlineData("program.cs")]
    [InlineData("random.js")]
    public void GetLanguageByFile_ReturnsNullForUnknownFiles(string fileName)
    {
        var discovery = new DefaultLanguageDiscovery(new TestFeatures());
        var file = new FileInfo(Path.Combine(Path.GetTempPath(), fileName));
 
        var language = discovery.GetLanguageByFile(file);
 
        Assert.Null(language);
    }
 
    [Fact]
    public void GetLanguageByFile_ReturnsNullForExperimentalLanguageWhenFlagDisabled()
    {
        var discovery = new DefaultLanguageDiscovery(new TestFeatures());
        var file = new FileInfo(Path.Combine(Path.GetTempPath(), "apphost.go"));
 
        var language = discovery.GetLanguageByFile(file);
 
        Assert.Null(language);
    }
 
    [Fact]
    public void GetLanguageByFile_ReturnsExperimentalLanguageWhenFlagEnabled()
    {
        var features = new TestFeatures();
        features.SetFeature(KnownFeatures.ExperimentalPolyglotGo, true);
        var discovery = new DefaultLanguageDiscovery(features);
        var file = new FileInfo(Path.Combine(Path.GetTempPath(), "apphost.go"));
 
        var language = discovery.GetLanguageByFile(file);
 
        Assert.NotNull(language);
        Assert.Equal(KnownLanguageId.Go, language.LanguageId.Value);
    }
 
    [Theory]
    [InlineData(KnownLanguageId.CSharp)]
    [InlineData("typescript/nodejs")]
    public void GetLanguageById_ReturnsCorrectLanguage(string languageId)
    {
        var discovery = new DefaultLanguageDiscovery(new TestFeatures());
 
        var language = discovery.GetLanguageById(new LanguageId(languageId));
 
        Assert.NotNull(language);
        Assert.Equal(languageId, language.LanguageId.Value);
    }
 
    [Fact]
    public void GetLanguageById_ReturnsNullForUnknownLanguage()
    {
        var discovery = new DefaultLanguageDiscovery(new TestFeatures());
 
        var language = discovery.GetLanguageById(new LanguageId("unknown"));
 
        Assert.Null(language);
    }
 
    [Fact]
    public void GetLanguageById_ReturnsNullForExperimentalLanguageWhenFlagDisabled()
    {
        var discovery = new DefaultLanguageDiscovery(new TestFeatures());
 
        var language = discovery.GetLanguageById(new LanguageId(KnownLanguageId.Rust));
 
        Assert.Null(language);
    }
 
    [Fact]
    public void GetLanguageById_ReturnsExperimentalLanguageWhenFlagEnabled()
    {
        var features = new TestFeatures();
        features.SetFeature(KnownFeatures.ExperimentalPolyglotRust, true);
        var discovery = new DefaultLanguageDiscovery(features);
 
        var language = discovery.GetLanguageById(new LanguageId(KnownLanguageId.Rust));
 
        Assert.NotNull(language);
        Assert.Equal(KnownLanguageId.Rust, language.LanguageId.Value);
    }
 
    private sealed class TestFeatures : IFeatures
    {
        private readonly Dictionary<string, bool> _features = new();
 
        public TestFeatures SetFeature(string featureName, bool value)
        {
            _features[featureName] = value;
            return this;
        }
 
        public bool IsFeatureEnabled(string featureName, bool defaultValue = false)
        {
            return _features.TryGetValue(featureName, out var value) ? value : defaultValue;
        }
    }
}