committed by
GitHub
18 changed files with 615 additions and 35 deletions
@ -0,0 +1,72 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using System; |
|||
using System.Reactive.Linq; |
|||
|
|||
namespace Avalonia.Styling |
|||
{ |
|||
/// <summary>
|
|||
/// The `:not()` style selector.
|
|||
/// </summary>
|
|||
internal class NotSelector : Selector |
|||
{ |
|||
private readonly Selector _previous; |
|||
private readonly Selector _argument; |
|||
private string _selectorString; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="NotSelector"/> class.
|
|||
/// </summary>
|
|||
/// <param name="previous">The previous selector.</param>
|
|||
/// <param name="argument">The selector to be not-ed.</param>
|
|||
public NotSelector(Selector previous, Selector argument) |
|||
{ |
|||
_previous = previous; |
|||
_argument = argument ?? throw new InvalidOperationException("Not selector must have a selector argument."); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool InTemplate => _argument.InTemplate; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool IsCombinator => false; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override Type TargetType => _previous?.TargetType; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
if (_selectorString == null) |
|||
{ |
|||
_selectorString = ":not(" + _argument.ToString() + ")"; |
|||
} |
|||
|
|||
return _selectorString; |
|||
} |
|||
|
|||
protected override SelectorMatch Evaluate(IStyleable control, bool subscribe) |
|||
{ |
|||
var innerResult = _argument.Match(control, subscribe); |
|||
|
|||
switch (innerResult.Result) |
|||
{ |
|||
case SelectorMatchResult.AlwaysThisInstance: |
|||
return SelectorMatch.NeverThisInstance; |
|||
case SelectorMatchResult.AlwaysThisType: |
|||
return SelectorMatch.NeverThisType; |
|||
case SelectorMatchResult.NeverThisInstance: |
|||
return SelectorMatch.AlwaysThisInstance; |
|||
case SelectorMatchResult.NeverThisType: |
|||
return SelectorMatch.AlwaysThisType; |
|||
case SelectorMatchResult.Sometimes: |
|||
return new SelectorMatch(innerResult.Activator.Select(x => !x)); |
|||
default: |
|||
throw new InvalidOperationException("Invalid SelectorMatchResult."); |
|||
} |
|||
} |
|||
|
|||
protected override Selector MovePrevious() => _previous; |
|||
} |
|||
} |
|||
@ -0,0 +1,114 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using System.Reactive.Linq; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Controls; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Styling.UnitTests |
|||
{ |
|||
public class SelectorTests_Not |
|||
{ |
|||
[Fact] |
|||
public void Not_Selector_Should_Have_Correct_String_Representation() |
|||
{ |
|||
var target = default(Selector).Not(x => x.Class("foo")); |
|||
|
|||
Assert.Equal(":not(.foo)", target.ToString()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Not_OfType_Matches_Control_Of_Incorrect_Type() |
|||
{ |
|||
var control = new Control1(); |
|||
var target = default(Selector).Not(x => x.OfType<Control1>()); |
|||
|
|||
Assert.Equal(SelectorMatchResult.NeverThisType, target.Match(control).Result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Not_OfType_Doesnt_Match_Control_Of_Correct_Type() |
|||
{ |
|||
var control = new Control2(); |
|||
var target = default(Selector).Not(x => x.OfType<Control1>()); |
|||
|
|||
Assert.Equal(SelectorMatchResult.AlwaysThisType, target.Match(control).Result); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Not_Class_Doesnt_Match_Control_With_Class() |
|||
{ |
|||
var control = new Control1 |
|||
{ |
|||
Classes = new Classes { "foo" }, |
|||
}; |
|||
|
|||
var target = default(Selector).Not(x => x.Class("foo")); |
|||
var match = target.Match(control); |
|||
|
|||
Assert.Equal(SelectorMatchResult.Sometimes, match.Result); |
|||
Assert.False(await match.Activator.Take(1)); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Not_Class_Matches_Control_Without_Class() |
|||
{ |
|||
var control = new Control1 |
|||
{ |
|||
Classes = new Classes { "bar" }, |
|||
}; |
|||
|
|||
var target = default(Selector).Not(x => x.Class("foo")); |
|||
var match = target.Match(control); |
|||
|
|||
Assert.Equal(SelectorMatchResult.Sometimes, match.Result); |
|||
Assert.True(await match.Activator.Take(1)); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task OfType_Not_Class_Matches_Control_Without_Class() |
|||
{ |
|||
var control = new Control1 |
|||
{ |
|||
Classes = new Classes { "bar" }, |
|||
}; |
|||
|
|||
var target = default(Selector).OfType<Control1>().Not(x => x.Class("foo")); |
|||
var match = target.Match(control); |
|||
|
|||
Assert.Equal(SelectorMatchResult.Sometimes, match.Result); |
|||
Assert.True(await match.Activator.Take(1)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void OfType_Not_Class_Doesnt_Match_Control_Of_Wrong_Type() |
|||
{ |
|||
var control = new Control2 |
|||
{ |
|||
Classes = new Classes { "foo" }, |
|||
}; |
|||
|
|||
var target = default(Selector).OfType<Control1>().Not(x => x.Class("foo")); |
|||
var match = target.Match(control); |
|||
|
|||
Assert.Equal(SelectorMatchResult.NeverThisType, match.Result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Returns_Correct_TargetType() |
|||
{ |
|||
var target = default(Selector).OfType<Control1>().Not(x => x.Class("foo")); |
|||
|
|||
Assert.Equal(typeof(Control1), target.TargetType); |
|||
} |
|||
|
|||
public class Control1 : TestControlBase |
|||
{ |
|||
} |
|||
|
|||
public class Control2 : TestControlBase |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue