提交 545084d4 编写于 作者: J Jeremy Kuhne 提交者: GitHub

Add more config tests (dotnet/corefx#14883)

- Adds a number of new tests
- Cleans up / clarifies some code
- Removes a chunk of duplicate code

Commit migrated from https://github.com/dotnet/corefx/commit/4a6cead5d3a0cdc3f0b6481ac082ad983ffd63bd
上级 9a413a6b
......@@ -4,8 +4,10 @@
namespace System.Configuration
{
// This attribute is expected on section properties of type derivied from ConfigurationElementCollection
// or on the itself
/// <summary>
/// Used on classes derived from ConfigurationElementCollection. Specifies the collection item type and
/// verbs used for add/remove/clear.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class)]
public sealed class ConfigurationCollectionAttribute : Attribute
{
......
......@@ -254,7 +254,7 @@ public override int GetHashCode()
Hashtable inheritance = new Hashtable();
_lockedAllExceptAttributesList = sourceElement._lockedAllExceptAttributesList;
_lockedAllExceptElementsList = sourceElement._lockedAllExceptElementsList;
_fItemLocked = sourceElement._fItemLocked;
_itemLockedFlag = sourceElement._itemLockedFlag;
_lockedAttributesList = sourceElement._lockedAttributesList;
_lockedElementsList = sourceElement._lockedElementsList;
......@@ -661,12 +661,13 @@ private void BaseAddInternal(int index, ConfigurationElement element, bool flagA
Items.Insert(index, new Entry(entryType, key, element));
}
else
{
Items.Add(new Entry(entryType, key, element));
}
_modified = true;
}
protected virtual void BaseAdd(int index, ConfigurationElement element)
{
BaseAdd(index, element, false);
......
......@@ -83,6 +83,7 @@ public bool HasParentElements
{
// return true if there is at least one element that was defined in the parent
bool result = false;
// Check to see if the exception list is empty as a result of a merge from config
// If so the there were some parent elements because empty string is invalid in config.
// and the only way to get an empty list is for the merged config to have no elements
......@@ -211,6 +212,7 @@ internal bool DefinedInParent(string name)
{
if (name == null)
return false;
if (!ExceptionList)
{
return _internalDictionary.Contains(name) &&
......
......@@ -24,11 +24,15 @@ public ConfigurationProperty(string name, Type type)
ConstructorInit(name, type, ConfigurationPropertyOptions.None, null, null);
if (type == typeof(string)) defaultValue = string.Empty;
else
if (type == typeof(string))
{
defaultValue = string.Empty;
}
else if (type.IsValueType)
{
if (type.IsValueType) defaultValue = TypeUtil.CreateInstance(type);
defaultValue = TypeUtil.CreateInstance(type);
}
SetDefaultValue(defaultValue);
}
......@@ -66,94 +70,91 @@ internal ConfigurationProperty(PropertyInfo info)
{
Debug.Assert(info != null, "info != null");
// Bellow are the attributes we handle
ConfigurationPropertyAttribute attribProperty = null;
ConfigurationPropertyAttribute propertyAttribute = null;
DescriptionAttribute descriptionAttribute = null;
// Compatability attributes
// If the approprite data is provided in the ConfigPropAttribute then the one bellow will be ignored
DescriptionAttribute attribStdDescription = null;
DefaultValueAttribute attribStdDefault = null;
// For compatibility we read the component model default value attribute. It is only
// used if ConfigurationPropertyAttribute doesn't provide the default value.
DefaultValueAttribute defaultValueAttribute = null;
TypeConverter typeConverter = null;
ConfigurationValidatorBase validator = null;
// Find the interesting attributes in the collection
// Look for relevant attributes
foreach (Attribute attribute in Attribute.GetCustomAttributes(info))
{
if (attribute is TypeConverterAttribute)
{
TypeConverterAttribute attribConverter = (TypeConverterAttribute)attribute;
typeConverter = TypeUtil.CreateInstance<TypeConverter>(attribConverter.ConverterTypeName);
typeConverter = TypeUtil.CreateInstance<TypeConverter>(((TypeConverterAttribute)attribute).ConverterTypeName);
}
else
else if (attribute is ConfigurationPropertyAttribute)
{
if (attribute is ConfigurationPropertyAttribute)
attribProperty = (ConfigurationPropertyAttribute)attribute;
else
propertyAttribute = (ConfigurationPropertyAttribute)attribute;
}
else if (attribute is ConfigurationValidatorAttribute)
{
if (validator != null)
{
if (attribute is ConfigurationValidatorAttribute)
{
// There could be more then one validator attribute specified on a property
// Currently we consider this an error since it's too late to fix it for whidbey
// but the right thing to do is to introduce new validator type ( CompositeValidator ) that is a list of validators and executes
// them all
if (validator != null)
{
throw new ConfigurationErrorsException(
string.Format(SR.Validator_multiple_validator_attributes, info.Name));
}
ConfigurationValidatorAttribute attribValidator = (ConfigurationValidatorAttribute)attribute;
attribValidator.SetDeclaringType(info.DeclaringType);
validator = attribValidator.ValidatorInstance;
}
else
{
if (attribute is DescriptionAttribute)
attribStdDescription = (DescriptionAttribute)attribute;
else
{
if (attribute is DefaultValueAttribute)
attribStdDefault = (DefaultValueAttribute)attribute;
}
}
// We only allow one validator to be specified on a property.
//
// Consider: introduce a new validator type ( CompositeValidator ) that is a
// list of validators and executes them all
throw new ConfigurationErrorsException(
string.Format(SR.Validator_multiple_validator_attributes, info.Name));
}
ConfigurationValidatorAttribute validatorAttribute = (ConfigurationValidatorAttribute)attribute;
validatorAttribute.SetDeclaringType(info.DeclaringType);
validator = validatorAttribute.ValidatorInstance;
}
else if (attribute is DescriptionAttribute)
{
descriptionAttribute = (DescriptionAttribute)attribute;
}
else if (attribute is DefaultValueAttribute)
{
defaultValueAttribute = (DefaultValueAttribute)attribute;
}
}
Type propertyType = info.PropertyType;
// Collections need some customization when the collection attribute is present
// If the property is a Collection we need to look for the ConfigurationCollectionAttribute for
// additional customization.
if (typeof(ConfigurationElementCollection).IsAssignableFrom(propertyType))
{
ConfigurationCollectionAttribute attribCollection =
// Look for the ConfigurationCollection attribute on the property itself, fall back
// on the property type.
ConfigurationCollectionAttribute collectionAttribute =
Attribute.GetCustomAttribute(info,
typeof(ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute ??
Attribute.GetCustomAttribute(propertyType,
typeof(ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;
// If none on the property - see if there is an attribute on the collection type itself
if (attribCollection != null)
if (collectionAttribute != null)
{
if (attribCollection.AddItemName.IndexOf(',') == -1) AddElementName = attribCollection.AddItemName;
RemoveElementName = attribCollection.RemoveItemName;
ClearElementName = attribCollection.ClearItemsName;
if (collectionAttribute.AddItemName.IndexOf(',') == -1) AddElementName = collectionAttribute.AddItemName;
RemoveElementName = collectionAttribute.RemoveItemName;
ClearElementName = collectionAttribute.ClearItemsName;
}
}
// This constructor shouldnt be invoked if the reflection info is not for an actual config property
Debug.Assert(attribProperty != null, "attribProperty != null");
// This constructor shouldn't be invoked if the reflection info is not for an actual config property
Debug.Assert(propertyAttribute != null, "attribProperty != null");
ConstructorInit(attribProperty.Name,
ConstructorInit(propertyAttribute.Name,
info.PropertyType,
attribProperty.Options,
propertyAttribute.Options,
validator,
typeConverter);
// Figure out the default value
InitDefaultValueFromTypeInfo(attribProperty, attribStdDefault);
InitDefaultValueFromTypeInfo(propertyAttribute, defaultValueAttribute);
// Get the description
if (!string.IsNullOrEmpty(attribStdDescription?.Description))
Description = attribStdDescription.Description;
if (!string.IsNullOrEmpty(descriptionAttribute?.Description))
Description = descriptionAttribute.Description;
}
public string Name { get; private set; }
......@@ -166,7 +167,8 @@ internal bool IsConfigurationElementType
{
get
{
if (_isTypeInited) return _isConfigurationElementType;
if (_isTypeInited)
return _isConfigurationElementType;
_isConfigurationElementType = typeof(ConfigurationElement).IsAssignableFrom(Type);
_isTypeInited = true;
......@@ -209,7 +211,8 @@ public TypeConverter Converter
internal string ClearElementName { get; }
private void ConstructorInit(string name,
private void ConstructorInit(
string name,
Type type,
ConfigurationPropertyOptions options,
ConfigurationValidatorBase validator,
......@@ -221,11 +224,17 @@ public TypeConverter Converter
string.Format(SR.Config_properties_may_not_be_derived_from_configuration_section, name));
}
ProvidedName = name; // save the provided name so we can check for default collection names
if (((options & ConfigurationPropertyOptions.IsDefaultCollection) != 0) &&
string.IsNullOrEmpty(name))
// save the provided name so we can check for default collection names
ProvidedName = name;
if (((options & ConfigurationPropertyOptions.IsDefaultCollection) != 0) && string.IsNullOrEmpty(name))
{
name = s_defaultCollectionPropertyName;
else ValidatePropertyName(name);
}
else
{
ValidatePropertyName(name);
}
Name = name;
Type = type;
......@@ -234,7 +243,10 @@ public TypeConverter Converter
_converter = converter;
// Use the default validator if none was supplied
if (Validator == null) Validator = s_defaultValidatorInstance;
if (Validator == null)
{
Validator = s_defaultValidatorInstance;
}
else
{
// Make sure the supplied validator supports the type of this property
......@@ -245,7 +257,8 @@ public TypeConverter Converter
private void ValidatePropertyName(string name)
{
if (string.IsNullOrEmpty(name)) throw new ArgumentException(SR.String_null_or_empty, nameof(name));
if (string.IsNullOrEmpty(name))
throw new ArgumentException(SR.String_null_or_empty, nameof(name));
if (BaseConfigurationRecord.IsReservedAttributeName(name))
throw new ArgumentException(string.Format(SR.Property_name_reserved, name));
......@@ -254,34 +267,34 @@ private void ValidatePropertyName(string name)
private void SetDefaultValue(object value)
{
// Validate the default value if any. This should make errors from invalid defaults easier to catch
if ((value == null) || (value == ConfigurationElement.s_nullPropertyValue)) return;
if (ConfigurationElement.IsNullOrNullProperty(value))
return;
if (!Type.IsInstanceOfType(value))
{
if (Converter.CanConvertFrom(value.GetType()))
value = Converter.ConvertFrom(value);
else
if (!Converter.CanConvertFrom(value.GetType()))
throw new ConfigurationErrorsException(string.Format(SR.Default_value_wrong_type, Name));
value = Converter.ConvertFrom(value);
}
Validate(value);
DefaultValue = value;
}
private void InitDefaultValueFromTypeInfo(ConfigurationPropertyAttribute attribProperty,
DefaultValueAttribute attribStdDefault)
private void InitDefaultValueFromTypeInfo(
ConfigurationPropertyAttribute configurationProperty,
DefaultValueAttribute defaultValueAttribute)
{
object defaultValue = attribProperty.DefaultValue;
object defaultValue = configurationProperty.DefaultValue;
// If there is no default value there - try the other attribute ( the clr standard one )
if (((defaultValue == null) || (defaultValue == ConfigurationElement.s_nullPropertyValue)) &&
(attribStdDefault != null))
defaultValue = attribStdDefault.Value;
// If the ConfigurationPropertyAttribute has no default try the DefaultValueAttribute
if (ConfigurationElement.IsNullOrNullProperty(defaultValue))
defaultValue = defaultValueAttribute?.Value;
// If there was a default value in the prop attribute - check if we need to convert it from string
// Convert the default value from string if necessary
if (defaultValue is string && (Type != typeof(string)))
{
// Use the converter to parse this property default value
try
{
defaultValue = Converter.ConvertFromInvariantString((string)defaultValue);
......@@ -293,14 +306,19 @@ private void SetDefaultValue(object value)
}
}
if ((defaultValue == null) || (defaultValue == ConfigurationElement.s_nullPropertyValue))
// If we still have no default, use string Empty for string or the default for value types
if (ConfigurationElement.IsNullOrNullProperty(defaultValue))
{
if (Type == typeof(string)) defaultValue = string.Empty;
else
if (Type == typeof(string))
{
defaultValue = string.Empty;
}
else if (Type.IsValueType)
{
if (Type.IsValueType) defaultValue = TypeUtil.CreateInstance(Type);
defaultValue = TypeUtil.CreateInstance(Type);
}
}
SetDefaultValue(defaultValue);
}
......@@ -323,21 +341,23 @@ internal object ConvertFromString(string value)
internal string ConvertToString(object value)
{
string result;
try
{
if (Type == typeof(bool))
result = (bool)value ? "true" : "false"; // the converter will break 1.1 compat for bool
else result = Converter.ConvertToInvariantString(value);
{
// The boolean converter will break 1.1 compat for bool
return (bool)value ? "true" : "false";
}
else
{
return Converter.ConvertToInvariantString(value);
}
}
catch (Exception ex)
{
throw new ConfigurationErrorsException(string.Format(SR.Top_level_conversion_error_to_string, Name,
ex.Message));
throw new ConfigurationErrorsException(
string.Format(SR.Top_level_conversion_error_to_string, Name, ex.Message));
}
return result;
}
internal void Validate(object value)
......@@ -348,31 +368,37 @@ internal void Validate(object value)
}
catch (Exception ex)
{
throw new ConfigurationErrorsException(string.Format(SR.Top_level_validation_error, Name, ex.Message),
ex);
throw new ConfigurationErrorsException(
string.Format(SR.Top_level_validation_error, Name, ex.Message), ex);
}
}
private void CreateConverter()
{
// Some properties cannot have type converters.
// Such examples are properties that are ConfigurationElement ( derived classes )
// or properties which are user-defined and the user code handles serialization/desirialization so
// the property itself is never converted to/from string
if (_converter != null) return;
// Enums are exception. We use our custom converter for all enums
if (Type.IsEnum) _converter = new GenericEnumConverter(Type);
if (Type.IsEnum)
{
// We use our custom converter for all enums
_converter = new GenericEnumConverter(Type);
}
else if (Type.IsSubclassOf(typeof(ConfigurationElement)))
{
// Type converters aren't allowed on ConfigurationElement
// derived classes.
return;
}
else
{
if (Type.IsSubclassOf(typeof(ConfigurationElement))) return;
_converter = TypeDescriptor.GetConverter(Type);
if ((_converter == null) ||
!_converter.CanConvertFrom(typeof(string)) ||
!_converter.CanConvertTo(typeof(string)))
{
// Need to be able to convert to/from string
throw new ConfigurationErrorsException(string.Format(SR.No_converter, Name, Type.Name));
}
}
}
}
......
......@@ -47,7 +47,7 @@ public ConnectionStringSettings(string name, string connectionString, string pro
protected internal override ConfigurationPropertyCollection Properties => s_properties;
[ConfigurationProperty("name",
Options = ConfigurationPropertyOptions.IsRequired | ConfigurationPropertyOptions.IsKey, DefaultValue = "")]
Options = ConfigurationPropertyOptions.IsRequired | ConfigurationPropertyOptions.IsKey, DefaultValue = "")]
public string Name
{
get { return (string)base[s_propName]; }
......
......@@ -8,7 +8,8 @@ internal sealed class InternalConfigConfigurationFactory : IInternalConfigConfig
{
private InternalConfigConfigurationFactory() { }
Configuration IInternalConfigConfigurationFactory.Create(Type typeConfigHost,
Configuration IInternalConfigConfigurationFactory.Create(
Type typeConfigHost,
params object[] hostInitConfigurationParams)
{
return new Configuration(null, typeConfigHost, hostInitConfigurationParams);
......
......@@ -144,9 +144,9 @@ private void ValidateWriteAccess(string filename)
}
}
// Replace one file with another using MoveFileEx. This will
// retry the operation if the file is locked because someone
// is reading it
/// <summary>
/// Replace one file with another, retrying if locked.
/// </summary>
private void ReplaceFile(string source, string target)
{
bool writeSucceeded;
......
......@@ -38,7 +38,9 @@ public void Add(KeyValueConfigurationElement keyValue)
// when add is called and teh key already exists.
KeyValueConfigurationElement oldValue = (KeyValueConfigurationElement)BaseGet(keyValue.Key);
if (oldValue == null)
{
BaseAdd(keyValue);
}
else
{
oldValue.Value += "," + keyValue.Value;
......
......@@ -7,8 +7,11 @@ namespace System.Configuration
public class ProtectedProviderSettings : ConfigurationElement
{
private readonly ConfigurationProperty _propProviders =
new ConfigurationProperty(null, typeof(ProviderSettingsCollection), null,
ConfigurationPropertyOptions.IsDefaultCollection);
new ConfigurationProperty(
name: null,
type: typeof(ProviderSettingsCollection),
defaultValue: null,
options: ConfigurationPropertyOptions.IsDefaultCollection);
private readonly ConfigurationPropertyCollection _properties;
......@@ -20,9 +23,7 @@ public ProtectedProviderSettings()
protected internal override ConfigurationPropertyCollection Properties => _properties;
[ConfigurationProperty("", IsDefaultCollection = true,
Options = ConfigurationPropertyOptions.IsDefaultCollection)]
[ConfigurationProperty("", IsDefaultCollection = true, Options = ConfigurationPropertyOptions.IsDefaultCollection)]
public ProviderSettingsCollection Providers => (ProviderSettingsCollection)base[_propProviders];
}
}
\ No newline at end of file
......@@ -52,6 +52,12 @@
</Compile>
<Compile Include="System\Configuration\AppSettingsTests.cs" />
<Compile Include="System\Configuration\ConfigPathUtilityTests.cs" />
<Compile Include="System\Configuration\ConfigurationElementCollectionTests.cs" />
<Compile Include="System\Configuration\ConfigurationElementTests.cs" />
<Compile Include="System\Configuration\ConfigurationPropertyAttributeTests.cs" />
<Compile Include="System\Configuration\ConfigurationPropertyTests.cs" />
<Compile Include="System\Configuration\ConfigurationTests.cs" />
<Compile Include="System\Configuration\BasicCustomSectionTests.cs" />
<Compile Include="System\Configuration\ExceptionUtilTests.cs" />
<Compile Include="System\Configuration\ImplicitMachineConfigTests.cs" />
<Compile Include="System\Configuration\SmokeTest.cs" />
......
......@@ -83,5 +83,26 @@ public void AddToAppSettings_Save()
Assert.Equal("NewValue", config.AppSettings.Settings["NewKey"].Value);
}
}
[Fact]
public void AppSettingsCannotLoadFromUser()
{
// By default you can't load a section from a user config file- validating that appSettings falls in this bucket
using (var machine = new TempConfig(TestData.ImplicitMachineConfig))
using (var exe = new TempConfig(TestData.EmptyConfig))
using (var user = new TempConfig(TestData.SimpleConfig))
{
ExeConfigurationFileMap map = new ExeConfigurationFileMap
{
MachineConfigFilename = machine.ConfigPath,
ExeConfigFilename = exe.ConfigPath,
RoamingUserConfigFilename = user.ConfigPath
};
var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.PerUserRoaming);
Assert.Throws<ConfigurationErrorsException>(() => config.AppSettings);
}
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Configuration;
using System.IO;
using Xunit;
namespace System.ConfigurationTests
{
public class BasicCustomSectionTests
{
public class SimpleCustomSection : ConfigurationSection
{
[ConfigurationProperty("test")]
public string Test
{
get { return (string)this["test"]; }
set { this["test"] = value; }
}
}
public static string SimpleCustomData =
@"<?xml version='1.0' encoding='utf-8' ?>
<configuration>
<configSections>
<section name='simpleCustomSection' type='System.ConfigurationTests.BasicCustomSectionTests+SimpleCustomSection, System.Configuration.Tests' />
</configSections>
<simpleCustomSection />
</configuration>";
[Fact]
public void SimpleCustomSectionExists()
{
using (var temp = new TempConfig(SimpleCustomData))
{
var config = ConfigurationManager.OpenExeConfiguration(temp.ExePath);
SimpleCustomSection section = config.GetSection("simpleCustomSection") as SimpleCustomSection;
Assert.NotNull(section);
Assert.Equal(string.Empty, section.Test);
}
}
public static string SimpleCustomDataWithValue =
@"<?xml version='1.0' encoding='utf-8' ?>
<configuration>
<configSections>
<section name='simpleCustomSection' type='System.ConfigurationTests.BasicCustomSectionTests+SimpleCustomSection, System.Configuration.Tests' />
</configSections>
<simpleCustomSection test='Foo' />
</configuration>";
[Fact]
public void SimpleCustomSectionWithData()
{
using (var temp = new TempConfig(SimpleCustomDataWithValue))
{
var config = ConfigurationManager.OpenExeConfiguration(temp.ExePath);
SimpleCustomSection section = config.GetSection("simpleCustomSection") as SimpleCustomSection;
Assert.NotNull(section);
Assert.Equal("Foo", section.Test);
}
}
public class SimpleCustomSectionRequiredValue : ConfigurationSection
{
[ConfigurationProperty("test", IsRequired = true)]
public string Test
{
get { return (string)this["test"]; }
set { this["test"] = value; }
}
}
public static string MissingRequiredData =
@"<?xml version='1.0' encoding='utf-8' ?>
<configuration>
<configSections>
<section name='simpleCustomSectionRequiredValue' type='System.ConfigurationTests.BasicCustomSectionTests+SimpleCustomSectionRequiredValue, System.Configuration.Tests' />
</configSections>
<simpleCustomSectionRequiredValue />
</configuration>";
[Fact]
public void SimpleCustomSectionMissingRequired()
{
using (var temp = new TempConfig(MissingRequiredData))
{
var config = ConfigurationManager.OpenExeConfiguration(temp.ExePath);
Assert.Throws<ConfigurationErrorsException>(() => config.GetSection("simpleCustomSectionRequiredValue") as SimpleCustomSectionRequiredValue);
}
}
public class SimpleCustomSectionDefaultValue: ConfigurationSection
{
[ConfigurationProperty("test", DefaultValue = "Bar" )]
public string Test
{
get { return (string)this["test"]; }
set { this["test"] = value; }
}
}
public static string DefaultAppliedData =
@"<?xml version='1.0' encoding='utf-8' ?>
<configuration>
<configSections>
<section name='simpleCustomSectionDefaultValue' type='System.ConfigurationTests.BasicCustomSectionTests+SimpleCustomSectionDefaultValue, System.Configuration.Tests' />
</configSections>
<simpleCustomSectionDefaultValue />
</configuration>";
[Fact]
public void SimpleCustomSectionWithDefault()
{
using (var temp = new TempConfig(DefaultAppliedData))
{
var config = ConfigurationManager.OpenExeConfiguration(temp.ExePath);
SimpleCustomSectionDefaultValue section = config.GetSection("simpleCustomSectionDefaultValue") as SimpleCustomSectionDefaultValue;
Assert.NotNull(section);
Assert.Equal("Bar", section.Test);
}
}
public class SimpleDefaultCollectionSection : ConfigurationSection
{
[ConfigurationProperty("", IsDefaultCollection = true)]
public KeyValueConfigurationCollection Settings => (KeyValueConfigurationCollection)base[""];
}
public static string SimpleDefaultCollection =
@"<?xml version='1.0' encoding='utf-8' ?>
<configuration>
<configSections>
<section name='simpleDefaultCollectionSection' type='System.ConfigurationTests.BasicCustomSectionTests+SimpleDefaultCollectionSection, System.Configuration.Tests' />
</configSections>
<simpleDefaultCollectionSection>
<add key='Fruit' value='Pear' />
<add key='Nut' value='Cashew' />
</simpleDefaultCollectionSection>
</configuration>";
[Fact]
public void CustomSectionDefaultCollection()
{
using (var temp = new TempConfig(SimpleDefaultCollection))
{
var config = ConfigurationManager.OpenExeConfiguration(temp.ExePath);
SimpleDefaultCollectionSection section = config.GetSection("simpleDefaultCollectionSection") as SimpleDefaultCollectionSection;
Assert.NotNull(section);
Assert.Equal(2, section.Settings.Count);
Assert.Equal("Pear", section.Settings["Fruit"].Value);
Assert.Equal("Cashew", section.Settings["Nut"].Value);
}
}
public class SimpleCollectionSection : ConfigurationSection
{
[ConfigurationProperty("foods", IsDefaultCollection = true)]
public KeyValueConfigurationCollection Foods => (KeyValueConfigurationCollection)base["foods"];
}
public static string SimpleCollection =
@"<?xml version='1.0' encoding='utf-8' ?>
<configuration>
<configSections>
<section name='simpleCollectionSection' type='System.ConfigurationTests.BasicCustomSectionTests+SimpleCollectionSection, System.Configuration.Tests' />
</configSections>
<simpleCollectionSection>
<foods>
<add key='Fruit' value='Pear' />
<add key='Nut' value='Cashew' />
</foods>
</simpleCollectionSection>
</configuration>";
[Fact]
public void CustomSectionCollection()
{
using (var temp = new TempConfig(SimpleCollection))
{
var config = ConfigurationManager.OpenExeConfiguration(temp.ExePath);
SimpleCollectionSection section = config.GetSection("simpleCollectionSection") as SimpleCollectionSection;
Assert.NotNull(section);
Assert.Equal(2, section.Foods.Count);
Assert.Equal("Pear", section.Foods["Fruit"].Value);
Assert.Equal("Cashew", section.Foods["Nut"].Value);
}
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections;
using System.Configuration;
using System.IO;
using Xunit;
namespace System.ConfigurationTests
{
public class ConfigurationElementCollectionTests
{
public class SimpleElement : ConfigurationElement
{
}
private class SimpleCollection : ConfigurationElementCollection
{
public SimpleCollection()
: base()
{ }
public SimpleCollection(IComparer comparer)
: base(comparer)
{ }
protected override ConfigurationElement CreateNewElement()
{
throw new NotImplementedException();
}
protected override object GetElementKey(ConfigurationElement element)
{
return "FooKey";
}
public bool TestThrowOnDuplicate => ThrowOnDuplicate;
public string TestElementName => ElementName;
public void TestBaseAdd(ConfigurationElement element)
{
BaseAdd(element);
}
public void TestBaseAdd(int index, ConfigurationElement element)
{
BaseAdd(index, element);
}
}
private class ReadOnlySimpleCollection : SimpleCollection
{
public override bool IsReadOnly() => true;
}
[Fact]
public void NullComparerThrows()
{
Assert.Equal("comparer", Assert.Throws<ArgumentNullException>(() => new SimpleCollection(null)).ParamName);
}
[Fact]
public void ReadOnlyFalseByDefault()
{
Assert.False(new SimpleCollection().IsReadOnly());
}
[Fact]
public void InitialCountIsZero()
{
Assert.Equal(0, new SimpleCollection().Count);
}
[Fact]
public void ElementNameIsEmpty()
{
Assert.Equal("", new SimpleCollection().TestElementName);
}
[Fact]
public void CollectionTypeIsAddRemoveMap()
{
Assert.Equal(ConfigurationElementCollectionType.AddRemoveClearMap, new SimpleCollection().CollectionType);
}
[Fact]
public void SyncRootIsNull()
{
Assert.Null(new SimpleCollection().SyncRoot);
}
[Fact]
public void SynchronizedIsFalse()
{
Assert.False(new SimpleCollection().IsSynchronized);
}
[Fact]
public void EmitClearIsFalse()
{
Assert.False(new SimpleCollection().EmitClear);
}
[Fact]
public void SetEmitClear()
{
var collection = new SimpleCollection();
collection.EmitClear = true;
Assert.True(collection.EmitClear);
}
[Fact]
public void AddBaseElementSucceeds()
{
var collection = new SimpleCollection();
collection.TestBaseAdd(new SimpleElement());
Assert.Equal(1, collection.Count);
}
[Fact]
public void AddBaseElementAtIndexSucceeds()
{
var collection = new SimpleCollection();
collection.TestBaseAdd(-1, new SimpleElement());
Assert.Equal(1, collection.Count);
}
[Fact]
public void BaseAddIndexOutOfRangeThrows()
{
Assert.Throws<ConfigurationErrorsException>(() => new SimpleCollection().TestBaseAdd(-2, null));
}
[Fact]
public void BaseAddReadOnlyThrows()
{
Assert.Throws<ConfigurationErrorsException>(() => new ReadOnlySimpleCollection().TestBaseAdd(null));
}
[Fact]
public void BaseAddIndexReadOnlyThrows()
{
Assert.Throws<ConfigurationErrorsException>(() => new ReadOnlySimpleCollection().TestBaseAdd(-1, null));
}
[Fact]
public void BaseAddNullThrows()
{
Assert.Throws<NullReferenceException>(() => new SimpleCollection().TestBaseAdd(null));
}
[Fact]
public void BaseAddIndexNullThrows()
{
Assert.Throws<NullReferenceException>(() => new SimpleCollection().TestBaseAdd(-1, null));
}
[Fact]
public void ThrowOnDuplicateIsTrue()
{
Assert.True(new SimpleCollection().TestThrowOnDuplicate);
}
public class BasicCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
throw new NotImplementedException();
}
protected override object GetElementKey(ConfigurationElement element)
{
throw new NotImplementedException();
}
public override ConfigurationElementCollectionType CollectionType => ConfigurationElementCollectionType.BasicMap;
public bool TestThrowOnDuplicate => ThrowOnDuplicate;
}
[Fact]
public void BasicThrowOnDuplicateIsFalse()
{
Assert.False(new BasicCollection().TestThrowOnDuplicate);
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Configuration;
using Xunit;
namespace System.ConfigurationTests
{
public class ConfigurationElementTests
{
[Fact]
public void HasNoConfiguration()
{
Assert.Null(new SimpleElement().CurrentConfiguration);
}
[Fact]
public void HasNoContext()
{
// There should be no configuration record and thus, no context
Assert.False(new SimpleElement().TestHasContext);
}
[Fact]
public void EvaluationContextThrows()
{
// If we haven't associated a configuration record we should fail
SimpleElement element = new SimpleElement();
Assert.Throws<ConfigurationErrorsException>(() => element.TestEvaluationContext);
}
[Fact]
public void TransformedNullTypeStringIsNull()
{
Assert.Null(new SimpleElement().TestGetTransformedTypeString(null));
}
[Fact]
public void TransformedTypeStringIsOriginal()
{
string foo = "foo";
// With no config record the transformed typename should be original
Assert.Same(foo, new SimpleElement().TestGetTransformedTypeString(foo));
}
[Fact]
public void TransformedNullAssemblyStringIsNull()
{
Assert.Null(new SimpleElement().TestGetTransformedAssemblyString(null));
}
[Fact]
public void TransformedAssemblyStringIsOriginal()
{
string foo = "foo";
// With no config record the transformed assembly name should be original
Assert.Same(foo, new SimpleElement().TestGetTransformedAssemblyString(foo));
}
public class SimpleElement : ConfigurationElement
{
public ContextInformation TestEvaluationContext => EvaluationContext;
public bool TestHasContext => HasContext;
public string TestGetTransformedTypeString(string typeName)
{
return GetTransformedTypeString(typeName);
}
public string TestGetTransformedAssemblyString(string assemblyName)
{
return GetTransformedAssemblyString(assemblyName);
}
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Configuration;
using Xunit;
namespace System.ConfigurationTests
{
public class ConfigurationPropertyAttributeTests
{
[Fact]
public void DefaultValueIsNullObject()
{
// It isn't publicly exposed anywhere else, first check that it is the same object instance here
ConfigurationPropertyAttribute one = new ConfigurationPropertyAttribute("one");
ConfigurationPropertyAttribute two = new ConfigurationPropertyAttribute("two");
Assert.IsType<object>(one.DefaultValue);
Assert.Same(one.DefaultValue, two.DefaultValue);
}
[Fact]
public void DefaultOptionsIsNone()
{
Assert.Equal(ConfigurationPropertyOptions.None, new ConfigurationPropertyAttribute("foo").Options);
}
[Fact]
public void IsDefaultCollection()
{
ConfigurationPropertyAttribute attribute = new ConfigurationPropertyAttribute("foo");
Assert.False(attribute.IsDefaultCollection);
attribute.Options = ConfigurationPropertyOptions.IsDefaultCollection;
Assert.True(attribute.IsDefaultCollection);
attribute.IsDefaultCollection = false;
Assert.False(attribute.IsDefaultCollection);
Assert.Equal(ConfigurationPropertyOptions.None, attribute.Options);
}
[Fact]
public void IsRequired()
{
ConfigurationPropertyAttribute attribute = new ConfigurationPropertyAttribute("foo");
Assert.False(attribute.IsDefaultCollection);
attribute.Options = ConfigurationPropertyOptions.IsRequired;
Assert.True(attribute.IsRequired);
attribute.IsRequired = false;
Assert.False(attribute.IsRequired);
Assert.Equal(ConfigurationPropertyOptions.None, attribute.Options);
}
[Fact]
public void IsKey()
{
ConfigurationPropertyAttribute attribute = new ConfigurationPropertyAttribute("foo");
Assert.False(attribute.IsDefaultCollection);
attribute.Options = ConfigurationPropertyOptions.IsKey;
Assert.True(attribute.IsKey);
attribute.IsKey = false;
Assert.False(attribute.IsKey);
Assert.Equal(ConfigurationPropertyOptions.None, attribute.Options);
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using System.Configuration;
using Xunit;
namespace System.ConfigurationTests
{
public class ConfigurationPropertyTests
{
[Fact]
public void ConfigurationSectionThrows()
{
Assert.Throws<ConfigurationErrorsException>(() => new ConfigurationProperty("foo", typeof(ConfigurationSection)));
}
[Fact]
public void AppSettingsSectionThrows()
{
Assert.Throws<ConfigurationErrorsException>(() => new ConfigurationProperty("foo", typeof(AppSettingsSection)));
}
[Fact]
public void NullNameThrows()
{
Assert.Throws<ArgumentException>(() => new ConfigurationProperty(null, typeof(string)));
}
[Fact]
public void EmptyNameThrows()
{
Assert.Throws<ArgumentException>(() => new ConfigurationProperty("", typeof(string)));
}
[Theory
InlineData("lock")
InlineData("locks")
InlineData("config")
InlineData("configuration")
]
public void ReservedNameThrows(string name)
{
Assert.Throws<ArgumentException>(() => new ConfigurationProperty(name, typeof(string)));
}
[Theory
InlineData("Lock")
InlineData("ilock")
InlineData("LOCKS")
InlineData("CoNfig")
InlineData("conFIGuration")
]
public void ReservedNameOrdinallyCompared(string name)
{
// Want to make sure the comparison is ordinal and starts with if people have depended on this
new ConfigurationProperty(name, typeof(string));
}
// Base class returns false for CanValidate by default
public class CantValidateValidator : ConfigurationValidatorBase
{
public override void Validate(object value)
{
throw new NotImplementedException();
}
}
[Fact]
public void NonMatchingValidatorThrows()
{
CantValidateValidator validator = new CantValidateValidator();
Assert.Throws<ConfigurationErrorsException>(() => new ConfigurationProperty("foo", typeof(string), null, null, validator, ConfigurationPropertyOptions.None));
}
public class FooFailsValidator : ConfigurationValidatorBase
{
public override bool CanValidate(Type type)
{
return true;
}
public override void Validate(object value)
{
if (string.Equals(value, "foo"))
throw new InvalidOperationException();
}
}
[Fact]
public void BadDefaultValueThrows()
{
FooFailsValidator validator = new FooFailsValidator();
Action action = () => new ConfigurationProperty("bar", typeof(string), "foo", null, validator, ConfigurationPropertyOptions.None);
Assert.IsType<InvalidOperationException>(Assert.Throws<ConfigurationErrorsException>(action).InnerException);
}
[TypeConverter(typeof(DummyCantConverter))]
public class SimpleConfigurationElement : ConfigurationElement
{
}
// By default can't convert from or to
public class DummyCantConverter : TypeConverter
{
}
public class DummyCanConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(string);
}
}
[Fact]
public void ConfigurationElementConverterIgnored()
{
ConfigurationProperty property = new ConfigurationProperty("foo", typeof(SimpleConfigurationElement));
Assert.Null(property.Converter);
}
[TypeConverter(typeof(DummyCanConverter))]
public class MyConvertableClass
{
}
[Fact]
public void TypeConverterRecognized()
{
ConfigurationProperty property = new ConfigurationProperty("foo", typeof(MyConvertableClass));
Assert.IsType<DummyCanConverter>(property.Converter);
}
[TypeConverter(typeof(DummyCantConverter))]
public class MyUnconvertableClass
{
}
[Fact]
public void UnconvertableFailsOnConverterAccess()
{
ConfigurationProperty property = new ConfigurationProperty("foo", typeof(MyUnconvertableClass));
Assert.Throws<ConfigurationErrorsException>(() => property.Converter);
}
[TypeConverter(typeof(DummyCantConverter))]
public enum AllSay
{
Yea,
Nay
}
[Fact]
public void EnumsGetGenericEnumConverter()
{
ConfigurationProperty property = new ConfigurationProperty("foo", typeof(AllSay));
Assert.IsType<GenericEnumConverter>(property.Converter);
}
[Theory
InlineData(typeof(string), typeof(StringConverter))
InlineData(typeof(int), typeof(Int32Converter))
]
public void FindConverterForBuiltInTypes(Type type, Type converterType)
{
ConfigurationProperty property = new ConfigurationProperty("foo", type);
Assert.IsType(converterType, property.Converter);
}
[Fact]
public void IsRequiredExposed()
{
Assert.False(new ConfigurationProperty("foo", typeof(string)).IsRequired);
Assert.True(new ConfigurationProperty("foo", typeof(string), null, ConfigurationPropertyOptions.IsRequired).IsRequired);
}
[Fact]
public void IsKeyExposed()
{
Assert.False(new ConfigurationProperty("foo", typeof(string)).IsRequired);
Assert.True(new ConfigurationProperty("foo", typeof(string), null, ConfigurationPropertyOptions.IsKey).IsKey);
}
[Fact]
public void IsDefaultCollectionExposed()
{
Assert.False(new ConfigurationProperty("foo", typeof(string)).IsDefaultCollection);
Assert.True(new ConfigurationProperty("foo", typeof(string), null, ConfigurationPropertyOptions.IsDefaultCollection).IsDefaultCollection);
}
[Fact]
public void IsTypeStringTransformationRequiredExposed()
{
Assert.False(new ConfigurationProperty("foo", typeof(string)).IsTypeStringTransformationRequired);
Assert.True(new ConfigurationProperty("foo", typeof(string), null, ConfigurationPropertyOptions.IsTypeStringTransformationRequired).IsTypeStringTransformationRequired);
}
[Fact]
public void IsAssemblyStringTransformationRequiredExposed()
{
Assert.False(new ConfigurationProperty("foo", typeof(string)).IsAssemblyStringTransformationRequired);
Assert.True(new ConfigurationProperty("foo", typeof(string), null, ConfigurationPropertyOptions.IsAssemblyStringTransformationRequired).IsAssemblyStringTransformationRequired);
}
[Fact]
public void IsVersionCheckRequiredExposed()
{
Assert.False(new ConfigurationProperty("foo", typeof(string)).IsVersionCheckRequired);
Assert.True(new ConfigurationProperty("foo", typeof(string), null, ConfigurationPropertyOptions.IsVersionCheckRequired).IsVersionCheckRequired);
}
[Fact]
public void TypeIsExposed()
{
Assert.Equal(typeof(string), new ConfigurationProperty("foo", typeof(string)).Type);
}
[Fact]
public void DefaultValueIsExposed()
{
Assert.Equal("bar", new ConfigurationProperty("foo", typeof(string), "bar").DefaultValue);
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Configuration;
using System.IO;
using Xunit;
namespace System.ConfigurationTests
{
public class ConfigurationTests
{
[Fact]
public void UnspecifiedTypeStringTransformer()
{
using (var temp = new TempConfig(TestData.EmptyConfig))
{
var config = ConfigurationManager.OpenExeConfiguration(temp.ExePath);
Assert.Null(config.TypeStringTransformer);
}
}
[Fact]
public void SpecifiedTypeStringTransformerReturned()
{
using (var temp = new TempConfig(TestData.EmptyConfig))
{
var config = ConfigurationManager.OpenExeConfiguration(temp.ExePath);
Func<string, string> transformer = s => s;
config.TypeStringTransformer = transformer;
Assert.Same(transformer, config.TypeStringTransformer);
}
}
[Fact]
public void UnspecifiedAssemblyStringTransformer()
{
using (var temp = new TempConfig(TestData.EmptyConfig))
{
var config = ConfigurationManager.OpenExeConfiguration(temp.ExePath);
Assert.Null(config.AssemblyStringTransformer);
}
}
[Fact]
public void SpecifiedAssemblyStringTransformerReturned()
{
using (var temp = new TempConfig(TestData.EmptyConfig))
{
var config = ConfigurationManager.OpenExeConfiguration(temp.ExePath);
Func<string, string> transformer = s => s;
config.AssemblyStringTransformer = transformer;
Assert.Same(transformer, config.AssemblyStringTransformer);
}
}
}
}
......@@ -6,6 +6,13 @@ namespace System.ConfigurationTests
{
public static class TestData
{
public static string ImplicitMachineConfig =
@"<configuration>
<configSections>
<section name='appSettings' type='System.Configuration.AppSettingsSection, System.Configuration' restartOnExternalChanges='false' requirePermission='false'/>
</configSections>
</configuration>";
public static string EmptyConfig =
@"<?xml version='1.0' encoding='utf-8' ?>
<configuration>
......@@ -15,8 +22,8 @@ public static class TestData
@"<?xml version='1.0' encoding='utf-8' ?>
<configuration>
<appSettings>
<add key='FooKey' value='FooValue'/>
<add key='BarKey' value='BarValue'/>
<add key='FooKey' value='FooValue' />
<add key='BarKey' value='BarValue' />
</appSettings>
</configuration>";
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册