Click here to Skip to main content
15,885,365 members
Articles / Desktop Programming / WPF

Catel - Part 4 of n: Unit testing with Catel

Rate me:
Please Sign up or sign in to vote.
4.55/5 (10 votes)
28 Jan 2011CPOL11 min read 48.9K   572   11  
This article explains how to write unit tests for MVVM using Catel.
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="PropertyDataManager.cs" company="Catel development team">
//   Copyright (c) 2008 - 2011 Catel development team. All rights reserved.
// </copyright>
// <summary>
//   Property data manager.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml.Serialization;

namespace Catel.Data
{
    /// <summary>
    /// Property data manager.
    /// </summary>
    internal class PropertyDataManager
    {
        #region Variables
        /// <summary>
        /// Dictionary containing all the properties per type.
        /// </summary>
        private readonly Dictionary<Type, Dictionary<string, PropertyData>> _propertyData = new Dictionary<Type, Dictionary<string, PropertyData>>();

        /// <summary>
        /// Lock object for the <see cref="_propertyData"/> field.
        /// </summary>
        private readonly object _propertyDataLock = new object();

        /// <summary>
        /// Dictionary to provide fast xml name to property name mappings.
        /// </summary>
        private readonly Dictionary<Type, Dictionary<string, string>> _xmlNameToPropertyNameMappings = new Dictionary<Type, Dictionary<string, string>>();

        /// <summary>
        /// Dictionary to provide fast property name to xml name mappings.
        /// </summary>
        private readonly Dictionary<Type, Dictionary<string, string>> _xmlPropertyNameToXmlNameMappings = new Dictionary<Type, Dictionary<string, string>>();
        #endregion

        #region Constructor & destructor
        #endregion

        #region Properties
        #endregion

        #region Methods
        /// <summary>
        /// Gets the properties of a specific type.
        /// </summary>
        /// <param name="type">The type for which the properties to return.</param>
        /// <returns>Dictionary with the properties.</returns>
        public Dictionary<string, PropertyData> GetProperties(Type type)
        {
            return _propertyData.ContainsKey(type) ? _propertyData[type] : new Dictionary<string, PropertyData>();
        }

        /// <summary>
        /// Registers a property for a specific type.
        /// </summary>
        /// <param name="type">The type for which to register the property.</param>
        /// <param name="name">The name of the property.</param>
        /// <param name="propertyData">The property data.</param>
        public void RegisterProperty(Type type, string name, PropertyData propertyData)
        {
            lock (_propertyDataLock)
            {
                if (!_propertyData.ContainsKey(type))
                {
                	_propertyData.Add(type, new Dictionary<string, PropertyData>());
                }

                if (_propertyData[type].ContainsKey(name))
                {
                	throw new PropertyAlreadyRegisteredException(name, type);
                }

                _propertyData[type].Add(name, propertyData);
            }
        }

        /// <summary>
        /// Returns whether a specific property is registered.
        /// </summary>
        /// <param name="type">The type for which to check whether the property is registered.</param>
        /// <param name="name">The name of the property.</param>
        /// <returns>
        /// True if the property is registered, otherwise false.
        /// </returns>
        public bool IsPropertyRegistered(Type type, string name)
        {
            lock (_propertyDataLock)
            {
                if (_propertyData.ContainsKey(type))
                {
                    return _propertyData[type].ContainsKey(name);
                }

                return false;
            }
        }

        /// <summary>
        /// Gets the property data.
        /// </summary>
        /// <param name="type">The type for which to get the property data.</param>
        /// <param name="name">The name of the property.</param>
        /// <returns>The <see cref="PropertyData"/> of the requested property.</returns>
        /// <exception cref="PropertyNotRegisteredException">Thrown when the property is not registered.</exception>
        public PropertyData GetPropertyData(Type type, string name)
        {
            if (!IsPropertyRegistered(type, name))
            {
            	throw new PropertyNotRegisteredException(name, type);
            }

            lock (_propertyDataLock)
            {
                return _propertyData[type][name];
            }
        }

        /// <summary>
        /// Maps the name of the XML element to a property name.
        /// </summary>
        /// <param name="type">The type for which to make the xml name.</param>
        /// <param name="xmlName">Name of the XML element.</param>
        /// <returns>
        /// Name of the property that represents the xml value.
        /// </returns>
        public string MapXmlNameToPropertyName(Type type, string xmlName)
        {
            InitializeXmlPropertyMappings(type);

            return _xmlNameToPropertyNameMappings[type][xmlName];
        }

        /// <summary>
        /// Maps the name of the property name to an XML name.
        /// </summary>
        /// <param name="type">The type for which to make the xml name.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <returns>
        /// Name of the XML element that represents the property value.
        /// </returns>
        public string MapPropertyNameToXmlName(Type type, string propertyName)
        {
            InitializeXmlPropertyMappings(type);

            return _xmlPropertyNameToXmlNameMappings[type][propertyName];
        }

        /// <summary>
        /// Initializes the XML property mappings.
        /// </summary>
        /// <param name="type">The type for which to initialize the xml mappings.</param>
        private void InitializeXmlPropertyMappings(Type type)
        {
            if (_xmlNameToPropertyNameMappings.ContainsKey(type))
            {
            	return;
            }

            _xmlNameToPropertyNameMappings.Add(type, new Dictionary<string, string>());
            _xmlPropertyNameToXmlNameMappings.Add(type, new Dictionary<string, string>());

            foreach (KeyValuePair<string, PropertyData> propertyData in GetProperties(type))
            {
                PropertyInfo propertyInfo = TypeHelper.GetPropertyInfo(type, propertyData.Key);
                XmlElementAttribute xmlElementAttribute;
                if (AttributeHelper.TryGetAttribute(propertyInfo, out xmlElementAttribute))
                {
                    _xmlNameToPropertyNameMappings[type].Add(xmlElementAttribute.ElementName, propertyData.Key);
                    _xmlPropertyNameToXmlNameMappings[type].Add(propertyData.Key, xmlElementAttribute.ElementName);
                }
                else
                {
                    _xmlNameToPropertyNameMappings[type].Add(propertyData.Key, propertyData.Key);
                    _xmlPropertyNameToXmlNameMappings[type].Add(propertyData.Key, propertyData.Key);
                }
            }
        }
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Netherlands Netherlands
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions