Example #1
0
        public void CopyConstructor_DoesDeepCopyOfOtherModels()
        {
            // Arrange
            var action = new ActionModel(typeof(TestController).GetMethod(nameof(TestController.Edit)),
                                         new List<object>());

            var parameter = new ParameterModel(action.ActionMethod.GetParameters()[0],
                                               new List<object>());
            parameter.Action = action;
            action.Parameters.Add(parameter);

            var route = new AttributeRouteModel(new HttpGetAttribute("api/Products"));
            action.Selectors.Add(new SelectorModel()
            {
                AttributeRouteModel = route
            });

            var apiExplorer = action.ApiExplorer;
            apiExplorer.IsVisible = false;
            apiExplorer.GroupName = "group1";

            // Act
            var action2 = new ActionModel(action);

            // Assert
            Assert.NotSame(action, action2.Parameters[0]);
            Assert.NotSame(apiExplorer, action2.ApiExplorer);
            Assert.NotSame(action.Selectors, action2.Selectors);
            Assert.NotNull(action2.Selectors);
            Assert.Single(action2.Selectors);
            Assert.NotSame(route, action2.Selectors[0].AttributeRouteModel);
        }
Example #2
0
        public AttributeRouteModel(AttributeRouteModel other)
        {
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }

            Attribute = other.Attribute;
            Name = other.Name;
            Order = other.Order;
            Template = other.Template;
        }
Example #3
0
        public SelectorModel(SelectorModel other)
        {
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }

            ActionConstraints = new List<IActionConstraintMetadata>(other.ActionConstraints);

            if (other.AttributeRouteModel != null)
            {
                AttributeRouteModel = new AttributeRouteModel(other.AttributeRouteModel);
            }
        }
Example #4
0
        public SelectorModel(SelectorModel other)
        {
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }

            ActionConstraints = new List <IActionConstraintMetadata>(other.ActionConstraints);

            if (other.AttributeRouteModel != null)
            {
                AttributeRouteModel = new AttributeRouteModel(other.AttributeRouteModel);
            }
        }
        /// <summary>
        /// Copy constructor for <see cref="AttributeRoute"/>.
        /// </summary>
        /// <param name="other">The <see cref="AttributeRouteModel"/> to copy.</param>
        public AttributeRouteModel(AttributeRouteModel other)
        {
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }

            Attribute = other.Attribute;
            Name      = other.Name;
            Order     = other.Order;
            Template  = other.Template;
            SuppressLinkGeneration = other.SuppressLinkGeneration;
            SuppressPathMatching   = other.SuppressPathMatching;
        }
        public void ReplaceTokens_InvalidFormat(string template, Dictionary <string, string> values, string reason)
        {
            // Arrange
            var expected = string.Format(
                "The route template '{0}' has invalid syntax. {1}",
                template,
                reason);

            // Act
            var ex = Assert.Throws <InvalidOperationException>(
                () => { AttributeRouteModel.ReplaceTokens(template, values); });

            // Assert
            Assert.Equal(expected, ex.Message);
        }
Example #7
0
        public void Combine_RightOverridesReflectedAttributeRouteModel(
            AttributeRouteModel left,
            AttributeRouteModel right)
        {
            // Arrange
            var expectedTemplate = AttributeRouteModel.CombineTemplates(null, right.Template);

            // Act
            var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right);

            // Assert
            Assert.NotNull(combined);
            Assert.Equal(expectedTemplate, combined.Template);
            Assert.Equal(combined.Order, right.Order);
        }
