|
| 1 | +namespace OpenClaw.Tray.Tests; |
| 2 | + |
| 3 | +public sealed class BrandMarkContractTests |
| 4 | +{ |
| 5 | + private const string LobsterEmoji = "\ud83e\udd9e"; |
| 6 | + private const string RobotEmoji = "\ud83e\udd16"; |
| 7 | + private const string RedBotAssetName = "Square44x44Logo.targetsize-256_altform-unplated.png"; |
| 8 | + private static string RepoRoot => TestRepositoryPaths.GetRepositoryRoot(); |
| 9 | + |
| 10 | + private static string ReadTrayFile(params string[] pathParts) |
| 11 | + => File.ReadAllText(Path.Combine(new[] { RepoRoot, "src", "OpenClaw.Tray.WinUI" }.Concat(pathParts).ToArray())); |
| 12 | + |
| 13 | + [Fact] |
| 14 | + public void BrandMark_UsesSharedRedBotImageAsset() |
| 15 | + { |
| 16 | + var xaml = ReadTrayFile("Controls", "BrandMark.xaml"); |
| 17 | + var code = ReadTrayFile("Controls", "BrandMark.xaml.cs"); |
| 18 | + var assets = ReadTrayFile("Helpers", "BrandAssets.cs"); |
| 19 | + var redBotAssetPath = Path.Combine( |
| 20 | + RepoRoot, |
| 21 | + "src", |
| 22 | + "OpenClaw.Tray.WinUI", |
| 23 | + "Assets", |
| 24 | + RedBotAssetName); |
| 25 | + |
| 26 | + Assert.Contains("<Image", xaml); |
| 27 | + Assert.Contains("AutomationProperties.AccessibilityView=\"Raw\"", xaml); |
| 28 | + Assert.Contains("IsHitTestVisible=\"False\"", xaml); |
| 29 | + Assert.Contains("IsTabStop=\"False\"", xaml); |
| 30 | + Assert.Contains("BrandAssets.CreateRedBotMarkSource()", code); |
| 31 | + Assert.Contains(RedBotAssetName, assets); |
| 32 | + Assert.True(File.Exists(redBotAssetPath), $"BrandMark asset is missing: {redBotAssetPath}"); |
| 33 | + Assert.DoesNotContain("FontIcon", xaml); |
| 34 | + Assert.DoesNotContain($"Text=\"{LobsterEmoji}\"", xaml); |
| 35 | + } |
| 36 | + |
| 37 | + [Fact] |
| 38 | + public void KnownBrandSurfaces_UseBrandMark() |
| 39 | + { |
| 40 | + Assert.Contains("controls:BrandMark", ReadTrayFile("Windows", "HubWindow.xaml")); |
| 41 | + Assert.Contains("controls:BrandMark", ReadTrayFile("Pages", "AgentEventsPage.xaml")); |
| 42 | + |
| 43 | + var expectedCodeFiles = new[] |
| 44 | + { |
| 45 | + Path.Combine("Dialogs", "WelcomeDialog.cs"), |
| 46 | + Path.Combine("Dialogs", "PairingApprovalDialog.cs"), |
| 47 | + Path.Combine("Dialogs", "RecordingConsentDialog.cs"), |
| 48 | + }; |
| 49 | + |
| 50 | + foreach (var file in expectedCodeFiles) |
| 51 | + { |
| 52 | + Assert.Contains("new BrandMark", ReadTrayFile(file.Split(Path.DirectorySeparatorChar))); |
| 53 | + } |
| 54 | + } |
| 55 | + |
| 56 | + [Fact] |
| 57 | + public void TrayWinUiSources_DoNotRenderEmojiBrandMarks() |
| 58 | + { |
| 59 | + var sourceRoot = Path.Combine(RepoRoot, "src", "OpenClaw.Tray.WinUI"); |
| 60 | + var offenders = Directory |
| 61 | + .EnumerateFiles(sourceRoot, "*", SearchOption.AllDirectories) |
| 62 | + .Where(path => path.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) |
| 63 | + || path.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase)) |
| 64 | + .Where(path => !IsBuildArtifact(sourceRoot, path)) |
| 65 | + .SelectMany(path => File.ReadLines(path) |
| 66 | + .Select((line, index) => (path, line, lineNumber: index + 1))) |
| 67 | + .Where(item => item.line.Contains(LobsterEmoji, StringComparison.Ordinal) |
| 68 | + || item.line.Contains(RobotEmoji, StringComparison.Ordinal)) |
| 69 | + .Select(item => $"{Path.GetRelativePath(RepoRoot, item.path)}:{item.lineNumber}") |
| 70 | + .ToArray(); |
| 71 | + |
| 72 | + Assert.True( |
| 73 | + offenders.Length == 0, |
| 74 | + "Use the shared BrandMark control instead of emoji brand marks:" |
| 75 | + + Environment.NewLine |
| 76 | + + string.Join(Environment.NewLine, offenders)); |
| 77 | + |
| 78 | + static bool IsBuildArtifact(string sourceRoot, string path) |
| 79 | + { |
| 80 | + var relative = Path.GetRelativePath(sourceRoot, path); |
| 81 | + return relative.StartsWith($"bin{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase) |
| 82 | + || relative.StartsWith($"obj{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase); |
| 83 | + } |
| 84 | + } |
| 85 | +} |
0 commit comments