Exemple #1
0
        /// <summary>
        /// Check that no parameters were removed or reordered, and compare them if it's not the case
        /// </summary>
        /// <param name="context">Comaprision Context</param>
        /// <param name="priorOperation">Operation object of old swagger</param>
        private void CheckParameters(ComparisonContext <ServiceDefinition> context, Operation priorOperation)
        {
            // Check that no parameters were removed or reordered, and compare them if it's not the case.

            var currentRoot  = context.CurrentRoot;
            var previousRoot = context.PreviousRoot;

            context.PushProperty("parameters");

            var priorOperationParameters = priorOperation.Parameters.Select(param =>
                                                                            string.IsNullOrWhiteSpace(param.Reference) ? param :
                                                                            FindReferencedParameter(param.Reference, previousRoot.Parameters)
                                                                            );

            foreach (var oldParam in priorOperationParameters)
            {
                SwaggerParameter newParam = FindParameter(oldParam.Name, Parameters, currentRoot.Parameters);

                // we should use PushItemByName instead of PushProperty because Swagger `parameters` is
                // an array of paremters.
                context.PushItemByName(oldParam.Name);

                if (newParam != null)
                {
                    newParam.Compare(context, oldParam);
                }
                else if (oldParam.IsRequired)
                {
                    // Removed required parameter
                    context.LogBreakingChange(ComparisonMessages.RemovedRequiredParameter, oldParam.Name);
                }

                context.Pop();
            }

            // Check that no required parameters were added.
            var requiredParamters = Parameters.Select(param =>
                                                      string.IsNullOrWhiteSpace(param.Reference) ?
                                                      param : FindReferencedParameter(param.Reference, currentRoot.Parameters))
                                    .Where(p => p != null && p.IsRequired);

            foreach (var newParam in requiredParamters)
            {
                if (newParam == null)
                {
                    continue;
                }

                SwaggerParameter oldParam = FindParameter(newParam.Name, priorOperation.Parameters, previousRoot.Parameters);

                if (oldParam == null)
                {
                    // Did not find required parameter in the old swagger i.e required parameter is added
                    context.PushItemByName(newParam.Name);
                    context.LogBreakingChange(ComparisonMessages.AddingRequiredParameter, newParam.Name);
                    context.Pop();
                }
            }
            context.Pop();
        }
        public static StringBuilder OnBuildMethodParameter(Method method,
            SwaggerParameter currentSwaggerParam,
            StringBuilder paramNameBuilder)
        {
            if (currentSwaggerParam == null)
            {
                throw new ArgumentNullException("currentSwaggerParam");
            }

            bool hasCollectionFormat = currentSwaggerParam.CollectionFormat != CollectionFormat.None;

            if (currentSwaggerParam.Type == DataType.Array && !hasCollectionFormat)
            {
                // If the parameter type is array default the collectionFormat to csv
                currentSwaggerParam.CollectionFormat = CollectionFormat.Csv;
            }

            if (hasCollectionFormat)
            {
                AddCollectionFormat(currentSwaggerParam, paramNameBuilder);
                if (currentSwaggerParam.In == ParameterLocation.Path)
                {
                    if (method == null || method.Url == null)
                    {
                       throw new ArgumentNullException("method");
                    }

                    method.Url = method.Url.Replace(
                        string.Format(CultureInfo.InvariantCulture, "{0}", currentSwaggerParam.Name),
                        string.Format(CultureInfo.InvariantCulture, "{0}", paramNameBuilder));
                }
            }
            return paramNameBuilder;
        }
Exemple #3
0
 private int FindParameterIndex(SwaggerParameter parameter, IEnumerable <SwaggerParameter> operationParameters)
 {
     for (int i = 0; i < operationParameters.Count(); i++)
     {
         if (operationParameters.ElementAt(i).Name == parameter.Name && operationParameters.ElementAt(i).In == parameter.In)
         {
             return(i);
         }
     }
     return(-1);
 }