Example #8
0
        public void ReplaceTokens_ValidValues(string template, object values, string expected)
        {
            // Arrange
            var valuesDictionary = values as IDictionary <string, object>;

            if (valuesDictionary == null)
            {
                valuesDictionary = new RouteValueDictionary(values);
            }

            // Act
            var result = AttributeRouteModel.ReplaceTokens(template, valuesDictionary);

            // Assert
            Assert.Equal(expected, result);
        }
        private static AttributeRouteInfo CreateAttributeRouteInfo(AttributeRouteModel routeModel)
        {
            if (routeModel == null)
            {
                return(null);
            }

            return(new AttributeRouteInfo
            {
                Template = routeModel.Template,
                Order = routeModel.Order ?? DefaultAttributeRouteOrder,
                Name = routeModel.Name,
                SuppressLinkGeneration = routeModel.SuppressLinkGeneration,
                SuppressPathMatching = routeModel.SuppressPathMatching,
            });
        }
        public static IEnumerable <(AttributeRouteModel?route, SelectorModel actionSelector, SelectorModel?controllerSelector)> GetAttributeRoutes(ActionModel actionModel)
        {
            var controllerAttributeRoutes = actionModel.Controller.Selectors
                                            .Where(sm => sm.AttributeRouteModel != null)
                                            .Select(sm => sm.AttributeRouteModel)
                                            .ToList();

            foreach (var actionSelectorModel in actionModel.Selectors)
            {
                var actionRouteModel = actionSelectorModel.AttributeRouteModel;

                // We check the action to see if the template allows combination behavior
                // (It doesn't start with / or ~/) so that in the case where we have multiple
                // [Route] attributes on the controller we don't end up creating multiple
                if (actionRouteModel != null && actionRouteModel.IsAbsoluteTemplate)
                {
                    var route = AttributeRouteModel.CombineAttributeRouteModel(
                        left: null,
                        right: actionRouteModel);

                    yield return(route, actionSelectorModel, null);
                }
                else if (controllerAttributeRoutes.Count > 0)
                {
                    for (var i = 0; i < actionModel.Controller.Selectors.Count; i++)
                    {
                        // We're using the attribute routes from the controller
                        var controllerSelector = actionModel.Controller.Selectors[i];

                        var route = AttributeRouteModel.CombineAttributeRouteModel(
                            controllerSelector.AttributeRouteModel,
                            actionRouteModel);

                        yield return(route, actionSelectorModel, controllerSelector);
                    }
                }

                else
                {
                    var route = AttributeRouteModel.CombineAttributeRouteModel(
                        left: null,
                        right: actionRouteModel);

                    yield return(route, actionSelectorModel, null);
                }
            }
        }
Example #11
0
        public void Combine_SetsSuppressPathGenerationToTrue_IfEitherIsTrue(bool leftSuppress, bool rightSuppress)
        {
            // Arrange
            var left = new AttributeRouteModel
            {
                Template             = "Template",
                SuppressPathMatching = leftSuppress,
            };
            var right = new AttributeRouteModel
            {
                SuppressPathMatching = rightSuppress,
            };
            var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right);

            // Assert
            Assert.True(combined.SuppressPathMatching);
        }
        internal static PageConventionCollection AddAreaFolderRouteInternal(this PageConventionCollection conventions,
                                                                            string areaName, string folderPath, string folderRoute, bool isAdmin)
        {
            conventions.AddAreaFolderRouteModelConvention(areaName, folderPath, model =>
            {
                if (isAdmin != (model.ViewEnginePath.Contains("/Admin/") || model.Properties.ContainsKey("Admin")))
                {
                    return;
                }

                var areaFolder = areaName + folderPath;

                foreach (var selector in model.Selectors.ToArray())
                {
                    var route = selector.AttributeRouteModel;

                    if (route.Template.StartsWith(areaFolder, StringComparison.Ordinal) || (route.Template == areaName && folderPath == "/"))
                    {
                        route.SuppressLinkGeneration = true;

                        string template;

                        if (route.Template == areaName && folderPath == "/")
                        {
                            template = folderRoute;
                        }
                        else
                        {
                            var cleanSubTemplate = route.Template.Substring(areaFolder.Length).TrimStart('/');
                            template             = AttributeRouteModel.CombineTemplates(folderRoute, cleanSubTemplate);
                        }

                        model.Selectors.Add(new SelectorModel
                        {
                            AttributeRouteModel = new AttributeRouteModel
                            {
                                Template = template
                            }
                        });
                    }
                }
            });

            return(conventions);
        }
