|
// <copyright file="Test.cs" company="MetaPropeller" author="Vladimir Klisic">
//
// Copyright 2005 Vladimir Klisic
// mailto:vladimir.klisic@free.fr
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any
// damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute
// it freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must
// not claim that you wrote the original software. If you use this
// software in a product, an acknowledgment in the product documentation
// would be appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must
// not be misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// </copyright>
//
// <history>
// <change who=�Vladimir Klisic� date=�2005.02.16�>Initial version</change>
// <history>
using System;
using System.Collections.Specialized;
using System.Drawing;
using System.IO;
using System.Collections;
using System.Diagnostics;
using MetaPropeller.UnitTest;
namespace MetaPropeller.Configuration
{
public class Test
{
// Test enumeration used in conversion tests
enum Digits { Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine };
private static TreeConfiguration CreateTreeConfigurationInstance(bool deleteExistingFile)
{
string configFilePath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) +
Path.DirectorySeparatorChar + "TreeConfigurationTest.cfg";
TreeConfiguration cfg = null;
try
{
if (deleteExistingFile && File.Exists(configFilePath))
File.Delete(configFilePath);
cfg = new XmlConfiguration(configFilePath, "MyApplication");
}
catch (Exception)
{
}
return cfg;
}
[TestMethod]
public static void TestPathSyntax()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true); // true: delete existing file
cfg["/node1/node2/key1"] = "1";
cfg["node1/node2/key2"] = "2";
cfg["rootkey1"] = "root1";
cfg["/rootkey2"] = "root2";
Debug.Assert((string) cfg["node1.node2.key1"] == "1");
Debug.Assert((string) cfg[".node1.node2.key1"] == "1");
Debug.Assert((string) cfg[@"\node1\node2\key1"] == "1");
Debug.Assert((string) cfg[@"node1\node2\key1"] == "1");
Debug.Assert((string) cfg[@"\node1/node2.key1"] == "1");
Debug.Assert((string) cfg[@"\node1\node2\key2"] == "2");
Debug.Assert((string) cfg[@"node1.node2.key2"] == "2");
Debug.Assert((string) cfg["rootkey1"] == "root1");
Debug.Assert((string) cfg["/rootkey1"] == "root1");
Debug.Assert((string) cfg[@"\rootkey2"] == "root2");
Debug.Assert((string) cfg["rootkey2"] == "root2");
}
[TestMethod]
public static void TestSetGetValue()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
// Set a few values
cfg["/node/StringKey"] = "abc";
cfg["/node/IntKey"] = 123;
cfg["/node/DoubleKey"] = 123.45678;
cfg["/node/BooleanKey"] = true;
DateTime now = DateTime.Now;
cfg["/node/DateTimeKey"] = now;
cfg["/node/EnumKey"] = Digits.Eight;
// Check those values
Debug.Assert((string) cfg["/node/StringKey"] == "abc");
Debug.Assert((int) cfg["/node/IntKey"] == 123);
Debug.Assert((double) cfg["/node/DoubleKey"] == 123.45678);
Debug.Assert((bool) cfg["/node/BooleanKey"] == true);
Debug.Assert((DateTime) cfg["/node/DateTimeKey"] == now);
Debug.Assert((Digits) cfg["/node/EnumKey"] == Digits.Eight);
}
[TestMethod]
public static void TestPathCaseInsensitivity()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
cfg["/Node1/Node2/Key"] = "abc";
Debug.Assert((string) cfg["/noDe1/NODE2/keY"] == "abc");
}
[TestMethod]
public static void TestUnknownKey()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
Debug.Assert(cfg["/NonExistingNode/ThisKeyShouldNotExist"] == null); // null: invalid path
// Try to remove an unknown key
cfg["/NonExistingNode/ThisKeyShouldNotExist"] = null;
}
[TestMethod]
public static void TestEnumerateKeys()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
// Test enumeration of a non-existing node (iterate over an empty collection)
foreach (string key in cfg.Keys["/NonExistingNode1/NonExistingNode2"])
{
Debug.Assert(false);
}
// Make a test hierarchy
cfg["/node1/node2/key1"] = "abcdef";
cfg["/node1/node2/key2"] = 123;
cfg["/node1/node2/key3"] = true;
// Enumerate keys of node node2
ICollection keysCollection = cfg.Keys["/node1/node2"];
Debug.Assert(keysCollection != null);
Debug.Assert(keysCollection.Count == 3);
string[] keys = new string[keysCollection.Count];
keysCollection.CopyTo(keys, 0);
// The order of Keys is not guaranteed in any way
// so we can only test for a presence of a certain key here
Debug.Assert(Array.IndexOf(keys, "key1") != -1);
Debug.Assert(Array.IndexOf(keys, "key2") != -1);
Debug.Assert(Array.IndexOf(keys, "key3") != -1);
}
[TestMethod]
public static void TestEnumerateValues()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
// Test enumeration of a non-existing node (iterate over an empty collection)
foreach (object val in cfg.Values["/NonExistingNode1/NonExistingNode2"])
{
Debug.Assert(false);
}
// Make a test hierarchy
cfg["/node1/node2/key1"] = "abcdef";
cfg["/node1/node2/key2"] = 123;
DateTime now = DateTime.Now;
cfg["/node1/node2/key3"] = now; // set value
// Enumerate values of node node2
ICollection valuesCollection = cfg.Values["/node1/node2"];
Debug.Assert(valuesCollection != null);
Debug.Assert(valuesCollection.Count == 3);
object[] values = new object[valuesCollection.Count];
valuesCollection.CopyTo(values, 0);
// The order of Values in is not guaranteed in any way
// (but matches the order returned in Keys)
// so we can only test for a presence of a concrete value here
Debug.Assert(Array.IndexOf(values, "abcdef") != -1);
Debug.Assert(Array.IndexOf(values, 123) != -1);
Debug.Assert(Array.IndexOf(values, now) != -1);
}
[TestMethod]
public static void TestEnumerateSubNodes()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
// Test enumeration of a non-existing node (iterate over an empty collection)
foreach (ConfigurationNode n in cfg.Nodes["/NonExistingNode1/NonExistingNode2"])
{
Debug.Assert(false);
}
// Make a test hierarchy
cfg["/node1/node2/key1"] = "abc";
cfg["/node1/node2/key2"] = 123;
cfg["/node1/node3/key1"] = DateTime.Now;
cfg["/node1/node4/node5/node6/key1"] = true;
ICollection subNodesCollection = cfg.Nodes["/node1"];
ConfigurationNode[] subNodes = new ConfigurationNode[subNodesCollection.Count];
subNodesCollection.CopyTo(subNodes, 0);
Debug.Assert(subNodes.Length == 3); // node2, node3 and node4
StringCollection nodesSeenSoFar = new StringCollection();
foreach (ConfigurationNode n in subNodes)
{
Debug.Assert(n.Name == "node2" || n.Name == "node3" || n.Name == "node4");
Debug.Assert(nodesSeenSoFar.Contains(n.Name) == false);
nodesSeenSoFar.Add(n.Name);
}
}
[TestMethod]
public static void TestDynamicStructure()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
cfg["node1/key1"] = "abc";
foreach (ConfigurationNode n in cfg.Nodes["/"])
{
if (n.Name == "node1")
{
ConfigurationPath path = new ConfigurationPath("node2/node3");
ConfigurationNode subNode = n.CreateSubNode(path);
Debug.Assert(cfg.FindNode("/node1/node2/node3") != null);
}
}
cfg.Save();
}
[TestMethod]
public static void TestFindNode()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
cfg["/node1/node2/node3/node4/key1"] = "find";
ConfigurationNode foundNode = cfg.FindNode("/node1/node2/node3");
Debug.Assert(foundNode != null);
foundNode = cfg.FindNode("/node1/node2/node3/node4");
Debug.Assert(foundNode != null);
foundNode = cfg.FindNode("/node5/node6/node7/node8");
Debug.Assert(foundNode == null);
}
[TestMethod]
public static void TestRemoveNode()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
cfg["/node1/node2/node3/node4/key1"] = "delete me";
Debug.Assert(cfg["/node1/node2/node3/node4/key1"] != null);
bool removed = cfg.RemoveNode("/node1/node2/node3");
Debug.Assert(removed);
Debug.Assert(cfg["/node1/node2/node3/node4/key1"] == null);
Debug.Assert(cfg["/node1/node2/node3/node4"] == null);
ConfigurationNode n = cfg.FindNode("/node1/node2");
Debug.Assert(n != null);
Debug.Assert(n.HasSubNodes == false);
}
[TestMethod]
public static void TestRemoveKey()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
// Make a test hierarchy
cfg["/node1/node2/node3/node4/key1"] = "One";
cfg["/node1/node2/node3/node4/key2"] = 2;
cfg["/node1/node2/node3/node4/key3"] = false;
// Remove key key2
cfg["/node1/node2/node3/node4/key2"] = null;
ICollection keys = cfg.Keys["/node1/node2/node3/node4"];
Debug.Assert(keys.Count == 2);
Debug.Assert((string)cfg["/node1/node2/node3/node4/key1"] == "One");
Debug.Assert(cfg["/node1/node2/node3/node4/key2"] == null);
Debug.Assert((bool)cfg["/node1/node2/node3/node4/key3"] == false);
ConfigurationNode n = cfg.FindNode("/node1/node2/node3/node4");
Debug.Assert(n != null);
Debug.Assert(!n.Empty);
Debug.Assert(n.HasKeys);
// Remove remaining keys
cfg["/node1/node2/node3/node4/key1"] = null;
cfg["/node1/node2/node3/node4/key3"] = null;
Debug.Assert(n.Empty);
Debug.Assert(n.HasKeys == false);
}
[TestMethod]
public static void TestClear()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
// Make a test hierarchy
cfg["/node1/node2/node3/node4/key1"] = "One";
cfg["/node1/node2/node3/node4/key2"] = 2;
cfg["/node1/node2/node3/node4/key3"] = true;
cfg["/node1/node2/key1"] = "abcdef";
cfg["/node1/node2/key2"] = 123;
cfg["/node2/node3/key1"] = DateTime.Now;
cfg["/node3/node5/node6/node7/key1"] = "hi!";
cfg["/rootkey1"] = 1;
cfg["/rootkey2"] = "two";
ICollection nodes = cfg.Nodes["/"];
ICollection keys = cfg.Keys["/"];
ICollection values = cfg.Values["/"];
Debug.Assert(nodes.Count == 3); // node1, node2 and node3
Debug.Assert(keys.Count == 2); // rootkey1 and rootkey2
Debug.Assert(values.Count == 2); // 1 and "two"
cfg.Clear();
nodes = cfg.Nodes["/"];
keys = cfg.Keys["/"];
values = cfg.Values["/"];
Debug.Assert(nodes.Count == 0);
Debug.Assert(keys.Count == 0);
Debug.Assert(values.Count == 0);
}
[TestMethod]
public static void TestCustomTypeConverter()
{
XmlConfiguration cfg = (XmlConfiguration) CreateTreeConfigurationInstance(true);
MetaPropeller.CustomTypeConverters.MyClass mc = new MetaPropeller.CustomTypeConverters.MyClass("text", 123, DateTime.Now);
cfg["/MyClassSetting"] = mc;
bool saved = cfg.Save();
Debug.Assert(saved);
cfg = (XmlConfiguration) CreateTreeConfigurationInstance(false); // false: use the existing file (the one we just saved)
bool loaded = cfg.Load();
Debug.Assert(loaded);
MetaPropeller.CustomTypeConverters.MyClass mc2 = (MetaPropeller.CustomTypeConverters.MyClass) cfg["/MyClassSetting"];
Debug.Assert(mc.Text == mc2.Text);
Debug.Assert(mc.Number == mc2.Number);
Debug.Assert(mc.Date.Date == mc2.Date.Date);
Debug.Assert(mc.Date.Hour == mc2.Date.Hour && mc.Date.Minute == mc2.Date.Minute); // only parts up to minute are maintained
}
[TestMethod]
public static void TestLoadSave()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
// Make a test hierarchy
cfg["rootkey1"] = "root1";
cfg["/rootkey2"] = "root2";
cfg["/node1/node2/key1"] = "abc";
cfg["/node1/node2/key2"] = 123;
DateTime savedDate = DateTime.Now;
cfg["/node1/node2/key3"] = savedDate;
cfg["/node1/node3/key1"] = true;
cfg["/node1/node4/node5/node6/key1"] = "hi!";
cfg["/node1/node4/node7/node8/key1"] = 123.4567;
cfg["/node9/key1"] = Digits.Eight;
cfg["/Colors/Foreground"] = System.Drawing.SystemColors.WindowText;
Font f = new Font("Tahoma", 12, FontStyle.Bold);
cfg["/Font"] = f;
bool saved = cfg.Save();
Debug.Assert(saved);
cfg = CreateTreeConfigurationInstance(false); // false: use the existing file (the one we just saved)
bool loaded = cfg.Load();
Debug.Assert(loaded);
// Repeat above checks on a freshly loaded cfg
Debug.Assert((string)cfg["rootkey1"] == "root1");
Debug.Assert((string)cfg["/rootkey2"] == "root2");
Debug.Assert((string)cfg["/node1/node2/key1"] == "abc");
Debug.Assert((int)cfg["/node1/node2/key2"] == 123);
DateTime loadedDate = (DateTime) cfg["/node1/node2/key3"];
// Since we didn't provide custom type converter for DateTime, default conversion
// was used. That one constructs loadedDate from a string that contains
// all date parts up to seconds. Milliseconds get some random value, so loadedDate
// is not entirely equal to savedDate. The following three asserts prove that.
Debug.Assert(savedDate.Ticks != loadedDate.Ticks);
Debug.Assert(loadedDate.Date == savedDate.Date);
Debug.Assert(loadedDate.Hour == savedDate.Hour && loadedDate.Minute == savedDate.Minute);
ICollection keys = cfg.Keys["/node1/node2"];
Debug.Assert(keys.Count == 3);
ICollection nodes = cfg.Nodes["/node1"];
Debug.Assert(nodes.Count == 3);
Debug.Assert((bool)cfg["/node1/node3/key1"] == true);
Debug.Assert((string)cfg["/node1/node4/node5/node6/key1"] == "hi!");
Debug.Assert((double)cfg["/node1/node4/node7/node8/key1"] == 123.4567);
Debug.Assert((Digits) cfg["/node9/key1"] == Digits.Eight);
Debug.Assert((System.Drawing.Color) cfg["/Colors/Foreground"] == System.Drawing.SystemColors.WindowText);
Font f2 = (Font) cfg["/Font"];
Debug.Assert(f2.Name == f.Name && f2.Size == f.Size && f2.Style == f.Style);
}
[TestMethod]
public static void TestCulture()
{
TreeConfiguration cfg = CreateTreeConfigurationInstance(true);
float number = 123.456F;
DateTime now = DateTime.Now;
// Set the French culture for the whole configuration
cfg.Culture = "fr-FR";
ConfigurationNode rootNode = cfg.FindNode("/");
Debug.Assert(rootNode != null);
cfg["french/number"] = number; // key in the root node, same as "/number"
cfg["french/date"] = now;
// Override the culture info for a child node
ConfigurationPath path = new ConfigurationPath("southafrican");
ConfigurationNode subNode = rootNode.CreateSubNode(path);
subNode["number"] = number;
subNode["date"] = now;
subNode.Culture = "af-ZA"; // (Afrikaans - South Africa). Culture can be set at any time (before/after setting the values)
bool saved = cfg.Save();
Debug.Assert(saved);
cfg = CreateTreeConfigurationInstance(false); // false: use the existing file (the one we just saved)
bool loaded = cfg.Load();
Debug.Assert(loaded);
// Check a freshly loaded cfg
// French info first
Debug.Assert((float)cfg["/french/number"] == number);
DateTime loadedDate = (DateTime) cfg["/french/date"];
// Since we didn't provide custom type converter for DateTime, default conversion
// was used. That one constructs loadedDate from a string that contains
// all date parts up to seconds. Milliseconds get some random value, so loadedDate
// is not entirely equal to savedDate. The following three asserts prove that.
Debug.Assert(now.Ticks != loadedDate.Ticks);
Debug.Assert(loadedDate.Date == now.Date);
Debug.Assert(loadedDate.Hour == now.Hour && loadedDate.Minute == now.Minute);
// South African part
Debug.Assert((float)cfg["/southafrican/number"] == number);
loadedDate = (DateTime) cfg["/southafrican/date"];
Debug.Assert(now.Ticks != loadedDate.Ticks);
Debug.Assert(loadedDate.Date == now.Date);
Debug.Assert(loadedDate.Hour == now.Hour && loadedDate.Minute == now.Minute);
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Vladimir Klisic is a half-human, half-software development engineer, currently working for Trema Laboratories in southeastern France (Sophia-Antipolis).