public void Configuration_Ctor_ExclusiveRequirementsSupplied_Multiple_ThrowsAggregate()
        {
            const int numberOfConflictingRequirements = 5;

            List <IConfigurationRequirement> requirements =
                new List <IConfigurationRequirement>()
            {
                TestUtil.CreateConfigurationRequirement()
            };

            for (int counter = 0; counter < numberOfConflictingRequirements; counter++)
            {
                requirements.Add(TestUtil.CreateConfigurationRequirement(
                                     exclusiveWith: new IConfigurationRequirement[] { requirements.Last() }));
            }

            Dictionary <IConfigurationRequirement, object> values = requirements
                                                                    .Select(x => new KeyValuePair <IConfigurationRequirement, object>(
                                                                                x,
                                                                                TestUtil.GetDefaultValidObjectForRequirement(x)))
                                                                    .ToDictionary(x => x.Key, x => x.Value);

            IRequirementSource configurable = ConfigurationTests.CreateRequirementSource(requirements.ToArray());
            AggregateException exception    = Assert.ThrowsException <AggregateException>(() =>
                                                                                          new Configuration(configurable, values));

            Assert.AreEqual(numberOfConflictingRequirements, exception.InnerExceptions.Count);
            Assert.IsTrue(
                exception
                .InnerExceptions
                .Select(x => x.Message)
                .All(x => x.Contains("has conflicting requirements specified.")),
                "Unexpected exception message encountered.");
        }
        public void Configuration_CanBeEnumerated_Succeeds()
        {
            const int numberOfRequirements = 50;

            IConfigurationRequirement[] requirements = TestUtil
                                                       .CreateIConfigurationRequirementCollection(numberOfRequirements, randomTypes: true)
                                                       .ToArray();

            Dictionary <IConfigurationRequirement, object> supplied = requirements
                                                                      .Select(x =>
                                                                              new KeyValuePair <IConfigurationRequirement, object>(
                                                                                  x,
                                                                                  TestUtil.GetDefaultValidObjectForRequirement(x)))
                                                                      .ToDictionary(x => x.Key, x => x.Value);

            IMapping[] expected = supplied.Select(x => new Mapping(x.Key, x.Value)).ToArray();

            IRequirementSource requirementSource = ConfigurationTests.CreateRequirementSource(requirements);

            IConfiguration configuration = new Configuration(requirementSource, supplied);

            IMapping[] actual = configuration.ToArray();

            CollectionAssert.AreEquivalent(expected, actual);
        }
        public void Configuration_Ctor_RequiredDependsOnMissing_MultipleMissing_ThrowsAggregate()
        {
            const int numberOfMissingDependedUpons = 5;

            IConfigurationRequirement[] dependedUpons = Enumerable
                                                        .Range(1, numberOfMissingDependedUpons)
                                                        .Select(x => TestUtil.CreateConfigurationRequirement(isOptional: true))
                                                        .ToArray();
            IConfigurationRequirement[] dependsOns = dependedUpons
                                                     .Select(x => TestUtil.CreateConfigurationRequirement(dependsOn: new IConfigurationRequirement[] { x }))
                                                     .ToArray();

            Dictionary <IConfigurationRequirement, object> values = dependsOns
                                                                    .Select(x => new KeyValuePair <IConfigurationRequirement, object>(
                                                                                x,
                                                                                TestUtil.GetDefaultValidObjectForRequirement(x)))
                                                                    .ToDictionary(x => x.Key, x => x.Value);

            IRequirementSource configurable = ConfigurationTests.CreateRequirementSource(dependsOns);
            AggregateException exception    = Assert.ThrowsException <AggregateException>(() =>
                                                                                          new Configuration(configurable, values));

            Assert.AreEqual(numberOfMissingDependedUpons, exception.InnerExceptions.Count);
            Assert.IsTrue(
                exception
                .InnerExceptions
                .Select(x => x.Message)
                .All(x => x.Contains("does not have its dependencies fulfilled.")),
                "Unexpected exception message encountered.");
        }
        public void Configuration_Ctor_MultipleFailuresOccur_ThrowsAggregateException()
        {
            const string validationFailureMessage = "BOUNDCONFIGURATIONTESTS_MultipleFailuresOccur";
            const string testFailureMessage       = "Missing/too many matches for expected exception.";
            const int    expectedFailureCount     = 4;

            IConfigurationRequirement requiredButMissing = TestUtil.CreateConfigurationRequirement(
                baseName: nameof(requiredButMissing),
                isOptional: false);
            IConfigurationRequirement dependsOnIsMissing = TestUtil.CreateConfigurationRequirement(
                baseName: nameof(dependsOnIsMissing),
                dependsOn: new IConfigurationRequirement[] { requiredButMissing });
            IConfigurationRequirement failsValidation = TestUtil.CreateConfigurationRequirement(
                baseName: nameof(failsValidation),
                validator: (x, y, z) => throw new NotImplementedException(validationFailureMessage));
            IConfigurationRequirement exclusiveWith = TestUtil.CreateConfigurationRequirement(
                baseName: nameof(exclusiveWith),
                exclusiveWith: new IConfigurationRequirement[] { failsValidation });
            IConfigurationRequirement isFine = TestUtil.CreateConfigurationRequirement(
                baseName: nameof(isFine),
                validator: (x, y, z) => null);

            IRequirementSource configurable = ConfigurationTests.CreateRequirementSource(
                requiredButMissing,
                dependsOnIsMissing,
                failsValidation,
                exclusiveWith,
                isFine);

            Dictionary <IConfigurationRequirement, object> bindings =
                new IConfigurationRequirement[] { dependsOnIsMissing, failsValidation, exclusiveWith, isFine }
            .Select(x => new KeyValuePair <IConfigurationRequirement, object>(x, null))
            .ToDictionary(x => x.Key, x => x.Value);

            AggregateException exception = Assert.ThrowsException <AggregateException>(() =>
                                                                                       new Configuration(configurable, bindings));

            Assert.AreEqual(expectedFailureCount, exception.InnerExceptions.Count);
            Assert.IsNotNull(
                exception
                .InnerExceptions
                .SingleOrDefault(x => x.Message.Contains(validationFailureMessage)),
                testFailureMessage);
            Assert.IsNotNull(
                exception
                .InnerExceptions
                .SingleOrDefault(x => x.Message.Contains("has conflicting requirements specified.")),
                testFailureMessage);
            Assert.IsNotNull(
                exception
                .InnerExceptions
                .SingleOrDefault(x => x.Message.Contains("does not have its dependencies fulfilled.")),
                testFailureMessage);
            Assert.IsNotNull(
                exception
                .InnerExceptions
                .SingleOrDefault(x => x.Message.Contains("Missing required requirement")),
                testFailureMessage);
        }
        public void Configuration_GetOrDefault_ValueFactoryNull_ThrowsArgumentNull()
        {
            Configuration configuration = ConfigurationTests.CreateConfiguration(
                TestUtil.GetDefaultValidObjectForRequirement,
                out IConfigurationRequirement requirement);

            Assert.ThrowsException <ArgumentNullException>(() => configuration.GetOrDefault(requirement, null));
        }
        public void Configuration_TryGetOrDefault_RequirementNull_ThrowsArgumentNull()
        {
            Configuration configuration = ConfigurationTests.CreateConfiguration(
                TestUtil.GetDefaultValidObjectForRequirement,
                out IConfigurationRequirement requirement);

            Assert.ThrowsException <ArgumentNullException>(
                () => configuration.TryGetOrDefault <object>(null, () => null, out object dontCare));
        }
        public void Configuration_Ctor_RequiredRequirementIsNotPresent_ThrowsAggregate()
        {
            IConfigurationRequirement required =
                TestUtil.CreateConfigurationRequirement(isOptional: false);

            IRequirementSource configurable = ConfigurationTests.CreateRequirementSource(required);

            AggregateException exception = Assert.ThrowsException <AggregateException>(() =>
                                                                                       new Configuration(configurable, new Dictionary <IConfigurationRequirement, object>()));

            Assert.AreEqual(1, exception.InnerExceptions.Count);
            StringAssert.Contains(exception.InnerExceptions.Single().Message, "Missing required requirement");
        }
        public void Configuration_TryGetOrDefault_ValueNotPresent_UsesValueFactory()
        {
            ConfigurationRequirementType type = ConfigurationRequirementType.Uri;

            Configuration configuration = ConfigurationTests.CreateConfiguration(
                TestUtil.GetDefaultValidObjectForRequirement,
                out IConfigurationRequirement present);
            IConfigurationRequirement notPresent = TestUtil.CreateConfigurationRequirement(type: type);

            Uri expected = (Uri)TestUtil.GetDefaultValidObjectForRequirement(notPresent);

            Assert.IsFalse(configuration.TryGetOrDefault(notPresent, () => expected, out Uri actual));
            Assert.AreEqual(expected, actual);
        }
        public void Configuration_TryGetOrDefault_ValuePresentButWrongType_ConversionFails_UsesValueFactory()
        {
            const string expected = "Configuration_TryGetOrDefault";

            // `expected` must be of a different type than `type`
            ConfigurationRequirementType type = ConfigurationRequirementType.Int32;

            Configuration configuration = ConfigurationTests.CreateConfiguration(
                TestUtil.GetDefaultValidObjectForRequirement,
                out IConfigurationRequirement requirement,
                () => TestUtil.CreateConfigurationRequirement(type: type));

            Assert.IsFalse(configuration.TryGetOrDefault <string>(requirement, () => expected, out string actual));
            Assert.AreEqual(expected, actual);
        }
        public void Configuration_TryGetOrDefault_ValuePresentButWrongType_ConversionSucceeds()
        {
            const long expected    = 8675309L;
            const int  notExpected = 111111;

            ConfigurationRequirementType type = ConfigurationRequirementType.Int32;

            Configuration configuration = ConfigurationTests.CreateConfiguration(
                x => expected,
                out IConfigurationRequirement requirement,
                () => TestUtil.CreateConfigurationRequirement(type: type));

            Assert.IsTrue(configuration.TryGetOrDefault <long>(requirement, () => notExpected, out long actual));
            Assert.AreEqual(expected, actual);
        }
        public void Configuration_Indexer_Get_Succeeds()
        {
            IConfigurationRequirement requirement = TestUtil.CreateConfigurationRequirement();
            object expected = TestUtil.GetDefaultValidObjectForRequirement(requirement);
            Dictionary <IConfigurationRequirement, object> bindings =
                new Dictionary <IConfigurationRequirement, object>()
            {
                [requirement] = expected
            };

            IRequirementSource configurable = ConfigurationTests.CreateRequirementSource(requirement);

            Configuration configuration = new Configuration(configurable, bindings);

            Assert.AreEqual(expected, configuration[requirement]);
        }
        public void Configuration_GetOrDefault_Succeeds()
        {
            object expected = null;
            Func <IConfigurationRequirement, object> valueFactory =
                x =>
            {
                expected = TestUtil.GetDefaultValidObjectForRequirement(x);
                return(expected);
            };

            Configuration configuration = ConfigurationTests.CreateConfiguration(
                valueFactory,
                out IConfigurationRequirement requirement);

            Assert.AreEqual(expected, configuration.GetOrDefault(requirement, () => null));
        }
        private static Configuration CreateConfiguration(
            Func <IConfigurationRequirement, object> valueFactory,
            out IConfigurationRequirement requirement,
            Func <IConfigurationRequirement> requirementFactory = null)
        {
            requirement = (requirementFactory ?? (() => TestUtil.CreateConfigurationRequirement())).Invoke();
            Dictionary <IConfigurationRequirement, object> bindings =
                new Dictionary <IConfigurationRequirement, object>()
            {
                [requirement] = valueFactory.Invoke(requirement)
            };

            IRequirementSource configurable = ConfigurationTests.CreateRequirementSource(requirement);

            return(new Configuration(configurable, bindings));
        }
        public void Configuration_GetOrDefault_ValueNotPresent_UsesValueFactory()
        {
            const string fallbackValue = "Configuration_GetOrDefault";

            IConfigurationRequirement present    = TestUtil.CreateConfigurationRequirement();
            IConfigurationRequirement notPresent = TestUtil.CreateConfigurationRequirement(isOptional: true);
            object expected = TestUtil.GetDefaultValidObjectForRequirement(present);
            Dictionary <IConfigurationRequirement, object> bindings =
                new Dictionary <IConfigurationRequirement, object>()
            {
                [present] = expected
            };

            IRequirementSource configurable = ConfigurationTests.CreateRequirementSource(notPresent);

            Configuration configuration = new Configuration(configurable, bindings);

            Assert.AreEqual(fallbackValue, configuration.GetOrDefault(notPresent, () => fallbackValue));
        }
        public void Configuration_Ctor_RequirementFailsValidation_ThrowsAggregate()
        {
            const string exceptionMessage = "BOUNDCONFIGURATIONTESTS_RequirementFailsValidation";

            IConfigurationRequirement required = TestUtil.CreateConfigurationRequirement(
                validator: (x, y, z) => throw new NotImplementedException(exceptionMessage));

            IRequirementSource configurable = ConfigurationTests.CreateRequirementSource(required);

            AggregateException exception = Assert.ThrowsException <AggregateException>(() =>
                                                                                       new Configuration(
                                                                                           configurable,
                                                                                           new Dictionary <IConfigurationRequirement, object>()
            {
                [required] = "dontCare"
            }));

            Assert.AreEqual(1, exception.InnerExceptions.Count);
            Assert.AreEqual(exceptionMessage, exception.InnerExceptions.Single().Message);
        }
        public void Configuration_TryGetOrDefault_Succeeds()
        {
            // The type here needs to match the expected generic type used later.
            ConfigurationRequirementType type = ConfigurationRequirementType.Bool;

            bool expected = false;

            Configuration configuration = ConfigurationTests.CreateConfiguration(
                x =>
            {
                // Use the inverse of the default value for our expected (just in case the default somehow slips in)
                expected = !(bool)TestUtil.GetDefaultValidObjectForRequirement(x);
                return(expected);
            },
                out IConfigurationRequirement requirement,
                () => TestUtil.CreateConfigurationRequirement(type: type));

            Assert.IsTrue(configuration.TryGetOrDefault <bool>(requirement, () => !expected, out bool actual));
            Assert.AreEqual(expected, actual);
        }
        public void Configuration_Ctor_RequirementDependsOnMissing_ThrowsAggregate()
        {
            // dependedUpon needs to be optional or we'll get two errors (because required requirement is missing).
            IConfigurationRequirement dependedUpon = TestUtil.CreateConfigurationRequirement(isOptional: true);
            IConfigurationRequirement dependsOn    = TestUtil.CreateConfigurationRequirement(
                type: ConfigurationRequirementType.String,
                dependsOn: new IConfigurationRequirement[] { dependedUpon });

            IRequirementSource configurable = ConfigurationTests.CreateRequirementSource(dependedUpon, dependsOn);

            AggregateException exception = Assert.ThrowsException <AggregateException>(() =>
                                                                                       new Configuration(
                                                                                           configurable,
                                                                                           new Dictionary <IConfigurationRequirement, object>()
            {
                [dependsOn] = "Passes validation"
            }));

            Assert.AreEqual(1, exception.InnerExceptions.Count);
            StringAssert.Contains(
                exception.InnerExceptions.Single().Message,
                "does not have its dependencies fulfilled.");
        }
        public void Configuration_Ctor_ExclusiveRequirementsSupplied_ThrowsAggregate()
        {
            IConfigurationRequirement first = TestUtil.CreateConfigurationRequirement(
                type: ConfigurationRequirementType.String);
            IConfigurationRequirement second = TestUtil.CreateConfigurationRequirement(
                type: ConfigurationRequirementType.String,
                exclusiveWith: new IConfigurationRequirement[] { first });

            IRequirementSource configurable = ConfigurationTests.CreateRequirementSource(first, second);

            AggregateException exception = Assert.ThrowsException <AggregateException>(() =>
                                                                                       new Configuration(
                                                                                           configurable,
                                                                                           new Dictionary <IConfigurationRequirement, object>()
            {
                [first]  = "Passes validation",
                [second] = "Also passes validation"
            }));

            Assert.AreEqual(1, exception.InnerExceptions.Count);
            StringAssert.Contains(
                exception.InnerExceptions.Single().Message,
                "has conflicting requirements specified.");
        }