public void Compare_DetectsNewMembersInThePresenceOfTheSameNumberOfRemovedAndAddedMembers()
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            var interfaceBreakingChanges = breakingChanges
                                           .Where(b => b.TypeId == "public interface ComparisonScenarios.IInterfaceWithSameNumberOfRemovedAndAddedMembers")
                                           .ToList();

            Assert.Single(interfaceBreakingChanges,
                          b => b.MemberId == "System.Void FirstMemberToRemove()" && b.Kind == ChangeKind.Removal);
            Assert.Single(interfaceBreakingChanges,
                          b => b.MemberId == "System.Void SecondMemberToRemove()" && b.Kind == ChangeKind.Removal);
            Assert.Single(interfaceBreakingChanges,
                          b => b.MemberId == "System.Void ThirdMemberToRemove()" && b.Kind == ChangeKind.Removal);
            Assert.Single(interfaceBreakingChanges,
                          b => b.MemberId == "System.Void FirstAddedMember()" && b.Kind == ChangeKind.Addition);
            Assert.Single(interfaceBreakingChanges,
                          b => b.MemberId == "System.Void SecondAddedMember()" && b.Kind == ChangeKind.Addition);
            Assert.Single(interfaceBreakingChanges,
                          b => b.MemberId == "System.Void ThirdAddedMember()" && b.Kind == ChangeKind.Addition);
        }
        public void Compare_AllowsExclusionsOnNewInterfaceMembers()
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);

            var knownBreakingChanges = new List <BreakingChange>
            {
                new BreakingChange(
                    "public interface ComparisonScenarios.IInterfaceToAddMembersTo",
                    "System.Int32 get_NewMember()",
                    ChangeKind.Addition),
                new BreakingChange(
                    "public interface ComparisonScenarios.IInterfaceToAddMembersTo",
                    "System.Void set_NewMember(System.Int32 value)",
                    ChangeKind.Addition)
            };

            // Act
            var breakingChanges = comparer.GetDifferences().Except(knownBreakingChanges);

            // Assert
            Assert.DoesNotContain(
                breakingChanges,
                bc => bc.TypeId == "public interface ComparisonScenarios.IInterfaceToAddMembersTo");
        }
        public void Compare_DetectsAbstractPropertyAdditions()
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);
            var typeToCheck  = "public abstract class ComparisonScenarios.AbstractClassToAddPropertiesTo";
            var expected     = new List <BreakingChange>
            {
                new BreakingChange(
                    typeToCheck,
                    "public abstract System.Int32 get_NewAbstractProperty()",
                    ChangeKind.Addition),
                new BreakingChange(
                    typeToCheck,
                    "public abstract System.Void set_PropertyToAddSetterTo(System.Int32 value)",
                    ChangeKind.Addition),
            };

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            var breakingChangesInType = breakingChanges
                                        .Where(change => string.Equals(change.TypeId, typeToCheck, StringComparison.Ordinal))
                                        .OrderBy(change => change.MemberId);

            Assert.Equal(expected, breakingChangesInType);
        }
        public void Compare_DetectsAllFieldRemovals(string typeToCheck)
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);

            // Oops. The NewInternalProperty addition is a breaking change; makes it impossible to subclass type in
            // another assembly.
            var expected = new List <BreakingChange>
            {
                // Changing a const's value doesn't cause a binary incompatibility but often causes problems.
                new BreakingChange(
                    typeToCheck,
                    "public const System.Int32 ConstToChangeValue = 1",
                    ChangeKind.Removal),
                // Removing a const doesn't cause a binary incompatibilty but often causes problems.
                new BreakingChange(
                    typeToCheck,
                    "public const System.Int32 ConstToMakeField = 2",
                    ChangeKind.Removal),
                // Oops. Making a field writable is not technically a breaking change.
                new BreakingChange(
                    typeToCheck,
                    "public readonly System.Int32 FieldToMakeWritable",
                    ChangeKind.Removal),
                new BreakingChange(
                    typeToCheck,
                    "public static readonly System.Int32 StaticFieldToMakeConst",
                    ChangeKind.Removal),
                // Oops. Making a field writable is not technically a breaking change.
                new BreakingChange(
                    typeToCheck,
                    "public static readonly System.Int32 StaticFieldToMakeWritable",
                    ChangeKind.Removal),
                new BreakingChange(
                    typeToCheck,
                    "public static System.Int32 StaticFieldToMakeReadonly",
                    ChangeKind.Removal),
                new BreakingChange(
                    typeToCheck,
                    "public System.Int32 FieldToMakeReadonly",
                    ChangeKind.Removal),
                new BreakingChange(
                    typeToCheck,
                    "public System.Int32 FieldToRemove",
                    ChangeKind.Removal),
            };

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            var breakingChanginesInType = breakingChanges
                                          .Where(change => string.Equals(change.TypeId, typeToCheck, StringComparison.Ordinal))
                                          .OrderBy(change => change.MemberId);

            Assert.Equal(expected, breakingChanginesInType);
        }
        public void Compare_DoesNotFailForTypeAddingAnInterface()
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            Assert.Null(breakingChanges.FirstOrDefault(
                            bc => bc.TypeId == "public ComparisonScenarios.TypeWithExtraInterface"));
        }
        public void Compare_AllowsTypeToBeForwarded()
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);
            var typeToCheck  = "public class ComparisonScenarios.TypeToBeForwarded";

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            Assert.DoesNotContain(breakingChanges, bc => bc.TypeId == typeToCheck);
        }
        public void Compare_Detects_TypeRenames_as_removal()
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            var expected = new BreakingChange(
                "public interface ComparisonScenarios.TypeToRename",
                memberId: null,
                kind: ChangeKind.Removal);

            Assert.Contains(expected, breakingChanges);
        }
        public void Compare_Detects_ChangesInTypeVisibility_as_removal()
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            var expected = new BreakingChange(
                "public class ComparisonScenarios.PublicToInternalClass",
                memberId: null,
                kind: ChangeKind.Removal);

            Assert.Contains(expected, breakingChanges);
        }
        public void Compare_Detects_MethodParametersBeingAdded_as_removal()
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            var expected = new BreakingChange(
                "public class ComparisonScenarios.ClassWithMethods",
                "public System.Void MethodToAddParameters()",
                kind: ChangeKind.Removal);

            Assert.Contains(expected, breakingChanges);
        }
        public void Compare_Detects_GenericTypeConstraintsBeingAdded_as_removal()
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            var expected = new BreakingChange(
                "public class ComparisonScenarios.GenericTypeWithConstraintsToBeAdded<T0>",
                memberId: null,
                kind: ChangeKind.Removal);

            Assert.Contains(expected, breakingChanges);
        }
        public void Compare_Detects_ClassBeingUnnested_as_removal()
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            var expected = new BreakingChange(
                "public class ComparisonScenarios.ClassToUnnestContainer+ClassToUnnest",
                memberId: null,
                kind: ChangeKind.Removal);

            Assert.Contains(expected, breakingChanges);
        }
        public void Compare_DetectsAbstractMethodAdditions()
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);
            var typeToCheck  = "public abstract class ComparisonScenarios.AbstractClassToAddMethodsTo";

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            var breakingChangesInType = breakingChanges
                                        .Where(change => string.Equals(change.TypeId, typeToCheck, StringComparison.Ordinal));
            var breakingChange = Assert.Single(breakingChangesInType);

            Assert.Equal(ChangeKind.Addition, breakingChange.Kind);
            Assert.Equal("public abstract System.Void NewAbstractMethod()", breakingChange.MemberId);
        }
        public void Compare_DetectsNewMembersBeingAddedToAnInterface_as_addition()
        {
            // Arrange
            var v1ApiListing = CreateApiListingDocument(V1Assembly);
            var v2ApiListing = CreateApiListingDocument(V2Assembly);
            var comparer     = new ApiListingComparer(v1ApiListing, v2ApiListing);

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            var interfaceBreakingChanges = breakingChanges
                                           .Where(b => b.TypeId == "public interface ComparisonScenarios.IInterfaceToAddMembersTo")
                                           .ToList();

            Assert.Single(interfaceBreakingChanges,
                          b => b.MemberId == "System.Int32 get_NewMember()" && b.Kind == ChangeKind.Addition);
            Assert.Single(interfaceBreakingChanges,
                          b => b.MemberId == "System.Void set_NewMember(System.Int32 value)" && b.Kind == ChangeKind.Addition);
        }
        public void Compare_DetectsChangesInForwardedType()
        {
            // Arrange
            var v1ApiListing  = CreateApiListingDocument(V1Assembly);
            var v2ApiListing  = CreateApiListingDocument(V2Assembly);
            var comparer      = new ApiListingComparer(v1ApiListing, v2ApiListing);
            var typeToCheck   = "public class ComparisonScenarios.TypeToBeForwardedAndChanged";
            var getterRemoval = new BreakingChange(
                typeToCheck,
                "public System.String get_PropertyToBeRemoved()",
                ChangeKind.Removal);
            var setterRemoval = new BreakingChange(
                typeToCheck,
                "public System.Void set_PropertyToBeRemoved(System.String value)",
                ChangeKind.Removal);

            // Act
            var breakingChanges = comparer.GetDifferences();

            // Assert
            Assert.Equal(2, breakingChanges.Count(bc => bc.TypeId == typeToCheck));
            Assert.Contains(getterRemoval, breakingChanges);
            Assert.Contains(setterRemoval, breakingChanges);
        }