Skip to content

Commit

Permalink
Solving issues #14 #16
Browse files Browse the repository at this point in the history
  • Loading branch information
mfidemraizer committed Aug 16, 2016
1 parent 8640f89 commit f73eb17
Show file tree
Hide file tree
Showing 19 changed files with 328 additions and 31 deletions.
4 changes: 2 additions & 2 deletions TrackerDog.NuGet.Signed/TrackerDog.NuGet.Signed.nuproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@
<Import Project="$(NuProjPath)\NuProj.props" Condition="Exists('$(NuProjPath)\NuProj.props')" />
<PropertyGroup Label="Configuration">
<Id>TrackerDog.Signed</Id>
<Version>2.1.0</Version>
<Version>2.1.1</Version>
<Title>TrackerDog: A generic .NET object change tracker (SIGNED)</Title>
<Authors>Matías Fidemraizer</Authors>
<Owners>Matías Fidemraizer</Owners>
<Summary>Track changes of any .NET object and full object graphs</Summary>
<Description>TrackerDog turns any .NET object or full object graph into a change-trackable object</Description>
<ReleaseNotes>See release notes here: https://github.com/mfidemraizer/trackerdog/releases/tag/v2.1.0</ReleaseNotes>
<ReleaseNotes>See release notes here: https://github.com/mfidemraizer/trackerdog/releases/tag/v2.1.1</ReleaseNotes>
<ProjectUrl>http://matiasfidemrazer.com/trackerdog/</ProjectUrl>
<LicenseUrl>https://github.com/mfidemraizer/trackerdog/blob/master/LICENSE</LicenseUrl>
<Copyright>Copyright © Matías Fidemraizer</Copyright>
Expand Down
4 changes: 2 additions & 2 deletions TrackerDog.NuGet/TrackerDog.NuGet.nuproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@
<Import Project="$(NuProjPath)\NuProj.props" Condition="Exists('$(NuProjPath)\NuProj.props')" />
<PropertyGroup Label="Configuration">
<Id>TrackerDog</Id>
<Version>2.1.0</Version>
<Version>2.1.1</Version>
<Title>TrackerDog: A generic .NET object change tracker</Title>
<Authors>Matías Fidemraizer</Authors>
<Owners>Matías Fidemraizer</Owners>
<Summary>Track changes of any .NET object and full object graphs</Summary>
<Description>TrackerDog turns any .NET object or full object graph into a change-trackable object</Description>
<ReleaseNotes>See release notes here: https://github.com/mfidemraizer/trackerdog/releases/tag/v2.1.0</ReleaseNotes>
<ReleaseNotes>See release notes here: https://github.com/mfidemraizer/trackerdog/releases/tag/v2.1.1</ReleaseNotes>
<ProjectUrl>http://matiasfidemrazer.com/trackerdog/</ProjectUrl>
<LicenseUrl>https://github.com/mfidemraizer/trackerdog/blob/master/LICENSE</LicenseUrl>
<Copyright>Copyright © Matías Fidemraizer</Copyright>
Expand Down
6 changes: 6 additions & 0 deletions TrackerDog.Signed/TrackerDog.Signed.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\TrackerDog\ChangeTrackableObjectState.cs">
<Link>ChangeTrackableObjectState.cs</Link>
</Compile>
<Compile Include="..\TrackerDog\CollectionHandling\CollectionChange.cs">
<Link>CollectionHandling\CollectionChange.cs</Link>
</Compile>
Expand Down Expand Up @@ -99,6 +102,9 @@
<Compile Include="..\TrackerDog\Configuration\IConfigurableTrackableType.cs">
<Link>Configuration\IConfigurableTrackableType.cs</Link>
</Compile>
<Compile Include="..\TrackerDog\Configuration\IConfigurableTrackableTypeContract.cs">
<Link>Configuration\IConfigurableTrackableTypeContract.cs</Link>
</Compile>
<Compile Include="..\TrackerDog\Configuration\IGenericConfigurableTrackableType.cs">
<Link>Configuration\IGenericConfigurableTrackableType.cs</Link>
</Compile>
Expand Down
123 changes: 121 additions & 2 deletions TrackerDog.Test/ConfigurationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class TwoPropertiesOneTrackable
{
[ChangeTrackable]
public virtual string Text { get; set; }

public virtual string Text2 { get; set; }
}

Expand All @@ -36,6 +36,56 @@ public class AllProperties
public virtual string Text2 { get; set; }
}

[ChangeTrackable]
public class ClassWithReadOnlyProperties
{
public virtual string Text { get; set; } = "hello world";
public virtual string Text2 { get; } = "hey";

public IList<string> Texts { get; } = new List<string>();

public virtual List<int> Numbers => new List<int> { 1, 2, 3 };
}

