Browse Source

Remove nesting selector validation.

Needs to be added later.
pull/8024/head
Steven Kirk 4 years ago
parent
commit
a91bad4d3b
  1. 13
      src/Avalonia.Base/Styling/Selector.cs
  2. 4
      src/Avalonia.Base/Styling/Selectors.cs
  3. 12
      src/Avalonia.Base/Styling/Style.cs
  4. 105
      tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs
  5. 42
      tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs

13
src/Avalonia.Base/Styling/Selector.cs

@ -96,11 +96,7 @@ namespace Avalonia.Styling
combinator = null;
var activators = new AndActivatorBuilder();
var foundNested = false;
var result = Match(control, start, parent, subscribe, ref activators, ref combinator, ref foundNested);
if (parent is not null && !foundNested)
throw new InvalidOperationException("Nesting selector '&' must appear in child selector.");
var result = Match(control, start, parent, subscribe, ref activators, ref combinator);
return result == SelectorMatchResult.Sometimes ?
new SelectorMatch(activators.Get()) :
@ -113,8 +109,7 @@ namespace Avalonia.Styling
IStyle? parent,
bool subscribe,
ref AndActivatorBuilder activators,
ref Selector? combinator,
ref bool foundNested)
ref Selector? combinator)
{
var previous = selector.MovePrevious();
@ -123,7 +118,7 @@ namespace Avalonia.Styling
// opportunity to exit early.
if (previous != null && !previous.IsCombinator)
{
var previousMatch = Match(control, previous, parent, subscribe, ref activators, ref combinator, ref foundNested);
var previousMatch = Match(control, previous, parent, subscribe, ref activators, ref combinator);
if (previousMatch < SelectorMatchResult.Sometimes)
{
@ -131,8 +126,6 @@ namespace Avalonia.Styling
}
}
foundNested |= selector is NestingSelector;
// Match this selector.
var match = selector.Evaluate(control, parent, subscribe);

4
src/Avalonia.Base/Styling/Selectors.cs

@ -111,10 +111,6 @@ namespace Avalonia.Styling
public static Selector Nesting(this Selector? previous)
{
if (previous is not null)
throw new InvalidOperationException(
"Nesting selector '&' must appear at the start of the style selector.");
return new NestingSelector();
}

12
src/Avalonia.Base/Styling/Style.cs

@ -169,6 +169,16 @@ namespace Avalonia.Styling
}
}
internal void SetParent(Style? parent) => Parent = parent;
internal void SetParent(Style? parent)
{
if (parent?.Selector is not null)
{
if (Selector is null)
throw new InvalidOperationException("Nested styles must have a selector.");
// TODO: Validate that selector contains & in the right place.
}
Parent = parent;
}
}
}

105
tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs

