public void ProductsToUninstall()
        {
            var tempFilePath = "X:\\temp\\";
            var products     = new ProductCollection();

            products.AddRange(new List <string> {
                "https://download/from/here/p1.msi",
                "https://download/from/here/p2.msi",
                "https://download/from/there/p3.msi",
                "https://download/from/somewhere/p4.msi",
            }.Aggregate(new ProductCollection(), (ps, s) =>
            {
                ps.Add(new ProductInfo {
                    Name = Path.GetFileNameWithoutExtension(s), Uri = new Uri(s), LocalPath = new Uri(s).MapToLocalPath(tempFilePath)
                }); return(ps);
            }));
            Assert.That(products.Count, Is.EqualTo(4));
            var existing = new List <string> {
                products[0].LocalPath,
                $"{tempFilePath}CrazyVirus.msi",
                products[3].LocalPath,
                $"{tempFilePath}SomethingElse.msi",
            };
            var uninstall = products.FilesToUninstall(existing).ToList();

            Assert.That(uninstall.Count(), Is.EqualTo(2));
            Assert.That(uninstall[0], Is.EqualTo(existing[1]));
            Assert.That(uninstall[1], Is.EqualTo(existing[3]));
        }
        public void Separate()
        {
            Assert.That(SemanticVersion.From("https://download/here/Prod01/9.4.7/p1.msi").CompareTo(SemanticVersion.From("https://download/here/Prod01/9.4.8+upgrade/p1.msi")), Is.LessThan(0));
            Assert.That(SemanticVersion.From("https://download/here/Prod02/3.3.5/p2.msi").CompareTo(SemanticVersion.From("https://download/here/Prod02/3.3.5+keep/p2.msi")), Is.EqualTo(0));
            Assert.That(SemanticVersion.From("https://download/there/Prod03/12.5.8/p3.msi").CompareTo(SemanticVersion.From("https://download/there/Prod03/12.5.4+downgrade/p3.msi")), Is.GreaterThan(0));
            //Assert.That(SemanticVersion.From("https://download/here/Prod01/9.4.7/p1.msi").CompareTo(SemanticVersion.From("https://download/here/Prod01/9.4.8+upgrade/p1.msi")), Is.LessThan(0));
            var installed = new Dictionary <string, string> {
                { "Prod01\\p1.msi", "https://download/here/Prod01/9.4.7/p1.msi" },
                { "Prod02\\p2.msi", "https://download/here/Prod02/3.3.5/p2.msi" },
                { "Prod03\\p3.msi", "https://download/there/Prod03/12.5.8/p3.msi" },
                { "ProdXX\\px.msi", "https://download/there/ProdXX/1.2.5.8+uninstall/px.msi" },
            };
            var products = new ProductCollection {
                new ProductInfo {
                    Name = "Prod01", Uri = new Uri("https://download/here/Prod01/9.4.8+upgrade/p1.msi"), LocalPath = "Prod01\\p1.msi",
                },
                new ProductInfo {
                    Name = "Prod02", Uri = new Uri("https://download/here/Prod02/3.3.5+keep/p2.msi"), LocalPath = "Prod02\\p2.msi",
                },
                new ProductInfo {
                    Name = "Prod03", Uri = new Uri("https://download/there/Prod03/12.5.4+downgrade/p3.msi"), LocalPath = "Prod03\\p3.msi",
                },
                new ProductInfo {
                    Name = "Prod04", Uri = new Uri("https://download/from/Prod04/1.2.3+install/p4.msi"), LocalPath = "Prod04\\p4.msi",
                },
            };
            var remove = products.FilesToUninstall(installed.Keys);

            var(uninstall, install) = products.Separate(localPath =>
            {
                var uri = installed.ContainsKey(localPath) ? installed[localPath] : null;
                return(null != uri ? new ProductInfo {
                    Uri = new Uri(uri),
                } : null);
            });
            //Console.WriteLine($"Remove:");
            //foreach (var r in remove) Console.WriteLine($"  {r}");
            //Console.WriteLine($"Uninstall:");
            //foreach(var u in uninstall) Console.WriteLine($"  {u}");
            //Console.WriteLine($"Install:");
            //foreach(var i in install) Console.WriteLine($"  {i}");
            Assert.That(remove.Count(), Is.EqualTo(1));
            Assert.That(remove.ElementAt(0), Is.EqualTo("ProdXX\\px.msi"));
            Assert.That(uninstall.Count(), Is.EqualTo(1));
            Assert.That(uninstall.ElementAt(0).Uri.ToString(), Is.EqualTo("https://download/there/Prod03/12.5.8/p3.msi"));
            Assert.That(install.Count(), Is.EqualTo(4));
            Assert.That(install.ElementAt(0).Uri.ToString(), Is.EqualTo("https://download/here/Prod01/9.4.8+upgrade/p1.msi"));
            Assert.That(install.ElementAt(1).Uri.ToString(), Is.EqualTo("https://download/here/Prod02/3.3.5+keep/p2.msi"));
            Assert.That(install.ElementAt(2).Uri.ToString(), Is.EqualTo("https://download/there/Prod03/12.5.4+downgrade/p3.msi"));
            Assert.That(install.ElementAt(3).Uri.ToString(), Is.EqualTo("https://download/from/Prod04/1.2.3+install/p4.msi"));
        }