Example #13
0
        public void CopyConstructor_CopiesAllProperties()
        {
            // Arrange
            var route = new AttributeRouteModel(new HttpGetAttribute("/api/Products"))
            {
                Name  = "products",
                Order = 5,
                SuppressLinkGeneration = true,
                SuppressPathMatching   = true,
            };

            // Act
            var route2 = new AttributeRouteModel(route);

            // Assert
            foreach (var property in typeof(AttributeRouteModel).GetProperties())
            {
                var value1 = property.GetValue(route);
                var value2 = property.GetValue(route2);

                if (typeof(IEnumerable <object>).IsAssignableFrom(property.PropertyType))
                {
                    Assert.Equal <object>((IEnumerable <object>)value1, (IEnumerable <object>)value2);

                    // Ensure non-default value
                    Assert.NotEmpty((IEnumerable <object>)value1);
                }
                else if (property.PropertyType.IsValueType ||
                         Nullable.GetUnderlyingType(property.PropertyType) != null)
                {
                    Assert.Equal(value1, value2);

                    // Ensure non-default value
                    Assert.NotEqual(value1, Activator.CreateInstance(property.PropertyType));
                }
                else
                {
                    Assert.Same(value1, value2);

                    // Ensure non-default value
                    Assert.NotNull(value1);
                }
            }
        }
Example #14
0
        public void CopyConstructor_DoesDeepCopyOfOtherModels()
        {
            // Arrange
            var action = new ActionModel(typeof(TestController).GetMethod(nameof(TestController.Edit)),
                                         new List <object>());

            var parameter = new ParameterModel(action.ActionMethod.GetParameters()[0],
                                               new List <object>());

            parameter.Action = action;
            action.Parameters.Add(parameter);

            var route = new AttributeRouteModel(new HttpGetAttribute("api/Products"));

            action.Selectors.Add(new SelectorModel()
            {
                AttributeRouteModel = route
            });

            var apiExplorer = action.ApiExplorer;

            apiExplorer.IsVisible = false;
            apiExplorer.GroupName = "group1";

            // Act
            var action2 = new ActionModel(action);

            // Assert
            Assert.NotSame(action.Parameters, action2.Parameters);
            Assert.NotNull(action2.Parameters);
            Assert.Single(action2.Parameters);
            Assert.NotSame(parameter, action2.Parameters[0]);
            Assert.NotSame(apiExplorer, action2.ApiExplorer);
            Assert.NotSame(action.Selectors, action2.Selectors);
            Assert.NotNull(action2.Selectors);
            Assert.Single(action2.Selectors);
            Assert.NotSame(action.Selectors[0], action2.Selectors[0]);
            Assert.NotSame(route, action2.Selectors[0].AttributeRouteModel);

            Assert.NotSame(action, action2.Parameters[0].Action);
            Assert.Same(action2, action2.Parameters[0].Action);
        }
        public void CopyConstructor_DoesDeepCopyOfOtherModels()
        {
            // Arrange
            var controller = new ControllerModel(typeof(TestController).GetTypeInfo(),
                                                 new List <object>());

            var action = new ActionModel(typeof(TestController).GetMethod("Edit"),
                                         new List <object>());

            controller.Actions.Add(action);
            action.Controller = controller;

            var route = new AttributeRouteModel(new HttpGetAttribute("api/Products"));

            controller.Selectors.Add(new SelectorModel()
            {
                AttributeRouteModel = route
            });

            var apiExplorer = controller.ApiExplorer;

            controller.ApiExplorer.GroupName = "group";
            controller.ApiExplorer.IsVisible = true;

            // Act
            var controller2 = new ControllerModel(controller);

            // Assert
            Assert.NotSame(action, controller2.Actions[0]);
            Assert.NotNull(controller2.Selectors);
            Assert.Single(controller2.Selectors);
            Assert.NotSame(route, controller2.Selectors[0].AttributeRouteModel);
            Assert.NotSame(apiExplorer, controller2.ApiExplorer);

            Assert.NotSame(controller.Selectors[0].ActionConstraints, controller2.Selectors[0].ActionConstraints);
            Assert.NotSame(controller.Actions, controller2.Actions);
            Assert.NotSame(controller.Attributes, controller2.Attributes);
            Assert.NotSame(controller.Filters, controller2.Filters);
            Assert.NotSame(controller.RouteValues, controller2.RouteValues);
        }
