public void TestExtractPatch__NeedsUnsatisfiedPassSpecifier()
        {
            UrlDir.UrlConfig urlConfig = CreateConfig("@NODE_TYPE");

            ITagList tagList = Substitute.For <ITagList>();

            tagListParser.Parse("NODE_TYPE", urlConfig).Returns(tagList);

            IPassSpecifier passSpecifier = Substitute.For <IPassSpecifier>();
            ProtoPatch     protoPatch    = new ProtoPatch(
                urlConfig,
                Command.Edit,
                "NODE_TYPE",
                "nodeName",
                "needs",
                "has",
                passSpecifier
                );

            protoPatchBuilder.Build(urlConfig, Command.Edit, tagList).Returns(protoPatch);
            needsChecker.CheckNeedsExpression("needs").Returns(true);
            passSpecifier.CheckNeeds(needsChecker, progress).Returns(false);

            Assert.Null(patchExtractor.ExtractPatch(urlConfig));

            AssertNoErrors();

            Assert.Empty(root.AllConfigs);

            needsChecker.DidNotReceiveWithAnyArgs().CheckNeedsRecursive(null, null);
            patchCompiler.DidNotReceiveWithAnyArgs().CompilePatch(null);

            progress.DidNotReceiveWithAnyArgs().NeedsUnsatisfiedRoot(null);
        }
示例#2
0
        public void TestCompilePatch__Insert()
        {
            ProtoPatch protoPatch = new ProtoPatch(
                UrlBuilder.CreateConfig(new TestConfigNode("NODEE")
            {
                { "name", "foo" },
                { "bar", "bleh" },
            }, file),
                Command.Insert,
                "NODE",
                "foo",
                null,
                "#bar",
                Substitute.For <IPassSpecifier>()
                );

            InsertPatch patch = Assert.IsType <InsertPatch>(patchCompiler.CompilePatch(protoPatch));

            Assert.Same(protoPatch.urlConfig, patch.UrlConfig);

            LinkedList <IProtoUrlConfig> configs = new LinkedList <IProtoUrlConfig>();

            patch.Apply(configs, progress, logger);

            Assert.Equal(1, configs.Count);
            Assert.NotSame(protoPatch.urlConfig.config, configs.First.Value.Node);
            AssertNodesEqual(new TestConfigNode("NODE")
            {
                { "name", "foo" },
                { "bar", "bleh" },
            }, configs.First.Value.Node);
            Assert.Same(file, configs.First.Value.UrlFile);
        }
示例#3
0
        public void TestCompilePatch__Delete()
        {
            ProtoPatch protoPatch = new ProtoPatch(
                UrlBuilder.CreateConfig("ghi/jkl", new ConfigNode("-NODE")),
                Command.Delete,
                "NODE",
                "foo",
                null,
                "#bar",
                Substitute.For <IPassSpecifier>()
                );

            DeletePatch patch = Assert.IsType <DeletePatch>(patchCompiler.CompilePatch(protoPatch));

            Assert.Same(protoPatch.urlConfig, patch.UrlConfig);
            AssertNodeMatcher(patch.NodeMatcher);

            UrlDir.UrlConfig urlConfig = UrlBuilder.CreateConfig(new TestConfigNode("NODE")
            {
                { "name", "foo" },
                { "bar", "baz" },
            }, file);

            patch.Apply(file, progress, logger);

            AssertNoErrors();

            progress.Received().ApplyingDelete(urlConfig, protoPatch.urlConfig);

            Assert.Equal(0, file.configs.Count);
        }
