using System;
using System.ComponentModel;
using System.IO;
using Catel.Data;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Catel.Test.Data
{
[TestClass]
public class DataObjectBaseTest
{
#region Variables
private FilesHelper _filesHelper = new FilesHelper();
#endregion
#region Initialization and cleanup
/// <summary>
/// Cleans up.
/// </summary>
[TestCleanup]
public void CleanUp()
{
if (_filesHelper != null)
{
_filesHelper.CleanUp();
_filesHelper = null;
}
}
#endregion
#region Equal tests
/// <summary>
/// Tests the Equals method 1 level deep.
/// </summary>
[TestMethod]
public void EqualsLevel1()
{
// Create 2 objects
var obj1 = DataObjectBaseTestHelper.CreateIniEntryObject();
var obj2 = DataObjectBaseTestHelper.CreateIniEntryObject();
// Equals
Assert.AreEqual(obj1, obj2);
}
/// <summary>
/// Tests the Equals method 2 level deep.
/// </summary>
[TestMethod]
public void EqualsLevel2()
{
// Create 2 objects
var obj1 = DataObjectBaseTestHelper.CreateIniFileObject();
var obj2 = DataObjectBaseTestHelper.CreateIniFileObject();
// Equals
Assert.AreEqual(obj1, obj2);
}
/// <summary>
/// Tests the Equals method 3 level deep.
/// </summary>
[TestMethod]
public void EqualsLevel3()
{
// Create 2 objects
var obj1 = DataObjectBaseTestHelper.CreateComputerSettingsObject();
var obj2 = DataObjectBaseTestHelper.CreateComputerSettingsObject();
// Equals
Assert.AreEqual(obj1, obj2);
}
[TestMethod]
public void Equals_AreNotEqual()
{
// Create 2 objects
var obj1 = DataObjectBaseTestHelper.CreateComputerSettingsObject();
var obj2 = DataObjectBaseTestHelper.CreateIniFileObject();
// Equals
Assert.AreNotEqual(obj1, obj2);
}
#endregion
#region Parent/child tests
/// <summary>
/// Tests the parent and child relations.
/// </summary>
[TestMethod]
public void TestParentAndChildRelationsWhenCreating()
{
Parent parent = new Parent("Parent");
Child child = parent.CreateChild("Child");
Assert.AreEqual(parent, ((IParent)child).Parent);
}
#if !SILVERLIGHT
/// <summary>
/// Tests the parent and child relations after deserialization.
/// </summary>
[TestMethod]
public void TestParentAndChildRelationsWhenBinaryDeserializing()
{
Parent parent = new Parent("Parent");
Child child = parent.CreateChild("Child");
Assert.AreEqual(((IParent)child).Parent, parent);
string fileName = _filesHelper.GetTempFileName();
parent.Save(fileName);
var loadedParent = SavableDataObjectBase<Parent>.Load(fileName);
Assert.AreEqual(parent, ((IParent)loadedParent.Children[0]).Parent);
}
#endif
/// <summary>
/// Tests the parent and child relations after deserialization.
/// </summary>
[TestMethod]
public void TestParentAndChildRelationsWhenXmlDeserializing()
{
Parent parent = new Parent("Parent");
Child child = parent.CreateChild("Child");
Assert.AreEqual(((IParent)child).Parent, parent);
Parent loadedParent;
using (MemoryStream memoryStream = new MemoryStream())
{
parent.Save(memoryStream, SerializationMode.Xml);
memoryStream.Position = 0L;
loadedParent = SavableDataObjectBase<Parent>.Load(memoryStream, SerializationMode.Xml);
}
Assert.AreEqual(parent, ((IParent)loadedParent.Children[0]).Parent);
}
#endregion
#region Multiple inheritance tests
/// <summary>
/// Creates the and verify properties on inherited class. This test is used to determine
/// if the properties defined in a derived class are also registered properly.
/// </summary>
[TestMethod]
public void CreateAndVerifyPropertiesOnInheritedClass()
{
// Create extend ini entry
ExtendedIniEntry extendedIniEntry = new ExtendedIniEntry();
// Try to set original properties
extendedIniEntry.Value = "MyValue";
// Try to set new properties
extendedIniEntry.DefaultValue = "DefaultValue";
}
#endregion
#region Read-only tests
[TestMethod]
public void ReadOnlyTest()
{
// Declare variables
const string testValue = "new value that shouldn't exist";
string originalValue, actualValue;
IniEntry iniEntry = DataObjectBaseTestHelper.CreateIniEntryObject();
// Test whether the object can be set to read-only
originalValue = iniEntry.Value;
iniEntry.SetReadOnly(true);
iniEntry.Value = testValue;
actualValue = iniEntry.Value;
Assert.AreEqual(originalValue, actualValue);
// Test whether the object can be set to edit mode again
iniEntry.SetReadOnly(false);
iniEntry.Value = testValue;
actualValue = iniEntry.Value;
Assert.AreEqual(testValue, actualValue);
}
#endregion
#region Validation
[TestMethod]
public void ValidationWithWarnings()
{
// Create object
ObjectWithValidation validationObject = new ObjectWithValidation();
// Check if the object now has warnings
Assert.AreEqual(false, validationObject.HasWarnings);
Assert.AreEqual(false, validationObject.HasErrors);
Assert.AreEqual(0, validationObject.FieldWarningCount);
Assert.AreEqual(0, validationObject.FieldErrorCount);
Assert.AreEqual(0, validationObject.BusinessRuleWarningCount);
Assert.AreEqual(0, validationObject.BusinessRuleErrorCount);
// Now set a field warning and check it
validationObject.ValueToValidate = ObjectWithValidation.ValueThatCausesFieldWarning;
Assert.AreEqual(true, validationObject.HasWarnings);
Assert.AreEqual(false, validationObject.HasErrors);
Assert.AreEqual(1, validationObject.FieldWarningCount);
Assert.AreEqual(0, validationObject.FieldErrorCount);
Assert.AreEqual(0, validationObject.BusinessRuleWarningCount);
Assert.AreEqual(0, validationObject.BusinessRuleErrorCount);
// Now set a business warning and check it
validationObject.ValueToValidate = ObjectWithValidation.ValueThatCausesBusinessWarning;
Assert.AreEqual(true, validationObject.HasWarnings);
Assert.AreEqual(false, validationObject.HasErrors);
Assert.AreEqual(0, validationObject.FieldWarningCount);
Assert.AreEqual(0, validationObject.FieldErrorCount);
Assert.AreEqual(1, validationObject.BusinessRuleWarningCount);
Assert.AreEqual(0, validationObject.BusinessRuleErrorCount);
// Clear warning
validationObject.ValueToValidate = ObjectWithValidation.ValueThatHasNoWarningsOrErrors;
Assert.AreEqual(false, validationObject.HasWarnings);
Assert.AreEqual(false, validationObject.HasErrors);
Assert.AreEqual(0, validationObject.FieldWarningCount);
Assert.AreEqual(0, validationObject.FieldErrorCount);
Assert.AreEqual(0, validationObject.BusinessRuleWarningCount);
Assert.AreEqual(0, validationObject.BusinessRuleErrorCount);
}
[TestMethod]
public void ValidationWithErrors()
{
// TODO: fix
}
#endregion
#if !SILVERLIGHT
#region Allow non serializable members tests
[TestMethod]
[ExpectedException(typeof(InvalidPropertyException), "object should crash because it contains a non-serializable value, but is not decorated with the AllowNonSerializableMembersAttribute")]
public void ObjectWithoutAllowNonSerializableAttribute()
{
var obj = new ObjectWithNonSerializableMembers();
}
[TestMethod]
public void ObjectWithAllowNonSerializableAttribute()
{
var obj = new ObjectWithNonSerializableMembersDecoratedWithAllowNonSerializableMembersAttribute();
}
#endregion
#endif
#region IClonable tests
/// <summary>
/// Tests the deep-clone functionality for 1 level deep.
/// </summary>
public void CloneLevel1()
{
// Create object
var obj = DataObjectBaseTestHelper.CreateIniEntryObject();
// Clonse
var clonedObj = obj.Clone();
// Make sure the objects are equal
Assert.AreEqual(obj, clonedObj);
}
/// <summary>
/// Tests the deep-clone functionality for 2 levels deep.
/// </summary>
public void CloneLevel2()
{
// Create object
var obj = DataObjectBaseTestHelper.CreateIniFileObject();
// Clonse
var clonedObj = obj.Clone();
// Make sure the objects are equal
Assert.AreEqual(obj, clonedObj);
}
/// <summary>
/// Tests the deep-clone functionality for 3 levels deep.
/// </summary>
public void CloneLevel3()
{
// Create object
var obj = DataObjectBaseTestHelper.CreateComputerSettingsObject();
// Clonse
var clonedObj = obj.Clone();
// Make sure the objects are equal
Assert.AreEqual(obj, clonedObj);
}
#endregion
#region IDisposable tests
[TestMethod]
public void UninitializedCallWithoutDirectDispose()
{
// Declare variables
IniEntry iniEntry = new IniEntry();
// Set to null
iniEntry = null;
}
[TestMethod]
public void UninitializedCallWithDirectDispose()
{
// Declare variables
IniEntry iniEntry = new IniEntry();
// Dispose
iniEntry.Dispose();
}
#endregion
#region IEditableObject tests
[TestMethod]
public void EditAndCancelChanges()
{
// Get value
var iniEntry = DataObjectBaseTestHelper.CreateIniEntryObject();
// Set the value we expect
iniEntry.Value = "MyOldValue";
// Begin edit
iniEntry.BeginEdit();
// Change value
iniEntry.Value = "MyNewValue";
// Cancel edit
iniEntry.CancelEdit();
// Compare
Assert.AreEqual("MyOldValue", iniEntry.Value);
}
[TestMethod]
public void EditAndCancelChanges_ObjectWithCustomType()
{
// Get value
var obj = new ObjectWithCustomType();
// Set the value we expect
obj.Gender = Gender.Female;
// Begin edit
obj.BeginEdit();
// Change value
obj.Gender = Gender.Male;
// Cancel edit
obj.CancelEdit();
// Compare
Assert.AreEqual(Gender.Female, obj.Gender);
}
[TestMethod]
public void EditAndApplyChanges()
{
// Get value
var iniEntry = DataObjectBaseTestHelper.CreateIniEntryObject();
// Set the value we expect
iniEntry.Value = "MyOldValue";
// Begin edit
iniEntry.BeginEdit();
// Change value
iniEntry.Value = "MyNewValue";
// End edit
iniEntry.EndEdit();
// Compare
Assert.AreEqual("MyNewValue", iniEntry.Value);
}
[TestMethod]
public void EditAndApplyChanges_ObjectWithCustomType()
{
// Get value
var obj = new ObjectWithCustomType();
// Set the value we expect
obj.Gender = Gender.Female;
// Begin edit
obj.BeginEdit();
// Change value
obj.Gender = Gender.Male;
// End edit
obj.EndEdit();
// Compare
Assert.AreEqual(Gender.Male, obj.Gender);
}
#endregion
#if !SILVERLIGHT
#region INotifyPropertyChanging tests
/// <summary>
/// Tests whether INotifyPropertyChanging is implemented correctly.
/// </summary>
[TestMethod]
public void NotifyPropertyChanging()
{
// Create object
var obj = DataObjectBaseTestHelper.CreateIniEntryObject();
// Get variable
bool isInvoked = false;
// Subscribe
obj.PropertyChanging += delegate(object sender, PropertyChangingEventArgs e)
{
// If we were invoked, exit (we only want to check the first event)
if (isInvoked)
{
return;
}
// Invoked
isInvoked = true;
// Check property
if (string.Compare(e.PropertyName, "Value") != 0)
{
Assert.Fail("Wrong PropertyChanging property name");
}
};
// Change value
obj.Value = "MyNewValue";
// Check if invoked);
if (!isInvoked)
{
Assert.Fail("PropertyChanging was not invoked");
}
}
#endregion
#endif
#region INotifyPropertyChanged tests
/// <summary>
/// Tests whether INotifyPropertyChanged is implemented correctly.
/// </summary>
[TestMethod]
public void NotifyPropertyChanged()
{
// Create object
var obj = DataObjectBaseTestHelper.CreateIniEntryObject();
// Get variable
bool isInvoked = false;
// Subscribe
obj.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
{
// Invoked
isInvoked = true;
// Check property
if (string.Compare(e.PropertyName, "Value") != 0)
{
Assert.Fail("Wrong PropertyChanged property name");
}
};
// Change value
obj.Value = "MyNewValue";
// Check if invoked);
if (!isInvoked)
{
Assert.Fail("PropertyChanged was not invoked");
}
}
#endregion
#region IDataErrorInfo tests
/// <summary>
/// Tests whether IDataErrorInfo is implemented correctly.
/// </summary>
[TestMethod]
public void IDataErrorInfo()
{
// Create object
var obj = DataObjectBaseTestHelper.CreateIniEntryObject();
// Set an error
obj.Value = string.Empty;
// Validate the object
obj.Validate();
// Make sure that the error is raised
Assert.IsFalse(string.IsNullOrEmpty(((IDataErrorInfo)obj)["Value"]));
}
#endregion
#region IsDirty with children test
[TestMethod]
public void IsDirtyWithChildrenWhenSavingChild()
{
// Create a collection
var computerSettings = DataObjectBaseTestHelper.CreateComputerSettingsObject();
SaveObjectToMemoryStream(computerSettings);
Assert.IsFalse(computerSettings.IsDirty);
// Make a chance in the lowest level
computerSettings.IniFileCollection[0].IniEntryCollection[0].Value = "is dirty should be enabled now";
Assert.IsTrue(computerSettings.IniFileCollection[0].IniEntryCollection[0].IsDirty);
Assert.IsTrue(computerSettings.IsDirty);
// Save the lowest level (so the parent stays dirty)
SaveObjectToMemoryStream(computerSettings.IniFileCollection[0].IniEntryCollection[0]);
Assert.IsFalse(computerSettings.IniFileCollection[0].IniEntryCollection[0].IsDirty);
Assert.IsTrue(computerSettings.IsDirty);
}
[TestMethod]
public void IsDirtyWithChildrenWhenSavingParent()
{
// Create a collection
var computerSettings = DataObjectBaseTestHelper.CreateComputerSettingsObject();
SaveObjectToMemoryStream(computerSettings);
Assert.IsFalse(computerSettings.IsDirty);
// Make a chance in the lowest level
computerSettings.IniFileCollection[0].IniEntryCollection[0].Value = "is dirty should be enabled now";
Assert.IsTrue(computerSettings.IniFileCollection[0].IniEntryCollection[0].IsDirty);
Assert.IsTrue(computerSettings.IsDirty);
// Save the top level
SaveObjectToMemoryStream(computerSettings);
Assert.IsFalse(computerSettings.IniFileCollection[0].IniEntryCollection[0].IsDirty);
Assert.IsFalse(computerSettings.IsDirty);
}
#endregion
/// <summary>
/// Saves the object to memory stream so the <see cref="IDataObjectBase.IsDirty"/> property is set to false.
/// </summary>
/// <param name="obj">The object.</param>
private static void SaveObjectToMemoryStream(ISavableDataObjectBase obj)
{
using (MemoryStream memoryStream = new MemoryStream())
{
obj.Save(memoryStream);
}
}
}
}