Skip to content

Commit 1d85f7f

Browse files
committed
add tests showing TypeConverterGeneric<T> is working when used without factory
1 parent 6b5955a commit 1d85f7f

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Globalization;
5+
using System.IO;
6+
using System.Linq;
7+
using CsvHelper.Configuration;
8+
using CsvHelper.TypeConversion;
9+
using Xunit;
10+
11+
namespace CsvHelper.Tests.TypeConversion
12+
{
13+
public class TypeConverterFactoryTests
14+
{
15+
public readonly record struct Option<T> : IEnumerable<T>
16+
{
17+
public bool IsPresent { get; }
18+
private readonly T _value;
19+
20+
internal Option(T value)
21+
{
22+
IsPresent = true;
23+
_value = value;
24+
}
25+
26+
public IEnumerator<T> GetEnumerator()
27+
{
28+
if (IsPresent) yield return _value;
29+
}
30+
31+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
32+
}
33+
34+
private class MyOptionTypeFactory : ITypeConverterFactory
35+
{
36+
public bool CanCreate(Type type) =>
37+
type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Option<>);
38+
39+
public bool Create(Type type, TypeConverterCache cache, out ITypeConverter typeConverter)
40+
{
41+
var wrappedType = type.GetGenericArguments().Single();
42+
typeConverter =
43+
Activator.CreateInstance(typeof(OptionConverter<>).MakeGenericType(wrappedType)) as
44+
ITypeConverter ?? throw new NullReferenceException();
45+
return true;
46+
}
47+
48+
internal class OptionConverter<T> : TypeConverterGeneric<Option<T>>
49+
{
50+
public override string ConvertToString(Option<T> value, IWriterRow row,
51+
MemberMapData memberMapData)
52+
{
53+
var wrappedTypeConverter = row.Context.TypeConverterCache.GetConverter<T>();
54+
return value.IsPresent
55+
? wrappedTypeConverter.ConvertToString(value.Single(), row, memberMapData)
56+
: "";
57+
}
58+
59+
public override Option<T> ConvertFromString(string text, IReaderRow row,
60+
MemberMapData memberMapData)
61+
{
62+
var wrappedTypeConverter = row.Context.TypeConverterCache.GetConverter<T>();
63+
64+
return text == ""
65+
? new Option<T>()
66+
: new Option<T>((T)wrappedTypeConverter.ConvertFromString(text, row, memberMapData));
67+
}
68+
}
69+
}
70+
71+
private record RecordWithGenerics(Option<int> MaybeNumber);
72+
73+
[Fact]
74+
void ReadTypeConverterGenericInt()
75+
{
76+
var input = """
77+
MaybeNumber
78+
23
79+
80+
""";
81+
82+
using var cr = new CsvReader(new StringReader(input), CultureInfo.InvariantCulture);
83+
cr.Context.TypeConverterCache.AddConverter(new MyOptionTypeFactory.OptionConverter<int>());
84+
var firstRow = cr.GetRecords<RecordWithGenerics>().First();
85+
Assert.Equal(new Option<int>(23), firstRow.MaybeNumber);
86+
}
87+
88+
[Fact]
89+
void WriteTypeConverterGenericInt()
90+
{
91+
var expected = """
92+
MaybeNumber
93+
42
94+
95+
""";
96+
97+
var stringWriter = new StringWriter();
98+
using var cw = new CsvWriter(stringWriter, CultureInfo.InvariantCulture);
99+
cw.Context.TypeConverterCache.AddConverter(new MyOptionTypeFactory.OptionConverter<int>());
100+
cw.WriteRecords(new[]
101+
{
102+
new RecordWithGenerics(new Option<int>(42))
103+
});
104+
Assert.Equal(expected, stringWriter.ToString());
105+
}
106+
}
107+
}

0 commit comments

Comments
 (0)