/// <summary>
        /// Clones the given <see cref="System.Collections.IEnumerable"/> concrete implementation
        /// </summary>
        /// <param name="enumerable">The <see cref="System.Collections.IEnumerable"/> to clone</param>
        /// <param name="configuration">Configuration to use to determine how to clone the whole enumerable</param>
        /// <returns>The cloned enumerable</returns>
        internal static IEnumerable CloneEnumerable(this IEnumerable enumerable, IObjectChangeTrackingConfiguration configuration)
        {
            Contract.Requires(() => enumerable != null, "Given enumerable must be a non-null reference");

            Type collectionType     = configuration.Collections.GetImplementation(enumerable.GetType()).Value.Type;
            Type collectionItemType = enumerable.GetCollectionItemType();

            List <Type> collectionTypeArguments = new List <Type>();

            if (collectionItemType.GetTypeInfo().IsGenericType&& collectionItemType.GetGenericTypeDefinition() == typeof(KeyValuePair <,>))
            {
                collectionTypeArguments.AddRange(collectionItemType.GenericTypeArguments);
            }
            else
            {
                collectionTypeArguments.Add(enumerable.GetCollectionItemType());
            }

            IEnumerable collectionClone = (IEnumerable)collectionType
                                          .CreateInstanceWithGenericArgs(null, collectionTypeArguments.ToArray());

            Type collectionInterface = collectionClone.GetType()
                                       .GetInterfaces()
                                       .Single(t => t.GetTypeInfo().IsGenericType&& t.GetGenericTypeDefinition() == typeof(ICollection <>));

            MethodInfo addMethod = collectionInterface.GetMethod("Add", BindingFlags.Instance | BindingFlags.Public);

            foreach (object item in enumerable)
            {
                addMethod.Invoke(collectionClone, new[] { item });
            }

            return(collectionClone);
        }
        public static void Init(TestContext context)
        {
            Configuration = ObjectChangeTracking.CreateConfiguration()
                            .TrackThisType <A>()
                            .TrackThisType <TestDynamicObject>();

            TrackableObjectFactory = Configuration.CreateTrackableObjectFactory();
        }
        public static void Init(TestContext context)
        {
            IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();

            config.TrackThisType <IWhatever>();

            TrackableObjectFactory = config.CreateTrackableObjectFactory();
        }
示例#4
0
        public void Initialize()
        {
            IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();

            config.TrackThisTypeRecursive <Class0>();

            _trackableObjectFactory = config.CreateTrackableObjectFactory();
        }
示例#5
0
        /// <summary>
        /// Default constructor
        /// </summary>
        /// <param name="targetObject">The object to track its changes</param>
        public ObjectChangeTracker(IObjectChangeTrackingConfiguration configuration, ITrackableObjectFactoryInternal trackableObjectFactory, object targetObject)
        {
            Contract.Requires(() => targetObject != null);

            Configuration          = configuration;
            TrackableObjectFactory = trackableObjectFactory;
            _targetObject          = targetObject;
            _targetObjectType      = targetObject.GetType();
        }
示例#6
0
 public ObjectPropertyChangeTracking(IObjectChangeTrackingConfiguration configuration, ITrackableObjectFactoryInternal trackableObjectFactory, ObjectChangeTracker tracker, object targetObject, string propertyName, object currentValue)
 {
     Configuration          = configuration;
     TrackableObjectFactory = trackableObjectFactory;
     _tracker      = tracker;
     _targetObject = targetObject;
     PropertyName  = propertyName;
     OldValue      = currentValue;
     CurrentValue  = currentValue;
 }
示例#7
0
 public DeclaredObjectPropertyChangeTracking(IObjectChangeTrackingConfiguration configuration, ITrackableObjectFactoryInternal trackableObjectFactory, ObjectChangeTracker tracker, object targetObject, PropertyInfo ownerProperty, PropertyInfo property, object currentValue)
 {
     Configuration          = configuration;
     TrackableObjectFactory = trackableObjectFactory;
     Tracker      = tracker;
     TargetObject = targetObject;
     Property     = property;
     OldValue     = currentValue;
     CurrentValue = currentValue;
 }