Example #16
0
        private static void PopulateRouteModel(PageRouteModel model, string pageRoute, string? routeTemplate)
        {
            model.RouteValues.Add("page", model.ViewEnginePath);

            var selectorModel = CreateSelectorModel(pageRoute, routeTemplate);
            model.Selectors.Add(selectorModel);

            var fileName = Path.GetFileName(model.RelativePath);
            if (!AttributeRouteModel.IsOverridePattern(routeTemplate) &&
                string.Equals(IndexFileName, fileName, StringComparison.OrdinalIgnoreCase))
            {
                // For pages without an override route, and ending in /Index.cshtml, we want to allow
                // incoming routing, but force outgoing routes to match to the path sans /Index.
                selectorModel.AttributeRouteModel!.SuppressLinkGeneration = true;

                var index = pageRoute.LastIndexOf('/');
                var parentDirectoryPath = index == -1 ?
                    string.Empty :
                    pageRoute.Substring(0, index);
                model.Selectors.Add(CreateSelectorModel(parentDirectoryPath, routeTemplate));
            }
        }
Example #17
0
        public void ReplaceTokens_UnknownValue(string template, string token)
        {
            // Arrange
            var values = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase)
            {
                { "area", "Help" },
                { "controller", "Admin" },
                { "action", "SeeUsers" },
            };

            var expected =
                $"While processing template '{template}', " +
                $"a replacement value for the token '{token}' could not be found. " +
                "Available tokens: 'action, area, controller'. To use a '[' or ']' as a literal string in a " +
                "route or within a constraint, use '[[' or ']]' instead.";

            // Act
            var ex = Assert.Throws <InvalidOperationException>(
                () => { AttributeRouteModel.ReplaceTokens(template, values); });

            // Assert
            Assert.Equal(expected, ex.Message);
        }
        public void Apply(ApplicationModel application)
        {
            var centralPrefix = new AttributeRouteModel(new RouteAttribute($"{routingModel.Prefix}/{routingModel.Controller}"));
            foreach (var controller in application.Controllers)
            {
                if (controller.ControllerType.UnderlyingSystemType == typeof(AppConfigurationController))
                {
                    var hasRouteAttributes = controller.Selectors.Any(selector => selector.AttributeRouteModel != null);
                    if (hasRouteAttributes)
                    {
                        // This controller manually defined some routes, so treat this 
                        // as an override and not apply the convention here.
                        continue;
                    }


                    foreach (var selector in controller.Selectors)
                    {
                        selector.AttributeRouteModel = centralPrefix;
                    }
                }
            }
        }
        public void ReplaceTokens_UnknownValue()
        {
            // Arrange
            var template = "[area]/[controller]/[action2]";
            var values   = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase)
            {
                { "area", "Help" },
                { "controller", "Admin" },
                { "action", "SeeUsers" },
            };

            var expected =
                "While processing template '[area]/[controller]/[action2]', " +
                "a replacement value for the token 'action2' could not be found. " +
                "Available tokens: 'action, area, controller'.";

            // Act
            var ex = Assert.Throws <InvalidOperationException>(
                () => { AttributeRouteModel.ReplaceTokens(template, values); });

            // Assert
            Assert.Equal(expected, ex.Message);
        }
Example #20
0
        public void Combine_RightOverridesReflectedAttributeRouteModel(
            AttributeRouteModel left,
            AttributeRouteModel right)
        {
            // Arrange
            var expectedTemplate = AttributeRouteModel.CombineTemplates(null, right.Template);

            // Act
            var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right);

            // Assert
            Assert.NotNull(combined);
            Assert.Equal(expectedTemplate, combined.Template);
            Assert.Equal(combined.Order, right.Order);
        }
Example #21
0
        public void Combine_Names(
            AttributeRouteModel left,
            AttributeRouteModel right,
            string expectedName)
        {
            // Arrange & Act
            var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right);

            // Assert
            Assert.NotNull(combined);
            Assert.Equal(expectedName, combined.Name);
        }