示例#4
0
        public void TestCompilePatch__Copy()
        {
            ProtoPatch protoPatch = new ProtoPatch(
                UrlBuilder.CreateConfig("ghi/jkl", new TestConfigNode("+NODE")
            {
                { "@name", "boo" },
                { "@bar", "bleh" },
            }),
                Command.Copy,
                "NODE",
                "foo",
                null,
                "#bar",
                Substitute.For <IPassSpecifier>()
                );

            CopyPatch patch = Assert.IsType <CopyPatch>(patchCompiler.CompilePatch(protoPatch));

            Assert.Same(protoPatch.urlConfig, patch.UrlConfig);
            AssertNodeMatcher(patch.NodeMatcher);

            ConfigNode config = new TestConfigNode("NODE")
            {
                { "name", "foo" },
                { "bar", "baz" },
            };

            IProtoUrlConfig urlConfig = Substitute.For <IProtoUrlConfig>();

            urlConfig.Node.Returns(config);
            urlConfig.UrlFile.Returns(file);

            LinkedList <IProtoUrlConfig> configs = new LinkedList <IProtoUrlConfig>();

            configs.AddLast(urlConfig);

            patch.Apply(configs, progress, logger);

            AssertNoErrors();

            progress.Received().ApplyingCopy(urlConfig, protoPatch.urlConfig);

            IProtoUrlConfig[] newConfigs = configs.ToArray();

            Assert.Equal(2, newConfigs.Length);
            Assert.Same(config, newConfigs[0].Node);
            AssertNodesEqual(new TestConfigNode("NODE")
            {
                { "name", "foo" },
                { "bar", "baz" },
            }, newConfigs[0].Node);
            AssertNodesEqual(new TestConfigNode("NODE")
            {
                { "name", "boo" },
                { "bar", "bleh" },
            }, newConfigs[1].Node);
            Assert.Same(file, newConfigs[1].UrlFile);
        }
        public void TestExtractPatch__Insert()
        {
            UrlDir.UrlConfig urlConfig = CreateConfig("NODE_TYPE");

            ITagList tagList = Substitute.For <ITagList>();

            tagListParser.Parse("NODE_TYPE", urlConfig).Returns(tagList);

            IPassSpecifier passSpecifier = Substitute.For <IPassSpecifier>();
            ProtoPatch     protoPatch    = new ProtoPatch(
                urlConfig,
                Command.Insert,
                "NODE_TYPE",
                null,
                "needs",
                null,
                passSpecifier
                );

            protoPatchBuilder.Build(urlConfig, Command.Insert, tagList).Returns(protoPatch);
            needsChecker.CheckNeedsExpression("needs").Returns(true);
            passSpecifier.CheckNeeds(needsChecker, progress).Returns(true);

            ConfigNode needsCheckedNode = null;

            needsChecker.CheckNeedsRecursive(Arg.Do <ConfigNode>(node => needsCheckedNode = node), urlConfig);

            Assert.Null(patchExtractor.ExtractPatch(urlConfig));

            AssertNoErrors();

            Received.InOrder(delegate
            {
                tagListParser.Parse("NODE_TYPE", urlConfig);
                protoPatchBuilder.Build(urlConfig, Command.Insert, tagList);
                needsChecker.CheckNeedsExpression("needs");
                passSpecifier.CheckNeeds(needsChecker, progress);
                needsChecker.CheckNeedsRecursive(needsCheckedNode, urlConfig);
            });

            patchCompiler.DidNotReceiveWithAnyArgs().CompilePatch(null);

            Assert.Equal(1, root.AllConfigs.Count());
            UrlDir.UrlConfig newUrlConfig = root.AllConfigs.First();
            Assert.NotSame(urlConfig, newUrlConfig);
            Assert.NotSame(urlConfig.config, newUrlConfig.config);
            AssertConfigNodesEqual(urlConfig.config, newUrlConfig.config);
            Assert.Same(needsCheckedNode, newUrlConfig.config);

            progress.DidNotReceiveWithAnyArgs().NeedsUnsatisfiedRoot(null);
        }
示例#6
0
        public void TestCompilePatch__Edit()
        {
            ProtoPatch protoPatch = new ProtoPatch(
                UrlBuilder.CreateConfig("ghi/jkl", new TestConfigNode("@NODE")
            {
                { "@bar", "bleh" },
            }),
                Command.Edit,
                "NODE",
                "foo",
                null,
                "#bar",
                Substitute.For <IPassSpecifier>()
                );

            EditPatch patch = Assert.IsType <EditPatch>(patchCompiler.CompilePatch(protoPatch));

            Assert.Same(protoPatch.urlConfig, patch.UrlConfig);
            AssertNodeMatcher(patch.NodeMatcher);

            ConfigNode config = new TestConfigNode("NODE")
            {
                { "name", "foo" },
                { "bar", "baz" },
            };

            IProtoUrlConfig urlConfig = Substitute.For <IProtoUrlConfig>();

            urlConfig.Node.Returns(config);
            urlConfig.UrlFile.Returns(file);

            LinkedList <IProtoUrlConfig> configs = new LinkedList <IProtoUrlConfig>();

            configs.AddLast(urlConfig);

            patch.Apply(configs, progress, logger);

            AssertNoErrors();

            progress.Received().ApplyingUpdate(urlConfig, protoPatch.urlConfig);

            Assert.Single(configs);
            Assert.NotSame(config, configs.First.Value.Node);
            AssertNodesEqual(new TestConfigNode("NODE")
            {
                { "name", "foo" },
                { "bar", "bleh" },
            }, configs.First.Value.Node);
            Assert.Same(file, configs.First.Value.UrlFile);
        }
示例#7
0
        public void TestCompilePatch__Copy()
        {
            ProtoPatch protoPatch = new ProtoPatch(
                UrlBuilder.CreateConfig("ghi/jkl", new TestConfigNode("+NODE")
            {
                { "@name", "boo" },
                { "@bar", "bleh" },
            }),
                Command.Copy,
                "NODE",
                "foo",
                null,
                "#bar",
                Substitute.For <IPassSpecifier>()
                );

            CopyPatch patch = Assert.IsType <CopyPatch>(patchCompiler.CompilePatch(protoPatch));

            Assert.Same(protoPatch.urlConfig, patch.UrlConfig);
            AssertNodeMatcher(patch.NodeMatcher);

            UrlDir.UrlConfig urlConfig = UrlBuilder.CreateConfig(new TestConfigNode("NODE")
            {
                { "name", "foo" },
                { "bar", "baz" },
            }, file);

            patch.Apply(file, progress, logger);

            AssertNoErrors();

            progress.Received().ApplyingCopy(urlConfig, protoPatch.urlConfig);

            Assert.Equal(2, file.configs.Count);
            Assert.Same(urlConfig, file.configs[0]);
            AssertNodesEqual(new TestConfigNode("NODE")
            {
                { "name", "foo" },
                { "bar", "baz" },
            }, file.configs[0].config);
            AssertNodesEqual(new TestConfigNode("NODE")
            {
                { "name", "boo" },
                { "bar", "bleh" },
            }, file.configs[1].config);
        }
