/// <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) { var priorResponse = previous as OperationResponse; if (priorResponse == null) { throw new ArgumentNullException("previous"); } if (context == null) { throw new ArgumentNullException("context"); } context.Direction = DataDirection.Response; base.Compare(context, previous); var headers = Headers != null ? Headers : new Dictionary<string, Header>(); var priorHeaders = priorResponse.Headers != null ? priorResponse.Headers : new Dictionary<string, Header>(); foreach (var header in headers) { context.Push(header.Key); Header oldHeader = null; if (!priorHeaders.TryGetValue(header.Key, out oldHeader)) { context.LogInfo(ComparisonMessages.AddingHeader, header.Key); } else { header.Value.Compare(context, oldHeader); } context.Pop(); } foreach (var header in priorHeaders) { context.Push(header.Key); Header newHeader = null; if (!headers.TryGetValue(header.Key, out newHeader)) { context.LogBreakingChange(ComparisonMessages.RemovingHeader, header.Key); } context.Pop(); } if (Schema != null && priorResponse.Schema != null) { Schema.Compare(context, priorResponse.Schema); } context.Direction = DataDirection.None; 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 virtual IEnumerable<ComparisonMessage> Compare(ComparisonContext context, SwaggerBase previous) { if (previous == null) throw new ArgumentNullException("previous"); if (context == null) throw new ArgumentNullException("context"); yield break; }
/// <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) { var priorParameter = previous as SwaggerParameter; if (priorParameter == null) { throw new ArgumentNullException("priorVersion"); } if (context == null) { throw new ArgumentNullException("context"); } context.Direction = DataDirection.Request; base.Compare(context, previous); if (In != priorParameter.In) { context.LogBreakingChange(ComparisonMessages.ParameterInHasChanged, priorParameter.In.ToString().ToLower(CultureInfo.CurrentCulture), In.ToString().ToLower(CultureInfo.CurrentCulture)); } if (this.IsConstant != priorParameter.IsConstant) { context.LogBreakingChange(ComparisonMessages.ConstantStatusHasChanged); } if (Reference != null && !Reference.Equals(priorParameter.Reference)) { context.LogBreakingChange(ComparisonMessages.ReferenceRedirection); } if (Schema != null && priorParameter.Schema != null) { Schema.Compare(context, priorParameter.Schema); } context.Direction = DataDirection.None; 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 virtual IEnumerable <ComparisonMessage> Compare(ComparisonContext context, SwaggerBase previous) { if (previous == null) { throw new ArgumentNullException("previous"); } if (context == null) { throw new ArgumentNullException("context"); } yield break; }
/// <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) { var priorParameter = previous as SwaggerParameter; if (priorParameter == null) { throw new ArgumentNullException("priorVersion"); } if (context == null) { throw new ArgumentNullException("context"); } context.Direction = DataDirection.Request; base.Compare(context, previous); if (In != priorParameter.In) { context.LogBreakingChange(ComparisonMessages.ParameterInHasChanged, priorParameter.In.ToString().ToLower(), In.ToString().ToLower()); } if (this.IsConstant != priorParameter.IsConstant) { context.LogBreakingChange(ComparisonMessages.ConstantStatusHasChanged); } if (Reference != null && !Reference.Equals(priorParameter.Reference)) { context.LogBreakingChange(ComparisonMessages.ReferenceRedirection); } if (Schema != null && priorParameter.Schema != null) { Schema.Compare(context, priorParameter.Schema); } context.Direction = DataDirection.None; 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 context, SwaggerBase previous) { var priorResponse = previous as OperationResponse; if (priorResponse == null) { throw new ArgumentNullException("previous"); } if (context == null) { throw new ArgumentNullException("context"); } context.Direction = DataDirection.Response; base.Compare(context, previous); var headers = Headers != null ? Headers : new Dictionary <string, Header>(); var priorHeaders = priorResponse.Headers != null ? priorResponse.Headers : new Dictionary <string, Header>(); foreach (var header in headers) { context.Push(header.Key); Header oldHeader = null; if (!priorHeaders.TryGetValue(header.Key, out oldHeader)) { context.LogInfo(ComparisonMessages.AddingHeader, header.Key); } else { header.Value.Compare(context, oldHeader); } context.Pop(); } foreach (var header in priorHeaders) { context.Push(header.Key); Header newHeader = null; if (!headers.TryGetValue(header.Key, out newHeader)) { context.LogBreakingChange(ComparisonMessages.RemovingHeader, header.Key); } context.Pop(); } if (Schema != null && priorResponse.Schema != null) { Schema.Compare(context, priorResponse.Schema); } context.Direction = DataDirection.None; 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 context, SwaggerBase previous) { var priorOperation = previous as Operation; var currentRoot = (context.CurrentRoot as ServiceDefinition); var previousRoot = (context.PreviousRoot as ServiceDefinition); if (priorOperation == null) { throw new ArgumentException("previous"); } base.Compare(context, previous); if (!OperationId.Equals(priorOperation.OperationId)) { context.LogBreakingChange(ComparisonMessages.ModifiedOperationId); } CheckParameters(context, priorOperation); if (Responses != null && priorOperation.Responses != null) { foreach (var response in Responses) { var oldResponse = priorOperation.FindResponse(response.Key, priorOperation.Responses); context.PushProperty(response.Key); if (oldResponse == null) { context.LogBreakingChange(ComparisonMessages.AddingResponseCode, response.Key); } else { response.Value.Compare(context, oldResponse); } context.Pop(); } foreach (var response in priorOperation.Responses) { var newResponse = this.FindResponse(response.Key, this.Responses); if (newResponse == null) { context.PushProperty(response.Key); context.LogBreakingChange(ComparisonMessages.RemovedResponseCode, response.Key); 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 context, SwaggerBase previous) { var prior = previous as SwaggerObject; if (prior == null) { throw new ArgumentNullException("priorVersion"); } if (context == null) { throw new ArgumentNullException("context"); } base.Compare(context, previous); if (Reference != null && !Reference.Equals(prior.Reference)) { context.LogBreakingChange(ComparisonMessages.ReferenceRedirection); } if (IsRequired != prior.IsRequired) { if (context.Direction != DataDirection.Response) { if (IsRequired && !prior.IsRequired) { context.LogBreakingChange(ComparisonMessages.RequiredStatusChange); } else { context.LogInfo(ComparisonMessages.RequiredStatusChange); } } } // Are the types the same? if (prior.Type.HasValue != Type.HasValue || (Type.HasValue && prior.Type.Value != Type.Value)) { context.LogBreakingChange(ComparisonMessages.TypeChanged); } // What about the formats? CompareFormats(context, prior); CompareItems(context, prior); if (Default != null && !Default.Equals(prior.Default) || (Default == null && !string.IsNullOrEmpty(prior.Default))) { context.LogBreakingChange(ComparisonMessages.DefaultValueChanged); } if (Type.HasValue && Type.Value == DataType.Array && prior.CollectionFormat != CollectionFormat) { context.LogBreakingChange(ComparisonMessages.ArrayCollectionFormatChanged); } CompareConstraints(context, prior); CompareProperties(context, prior); CompareEnums(context, prior); 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 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 context, SwaggerBase previous) { var priorSchema = previous as Schema; if (priorSchema == null) { throw new ArgumentNullException("priorVersion"); } if (context == null) { throw new ArgumentNullException("context"); } int referenced = 0; var thisSchema = this; if (!string.IsNullOrWhiteSpace(thisSchema.Reference)) { thisSchema = FindReferencedSchema(thisSchema.Reference, (context.CurrentRoot as ServiceDefinition).Definitions); referenced += 1; } if (!string.IsNullOrWhiteSpace(priorSchema.Reference)) { priorSchema = FindReferencedSchema(priorSchema.Reference, (context.PreviousRoot as ServiceDefinition).Definitions); referenced += 1; } // Avoid doing the comparison repeatedly by marking for which direction it's already been done. if (context.Direction != DataDirection.None && referenced == 2) { // Comparing two referenced schemas in the context of a parameter or response -- did we already do this? if (thisSchema._compareDirection == context.Direction || thisSchema._compareDirection == DataDirection.Both) { return(new ComparisonMessage[0]); } _compareDirection |= context.Direction; } if (thisSchema != this || priorSchema != previous) { return(thisSchema.Compare(context, priorSchema)); } base.Compare(context, previous); if (priorSchema.ReadOnly != ReadOnly) { context.LogBreakingChange(ComparisonMessages.ReadonlyPropertyChanged2, priorSchema.ReadOnly.ToString().ToLower(CultureInfo.CurrentCulture), ReadOnly.ToString().ToLower(CultureInfo.CurrentCulture)); } if ((priorSchema.Discriminator == null && Discriminator != null) || (priorSchema.Discriminator != null && !priorSchema.Discriminator.Equals(Discriminator))) { context.LogBreakingChange(ComparisonMessages.DifferentDiscriminator); } if ((priorSchema.Extends == null && Extends != null) || (priorSchema.Extends != null && !priorSchema.Extends.Equals(Extends))) { context.LogBreakingChange(ComparisonMessages.DifferentExtends); } if ((priorSchema.AllOf == null && AllOf != null) || (priorSchema.AllOf != null && AllOf == null)) { context.LogBreakingChange(ComparisonMessages.DifferentAllOf); } else if (priorSchema.AllOf != null) { CompareAllOfs(context, priorSchema); } context.PushProperty("properties"); CompareProperties(context, priorSchema); 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 context, SwaggerBase previous) { var prior = previous as SwaggerObject; if (prior == null) { throw new ArgumentNullException("priorVersion"); } if (context == null) { throw new ArgumentNullException("context"); } base.Compare(context, previous); if (Reference != null && !Reference.Equals(prior.Reference)) { context.LogBreakingChange(ComparisonMessages.ReferenceRedirection); } if (IsRequired != prior.IsRequired) { if (context.Direction != DataDirection.Response) { if (IsRequired && !prior.IsRequired) { context.LogBreakingChange(ComparisonMessages.RequiredStatusChange); } else { context.LogInfo(ComparisonMessages.RequiredStatusChange); } } } // Are the types the same? if (prior.Type.HasValue != Type.HasValue || (Type.HasValue && prior.Type.Value != Type.Value)) { context.LogBreakingChange(ComparisonMessages.TypeChanged); } // What about the formats? CompareFormats(context, prior); CompareItems(context, prior); if (Default != null && !Default.Equals(prior.Default) || (Default == null && !string.IsNullOrEmpty(prior.Default))) { context.LogBreakingChange(ComparisonMessages.DefaultValueChanged); } if (Type.HasValue && Type.Value == DataType.Array && prior.CollectionFormat != CollectionFormat) { context.LogBreakingChange(ComparisonMessages.ArrayCollectionFormatChanged); } CompareConstraints(context, prior); CompareProperties(context, prior); CompareEnums(context, prior); 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 context, SwaggerBase previous) { if (previous == null) throw new ArgumentNullException("previous"); context.CurrentRoot = this; context.PreviousRoot = previous; context.Push("#"); 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.Push("info/version"); CompareVersions(context, Info.Version, previousDefinition.Info.Version); 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.Push("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.Push("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.Push("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.Push("paths"); foreach (var path in previousDefinition.Paths.Keys) { var p = Regex.Replace(path, @"\{\w*\}", @"{}"); context.Push(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.Push(operation.Key); operation.Value.Compare(context, previousOperation); context.Pop(); } } } context.Pop(); } context.Pop(); newPaths = RemovePathVariables(CustomPaths); context.Push("x-ms-paths"); foreach (var path in previousDefinition.CustomPaths.Keys) { var p = Regex.Replace(path, @"\{\w*\}", @"{}"); context.Push(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.Push(operation.Key); operation.Value.Compare(context, previousOperation); context.Pop(); } } } context.Pop(); } context.Pop(); ReferenceTrackSchemas(this); ReferenceTrackSchemas(previousDefinition); context.Push("parameters"); foreach (var def in previousDefinition.Parameters.Keys) { SwaggerParameter parameter = null; if (!Parameters.TryGetValue(def, out parameter)) { context.LogBreakingChange(ComparisonMessages.RemovedClientParameter, def); } else { context.Push(def); parameter.Compare(context, previousDefinition.Parameters[def]); context.Pop(); } } context.Pop(); context.Push("responses"); foreach (var def in previousDefinition.Responses.Keys) { OperationResponse response = null; if (!Responses.TryGetValue(def, out response)) { context.LogBreakingChange(ComparisonMessages.RemovedDefinition, def); } else { context.Push(def); response.Compare(context, previousDefinition.Responses[def]); context.Pop(); } } context.Pop(); context.Push("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.Push(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 context, SwaggerBase previous) { var priorOperation = previous as Operation; var currentRoot = (context.CurrentRoot as ServiceDefinition); var previousRoot = (context.PreviousRoot as ServiceDefinition); if (priorOperation == null) { throw new ArgumentException("previous"); } base.Compare(context, previous); if (!OperationId.Equals(priorOperation.OperationId)) { context.LogBreakingChange(ComparisonMessages.ModifiedOperationId); } CheckParameters(context, priorOperation); if (Responses != null && priorOperation.Responses != null) { foreach (var response in Responses) { var oldResponse = priorOperation.FindResponse(response.Key, priorOperation.Responses); context.Push(response.Key); if (oldResponse == null) { context.LogBreakingChange(ComparisonMessages.AddingResponseCode, response.Key); } else { response.Value.Compare(context, oldResponse); } context.Pop(); } foreach (var response in priorOperation.Responses) { var newResponse = this.FindResponse(response.Key, this.Responses); if (newResponse == null) { context.Push(response.Key); context.LogBreakingChange(ComparisonMessages.RemovedResponseCode, response.Key); 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 context, SwaggerBase previous) { var priorSchema = previous as Schema; if (priorSchema == null) { throw new ArgumentNullException("priorVersion"); } if (context == null) { throw new ArgumentNullException("context"); } int referenced = 0; var thisSchema = this; if (!string.IsNullOrWhiteSpace(thisSchema.Reference)) { thisSchema = FindReferencedSchema(thisSchema.Reference, (context.CurrentRoot as ServiceDefinition).Definitions); referenced += 1; } if (!string.IsNullOrWhiteSpace(priorSchema.Reference)) { priorSchema = FindReferencedSchema(priorSchema.Reference, (context.PreviousRoot as ServiceDefinition).Definitions); referenced += 1; } // Avoid doing the comparison repeatedly by marking for which direction it's already been done. if (context.Direction != DataDirection.None && referenced == 2) { // Comparing two referenced schemas in the context of a parameter or response -- did we already do this? if (thisSchema._compareDirection == context.Direction || thisSchema._compareDirection == DataDirection.Both) { return new ComparisonMessage[0]; } _compareDirection |= context.Direction; } if (thisSchema != this || priorSchema != previous) { return thisSchema.Compare(context, priorSchema); } base.Compare(context, previous); if (priorSchema.ReadOnly != ReadOnly) { context.LogBreakingChange(ComparisonMessages.ReadonlyPropertyChanged2, priorSchema.ReadOnly.ToString().ToLower(CultureInfo.CurrentCulture), ReadOnly.ToString().ToLower(CultureInfo.CurrentCulture)); } if ((priorSchema.Discriminator == null && Discriminator != null) || (priorSchema.Discriminator != null && !priorSchema.Discriminator.Equals(Discriminator))) { context.LogBreakingChange(ComparisonMessages.DifferentDiscriminator); } if ((priorSchema.Extends == null && Extends != null) || (priorSchema.Extends != null && !priorSchema.Extends.Equals(Extends))) { context.LogBreakingChange(ComparisonMessages.DifferentExtends); } if ((priorSchema.AllOf == null && AllOf != null) || (priorSchema.AllOf != null && AllOf == null)) { context.LogBreakingChange(ComparisonMessages.DifferentAllOf); } else if (priorSchema.AllOf != null) { CompareAllOfs(context, priorSchema); } context.Push("properties"); CompareProperties(context, priorSchema); context.Pop(); return context.Messages; }