Example #22
0
 private static string ChooseName(
     AttributeRouteModel left,
     AttributeRouteModel right)
 {
     if (right.Name == null && string.IsNullOrEmpty(right.Template))
     {
         return left.Name;
     }
     else
     {
         return right.Name;
     }
 }
Example #23
0
        public void Combine_NullOrNullTemplateReflectedAttributeRouteModels(
            AttributeRouteModel left,
            AttributeRouteModel right)
        {
            // Arrange & Act
            var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right);

            // Assert
            Assert.Null(combined);
        }
        public static IEnumerable <SelectorModel> FlattenSelectors(ActionModel actionModel)
        {
            // Loop through all attribute routes defined on the controller.
            // These perform a cross-product with all of the action-level attribute routes.
            var controllerSelectors = actionModel.Controller.Selectors
                                      .Where(sm => sm.AttributeRouteModel != null)
                                      .ToList();

            // We also include metadata and action constraints from the controller
            // even when there are no routes, or when an action overrides the route template.
            SelectorModel?additionalSelector = null;

            if (actionModel.Controller.Selectors.Count > 0)
            {
                // This logic seems arbitrary but there's a good reason for it.
                //
                // When we build the controller level selectors, any metadata or action constraints
                // that aren't IRouteTemplateProvider will be included in all selectors. So we
                // pick any selector and then grab all of the stuff that isn't IRouteTemplateProvider
                // then we've found all of the items that aren't routes.
                //
                // This is fragile wrt application model customizing the data - but no one has
                // run into an issue with this and its pretty esoteric.
                additionalSelector = new SelectorModel(actionModel.Controller.Selectors.First());
                additionalSelector.AttributeRouteModel = null;

                for (var i = additionalSelector.ActionConstraints.Count - 1; i >= 0; i--)
                {
                    if (additionalSelector.ActionConstraints[i] is IRouteTemplateProvider)
                    {
                        additionalSelector.ActionConstraints.RemoveAt(i);
                    }
                }

                for (var i = additionalSelector.EndpointMetadata.Count - 1; i >= 0; i--)
                {
                    if (additionalSelector.EndpointMetadata[i] is IRouteTemplateProvider)
                    {
                        additionalSelector.EndpointMetadata.RemoveAt(i);
                    }
                }
            }

            var actionConstraints = new List <IActionConstraintMetadata>();

            foreach (var actionSelector in actionModel.Selectors)
            {
                var actionRouteModel = actionSelector.AttributeRouteModel;

                // We check the action to see if the template allows combination behavior
                // (It doesn't start with / or ~/) so that in the case where we have multiple
                // [Route] attributes on the controller we don't end up creating multiple
                if (actionRouteModel != null && actionRouteModel.IsAbsoluteTemplate)
                {
                    // We're overriding the routes from the controller, but any *unbound* constraints
                    // still apply.
                    var selector = new SelectorModel(actionSelector);

                    selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(
                        left: null,
                        right: actionRouteModel);

                    AddActionConstraints(selector, additionalSelector?.ActionConstraints);
                    AddEndpointMetadata(selector, additionalSelector?.EndpointMetadata);

                    yield return(selector);
                }
                else if (controllerSelectors.Count > 0)
                {
                    for (var i = 0; i < controllerSelectors.Count; i++)
                    {
                        var controllerSelector = controllerSelectors[i];

                        // We're using the attribute routes from the controller
                        var selector = new SelectorModel(actionSelector);

                        selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(
                            controllerSelector.AttributeRouteModel,
                            actionRouteModel);

                        AddActionConstraints(selector, controllerSelector.ActionConstraints);
                        AddEndpointMetadata(selector, controllerSelector.EndpointMetadata);

                        // No need to include the additional selector here because it would duplicate
                        // data in controllerSelector.

                        yield return(selector);
                    }
                }
                else
                {
                    // There are no routes on the controller, but any *unbound* constraints
                    // still apply.
                    var selector = new SelectorModel(actionSelector);

                    selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(
                        left: null,
                        right: actionRouteModel);

                    AddActionConstraints(selector, additionalSelector?.ActionConstraints);
                    AddEndpointMetadata(selector, additionalSelector?.EndpointMetadata);

                    yield return(selector);
                }
            }
        }
 public GlobalRoutePrefixConvention(IRouteTemplateProvider routeTemplateProvider)
 {
     _centralPrefix = new AttributeRouteModel(routeTemplateProvider);
 }