示例#8
0
        public void TestCompilePatch__InvalidCommand__Special()
        {
            ProtoPatch protoPatch = new ProtoPatch(
                UrlBuilder.CreateConfig("ghi/jkl", new ConfigNode()),
                Command.Special,
                "NODE",
                "foo",
                null,
                "#bar",
                Substitute.For <IPassSpecifier>()
                );

            ArgumentException ex = Assert.Throws <ArgumentException>(delegate
            {
                patchCompiler.CompilePatch(protoPatch);
            });

            Assert.Equal("protoPatch", ex.ParamName);
            Assert.Contains("invalid command for a root node: Special", ex.Message);
        }
示例#9
0
        public void TestCompilePatch__Delete()
        {
            ProtoPatch protoPatch = new ProtoPatch(
                UrlBuilder.CreateConfig("ghi/jkl", new ConfigNode("-NODE")),
                Command.Delete,
                "NODE",
                "foo",
                null,
                "#bar",
                Substitute.For <IPassSpecifier>()
                );

            DeletePatch patch = Assert.IsType <DeletePatch>(patchCompiler.CompilePatch(protoPatch));

            Assert.Same(protoPatch.urlConfig, patch.UrlConfig);
            AssertNodeMatcher(patch.NodeMatcher);

            IProtoUrlConfig urlConfig = Substitute.For <IProtoUrlConfig>();

            urlConfig.Node.Returns(new TestConfigNode("NODE")
            {
                { "name", "foo" },
                { "bar", "baz" },
            });

            LinkedList <IProtoUrlConfig> configs = new LinkedList <IProtoUrlConfig>();

            configs.AddLast(urlConfig);

            patch.Apply(configs, progress, logger);

            AssertNoErrors();

            progress.Received().ApplyingDelete(urlConfig, protoPatch.urlConfig);

            Assert.Empty(configs);
        }
示例#10
0
        public IPatch ExtractPatch(UrlDir.UrlConfig urlConfig)
        {
            if (urlConfig == null)
            {
                throw new ArgumentNullException(nameof(urlConfig));
            }

            try
            {
                if (!urlConfig.type.IsBracketBalanced())
                {
                    progress.Error(urlConfig, "Error - node name does not have balanced brackets (or a space - if so replace with ?):\n" + urlConfig.SafeUrl());
                    return(null);
                }

                Command command = CommandParser.Parse(urlConfig.type, out string name);

                if (command == Command.Replace)
                {
                    progress.Error(urlConfig, $"Error - replace command (%) is not valid on a root node: {urlConfig.SafeUrl()}");
                    return(null);
                }
                else if (command == Command.Create)
                {
                    progress.Error(urlConfig, $"Error - create command (&) is not valid on a root node: {urlConfig.SafeUrl()}");
                    return(null);
                }
                else if (command == Command.Rename)
                {
                    progress.Error(urlConfig, $"Error - rename command (|) is not valid on a root node: {urlConfig.SafeUrl()}");
                    return(null);
                }
                else if (command == Command.Paste)
                {
                    progress.Error(urlConfig, $"Error - paste command (#) is not valid on a root node: {urlConfig.SafeUrl()}");
                    return(null);
                }
                else if (command == Command.Special)
                {
                    progress.Error(urlConfig, $"Error - special command (*) is not valid on a root node: {urlConfig.SafeUrl()}");
                    return(null);
                }

                ITagList tagList;
                try
                {
                    tagList = tagListParser.Parse(name, urlConfig);
                }
                catch (FormatException ex)
                {
                    progress.Error(urlConfig, $"Cannot parse node name as tag list: {ex.Message}\non: {urlConfig.SafeUrl()}");
                    return(null);
                }

                ProtoPatch protoPatch = protoPatchBuilder.Build(urlConfig, command, tagList);

                if (protoPatch == null)
                {
                    return(null);
                }

                if (protoPatch.needs != null && !needsChecker.CheckNeedsExpression(protoPatch.needs))
                {
                    progress.NeedsUnsatisfiedRoot(urlConfig);
                    return(null);
                }
                else if (!protoPatch.passSpecifier.CheckNeeds(needsChecker, progress))
                {
                    return(null);
                }

                needsChecker.CheckNeedsRecursive(urlConfig.config, urlConfig);
                return(patchCompiler.CompilePatch(protoPatch));
            }
            catch (Exception e)
            {
                progress.Exception(urlConfig, $"Exception while attempting to create patch from config: {urlConfig.SafeUrl()}", e);
                return(null);
            }
        }