Index: ps/trunk/binaries/data/mods/_test.sim/simulation/templates/special_filter/foundation.xml
===================================================================
--- ps/trunk/binaries/data/mods/_test.sim/simulation/templates/special_filter/foundation.xml
+++ ps/trunk/binaries/data/mods/_test.sim/simulation/templates/special_filter/foundation.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+ 0
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ false
+
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/construction.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/construction.xml
+++ ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/construction.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/corpse.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/corpse.xml
+++ ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/corpse.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+ true
+
+
+
+ false
+
+
Index: ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/foundation.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/foundation.xml
+++ ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/foundation.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ false
+
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/mirage.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/mirage.xml
+++ ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/mirage.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/preview.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/preview.xml
+++ ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/preview.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+ true
+ true
+
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/resource.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/resource.xml
+++ ps/trunk/binaries/data/mods/public/simulation/templates/special_filter/resource.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
Index: ps/trunk/source/ps/TemplateLoader.h
===================================================================
--- ps/trunk/source/ps/TemplateLoader.h
+++ ps/trunk/source/ps/TemplateLoader.h
@@ -82,36 +82,6 @@
void ConstructTemplateActor(const std::string& actorName, CParamNode& out);
/**
- * Copy the non-interactive components of an entity template (position, actor, etc) into
- * a new entity template
- */
- void CopyPreviewSubset(CParamNode& out, const CParamNode& in, bool corpse);
-
- /**
- * Copy the components of an entity template necessary for a fogged "mirage"
- * entity (position, actor) into a new entity template
- */
- void CopyMirageSubset(CParamNode& out, const CParamNode& in);
-
- /**
- * Copy the components of an entity template necessary for a construction foundation
- * (position, actor, armour, health, etc) into a new entity template
- */
- void CopyFoundationSubset(CParamNode& out, const CParamNode& in);
-
- /**
- * Copy the components of an entity template necessary for a non-foundation construction entity
- * into a new entity template
- */
- void CopyConstructionSubset(CParamNode& out, const CParamNode& in);
-
- /**
- * Copy the components of an entity template necessary for a gatherable resource
- * into a new entity template
- */
- void CopyResourceSubset(CParamNode& out, const CParamNode& in);
-
- /**
* Map from template name (XML filename or special |-separated string) to the most recently
* loaded non-broken template data. This includes files that will fail schema validation.
* (Failed loads won't remove existing entries under the same name, so we behave more nicely
Index: ps/trunk/source/ps/TemplateLoader.cpp
===================================================================
--- ps/trunk/source/ps/TemplateLoader.cpp
+++ ps/trunk/source/ps/TemplateLoader.cpp
@@ -49,93 +49,33 @@
return true;
}
- // Handle special case "preview|foo"
- if (templateName.find("preview|") == 0)
+ // Handle special case "bar|foo"
+ size_t pos = templateName.find_first_of('|');
+ if (pos != std::string::npos)
{
- // Load the base entity template, if it wasn't already loaded
- std::string baseName = templateName.substr(8);
- if (!LoadTemplateFile(baseName, depth+1))
- {
- LOGERROR("Failed to load entity template '%s'", baseName.c_str());
- return false;
- }
- // Copy a subset to the requested template
- CopyPreviewSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName], false);
- return true;
- }
+ std::string prefix = templateName.substr(0, pos);
+ std::string baseName = templateName.substr(pos+1);
- // Handle special case "corpse|foo"
- if (templateName.find("corpse|") == 0)
- {
- // Load the base entity template, if it wasn't already loaded
- std::string baseName = templateName.substr(7);
if (!LoadTemplateFile(baseName, depth+1))
{
LOGERROR("Failed to load entity template '%s'", baseName.c_str());
return false;
}
- // Copy a subset to the requested template
- CopyPreviewSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName], true);
- return true;
- }
- // Handle special case "mirage|foo"
- if (templateName.find("mirage|") == 0)
- {
- // Load the base entity template, if it wasn't already loaded
- std::string baseName = templateName.substr(7);
- if (!LoadTemplateFile(baseName, depth+1))
+ VfsPath path = VfsPath(TEMPLATE_ROOT) / L"special_filter" / wstring_from_utf8(prefix + ".xml");
+ if (!VfsFileExists(path))
{
- LOGERROR("Failed to load entity template '%s'", baseName.c_str());
+ LOGERROR("Invalid subset '%s'", prefix.c_str());
return false;
}
- // Copy a subset to the requested template
- CopyMirageSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]);
- return true;
- }
- // Handle special case "foundation|foo"
- if (templateName.find("foundation|") == 0)
- {
- // Load the base entity template, if it wasn't already loaded
- std::string baseName = templateName.substr(11);
- if (!LoadTemplateFile(baseName, depth+1))
- {
- LOGERROR("Failed to load entity template '%s'", baseName.c_str());
- return false;
- }
- // Copy a subset to the requested template
- CopyFoundationSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]);
- return true;
- }
+ CXeromyces xero;
+ PSRETURN ok = xero.Load(g_VFS, path);
+ if (ok != PSRETURN_OK)
+ return false; // (Xeromyces already logged an error with the full filename)
- // Handle special case "construction|foo"
- if (templateName.find("construction|") == 0)
- {
- // Load the base entity template, if it wasn't already loaded
- std::string baseName = templateName.substr(13);
- if (!LoadTemplateFile(baseName, depth+1))
- {
- LOGERROR("Failed to load entity template '%s'", baseName.c_str());
- return false;
- }
- // Copy a subset to the requested template
- CopyConstructionSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]);
- return true;
- }
-
- // Handle special case "resource|foo"
- if (templateName.find("resource|") == 0)
- {
- // Load the base entity template, if it wasn't already loaded
- std::string baseName = templateName.substr(9);
- if (!LoadTemplateFile(baseName, depth+1))
- {
- LOGERROR("Failed to load entity template '%s'", baseName.c_str());
- return false;
- }
- // Copy a subset to the requested template
- CopyResourceSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]);
+ m_TemplateFileData[templateName] = m_TemplateFileData[baseName];
+ CParamNode::LoadXML(m_TemplateFileData[templateName], xero, path.string().c_str());
return true;
}
@@ -348,203 +288,3 @@
CParamNode::LoadXMLString(out, xml.c_str(), actorNameW.c_str());
}
-
-void CTemplateLoader::CopyPreviewSubset(CParamNode& out, const CParamNode& in, bool corpse)
-{
- // We only want to include components which are necessary (for the visual previewing of an entity)
- // and safe (i.e. won't do anything that affects the synchronised simulation state), so additions
- // to this list should be carefully considered
- std::set permittedComponentTypes;
- permittedComponentTypes.insert("Identity");
- permittedComponentTypes.insert("Ownership");
- permittedComponentTypes.insert("Position");
- permittedComponentTypes.insert("Visibility");
- permittedComponentTypes.insert("VisualActor");
- permittedComponentTypes.insert("Footprint");
- permittedComponentTypes.insert("Obstruction");
- permittedComponentTypes.insert("Decay");
- permittedComponentTypes.insert("BuildRestrictions");
-
- // Need these for the Actor Viewer:
- permittedComponentTypes.insert("Attack");
- permittedComponentTypes.insert("UnitMotion");
- permittedComponentTypes.insert("Sound");
-
- // (This set could be initialised once and reused, but it's not worth the effort)
-
- CParamNode::LoadXMLString(out, "");
- out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);
-
- // Disable the Obstruction component (if there is one) so it doesn't affect pathfinding
- // (but can still be used for testing this entity for collisions against others)
- if (out.GetChild("Entity").GetChild("Obstruction").IsOk())
- CParamNode::LoadXMLString(out, "false");
-
- if (!corpse)
- {
- // Previews should not cast shadows
- if (out.GetChild("Entity").GetChild("VisualActor").IsOk())
- CParamNode::LoadXMLString(out, "");
-
- // Previews should always be visible in fog-of-war/etc
- CParamNode::LoadXMLString(out, "truetrue");
- }
-
- if (corpse)
- {
- // Corpses should include decay components and activate them
- if (out.GetChild("Entity").GetChild("Decay").IsOk())
- CParamNode::LoadXMLString(out, "true");
-
- // Corpses shouldn't display silhouettes (especially since they're often half underground)
- if (out.GetChild("Entity").GetChild("VisualActor").IsOk())
- CParamNode::LoadXMLString(out, "false");
-
- // Corpses should remain visible in fog-of-war (for the owner only)
- CParamNode::LoadXMLString(out, "true");
- }
-}
-
-void CTemplateLoader::CopyMirageSubset(CParamNode& out, const CParamNode& in)
-{
- // Currently used for mirage entities replacing real ones in fog-of-war
-
- std::set permittedComponentTypes;
- permittedComponentTypes.insert("Footprint");
- permittedComponentTypes.insert("Minimap");
- permittedComponentTypes.insert("Obstruction");
- permittedComponentTypes.insert("Ownership");
- permittedComponentTypes.insert("OverlayRenderer");
- permittedComponentTypes.insert("Position");
- permittedComponentTypes.insert("Selectable");
- permittedComponentTypes.insert("StatusBars");
- permittedComponentTypes.insert("Visibility");
- permittedComponentTypes.insert("VisualActor");
-
- CParamNode::LoadXMLString(out, "");
- out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);
-
- // Select a subset of identity data. We don't want to have, for example, a CC mirage
- // that has also the CC class and then prevents construction of other CCs
- std::set identitySubset;
- identitySubset.insert("Civ");
- identitySubset.insert("GenericName");
- identitySubset.insert("SpecificName");
- identitySubset.insert("Tooltip");
- identitySubset.insert("History");
- identitySubset.insert("Icon");
- CParamNode identity;
- CParamNode::LoadXMLString(identity, "");
- identity.CopyFilteredChildrenOfChild(in.GetChild("Entity"), "Identity", identitySubset);
- CParamNode::LoadXMLString(out, (""+utf8_from_wstring(identity.ToXML())+"").c_str());
-
- // Mirages obstruction shouldn't block anything
- if (out.GetChild("Entity").GetChild("Obstruction").IsOk())
- CParamNode::LoadXMLString(out, "falsefalsefalsefalse");
-
- // Set the entity as mirage entity
- CParamNode::LoadXMLString(out, "");
-}
-
-void CTemplateLoader::CopyFoundationSubset(CParamNode& out, const CParamNode& in)
-{
- // TODO: this is all kind of yucky and hard-coded; it'd be nice to have a more generic
- // extensible scriptable way to define these subsets
-
- std::set permittedComponentTypes;
- permittedComponentTypes.insert("Ownership");
- permittedComponentTypes.insert("Position");
- permittedComponentTypes.insert("VisualActor");
- permittedComponentTypes.insert("Identity");
- permittedComponentTypes.insert("BuildRestrictions");
- permittedComponentTypes.insert("Obstruction");
- permittedComponentTypes.insert("Selectable");
- permittedComponentTypes.insert("Footprint");
- permittedComponentTypes.insert("Fogging");
- permittedComponentTypes.insert("Armour");
- permittedComponentTypes.insert("Health");
- permittedComponentTypes.insert("Market");
- permittedComponentTypes.insert("StatusBars");
- permittedComponentTypes.insert("OverlayRenderer");
- permittedComponentTypes.insert("Decay");
- permittedComponentTypes.insert("Cost");
- permittedComponentTypes.insert("Sound");
- permittedComponentTypes.insert("Visibility");
- permittedComponentTypes.insert("Vision");
- permittedComponentTypes.insert("AIProxy");
- permittedComponentTypes.insert("RallyPoint");
- permittedComponentTypes.insert("RallyPointRenderer");
-
- CParamNode::LoadXMLString(out, "");
- out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);
-
- // Switch the actor to foundation mode
- CParamNode::LoadXMLString(out, "");
-
- // Add the Foundation component, to deal with the construction process
- CParamNode::LoadXMLString(out, "");
-
- // Initialise health to 1
- CParamNode::LoadXMLString(out, "1");
-
- // Foundations shouldn't initially block unit movement
- if (out.GetChild("Entity").GetChild("Obstruction").IsOk())
- CParamNode::LoadXMLString(out, "truetrue");
-
- // Don't provide population bonuses yet (but still do take up population cost)
- if (out.GetChild("Entity").GetChild("Cost").IsOk())
- CParamNode::LoadXMLString(out, "0");
-
- // Foundations should be visible themselves in fog-of-war if their base template is,
- // but shouldn't have any vision range
- if (out.GetChild("Entity").GetChild("Vision").IsOk())
- {
- CParamNode::LoadXMLString(out, "0");
- // Foundations should not have special vision capabilities either
- if (out.GetChild("Entity").GetChild("Vision").GetChild("RevealShore").IsOk())
- CParamNode::LoadXMLString(out, "false");
- }
-}
-
-void CTemplateLoader::CopyConstructionSubset(CParamNode& out, const CParamNode& in)
-{
- // Currently used for buildings rising during construction
- // Mostly serves to filter out components like Vision, UnitAI, etc.
- std::set permittedComponentTypes;
- permittedComponentTypes.insert("Footprint");
- permittedComponentTypes.insert("Ownership");
- permittedComponentTypes.insert("Position");
- permittedComponentTypes.insert("VisualActor");
-
- CParamNode::LoadXMLString(out, "");
- out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);
-}
-
-void CTemplateLoader::CopyResourceSubset(CParamNode& out, const CParamNode& in)
-{
- // Currently used for animals which die and leave a gatherable corpse.
- // Mostly serves to filter out components like Vision, UnitAI, etc.
- // Don't emit sound as our samples only apply to living animals.
- std::set permittedComponentTypes;
- permittedComponentTypes.insert("Ownership");
- permittedComponentTypes.insert("Position");
- permittedComponentTypes.insert("VisualActor");
- permittedComponentTypes.insert("Identity");
- permittedComponentTypes.insert("Minimap");
- permittedComponentTypes.insert("ResourceSupply");
- permittedComponentTypes.insert("Selectable");
- permittedComponentTypes.insert("Footprint");
- permittedComponentTypes.insert("StatusBars");
- permittedComponentTypes.insert("OverlayRenderer");
- permittedComponentTypes.insert("AIProxy");
-
- CParamNode::LoadXMLString(out, "");
- out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);
-
- // When dying, resources lose the unitMotion component
- // This causes them to have no clearance. Since unit obstructions no longer have a radius,
- // this makes them unreachable in some cases (see #3530).
- // Instead, create a static, unblocking (see #3530 for why) static obstruction.
- // TODO: this should probably be generalized as a parameter on entity death or something.
- CParamNode::LoadXMLString(out, "truefalsefalsefalsefalsefalsefalse");
-}
Index: ps/trunk/source/simulation2/system/ParamNode.h
===================================================================
--- ps/trunk/source/simulation2/system/ParamNode.h
+++ ps/trunk/source/simulation2/system/ParamNode.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015 Wildfire Games.
+/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -58,6 +58,15 @@
*
* one two three
*
+ *
+ *
+ *
+ * test
+ *
+ *
+ * example
+ *
+ *
*
* @endcode
* then a second like:
@@ -75,6 +84,15 @@
* four
* -two
*
+ *
+ *
+ * example
+ *
+ *
+ *
+ * text
+ *
+ *
*
* @endcode
* is equivalent to loading a single file like:
@@ -90,6 +108,15 @@
*
* one three four
*
+ *
+ *
+ * test
+ * example
+ *
+ *
+ * text
+ *
+ *
*
* @endcode
*
@@ -103,7 +130,16 @@
* "Example3": {
* "D": "new"
* },
- * "Example4": { "@datatype": "tokens", "_string": "one three four" }
+ * "Example4": { "@datatype": "tokens", "_string": "one three four" },
+ * "Example5": {
+ * "F": {
+ * "I": "test",
+ * "K": "example"
+ * },
+ * "H": {
+ * "J": "text"
+ * }
+ * }
* }
* }
* @endcode
@@ -146,14 +182,6 @@
static PSRETURN LoadXMLString(CParamNode& ret, const char* xml, const wchar_t* sourceIdentifier = NULL);
/**
- * Finds the childs named @a name from @a src and from @a this, and copies the source child's children
- * which are in the @a permitted set into this node's child.
- * Intended for use as a filtered clone of XML files.
- * @a this and @a src must have childs named @a name.
- */
- void CopyFilteredChildrenOfChild(const CParamNode& src, const char* name, const std::set& permitted);
-
- /**
* Returns the (unique) child node with the given name, or a node with IsOk() == false if there is none.
*/
const CParamNode& GetChild(const char* name) const;
Index: ps/trunk/source/simulation2/system/ParamNode.cpp
===================================================================
--- ps/trunk/source/simulation2/system/ParamNode.cpp
+++ ps/trunk/source/simulation2/system/ParamNode.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015 Wildfire Games.
+/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -76,6 +76,8 @@
// Look for special attributes
int at_disable = xmb.GetAttributeID("disable");
int at_replace = xmb.GetAttributeID("replace");
+ int at_filtered = xmb.GetAttributeID("filtered");
+ int at_merge = xmb.GetAttributeID("merge");
int at_op = xmb.GetAttributeID("op");
int at_datatype = xmb.GetAttributeID("datatype");
enum op {
@@ -84,6 +86,8 @@
MUL
} op = INVALID;
bool replacing = false;
+ bool filtering = false;
+ bool merging = false;
{
XERO_ITER_ATTR(element, attr)
{
@@ -97,6 +101,16 @@
m_Childs.erase(name);
replacing = true;
}
+ else if (attr.Name == at_filtered)
+ {
+ filtering = true;
+ }
+ else if (attr.Name == at_merge)
+ {
+ if (m_Childs.find(name) == m_Childs.end())
+ return;
+ merging = true;
+ }
else if (attr.Name == at_op)
{
if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"add")
@@ -157,6 +171,7 @@
// TODO: Support parsing of data types other than fixed; log warnings in other cases
fixed oldval = node.ToFixed();
fixed mod = fixed::FromString(CStrW(value));
+
switch (op)
{
case ADD:
@@ -168,24 +183,37 @@
}
hasSetValue = true;
}
- if (!hasSetValue)
+
+ if (!hasSetValue && !merging)
node.m_Value = value;
// We also need to reset node's script val, even if it has no children
// or if the attributes change.
node.ResetScriptVal();
+ // For the filtered case
+ ChildrenMap childs;
+
// Recurse through the element's children
XERO_ITER_EL(element, child)
{
node.ApplyLayer(xmb, child, sourceIdentifier);
+ if (filtering)
+ {
+ std::string childname = xmb.GetElementString(child.GetNodeName());
+ if (node.m_Childs.find(childname) != node.m_Childs.end())
+ childs[childname] = std::move(node.m_Childs[childname]);
+ }
}
+ if (filtering)
+ node.m_Childs.swap(childs);
+
// Add the element's attributes, prefixing names with "@"
XERO_ITER_ATTR(element, attr)
{
// Skip special attributes
- if (attr.Name == at_replace || attr.Name == at_op)
+ if (attr.Name == at_replace || attr.Name == at_op || attr.Name == at_merge || attr.Name == at_filtered)
continue;
// Add any others
std::string attrName = xmb.GetAttributeString(attr.Name);
@@ -193,21 +221,6 @@
}
}
-void CParamNode::CopyFilteredChildrenOfChild(const CParamNode& src, const char* name, const std::set& permitted)
-{
- ResetScriptVal();
-
- ChildrenMap::iterator dstChild = m_Childs.find(name);
- ChildrenMap::const_iterator srcChild = src.m_Childs.find(name);
- if (dstChild == m_Childs.end() || srcChild == src.m_Childs.end())
- return; // error
-
- ChildrenMap::const_iterator it = srcChild->second.m_Childs.begin();
- for (; it != srcChild->second.m_Childs.end(); ++it)
- if (permitted.count(it->first))
- dstChild->second.m_Childs[it->first] = it->second;
-}
-
const CParamNode& CParamNode::GetChild(const char* name) const
{
ChildrenMap::const_iterator it = m_Childs.find(name);
Index: ps/trunk/source/simulation2/tests/test_ParamNode.h
===================================================================
--- ps/trunk/source/simulation2/tests/test_ParamNode.h
+++ ps/trunk/source/simulation2/tests/test_ParamNode.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Wildfire Games.
+/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -135,6 +135,35 @@
TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"Y X");
}
+ void test_overlay_filtered()
+ {
+ CParamNode node;
+ TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, " toberemoved "), PSRETURN_OK);
+ TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, " "), PSRETURN_OK);
+ TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"");
+
+ CParamNode node2;
+ TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node2, " bcde "), PSRETURN_OK);
+ TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node2, " c2 "), PSRETURN_OK);
+ TS_ASSERT_WSTR_EQUALS(node2.ToXML(), L"bc2");
+ }
+
+ void test_overlay_merge()
+ {
+ CParamNode node;
+ TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, " foobar foo "), PSRETURN_OK);
+ TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, " testbaz willnotbeincluded textmore text "), PSRETURN_OK);
+ TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"testbarbazmore texttextfoo");
+ }
+
+ void test_overlay_filtered_merge()
+ {
+ CParamNode node;
+ TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, " 1200 "), PSRETURN_OK);
+ TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, " bar 1 "), PSRETURN_OK);
+ TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"11200bar");
+ }
+
void test_types()
{
CParamNode node;