-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#44 Various updates to the Copy and With methods:
Renamed to TryWith and TryCopy With (version that throws exceptions rather than using an Option<T> type) added Various code changes to support edge-case badly behaved types
- Loading branch information
Showing
8 changed files
with
604 additions
and
130 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
|
||
namespace SuccincT.Functional | ||
{ | ||
internal class CachedConstructorInfo | ||
{ | ||
public ConstructorInfo Constructor { get; } | ||
public List<ParameterInfo> Parameters { get; } | ||
|
||
public CachedConstructorInfo(ConstructorInfo constructorInfo) | ||
{ | ||
Constructor = constructorInfo; | ||
Parameters = constructorInfo.GetParameters().ToList(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
|
||
namespace SuccincT.Functional | ||
{ | ||
internal class CachedTypeInfo | ||
{ | ||
public List<CachedConstructorInfo> CachedPublicConstructors { get; } | ||
public List<PropertyInfo> Properties { get; } | ||
public List<PropertyInfo> ReadOnlyProperties { get; } | ||
public List<PropertyInfo> WriteOnlyProperties { get; } | ||
|
||
public CachedTypeInfo(Type type) | ||
{ | ||
var typeInfo = type.GetTypeInfo(); | ||
|
||
var cachedConstructors = | ||
typeInfo.DeclaredConstructors.Select(c => new CachedConstructorInfo(c)).ToList(); | ||
|
||
CachedPublicConstructors = cachedConstructors | ||
.Where(cc => cc.Constructor.IsPublic && !cc.Constructor.IsStatic).ToList(); | ||
|
||
Properties = type.GetRuntimeProperties().ToList(); | ||
ReadOnlyProperties = Properties.Where(p => p.CanRead && !p.CanWrite).ToList(); | ||
WriteOnlyProperties = Properties.Where(p => !p.CanRead && p.CanWrite).ToList(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using System; | ||
|
||
namespace SuccincT.Functional | ||
{ | ||
public class CopyException : Exception | ||
{ | ||
public CopyException(string message) : base(message) {} | ||
|
||
public CopyException(string message, Exception innerException) : base(message, innerException) {} | ||
} | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
206 changes: 206 additions & 0 deletions
206
tests/SuccincT.Tests/SuccincT/Functional/WithExtensionsAdverseConditionsTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
using NUnit.Framework; | ||
using SuccincT.Functional; | ||
using static NUnit.Framework.Assert; | ||
|
||
namespace SuccincTTests.SuccincT.Functional | ||
{ | ||
[TestFixture] | ||
public class WithExtensionsAdverseConditionsTests | ||
{ | ||
[Test] | ||
public void TryWithOfTypeWithConstructorAndNoGetters_FailsCleanly() | ||
{ | ||
var x = new TypeWithConstructorAndNoGetters(1); | ||
var y = x.TryWith(new { }); | ||
|
||
IsFalse(y.HasValue); | ||
} | ||
|
||
[Test] | ||
public void WithOfTypeWithConstructorAndNoGetters_ThrowsCopyException() | ||
{ | ||
var x = new TypeWithConstructorAndNoGetters(1); | ||
Throws<CopyException>(() => x.With(new { })); | ||
} | ||
|
||
[Test] | ||
public void TryWithOfTypeWithConstructorAndNoGettersSuppliedWithWrongParam_FailsCleanly() | ||
{ | ||
var x = new TypeWithConstructorAndNoGetters(1); | ||
var y = x.TryWith(new { x = "2" }); | ||
|
||
IsFalse(y.HasValue); | ||
} | ||
|
||
[Test] | ||
public void WithOfTypeWithConstructorAndNoGettersSuppliedWithWrongParam_ThrowsCopyException() | ||
{ | ||
var x = new TypeWithConstructorAndNoGetters(1); | ||
Throws<CopyException>(() => x.With(new { x = "2" })); | ||
} | ||
|
||
[Test] | ||
public void TryWithOfTypeWithConstructorAndNoGettersSuppliedWithWrongParamName_FailsCleanly() | ||
{ | ||
var x = new TypeWithConstructorAndNoGetters(1); | ||
var y = x.TryWith(new { y = 1 }); | ||
|
||
IsFalse(y.HasValue); | ||
} | ||
|
||
[Test] | ||
public void WithOfTypeWithConstructorAndNoGettersSuppliedWithWrongParamName_ThrowsCopyException() | ||
{ | ||
var x = new TypeWithConstructorAndNoGetters(1); | ||
Throws<CopyException>(() => x.With(new { y = 1 })); | ||
} | ||
|
||
[Test] | ||
public void TryWithOfTypeWithConstructorAndNoMatchingGetter_CanHavePropSetViaConstructor() | ||
{ | ||
var x = new TypeWithConstructorAndNoMatchingGetter(1); | ||
var y = x.TryWith(new { a = 2 }); | ||
|
||
AreEqual(2, y.Value.B); | ||
} | ||
|
||
[Test] | ||
public void WithOfTypeWithConstructorAndNoMatchingGetter_CanHavePropSetViaConstructor() | ||
{ | ||
var x = new TypeWithConstructorAndNoMatchingGetter(1); | ||
var y = x.With(new { a = 2 }); | ||
|
||
AreEqual(2, y.B); | ||
} | ||
|
||
[Test] | ||
public void TryWithOfTypeWithConstructorAndNoMatchingGetter_FailsCleanlyWhenPropertyNameRatherThanParamNameIsSupplied() | ||
{ | ||
var x = new TypeWithConstructorAndNoMatchingGetter(1); | ||
var y = x.TryWith(new { b = 2 }); | ||
|
||
IsFalse(y.HasValue); | ||
} | ||
|
||
[Test] | ||
public void WithOfTypeWithConstructorAndNoMatchingGetter_ThrowsCopyExceptionWhenPropertyNameRatherThanParamNameIsSupplied() | ||
{ | ||
var x = new TypeWithConstructorAndNoMatchingGetter(1); | ||
Throws<CopyException>(() => x.With(new { b = 2 })); | ||
} | ||
|
||
[Test] | ||
public void TryWithOfTypeWithMultipleConstructors_ChoosesCorrectConstructor() | ||
{ | ||
var x = new TypeWithMultipleConstructors(1); | ||
|
||
var y = x.TryWith(new { B = 3 }); | ||
|
||
AreEqual(1, y.Value.A); | ||
AreEqual(3, y.Value.B); | ||
} | ||
|
||
[Test] | ||
public void WithOfTypeWithMultipleConstructors_ChoosesCorrectConstructor() | ||
{ | ||
var x = new TypeWithMultipleConstructors(1); | ||
|
||
var y = x.With(new { B = 3 }); | ||
|
||
AreEqual(1, y.A); | ||
AreEqual(3, y.B); | ||
} | ||
|
||
[Test] | ||
public void TryWithOfTypeToTestPropertiesSetViaConstructorArentSetAfterConstruction_OnlySetsPropertyViaConstructor() | ||
{ | ||
var x = new TypeToTestPropertiesSetViaConstructorArentSetAfterConstruction(2); | ||
|
||
var y = x.TryWith(new { a = 3 }); | ||
|
||
AreEqual(3, y.Value.A); | ||
} | ||
|
||
[Test] | ||
public void WithOfTypeToTestPropertiesSetViaConstructorArentSetAfterConstruction_OnlySetsPropertyViaConstructor() | ||
{ | ||
var x = new TypeToTestPropertiesSetViaConstructorArentSetAfterConstruction(2); | ||
|
||
var y = x.With(new { a = 3 }); | ||
|
||
AreEqual(3, y.A); | ||
} | ||
|
||
[Test] | ||
public void TryWithOfTypeToTestPropertiesAreOnlySetOnceWhenNoConstructor_OnlySetsPropertyOnce() | ||
{ | ||
var x = new TypeToTestPropertiesAreOnlySetOnceWhenNoConstructor { A = 2 }; | ||
|
||
var y = x.TryWith(new { a = 3 }); | ||
|
||
AreEqual(3, y.Value.A); | ||
} | ||
|
||
[Test] | ||
public void WithOfTypeToTestPropertiesAreOnlySetOnceWhenNoConstructor_OnlySetsPropertyOnce() | ||
{ | ||
var x = new TypeToTestPropertiesAreOnlySetOnceWhenNoConstructor { A = 2 }; | ||
|
||
var y = x.With(new { a = 3 }); | ||
|
||
AreEqual(3, y.A); | ||
} | ||
|
||
private class TypeWithConstructorAndNoGetters | ||
{ | ||
// ReSharper disable once UnusedParameter.Local | ||
public TypeWithConstructorAndNoGetters(int x) { } | ||
} | ||
|
||
private class TypeWithConstructorAndNoMatchingGetter | ||
{ | ||
// ReSharper disable once UnusedMember.Local | ||
// ReSharper disable UnusedParameter.Local | ||
public TypeWithConstructorAndNoMatchingGetter(int a, int c) { } | ||
public TypeWithConstructorAndNoMatchingGetter(int a) => B = a; | ||
public int B { get; } | ||
} | ||
|
||
private class TypeWithMultipleConstructors | ||
{ | ||
public TypeWithMultipleConstructors(int a) => (A, B) = (a, 1); | ||
// ReSharper disable once UnusedMember.Local | ||
public TypeWithMultipleConstructors(int a, int b) => (A, B) = (a, b); | ||
// ReSharper disable once UnusedMember.Local | ||
// ReSharper disable once UnusedParameter.Local | ||
public TypeWithMultipleConstructors(int a, int c, int b) => (A, B) = (a, b); | ||
public int A { get; } | ||
public int B { get; } | ||
} | ||
|
||
private class TypeToTestPropertiesSetViaConstructorArentSetAfterConstruction | ||
{ | ||
private int _a; | ||
|
||
public TypeToTestPropertiesSetViaConstructorArentSetAfterConstruction(int a) => A = a; | ||
|
||
public int A | ||
{ | ||
get => _a; | ||
// ReSharper disable once MemberCanBePrivate.Local | ||
set => _a = _a + value; | ||
} | ||
} | ||
|
||
private class TypeToTestPropertiesAreOnlySetOnceWhenNoConstructor | ||
{ | ||
private int _a; | ||
|
||
public int A | ||
{ | ||
get => _a; | ||
set => _a = _a + value; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.