Exemple #4
0
        private void CheckParameters(ComparisonContext context, Operation priorOperation)
        {
            // Check that no parameters were removed or reordered, and compare them if it's not the case.

            var currentRoot  = (context.CurrentRoot as ServiceDefinition);
            var previousRoot = (context.PreviousRoot as ServiceDefinition);

            foreach (var oldParam in priorOperation.Parameters
                     .Select(p => string.IsNullOrEmpty(p.Reference) ? p : FindReferencedParameter(p.Reference, previousRoot.Parameters)))
            {
                SwaggerParameter newParam = FindParameter(oldParam.Name, Parameters, currentRoot.Parameters);

                context.PushProperty(oldParam.Name);

                if (newParam != null)
                {
                    newParam.Compare(context, oldParam);
                }
                else if (oldParam.IsRequired)
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedRequiredParameter, oldParam.Name);
                }

                context.Pop();
            }

            // Check that no required parameters were added.

            foreach (var newParam in Parameters
                     .Select(p => string.IsNullOrEmpty(p.Reference) ? p : FindReferencedParameter(p.Reference, currentRoot.Parameters))
                     .Where(p => p != null && p.IsRequired))
            {
                if (newParam == null)
                {
                    continue;
                }

                SwaggerParameter oldParam = FindParameter(newParam.Name, priorOperation.Parameters, previousRoot.Parameters);

                if (oldParam == null)
                {
                    context.PushProperty(newParam.Name);
                    context.LogBreakingChange(ComparisonMessages.AddingRequiredParameter, newParam.Name);
                    context.Pop();
                }
            }
        }
        private static void AddCollectionFormat(SwaggerParameter swaggerParameter, StringBuilder parameterName)
        {
            if (swaggerParameter.In == ParameterLocation.FormData)
            {
                // http://vstfrd:8080/Azure/RD/_workitems/edit/3172874
                throw new NotImplementedException();
            }

            //Debug.Assert(!string.IsNullOrEmpty(swaggerParameter.CollectionFormat));
            Debug.Assert(swaggerParameter.CollectionFormat != CollectionFormat.None);
            parameterName.Append(":");

            switch (swaggerParameter.CollectionFormat)
            {
                case CollectionFormat.Csv:
                    parameterName.Append("commaSeparated");
                    break;

                case CollectionFormat.Pipes:
                    parameterName.Append("pipeSeparated");
                    break;

                case CollectionFormat.Ssv:
                    parameterName.Append("spaceSeparated");
                    break;

                case CollectionFormat.Tsv:
                    parameterName.Append("tabSeparated");
                    break;

                case CollectionFormat.Multi:
                    if (swaggerParameter.In != ParameterLocation.Query)
                    {
                        throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture,
                            Resources.MultiCollectionFormatNotSupported,
                            swaggerParameter.Name));
                    }
                    parameterName.Append("ampersandSeparated");
                    break;

                default:
                    throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
                        Resources.InvalidCollectionFormat,
                        swaggerParameter.CollectionFormat,
                        swaggerParameter.Name));
            }
        }
Exemple #6
0
        private static SwaggerParameter FindReferencedParameter(string reference, IDictionary <string, SwaggerParameter> parameters)
        {
            if (reference != null && reference.StartsWith("#", StringComparison.Ordinal))
            {
                var parts = reference.Split('/');
                if (parts.Length == 3 && parts[1].Equals("parameters"))
                {
                    SwaggerParameter p = null;
                    if (parameters.TryGetValue(parts[2], out p))
                    {
                        return(p);
                    }
                }
            }

            return(null);
        }
