Skip to content

Commit 1ee98c8

Browse files
committed
Adjusted tests + version bump
1 parent 2bcb88a commit 1ee98c8

File tree

17 files changed

+1378
-501
lines changed

17 files changed

+1378
-501
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<Copyright>(c) $([System.DateTime]::Now.Year), Pawel Gerr. All rights reserved.</Copyright>
5-
<VersionPrefix>6.4.0</VersionPrefix>
5+
<VersionPrefix>6.5.0</VersionPrefix>
66
<Authors>Pawel Gerr</Authors>
77
<GenerateDocumentationFile>true</GenerateDocumentationFile>
88
<PackageProjectUrl>https://github.com/PawelGerr/Thinktecture.Runtime.Extensions</PackageProjectUrl>

src/Thinktecture.Runtime.Extensions/IValueObjectConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ public interface IValueObjectConverter<out T>
1313
/// <summary>
1414
/// Converts the value object to type <typeparamref name="T"/>.
1515
/// </summary>
16-
T ToValue();
16+
T ToValue() => throw new NotImplementedException("This method will be implemented by the source generator.");
1717
}

test/Thinktecture.Runtime.Extensions.AspNetCore.Tests/AspNetCore/ModelBinding/ValueObjectModelBinderProviderTests/GetBinder.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ public void Should_return_binder_for_string_based_value_type()
3131
binder.Should().BeOfType<ValueObjectModelBinder<StringBasedReferenceValueObject, string>>();
3232
}
3333

34+
[Fact]
35+
public void Should_return_string_base_binder_specified_by_ValueObjectFactoryAttribute()
36+
{
37+
var binder = GetModelBinder<BoundaryWithFactories>();
38+
binder.Should().BeOfType<ValueObjectModelBinder<BoundaryWithFactories, string>>();
39+
}
40+
3441
[Fact]
3542
public void Should_return_null_for_non_enums_and_non_value_types()
3643
{

test/Thinktecture.Runtime.Extensions.AspNetCore.Tests/AspNetCore/ModelBinding/ValueObjectModelBinderTests/BindModelAsync.cs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public async Task Should_not_bind_validatable_enum_if_value_not_matching_key_typ
6363
var ctx = await BindAsync<IntegerEnum, int>("item1");
6464

6565
ctx.ModelState.ErrorCount.Should().Be(1);
66-
ctx.ModelState[ctx.ModelName].Errors.Should().BeEquivalentTo(new[] { new ModelError("The value 'item1' is not valid.") });
66+
ctx.ModelState[ctx.ModelName]!.Errors.Should().BeEquivalentTo(new[] { new ModelError("The value 'item1' is not valid.") });
6767
ctx.Result.IsModelSet.Should().BeFalse();
6868
}
6969

@@ -73,7 +73,7 @@ public async Task Should_not_bind_enum_if_key_is_unknown()
7373
var ctx = await BindAsync<ValidIntegerEnum, int>("42");
7474

7575
ctx.ModelState.ErrorCount.Should().Be(1);
76-
ctx.ModelState[ctx.ModelName].Errors.Should().BeEquivalentTo(new[] { new ModelError("There is no item of type 'ValidIntegerEnum' with the identifier '42'.") });
76+
ctx.ModelState[ctx.ModelName]!.Errors.Should().BeEquivalentTo(new[] { new ModelError("There is no item of type 'ValidIntegerEnum' with the identifier '42'.") });
7777
ctx.Result.IsModelSet.Should().BeFalse();
7878
}
7979

@@ -83,7 +83,7 @@ public async Task Should_not_bind_enum_if_value_not_matching_key_type()
8383
var ctx = await BindAsync<ValidIntegerEnum, int>("item1");
8484

8585
ctx.ModelState.ErrorCount.Should().Be(1);
86-
ctx.ModelState[ctx.ModelName].Errors.Should().BeEquivalentTo(new[] { new ModelError("The value 'item1' is not valid.") });
86+
ctx.ModelState[ctx.ModelName]!.Errors.Should().BeEquivalentTo(new[] { new ModelError("The value 'item1' is not valid.") });
8787
ctx.Result.IsModelSet.Should().BeFalse();
8888
}
8989

