SelectorTests_Nesting.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. using System;
  2. using Avalonia.Controls;
  3. using Avalonia.Controls.Templates;
  4. using Avalonia.Styling;
  5. using Avalonia.Styling.Activators;
  6. using Xunit;
  7. namespace Avalonia.Base.UnitTests.Styling
  8. {
  9. public class SelectorTests_Nesting
  10. {
  11. [Fact]
  12. public void Nesting_Class_Doesnt_Match_Parent_OfType_Selector()
  13. {
  14. var control = new Control2();
  15. Style nested;
  16. var parent = new Style(x => x.OfType<Control1>())
  17. {
  18. Children =
  19. {
  20. (nested = new Style(x => x.Nesting().Class("foo"))),
  21. }
  22. };
  23. var match = nested.Selector!.Match(control, parent);
  24. Assert.Equal(SelectorMatchResult.NeverThisType, match.Result);
  25. }
  26. [Fact]
  27. public void Or_Nesting_Class_Doesnt_Match_Parent_OfType_Selector()
  28. {
  29. var control = new Control2();
  30. Style nested;
  31. var parent = new Style(x => x.OfType<Control1>())
  32. {
  33. Children =
  34. {
  35. (nested = new Style(x => Selectors.Or(
  36. x.Nesting().Class("foo"),
  37. x.Nesting().Class("bar")))),
  38. }
  39. };
  40. var match = nested.Selector!.Match(control, parent);
  41. Assert.Equal(SelectorMatchResult.NeverThisType, match.Result);
  42. }
  43. [Fact]
  44. public void Or_Nesting_Child_OfType_Doesnt_Match_Parent_OfType_Selector()
  45. {
  46. var control = new Control1();
  47. var panel = new DockPanel { Children = { control } };
  48. Style nested;
  49. var parent = new Style(x => x.OfType<Panel>())
  50. {
  51. Children =
  52. {
  53. (nested = new Style(x => Selectors.Or(
  54. x.Nesting().Child().OfType<Control1>(),
  55. x.Nesting().Child().OfType<Control1>()))),
  56. }
  57. };
  58. var match = nested.Selector!.Match(control, parent);
  59. Assert.Equal(SelectorMatchResult.NeverThisInstance, match.Result);
  60. }
  61. [Fact]
  62. public void Double_Nesting_Class_Doesnt_Match_Grandparent_OfType_Selector()
  63. {
  64. var control = new Control2
  65. {
  66. Classes = { "foo", "bar" },
  67. };
  68. Style parent;
  69. Style nested;
  70. var grandparent = new Style(x => x.OfType<Control1>())
  71. {
  72. Children =
  73. {
  74. (parent = new Style(x => x.Nesting().Class("foo"))
  75. {
  76. Children =
  77. {
  78. (nested = new Style(x => x.Nesting().Class("bar")))
  79. }
  80. })
  81. }
  82. };
  83. var match = nested.Selector!.Match(control, parent);
  84. Assert.Equal(SelectorMatchResult.NeverThisType, match.Result);
  85. }
  86. [Fact]
  87. public void Nesting_Class_Matches()
  88. {
  89. var control = new Control1 { Classes = { "foo" } };
  90. Style nested;
  91. var parent = new Style(x => x.OfType<Control1>())
  92. {
  93. Children =
  94. {
  95. (nested = new Style(x => x.Nesting().Class("foo"))),
  96. }
  97. };
  98. var match = nested.Selector!.Match(control, parent);
  99. Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
  100. Assert.NotNull(match.Activator);
  101. var sink = new ActivatorSink(match.Activator);
  102. Assert.True(sink.Active);
  103. control.Classes.Clear();
  104. Assert.False(sink.Active);
  105. }
  106. [Fact]
  107. public void Double_Nesting_Class_Matches()
  108. {
  109. var control = new Control1
  110. {
  111. Classes = { "foo", "bar" },
  112. };
  113. Style parent;
  114. Style nested;
  115. var grandparent = new Style(x => x.OfType<Control1>())
  116. {
  117. Children =
  118. {
  119. (parent = new Style(x => x.Nesting().Class("foo"))
  120. {
  121. Children =
  122. {
  123. (nested = new Style(x => x.Nesting().Class("bar")))
  124. }
  125. })
  126. }
  127. };
  128. var match = nested.Selector!.Match(control, parent);
  129. Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
  130. Assert.NotNull(match.Activator);
  131. var sink = new ActivatorSink(match.Activator);
  132. Assert.True(sink.Active);
  133. control.Classes.Remove("foo");
  134. Assert.False(sink.Active);
  135. }
  136. [Fact]
  137. public void Or_Nesting_Class_Matches()
  138. {
  139. var control = new Control1 { Classes = { "foo" } };
  140. Style nested;
  141. var parent = new Style(x => x.OfType<Control1>())
  142. {
  143. Children =
  144. {
  145. (nested = new Style(x => Selectors.Or(
  146. x.Nesting().Class("foo"),
  147. x.Nesting().Class("bar")))),
  148. }
  149. };
  150. var match = nested.Selector!.Match(control, parent);
  151. Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
  152. Assert.NotNull(match.Activator);
  153. var sink = new ActivatorSink(match.Activator);
  154. Assert.True(sink.Active);
  155. control.Classes.Clear();
  156. Assert.False(sink.Active);
  157. }
  158. [Fact]
  159. public void Or_Nesting_Child_OfType_Matches()
  160. {
  161. var control = new Control1 { Classes = { "foo" } };
  162. var panel = new Panel { Children = { control } };
  163. Style nested;
  164. var parent = new Style(x => x.OfType<Panel>())
  165. {
  166. Children =
  167. {
  168. (nested = new Style(x => Selectors.Or(
  169. x.Nesting().Child().OfType<Control1>(),
  170. x.Nesting().Child().OfType<Control1>()))),
  171. }
  172. };
  173. var match = nested.Selector!.Match(control, parent);
  174. Assert.Equal(SelectorMatchResult.AlwaysThisInstance, match.Result);
  175. }
  176. [Fact]
  177. public void Nesting_With_No_Parent_Style_Fails()
  178. {
  179. var control = new Control1();
  180. var style = new Style(x => x.Nesting().OfType<Control1>());
  181. Assert.Throws<InvalidOperationException>(() => style.Selector!.Match(control, null));
  182. }
  183. [Fact]
  184. public void Nesting_With_No_Parent_Selector_Fails()
  185. {
  186. var control = new Control1();
  187. Style nested;
  188. var parent = new Style
  189. {
  190. Children =
  191. {
  192. (nested = new Style(x => x.Nesting().Class("foo"))),
  193. }
  194. };
  195. Assert.Throws<InvalidOperationException>(() => nested.Selector!.Match(control, parent));
  196. }
  197. [Fact]
  198. public void Adding_Child_With_No_Nesting_Selector_Fails()
  199. {
  200. var parent = new Style(x => x.OfType<Control1>());
  201. var child = new Style(x => x.Class("foo"));
  202. Assert.Throws<InvalidOperationException>(() => parent.Children.Add(child));
  203. }
  204. [Fact]
  205. public void Adding_Combinator_Selector_Child_With_No_Nesting_Selector_Fails()
  206. {
  207. var parent = new Style(x => x.OfType<Control1>());
  208. var child = new Style(x => x.Class("foo").Descendant().Class("bar"));
  209. Assert.Throws<InvalidOperationException>(() => parent.Children.Add(child));
  210. }
  211. [Fact]
  212. public void Adding_Or_Selector_Child_With_No_Nesting_Selector_Fails()
  213. {
  214. var parent = new Style(x => x.OfType<Control1>());
  215. var child = new Style(x => Selectors.Or(
  216. x.Nesting().Class("foo"),
  217. x.Class("bar")));
  218. Assert.Throws<InvalidOperationException>(() => parent.Children.Add(child));
  219. }
  220. [Fact]
  221. public void Can_Add_Child_Without_Nesting_Selector_To_Style_Without_Selector()
  222. {
  223. var parent = new Style();
  224. var child = new Style(x => x.Class("foo"));
  225. parent.Children.Add(child);
  226. }
  227. [Fact]
  228. public void Nesting_Not_Class_Matches()
  229. {
  230. var control = new Control1 { Classes = { "foo" } };
  231. Style nested;
  232. var parent = new Style(x => x.OfType<Control1>())
  233. {
  234. Children =
  235. {
  236. (nested = new Style(x => x.Nesting().Not(y => y.Class("foo")))),
  237. }
  238. };
  239. var match = nested.Selector!.Match(control, parent);
  240. Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
  241. Assert.NotNull(match.Activator);
  242. var sink = new ActivatorSink(match.Activator);
  243. Assert.False(sink.Active);
  244. control.Classes.Clear();
  245. Assert.True(sink.Active);
  246. }
  247. public class Control1 : Control
  248. {
  249. }
  250. public class Control2 : Control
  251. {
  252. }
  253. private class ActivatorSink : IStyleActivatorSink
  254. {
  255. public ActivatorSink(IStyleActivator source)
  256. {
  257. source.Subscribe(this);
  258. Active = source.GetIsActive();
  259. }
  260. public bool Active { get; private set; }
  261. public void OnNext(bool value) => Active = value;
  262. }
  263. }
  264. }