@ -9,7 +9,7 @@ namespace Avalonia.Base.UnitTests.Styling
public class SelectorTests_Nesting
{
[Fact]
public void Parent_Selector_Doesnt_Match_OfType()
public void Nesting_Class_Doesnt_Match_Parent_Selector()
{
var control = new Control2();
Style nested;
@ -26,43 +26,50 @@ namespace Avalonia.Base.UnitTests.Styling
}
[Fact]
public void Nested_Class_Selector()
public void Or_Nesting_Class_Doesnt_Match_Parent_Selector()
{
var control = new Control1 { Classes = { "foo" } };
var control = new Control2();
Style nested;
var parent = new Style(x => x.OfType<Control1>())
{
Children =
{
(nested = new Style(x => x.Nesting().Class("foo"))),
(nested = new Style(x => Selectors.Or(
x.Nesting().Class("foo"),
x.Nesting().Class("bar")))),
}
};
var match = nested.Selector.Match(control, parent);
Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
var sink = new ActivatorSink(match.Activator);
Assert.True(sink.Active);
control.Classes.Clear();
Assert.False(sink.Active);
Assert.Equal(SelectorMatchResult.NeverThisType, match.Result);
}
[Fact]
public void Nesting_With_No_Parent_Style_Fails()
public void Or_Nesting_Child_OfType_Does_Not_Match_Parent_Selector()
{
var control = new Control1();
var style = new Style(x => x.Nesting().OfType<Control1>());
var panel = new DockPanel { Children = { control } };
Style nested;
var parent = new Style(x => x.OfType<Panel>())
{
Children =
{
(nested = new Style(x => Selectors.Or(
x.Nesting().Child().OfType<Control1>(),
x.Nesting().Child().OfType<Control1>()))),
}
};
Assert.Throws<InvalidOperationException>(() => style.Selector.Match(control, null));
var match = nested.Selector.Match(control, parent);
Assert.Equal(SelectorMatchResult.NeverThisInstance, match.Result);
}
[Fact]
public void Nesting_With_No_Parent_Selector_Fails()
public void Nesting_Class_Matches()
{
var control = new Control1();
var control = new Control1 { Classes = { "foo" } };
Style nested;
var parent = new Style
var parent = new Style(x => x.OfType<Control1>())
{
Children =
{
@ -70,44 +77,80 @@ namespace Avalonia.Base.UnitTests.Styling
}
};
Assert.Throws<InvalidOperationException>(() => nested.Selector.Match(control, parent));
var match = nested.Selector.Match(control, parent);
Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
var sink = new ActivatorSink(match.Activator);
Assert.True(sink.Active);
control.Classes.Clear();
Assert.False(sink.Active);
}
[Fact]
public void Nesting_Must_Appear_At_Start_Of_Selector()
public void Or_Nesting_Class_Matches()
{
var control = new Control1();
Assert.Throws<InvalidOperationException>(() => new Style(x => x.OfType<Control1>().Nesting()));
var control = new Control1 { Classes = { "foo" } };
Style nested;
var parent = new Style(x => x.OfType<Control1>())
{
Children =
{
(nested = new Style(x => Selectors.Or(
x.Nesting().Class("foo"),
x.Nesting().Class("bar")))),
}
};
var match = nested.Selector.Match(control, parent);
Assert.Equal(SelectorMatchResult.Sometimes, match.Result);
var sink = new ActivatorSink(match.Activator);
Assert.True(sink.Active);
control.Classes.Clear();
Assert.False(sink.Active);
}
[Fact]
public void Nesting_Must_Appear()
public void Or_Nesting_Child_OfType_Matches()
{
var control = new Control1();
var control = new Control1 { Classes = { "foo" } };
var panel = new Panel { Children = { control } };
Style nested;
var parent = new Style
var parent = new Style(x => x.OfType<Panel>())
{
Children =
{
(nested = new Style(x => x.OfType<Control1>().Class("foo"))),
(nested = new Style(x => Selectors.Or(
x.Nesting().Child().OfType<Control1>(),
x.Nesting().Child().OfType<Control1>()))),
}
};
Assert.Throws<InvalidOperationException>(() => nested.Selector.Match(control, parent));
var match = nested.Selector.Match(control, parent);
Assert.Equal(SelectorMatchResult.AlwaysThisInstance, match.Result);
}
[Fact]
public void Nesting_Must_Appear_In_All_Or_Arguments()
public void Nesting_With_No_Parent_Style_Fails()
{
var control = new Control1();
var style = new Style(x => x.Nesting().OfType<Control1>());
Assert.Throws<InvalidOperationException>(() => style.Selector.Match(control, null));
}
[Fact]
public void Nesting_With_No_Parent_Selector_Fails()
{
var control = new Control1();
Style nested;
var parent = new Style(x => x.OfType<Control1>())
var parent = new Style
{
Children =
{
(nested = new Style(x => Selectors.Or(
x.Nesting().Class("foo"),
x.Class("bar"))))
(nested = new Style(x => x.Nesting().Class("foo"))),
}
};

42
tests/Avalonia.Base.UnitTests/Styling/StyleTests.cs

@ -722,6 +722,48 @@ namespace Avalonia.Base.UnitTests.Styling
resources.Verify(x => x.AddOwner(host.Object), Times.Once);
}
[Fact]
public void Nested_Style_Can_Be_Added()
{
var parent = new Style(x => x.OfType<Class1>());
var nested = new Style(x => x.Nesting().Class("foo"));
parent.Children.Add(nested);
Assert.Same(parent, nested.Parent);
}
[Fact]
public void Nested_Or_Style_Can_Be_Added()
{
var parent = new Style(x => x.OfType<Class1>());
var nested = new Style(x => Selectors.Or(
x.Nesting().Class("foo"),
x.Nesting().Class("bar")));
parent.Children.Add(nested);
Assert.Same(parent, nested.Parent);
}
[Fact]
public void Nested_Style_Without_Selector_Throws()
{
var parent = new Style(x => x.OfType<Class1>());
var nested = new Style();
Assert.Throws<InvalidOperationException>(() => parent.Children.Add(nested));
}
[Fact(Skip = "TODO")]
public void Nested_Style_Without_Nesting_Operator_Throws()
{
var parent = new Style(x => x.OfType<Class1>());
var nested = new Style(x => x.Class("foo"));
Assert.Throws<InvalidOperationException>(() => parent.Children.Add(nested));
}
private class Class1 : Control
{
public static readonly StyledProperty<string> FooProperty =

Loading…
Cancel
Save