Exemple #7
0
        /// <summary>
        /// Finds given parameter in the list of operation parameters or global parameters ,
        /// </summary>
        /// <param name="parameter">the parameter to search</param>
        /// <param name="operationParameters">list of operation parameters to search</param>
        /// <param name="clientParameters">Dictionary of global paramters to search</param>
        /// <returns>Swagger Parameter if found; otherwise null</returns>
        private SwaggerParameter FindParameterEx(SwaggerParameter parameter, IEnumerable <SwaggerParameter> operationParameters, IDictionary <string, SwaggerParameter> clientParameters)
        {
            if (Parameters != null)
            {
                ///first try to find the param has same 'name' and 'in'
                foreach (var param in operationParameters)
                {
                    if (parameter.Name.Equals(param.Name) && parameter.In.Equals(param.In))
                    {
                        return(param);
                    }

                    var pRef = FindReferencedParameter(param.Reference, clientParameters);

                    if (pRef != null && parameter.Name.Equals(pRef.Name) && parameter.In.Equals(pRef.In))
                    {
                        return(pRef);
                    }
                }
            }
            /// then try to find the parameter has same 'name'
            return(FindParameter(parameter.Name, operationParameters, clientParameters));
        }
Exemple #8
0
        /// <summary>
        /// Check that no parameters were removed or reordered, and compare them if it's not the case
        /// </summary>
        /// <param name="context">Comaprision Context</param>
        /// <param name="priorOperation">Operation object of old swagger</param>
        private void CheckParameters(ComparisonContext <ServiceDefinition> context, Operation priorOperation)
        {
            // Check that no parameters were removed or reordered, and compare them if it's not the case.

            var currentRoot  = context.CurrentRoot;
            var previousRoot = context.PreviousRoot;

            context.PushProperty("parameters");

            var priorOperationParameters = priorOperation.Parameters.Select(param =>
                                                                            string.IsNullOrWhiteSpace(param.Reference) ? param :
                                                                            FindReferencedParameter(param.Reference, previousRoot.Parameters)
                                                                            );

            var currentOperationParameters = Parameters.Select(param =>
                                                               string.IsNullOrWhiteSpace(param.Reference) ? param :
                                                               FindReferencedParameter(param.Reference, currentRoot.Parameters));

            for (int i = 0; i < currentOperationParameters.Count(); i++)
            {
                var curOriginalParameter = Parameters.ElementAt(i);
                var curParameter         = currentOperationParameters.ElementAt(i);
                curParameter.Extensions.TryGetValue("x-ms-long-running-operation", out var curParameterLocation);
                if (
                    !string.IsNullOrWhiteSpace(curOriginalParameter.Reference) &&
                    (curParameterLocation == null || !curParameterLocation.Equals("method"))
                    )
                {
                    continue;
                }
                var priorIndex = FindParameterIndex(curParameter, priorOperationParameters);
                if (priorIndex != -1 && priorIndex != i)
                {
                    context.LogBreakingChange(ComparisonMessages.ChangedParameterOrder, curParameter.Name);
                }
            }

            foreach (var oldParam in priorOperationParameters)
            {
                SwaggerParameter newParam = FindParameterEx(oldParam, Parameters, currentRoot.Parameters);

                // we should use PushItemByName instead of PushProperty because Swagger `parameters` is
                // an array of paremters.
                context.PushItemByName(oldParam.Name);

                if (newParam != null)
                {
                    newParam.Compare(context, oldParam);
                }
                else if (oldParam.IsRequired)
                {
                    // Removed required parameter
                    context.LogBreakingChange(ComparisonMessages.RemovedRequiredParameter, oldParam.Name);
                }
                else
                {
                    // Removed optional parameter
                    context.LogBreakingChange(ComparisonMessages.RemovedOptionalParameter, oldParam.Name);
                }

                context.Pop();
            }

            // Check that no required or optional parameters were added.
            var allParamters = Parameters.Select(param =>
                                                 string.IsNullOrWhiteSpace(param.Reference) ?
                                                 param : FindReferencedParameter(param.Reference, currentRoot.Parameters))
                               .Where(p => p != null);

            foreach (var newParam in allParamters)
            {
                if (newParam == null)
                {
                    continue;
                }


                SwaggerParameter oldParam = FindParameterEx(newParam, priorOperation.Parameters, previousRoot.Parameters);

                if (oldParam == null)
                {
                    // Did not find required parameter in the old swagger i.e required parameter is added
                    context.PushItemByName(newParam.Name);
                    if (newParam.IsRequired)
                    {
                        context.LogBreakingChange(ComparisonMessages.AddingRequiredParameter, newParam.Name);
                    }
                    else
                    {
                        context.LogBreakingChange(ComparisonMessages.AddingOptionalParameter, newParam.Name);
                    }
                    context.Pop();
                }
            }
            context.Pop();
        }
        public SwaggerParameter Unwrap(SwaggerParameter swaggerParameter)
        {
            if (swaggerParameter == null)
            {
                throw new ArgumentNullException("swaggerParameter");
            }

            // If referencing global parameters serializationProperty
            if (swaggerParameter.Reference != null)
            {
                string referenceKey = swaggerParameter.Reference.StripParameterPath();
                if (!ServiceDefinition.Parameters.ContainsKey(referenceKey))
                {
                    throw new ArgumentException(
                        string.Format(CultureInfo.InvariantCulture,
                        Resources.DefinitionDoesNotExist, referenceKey));
                }

                swaggerParameter = ServiceDefinition.Parameters[referenceKey];
            }

            // Unwrap the schema if in "body"
            if (swaggerParameter.Schema != null && swaggerParameter.In == ParameterLocation.Body)
            {
                swaggerParameter.Schema = Resolver.Unwrap(swaggerParameter.Schema);
            }

            return swaggerParameter;
        }
        /// <summary>
        /// Compare a modified document node (this) to a previous one and look for breaking as well as non-breaking changes.
        /// </summary>
        /// <param name="context">The modified document context.</param>
        /// <param name="previous">The original document model.</param>
        /// <returns>A list of messages from the comparison.</returns>
        public override IEnumerable <ComparisonMessage> Compare(ComparisonContext context, SwaggerBase previous)
        {
            if (previous == null)
            {
                throw new ArgumentNullException("previous");
            }

            context.CurrentRoot  = this;
            context.PreviousRoot = previous;

            base.Compare(context, previous);

            var previousDefinition = previous as ServiceDefinition;

            if (previousDefinition == null)
            {
                throw new ArgumentException("Comparing a service definition with something else.");
            }

            if (Info != null && previousDefinition.Info != null)
            {
                context.PushProperty("info");
                context.PushProperty("version");

                CompareVersions(context, Info.Version, previousDefinition.Info.Version);

                context.Pop();
                context.Pop();
            }

            if (context.Strict)
            {
                // There was no version change between the documents. This is not an error, but noteworthy.
                context.LogInfo(ComparisonMessages.NoVersionChange);
            }

            // Check that all the protocols of the old version are supported by the new version.

            context.PushProperty("schemes");
            foreach (var scheme in previousDefinition.Schemes)
            {
                if (!Schemes.Contains(scheme))
                {
                    context.LogBreakingChange(ComparisonMessages.ProtocolNoLongerSupported, scheme);
                }
            }
            context.Pop();

            // Check that all the request body formats that were accepted still are.

            context.PushProperty("consumes");
            foreach (var format in previousDefinition.Consumes)
            {
                if (!Consumes.Contains(format))
                {
                    context.LogBreakingChange(ComparisonMessages.RequestBodyFormatNoLongerSupported, format);
                }
            }
            context.Pop();

            // Check that all the response body formats were also supported by the old version.

            context.PushProperty("produces");
            foreach (var format in Produces)
            {
                if (!previousDefinition.Produces.Contains(format))
                {
                    context.LogBreakingChange(ComparisonMessages.ResponseBodyFormatNowSupported, format);
                }
            }
            context.Pop();

            // Check that no paths were removed, and compare the paths that are still there.

            var newPaths = RemovePathVariables(Paths);

            context.PushProperty("paths");
            foreach (var path in previousDefinition.Paths.Keys)
            {
                var p = Regex.Replace(path, @"\{\w*\}", @"{}");

                context.PushProperty(path);

                Dictionary <string, Operation> operations = null;
                if (!newPaths.TryGetValue(p, out operations))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedPath, path);
                }
                else
                {
                    Dictionary <string, Operation> previousOperations = previousDefinition.Paths[path];
                    foreach (var previousOperation in previousOperations)
                    {
                        Operation newOperation = null;
                        if (!operations.TryGetValue(previousOperation.Key, out newOperation))
                        {
                            context.LogBreakingChange(ComparisonMessages.RemovedOperation, previousOperation.Value.OperationId);
                        }
                    }

                    foreach (var operation in operations)
                    {
                        Operation previousOperation = null;
                        if (previousDefinition.Paths[path].TryGetValue(operation.Key, out previousOperation))
                        {
                            context.PushProperty(operation.Key);
                            operation.Value.Compare(context, previousOperation);
                            context.Pop();
                        }
                    }
                }
                context.Pop();
            }
            context.Pop();

            newPaths = RemovePathVariables(CustomPaths);

            context.PushProperty("x-ms-paths");
            foreach (var path in previousDefinition.CustomPaths.Keys)
            {
                var p = Regex.Replace(path, @"\{\w*\}", @"{}");

                context.PushProperty(path);

                Dictionary <string, Operation> operations = null;
                if (!newPaths.TryGetValue(p, out operations))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedPath, path);
                }
                else
                {
                    Dictionary <string, Operation> previousOperations = previousDefinition.CustomPaths[path];
                    foreach (var previousOperation in previousOperations)
                    {
                        Operation newOperation = null;
                        if (!operations.TryGetValue(previousOperation.Key, out newOperation))
                        {
                            context.LogBreakingChange(ComparisonMessages.RemovedOperation, previousOperation.Value.OperationId);
                        }
                    }

                    foreach (var operation in operations)
                    {
                        Operation previousOperation = null;
                        if (previousDefinition.CustomPaths[path].TryGetValue(operation.Key, out previousOperation))
                        {
                            context.PushProperty(operation.Key);
                            operation.Value.Compare(context, previousOperation);
                            context.Pop();
                        }
                    }
                }
                context.Pop();
            }
            context.Pop();

            ReferenceTrackSchemas(this);
            ReferenceTrackSchemas(previousDefinition);

            context.PushProperty("parameters");
            foreach (var def in previousDefinition.Parameters.Keys)
            {
                SwaggerParameter parameter = null;
                if (!Parameters.TryGetValue(def, out parameter))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedClientParameter, def);
                }
                else
                {
                    context.PushProperty(def);
                    parameter.Compare(context, previousDefinition.Parameters[def]);
                    context.Pop();
                }
            }
            context.Pop();

            context.PushProperty("responses");
            foreach (var def in previousDefinition.Responses.Keys)
            {
                OperationResponse response = null;
                if (!Responses.TryGetValue(def, out response))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedDefinition, def);
                }
                else
                {
                    context.PushProperty(def);
                    response.Compare(context, previousDefinition.Responses[def]);
                    context.Pop();
                }
            }
            context.Pop();

            context.PushProperty("definitions");
            foreach (var def in previousDefinition.Definitions.Keys)
            {
                Schema schema    = null;
                Schema oldSchema = previousDefinition.Definitions[def];

                if (!Definitions.TryGetValue(def, out schema))
                {
                    if (oldSchema.IsReferenced)
                    {
                        // It's only an error if the definition is referenced in the old service.
                        context.LogBreakingChange(ComparisonMessages.RemovedDefinition, def);
                    }
                }
                else if (schema.IsReferenced && oldSchema.IsReferenced)
                {
                    context.PushProperty(def);
                    schema.Compare(context, previousDefinition.Definitions[def]);
                    context.Pop();
                }
            }
            context.Pop();

            context.Pop();

            return(context.Messages);
        }
        /// <summary>
        /// Compare a modified document node (this) to a previous one and look for breaking as well as non-breaking changes.
        /// </summary>
        /// <param name="context">The modified document context.</param>
        /// <param name="previous">The original document model.</param>
        /// <returns>A list of messages from the comparison.</returns>
        public override IEnumerable <ComparisonMessage> Compare(
            ComparisonContext <ServiceDefinition> context,
            ServiceDefinition previousDefinition
            )
        {
            if (context.CurrentRoot != this)
            {
                throw new ArgumentException("context.CurrentRoot != this");
            }
            if (context.PreviousRoot != previousDefinition)
            {
                throw new ArgumentException("context.PreviousRoot != previousDefinition");
            }

            if (previousDefinition == null)
            {
                throw new ArgumentException("Comparing a service definition with something else.");
            }

            base.Compare(context, previousDefinition);

            if (Info?.Version != null &&
                previousDefinition.Info?.Version != null)
            {
                context.PushProperty("info");
                context.PushProperty("version");

                CompareVersions(context, Info.Version, previousDefinition.Info.Version);

                context.Pop();
                context.Pop();
            }

            if (context.Strict)
            {
                // There was no version change between the documents. This is not an error, but noteworthy.
                context.LogInfo(ComparisonMessages.NoVersionChange);
            }

            // Check that all the protocols of the old version are supported by the new version.

            context.PushProperty("schemes");
            foreach (var scheme in previousDefinition.Schemes)
            {
                if (!Schemes.Contains(scheme))
                {
                    context.LogBreakingChange(ComparisonMessages.ProtocolNoLongerSupported, scheme);
                }
            }
            context.Pop();

            // Check that all the request body formats that were accepted still are.

            context.PushProperty("consumes");
            foreach (var format in previousDefinition.Consumes)
            {
                if (!Consumes.Contains(format))
                {
                    context.LogBreakingChange(ComparisonMessages.RequestBodyFormatNoLongerSupported, format);
                }
            }
            context.Pop();

            // Check that all the response body formats were also supported by the old version.

            context.PushProperty("produces");
            foreach (var format in Produces)
            {
                if (!previousDefinition.Produces.Contains(format))
                {
                    context.LogBreakingChange(ComparisonMessages.ResponseBodyFormatNowSupported, format);
                }
            }
            context.Pop();

            // Check that no paths were removed, and compare the paths that are still there.

            var newPaths = RemovePathVariables(Paths);

            context.PushProperty("paths");
            foreach (var path in previousDefinition.Paths.Keys)
            {
                var p = ObjectPath.OpenApiPathName(path);

                context.PushPathProperty(path);

                if (!newPaths.TryGetValue(p, out var operations))
                {
                    // Entrie path was removeed
                    context.LogBreakingChange(ComparisonMessages.RemovedPath, path);
                }
                else
                {
                    // 1. Remove this path from the current list to find the added paths
                    newPaths.Remove(p);
                    var copyOfOperations = operations.ToDictionary(e => e.Key, e => e.Value);

                    // 2. look for operation match inside this path
                    var previousOperations = previousDefinition.Paths[path];
                    foreach (var previousOperation in previousOperations)
                    {
                        if (!operations.TryGetValue(previousOperation.Key, out var newOperation))
                        {
                            // Operation was removed from the path
                            context.LogBreakingChange(ComparisonMessages.RemovedOperation, previousOperation.Value.OperationId);
                        }
                        else
                        {
                            copyOfOperations.Remove(previousOperation.Key);
                        }
                    }

                    // Look for added operations
                    foreach (var copyOfOperation in copyOfOperations)
                    {
                        context.PushProperty(copyOfOperation.Key);
                        context.LogInfo(ComparisonMessages.AddedOperation);
                        context.Pop();
                    }

                    // Compare operations
                    foreach (var operation in operations)
                    {
                        if (previousDefinition.Paths[path].TryGetValue(operation.Key, out var previousOperation))
                        {
                            context.PushProperty(operation.Key);
                            operation.Value.Compare(context, previousOperation);
                            context.Pop();
                        }
                    }
                }
                context.Pop();
            }

            // Check wether any new paths are being added
            foreach (var path in newPaths.Keys)
            {
                context.PushPathProperty(path);
                context.LogInfo(ComparisonMessages.AddedPath);
                context.Pop();
            }


            context.Pop();

            // Check for custom paths : x-ms-paths
            var newCustomPaths = RemovePathVariables(CustomPaths);

            context.PushProperty("x-ms-paths");
            foreach (var path in previousDefinition.CustomPaths.Keys)
            {
                var p = ObjectPath.OpenApiPathName(path);

                context.PushPathProperty(path);

                Dictionary <string, Operation> operations = null;
                if (!newCustomPaths.TryGetValue(p, out operations))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedPath, path);
                }
                else
                {
                    // 1. Remove this custom path from the current list to find the added paths
                    newCustomPaths.Remove(p);
                    Dictionary <string, Operation> copyOfOperations = operations.ToDictionary(e => e.Key, e => e.Value);

                    // 2. look for operation match inside this path
                    Dictionary <string, Operation> previousOperations = previousDefinition.CustomPaths[path];
                    foreach (var previousOperation in previousOperations)
                    {
                        Operation newOperation = null;
                        if (!operations.TryGetValue(previousOperation.Key, out newOperation))
                        {
                            context.LogBreakingChange(ComparisonMessages.RemovedOperation, previousOperation.Value.OperationId);
                        }
                    }

                    // Look for added operations
                    foreach (var copyOfOperation in copyOfOperations)
                    {
                        context.PushProperty(copyOfOperation.Key);
                        context.LogInfo(ComparisonMessages.AddedOperation);
                        context.Pop();
                    }

                    // Compare operations
                    foreach (var operation in operations)
                    {
                        Operation previousOperation = null;
                        if (previousDefinition.CustomPaths[path].TryGetValue(operation.Key, out previousOperation))
                        {
                            context.PushProperty(operation.Key);
                            operation.Value.Compare(context, previousOperation);
                            context.Pop();
                        }
                    }
                }
                context.Pop();
            }

            // Check wether any new paths are being added into x-ms-paths
            foreach (var path in newCustomPaths.Keys)
            {
                context.PushPathProperty(path);
                context.LogInfo(ComparisonMessages.AddedPath);
                context.Pop();
            }

            context.Pop();

            ReferenceTrackSchemas(this);
            ReferenceTrackSchemas(previousDefinition);

            context.PushProperty("parameters");
            foreach (var def in previousDefinition.Parameters.Keys)
            {
                SwaggerParameter parameter = null;
                if (!Parameters.TryGetValue(def, out parameter))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedClientParameter, def);
                }
                else
                {
                    context.PushProperty(def);
                    parameter.Compare(context, previousDefinition.Parameters[def]);
                    context.Pop();
                }
            }
            context.Pop();

            context.PushProperty("responses");
            foreach (var def in previousDefinition.Responses.Keys)
            {
                OperationResponse response = null;
                if (!Responses.TryGetValue(def, out response))
                {
                    context.LogBreakingChange(ComparisonMessages.RemovedDefinition, def);
                }
                else
                {
                    context.PushProperty(def);
                    response.Compare(context, previousDefinition.Responses[def]);
                    context.Pop();
                }
            }
            context.Pop();

            context.PushProperty("definitions");
            foreach (var def in previousDefinition.Definitions.Keys)
            {
                Schema schema    = null;
                Schema oldSchema = previousDefinition.Definitions[def];

                if (!Definitions.TryGetValue(def, out schema))
                {
                    if (oldSchema.IsReferenced)
                    {
                        // It's only an error if the definition is referenced in the old service.
                        context.LogBreakingChange(ComparisonMessages.RemovedDefinition, def);
                    }
                }
                else
                {
                    context.PushProperty(def);
                    schema.Compare(context, previousDefinition.Definitions[def]);
                    context.Pop();
                }
            }
            context.Pop();

            context.Pop();

            return(context.Messages);
        }
 public ParameterBuilder(SwaggerParameter swaggerParameter, SwaggerModeler modeler)
     : base(swaggerParameter, modeler)
 {
     _swaggerParameter = swaggerParameter;
 }