Browse Source

Added validation/coercion to RangeBase properties.

pull/63/head
Steven Kirk 11 years ago
parent
commit
09ef0309b1
  1. 1
      Perspex.Base/Perspex.Base.csproj
  2. 42
      Perspex.Base/Utilities/MathUtilities.cs
  3. 74
      Perspex.Controls/Primitives/RangeBase.cs
  4. 1
      Tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj
  5. 2
      Tests/Perspex.Controls.UnitTests/Presenters/ItemsPresenterTests.cs
  6. 97
      Tests/Perspex.Controls.UnitTests/Primitives/RangeBaseTests.cs
  7. 2
      Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

1
Perspex.Base/Perspex.Base.csproj

@ -66,6 +66,7 @@
<Compile Include="Threading\DispatcherTimer.cs" />
<Compile Include="Threading\MainLoop.cs" />
<Compile Include="Threading\PerspexScheduler.cs" />
<Compile Include="Utilities\MathUtilities.cs" />
<Compile Include="Utilities\TypeUtilities.cs" />
</ItemGroup>
<ItemGroup>

42
Perspex.Base/Utilities/MathUtilities.cs

@ -0,0 +1,42 @@
// -----------------------------------------------------------------------
// <copyright file="TypeUtilities.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Utilities
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
/// <summary>
/// Provides math utilities not provided in System.Math.
/// </summary>
public static class MathUtilities
{
/// <summary>
/// Clamps a value between a minimum and maximum value.
/// </summary>
/// <param name="val">The value.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <returns>The clamped value.</returns>
public static double Clamp(double val, double min, double max)
{
if (val < min)
{
return min;
}
else if (val > max)
{
return max;
}
else
{
return val;
}
}
}
}

74
Perspex.Controls/Primitives/RangeBase.cs

@ -6,6 +6,9 @@
namespace Perspex.Controls.Primitives
{
using System;
using Perspex.Utilities;
/// <summary>
/// Base class for controls that display a value within a range.
/// </summary>
@ -15,19 +18,35 @@ namespace Perspex.Controls.Primitives
/// Defines the <see cref="Minimum"/> property.
/// </summary>
public static readonly PerspexProperty<double> MinimumProperty =
PerspexProperty.Register<RangeBase, double>("Minimum");
PerspexProperty.Register<RangeBase, double>(
nameof(Minimum),
validate: ValidateMinimum);
/// <summary>
/// Defines the <see cref="Maximum"/> property.
/// </summary>
public static readonly PerspexProperty<double> MaximumProperty =
PerspexProperty.Register<RangeBase, double>("Maximum", defaultValue: 100.0);
PerspexProperty.Register<RangeBase, double>(
nameof(Maximum),
defaultValue: 100.0,
validate: ValidateMaximum);
/// <summary>
/// Defines the <see cref="Value"/> property.
/// </summary>
public static readonly PerspexProperty<double> ValueProperty =
PerspexProperty.Register<RangeBase, double>("Value");
PerspexProperty.Register<RangeBase, double>(
nameof(Value),
validate: ValidateValue);
/// <summary>
/// Initializes a new instance of the <see cref="RangeBase"/> class.
/// </summary>
public RangeBase()
{
AffectsValidation(MinimumProperty, MaximumProperty, ValueProperty);
AffectsValidation(MaximumProperty, ValueProperty);
}
/// <summary>
/// Gets or sets the minimum value.
@ -55,5 +74,54 @@ namespace Perspex.Controls.Primitives
get { return this.GetValue(ValueProperty); }
set { this.SetValue(ValueProperty, value); }
}
/// <summary>
/// Throws an exception if the double valus is NaN or Inf.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="property">The name of the property being set.</param>
private static void ValidateDouble(double value, string property)
{
if (double.IsInfinity(value) || double.IsNaN(value))
{
throw new ArgumentException($"{value} is not a valid value for {property}.");
}
}
/// <summary>
/// Validates the <see cref="Minimum"/> property.
/// </summary>
/// <param name="sender">The RangeBase control.</param>
/// <param name="value">The value.</param>
/// <returns>The coerced value.</returns>
private static double ValidateMinimum(RangeBase sender, double value)
{
ValidateDouble(value, "Minimum");
return value;
}
/// <summary>
/// Validates/coerces the <see cref="Maximum"/> property.
/// </summary>
/// <param name="sender">The RangeBase control.</param>
/// <param name="value">The value.</param>
/// <returns>The coerced value.</returns>
private static double ValidateMaximum(RangeBase sender, double value)
{
ValidateDouble(value, "Maximum");
return Math.Max(value, sender.Minimum);
}
/// <summary>
/// Validates/coerces the <see cref="Value"/> property.
/// </summary>
/// <param name="sender">The RangeBase control.</param>
/// <param name="value">The value.</param>
/// <returns>The coerced value.</returns>
private static double ValidateValue(RangeBase sender, double value)
{
ValidateDouble(value, "Value");
return MathUtilities.Clamp(value, sender.Minimum, sender.Maximum);
}
}
}