示例#8
0
        public TrackableType(IObjectChangeTrackingConfiguration configuration, Type type)
        {
            //Contract.Requires(type != null, "Give type reference must be non-null");
            Contract.Assert((type.IsClass && !type.IsSealed) || type.IsInterface, $"Given type '{type.AssemblyQualifiedName}' must be either a non-sealed class or an interface");

            _type        = type;
            _objectPaths = new Lazy <IImmutableSet <IObjectPropertyInfo> >
                           (
                () => Type.BuildAllPropertyPaths(p => configuration.CanTrackType(p.DeclaringType))
                .Cast <IObjectPropertyInfo>()
                .ToImmutableHashSet()
                           );
        }
        public void CanConfigureAbstractClass()
        {
            IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();

            config.TrackTypesFromAssembly(typeof(ConfigurationTest).GetTypeInfo().Assembly, searchSettings: new TypeSearchSettings
            {
                Mode = TypeSearchMode.AttributeConfigurationOnly,
                /*Filter = t => t == typeof(AbstractClass) || t == typeof(DerivesAbstractClass),*/
                Recursive = true
            });

            ITrackableObjectFactory factory = config.CreateTrackableObjectFactory();
            var x = factory.CreateFrom(new DerivesAbstractClass());
        }
示例#10
0
        public void ConfiguresClassWithAllPropertiesExceptingNonTrackable()
        {
            IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();

            config.TrackTypesFromAssembly(typeof(ConfigurationTest).GetTypeInfo().Assembly, searchSettings: new TypeSearchSettings
            {
                Mode   = TypeSearchMode.AttributeConfigurationOnly,
                Filter = t => t == typeof(TwoPropertiesOneTrackable)
            });

            ITrackableType trackableType = config.TrackableTypes.Single();

            Assert.AreEqual(1, trackableType.IncludedProperties.Count);
            Assert.AreEqual("Text", trackableType.IncludedProperties.Single().Name);
        }
示例#11
0
        public void CanConfigureClassWithMultipleConstructors()
        {
            IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();

            config.TrackTypesFromAssembly(typeof(ConfigurationTest).GetTypeInfo().Assembly, searchSettings: new TypeSearchSettings
            {
                Mode   = TypeSearchMode.AttributeConfigurationOnly,
                Filter = t => t == typeof(WithMultipleConstructors)
            });

            ITrackableObjectFactory factory = config.CreateTrackableObjectFactory();

            WithMultipleConstructors instance = factory.CreateFrom(new WithMultipleConstructors());

            Assert.IsNotNull(instance);
        }
示例#12
0
        public void ConfiguresClassWithAllProperties()
        {
            IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();

            config.TrackTypesFromAssembly(typeof(ConfigurationTest).GetTypeInfo().Assembly, searchSettings: new TypeSearchSettings
            {
                Mode   = TypeSearchMode.AttributeConfigurationOnly,
                Filter = t => t == typeof(AllProperties)
            });

            ITrackableType trackableType = config.TrackableTypes.Single();

            Assert.AreEqual(2, trackableType.IncludedProperties.Count);
            Assert.IsTrue(trackableType.IncludedProperties.Any(p => p.Name == "Text"));
            Assert.IsTrue(trackableType.IncludedProperties.Any(p => p.Name == "Text2"));
        }
示例#13
0
        public static void Init(TestContext context)
        {
            Configuration = ObjectChangeTracking.CreateConfiguration()
                            .TrackThisType <A>(t => t.IncludeProperty(a => a.Items))
                            .TrackThisType <B>(t => t.IncludeProperty(b => b.Dogs))
                            .TrackThisType <C>(t => t.IncludeProperty(c => c.Dogs))
                            .TrackThisType <Dog>(t => t.IncludeProperty(d => d.Name))
                            .TrackThisType <D>()
                            .TrackThisType <E>(t => t.IncludeProperty(e => e.Dictionary))
                            .TrackThisType <F>(t => t.IncludeProperty(f => f.ListOfF))
                            .TrackThisType <G>(t => t.IncludeProperty(g => g.Buffer))
                            .TrackThisType <WhateverBase>(t => t.IncludeProperty(w => w.List2))
                            .TrackThisType <WhateverParent>(t => t.IncludeProperty(w => w.List));

            TrackableObjectFactory = Configuration.CreateTrackableObjectFactory();
        }