[ChangeTrackable]
public abstract class AbstractClass
{
public AbstractClass() { }
public AbstractClass(int a) { }

public virtual string Text { get; set; }
}

[ChangeTrackable]
public class DerivesAbstractClass : AbstractClass
{
}

[ChangeTrackable]
public class WithMultipleConstructors
{
public WithMultipleConstructors() { }
public WithMultipleConstructors(int a) { }
}

[ChangeTrackable]
public abstract class ClassWithNestedEnum
{
public enum Test
{
One
}

[ChangeTrackable]
public virtual Test TestEnumProperty { get; set; }
}

[ChangeTrackable]
public class DerivedClassWithNestedEnum : ClassWithNestedEnum
{

}

[TestMethod]
public void ConfiguresClassWithTwoPropertiesButOneIsTrackable()
{
Expand Down Expand Up @@ -97,11 +147,80 @@ public void ConfiguresWithAttributesOnly()

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

Assert.AreEqual(3, config.TrackableTypes.Count);
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)));
}

[TestMethod]
public void CanConfigureClassWithReadOnlyProperties()
{
IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();
config.TrackTypesFromAssembly(typeof(ConfigurationTest).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);
}

[TestMethod]
public void CanConfigureAbstractClass()
{
IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();
config.TrackTypesFromAssembly(typeof(ConfigurationTest).Assembly, searchSettings: new TypeSearchSettings
{
Mode = TypeSearchMode.AttributeConfigurationOnly,
Filter = t => t == typeof(AbstractClass) || t == typeof(DerivesAbstractClass)
});

ITrackableObjectFactory factory = config.CreateTrackableObjectFactory();
factory.CreateFrom(new DerivesAbstractClass());
}

[TestMethod]
public void CanConfigureClassWithMultipleConstructors()
{
IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();
config.TrackTypesFromAssembly(typeof(ConfigurationTest).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);
}

[TestMethod]
public void CanConfigureWithNestedTypes()
{
IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();
config.TrackTypesFromAssembly(typeof(ConfigurationTest).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);
}
}
}
47 changes: 41 additions & 6 deletions TrackerDog.Test/SimplePropertyTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Castle.DynamicProxy;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using TrackerDog.Configuration;
Expand All @@ -23,7 +24,9 @@ public static void Init(TestContext context)
.TrackThisType<E>(t => t.IncludeProperties(e => e.Text, e => e.Number))
.TrackThisType<Customer>(t => t.IncludeProperty(c => c.ContactInfo))
.TrackThisType<Contact>(t => t.IncludeProperty(c => c.Name))
.TrackThisType<EnhancedContact>(t => t.IncludeProperty(c => c.Default));
.TrackThisType<EnhancedContact>(t => t.IncludeProperty(c => c.Default))
.TrackThisType<ClassWithReadOnlyPropertyThrowingException>()
.TrackThisType<ClassSettingPropertiesDuringConstructionTime>(t => t.IncludeProperty(c => c.Text));

TrackableObjectFactory = Configuration.CreateTrackableObjectFactory();
}
Expand Down Expand Up @@ -53,23 +56,47 @@ public class D

public class E
{
public string Text { get; set; }
public int Number { get; set; }
public virtual string Text { get; set; }
public virtual int Number { get; set; }
}

public class Customer
{
public EnhancedContact ContactInfo { get; set; }
public virtual EnhancedContact ContactInfo { get; set; }
}

public class Contact
{
public string Name { get; set; }
public virtual string Name { get; set; }
}

public class EnhancedContact : Contact
{
public bool Default { get; set; }
public virtual bool Default { get; set; }
}

public class ClassWithReadOnlyPropertyThrowingException
{
public virtual string Text
{
get { throw new InvalidOperationException(); }
}
}

public class ClassSettingPropertiesDuringConstructionTime
{
public ClassSettingPropertiesDuringConstructionTime()
{
Text = "hello world";
}

public virtual string Text { get; set; }
}

[TestMethod]
public void CanTrackClassWithReadOnlyPropertiesThrowingExceptions()
{
TrackableObjectFactory.CreateOf<ClassWithReadOnlyPropertyThrowingException>();
}

[TestMethod]
Expand Down Expand Up @@ -410,5 +437,13 @@ public void CanGetOldAndCurrentValueAndCheckIfHasChanged()
Assert.AreEqual(changedValue, a.CurrentPropertyValue(i => i.Text));
Assert.IsTrue(a.PropertyHasChanged(i => i.Text));
}