1
Tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj

@ -96,6 +96,7 @@
<Compile Include="DropDownTests.cs" />
<Compile Include="Presenters\ItemsPresenterTests.cs" />
<Compile Include="Presenters\ScrollContentPresenterTests.cs" />
<Compile Include="Primitives\RangeBaseTests.cs" />
<Compile Include="ScrollViewerTests.cs" />
<Compile Include="Primitives\SelectingItemsControlTests.cs" />
<Compile Include="ListBoxTests.cs" />

2
Tests/Perspex.Controls.UnitTests/Presenters/ItemsPresenterTests.cs

@ -6,10 +6,10 @@
namespace Perspex.Controls.UnitTests.Presenters
{
using System.Linq;
using Perspex.Controls.Presenters;
using Perspex.Input;
using Perspex.VisualTree;
using System.Linq;
using Xunit;
public class ItemsPresenterTests

97
Tests/Perspex.Controls.UnitTests/Primitives/RangeBaseTests.cs

@ -0,0 +1,97 @@
// -----------------------------------------------------------------------
// <copyright file="RangeBaseTests.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls.UnitTests.Primitives
{
using Perspex.Controls.Primitives;
using System;
using Xunit;
public class RangeBaseTests
{
[Fact]
public void Maximum_Should_Be_Coerced_To_Minimum()
{
var target = new TestRange
{
Minimum = 100,
Maximum = 50,
};
Assert.Equal(100, target.Minimum);
Assert.Equal(100, target.Maximum);
}
[Fact]
public void Value_Should_Be_Coerced_To_Range()
{
var target = new TestRange
{
Minimum = 0,
Maximum = 50,
Value = 100,
};
Assert.Equal(0, target.Minimum);
Assert.Equal(50, target.Maximum);
Assert.Equal(50, target.Value);
}
[Fact]
public void Changing_Minimum_Should_Coerce_Value_And_Maximum()
{
var target = new TestRange
{
Minimum = 0,
Maximum = 100,
Value = 50,
};
target.Minimum = 200;
Assert.Equal(200, target.Minimum);
Assert.Equal(200, target.Maximum);
Assert.Equal(200, target.Value);
}
[Fact]
public void Changing_Maximum_Should_Coerce_Value()
{
var target = new TestRange
{
Minimum = 0,
Maximum = 100,
Value = 100,
};
target.Maximum = 50;
Assert.Equal(0, target.Minimum);
Assert.Equal(50, target.Maximum);
Assert.Equal(50, target.Value);
}
[Fact]
public void Properties_Should_Not_Accept_Nan_And_Inifinity()
{
var target = new TestRange();
Assert.Throws<ArgumentException>(() => target.Minimum = double.NaN);
Assert.Throws<ArgumentException>(() => target.Minimum = double.PositiveInfinity);
Assert.Throws<ArgumentException>(() => target.Minimum = double.NegativeInfinity);
Assert.Throws<ArgumentException>(() => target.Maximum = double.NaN);
Assert.Throws<ArgumentException>(() => target.Maximum = double.PositiveInfinity);
Assert.Throws<ArgumentException>(() => target.Maximum = double.NegativeInfinity);
Assert.Throws<ArgumentException>(() => target.Value = double.NaN);
Assert.Throws<ArgumentException>(() => target.Value = double.PositiveInfinity);
Assert.Throws<ArgumentException>(() => target.Value = double.NegativeInfinity);
}
private class TestRange : RangeBase
{
}
}
}

2
Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

@ -4,7 +4,7 @@
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls.Primitives.UnitTests
namespace Perspex.Controls.UnitTests.Primitives
{
using Perspex.Collections;
using Perspex.Controls.Presenters;

Loading…
Cancel
Save