public static Collection<Feature> LoadFeatureDataFromXmlNode(XElement xdoc, ICollection<DataProperty> properties, string featureName, ICollection<MsiFile> msifiles, ICollection<PluginData> plugins)
        {
            var testDataLoaders = new Collection<ITestDataLoader>();

            var asm = new CheckerDataTypeLoader(plugins);
            foreach (var loader in asm.GetAllLoaders())
            {
                testDataLoaders.Add(loader);
            }

            var internalPropertyCollection = CollectionTools.CopyCollection(properties);
            DataPropertyTool.ResolveProperties(internalPropertyCollection);

            var features = new Collection<Feature>();

            foreach (var featureNode in xdoc.Descendants().Where(x => x.Name.LocalName == "feature"))
            {
                var feature = new Feature
                                  {
                                      FeatureName = XmlTools.GetNamedAttributeValue(featureNode, "name", null)
                                  };
                if (featureName != null && featureName != feature.FeatureName)
                {
                    continue;
                }

                foreach (var loader in testDataLoaders)
                {
                    try
                    {
                        var mentry = loader as MsiFeatureTestDataLoader;
                        if (mentry != null)
                        {
                            ((MsiFeatureTestDataLoader)loader).Msifiles = msifiles;
                            ((MsiFeatureTestDataLoader)loader).Plugins = plugins;
                        }

                        foreach (var item in loader.ExtractData(featureNode, internalPropertyCollection))
                        {
                            feature.FeatureData.Add(item);
                        }
                    }
                    catch (Exception e)
                    {
                        Log.WriteError(e, "From method LoadFeatureDataFromXmlNode. An exception was thrown when executing the ExtractData method on loader:'" + loader.Name + "'");
                        throw;
                    }
                }

                features.Add(feature);
            }

            return features;
        }
        public bool VerifyInstallation(ICollection<FileChange> fileChanges, ICollection<Registryhange> registryChanges)
        {
            var ok = true;
            var asm = new CheckerDataTypeLoader(Plugins);

            Log.WriteInfo("Checking " + TestData.Count + " number of items", "VerifyInstallation");
            Log.Indent();
            foreach (var check in asm.GetAllChecks())
            {
                try
                {
                    if (!check.Check(TestData, fileChanges, registryChanges).Success)
                    {
                        ok = false;
                    }
                }
                catch (Exception e)
                {
                    Log.WriteError(e, "An exception was thrown when executing check:'" + check.Name + "'");
                    ok = false;
                }
            }

            Log.Unindent();

            if (fileChanges.Any() || registryChanges.Any())
            {
                Log.WriteError("Unexpected changes detected", "VerifyInstallation");
                ok = false;

            }

            Log.Indent();

            // Log all changes that have not been handled
            foreach (var fileChange in fileChanges)
            {
                Log.WriteError("Unexpected file change => " + fileChange, "VerifyInstallation");
            }

            foreach (var registryhange in registryChanges)
            {
                Log.WriteError("Unexpected registry change => " + registryhange, "VerifyInstallation");
            }

            Log.Unindent();

            return ok;
        }