public void Create_StartAtZeroAndMetadata()
        {
            // This constructor allows the initial version produced to
            // be produced with the specified metadata, as well as allowing
            // the caller to specify whether the compatibility sequence starts
            // at one or zero.

            var md = new[] { "abc", "123" };

            // Ensure it works when starting at one
            var mv0 = new MonotonicVersioner(
                startAtOne: true,
                metadata:   md
                );

            Assert.AreEqual(
                new SemanticVersion(1, 0, 0, new string[0], md),
                mv0.Latest
                );

            // Ensure it works when starting at zero
            var mv1 = new MonotonicVersioner(
                startAtOne: false,
                metadata:   md
                );

            Assert.AreEqual(
                new SemanticVersion(0, 0, 0, new string[0], md),
                mv1.Latest
                );
        }
        public void Create_StartAtZero()
        {
            // These are pretty much the same tests as are in the
            // [Create_Default] test, but with values substituted for
            // a compatibility component that starts at zero.
            //
            // Check that test for appropriate comments.
            var mv = new MonotonicVersioner(startAtOne: false);

            Assert.AreEqual(0, mv.Compatibility);
            Assert.AreEqual(0, mv.Latest.Major);

            Assert.AreEqual(0, mv.Release);
            Assert.AreEqual(0, mv.Latest.Minor);

            Assert.AreEqual(0, mv.Latest.Patch);

            Assert.IsFalse(mv.Latest.Identifiers.Any());
            Assert.IsFalse(mv.Latest.Metadata.Any());


            Assert.IsTrue(mv.LatestVersions.Contains(
                              new KeyValuePair <int, SemanticVersion>(
                                  0, new SemanticVersion(0, 0)
                                  )));

            Assert.AreEqual(1, mv.LatestVersions.Count);


            Assert.IsTrue(mv.Chronology.SequenceEqual(new[]
            {
                new SemanticVersion(0, 0)
            }));
        }
        public void General_Next_ChangeAndMetadata_Valid()
        {
            var mv = new MonotonicVersioner();

            // Compatible change
            var sv0 = (SemanticVersion)"1.1+abc.123";

            Assert.AreEqual(
                sv0, mv.Next(MonotonicChange.Compatible, new[] { "abc", "123" })
                );

            // Breaking change
            var sv1 = (SemanticVersion)"2.2+abc.123";

            Assert.AreEqual(
                sv1, mv.Next(MonotonicChange.Breaking, new[] { "abc", "123" })
                );

            // Change applies to latest version.
            var sv2 = (SemanticVersion)"2.3+def.456";

            Assert.AreEqual(
                sv2, mv.Next(MonotonicChange.Compatible, new[] { "def", "456" })
                );

            // Change applies to latest version.
            // This call causes the latest version to be in the 1.x line.
            mv.Next(1, MonotonicChange.Compatible);
            // Thus, this call should return another version in the 1.x line.
            var sv3 = (SemanticVersion)"1.5+ghi.789";

            Assert.AreEqual(
                sv3, mv.Next(MonotonicChange.Compatible, new[] { "ghi", "789" })
                );
        }
        public void General_Next_ChangeAndMetadata_Invalid()
        {
            var mv     = new MonotonicVersioner();
            var valarr = new[] { "abc", "123" };

            // Change type is invalid
            new Action(() => mv.Next((MonotonicChange)Int32.MinValue, valarr))
            .AssertThrows <ArgumentOutOfRangeException>();


            // Metadata collection is null
            new Action(() => mv.Next(MonotonicChange.Compatible, null))
            .AssertThrows <ArgumentNullException>();

            // Metadata item is null
            var nularr = new string[] { null };

            new Action(() => mv.Next(MonotonicChange.Compatible, nularr))
            .AssertThrows <ArgumentNullException>();


            // Metadata item is invalid
            foreach (var item in SemanticVersionTests.InvalidMetadata
                     .Where(m => m != null))
            {
                var iarr = new[] { item };
                new Action(() => mv.Next(MonotonicChange.Compatible, iarr))
                .AssertThrowsExact <ArgumentException>(item);
            }
        }
        public void Create_Default()
        {
            var mv = new MonotonicVersioner();

            // Compatibility component starts at one
            Assert.AreEqual(1, mv.Compatibility);
            Assert.AreEqual(1, mv.Latest.Major);

            // Release component starts at zero
            Assert.AreEqual(0, mv.Release);
            Assert.AreEqual(0, mv.Latest.Minor);

            // Patch component is zero
            Assert.AreEqual(0, mv.Latest.Patch);

            // No identifiers or metadata
            Assert.IsFalse(mv.Latest.Identifiers.Any());
            Assert.IsFalse(mv.Latest.Metadata.Any());


            // Collection of all latest versions is populated
            Assert.IsTrue(mv.LatestVersions.Contains(
                              new KeyValuePair <int, SemanticVersion>(
                                  1, new SemanticVersion(1, 0)
                                  )));

            Assert.AreEqual(1, mv.LatestVersions.Count);


            // Chronology contains the first version
            Assert.IsTrue(mv.Chronology.SequenceEqual(new[]
            {
                new SemanticVersion(1, 0)
            }));
        }
        public void Create_Default()
        {
            var mv = new MonotonicVersioner();

            // Compatibility component starts at one
            Assert.AreEqual(1, mv.Compatibility);
            Assert.AreEqual(1, mv.Latest.Major);

            // Release component starts at zero
            Assert.AreEqual(0, mv.Release);
            Assert.AreEqual(0, mv.Latest.Minor);

            // Patch component is zero
            Assert.AreEqual(0, mv.Latest.Patch);

            // No identifiers or metadata
            Assert.IsFalse(mv.Latest.Identifiers.Any());
            Assert.IsFalse(mv.Latest.Metadata.Any());


            // Collection of all latest versions is populated
            Assert.IsTrue(mv.LatestVersions.Contains(
                new KeyValuePair<int, SemanticVersion>(
                    1, new SemanticVersion(1, 0)
                    )));

            Assert.AreEqual(1, mv.LatestVersions.Count);


            // Chronology contains the first version
            Assert.IsTrue(mv.Chronology.SequenceEqual(new[]
            {
                new SemanticVersion(1, 0)
            }));
        }
        public void General_LatestVersions()
        {
            // The [LatestVersions] property provides a dictionary
            // where the key is the line of compatibility and the
            // version is the latest version produced in that line.
            var mv = new MonotonicVersioner();


            // Expected initial value.
            Assert.AreEqual(1, mv.LatestVersions.Count);
            Assert.IsTrue(mv.LatestVersions.ContainsKey(1));
            Assert.AreEqual((SemanticVersion)"1.0", mv.LatestVersions[1]);

            // Value updates with compatible change
            mv.Next(MonotonicChange.Compatible);

            Assert.AreEqual(1, mv.LatestVersions.Count);
            Assert.IsTrue(mv.LatestVersions.ContainsKey(1));
            Assert.AreEqual((SemanticVersion)"1.1", mv.LatestVersions[1]);

            // Value updates with breaking change
            mv.Next(MonotonicChange.Breaking);

            Assert.AreEqual(2, mv.LatestVersions.Count);
            Assert.IsTrue(mv.LatestVersions.ContainsKey(1));
            Assert.IsTrue(mv.LatestVersions.ContainsKey(2));
            Assert.AreEqual((SemanticVersion)"1.1", mv.LatestVersions[1]);
            Assert.AreEqual((SemanticVersion)"2.2", mv.LatestVersions[2]);
        }
        public void General_Next_ChangeOnly_Valid()
        {
            var mv = new MonotonicVersioner();

            // A compatible change increments only the release number
            Assert.AreEqual(
                new SemanticVersion(1, 1), mv.Next(MonotonicChange.Compatible)
                );

            // A breaking change increments both the release number and the
            // compatibility number.
            Assert.AreEqual(
                new SemanticVersion(2, 2), mv.Next(MonotonicChange.Breaking)
                );

            // A change is applied to the latest version.
            Assert.AreEqual(
                new SemanticVersion(2, 3), mv.Next(MonotonicChange.Compatible)
                );

            // A change is applied to the latest version.
            // This call makes the latest version "1.4".
            mv.Next(1, MonotonicChange.Compatible);
            // So this call should result in 1.5.
            Assert.AreEqual(
                new SemanticVersion(1, 5), mv.Next(MonotonicChange.Compatible)
                );
        }
        public void General_Next_ChangeOnly_Invalid()
        {
            var mv = new MonotonicVersioner();

            // Specified change is not a recognised value
            new Action(() => mv.Next((MonotonicChange)Int32.MinValue))
            .AssertThrows <ArgumentOutOfRangeException>();
        }
        public void General_Next_ChangeAndLine_Invalid()
        {
            var mv = new MonotonicVersioner();

            // Line is negative
            new Action(() => mv.Next(-1, MonotonicChange.Compatible))
            .AssertThrows <ArgumentOutOfRangeException>();

            // Type of change is not recognised
            new Action(() => mv.Next(1, (MonotonicChange)Int32.MinValue))
            .AssertThrows <ArgumentOutOfRangeException>();


            // Line is not a line present in the versioner
            new Action(() => mv.Next(100, MonotonicChange.Compatible))
            .AssertThrowsExact <ArgumentException>();
        }
        public void General_Clone()
        {
            var seed = new SemanticVersion[]
            {
                new SemanticVersion(1, 0),
                new SemanticVersion(1, 1),
                new SemanticVersion(1, 2),
                new SemanticVersion(2, 3),
                new SemanticVersion(2, 4),
                new SemanticVersion(3, 5),
                new SemanticVersion(1, 6),
            };

            var mv0 = new MonotonicVersioner(seed);


            // Here we go.
            var mv1 = mv0.Clone();

            // The instances should not be the same instance.
            Assert.IsFalse(object.ReferenceEquals(mv0, mv1));

            // But they should start with the same chronology.
            Assert.IsTrue(mv0.Chronology.SequenceEqual(mv1.Chronology));

            // And should have the same values for other properties.
            Assert.AreEqual(mv0.Latest, mv1.Latest);
            Assert.AreEqual(mv0.Compatibility, mv1.Compatibility);
            Assert.AreEqual(mv0.Release, mv1.Release);
            Assert.IsTrue(mv0.LatestVersions.SequenceEqual(mv1.LatestVersions));

            // But if we advance one, it shouldn't affect the other.
            var mv1_lat = mv1.Latest;

            mv0.Next(MonotonicChange.Compatible);
            Assert.AreEqual(new SemanticVersion(1, 7), mv0.Latest);
            Assert.AreEqual(mv1_lat, mv1.Latest);
            Assert.AreNotEqual(mv0.Latest, mv1.Latest);

            var mv0_lat = mv0.Latest;

            mv1.Next(MonotonicChange.Breaking);
            Assert.AreEqual(new SemanticVersion(4, 7), mv1.Latest);
            Assert.AreEqual(mv0_lat, mv0.Latest);
            Assert.AreNotEqual(mv0.Latest, mv1.Latest);
        }
        public void General_Compatibility()
        {
            // The [Compatibility] property gives the greatest line of
            // compatibility present in a version created by the instance.
            var mv = new MonotonicVersioner();

            // Starts off as expected
            Assert.AreEqual(1, mv.Compatibility);

            // Does not increment with a compatible change
            mv.Next(MonotonicChange.Compatible);
            Assert.AreEqual(1, mv.Compatibility);

            // Does increment with a breaking change
            mv.Next(MonotonicChange.Breaking);
            Assert.AreEqual(2, mv.Compatibility);
        }
        public void General_Release()
        {
            // The [Release] property tracks the current release number,
            // and is incremented with each new version generated.
            var mv = new MonotonicVersioner();

            // Starts off as expected
            Assert.AreEqual(0, mv.Release);

            // Increments with a compatible release
            mv.Next(MonotonicChange.Compatible);
            Assert.AreEqual(1, mv.Release);

            // Increments with a breaking release
            mv.Next(MonotonicChange.Breaking);
            Assert.AreEqual(2, mv.Release);
        }
        public void General_Next_LineAndMetadata_Valid()
        {
            var mv = new MonotonicVersioner();

            var md = new[] { "abc", "123" };

            // Compatible changes
            Assert.AreEqual(
                new SemanticVersion(1, 1, 0, new string[0], md),
                mv.Next(1, MonotonicChange.Compatible, md)
                );

            // Breaking changes
            Assert.AreEqual(
                new SemanticVersion(2, 2, 0, new string[0], md),
                mv.Next(1, MonotonicChange.Breaking, md)
                );
        }
        public void Create_Chronology_Valid_Basic()
        {
            // Does it work at all?
            var ch = new SemanticVersion[]
            {
                new SemanticVersion(1, 0),
                new SemanticVersion(1, 1),
                new SemanticVersion(1, 2),
            };
            var mv = new MonotonicVersioner(ch);

            Assert.AreEqual(1, mv.Compatibility);
            Assert.AreEqual(2, mv.Release);

            Assert.AreEqual(new SemanticVersion(1, 2), mv.Latest);

            Assert.AreEqual(ch.Last(), mv.LatestVersions[1]);

            Assert.IsTrue(mv.Chronology.SequenceEqual(ch));
        }
        public void General_Chronology()
        {
            // The [Chronology] property provides an ordered
            // record of the versions created by the instance.
            var mv = new MonotonicVersioner();

            // Chronology starts with only the initial version
            Assert.IsTrue(mv.Chronology.SequenceEqual(new[]
            {
                new SemanticVersion(1, 0),
            }));

            // Compatible change adds to the chronology
            mv.Next(MonotonicChange.Compatible);
            Assert.IsTrue(mv.Chronology.SequenceEqual(new[]
            {
                new SemanticVersion(1, 0),
                new SemanticVersion(1, 1),
            }));

            // Breaking change adds to the chronology
            mv.Next(MonotonicChange.Breaking);
            Assert.IsTrue(mv.Chronology.SequenceEqual(new[]
            {
                new SemanticVersion(1, 0),
                new SemanticVersion(1, 1),
                new SemanticVersion(2, 2),
            }));

            // A second compatible change produces a chronology
            // with the correct ordering
            mv.Next(1, MonotonicChange.Compatible);
            Assert.IsTrue(mv.Chronology.SequenceEqual(new[]
            {
                new SemanticVersion(1, 0),
                new SemanticVersion(1, 1),
                new SemanticVersion(2, 2),
                new SemanticVersion(1, 3),
            }));
        }
        public void Create_Chronology_Valid_Disordered()
        {
            var ch = new SemanticVersion[]
            {
                new SemanticVersion(2, 2),
                new SemanticVersion(1, 0),
                new SemanticVersion(1, 1),
            };
            var mv = new MonotonicVersioner(ch);

            Assert.AreEqual(2, mv.Compatibility);
            Assert.AreEqual(2, mv.Release);

            Assert.AreEqual(ch[0], mv.Latest);

            Assert.AreEqual(ch[2], mv.LatestVersions[1]);
            Assert.AreEqual(ch[0], mv.LatestVersions[2]);

            Assert.AreEqual(2, mv.LatestVersions.Keys.Count());

            Assert.IsTrue(mv.Chronology.SequenceEqual(
                              ch.OrderBy(sv => sv.Minor)
                              ));
        }
        public void Create_Chronology_Valid_StartsAtZero()
        {
            var ch = new SemanticVersion[]
            {
                new SemanticVersion(0, 0),
                new SemanticVersion(0, 1),
                new SemanticVersion(1, 2),
                new SemanticVersion(2, 3),
            };
            var mv = new MonotonicVersioner(ch);

            Assert.AreEqual(2, mv.Compatibility);
            Assert.AreEqual(3, mv.Release);

            Assert.AreEqual(ch.Last(), mv.Latest);

            Assert.AreEqual(ch[1], mv.LatestVersions[0]);
            Assert.AreEqual(ch[2], mv.LatestVersions[1]);
            Assert.AreEqual(ch[3], mv.LatestVersions[2]);

            Assert.AreEqual(3, mv.LatestVersions.Keys.Count());

            Assert.IsTrue(mv.Chronology.SequenceEqual(ch));
        }
        public void General_Next_ChangeAndLine_Valid()
        {
            var mv = new MonotonicVersioner();

            // A compatible change increments only the release number.
            Assert.AreEqual(
                new SemanticVersion(1, 1),
                mv.Next(1, MonotonicChange.Compatible)
                );

            // A breaking change increments compatibility and release numbers.
            Assert.AreEqual(
                new SemanticVersion(2, 2),
                mv.Next(1, MonotonicChange.Breaking)
                );

            // But having released a breaking change does not preclude
            // updating a previous line of compatibility.
            Assert.AreEqual(
                new SemanticVersion(1, 3),
                mv.Next(1, MonotonicChange.Compatible)
                );

            // Nor does updating an older release preclude updating a newer one.
            Assert.AreEqual(
                new SemanticVersion(2, 4),
                mv.Next(2, MonotonicChange.Compatible)
                );

            // And specifying another breaking change on an older line of
            // compatibility should increment the compatibility number.
            Assert.AreEqual(
                new SemanticVersion(3, 5),
                mv.Next(1, MonotonicChange.Breaking)
                );
        }
        public void Create_Chronology_Valid_Complex()
        {
            var ch = new SemanticVersion[]
            {
                /* 0 */ new SemanticVersion(1, 0),
                /* 1 */ new SemanticVersion(1, 1),
                /* 2 */ new SemanticVersion(2, 2), // Latest, line 2
                /* 3 */ new SemanticVersion(1, 3),
                /* 4 */ new SemanticVersion(3, 4),
                /* 5 */ new SemanticVersion(3, 5), // Latest, line 3
                /* 6 */ new SemanticVersion(1, 6), // Latest, line 1 & overall
            };
            var mv = new MonotonicVersioner(ch);

            // [Compatibility] provides the greatest-value component
            // yet generated by the class, not the latest component.
            Assert.AreEqual(3, mv.Compatibility);
            // [Release] is not related to [Compatibility], and provides
            // the current release number.
            Assert.AreEqual(6, mv.Release);

            // [Latest] should provide the chronologically-latest version,
            // regardless of the line of compatibility.
            Assert.AreEqual(ch.Last(), mv.Latest);

            // [LatestVersions] should, as the name might imply, provide
            // the latest version in each line of compatibility.
            Assert.AreEqual(ch[6], mv.LatestVersions[1]);
            Assert.AreEqual(ch[2], mv.LatestVersions[2]);
            Assert.AreEqual(ch[5], mv.LatestVersions[3]);
            // Make sure these are the only keys in the collection.
            Assert.AreEqual(3, mv.LatestVersions.Keys.Count());

            // The chronology must be in order.
            Assert.IsTrue(mv.Chronology.SequenceEqual(ch));
        }
        public void General_Latest()
        {
            // [Latest] provides the chronologically-latest version
            // created by the instance. That is, the version with the
            // greatest-value release number, regardless of line of
            // compatibility.
            var mv = new MonotonicVersioner();

            // Starts at the initial version
            Assert.AreEqual((SemanticVersion)"1.0", mv.Latest);

            // Updated on a compatible change
            mv.Next(MonotonicChange.Compatible);
            Assert.AreEqual((SemanticVersion)"1.1", mv.Latest);

            // Updated on a breaking change
            mv.Next(MonotonicChange.Breaking);
            Assert.AreEqual((SemanticVersion)"2.2", mv.Latest);

            // Updating a lower-value line of compatibility produces
            // the correct result.
            mv.Next(1, MonotonicChange.Compatible);
            Assert.AreEqual((SemanticVersion)"1.3", mv.Latest);
        }
        public void General_Next_ChangeAndLine_Valid()
        {
            var mv = new MonotonicVersioner();

            // A compatible change increments only the release number.
            Assert.AreEqual(
                new SemanticVersion(1, 1),
                mv.Next(1, MonotonicChange.Compatible)
                );

            // A breaking change increments compatibility and release numbers.
            Assert.AreEqual(
                new SemanticVersion(2, 2),
                mv.Next(1, MonotonicChange.Breaking)
                );

            // But having released a breaking change does not preclude
            // updating a previous line of compatibility.
            Assert.AreEqual(
                new SemanticVersion(1, 3),
                mv.Next(1, MonotonicChange.Compatible)
                );

            // Nor does updating an older release preclude updating a newer one.
            Assert.AreEqual(
                new SemanticVersion(2, 4),
                mv.Next(2, MonotonicChange.Compatible)
                );

            // And specifying another breaking change on an older line of
            // compatibility should increment the compatibility number.
            Assert.AreEqual(
                new SemanticVersion(3, 5),
                mv.Next(1, MonotonicChange.Breaking)
                );
        }
        public void General_Next_ChangeOnly_Invalid()
        {
            var mv = new MonotonicVersioner();

            // Specified change is not a recognised value
            new Action(() => mv.Next((MonotonicChange)Int32.MinValue))
                .AssertThrows<ArgumentOutOfRangeException>();
        }
        public void General_Next_LineAndMetadata_Invalid()
        {
            var mv = new MonotonicVersioner();
            var valarr = new string[] { "abc", "123" };
            var nularr = new string[] { null };

            // Line is negative
            new Action(() => mv.Next(-1, MonotonicChange.Compatible, valarr))
                .AssertThrows<ArgumentOutOfRangeException>();

            // Change type is not valid
            new Action(() => mv.Next(1, (MonotonicChange)Int32.MinValue, valarr))
                .AssertThrows<ArgumentOutOfRangeException>();


            // Metadata collection is null
            new Action(() => mv.Next(1, MonotonicChange.Compatible, null))
                .AssertThrows<ArgumentNullException>();

            // Item in metadata collection is null
            new Action(() => mv.Next(1, MonotonicChange.Compatible, nularr))
                .AssertThrows<ArgumentNullException>();


            // Line is not a current line of compatibility
            new Action(() => mv.Next(100, MonotonicChange.Compatible, valarr))
                .AssertThrowsExact<ArgumentException>();

            // Metadata item is invalid
            foreach (var item in SemanticVersionTests.InvalidMetadata
                                                     .Where(m => m != null))
            {
                var iarr = new[] { item };
                new Action(() => mv.Next(1, MonotonicChange.Compatible, iarr))
                    .AssertThrowsExact<ArgumentException>(item);
            }
        }
        public void General_Next_ChangeAndLine_Invalid()
        {
            var mv = new MonotonicVersioner();

            // Line is negative
            new Action(() => mv.Next(-1, MonotonicChange.Compatible))
                .AssertThrows<ArgumentOutOfRangeException>();

            // Type of change is not recognised
            new Action(() => mv.Next(1, (MonotonicChange)Int32.MinValue))
                .AssertThrows<ArgumentOutOfRangeException>();


            // Line is not a line present in the versioner
            new Action(() => mv.Next(100, MonotonicChange.Compatible))
                .AssertThrowsExact<ArgumentException>();
        }
        public void General_Compatibility()
        {
            // The [Compatibility] property gives the greatest line of
            // compatibility present in a version created by the instance.
            var mv = new MonotonicVersioner();

            // Starts off as expected
            Assert.AreEqual(1, mv.Compatibility);

            // Does not increment with a compatible change
            mv.Next(MonotonicChange.Compatible);
            Assert.AreEqual(1, mv.Compatibility);

            // Does increment with a breaking change
            mv.Next(MonotonicChange.Breaking);
            Assert.AreEqual(2, mv.Compatibility);
        }
        public void Create_Chronology_Valid_StartsAtZero()
        {
            var ch = new SemanticVersion[]
            {
                new SemanticVersion(0, 0),
                new SemanticVersion(0, 1),
                new SemanticVersion(1, 2),
                new SemanticVersion(2, 3),
            };
            var mv = new MonotonicVersioner(ch);

            Assert.AreEqual(2, mv.Compatibility);
            Assert.AreEqual(3, mv.Release);

            Assert.AreEqual(ch.Last(), mv.Latest);

            Assert.AreEqual(ch[1], mv.LatestVersions[0]);
            Assert.AreEqual(ch[2], mv.LatestVersions[1]);
            Assert.AreEqual(ch[3], mv.LatestVersions[2]);

            Assert.AreEqual(3, mv.LatestVersions.Keys.Count());

            Assert.IsTrue(mv.Chronology.SequenceEqual(ch));
        }
        public void General_Next_LineAndMetadata_Valid()
        {
            var mv = new MonotonicVersioner();

            var md = new[] { "abc", "123" };

            // Compatible changes
            Assert.AreEqual(
                new SemanticVersion(1, 1, 0, new string[0], md),
                mv.Next(1, MonotonicChange.Compatible, md)
                );

            // Breaking changes
            Assert.AreEqual(
                new SemanticVersion(2, 2, 0, new string[0], md),
                mv.Next(1, MonotonicChange.Breaking, md)
                );
        }
        public void Create_Chronology_Valid_Disordered()
        {
            var ch = new SemanticVersion[]
            {
                new SemanticVersion(2, 2),
                new SemanticVersion(1, 0),
                new SemanticVersion(1, 1),
            };
            var mv = new MonotonicVersioner(ch);

            Assert.AreEqual(2, mv.Compatibility);
            Assert.AreEqual(2, mv.Release);

            Assert.AreEqual(ch[0], mv.Latest);

            Assert.AreEqual(ch[2], mv.LatestVersions[1]);
            Assert.AreEqual(ch[0], mv.LatestVersions[2]);

            Assert.AreEqual(2, mv.LatestVersions.Keys.Count());

            Assert.IsTrue(mv.Chronology.SequenceEqual(
                ch.OrderBy(sv => sv.Minor)
                ));
        }
        public void General_Release()
        {
            // The [Release] property tracks the current release number,
            // and is incremented with each new version generated.
            var mv = new MonotonicVersioner();

            // Starts off as expected
            Assert.AreEqual(0, mv.Release);

            // Increments with a compatible release
            mv.Next(MonotonicChange.Compatible);
            Assert.AreEqual(1, mv.Release);

            // Increments with a breaking release
            mv.Next(MonotonicChange.Breaking);
            Assert.AreEqual(2, mv.Release);
        }
        public void Create_StartAtZero()
        {
            // These are pretty much the same tests as are in the
            // [Create_Default] test, but with values substituted for
            // a compatibility component that starts at zero.
            //
            // Check that test for appropriate comments.
            var mv = new MonotonicVersioner(startAtOne: false);

            Assert.AreEqual(0, mv.Compatibility);
            Assert.AreEqual(0, mv.Latest.Major);

            Assert.AreEqual(0, mv.Release);
            Assert.AreEqual(0, mv.Latest.Minor);

            Assert.AreEqual(0, mv.Latest.Patch);

            Assert.IsFalse(mv.Latest.Identifiers.Any());
            Assert.IsFalse(mv.Latest.Metadata.Any());


            Assert.IsTrue(mv.LatestVersions.Contains(
                new KeyValuePair<int, SemanticVersion>(
                    0, new SemanticVersion(0, 0)
                    )));

            Assert.AreEqual(1, mv.LatestVersions.Count);


            Assert.IsTrue(mv.Chronology.SequenceEqual(new[]
            {
                new SemanticVersion(0, 0)
            }));
        }
        public void General_Chronology()
        {
            // The [Chronology] property provides an ordered
            // record of the versions created by the instance.
            var mv = new MonotonicVersioner();

            // Chronology starts with only the initial version
            Assert.IsTrue(mv.Chronology.SequenceEqual(new[]
            {
                new SemanticVersion(1, 0),
            }));

            // Compatible change adds to the chronology
            mv.Next(MonotonicChange.Compatible);
            Assert.IsTrue(mv.Chronology.SequenceEqual(new[]
            {
                new SemanticVersion(1, 0),
                new SemanticVersion(1, 1),
            }));

            // Breaking change adds to the chronology
            mv.Next(MonotonicChange.Breaking);
            Assert.IsTrue(mv.Chronology.SequenceEqual(new[]
            {
                new SemanticVersion(1, 0),
                new SemanticVersion(1, 1),
                new SemanticVersion(2, 2),
            }));

            // A second compatible change produces a chronology
            // with the correct ordering
            mv.Next(1, MonotonicChange.Compatible);
            Assert.IsTrue(mv.Chronology.SequenceEqual(new[]
            {
                new SemanticVersion(1, 0),
                new SemanticVersion(1, 1),
                new SemanticVersion(2, 2),
                new SemanticVersion(1, 3),
            }));
        }
        public void General_Next_ChangeAndMetadata_Valid()
        {
            var mv = new MonotonicVersioner();

            // Compatible change
            var sv0 = (SemanticVersion)"1.1+abc.123";
            Assert.AreEqual(
                sv0, mv.Next(MonotonicChange.Compatible, new[] { "abc", "123" })
                );

            // Breaking change
            var sv1 = (SemanticVersion)"2.2+abc.123";
            Assert.AreEqual(
                sv1, mv.Next(MonotonicChange.Breaking, new[] { "abc", "123" })
                );

            // Change applies to latest version.
            var sv2 = (SemanticVersion)"2.3+def.456";
            Assert.AreEqual(
                sv2, mv.Next(MonotonicChange.Compatible, new[] { "def", "456" })
                );

            // Change applies to latest version.
            // This call causes the latest version to be in the 1.x line.
            mv.Next(1, MonotonicChange.Compatible);
            // Thus, this call should return another version in the 1.x line.
            var sv3 = (SemanticVersion)"1.5+ghi.789";
            Assert.AreEqual(
                sv3, mv.Next(MonotonicChange.Compatible, new[] { "ghi", "789" })
                );
        }
        public void General_Latest()
        {
            // [Latest] provides the chronologically-latest version
            // created by the instance. That is, the version with the
            // greatest-value release number, regardless of line of
            // compatibility.
            var mv = new MonotonicVersioner();

            // Starts at the initial version
            Assert.AreEqual((SemanticVersion)"1.0", mv.Latest);

            // Updated on a compatible change
            mv.Next(MonotonicChange.Compatible);
            Assert.AreEqual((SemanticVersion)"1.1", mv.Latest);

            // Updated on a breaking change
            mv.Next(MonotonicChange.Breaking);
            Assert.AreEqual((SemanticVersion)"2.2", mv.Latest);

            // Updating a lower-value line of compatibility produces
            // the correct result.
            mv.Next(1, MonotonicChange.Compatible);
            Assert.AreEqual((SemanticVersion)"1.3", mv.Latest);
        }
        public void General_Next_ChangeOnly_Valid()
        {
            var mv = new MonotonicVersioner();

            // A compatible change increments only the release number
            Assert.AreEqual(
                new SemanticVersion(1, 1), mv.Next(MonotonicChange.Compatible)
                );

            // A breaking change increments both the release number and the
            // compatibility number.
            Assert.AreEqual(
                new SemanticVersion(2, 2), mv.Next(MonotonicChange.Breaking)
                );

            // A change is applied to the latest version.
            Assert.AreEqual(
                new SemanticVersion(2, 3), mv.Next(MonotonicChange.Compatible)
                );

            // A change is applied to the latest version.
            // This call makes the latest version "1.4".
            mv.Next(1, MonotonicChange.Compatible);
            // So this call should result in 1.5.
            Assert.AreEqual(
                new SemanticVersion(1, 5), mv.Next(MonotonicChange.Compatible)
                );
        }
        public void General_Clone()
        {
            var seed = new SemanticVersion[]
            {
                new SemanticVersion(1, 0),
                new SemanticVersion(1, 1),
                new SemanticVersion(1, 2),
                new SemanticVersion(2, 3),
                new SemanticVersion(2, 4),
                new SemanticVersion(3, 5),
                new SemanticVersion(1, 6),
            };

            var mv0 = new MonotonicVersioner(seed);


            // Here we go.
            var mv1 = mv0.Clone();

            // The instances should not be the same instance.
            Assert.IsFalse(object.ReferenceEquals(mv0, mv1));

            // But they should start with the same chronology.
            Assert.IsTrue(mv0.Chronology.SequenceEqual(mv1.Chronology));

            // And should have the same values for other properties.
            Assert.AreEqual(mv0.Latest, mv1.Latest);
            Assert.AreEqual(mv0.Compatibility, mv1.Compatibility);
            Assert.AreEqual(mv0.Release, mv1.Release);
            Assert.IsTrue(mv0.LatestVersions.SequenceEqual(mv1.LatestVersions));

            // But if we advance one, it shouldn't affect the other.
            var mv1_lat = mv1.Latest;
            mv0.Next(MonotonicChange.Compatible);
            Assert.AreEqual(new SemanticVersion(1, 7), mv0.Latest);
            Assert.AreEqual(mv1_lat, mv1.Latest);
            Assert.AreNotEqual(mv0.Latest, mv1.Latest);

            var mv0_lat = mv0.Latest;
            mv1.Next(MonotonicChange.Breaking);
            Assert.AreEqual(new SemanticVersion(4, 7), mv1.Latest);
            Assert.AreEqual(mv0_lat, mv0.Latest);
            Assert.AreNotEqual(mv0.Latest, mv1.Latest);
        }
        public void Create_Chronology_Valid_Basic()
        {
            // Does it work at all?
            var ch = new SemanticVersion[]
            {
                new SemanticVersion(1, 0),
                new SemanticVersion(1, 1),
                new SemanticVersion(1, 2),
            };
            var mv = new MonotonicVersioner(ch);

            Assert.AreEqual(1, mv.Compatibility);
            Assert.AreEqual(2, mv.Release);

            Assert.AreEqual(new SemanticVersion(1, 2), mv.Latest);

            Assert.AreEqual(ch.Last(), mv.LatestVersions[1]);

            Assert.IsTrue(mv.Chronology.SequenceEqual(ch));
        }
        public void General_LatestVersions()
        {
            // The [LatestVersions] property provides a dictionary
            // where the key is the line of compatibility and the
            // version is the latest version produced in that line.
            var mv = new MonotonicVersioner();


            // Expected initial value.
            Assert.AreEqual(1, mv.LatestVersions.Count);
            Assert.IsTrue(mv.LatestVersions.ContainsKey(1));
            Assert.AreEqual((SemanticVersion)"1.0", mv.LatestVersions[1]);

            // Value updates with compatible change
            mv.Next(MonotonicChange.Compatible);

            Assert.AreEqual(1, mv.LatestVersions.Count);
            Assert.IsTrue(mv.LatestVersions.ContainsKey(1));
            Assert.AreEqual((SemanticVersion)"1.1", mv.LatestVersions[1]);

            // Value updates with breaking change
            mv.Next(MonotonicChange.Breaking);

            Assert.AreEqual(2, mv.LatestVersions.Count);
            Assert.IsTrue(mv.LatestVersions.ContainsKey(1));
            Assert.IsTrue(mv.LatestVersions.ContainsKey(2));
            Assert.AreEqual((SemanticVersion)"1.1", mv.LatestVersions[1]);
            Assert.AreEqual((SemanticVersion)"2.2", mv.LatestVersions[2]);
        }
        public void Create_StartAtZeroAndMetadata()
        {
            // This constructor allows the initial version produced to
            // be produced with the specified metadata, as well as allowing
            // the caller to specify whether the compatibility sequence starts
            // at one or zero.

            var md = new[] { "abc", "123" };

            // Ensure it works when starting at one
            var mv0 = new MonotonicVersioner(
                startAtOne: true,
                metadata:   md
                );
            Assert.AreEqual(
                new SemanticVersion(1, 0, 0, new string[0], md),
                mv0.Latest
                );

            // Ensure it works when starting at zero
            var mv1 = new MonotonicVersioner(
                startAtOne: false,
                metadata:   md
                );
            Assert.AreEqual(
                new SemanticVersion(0, 0, 0, new string[0], md),
                mv1.Latest
                );
        }
        public void Create_Chronology_Valid_Complex()
        {
            var ch = new SemanticVersion[]
            {
                /* 0 */ new SemanticVersion(1, 0),
                /* 1 */ new SemanticVersion(1, 1),
                /* 2 */ new SemanticVersion(2, 2), // Latest, line 2
                /* 3 */ new SemanticVersion(1, 3),
                /* 4 */ new SemanticVersion(3, 4),
                /* 5 */ new SemanticVersion(3, 5), // Latest, line 3
                /* 6 */ new SemanticVersion(1, 6), // Latest, line 1 & overall
            };
            var mv = new MonotonicVersioner(ch);

            // [Compatibility] provides the greatest-value component
            // yet generated by the class, not the latest component.
            Assert.AreEqual(3, mv.Compatibility);
            // [Release] is not related to [Compatibility], and provides
            // the current release number.
            Assert.AreEqual(6, mv.Release);

            // [Latest] should provide the chronologically-latest version,
            // regardless of the line of compatibility.
            Assert.AreEqual(ch.Last(), mv.Latest);

            // [LatestVersions] should, as the name might imply, provide
            // the latest version in each line of compatibility.
            Assert.AreEqual(ch[6], mv.LatestVersions[1]);
            Assert.AreEqual(ch[2], mv.LatestVersions[2]);
            Assert.AreEqual(ch[5], mv.LatestVersions[3]);
            // Make sure these are the only keys in the collection.
            Assert.AreEqual(3, mv.LatestVersions.Keys.Count());

            // The chronology must be in order.
            Assert.IsTrue(mv.Chronology.SequenceEqual(ch));
        }