using AIStudio.Tools; using AIStudio.Tools.CodeHighlighting; namespace AIStudio.Tests.Tools.CodeHighlighting; /// /// Checks which language AI Studio recognizes in a code block which names none. /// [TestFixture] public sealed class CodeLanguageDetectorTests { /// /// The languages MudBlazor.Markdown highlights itself, as a model writes them behind the fence. /// private static readonly string[] LIBRARY_LANGUAGES = ["csharp", "go", "kotlin", "rust", "json", "xml", "html", "yaml"]; [TestCase("import os\n\ndef greet(name):\n if name is None:\n return \"nobody\"\n print(f\"Hello {name}\")", "python")] [TestCase("#!/bin/bash\nfor file in *.txt; do\n echo \"$file\"\ndone", "bash")] [TestCase("npm install express", "bash", Description = "A single command is enough when only a shell runs it.")] [TestCase("Get-ChildItem -Path . | ForEach-Object {\n Write-Host $_.Name\n}", "powershell")] [TestCase("local function greet(name)\n if name ~= nil then\n print(\"Hello \" .. name)\n end\nend", "lua")] [TestCase("const express = require('express');\nconst app = express();\napp.get('/', (req, res) => res.send('Hi'));", "javascript")] [TestCase("interface User {\n name: string;\n age: number;\n}\nconst user: User = { name: 'Ada', age: 36 };", "typescript")] [TestCase("#include \n\nint main(void) {\n printf(\"Hello\\n\");\n return 0;\n}", "c")] [TestCase("#include \n\nint main() {\n std::cout << \"Hello\" << std::endl;\n}", "cpp")] [TestCase("using System;\n\npublic class Greeter\n{\n public string Name { get; set; }\n public void Greet() => Console.WriteLine($\"Hello {Name}\");\n}", "csharp")] [TestCase("import java.util.List;\n\npublic class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}", "java")] [TestCase("data class User(val name: String)\n\nfun main() {\n val user = User(\"Ada\")\n println(user.name)\n}", "kotlin")] [TestCase("package main\n\nimport \"fmt\"\n\nfunc main() {\n msg := \"Hello\"\n fmt.Println(msg)\n}", "go")] [TestCase("use std::collections::HashMap;\n\nfn main() {\n let mut map = HashMap::new();\n println!(\"{:?}\", map);\n}", "rust")] [TestCase("SELECT name, COUNT(*) AS total\nFROM orders\nWHERE created_at > '2026-01-01'\nGROUP BY name\nORDER BY total DESC;", "sql")] [TestCase("select * from users;", "sql", Description = "SQL ignores the case of its keywords.")] [TestCase(".card {\n color: #333;\n margin: 0 auto;\n padding: 1rem;\n}", "css")] [TestCase("services:\n web:\n image: nginx\n ports:\n - \"80:80\"", "yaml")] [TestCase("{\"name\": \"Ada\", \"age\": 36}", "json")] [TestCase("
\n

Hello

\n
", "html")] [TestCase("\n", "xml")] public void TheCodeNamesItsLanguage(string code, string expected) { Assert.That(CodeLanguageDetector.Detect(code), Is.EqualTo(expected)); } [TestCase("Just some words in a block.", TestName = "Prose")] [TestCase("hello", TestName = "A single word")] [TestCase("x = 1", TestName = "A line many languages write alike")] [TestCase("let x = 5", TestName = "A line with a single weak hint")] [TestCase("{\"name\": \"Ada\",", TestName = "JSON a model has not finished yet")] [TestCase("", TestName = "Nothing")] [TestCase(" \n ", TestName = "Only space")] public void UnclearCodeStaysText(string code) { Assert.That(CodeLanguageDetector.Detect(code), Is.Null, "A file saved under a wrong extension is worse than a text file."); } [TestCase("text")] [TestCase("python")] [TestCase("foo")] public void TheLanguageBehindTheFenceWins(string fenceLanguage) { Assert.That(CodeLanguageDetector.FenceLanguageOf(fenceLanguage, "using System;\nConsole.WriteLine(\"Hi\");"), Is.EqualTo(fenceLanguage)); } [TestCase(null)] [TestCase("")] [TestCase(" ")] public void WithoutALanguageTheCodeDecides(string? fenceLanguage) { Assert.That(CodeLanguageDetector.FenceLanguageOf(fenceLanguage, "using System;\nConsole.WriteLine(\"Hi\");"), Is.EqualTo("csharp")); } /// /// A recognized language has to be one the export saves under its extension, and one which gets /// colors. Otherwise, the guess would help neither. /// [Test] public void EveryLanguageIsSavedAndHighlighted([ValueSource(nameof(FenceLanguages))] string fenceLanguage) { using (Assert.EnterMultipleScope()) { var isFormat = FileExportFormatExtensions.TryFromCodeFenceLanguage(fenceLanguage, out _); Assert.That(isFormat || SourceCodeLanguages.Aliases.Contains(fenceLanguage, StringComparer.OrdinalIgnoreCase), Is.True, "The export would save it as a text file."); Assert.That(CodeHighlighters.TryGetRules(fenceLanguage, out _) || LIBRARY_LANGUAGES.Contains(fenceLanguage), Is.True, "Nobody highlights it."); } } private static IEnumerable FenceLanguages() => CodeLanguageDetector.FenceLanguages; }