示例#14
0
        public void CanConfigureWithNestedTypes()
        {
            IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();

            config.TrackTypesFromAssembly(typeof(ConfigurationTest).GetTypeInfo().Assembly, searchSettings: new TypeSearchSettings
            {
                Mode   = TypeSearchMode.AttributeConfigurationOnly,
                Filter = t => t == typeof(ClassWithNestedEnum) || t == typeof(DerivedClassWithNestedEnum)
            });

            ITrackableObjectFactory factory = config.CreateTrackableObjectFactory();

            DerivedClassWithNestedEnum instance = factory.CreateOf <DerivedClassWithNestedEnum>();

            Assert.IsNotNull(instance);
        }
        /// <summary>
        /// Iterates the given enumerable and returns an instance of given target collection type configured implementation
        /// where each item will be also converted to untracked objects.
        /// </summary>
        /// <param name="enumerable">The whole enumerable to untrack</param>
        /// <param name="targetCollectionType">The whole target collection type. This type should be a supported trackable collection type</param>
        /// <returns>A copy of source enumerable turned into an untracked collection</returns>
        public static IEnumerable ToUntrackedEnumerable(this IEnumerable enumerable, Type targetCollectionType)
        {
            Contract.Requires(() => targetCollectionType != null, "Target collection type cannot be a non-null reference");

            if (enumerable != null)
            {
                Type collectionItemType = enumerable.GetCollectionItemType();

                List <Type> collectionTypeArguments = new List <Type>();

                if (collectionItemType.GetTypeInfo().IsGenericType&& collectionItemType.GetGenericTypeDefinition() == typeof(KeyValuePair <,>))
                {
                    collectionTypeArguments.AddRange(collectionItemType.GenericTypeArguments);
                }
                else
                {
                    collectionTypeArguments.Add(enumerable.GetCollectionItemType());
                }

                IObjectChangeTrackingConfiguration configuration = ((IChangeTrackableCollection)enumerable).GetChangeTrackingContext().Configuration;

                IEnumerable enumerableCopy =
                    (IEnumerable)configuration.Collections.GetImplementation(targetCollectionType)
                    .Value.Type.CreateInstanceWithGenericArgs(null, collectionTypeArguments.ToArray());

                Type collectionInterface = enumerableCopy.GetType()
                                           .GetInterfaces()
                                           .Single(t => t.GetTypeInfo().IsGenericType&& t.GetGenericTypeDefinition() == typeof(ICollection <>));

                MethodInfo addMethod = collectionInterface.GetMethod("Add", BindingFlags.Instance | BindingFlags.Public);

                Contract.Assert(() => addMethod != null);

                foreach (object item in enumerable)
                {
                    addMethod.Invoke(enumerableCopy, new[] { item.ToUntypedUntracked() });
                }

                return(enumerableCopy);
            }
            else
            {
                return(null);
            }
        }
示例#16
0
        public void ConfiguresWithAttributesOnly()
        {
            IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();

            config.TrackTypesFromAssembly(typeof(ConfigurationTest).Assembly, searchSettings: new TypeSearchSettings
            {
                Mode   = TypeSearchMode.AttributeConfigurationOnly,
                Filter = t => t.ReflectedType == typeof(ConfigurationTest)
            });

            IList <Type> trackables = config.TrackableTypes.Select(t => t.Type).ToList();

            Assert.IsTrue(config.TrackableTypes.Count > 0);
            Assert.IsTrue(trackables.Contains(typeof(AllProperties)));
            Assert.IsTrue(trackables.Contains(typeof(AllPropertiesExceptingNonTrackable)));
            Assert.IsTrue(trackables.Contains(typeof(TwoPropertiesOneTrackable)));
            Assert.IsFalse(trackables.Contains(typeof(NoAttributes)));
        }
示例#17
0
        public void CanConfigureClassWithReadOnlyProperties()
        {
            IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();

            config.TrackTypesFromAssembly(typeof(ConfigurationTest).GetTypeInfo().Assembly, searchSettings: new TypeSearchSettings
            {
                Mode   = TypeSearchMode.AttributeConfigurationOnly,
                Filter = t => t == typeof(ClassWithReadOnlyProperties)
            });

            ITrackableObjectFactory factory = config.CreateTrackableObjectFactory();

            ClassWithReadOnlyProperties instance = factory.CreateFrom(new ClassWithReadOnlyProperties());

            instance.Text = "hey";

            IObjectChangeTracker tracker = instance.GetChangeTracker();

            Assert.AreEqual(1, tracker.ChangedProperties.Count);
            Assert.AreEqual(1, ((ObjectChangeTracker)tracker).PropertyTrackings.Count);
        }