[TestMethod]
public void CanSetPropertyOnConstructor()
{
ClassSettingPropertiesDuringConstructionTime some = TrackableObjectFactory.CreateOf<ClassSettingPropertiesDuringConstructionTime>();

Assert.AreEqual("hello world", some.Text);
}
}
}
44 changes: 44 additions & 0 deletions TrackerDog.Test/TrackerDog.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<CodeContractsAssemblyMode>0</CodeContractsAssemblyMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
Expand All @@ -25,6 +26,49 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
<CodeContractsNonNullObligations>True</CodeContractsNonNullObligations>
<CodeContractsBoundsObligations>True</CodeContractsBoundsObligations>
<CodeContractsArithmeticObligations>True</CodeContractsArithmeticObligations>
<CodeContractsEnumObligations>True</CodeContractsEnumObligations>
<CodeContractsRedundantAssumptions>True</CodeContractsRedundantAssumptions>
<CodeContractsAssertsToContractsCheckBox>True</CodeContractsAssertsToContractsCheckBox>
<CodeContractsRedundantTests>True</CodeContractsRedundantTests>
<CodeContractsMissingPublicRequiresAsWarnings>True</CodeContractsMissingPublicRequiresAsWarnings>
<CodeContractsMissingPublicEnsuresAsWarnings>False</CodeContractsMissingPublicEnsuresAsWarnings>
<CodeContractsInferRequires>True</CodeContractsInferRequires>
<CodeContractsInferEnsures>False</CodeContractsInferEnsures>
<CodeContractsInferEnsuresAutoProperties>True</CodeContractsInferEnsuresAutoProperties>
<CodeContractsInferObjectInvariants>False</CodeContractsInferObjectInvariants>
<CodeContractsSuggestAssumptions>False</CodeContractsSuggestAssumptions>
<CodeContractsSuggestAssumptionsForCallees>False</CodeContractsSuggestAssumptionsForCallees>
<CodeContractsSuggestRequires>False</CodeContractsSuggestRequires>
<CodeContractsNecessaryEnsures>True</CodeContractsNecessaryEnsures>
<CodeContractsSuggestObjectInvariants>False</CodeContractsSuggestObjectInvariants>
<CodeContractsSuggestReadonly>True</CodeContractsSuggestReadonly>
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
<CodeContractsShowSquigglies>True</CodeContractsShowSquigglies>
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
<CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
<CodeContractsCustomRewriterAssembly />
<CodeContractsCustomRewriterClass />
<CodeContractsLibPaths />
<CodeContractsExtraRewriteOptions />
<CodeContractsExtraAnalysisOptions />
<CodeContractsSQLServerOption />
<CodeContractsBaseLineFile />
<CodeContractsCacheAnalysisResults>True</CodeContractsCacheAnalysisResults>
<CodeContractsSkipAnalysisIfCannotConnectToCache>False</CodeContractsSkipAnalysisIfCannotConnectToCache>
<CodeContractsFailBuildOnWarnings>False</CodeContractsFailBuildOnWarnings>
<CodeContractsBeingOptimisticOnExternal>True</CodeContractsBeingOptimisticOnExternal>
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
<CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
<CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
Expand Down
18 changes: 18 additions & 0 deletions TrackerDog/ChangeTrackableObjectState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace TrackerDog
{
/// <summary>
/// Defines possible change-tracked object states
/// </summary>
internal enum ChangeTrackableObjectState
{
/// <summary>
/// Trackable object is being built
/// </summary>
Constructing,

/// <summary>
/// Trackable object is ready to track changes
/// </summary>
Ready
}
}
11 changes: 9 additions & 2 deletions TrackerDog/Configuration/AttributeConfigurationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,22 @@ public void ConfigureType(IConfigurableTrackableType trackableType)
Contract.Requires(trackableType != null);

if (trackableType.Type.GetCustomAttribute<ChangeTrackableAttribute>() != null)
trackableType.IncludeProperties(GetTrackableProperties(trackableType.Type));
{
IEnumerable<PropertyInfo> trackableProperties = GetTrackableProperties(trackableType.Type);

if (trackableProperties.Count() > 0)
trackableType.IncludeProperties(trackableProperties);
}
}

private IEnumerable<PropertyInfo> GetTrackableProperties(Type type)
{
Contract.Requires(type != null);
Contract.Ensures(Contract.Result<IEnumerable<PropertyInfo>>() != null);

IEnumerable<PropertyInfo> allProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
IEnumerable<PropertyInfo> allProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Where(p => p.CanReadAndWrite() && p.GetMethod.IsVirtual);

IEnumerable<PropertyInfo> trackableProperties = allProperties.Where(p => p.GetCustomAttribute<ChangeTrackableAttribute>() != null);
IEnumerable<PropertyInfo> nonTrackableProperties = allProperties.Where(p => p.GetCustomAttribute<DoNotTrackChangesAttribute>() != null);

Expand Down
Loading

0 comments on commit f73eb17

Please sign in to comment.