Example #26
0
        public void Combine_Orders(
            AttributeRouteModel left,
            AttributeRouteModel right,
            int? expected)
        {
            // Arrange & Act
            var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right);

            // Assert
            Assert.NotNull(combined);
            Assert.Equal(expected, combined.Order);
        }
Example #27
0
        /// <summary>
        /// Combines two <see cref="AttributeRouteModel"/> instances and returns
        /// a new <see cref="AttributeRouteModel"/> instance with the result.
        /// </summary>
        /// <param name="left">The left <see cref="AttributeRouteModel"/>.</param>
        /// <param name="right">The right <see cref="AttributeRouteModel"/>.</param>
        /// <returns>A new instance of <see cref="AttributeRouteModel"/> that represents the
        /// combination of the two <see cref="AttributeRouteModel"/> instances or <c>null</c> if both
        /// parameters are <c>null</c>.</returns>
        public static AttributeRouteModel CombineAttributeRouteModel(
            AttributeRouteModel left,
            AttributeRouteModel right)
        {
            right = right ?? _default;

            // If the right template is an override template (starts with / or ~/)
            // we ignore the values from left.
            if (left == null || IsOverridePattern(right.Template))
            {
                left = _default;
            }

            var combinedTemplate = CombineTemplates(left.Template, right.Template);

            // The action is not attribute routed.
            if (combinedTemplate == null)
            {
                return null;
            }

            return new AttributeRouteModel()
            {
                Template = combinedTemplate,
                Order = right.Order ?? left.Order,
                Name = ChooseName(left, right),
            };
        }
Example #28
0
        public void Combine_ValidReflectedAttributeRouteModels(
            AttributeRouteModel left,
            AttributeRouteModel right,
            AttributeRouteModel expectedResult)
        {
            // Arrange & Act
            var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right);

            // Assert
            Assert.NotNull(combined);
            Assert.Equal(expectedResult.Template, combined.Template);
        }
        private static ControllerActionDescriptor CreateActionDescriptor(ActionModel action, AttributeRouteModel routeModel)
        {
            var parameterDescriptors = new List <ParameterDescriptor>();

            foreach (var parameter in action.Parameters)
            {
                var parameterDescriptor = CreateParameterDescriptor(parameter);
                parameterDescriptors.Add(parameterDescriptor);
            }

            var actionDescriptor = new ControllerActionDescriptor
            {
                ActionName         = action.ActionName,
                MethodInfo         = action.ActionMethod,
                Parameters         = parameterDescriptors,
                AttributeRouteInfo = CreateAttributeRouteInfo(routeModel),
            };

            return(actionDescriptor);
        }
Example #30
0
        public void CopyConstructor_CopiesAllProperties()
        {
            // Arrange
            var route = new AttributeRouteModel(new HttpGetAttribute("/api/Products"));

            route.Name = "products";
            route.Order = 5;

            // Act
            var route2 = new AttributeRouteModel(route);

            // Assert
            foreach (var property in typeof(AttributeRouteModel).GetProperties())
            {
                var value1 = property.GetValue(route);
                var value2 = property.GetValue(route2);

                if (typeof(IEnumerable<object>).GetTypeInfo().IsAssignableFrom(property.PropertyType.GetTypeInfo()))
                {
                    Assert.Equal<object>((IEnumerable<object>)value1, (IEnumerable<object>)value2);

                    // Ensure non-default value
                    Assert.NotEmpty((IEnumerable<object>)value1);
                }
                else if (property.PropertyType.GetTypeInfo().IsValueType ||
                    Nullable.GetUnderlyingType(property.PropertyType) != null)
                {
                    Assert.Equal(value1, value2);

                    // Ensure non-default value
                    Assert.NotEqual(value1, Activator.CreateInstance(property.PropertyType));
                }
                else
                {
                    Assert.Same(value1, value2);

                    // Ensure non-default value
                    Assert.NotNull(value1);
                }
            }
        }