Skip to content

Commit dea0121

Browse files
committed
Adding unit tests to verify the fix.
1 parent 6480266 commit dea0121

File tree

5 files changed

+231
-53
lines changed

5 files changed

+231
-53
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System.Linq;
2+
using System.Windows.Controls;
3+
using Xunit;
4+
5+
namespace MaterialDesignThemes.Wpf.Tests
6+
{
7+
public class ClockTests
8+
{
9+
[StaFact(Timeout = 500)]
10+
public void CanGenerateHoursButtons()
11+
{
12+
var clock = new Clock();
13+
clock.ApplyDefaultStyle();
14+
15+
Canvas hoursCanvas = clock.FindVisualChild<Canvas>(Clock.HoursCanvasPartName);
16+
var buttonContents = hoursCanvas.GetVisualChildren<ClockItemButton>().Select(x => x.Content.ToString());
17+
18+
var expected = Enumerable.Range(1, 12).Select(x => $"{x:0}");
19+
Assert.Equal(expected.OrderBy(x => x), buttonContents.OrderBy(x => x));
20+
}
21+
22+
[StaFact(Timeout = 500)]
23+
public void CanGenerateHoursButtonsWith24Hours()
24+
{
25+
var clock = new Clock {Is24Hours = true};
26+
clock.ApplyDefaultStyle();
27+
28+
Canvas hoursCanvas = clock.FindVisualChild<Canvas>(Clock.HoursCanvasPartName);
29+
var buttonContents = hoursCanvas.GetVisualChildren<ClockItemButton>().Select(x => x.Content.ToString());
30+
31+
var expected = Enumerable.Range(13, 11).Select(x => $"{x:00}")
32+
.Concat(new [] {"00"})
33+
.Concat(Enumerable.Range(1, 12).Select(x => $"{x:#}"));
34+
Assert.Equal(expected.OrderBy(x => x), buttonContents.OrderBy(x => x));
35+
}
36+
37+
[StaFact(Timeout = 500)]
38+
public void CanGenerateMinuteButtons()
39+
{
40+
var clock = new Clock();
41+
clock.ApplyDefaultStyle();
42+
43+
Canvas minutesCanvas = clock.FindVisualChild<Canvas>(Clock.MinutesCanvasPartName);
44+
var buttonContents = minutesCanvas.GetVisualChildren<ClockItemButton>().Select(x => x.Content.ToString());
45+
46+
var expected = Enumerable.Range(0, 60).Select(x => $"{x:0}");
47+
Assert.Equal(expected.OrderBy(x => x), buttonContents.OrderBy(x => x));
48+
}
49+
50+
[StaFact(Timeout = 500)]
51+
public void CanGenerateSecondsButtons()
52+
{
53+
var clock = new Clock();
54+
clock.ApplyDefaultStyle();
55+
56+
Canvas secondsCanvas = clock.FindVisualChild<Canvas>(Clock.SecondsCanvasPartName);
57+
var buttonContents = secondsCanvas.GetVisualChildren<ClockItemButton>().Select(x => x.Content.ToString());
58+
59+
var expected = Enumerable.Range(0, 60).Select(x => $"{x:0}");
60+
Assert.Equal(expected.OrderBy(x => x), buttonContents.OrderBy(x => x));
61+
}
62+
}
63+
}

