Changed all icons of AI Studio to Lucide (#1187)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-11-11 14:20:49 +01:00
1 parent 9a676101f7
commit 7ef26cd5c8
352 files changed
+6261 -1620

No files matched your search

@@ -0,0 +1,115 @@
using AIStudio.Tests.Models.Generation;
using Microsoft.CodeAnalysis;
using SourceCodeRules.UsageAnalyzers;
namespace AIStudio.Tests.Analyzers;
/// <summary>
/// Checks that the app takes its icons only from the catalog AppIcons.
/// </summary>
/// <remarks>
/// AppIcons names every icon after its meaning and decides there which Lucide icon stands for it. MWAIS0017 refuses
/// an icon of LucideIcons or of MudBlazor anywhere else while compiling, so no component picks an icon on its own.
/// </remarks>
[TestFixture]
public sealed class IconCatalogAnalyzerTests
{
[TestCase("public string Icon => LucideIcons.HOUSE;", "AIStudio.Tools.LucideIcons.HOUSE", TestName = "A Lucide icon")]
[TestCase("public string Icon => MudBlazor.Icons.Material.Filled.Home;", "MudBlazor.Icons.Material.Filled.Home", TestName = "A Material icon of MudBlazor")]
[TestCase("public string Icon => Icons.Material.Outlined.Home;", "MudBlazor.Icons.Material.Outlined.Home", TestName = "A Material icon of MudBlazor through its using")]
[TestCase("public string Icon => Icons.Custom.Brands.GitHub;", "MudBlazor.Icons.Custom.Brands.GitHub", TestName = "A brand logo of MudBlazor")]
[TestCase("public int Rank(string icon) => icon switch { LucideIcons.HOUSE => 1, _ => 0 };", "AIStudio.Tools.LucideIcons.HOUSE", TestName = "A Lucide icon in a pattern")]
[TestCase("private const string ICON = LucideIcons.HOUSE;", "AIStudio.Tools.LucideIcons.HOUSE", TestName = "A Lucide icon in a constant of another class")]
public async Task AnIconOutsideTheCatalogIsRefused(string member, string icon)
{
var reported = await AnalyzeAsync(member);
using (Assert.EnterMultipleScope())
{
Assert.That(reported, Has.Count.EqualTo(1));
Assert.That(reported.FirstOrDefault()?.Id, Is.EqualTo("MWAIS0017"));
Assert.That(reported.FirstOrDefault()?.GetMessage(), Does.Contain($"'{icon}'"));
}
}
[TestCase("public string Icon => AppIcons.DELETE;", TestName = "A constant of the catalog")]
[TestCase("public bool Find(out string icon) => LucideIconRegistry.TryGet(\"house\", out icon);", TestName = "The registry plugins name their icons with")]
[TestCase("public string Icon => \"lucide/x\";", TestName = "A plain string")]
public async Task EverythingElseIsAllowed(string member)
{
var reported = await AnalyzeAsync(member);
Assert.That(reported, Is.Empty);
}
[Test]
public async Task TheCatalogMayUseBothIconSets()
{
//
// The snippet declares its own AppIcons where the analyzer looks for it. It takes the place of the one
// of the app, which the compilation references as well:
//
const string SOURCE =
"""
namespace AIStudio.Tools;
public static class AppIcons
{
public const string HOME = LucideIcons.HOUSE;
public const string GITHUB = MudBlazor.Icons.Custom.Brands.GitHub;
public static class Steps
{
public const string FIRST = MudBlazor.Icons.Material.Filled.LooksOne;
}
}
""";
var reported = await CompilationHarness.AnalyzeAsync(SOURCE, new IconCatalogAnalyzer());
Assert.That(reported, Is.Empty);
}
[Test]
public async Task GeneratedCodeIsCheckedAsWell()
{
//
// The Razor compiler turns the markup of a component into generated code, where most icons are set:
//
const string SOURCE =
"""
// <auto-generated/>
namespace Sample;
public sealed class Component
{
public string Icon => AIStudio.Tools.LucideIcons.HOUSE;
}
""";
var reported = await CompilationHarness.AnalyzeAsync(SOURCE, new IconCatalogAnalyzer());
Assert.That(reported, Has.Count.EqualTo(1));
}
private static async Task<IReadOnlyList<Diagnostic>> AnalyzeAsync(string member)
{
var source =
$$"""
using AIStudio.Tools;
using MudBlazor;
namespace Sample;
public sealed class Component
{
{{member}}
}
""";
return await CompilationHarness.AnalyzeAsync(source, new IconCatalogAnalyzer());
}
}