Fixing issue where a cast exception in the Converter could cause the app to crash.

Added unit tests for the Binding converters.
This commit is contained in:
Laurent Bugnion 2016-01-31 14:35:45 +01:00
Родитель 67f716044a
Коммит 211c05a45d
2 изменённых файлов: 257 добавлений и 2 удалений

Просмотреть файл

@ -1114,13 +1114,36 @@ namespace GalaSoft.MvvmLight.Helpers
}
var sourceValue = (TSource)_sourceProperty.GetValue(_propertySource.Target, null);
return _converter.Convert(sourceValue);
try
{
return _converter.Convert(sourceValue);
}
catch (Exception)
{
if (!Equals(FallbackValue, default(TSource)))
{
return _converter.Convert(FallbackValue);
}
var targetValue = (TTarget)_targetProperty.GetValue(_propertyTarget.Target, null);
return targetValue;
}
}
private TSource GetTargetValue()
{
var targetValue = (TTarget)_targetProperty.GetValue(_propertyTarget.Target, null);
return _converter.ConvertBack(targetValue);
try
{
return _converter.ConvertBack(targetValue);
}
catch (Exception)
{
var sourceValue = (TSource)_sourceProperty.GetValue(_propertySource.Target, null);
return sourceValue;
}
}
private void HandleSourceEvent<TEventArgs>(object sender, TEventArgs args)

Просмотреть файл

@ -0,0 +1,232 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using GalaSoft.MvvmLight.Helpers;
using GalaSoft.MvvmLight.Test.Controls;
using GalaSoft.MvvmLight.Test.ViewModel;
using NUnit.Framework;
#if ANDROID
using Android.App;
using Android.Widget;
#elif __IOS__
using UIKit;
#endif
namespace GalaSoft.MvvmLight.Test.Binding
{
[TestFixture]
[SuppressMessage("ReSharper", "InconsistentNaming")]
public class ConverterTest
{
public TestViewModel Vm
{
get;
private set;
}
#if ANDROID
public EditText Text
{
get;
private set;
}
#elif __IOS__
public UITextViewEx Text
{
get;
private set;
}
#endif
[Test]
public void BindingConverter_ConvertDateTimeToText_NoError()
{
var now = DateTime.Now;
Vm = new TestViewModel
{
Date = now
};
#if ANDROID
Text = new EditText(Application.Context);
#elif __IOS__
Text = new UITextViewEx();
#endif
this.SetBinding(
() => Vm.Date,
() => Text.Text)
.ConvertSourceToTarget(d => d.Date.ToShortDateString());
Assert.AreEqual(now, Vm.Date);
Assert.AreEqual(now.ToShortDateString(), Text.Text);
Vm.Date += TimeSpan.FromDays(3);
Assert.AreEqual((now + TimeSpan.FromDays(3)).ToShortDateString(), Text.Text);
}
[Test]
public void BindingConverter_ConvertDateTimeTwoWayToText_NoError()
{
var now = DateTime.Now;
Vm = new TestViewModel
{
Date = now
};
#if ANDROID
Text = new EditText(Application.Context);
#elif __IOS__
Text = new UITextViewEx();
#endif
this.SetBinding(
() => Vm.Date,
() => Text.Text,
BindingMode.TwoWay)
.ConvertSourceToTarget(d => d.Date.ToShortDateString())
.ConvertTargetToSource(d => DateTime.ParseExact(d, "dd/MM/yyyy", CultureInfo.InvariantCulture));
Assert.AreEqual(now, Vm.Date);
Assert.AreEqual(now.ToShortDateString(), Text.Text);
Vm.Date += TimeSpan.FromDays(3);
Assert.AreEqual((now + TimeSpan.FromDays(3)).ToShortDateString(), Text.Text);
var newDateString = "13/04/1971";
var newDate = new DateTime(1971, 4, 13);
Text.Text = newDateString;
Assert.AreEqual(newDateString, Text.Text);
Assert.AreEqual(newDate, Vm.Date);
}
[Test]
public void BindingConverter_ConvertInvalidDateConversion_NoError()
{
var vmSource = new TestViewModel
{
Model = new TestModel
{
MyProperty = "13/04/1971"
}
};
var vmTarget = new TestViewModel();
var binding = new Binding<string, DateTime>(
vmSource,
() => vmSource.Model.MyProperty,
vmTarget,
() => vmTarget.Date)
.ConvertSourceToTarget(d => DateTime.ParseExact(d, "dd/MM/yyyy", CultureInfo.InvariantCulture));
var referenceDate = new DateTime(1971, 4, 13);
Assert.AreEqual(referenceDate, vmTarget.Date);
var newDateString = "13/04/197"; // Invalid date string
vmSource.Model.MyProperty = newDateString;
Assert.AreEqual(referenceDate, vmTarget.Date);
newDateString = "13/04/1972"; // Valid date string
vmSource.Model.MyProperty = newDateString;
referenceDate = new DateTime(1972, 4, 13);
Assert.AreEqual(referenceDate, vmTarget.Date);
}
[Test]
public void BindingConverter_ConvertBackInvalidDateConversion_NoError()
{
var date = DateTime.Now;
Vm = new TestViewModel
{
Date = date
};
#if ANDROID
Text = new EditText(Application.Context);
#elif __IOS__
Text = new UITextViewEx();
#endif
this.SetBinding(
() => Vm.Date,
() => Text.Text,
BindingMode.TwoWay)
.ConvertSourceToTarget(d => d.Date.ToShortDateString())
.ConvertTargetToSource(d => DateTime.ParseExact(d, "dd/MM/yyyy", CultureInfo.InvariantCulture));
Assert.AreEqual(date, Vm.Date);
Assert.AreEqual(date.ToShortDateString(), Text.Text);
date += TimeSpan.FromDays(3);
Vm.Date = date;
Assert.AreEqual(date.ToShortDateString(), Text.Text);
var newDateString = "13/04/197"; // Invalid date string
Text.Text = newDateString;
Assert.AreEqual(newDateString, Text.Text);
Assert.AreEqual(date, Vm.Date);
newDateString = "13/04/1971"; // Valid date string
Text.Text = newDateString;
Assert.AreEqual(newDateString, Text.Text);
Assert.AreEqual(new DateTime(1971, 4, 13), Vm.Date);
}
[Test]
public void BindingConverter_ConvertInvalidDateConversionWithExplicitExceptionHandling_NoError()
{
var vmSource = new TestViewModel
{
Model = new TestModel
{
MyProperty = "13/04/1971"
}
};
var vmTarget = new TestViewModel();
var binding = new Binding<string, DateTime>(
vmSource,
() => vmSource.Model.MyProperty,
vmTarget,
() => vmTarget.Date)
.ConvertSourceToTarget(
d =>
{
try
{
return DateTime.ParseExact(d, "dd/MM/yyyy", CultureInfo.InvariantCulture);
}
catch (Exception)
{
return DateTime.MinValue;
}
});
var referenceDate = new DateTime(1971, 4, 13);
Assert.AreEqual(referenceDate, vmTarget.Date);
var newDateString = "13/04/197"; // Invalid date string
vmSource.Model.MyProperty = newDateString;
Assert.AreEqual(DateTime.MinValue, vmTarget.Date);
newDateString = "13/04/1972"; // Valid date string
vmSource.Model.MyProperty = newDateString;
referenceDate = new DateTime(1972, 4, 13);
Assert.AreEqual(referenceDate, vmTarget.Date);
}
}
}