-
Notifications
You must be signed in to change notification settings - Fork 4.6k
/
OpenGenericsTests.cs
155 lines (126 loc) · 5.38 KB
/
OpenGenericsTests.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Composition.Hosting;
using System.Composition.Hosting.Core;
using System.Composition.Runtime;
using System.Composition.UnitTests.Util;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace System.Composition.UnitTests
{
public class OpenGenericsTests : ContainerTests
{
private interface IRepository<T> { }
[Export(typeof(IRepository<>))]
private class BasicRepository<T> : IRepository<T> { }
private class RepositoryProperty<T>
{
private readonly IRepository<T> _repository = new BasicRepository<T>();
[Export(typeof(IRepository<>))]
public IRepository<T> Repository { get { return _repository; } }
}
[Shared]
private class TwoGenericExports<T>
{
private readonly BasicRepository<T> _repository = new BasicRepository<T>();
[Export(typeof(IRepository<>))]
public IRepository<T> Repository { get { return _repository; } }
[Export(typeof(BasicRepository<>))]
public BasicRepository<T> Repository2 { get { return _repository; } }
}
private interface IFirst<T> { }
private interface ISecond<T> { }
[Export(typeof(IFirst<>)), Export(typeof(ISecond<>))]
private class FirstAndSecond<T> : IFirst<T>, ISecond<T> { }
[Export(typeof(IRepository<>))]
private class RepositoryWithKey<T, TKey> : IRepository<T> { }
private interface IRepository { }
[Export(typeof(IRepository))]
private class RepositoryWithNonGenericExport<T> : IRepository { }
[Export]
private class ExportSelf<T> { }
private class SomeGenericType<T> { }
[Export(typeof(SomeGenericType<>))]
private class ExportsBase<T> : SomeGenericType<T> { }
[Fact]
public void CanExportBasicOpenGeneric()
{
var cc = CreateContainer(typeof(BasicRepository<>));
var r = cc.GetExport<IRepository<string>>();
Assert.IsAssignableFrom<BasicRepository<string>>(r);
}
[Fact]
public void OpenGenericProvidesMultipleInstantiations()
{
var cc = CreateContainer(typeof(BasicRepository<>));
var r = cc.GetExport<IRepository<string>>();
var r2 = cc.GetExport<IRepository<int>>();
Assert.IsAssignableFrom<BasicRepository<int>>(r2);
}
[Fact]
public void CanExportOpenGenericProperty()
{
var cc = CreateContainer(typeof(RepositoryProperty<>));
var r = cc.GetExport<IRepository<string>>();
Assert.IsAssignableFrom<BasicRepository<string>>(r);
}
[Fact]
public void ASharedOpenGenericWithTwoExportsIsProvidedByASingleInstance()
{
var cc = CreateContainer(typeof(TwoGenericExports<>));
var r = cc.GetExport<IRepository<string>>();
var r2 = cc.GetExport<BasicRepository<string>>();
Assert.NotNull(r);
Assert.Same(r, r2);
}
[Fact]
public void APartWithMultipleGenericExportsIsOnlyDiscoveredOnce()
{
var cc = CreateContainer(typeof(BasicRepository<>), typeof(TwoGenericExports<>));
// Provided by TwoGenericExports
var r1 = cc.GetExport<BasicRepository<string>>();
// Provided by both
var others = cc.GetExports<IRepository<string>>();
Assert.Equal(2, others.Count());
}
[Fact]
public void MultipleGenericExportsCanBeSpecifiedAtTheClassLevel()
{
var cc = CreateContainer(typeof(FirstAndSecond<>));
var first = cc.GetExport<IFirst<string>>();
Assert.IsAssignableFrom<FirstAndSecond<string>>(first);
}
// In future, the set of allowable generic type mappings will be expanded (see
// ignored tests above).
[Fact]
public void TypesWithMismatchedGenericParameterListsAreDetectedDuringDiscovery()
{
var x = Assert.Throws<CompositionFailedException>(() => CreateContainer(typeof(RepositoryWithKey<,>)));
Assert.Equal("Exported contract 'IRepository`1' of open generic part 'RepositoryWithKey`2' does not match the generic arguments of the class.", x.Message);
}
[Fact]
public void TypesWithNonGenericExportsAreDetectedDuringDiscovery()
{
var x = Assert.Throws<CompositionFailedException>(() => CreateContainer(typeof(RepositoryWithNonGenericExport<>)));
Assert.Equal("Open generic part 'RepositoryWithNonGenericExport`1' cannot export non-generic contract 'IRepository'.", x.Message);
}
[Fact]
public void OpenGenericsCanExportSelf()
{
var cc = CreateContainer(typeof(ExportSelf<>));
var es = cc.GetExport<ExportSelf<string>>();
Assert.IsAssignableFrom<ExportSelf<string>>(es);
}
[Fact]
public void OpenGenericsCanExportBase()
{
var cc = CreateContainer(typeof(ExportsBase<>));
var es = cc.GetExport<SomeGenericType<string>>();
Assert.IsAssignableFrom<ExportsBase<string>>(es);
}
}
}