示例#18
0
        public void CanConfigureNonTrackablePropertiesFromBaseClasses()
        {
            IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();

            config.TrackTypesFromAssembly(typeof(ConfigurationTest).GetTypeInfo().Assembly, searchSettings: new TypeSearchSettings
            {
                Mode      = TypeSearchMode.AttributeConfigurationOnly,
                Recursive = true,
                Filter    = t =>
                {
                    return(t.DeclaringType == typeof(ConfigurationTest));
                }
            });

            ITrackableObjectFactory trackableObjectFactory      = config.CreateTrackableObjectFactory();
            DerivedClassOfBaseClassWithNonTrackableProperty obj = trackableObjectFactory.CreateOf <DerivedClassOfBaseClassWithNonTrackableProperty>();

            IObjectChangeTracker changeTracker = obj.GetChangeTracker();

            Assert.AreEqual(1, changeTracker.Count());
            Assert.IsTrue(changeTracker.First().PropertyName == "Text2");
        }
        // TODO: Remove?
        /// <summary>
        /// Turns all objects into change-trackable ones found in the given sequence.
        /// </summary>
        /// <typeparam name="T">The type of objects</typeparam>
        /// <param name="enumerable">The sequence of objects to turn into change-trackable ones</param>
        /// <param name="parentObjectProperty">The collection property representing the association to some object</param>
        /// <param name="parentObject">The parent object that owns the association of the collection</param>
        /// <returns>The already converted objects into change-trackable ones</returns>
        public static IEnumerable <T> MakeAllTrackable <T>(this IEnumerable <T> enumerable, IObjectChangeTrackingConfiguration configuration, ITrackableObjectFactory trackableObjectFactory, PropertyInfo parentObjectProperty, IChangeTrackableObject parentObject)
            where T : class
        {
            Contract.Requires(() => enumerable != null, "Given enumerable must be a non-null reference to turn its objects into trackable ones");
            Contract.Requires(() => parentObjectProperty != null, "A reference to property which holds the enumerable is mandatory");
            Contract.Requires(() => parentObject != null, "The instance of the object where the property holding the enumerable is declared is mandatory");
            Contract.Requires(() => parentObjectProperty.DeclaringType.GetActualTypeIfTrackable().IsAssignableFrom(parentObject.GetActualTypeIfTrackable()), "Given property holding the enumerable must be declared on the given parent object type");

            if (enumerable.Count() > 0 &&
                configuration.CanTrackType(enumerable.First().GetType()))
            {
                List <T> result = new List <T>();

                foreach (T item in enumerable)
                {
                    IChangeTrackableObject trackableObject = item as IChangeTrackableObject;

                    if (trackableObject == null)
                    {
                        trackableObject = (IChangeTrackableObject)trackableObjectFactory.CreateFrom(item);

                        trackableObject.PropertyChanged += (sender, e) =>
                                                           parentObject.RaisePropertyChanged(parentObject, parentObjectProperty.Name);
                    }

                    result.Add((T)trackableObject);
                }

                Contract.Assert(() => result.Count == enumerable.Count(), "New sequence with objects turned into trackable ones must match the count of source sequence");

                return(result);
            }
            else
            {
                return(enumerable);
            }
        }
示例#20
0
 public TrackableType(IObjectChangeTrackingConfiguration configuration)
     : base(configuration, typeof(T))
 {
 }
 public ChangeTrackableObjectMixin(IObjectChangeTrackingConfiguration configuration, ITrackableObjectFactoryInternal trackableObjectFactory)
 {
     ChangeTrackingContext.Configuration = configuration;
     TrackableObjectFactory = trackableObjectFactory;
 }
示例#22
0
        public void CanReplaceCollectionChangeTrackingImplementation()
        {
            IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();

            config.Collections.AddOrUpdateImplementation <ICollection <string>, List <string>, DefaultCollectionChangeInterceptor <string> >();
        }
示例#23
0
 public SimplePropertyInterceptionHook(IObjectChangeTrackingConfiguration configuration)
 {
     Configuration = configuration;
 }
 public TrackableObjectFactoryInternal(IObjectChangeTrackingConfiguration configuration)
 {
     Configuration = configuration;
 }
 public CollectionPropertyInterceptor(IObjectChangeTrackingConfiguration configuration, ITrackableObjectFactory trackableObjectFactory)
 {
     Configuration          = configuration;
     TrackableObjectFactory = trackableObjectFactory;
 }
 public AttributeConfigurationBuilder(IObjectChangeTrackingConfiguration config)
 {
     Configuration = config;
 }
示例#27
0
 public DynamicObjectInterceptor(IObjectChangeTrackingConfiguration configuration, ITrackableObjectFactory trackableObjectFactory)
 {
     Configuration          = configuration;
     TrackableObjectFactory = trackableObjectFactory;
 }