SelectorTests_Nesting.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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. var sink = new ActivatorSink(match.Activator);
  101. Assert.True(sink.Active);
  102. control.Classes.Clear();
  103. Assert.False(sink.Active);
  104. }
  105. [Fact]
  106. public void Double_Nesting_Class_Matches()
  107. {
  108. var control = new Control1
  109. {
  110. Classes = { "foo", "bar" },
  111. };
  112. Style parent;
  113. Style nested;
  114. var grandparent = new Style(x => x.OfType<Control1>())
  115. {
  116. Children =
  117. {
  118. (parent = new Style(x => x.Nesting().Class("foo"))
  119. {
  120. Children =
  121. {
  122. (nested = new Style(x => x.Nesting().Class("bar")))
  123. }
  124. })
  125. }
  126. };
  127. var match = nested.Selector.Match(control, parent);
  128. Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
  129. var sink = new ActivatorSink(match.Activator);
  130. Assert.True(sink.Active);
  131. control.Classes.Remove("foo");
  132. Assert.False(sink.Active);
  133. }
  134. [Fact]
  135. public void Or_Nesting_Class_Matches()
  136. {
  137. var control = new Control1 { Classes = { "foo" } };
  138. Style nested;
  139. var parent = new Style(x => x.OfType<Control1>())
  140. {
  141. Children =
  142. {
  143. (nested = new Style(x => Selectors.Or(
  144. x.Nesting().Class("foo"),
  145. x.Nesting().Class("bar")))),
  146. }
  147. };
  148. var match = nested.Selector.Match(control, parent);
  149. Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
  150. var sink = new ActivatorSink(match.Activator);
  151. Assert.True(sink.Active);
  152. control.Classes.Clear();
  153. Assert.False(sink.Active);
  154. }
  155. [Fact]
  156. public void Or_Nesting_Child_OfType_Matches()
  157. {
  158. var control = new Control1 { Classes = { "foo" } };
  159. var panel = new Panel { Children = { control } };
  160. Style nested;
  161. var parent = new Style(x => x.OfType<Panel>())
  162. {
  163. Children =
  164. {
  165. (nested = new Style(x => Selectors.Or(
  166. x.Nesting().Child().OfType<Control1>(),
  167. x.Nesting().Child().OfType<Control1>()))),
  168. }
  169. };
  170. var match = nested.Selector.Match(control, parent);
  171. Assert.Equal(SelectorMatchResult.AlwaysThisInstance, match.Result);
  172. }
  173. [Fact]
  174. public void Nesting_With_No_Parent_Style_Fails()
  175. {
  176. var control = new Control1();
  177. var style = new Style(x => x.Nesting().OfType<Control1>());
  178. Assert.Throws<InvalidOperationException>(() => style.Selector.Match(control, null));
  179. }
  180. [Fact]
  181. public void Nesting_With_No_Parent_Selector_Fails()
  182. {
  183. var control = new Control1();
  184. Style nested;
  185. var parent = new Style
  186. {
  187. Children =
  188. {
  189. (nested = new Style(x => x.Nesting().Class("foo"))),
  190. }
  191. };
  192. Assert.Throws<InvalidOperationException>(() => nested.Selector.Match(control, parent));
  193. }
  194. [Fact]
  195. public void Adding_Child_With_No_Nesting_Selector_Fails()
  196. {
  197. var parent = new Style(x => x.OfType<Control1>());
  198. var child = new Style(x => x.Class("foo"));
  199. Assert.Throws<InvalidOperationException>(() => parent.Children.Add(child));
  200. }
  201. [Fact]
  202. public void Adding_Combinator_Selector_Child_With_No_Nesting_Selector_Fails()
  203. {
  204. var parent = new Style(x => x.OfType<Control1>());
  205. var child = new Style(x => x.Class("foo").Descendant().Class("bar"));
  206. Assert.Throws<InvalidOperationException>(() => parent.Children.Add(child));
  207. }
  208. [Fact]
  209. public void Adding_Or_Selector_Child_With_No_Nesting_Selector_Fails()
  210. {
  211. var parent = new Style(x => x.OfType<Control1>());
  212. var child = new Style(x => Selectors.Or(
  213. x.Nesting().Class("foo"),
  214. x.Class("bar")));
  215. Assert.Throws<InvalidOperationException>(() => parent.Children.Add(child));
  216. }
  217. [Fact]
  218. public void Can_Add_Child_Without_Nesting_Selector_To_Style_Without_Selector()
  219. {
  220. var parent = new Style();
  221. var child = new Style(x => x.Class("foo"));
  222. parent.Children.Add(child);
  223. }
  224. [Fact]
  225. public void Nesting_Not_Class_Matches()
  226. {
  227. var control = new Control1 { Classes = { "foo" } };
  228. Style nested;
  229. var parent = new Style(x => x.OfType<Control1>())
  230. {
  231. Children =
  232. {
  233. (nested = new Style(x => x.Nesting().Not(y => y.Class("foo")))),
  234. }
  235. };
  236. var match = nested.Selector.Match(control, parent);
  237. Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
  238. var sink = new ActivatorSink(match.Activator);
  239. Assert.False(sink.Active);
  240. control.Classes.Clear();
  241. Assert.True(sink.Active);
  242. }
  243. public class Control1 : Control
  244. {
  245. }
  246. public class Control2 : Control
  247. {
  248. }
  249. private class ActivatorSink : IStyleActivatorSink
  250. {
  251. public ActivatorSink(IStyleActivator source)
  252. {
  253. source.Subscribe(this);
  254. Active = source.GetIsActive();
  255. }
  256. public bool Active { get; private set; }
  257. public void OnNext(bool value) => Active = value;
  258. }
  259. }
  260. }