ResourceIncludeTests.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #nullable enable
  2. using System;
  3. using System.Collections.Generic;
  4. using Avalonia.Controls;
  5. using Avalonia.Media;
  6. using Avalonia.Styling;
  7. using Avalonia.UnitTests;
  8. using Xunit;
  9. namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
  10. {
  11. public class ResourceIncludeTests : XamlTestBase
  12. {
  13. [Fact]
  14. public void ResourceInclude_Loads_ResourceDictionary()
  15. {
  16. var documents = new[]
  17. {
  18. new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Resource.xaml"), @"
  19. <ResourceDictionary xmlns='https://github.com/avaloniaui'
  20. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  21. <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
  22. </ResourceDictionary>"),
  23. new RuntimeXamlLoaderDocument(@"
  24. <UserControl xmlns='https://github.com/avaloniaui'
  25. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  26. <UserControl.Resources>
  27. <ResourceDictionary>
  28. <ResourceDictionary.MergedDictionaries>
  29. <ResourceInclude Source='avares://Tests/Resource.xaml'/>
  30. </ResourceDictionary.MergedDictionaries>
  31. </ResourceDictionary>
  32. </UserControl.Resources>
  33. <Border Name='border' Background='{StaticResource brush}'/>
  34. </UserControl>")
  35. };
  36. using (StartWithResources())
  37. {
  38. var compiled = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
  39. var userControl = Assert.IsType<UserControl>(compiled[1]);
  40. var border = userControl.GetControl<Border>("border");
  41. var brush = (ISolidColorBrush)border.Background!;
  42. Assert.Equal(0xff506070, brush.Color.ToUInt32());
  43. }
  44. }
  45. [Fact]
  46. public void Missing_ResourceKey_In_ResourceInclude_Does_Not_Cause_StackOverflow()
  47. {
  48. var app = Application.Current;
  49. var documents = new[]
  50. {
  51. new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Resource.xaml"), @"
  52. <ResourceDictionary xmlns='https://github.com/avaloniaui'
  53. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  54. <StaticResource x:Key='brush' ResourceKey='missing' />
  55. </ResourceDictionary>"),
  56. new RuntimeXamlLoaderDocument(app, @"
  57. <Application xmlns='https://github.com/avaloniaui'
  58. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  59. <Application.Resources>
  60. <ResourceDictionary>
  61. <ResourceDictionary.MergedDictionaries>
  62. <ResourceInclude Source='avares://Tests/Resource.xaml'/>
  63. </ResourceDictionary.MergedDictionaries>
  64. </ResourceDictionary>
  65. </Application.Resources>
  66. </Application>")
  67. };
  68. using (StartWithResources())
  69. {
  70. try
  71. {
  72. AvaloniaRuntimeXamlLoader.LoadGroup(documents);
  73. }
  74. catch (KeyNotFoundException)
  75. {
  76. }
  77. }
  78. }
  79. [Fact]
  80. public void ResourceInclude_Should_Be_Allowed_To_Have_Key_In_Custom_Container()
  81. {
  82. var app = Application.Current;
  83. var documents = new[]
  84. {
  85. new RuntimeXamlLoaderDocument(new Uri("avares://Demo/en-us.axaml"), @"
  86. <ResourceDictionary xmlns='https://github.com/avaloniaui'
  87. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
  88. <x:String x:Key='OkButton'>OK</x:String>
  89. </ResourceDictionary>"),
  90. new RuntimeXamlLoaderDocument(app, @"
  91. <ResourceDictionary xmlns='https://github.com/avaloniaui'
  92. xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  93. xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'>
  94. <ResourceDictionary.MergedDictionaries>
  95. <local:LocaleCollection>
  96. <ResourceInclude Source='avares://Demo/en-us.axaml' x:Key='English' />
  97. </local:LocaleCollection>
  98. </ResourceDictionary.MergedDictionaries>
  99. </ResourceDictionary>")
  100. };
  101. using (StartWithResources())
  102. {
  103. var groups = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
  104. var res = Assert.IsType<ResourceDictionary>(groups[1]);
  105. Assert.True(res.TryGetResource("OkButton", null, out var val));
  106. Assert.Equal("OK", val);
  107. }
  108. }
  109. private IDisposable StartWithResources(params (string, string)[] assets)
  110. {
  111. var assetLoader = new MockAssetLoader(assets);
  112. var services = new TestServices(assetLoader: assetLoader);
  113. return UnitTestApplication.Start(services);
  114. }
  115. }
  116. // See https://github.com/AvaloniaUI/Avalonia/issues/11172
  117. public class LocaleCollection : ResourceProvider
  118. {
  119. private readonly Dictionary<object, IResourceProvider> _langs = new();
  120. public override bool HasResources => true;
  121. public override bool TryGetResource(object key, ThemeVariant? theme, out object? value)
  122. {
  123. if (_langs.TryGetValue("English", out var res))
  124. {
  125. return res.TryGetResource(key, theme, out value);
  126. }
  127. value = null;
  128. return false;
  129. }
  130. // Allow Avalonia to use this class as a collection, requires x:Key on the IResourceProvider
  131. public void Add(object k, IResourceProvider v) => _langs.Add(k, v);
  132. }
  133. }