1+ #region FreeBSD
2+
3+ // Copyright (c) 2013, John Batte
4+ // All rights reserved.
5+ //
6+ // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7+ //
8+ // * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
9+ //
10+ // * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
11+ // documentation and/or other materials provided with the distribution.
12+ //
13+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
14+ // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
15+ // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
16+ // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
17+ // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
18+ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19+
20+ #endregion
21+
22+ using System ;
23+ using System . Collections . Generic ;
24+ using System . Configuration ;
25+ using System . Linq ;
26+ using System . Reflection ;
27+ using System . Xml . Linq ;
28+
29+ using Patterns . Configuration ;
30+
31+ namespace Patterns . Testing . Configuration
32+ {
33+ /// <summary>
34+ /// Provides a configuration source that uses an in-memory configuration rather than a
35+ /// file-based one.
36+ /// </summary>
37+ public class TestConfigurationSource : IConfigurationSource
38+ {
39+ private readonly XContainer _configXml ;
40+
41+ /// <summary>
42+ /// Initializes a new instance of the <see cref="TestConfigurationSource" /> class.
43+ /// </summary>
44+ /// <param name="configXml">The config XML.</param>
45+ public TestConfigurationSource ( XContainer configXml )
46+ {
47+ _configXml = configXml ;
48+ var appSettings = GetSection < AppSettingsSection > ( "appSettings" ) ;
49+ if ( appSettings != null )
50+ {
51+ AppSettings = appSettings . Settings . AllKeys
52+ . ToDictionary ( key => key , key => appSettings . Settings [ key ] . Value ) ;
53+ }
54+ var connectionStrings = GetSection < ConnectionStringsSection > ( "connectionStrings" ) ;
55+ if ( connectionStrings != null )
56+ {
57+ ConnectionStrings = connectionStrings . ConnectionStrings . OfType < ConnectionStringSettings > ( )
58+ . ToDictionary ( settings => settings . Name , settings => settings ) ;
59+ }
60+ }
61+
62+ /// <summary>
63+ /// Gets the app settings.
64+ /// </summary>
65+ /// <value>
66+ /// The app settings.
67+ /// </value>
68+ public IDictionary < string , string > AppSettings { get ; private set ; }
69+
70+ /// <summary>
71+ /// Gets the connection strings.
72+ /// </summary>
73+ /// <value>
74+ /// The connection strings.
75+ /// </value>
76+ public IDictionary < string , ConnectionStringSettings > ConnectionStrings { get ; private set ; }
77+
78+ /// <summary>
79+ /// Gets the section.
80+ /// </summary>
81+ /// <param name="sectionName">Name of the section.</param>
82+ /// <returns></returns>
83+ /// <exception cref="System.NotImplementedException"></exception>
84+ public ConfigurationSection GetSection ( string sectionName )
85+ {
86+ return DeserializeSection ( _configXml , sectionName ) ;
87+ }
88+
89+ /// <summary>
90+ /// Gets the section.
91+ /// </summary>
92+ /// <typeparam name="TSection">The type of the section.</typeparam>
93+ /// <param name="sectionName">Name of the section.</param>
94+ /// <returns></returns>
95+ /// <exception cref="System.NotImplementedException"></exception>
96+ public TSection GetSection < TSection > ( string sectionName ) where TSection : ConfigurationSection , new ( )
97+ {
98+ return DeserializeSection < TSection > ( _configXml , sectionName ) ;
99+ }
100+
101+ /// <summary>
102+ /// Opens the exe configuration.
103+ /// </summary>
104+ /// <param name="exePath">The exe path.</param>
105+ /// <returns></returns>
106+ /// <exception cref="System.NotImplementedException"></exception>
107+ public IConfiguration OpenExeConfiguration ( string exePath )
108+ {
109+ throw new NotSupportedException ( ) ;
110+ }
111+
112+ /// <summary>
113+ /// Opens the machine configuration.
114+ /// </summary>
115+ /// <returns></returns>
116+ /// <exception cref="System.NotImplementedException"></exception>
117+ public IConfiguration OpenMachineConfiguration ( )
118+ {
119+ throw new NotSupportedException ( ) ;
120+ }
121+
122+ /// <summary>
123+ /// Refreshes the section.
124+ /// </summary>
125+ /// <param name="sectionName">Name of the section.</param>
126+ /// <exception cref="System.NotImplementedException"></exception>
127+ public void RefreshSection ( string sectionName ) { }
128+
129+ /// <summary>
130+ /// Opens the mapped exe configuration.
131+ /// </summary>
132+ /// <param name="fileMap">The file map.</param>
133+ /// <param name="userLevel">The user level.</param>
134+ /// <returns></returns>
135+ /// <exception cref="System.NotImplementedException"></exception>
136+ public IConfiguration OpenMappedExeConfiguration ( ExeConfigurationFileMap fileMap , ConfigurationUserLevel userLevel )
137+ {
138+ throw new NotSupportedException ( ) ;
139+ }
140+
141+ /// <summary>
142+ /// Opens the exe configuration.
143+ /// </summary>
144+ /// <param name="userLevel">The user level.</param>
145+ /// <returns></returns>
146+ /// <exception cref="System.NotImplementedException"></exception>
147+ public IConfiguration OpenExeConfiguration ( ConfigurationUserLevel userLevel )
148+ {
149+ throw new NotSupportedException ( ) ;
150+ }
151+
152+ private static ConfigurationSection DeserializeSection ( XContainer xml , string name )
153+ {
154+ XElement sectionDefinition = xml . Element ( "configSections" )
155+ . Elements ( "section" )
156+ . FirstOrDefault ( section => section . Attribute ( "name" ) . Value == name ) ;
157+
158+ if ( sectionDefinition == null ) return null ;
159+
160+ Type sectionType = Type . GetType ( sectionDefinition . Attribute ( "type" ) . Value , false ) ;
161+
162+ if ( sectionType == null ) return null ;
163+
164+ const BindingFlags flags = BindingFlags . Static | BindingFlags . NonPublic ;
165+ MethodInfo genericFlavor = typeof ( TestConfigurationSource ) . GetMethods ( flags )
166+ . FirstOrDefault ( method => method . Name == "DeserializeSection" && method . IsGenericMethod ) ;
167+
168+ MethodInfo typedGenericFlavor = genericFlavor . MakeGenericMethod ( sectionType ) ;
169+
170+ try
171+ {
172+ return ( ConfigurationSection ) typedGenericFlavor . Invoke ( null , new object [ ] { xml , name } ) ;
173+ }
174+ catch ( TargetInvocationException error )
175+ {
176+ throw error . InnerException ;
177+ }
178+ }
179+
180+ private static TSection DeserializeSection < TSection > ( XContainer xml , string name ) where TSection : ConfigurationSection , new ( )
181+ {
182+ var config = new TSection ( ) ;
183+ const BindingFlags flags = BindingFlags . Instance | BindingFlags . NonPublic ;
184+ MethodInfo deserializer = typeof ( TSection ) . GetMethod ( "DeserializeSection" , flags ) ;
185+ XElement sectionXml = xml . Element ( name ) ;
186+ if ( sectionXml == null ) return null ;
187+
188+ try
189+ {
190+ deserializer . Invoke ( config , new object [ ] { sectionXml . CreateReader ( ) } ) ;
191+ }
192+ catch ( TargetInvocationException error )
193+ {
194+ throw error . InnerException ;
195+ }
196+
197+ return config ;
198+ }
199+ }
200+ }
0 commit comments