@@ -196,9 +196,29 @@ public async Task Should_return_error_if_value_violates_validation_rules()
196196
ctx.Result.IsModelSet.Should().BeFalse();
197197
}
198198

199+
[Fact]
200+
public async Task Should_bind_successfully_having_string_base_factory_specified_by_ValueObjectFactoryAttribute()
201+
{
202+
var ctx = await BindAsync<BoundaryWithFactories, string>("1:2");
203+
204+
ctx.ModelState.ErrorCount.Should().Be(0);
205+
ctx.Result.IsModelSet.Should().BeTrue();
206+
ctx.Result.Model.Should().BeEquivalentTo(BoundaryWithFactories.Create(1, 2));
207+
}
208+
209+
[Fact]
210+
public async Task Should_return_error_having_string_base_factory_specified_by_ValueObjectFactoryAttribute()
211+
{
212+
var ctx = await BindAsync<BoundaryWithFactories, string>("1");
213+
214+
ctx.ModelState.ErrorCount.Should().Be(1);
215+
ctx.ModelState[ctx.ModelName]!.Errors.Should().BeEquivalentTo(new[] { new ModelError("Invalid format.") });
216+
ctx.Result.IsModelSet.Should().BeFalse();
217+
}
218+
199219
private static async Task<DefaultModelBindingContext> BindAsync<T, TKey>(
200220
string value)
201-
where T : IKeyedValueObject<T, TKey>
221+
where T : IValueObjectFactory<T, TKey>
202222
{
203223
var binder = new ValueObjectModelBinder<T, TKey>(NullLoggerFactory.Instance);
204224
var query = new Dictionary<string, StringValues> { { "name", value } };

test/Thinktecture.Runtime.Extensions.Json.Tests/Text/Json/Serialization/ValueObjectJsonConverterFactoryTests/ReadJson.cs

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -25,58 +25,58 @@ public class ReadJson : JsonTestsBase
2525
[Fact]
2626
public void Should_deserialize_enum_when_null_and_default_unless_enum_and_underlying_are_both_null()
2727
{
28-
Deserialize<TestSmartEnum_Class_IntBased, ValueObjectJsonConverterFactory<TestSmartEnum_Class_IntBased, int>>("null").Should().Be(null);
29-
Deserialize<TestSmartEnum_Class_StringBased, ValueObjectJsonConverterFactory<TestSmartEnum_Class_StringBased, string>>("null").Should().Be(null);
30-
Deserialize<TestSmartEnum_Struct_IntBased?, ValueObjectJsonConverterFactory<TestSmartEnum_Struct_IntBased, int>>("null").Should().Be(null);
31-
Deserialize<TestSmartEnum_Struct_StringBased?, ValueObjectJsonConverterFactory<TestSmartEnum_Struct_StringBased, string>>("null").Should().Be(null);
32-
Deserialize<TestSmartEnum_Struct_IntBased, ValueObjectJsonConverterFactory<TestSmartEnum_Struct_IntBased, int>>("0").Should().Be(default(TestSmartEnum_Struct_IntBased)); // default(int) is 0
33-
Deserialize<TestSmartEnum_Struct_StringBased, ValueObjectJsonConverterFactory<TestSmartEnum_Struct_StringBased, string>>("null").Should().Be(default(TestSmartEnum_Struct_StringBased));
34-
35-
FluentActions.Invoking(() => Deserialize<TestSmartEnum_Struct_IntBased, ValueObjectJsonConverterFactory<TestSmartEnum_Struct_IntBased, int>>("null")).Should()
28+
DeserializeWithConverter<TestSmartEnum_Class_IntBased, ValueObjectJsonConverterFactory<TestSmartEnum_Class_IntBased, int>>("null").Should().Be(null);
29+
DeserializeWithConverter<TestSmartEnum_Class_StringBased, ValueObjectJsonConverterFactory<TestSmartEnum_Class_StringBased, string>>("null").Should().Be(null);
30+
DeserializeWithConverter<TestSmartEnum_Struct_IntBased?, ValueObjectJsonConverterFactory<TestSmartEnum_Struct_IntBased, int>>("null").Should().Be(null);
31+
DeserializeWithConverter<TestSmartEnum_Struct_StringBased?, ValueObjectJsonConverterFactory<TestSmartEnum_Struct_StringBased, string>>("null").Should().Be(null);
32+
DeserializeWithConverter<TestSmartEnum_Struct_IntBased, ValueObjectJsonConverterFactory<TestSmartEnum_Struct_IntBased, int>>("0").Should().Be(default(TestSmartEnum_Struct_IntBased)); // default(int) is 0
33+
DeserializeWithConverter<TestSmartEnum_Struct_StringBased, ValueObjectJsonConverterFactory<TestSmartEnum_Struct_StringBased, string>>("null").Should().Be(default(TestSmartEnum_Struct_StringBased));
34+
35+
FluentActions.Invoking(() => DeserializeWithConverter<TestSmartEnum_Struct_IntBased, ValueObjectJsonConverterFactory<TestSmartEnum_Struct_IntBased, int>>("null")).Should()
3636
.Throw<JsonException>()
3737
.WithInnerException<InvalidOperationException>().WithMessage("Cannot get the value of a token type 'Null' as a number.");
3838
}
3939

4040
[Fact]
4141
public void Should_deserialize_keyed_value_object_when_null_and_default_unless_enum_and_underlying_are_both_null()
4242
{
43-
Deserialize<IntBasedReferenceValueObject, ValueObjectJsonConverterFactory<IntBasedReferenceValueObject, int>>("null").Should().Be(null);
44-
Deserialize<StringBasedReferenceValueObject, ValueObjectJsonConverterFactory<StringBasedReferenceValueObject, string>>("null").Should().Be(null);
45-
Deserialize<IntBasedStructValueObject?, ValueObjectJsonConverterFactory<IntBasedStructValueObject, int>>("null").Should().Be(null);
46-
Deserialize<StringBasedStructValueObject?, ValueObjectJsonConverterFactory<StringBasedStructValueObject, string>>("null").Should().Be(null);
47-
Deserialize<IntBasedStructValueObject, ValueObjectJsonConverterFactory<IntBasedStructValueObject, int>>("0").Should().Be(default); // default(int) is 0
48-
Deserialize<StringBasedStructValueObject, ValueObjectJsonConverterFactory<StringBasedStructValueObject, string>>("null").Should().Be(default);
43+
DeserializeWithConverter<IntBasedReferenceValueObject, ValueObjectJsonConverterFactory<IntBasedReferenceValueObject, int>>("null").Should().Be(null);
44+
DeserializeWithConverter<StringBasedReferenceValueObject, ValueObjectJsonConverterFactory<StringBasedReferenceValueObject, string>>("null").Should().Be(null);
45+
DeserializeWithConverter<IntBasedStructValueObject?, ValueObjectJsonConverterFactory<IntBasedStructValueObject, int>>("null").Should().Be(null);
46+
DeserializeWithConverter<StringBasedStructValueObject?, ValueObjectJsonConverterFactory<StringBasedStructValueObject, string>>("null").Should().Be(null);
47+
DeserializeWithConverter<IntBasedStructValueObject, ValueObjectJsonConverterFactory<IntBasedStructValueObject, int>>("0").Should().Be(default); // default(int) is 0
48+
DeserializeWithConverter<StringBasedStructValueObject, ValueObjectJsonConverterFactory<StringBasedStructValueObject, string>>("null").Should().Be(default);
4949

5050
// NullInFactoryMethodsYieldsNull
51-
Deserialize<StringBasedReferenceValueObjectWithNullInFactoryMethodsYieldsNull, ValueObjectJsonConverterFactory<StringBasedReferenceValueObjectWithNullInFactoryMethodsYieldsNull, string>>("null").Should().Be(null);
52-
FluentActions.Invoking(() => Deserialize<StringBasedReferenceValueObjectWithNullInFactoryMethodsYieldsNull, ValueObjectJsonConverterFactory<StringBasedReferenceValueObjectWithNullInFactoryMethodsYieldsNull, string>>("\"\""))
51+
DeserializeWithConverter<StringBasedReferenceValueObjectWithNullInFactoryMethodsYieldsNull, ValueObjectJsonConverterFactory<StringBasedReferenceValueObjectWithNullInFactoryMethodsYieldsNull, string>>("null").Should().Be(null);
52+
FluentActions.Invoking(() => DeserializeWithConverter<StringBasedReferenceValueObjectWithNullInFactoryMethodsYieldsNull, ValueObjectJsonConverterFactory<StringBasedReferenceValueObjectWithNullInFactoryMethodsYieldsNull, string>>("\"\""))
5353
.Should().Throw<JsonException>().WithMessage("Property cannot be empty.");
54-
FluentActions.Invoking(() => Deserialize<StringBasedReferenceValueObjectWithNullInFactoryMethodsYieldsNull, ValueObjectJsonConverterFactory<StringBasedReferenceValueObjectWithNullInFactoryMethodsYieldsNull, string>>("\" \""))
54+
FluentActions.Invoking(() => DeserializeWithConverter<StringBasedReferenceValueObjectWithNullInFactoryMethodsYieldsNull, ValueObjectJsonConverterFactory<StringBasedReferenceValueObjectWithNullInFactoryMethodsYieldsNull, string>>("\" \""))
5555
.Should().Throw<JsonException>().WithMessage("Property cannot be empty.");
5656

5757
// EmptyStringInFactoryMethodsYieldsNull
58-
Deserialize<StringBasedReferenceValueObjectWithEmptyStringInFactoryMethodsYieldsNull, ValueObjectJsonConverterFactory<StringBasedReferenceValueObjectWithEmptyStringInFactoryMethodsYieldsNull, string>>("null").Should().Be(null);
59-
Deserialize<StringBasedReferenceValueObjectWithEmptyStringInFactoryMethodsYieldsNull, ValueObjectJsonConverterFactory<StringBasedReferenceValueObjectWithEmptyStringInFactoryMethodsYieldsNull, string>>("\"\"").Should().Be(null);
60-
Deserialize<StringBasedReferenceValueObjectWithEmptyStringInFactoryMethodsYieldsNull, ValueObjectJsonConverterFactory<StringBasedReferenceValueObjectWithEmptyStringInFactoryMethodsYieldsNull, string>>("\" \"").Should().Be(null);
58+
DeserializeWithConverter<StringBasedReferenceValueObjectWithEmptyStringInFactoryMethodsYieldsNull, ValueObjectJsonConverterFactory<StringBasedReferenceValueObjectWithEmptyStringInFactoryMethodsYieldsNull, string>>("null").Should().Be(null);
59+
DeserializeWithConverter<StringBasedReferenceValueObjectWithEmptyStringInFactoryMethodsYieldsNull, ValueObjectJsonConverterFactory<StringBasedReferenceValueObjectWithEmptyStringInFactoryMethodsYieldsNull, string>>("\"\"").Should().Be(null);
60+
DeserializeWithConverter<StringBasedReferenceValueObjectWithEmptyStringInFactoryMethodsYieldsNull, ValueObjectJsonConverterFactory<StringBasedReferenceValueObjectWithEmptyStringInFactoryMethodsYieldsNull, string>>("\" \"").Should().Be(null);
6161

62-
FluentActions.Invoking(() => Deserialize<IntBasedStructValueObject, ValueObjectJsonConverterFactory<IntBasedStructValueObject, int>>("null")).Should()
62+
FluentActions.Invoking(() => DeserializeWithConverter<IntBasedStructValueObject, ValueObjectJsonConverterFactory<IntBasedStructValueObject, int>>("null")).Should()
6363
.Throw<JsonException>()
6464
.WithInnerException<InvalidOperationException>().WithMessage("Cannot get the value of a token type 'Null' as a number.");
6565
}
6666

6767
[Fact]
6868
public void Should_deserialize_value_object_if_null_and_default()
6969
{
70-
Deserialize<TestValueObject_Complex_Class, TestValueObject_Complex_Class.ValueObjectJsonConverterFactory>("null").Should().Be(null);
71-
Deserialize<TestValueObject_Complex_Struct?, TestValueObject_Complex_Struct.ValueObjectJsonConverterFactory>("null").Should().Be(null);
72-
Deserialize<TestValueObject_Complex_Struct, TestValueObject_Complex_Struct.ValueObjectJsonConverterFactory>("null").Should().Be(default(TestValueObject_Complex_Struct));
70+
DeserializeWithConverter<TestValueObject_Complex_Class, TestValueObject_Complex_Class.ValueObjectJsonConverterFactory>("null").Should().Be(null);
71+
DeserializeWithConverter<TestValueObject_Complex_Struct?, TestValueObject_Complex_Struct.ValueObjectJsonConverterFactory>("null").Should().Be(null);
72+
DeserializeWithConverter<TestValueObject_Complex_Struct, TestValueObject_Complex_Struct.ValueObjectJsonConverterFactory>("null").Should().Be(default(TestValueObject_Complex_Struct));
7373
}
7474

7575
[Theory]
7676
[MemberData(nameof(DataForStringBasedEnumTest))]
7777
public void Should_deserialize_string_based_enum(TestEnum expectedValue, string json)
7878
{
79-
var value = Deserialize<TestEnum, ValueObjectJsonConverterFactory<TestEnum, string>>(json);
79+
var value = DeserializeWithConverter<TestEnum, ValueObjectJsonConverterFactory<TestEnum, string>>(json);
8080

8181
value.Should().Be(expectedValue);
8282
}
@@ -85,7 +85,7 @@ public void Should_deserialize_string_based_enum(TestEnum expectedValue, string
8585
[MemberData(nameof(DataForIntBasedEnumTest))]
8686
public void Should_deserialize_int_based_enum(IntegerEnum expectedValue, string json)
8787
{
88-
var value = Deserialize<IntegerEnum, ValueObjectJsonConverterFactory<IntegerEnum, int>>(json);
88+
var value = DeserializeWithConverter<IntegerEnum, ValueObjectJsonConverterFactory<IntegerEnum, int>>(json);
8989

9090
value.Should().Be(expectedValue);
9191
}
@@ -94,7 +94,7 @@ public void Should_deserialize_int_based_enum(IntegerEnum expectedValue, string
9494
[MemberData(nameof(DataForClassWithStringBasedEnumTest))]
9595
public void Should_deserialize_class_containing_string_based_enum(ClassWithStringBasedEnum expectedValue, string json, bool ignoreNullValues = false)
9696
{
97-
var value = Deserialize<ClassWithStringBasedEnum, ValueObjectJsonConverterFactory<TestEnum, string>>(json, ignoreNullValues: ignoreNullValues);
97+
var value = DeserializeWithConverter<ClassWithStringBasedEnum, ValueObjectJsonConverterFactory<TestEnum, string>>(json, ignoreNullValues: ignoreNullValues);
9898

9999
value.Should().BeEquivalentTo(expectedValue);
100100
}
@@ -103,7 +103,7 @@ public void Should_deserialize_class_containing_string_based_enum(ClassWithStrin
103103
[MemberData(nameof(DataForClassWithIntBasedEnumTest))]
104104
public void Should_deserialize_class_containing_int_based_enum(ClassWithIntBasedEnum expectedValue, string json, bool ignoreNullValues = false)
105105
{
106-
var value = Deserialize<ClassWithIntBasedEnum, ValueObjectJsonConverterFactory<IntegerEnum, int>>(json, ignoreNullValues: ignoreNullValues);
106+
var value = DeserializeWithConverter<ClassWithIntBasedEnum, ValueObjectJsonConverterFactory<IntegerEnum, int>>(json, ignoreNullValues: ignoreNullValues);
107107

108108
value.Should().BeEquivalentTo(expectedValue);
109109
}
@@ -116,30 +116,46 @@ public void Should_deserialize_value_type_with_multiple_properties(
116116
JsonNamingPolicy namingPolicy = null,
117117
bool propertyNameCaseInsensitive = false)
118118
{
119-
var value = Deserialize<ValueObjectWithMultipleProperties, ValueObjectWithMultipleProperties.ValueObjectJsonConverterFactory>(json, namingPolicy, propertyNameCaseInsensitive);
119+
var value = DeserializeWithConverter<ValueObjectWithMultipleProperties, ValueObjectWithMultipleProperties.ValueObjectJsonConverterFactory>(json, namingPolicy, propertyNameCaseInsensitive);
120120

121121
value.Should().BeEquivalentTo(expectedValueObject);
122122
}
123123

124124
[Fact]
125125
public void Should_throw_JsonException_if_enum_parsing_throws_UnknownEnumIdentifierException()
126126
{
127-
FluentActions.Invoking(() => Deserialize<ValidTestEnum, ValueObjectJsonConverterFactory<ValidTestEnum, string>>("\"invalid\""))
127+
FluentActions.Invoking(() => DeserializeWithConverter<ValidTestEnum, ValueObjectJsonConverterFactory<ValidTestEnum, string>>("\"invalid\""))
128128
.Should().Throw<JsonException>().WithMessage("There is no item of type 'ValidTestEnum' with the identifier 'invalid'.");
129129
}
130130

131131
[Fact]
132132
public void Should_throw_JsonException_if_complex_value_object_is_not_a_json_object()
133133
{
134-
FluentActions.Invoking(() => Deserialize<TestValueObject_Complex_Class, TestValueObject_Complex_Class.ValueObjectJsonConverterFactory>("\"invalid\""))
134+
FluentActions.Invoking(() => DeserializeWithConverter<TestValueObject_Complex_Class, TestValueObject_Complex_Class.ValueObjectJsonConverterFactory>("\"invalid\""))
135135
.Should().Throw<JsonException>().WithMessage("Unexpected token \"String\" when trying to deserialize \"TestValueObject_Complex_Class\". Expected token: \"StartObject\".");
136-
FluentActions.Invoking(() => Deserialize<TestValueObject_Complex_Class, TestValueObject_Complex_Class.ValueObjectJsonConverterFactory>("42"))
136+
FluentActions.Invoking(() => DeserializeWithConverter<TestValueObject_Complex_Class, TestValueObject_Complex_Class.ValueObjectJsonConverterFactory>("42"))
137137
.Should().Throw<JsonException>().WithMessage("Unexpected token \"Number\" when trying to deserialize \"TestValueObject_Complex_Class\". Expected token: \"StartObject\".");
138-
FluentActions.Invoking(() => Deserialize<TestValueObject_Complex_Class, TestValueObject_Complex_Class.ValueObjectJsonConverterFactory>("[]"))
138+
FluentActions.Invoking(() => DeserializeWithConverter<TestValueObject_Complex_Class, TestValueObject_Complex_Class.ValueObjectJsonConverterFactory>("[]"))
139139
.Should().Throw<JsonException>().WithMessage("Unexpected token \"StartArray\" when trying to deserialize \"TestValueObject_Complex_Class\". Expected token: \"StartObject\".");
140140
}
141141

142-
private static T Deserialize<T, TConverterFactory>(
142+
[Fact]
143+
public void Should_deserialize_using_custom_factory_specified_by_ValueObjectFactoryAttribute()
144+
{
145+
var value = Deserialize<BoundaryWithFactories, string>("\"1:2\"");
146+
147+
value.Should().BeEquivalentTo(BoundaryWithFactories.Create(1, 2));
148+
}
149+
150+
private static T Deserialize<T, TKey>(
151+
string json,
152+
JsonNamingPolicy namingPolicy = null)
153+
where T : IValueObjectFactory<T, TKey>, IValueObjectConverter<TKey>
154+
{
155+
return DeserializeWithConverter<T, ValueObjectJsonConverterFactory>(json, namingPolicy);
156+
}
157+
158+
private static T DeserializeWithConverter<T, TConverterFactory>(
143159
string json,
144160
JsonNamingPolicy namingPolicy = null,
145161
bool propertyNameCaseInsensitive = false,

0 commit comments

Comments
 (0)