MaterialDesignThemes.Wpf.Tests/MaterialDesignThemes.Wpf.Tests.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<AssemblyName>MaterialDesignThemes.Wpf.Tests</AssemblyName>
1313
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
1414
<FileAlignment>512</FileAlignment>
15+
<LangVersion>latest</LangVersion>
1516
</PropertyGroup>
1617
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
1718
<DebugSymbols>true</DebugSymbols>
@@ -29,6 +30,7 @@
2930
<DefineConstants>TRACE</DefineConstants>
3031
<ErrorReport>prompt</ErrorReport>
3132
<WarningLevel>4</WarningLevel>
33+
<LangVersion>latest</LangVersion>
3234
</PropertyGroup>
3335
<ItemGroup>
3436
<Reference Include="PresentationCore" />
@@ -43,9 +45,12 @@
4345
<Reference Include="System.Xml" />
4446
</ItemGroup>
4547
<ItemGroup>
48+
<Compile Include="ClockTests.cs" />
4649
<Compile Include="DialogHostTests.cs" />
50+
<Compile Include="MdixHelper.cs" />
4751
<Compile Include="PaletteHelperFixture.cs" />
4852
<Compile Include="Properties\AssemblyInfo.cs" />
53+
<Compile Include="VisualTreeHelper.cs" />
4954
</ItemGroup>
5055
<ItemGroup>
5156
<ProjectReference Include="..\MaterialDesignThemes.Wpf\MaterialDesignThemes.Wpf.csproj">
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System;
2+
using System.IO.Packaging;
3+
using System.Windows;
4+
using System.Windows.Controls;
5+
using Xunit;
6+
7+
namespace MaterialDesignThemes.Wpf.Tests
8+
{
9+
public static class MdixHelper
10+
{
11+
static MdixHelper()
12+
{
13+
var _ = Application.Current;
14+
15+
_defaultResourceDictionary = new Lazy<ResourceDictionary>(() => GetThemeResourceDictionary("Defaults"));
16+
_genericResourceDictionary = new Lazy<ResourceDictionary>(GetGenericResourceDictionary);
17+
}
18+
19+
private static readonly Lazy<ResourceDictionary> _defaultResourceDictionary;
20+
private static ResourceDictionary DefaultResourceDictionary => _defaultResourceDictionary.Value;
21+
22+
private static readonly Lazy<ResourceDictionary> _genericResourceDictionary;
23+
private static ResourceDictionary GenericResourceDictionary => _genericResourceDictionary.Value;
24+
25+
public static void ApplyDefaultStyle<T>(this T control) where T : FrameworkElement
26+
{
27+
Style style = GetDefaultStyle<T>();
28+
Assert.True(style != null, $"Could not find default style for control type {typeof(T).FullName}");
29+
control.Style = style;
30+
Assert.True(control.ApplyTemplate(), "Failed to apply template ");
31+
}
32+
33+
private static Style GetDefaultStyle<T>() where T : FrameworkElement
34+
{
35+
return DefaultResourceDictionary[typeof(T)] as Style ??
36+
GenericResourceDictionary[typeof(T)] as Style;
37+
}
38+
39+
private static ResourceDictionary GetThemeResourceDictionary(string name)
40+
{
41+
var uri = new Uri(
42+
$"/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.{name}.xaml", UriKind.Relative);
43+
return new ResourceDictionary {
44+
Source = uri
45+
};
46+
}
47+
48+
private static ResourceDictionary GetGenericResourceDictionary()
49+
{
50+
var uri = new Uri(
51+
$"/MaterialDesignThemes.Wpf;component/Themes/Generic.xaml", UriKind.Relative);
52+
return new ResourceDictionary {
53+
Source = uri
54+
};
55+
}
56+
}
57+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Windows;
6+
7+
using WPFVisualTreeHelper= System.Windows.Media.VisualTreeHelper;
8+
9+
namespace MaterialDesignThemes.Wpf.Tests
10+
{
11+
public static class VisualTreeHelper
12+
{
13+
public static T FindVisualChild<T>(this DependencyObject source, string name) where T : FrameworkElement
14+
{
15+
return GetAllVisualChildren(source).OfType<T>().Single(x => x.Name == name);
16+
}
17+
18+
public static IEnumerable<T> GetVisualChildren<T>(this DependencyObject source) where T : DependencyObject
19+
{
20+
if (source == null) throw new ArgumentNullException(nameof(source));
21+
22+
return GetVisualChildrenImplementation();
23+
24+
IEnumerable<T> GetVisualChildrenImplementation()
25+
{
26+
int count = WPFVisualTreeHelper.GetChildrenCount(source);
27+
for (int i = 0; i < count; i++)
28+
{
29+
if (WPFVisualTreeHelper.GetChild(source, i) is T child)
30+
{
31+
yield return child;
32+
}
33+
}
34+
}
35+
}
36+
37+
private static IEnumerable<DependencyObject> GetAllVisualChildren(DependencyObject source)
38+
{
39+
var stack = new Queue<DependencyObject>();
40+
stack.Enqueue(source);
41+
42+
while (stack.Any())
43+
{
44+
DependencyObject current = stack.Dequeue();
45+
int childCount = WPFVisualTreeHelper.GetChildrenCount(current);
46+
for (int i = 0; i < childCount; i++)
47+
{
48+
var child = WPFVisualTreeHelper.GetChild(current, i);
49+
yield return child;
50+
stack.Enqueue(child);
51+
}
52+
}
53+
}
54+
}
55+
}

MaterialDesignThemes.Wpf/Converters/ClockItemIsCheckedConverter.cs

Lines changed: 51 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,81 +4,79 @@
44

55
namespace MaterialDesignThemes.Wpf.Converters
66
{
7-
internal class ClockItemIsCheckedConverter : IValueConverter
8-
{
9-
private readonly Func<DateTime> _currentTimeGetter;
10-
private readonly ClockDisplayMode _displayMode;
11-
private readonly bool _is24Hours;
7+
internal class ClockItemIsCheckedConverter : IValueConverter
8+
{
9+
private readonly Func<DateTime> _currentTimeGetter;
10+
private readonly ClockDisplayMode _displayMode;
11+
private readonly bool _is24Hours;
1212

13-
public ClockItemIsCheckedConverter(Func<DateTime> currentTimeGetter, ClockDisplayMode displayMode, bool is24Hours)
14-
{
15-
if (currentTimeGetter == null) throw new ArgumentNullException(nameof(currentTimeGetter));
13+
public ClockItemIsCheckedConverter(Func<DateTime> currentTimeGetter, ClockDisplayMode displayMode, bool is24Hours)
14+
{
15+
_currentTimeGetter = currentTimeGetter ?? throw new ArgumentNullException(nameof(currentTimeGetter));
16+
_displayMode = displayMode;
17+
_is24Hours = is24Hours;
18+
}
1619

17-
_currentTimeGetter = currentTimeGetter;
18-
_displayMode = displayMode;
19-
_is24Hours = is24Hours;
20-
}
21-
22-
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
23-
{
24-
var dateTime = (DateTime) value;
25-
var i = (int) parameter;
20+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
21+
{
22+
var dateTime = (DateTime)value;
23+
var i = (int)parameter;
2624

2725
int converted = 0;
28-
if (_displayMode == ClockDisplayMode.Hours )
26+
if (_displayMode == ClockDisplayMode.Hours)
2927
converted = MassageHour(dateTime.Hour, _is24Hours);
3028
else if (_displayMode == ClockDisplayMode.Minutes)
3129
converted = MassageMinuteSecond(dateTime.Minute);
3230
else
3331
converted = MassageMinuteSecond(dateTime.Second);
3432
return converted == i;
35-
}
33+
}
3634

37-
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
38-
{
39-
if ((bool)value != true) return Binding.DoNothing;
35+
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
36+
{
37+
if ((bool)value != true) return Binding.DoNothing;
4038

41-
var currentTime = _currentTimeGetter();
39+
var currentTime = _currentTimeGetter();
4240

4341
return new DateTime(
4442
currentTime.Year, currentTime.Month, currentTime.Day,
4543
(_displayMode == ClockDisplayMode.Hours) ? ReverseMassageHour((int)parameter, currentTime, _is24Hours) : currentTime.Hour,
4644
(_displayMode == ClockDisplayMode.Minutes) ? ReverseMassageMinuteSecond((int)parameter) : currentTime.Minute,
4745
(_displayMode == ClockDisplayMode.Seconds) ? ReverseMassageMinuteSecond((int)parameter) : currentTime.Second);
48-
}
46+
}
4947

50-
private static int MassageHour(int val, bool is24Hours)
51-
{
52-
if (is24Hours)
53-
{
54-
return val == 0 ? 24 : val;
55-
}
48+
private static int MassageHour(int val, bool is24Hours)
49+
{
50+
if (is24Hours)
51+
{
52+
return val == 0 ? 24 : val;
53+
}
5654

57-
if (val == 0) return 12;
58-
if (val > 12) return val - 12;
59-
return val;
60-
}
55+
if (val == 0) return 12;
56+
if (val > 12) return val - 12;
57+
return val;
58+
}
6159

62-
private static int MassageMinuteSecond(int val)
63-
{
64-
return val == 0 ? 60 : val;
65-
}
60+
private static int MassageMinuteSecond(int val)
61+
{
62+
return val == 0 ? 60 : val;
63+
}
6664

67-
private static int ReverseMassageHour(int val, DateTime currentTime, bool is24Hours)
68-
{
69-
if (is24Hours)
70-
{
71-
return val == 24 ? 0 : val;
72-
}
65+
private static int ReverseMassageHour(int val, DateTime currentTime, bool is24Hours)
66+
{
67+
if (is24Hours)
68+
{
69+
return val == 24 ? 0 : val;
70+
}
7371

74-
return currentTime.Hour < 12
75-
? (val == 12 ? 0 : val)
76-
: (val == 12 ? 12 : val + 12);
77-
}
72+
return currentTime.Hour < 12
73+
? (val == 12 ? 0 : val)
74+
: (val == 12 ? 12 : val + 12);
75+
}
7876

79-
private static int ReverseMassageMinuteSecond(int val)
80-
{
81-
return val == 60 ? 0 : val;
82-
}
83-
}
77+
private static int ReverseMassageMinuteSecond(int val)
78+
{
79+
return val == 60 ? 0 : val;
80+
}
81+
}
8482
}

0 commit comments

Comments
 (0)