public void TestCheckNeeds__AllNeedsSatisfied() { string[] modList = { "mod1", "mod2" }; UrlDir.UrlConfig config1 = UrlBuilder.CreateConfig(new TestConfigNode("SOME_NODE") { { "value", "1" }, }, file); UrlDir.UrlConfig config2 = UrlBuilder.CreateConfig(new TestConfigNode("@SOME_NODE") { { "@value", "2" }, { "@value:NEEDS[mod1] +", "4" }, }, file); NeedsChecker.CheckNeeds(root, modList, progress, logger); progress.DidNotReceiveWithAnyArgs().Exception(null, null); progress.DidNotReceiveWithAnyArgs().Exception(null, null, null); progress.DidNotReceiveWithAnyArgs().Error(null, null); ConfigNode node = root.AllConfigs.ToArray().Last().config; Assert.Equal("@SOME_NODE", node.name); Assert.Equal("@value", node.values[0].name); Assert.Equal("2", node.values[0].value); Assert.Equal("@value +", node.values[1].name); Assert.Equal("4", node.values[1].value); progress.DidNotReceiveWithAnyArgs().NeedsUnsatisfiedValue(null, null, null); }
private string FindPartMod(Part part) { if (configs == null) { configs = GameDatabase.Instance.GetConfigs("PART"); } UrlDir.UrlConfig config = Array.Find <UrlDir.UrlConfig>(configs, (c => (part.name == c.name.Replace('_', '.').Replace(' ', '.')))); if (config == null) { config = Array.Find <UrlDir.UrlConfig>(configs, (c => (part.name == c.name))); if (config == null) { return(""); } } var id = new UrlDir.UrlIdentifier(config.url); if (id[0].Equals("SquadExpansion")) { if (id[1].Equals("Serenity")) { return("BreakingGround"); } return(id[1]); } if (id[0].Equals("UmbraSpaceIndustries") || id[0].Equals("WildBlueIndustries")) { return(id[0] + "/" + id[1]); } return(id[0]); }
private static bool IsMatch(UrlDir.UrlConfig url, string type, string[] namePatterns, string constraints) { if (url.type != type) { return(false); } if (namePatterns != null) { if (url.name == url.type) { return(false); } bool match = false; foreach (string pattern in namePatterns) { if (MMPatchLoader.WildcardMatch(url.name, pattern)) { match = true; break; } } if (!match) { return(false); } } return(MMPatchLoader.CheckConstraints(url.config, constraints)); }
public PatchContext(UrlDir.UrlConfig patchUrl, IEnumerable <IProtoUrlConfig> databaseConfigs, IBasicLogger logger, IPatchProgress progress) { this.patchUrl = patchUrl; this.databaseConfigs = databaseConfigs; this.logger = logger; this.progress = progress; }
public void TestPrettyPrint() { ConfigNode node = new TestConfigNode("SOME_NODE") { { "abc", "def" }, { "ghi", "jkl" }, new TestConfigNode("INNER_NODE_1") { { "mno", "pqr" }, }, }; UrlDir.UrlConfig url = UrlBuilder.CreateConfig("abc/def.cfg", node); string expected = @" abc/def/SOME_NODE SOME_NODE { abc = def ghi = jkl INNER_NODE_1 { mno = pqr } } ".TrimStart().Replace("\r", null); Assert.Equal(expected, url.PrettyPrint()); }
public void TestSortAndExtractPatches__InsertWithPass() { UrlDir.UrlConfig config1 = CreateConfig("NODE"); UrlDir.UrlConfig config2 = CreateConfig("NODE:FOR[mod1]"); UrlDir.UrlConfig config3 = CreateConfig("NODE:FOR[mod2]"); UrlDir.UrlConfig config4 = CreateConfig("NODE:FINAL"); string[] modList = { "mod1" }; PatchList list = PatchExtractor.SortAndExtractPatches(root, modList, progress); Assert.Equal(new[] { config1 }, root.AllConfigs); progress.Received().Error(config2, "Error - pass specifier detected on an insert node (not a patch): abc/def/NODE:FOR[mod1]"); progress.Received().Error(config3, "Error - pass specifier detected on an insert node (not a patch): abc/def/NODE:FOR[mod2]"); progress.Received().Error(config4, "Error - pass specifier detected on an insert node (not a patch): abc/def/NODE:FINAL"); Assert.Empty(list.firstPatches); Assert.Empty(list.legacyPatches); Assert.Empty(list.finalPatches); Assert.Empty(list.modPasses["mod1"].beforePatches); Assert.Empty(list.modPasses["mod1"].forPatches); Assert.Empty(list.modPasses["mod1"].afterPatches); progress.DidNotReceive().PatchAdded(); }
public void TestModifyNode__EditNode__SpecialCharacters() { ConfigNode c1 = new TestConfigNode("NODE") { new TestConfigNode("INNER_NODE") { { "weird_values", "some\r\n\tstuff" }, }, }; UrlDir.UrlConfig c2u = UrlBuilder.CreateConfig("abc/def", new TestConfigNode("@NODE") { new TestConfigNode("@INNER_NODE") { { "another_weird_value", "some\r\nmore\tstuff" }, }, }); PatchContext context = new PatchContext(c2u, Enumerable.Empty <IProtoUrlConfig>(), logger, progress); ConfigNode c3 = MMPatchLoader.ModifyNode(new NodeStack(c1), c2u.config, context); EnsureNoErrors(); AssertConfigNodesEqual(new TestConfigNode("NODE") { new TestConfigNode("INNER_NODE") { { "weird_values", "some\r\n\tstuff" }, { "another_weird_value", "some\r\nmore\tstuff" }, }, }, c3); }
public void TestCheckNeeds__Exception() { string[] modList = { "mod1", "mod2" }; UrlDir.UrlConfig config1 = UrlBuilder.CreateConfig(new ConfigNode("SOME_NODE"), file); UrlDir.UrlConfig config2 = UrlBuilder.CreateConfig(new ConfigNode("SOME_NODE:NEEDS[mod3]"), file); UrlDir.UrlConfig config3 = UrlBuilder.CreateConfig(new ConfigNode("SOME_NODE"), file); Exception e = new Exception(); progress.When(p => p.NeedsUnsatisfiedRoot(config2)).Throw(e); NeedsChecker.CheckNeeds(root, modList, progress, logger); progress.DidNotReceiveWithAnyArgs().Exception(null, null); progress.DidNotReceiveWithAnyArgs().Error(null, null); string expected = @" Exception while checking needs on root node : abc/def/SOME_NODE:NEEDS[mod3] SOME_NODE:NEEDS[mod3] { } ".Replace("\r", null).TrimStart(); progress.Received().Exception(config2, expected, e); Assert.Equal(new[] { config1, config3 }, root.AllConfigs); }
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); }
public PatchContext(UrlDir.UrlConfig patchUrl, UrlDir databaseRoot, IBasicLogger logger, IPatchProgress progress) { this.patchUrl = patchUrl; this.databaseRoot = databaseRoot; this.logger = logger; this.progress = progress; }
public void TestExtractPatch__InvalidCommand__Paste() { UrlDir.UrlConfig urlConfig = CreateConfig("#NODE"); Assert.Null(patchExtractor.ExtractPatch(urlConfig)); progress.Received().Error(urlConfig, "Error - paste command (#) is not valid on a root node: abc/def/#NODE"); }
public void TestExtractPatch__InvalidCommand__Special() { UrlDir.UrlConfig urlConfig = CreateConfig("*NODE"); Assert.Null(patchExtractor.ExtractPatch(urlConfig)); progress.Received().Error(urlConfig, "Error - special command (*) is not valid on a root node: abc/def/*NODE"); }
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); }
public ITagList Parse(string toParse, UrlDir.UrlConfig urlConfig) { if (toParse == null) { throw new ArgumentNullException(nameof(toParse)); } if (urlConfig == null) { throw new ArgumentNullException(nameof(urlConfig)); } if (toParse.Length == 0) { throw new FormatException("can't create tag list from empty string"); } if (toParse[0] == '[') { throw new FormatException("can't create tag list beginning with ["); } if (toParse[0] == ':') { throw new FormatException("can't create tag list beginning with :"); } if (toParse[toParse.Length - 1] == ':') { progress.Warning(urlConfig, "trailing : detected"); toParse = toParse.TrimEnd(':'); } List <Tag> tags = new List <Tag>(); Tag primaryTag = ParsePrimaryTag(toParse, ref tags, urlConfig); return(new TagList(primaryTag, tags)); }
private void AssertUrlCorrect(string expectedNodeName, UrlDir.UrlConfig originalUrl, UrlDir.UrlConfig observedUrl) { Assert.Equal(expectedNodeName, observedUrl.type); ConfigNode originalNode = originalUrl.config; ConfigNode observedNode = observedUrl.config; Assert.Equal(expectedNodeName, observedNode.name); if (originalNode.HasValue("name")) { Assert.Equal(originalNode.GetValue("name"), observedUrl.name); } Assert.Same(originalUrl.parent, observedUrl.parent); Assert.Equal(originalNode.id, observedNode.id); Assert.Equal(originalNode.values.Count, observedNode.values.Count); Assert.Equal(originalNode.nodes.Count, observedNode.nodes.Count); for (int i = 0; i < originalNode.values.Count; i++) { Assert.Same(originalNode.values[i], observedNode.values[i]); } for (int i = 0; i < originalNode.nodes.Count; i++) { Assert.Same(originalNode.nodes[i], observedNode.nodes[i]); } }
public void TestSortAndExtractPatches__InvalidCommand() { UrlDir.UrlConfig config1 = CreateConfig("@NODE:FOR[mod1]"); UrlDir.UrlConfig config2 = CreateConfig("%NODE:FOR[mod1]"); UrlDir.UrlConfig config3 = CreateConfig("&NODE:FOR[mod1]"); UrlDir.UrlConfig config4 = CreateConfig("|NODE:FOR[mod1]"); UrlDir.UrlConfig config5 = CreateConfig("#NODE:FOR[mod1]"); UrlDir.UrlConfig config6 = CreateConfig("*NODE:FOR[mod1]"); string[] modList = { "mod1" }; PatchList list = PatchExtractor.SortAndExtractPatches(root, modList, progress); Assert.Empty(root.AllConfigs); progress.Received().Error(config2, "Error - replace command (%) is not valid on a root node: abc/def/%NODE:FOR[mod1]"); progress.Received().Error(config3, "Error - create command (&) is not valid on a root node: abc/def/&NODE:FOR[mod1]"); progress.Received().Error(config4, "Error - rename command (|) is not valid on a root node: abc/def/|NODE:FOR[mod1]"); progress.Received().Error(config5, "Error - paste command (#) is not valid on a root node: abc/def/#NODE:FOR[mod1]"); progress.Received().Error(config6, "Error - special command (*) is not valid on a root node: abc/def/*NODE:FOR[mod1]"); Assert.Empty(list.firstPatches); Assert.Empty(list.legacyPatches); Assert.Empty(list.finalPatches); Assert.Empty(list.modPasses["mod1"].beforePatches); Assert.Equal(1, list.modPasses["mod1"].forPatches.Count); AssertUrlCorrect("@NODE", config1, list.modPasses["mod1"].forPatches[0]); Assert.Empty(list.modPasses["mod1"].afterPatches); progress.Received(1).PatchAdded(); }
public void TestSortAndExtractPatches__BadlyFormed() { UrlDir.UrlConfig config1 = CreateConfig("@NODE:FOR[mod1]"); UrlDir.UrlConfig config2 = CreateConfig("@NODE:FOR[]"); UrlDir.UrlConfig config3 = CreateConfig("@NADE:FIRST:BEFORE"); UrlDir.UrlConfig config4 = CreateConfig("@NADE:AFTER"); string[] modList = { "mod1" }; PatchList list = PatchExtractor.SortAndExtractPatches(root, modList, progress); Assert.Empty(root.AllConfigs); progress.Received().Error(config2, "Error - malformed :FOR patch specifier detected: abc/def/@NODE:FOR[]"); progress.Received().Error(config3, "Error - more than one pass specifier on a node: abc/def/@NADE:FIRST:BEFORE"); progress.Received().Error(config3, "Error - malformed :BEFORE patch specifier detected: abc/def/@NADE:FIRST:BEFORE"); progress.Received().Error(config4, "Error - malformed :AFTER patch specifier detected: abc/def/@NADE:AFTER"); Assert.Empty(list.firstPatches); Assert.Empty(list.legacyPatches); Assert.Empty(list.finalPatches); Assert.Empty(list.modPasses["mod1"].beforePatches); Assert.Equal(1, list.modPasses["mod1"].forPatches.Count); AssertUrlCorrect("@NODE", config1, list.modPasses["mod1"].forPatches[0]); Assert.Empty(list.modPasses["mod1"].afterPatches); progress.Received(1).PatchAdded(); }
public void TestModifyNode__IndexAllWithAssign() { ConfigNode c1 = new TestConfigNode("NODE") { { "foo", "bar1" }, { "foo", "bar2" }, }; UrlDir.UrlConfig c2u = UrlBuilder.CreateConfig("abc/def", new TestConfigNode("@NODE") { { "@foo,*", "bar3" }, }); PatchContext context = new PatchContext(c2u, Enumerable.Empty <IProtoUrlConfig>(), logger, progress); ConfigNode c3 = MMPatchLoader.ModifyNode(new NodeStack(c1), c2u.config, context); EnsureNoErrors(); AssertConfigNodesEqual(new TestConfigNode("NODE") { { "foo", "bar3" }, { "foo", "bar3" }, }, c3); }
public bool IsPartInCat(AvailablePart availablePart) { string[] folderNames = modName.Split(new char[] { ';' }); if (string.IsNullOrEmpty(availablePart.partUrl)) { UrlDir.UrlConfig url = GameDatabase.Instance.GetConfigs("PART").FirstOrDefault(u => u.name.Replace('_', '.') == availablePart.name); if (url == null) { return(false); } availablePart.partUrl = url.url; } foreach (string folderName in folderNames) { if (availablePart.partUrl.Contains("Deprecated")) { return(false); } else if (availablePart.TechHidden == true) { return(false); } else if (availablePart.partUrl.Contains(folderName)) { return(true); } } return(false); }
/// <summary>Makes a patch form the config.</summary> /// <remarks>Some sanity checks are done when loading, so this method can throw.</remarks> /// <param name="config">The config to make the pacth from.</param> /// <returns> /// The patch node. It's never <c>null</c>, but if some fields cannot be read, they will remain /// uninitialized. /// </returns> public static ConfigNodePatch MakeFromConfig(UrlDir.UrlConfig config) { ArgumentGuard.NotNull(config, "config"); var res = MakeFromNodeInternal(config.config, config, url: config.url); return(res); }
public void TestModifyNode__MultiplyValue() { ConfigNode c1 = new TestConfigNode("NODE") { { "foo", "3" }, { "foo", "5" }, }; UrlDir.UrlConfig c2u = UrlBuilder.CreateConfig("abc/def", new TestConfigNode("@NODE") { { "@foo *", "2" }, }, root); PatchContext context = new PatchContext(c2u, root, logger, progress); ConfigNode c3 = MMPatchLoader.ModifyNode(new NodeStack(c1), c2u.config, context); EnsureNoErrors(); AssertConfigNodesEqual(new TestConfigNode("NODE") { { "foo", "6" }, { "foo", "5" }, }, c3); }
public void TestUrlConfig() { UrlDir.UrlConfig urlConfig = UrlBuilder.CreateConfig("abc/def", new ConfigNode()); EditPatch patch = new EditPatch(urlConfig, Substitute.For <INodeMatcher>(), Substitute.For <IPassSpecifier>()); Assert.Same(urlConfig, patch.UrlConfig); }
public void TestCheckNeeds__Root() { string[] modList = { "mod1", "mod2" }; UrlDir.UrlConfig config1 = UrlBuilder.CreateConfig(new ConfigNode("SOME_NODE"), file); UrlDir.UrlConfig config2 = UrlBuilder.CreateConfig(new ConfigNode("SOME_NODE:NEEDS[mod1]"), file); UrlDir.UrlConfig config3 = UrlBuilder.CreateConfig(new ConfigNode("SOME_NODE:needs[mod1]"), file); UrlDir.UrlConfig config4 = UrlBuilder.CreateConfig(new ConfigNode("SOME_NODE:NEEDS[mod2]:AFTER[mod3]"), file); UrlDir.UrlConfig config5 = UrlBuilder.CreateConfig(new ConfigNode("SOME_NODE:NEEDS[mod3]"), file); UrlDir.UrlConfig config6 = UrlBuilder.CreateConfig(new ConfigNode("SOME_NODE:needs[mod3]"), file); UrlDir.UrlConfig config7 = UrlBuilder.CreateConfig(new ConfigNode("SOME_NODE:NEEDS[mod3]:FOR[mod2]"), file); NeedsChecker.CheckNeeds(root, modList, progress, logger); progress.DidNotReceiveWithAnyArgs().Exception(null, null); progress.DidNotReceiveWithAnyArgs().Exception(null, null, null); progress.DidNotReceiveWithAnyArgs().Error(null, null); UrlDir.UrlConfig[] configs = root.AllConfigs.ToArray(); Assert.Equal(4, configs.Length); Assert.Same(config1, configs[0]); AssertUrlCorrect("SOME_NODE", config2, configs[1]); AssertUrlCorrect("SOME_NODE", config3, configs[2]); AssertUrlCorrect("SOME_NODE:AFTER[mod3]", config4, configs[3]); progress.Received().NeedsUnsatisfiedRoot(config5); progress.Received().NeedsUnsatisfiedRoot(config6); progress.Received().NeedsUnsatisfiedRoot(config7); }
public void TestApplyPatches__Name__Or() { UrlDir.UrlConfig config1 = UrlBuilder.CreateConfig(new TestConfigNode("PART") { { "name", "000" }, { "aaa", "001" }, }, file); UrlDir.UrlConfig config2 = UrlBuilder.CreateConfig(new TestConfigNode("PART") { { "name", "002" }, { "bbb", "003" }, }, file); UrlDir.UrlConfig config3 = UrlBuilder.CreateConfig(new TestConfigNode("PART") { { "name", "004" }, { "ccc", "005" }, }, file); UrlDir.UrlConfig patch1 = new UrlDir.UrlConfig(file, new TestConfigNode("@PART[000|0*2]") { { "@aaa", "011" }, { "ddd", "006" }, }); patchList.firstPatches.Add(patch1); patchApplier.ApplyPatches(); EnsureNoErrors(); progress.Received(1).PatchApplied(); progress.Received().ApplyingUpdate(config1, patch1); progress.Received().ApplyingUpdate(config2, patch1); UrlDir.UrlConfig[] allConfigs = databaseRoot.AllConfigs.ToArray(); Assert.Equal(3, allConfigs.Length); AssertNodesEqual(new TestConfigNode("PART") { { "name", "000" }, { "aaa", "011" }, { "ddd", "006" }, }, allConfigs[0].config); AssertNodesEqual(new TestConfigNode("PART") { { "name", "002" }, { "bbb", "003" }, { "ddd", "006" }, }, allConfigs[1].config); AssertNodesEqual(new TestConfigNode("PART") { { "name", "004" }, { "ccc", "005" }, }, allConfigs[2].config); }
// credit to EvilReeperx for this lifesaving function /// <summary> /// Fills in the part url which KSP strips after loading is complete /// </summary> /// <param name="ap">the part to add the url back to</param> private void RepairAvailablePartUrl(AvailablePart ap) { UrlDir.UrlConfig url = GameDatabase.Instance.GetConfigs("PART").FirstOrDefault(u => u.name.Replace('_', '.') == ap.name); if (url != null) { ap.partUrl = url.url; } }
public EditPatch(UrlDir.UrlConfig urlConfig, INodeMatcher nodeMatcher, IPassSpecifier passSpecifier) { UrlConfig = urlConfig ?? throw new ArgumentNullException(nameof(urlConfig)); NodeMatcher = nodeMatcher ?? throw new ArgumentNullException(nameof(nodeMatcher)); PassSpecifier = passSpecifier ?? throw new ArgumentNullException(nameof(passSpecifier)); loop = urlConfig.config.HasNode("MM_PATCH_LOOP"); }
public void TestExtractPatch__TagListBadlyFormatted() { UrlDir.UrlConfig urlConfig = CreateConfig("badSomehow"); tagListParser.When(t => t.Parse("badSomehow", urlConfig)).Throw(new FormatException("badly formatted")); Assert.Null(patchExtractor.ExtractPatch(urlConfig)); progress.Received().Error(urlConfig, "Cannot parse node name as tag list: badly formatted\non: abc/def/badSomehow"); }
public void TestExtractPatch__ProtoPatchFailed() { UrlDir.UrlConfig urlConfig = CreateConfig("NODE"); protoPatchBuilder.Build(urlConfig, Command.Insert, Arg.Any <ITagList>()).Returns((ProtoPatch)null); Assert.Null(patchExtractor.ExtractPatch(urlConfig)); AssertNoErrors(); }
public void TestApply() { UrlDir.UrlConfig urlConfig = UrlBuilder.CreateConfig("abc/def", new TestConfigNode("A_NODE:NEEDS[someMod]:FOR[somePass]") { { "key1", "value1" }, { "key2", "value2" }, new TestConfigNode("NODE_1") { { "key3", "value3" }, }, new TestConfigNode("NODE_2") { { "key4", "value4" }, }, }); InsertPatch patch = new InsertPatch(urlConfig, "A_NODE", Substitute.For <IPassSpecifier>()); LinkedList <IProtoUrlConfig> databaseConfigs = new LinkedList <IProtoUrlConfig>(); IProtoUrlConfig config1 = Substitute.For <IProtoUrlConfig>(); IProtoUrlConfig config2 = Substitute.For <IProtoUrlConfig>(); databaseConfigs.AddLast(config1); databaseConfigs.AddLast(config2); patch.Apply(databaseConfigs, Substitute.For <IPatchProgress>(), Substitute.For <IBasicLogger>()); IProtoUrlConfig[] databaseConfigsArray = databaseConfigs.ToArray(); Assert.Equal(3, databaseConfigsArray.Length); Assert.Same(config1, databaseConfigsArray[0]); Assert.Same(config2, databaseConfigsArray[1]); Assert.Same(urlConfig.parent, databaseConfigsArray[2].UrlFile); Assert.Equal("abc/def.cfg", databaseConfigsArray[2].FileUrl); Assert.Equal("A_NODE", databaseConfigsArray[2].NodeType); Assert.Equal("abc/def.cfg/A_NODE", databaseConfigsArray[2].FullUrl); Assert.NotSame(urlConfig.config, databaseConfigsArray[2].Node); Assert.Equal("A_NODE", databaseConfigsArray[2].Node.name); Assert.Equal("A_NODE:NEEDS[someMod]:FOR[somePass]", urlConfig.config.name); // make sure this hasn't been changed Assert.Equal(2, databaseConfigsArray[2].Node.values.Count); Assert.Equal("key1", databaseConfigsArray[2].Node.values[0].name); Assert.Equal("value1", databaseConfigsArray[2].Node.values[0].value); Assert.Equal("key2", databaseConfigsArray[2].Node.values[1].name); Assert.Equal("value2", databaseConfigsArray[2].Node.values[1].value); Assert.Equal(2, databaseConfigsArray[2].Node.nodes.Count); Assert.Equal("NODE_1", databaseConfigsArray[2].Node.nodes[0].name); Assert.Equal(1, databaseConfigsArray[2].Node.nodes[0].values.Count); Assert.Equal("key3", databaseConfigsArray[2].Node.nodes[0].values[0].name); Assert.Equal("value3", databaseConfigsArray[2].Node.nodes[0].values[0].value); Assert.Equal(0, databaseConfigsArray[2].Node.nodes[0].nodes.Count); Assert.Equal("NODE_2", databaseConfigsArray[2].Node.nodes[1].name); Assert.Equal(1, databaseConfigsArray[2].Node.nodes[1].values.Count); Assert.Equal("key4", databaseConfigsArray[2].Node.nodes[1].values[0].name); Assert.Equal("value4", databaseConfigsArray[2].Node.nodes[1].values[0].value); Assert.Equal(0, databaseConfigsArray[2].Node.nodes[1].nodes.Count); }
public ForPassSpecifier(string mod, UrlDir.UrlConfig urlConfig) { if (mod == string.Empty) { throw new ArgumentException("can't be empty", nameof(mod)); } this.mod = mod ?? throw new ArgumentNullException(nameof(mod)); this.urlConfig = urlConfig ?? throw new ArgumentNullException(nameof(urlConfig)); }
private void CheckNeeds(List<string> excludePaths) { UrlDir.UrlConfig[] allConfigs = GameDatabase.Instance.root.AllConfigs.ToArray(); // Check the NEEDS parts first. foreach (UrlDir.UrlConfig mod in allConfigs) { UrlDir.UrlConfig currentMod = mod; try { string name; if (IsPathInList(currentMod.url, excludePaths) && (ParseCommand(currentMod.type, out name) != Command.Insert)) { mod.parent.configs.Remove(currentMod); catEatenCount++; log("Deleting Node in file " + currentMod.parent.url + " subnode: " + currentMod.type + " as it is set to be disabled on KSP Win64"); continue; } if (mod.config.name == null) { log("Error - Node in file " + currentMod.parent.url + " subnode: " + currentMod.type + " has config.name == null"); } if (currentMod.type.Contains(":NEEDS[")) { mod.parent.configs.Remove(currentMod); string type = currentMod.type; if (!CheckNeeds(ref type)) { log("Deleting Node in file " + currentMod.parent.url + " subnode: " + currentMod.type + " as it can't satisfy its NEEDS"); needsUnsatisfiedCount++; continue; } ConfigNode copy = new ConfigNode(type); ShallowCopy(currentMod.config, copy); currentMod = new UrlDir.UrlConfig(currentMod.parent, copy); mod.parent.configs.Add(currentMod); } // Recursively check the contents CheckNeeds(currentMod.config, currentMod.parent.url, new List<string>()); } catch (Exception ex) { log("Exception while checking needs : " + currentMod.url + " with a type of " + currentMod.type + "\n" + ex); log("Node is : " + PrettyConfig(currentMod)); exceptionCount++; } } }