/// <summary>
        /// Instantiate a new SourceLineNumberCollection from an array of SourceLineNumber objects.
        /// </summary>
        /// <param name="sourceLineNumbers">The SourceLineNumber objects.</param>
        public SourceLineNumberCollection(SourceLineNumber[] sourceLineNumbers)
        {
            if (null == sourceLineNumbers)
            {
                throw new ArgumentNullException("sourceLineNumbers");
            }

            this.sourceLineNumbers = sourceLineNumbers;
        }
Example #2
0
        /// <summary>
        /// Creates a new preprocesor.
        /// </summary>
        public Preprocessor()
        {
            this.extensionMessages = new ExtensionMessages(this);
            this.variables = new Hashtable();
            this.includeSearchPaths = new StringCollection();
            this.extensionTypes = new Hashtable();

            this.currentLineNumber = null;
            this.sourceStack = new Stack();

            this.includeNextStack = new Stack();

            this.foundError = false;
            this.preprocessOut = null;

            // add the system variables
            this.variables.Add("sys.CURRENTDIR", String.Concat(Directory.GetCurrentDirectory(), "\\"));
        }
Example #3
0
        public XmlDocument Process(string sourceFile, Hashtable variables)
        {
            Stream processed = new MemoryStream();
            XmlDocument sourceDocument = new XmlDocument();

            try
            {
                this.core = new PreprocessorCore(this.extensionsByPrefix, this.Message, sourceFile, variables);
                this.core.ResolvedVariableHandler = this.ResolvedVariable;
                this.core.CurrentPlatform = this.currentPlatform;
                this.currentLineNumberWritten = false;
                this.currentLineNumber = new SourceLineNumber(sourceFile);
                this.currentFileStack.Clear();
                this.currentFileStack.Push(this.core.GetVariableValue(this.GetCurrentSourceLineNumbers(), "sys", "SOURCEFILEDIR"));

                // open the source file for processing
                using (Stream sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    // inspect the raw source
                    InspectorCore inspectorCore = new InspectorCore(this.Message);
                    foreach (InspectorExtension inspectorExtension in this.inspectorExtensions)
                    {
                        inspectorExtension.Core = inspectorCore;
                        inspectorExtension.InspectSource(sourceStream);

                        // reset
                        inspectorExtension.Core = null;
                        sourceStream.Position = 0;
                    }

                    if (inspectorCore.EncounteredError)
                    {
                        return null;
                    }

                    XmlReader reader = new XmlTextReader(sourceStream);
                    XmlTextWriter writer = new XmlTextWriter(processed, Encoding.UTF8);

                    // process the reader into the writer
                    try
                    {
                        foreach (PreprocessorExtension extension in this.extensions)
                        {
                            extension.Core = this.core;
                            extension.InitializePreprocess();
                        }
                        this.PreprocessReader(false, reader, writer, 0);
                    }
                    catch (XmlException e)
                    {
                        this.UpdateInformation(reader, 0);
                        throw new WixException(WixErrors.InvalidXml(this.GetCurrentSourceLineNumbers(), "source", e.Message));
                    }

                    writer.Flush();
                }

                // fire event with processed stream
                ProcessedStreamEventArgs args = new ProcessedStreamEventArgs(sourceFile, processed);
                this.OnProcessedStream(args);

                // create an XML Document from the post-processed memory stream
                XmlTextReader xmlReader = null;

                try
                {
                    // create an XmlReader with the path to the original file
                    // to properly set the BaseURI property of the XmlDocument
                    processed.Position = 0;
                    xmlReader = new XmlTextReader(new Uri(Path.GetFullPath(sourceFile)).AbsoluteUri, processed);
                    sourceDocument.Load(xmlReader);

                }
                catch (XmlException e)
                {
                    this.UpdateInformation(xmlReader, 0);
                    throw new WixException(WixErrors.InvalidXml(this.GetCurrentSourceLineNumbers(), "source", e.Message));
                }
                finally
                {
                    if (null != xmlReader)
                    {
                        xmlReader.Close();
                    }
                }

                // preprocess the generated XML Document
                foreach (PreprocessorExtension extension in this.extensions)
                {
                    extension.PreprocessDocument(sourceDocument);
                }
            }
            finally
            {
                // finalize the preprocessing
                foreach (PreprocessorExtension extension in this.extensions)
                {
                    extension.FinalizePreprocess();
                    extension.Core = null;
                }
            }

            if (this.core.EncounteredError)
            {
                return null;
            }
            else
            {
                if (null != this.preprocessOut)
                {
                    sourceDocument.Save(this.preprocessOut);
                    this.preprocessOut.Flush();
                }

                return sourceDocument;
            }
        }
Example #4
0
        /// <summary>
        /// Pops a file name from the stack of included files.
        /// </summary>
        private void PopInclude()
        {
            this.currentLineNumber = (SourceLineNumber)this.sourceStack.Pop();

            this.currentFileStack.Pop();
            this.includeNextStack.Pop();
        }
Example #5
0
        /// <summary>

        /// Pushes a file name on the stack of included files.
        /// </summary>
        /// <param name="fileName">Name to push on to the stack of included files.</param>
        private void PushInclude(string fileName)
        {
            this.currentFileStack.Push(fileName);
            this.sourceStack.Push(this.currentLineNumber);
            this.currentLineNumber = new SourceLineNumber(fileName);
            this.includeNextStack.Push(true);
        }
Example #6
0
        /// <summary>
        /// Main running method for the application.
        /// </summary>
        /// <param name="args">Commandline arguments to the application.</param>
        /// <returns>Returns the application error code.</returns>
        private int Run(string[] args)
        {
            int beginTickCount = Environment.TickCount;

            try
            {
                this.tempFileCollection = new TempFileCollection();

                Environment.SetEnvironmentVariable("WixUnitTempDir", this.tempFileCollection.BasePath, EnvironmentVariableTarget.Process);
                this.ParseCommandline(args);

                // get the assemblies
                Assembly wixUnitAssembly = this.GetType().Assembly;
                FileVersionInfo fv = FileVersionInfo.GetVersionInfo(wixUnitAssembly.Location);

                if (this.showHelp)
                {
                    Console.WriteLine("WixUnit version {0}", fv.FileVersion);
                    Console.WriteLine("Copyright (C) .NET Foundation and contributors. All rights reserved.");
                    Console.WriteLine();
                    Console.WriteLine(" usage: WixUnit [-?] tests.xml");
                    Console.WriteLine();
                    Console.WriteLine("   -env:<var>=<value>  Sets an environment variable to the value for the current process");
                    Console.WriteLine("   -notidy             Do not delete temporary files (for checking results)");
                    Console.WriteLine("   -rf                 Re-run the failed test from the last run");
                    Console.WriteLine("   -st                 Run the tests on a single thread");
                    Console.WriteLine("   -test:<Test_name>   Run only the specified test (may use wildcards)");
                    Console.WriteLine("   -update             Prompt user to auto-update a test if expected and actual output files do not match");
                    Console.WriteLine("   -v                  Verbose output");
                    Console.WriteLine("   -val                Run MSI validation for light unit tests");

                    return 0;
                }

                // set the environment variables for the process only
                foreach (KeyValuePair<string, string> environmentVariable in this.environmentVariables)
                {
                    Environment.SetEnvironmentVariable(environmentVariable.Key, environmentVariable.Value, EnvironmentVariableTarget.Process);
                }

                // load the schema
                XmlReader schemaReader = null;
                XmlSchemaCollection schemas = null;
                try
                {
                    schemas = new XmlSchemaCollection();

                    schemaReader = new XmlTextReader(wixUnitAssembly.GetManifestResourceStream("Microsoft.Tools.WindowsInstallerXml.Unit.unitTests.xsd"));
                    XmlSchema schema = XmlSchema.Read(schemaReader, null);
                    schemas.Add(schema);
                }
                finally
                {
                    if (schemaReader != null)
                    {
                        schemaReader.Close();
                    }
                }

                // load the unit tests
                XmlTextReader reader = null;
                XmlDocument doc = new XmlDocument();
                try
                {
                    reader = new XmlTextReader(this.unitTestsFile);
                    XmlValidatingReader validatingReader = new XmlValidatingReader(reader);
                    validatingReader.Schemas.Add(schemas);

                    // load the xml into a DOM
                    doc.Load(validatingReader);
                }
                catch (XmlException e)
                {
                    SourceLineNumber sourceLineNumber = new SourceLineNumber(this.unitTestsFile, e.LineNumber);
                    SourceLineNumberCollection sourceLineNumbers = new SourceLineNumberCollection(new SourceLineNumber[] { sourceLineNumber });

                    throw new WixException(WixErrors.InvalidXml(sourceLineNumbers, "unitTests", e.Message));
                }
                catch (XmlSchemaException e)
                {
                    SourceLineNumber sourceLineNumber = new SourceLineNumber(this.unitTestsFile, e.LineNumber);
                    SourceLineNumberCollection sourceLineNumbers = new SourceLineNumberCollection(new SourceLineNumber[] { sourceLineNumber });

                    throw new WixException(WixErrors.SchemaValidationFailed(sourceLineNumbers, e.Message, e.LineNumber, e.LinePosition));
                }
                finally
                {
                    if (reader != null)
                    {
                        reader.Close();
                    }
                }

                // check the document element
                if ("UnitTests" != doc.DocumentElement.LocalName || XmlNamespace != doc.DocumentElement.NamespaceURI)
                {
                    throw new InvalidOperationException("Unrecognized document element.");
                }

                // create a regular expression of the selected tests
                Regex selectedUnitTests = new Regex(String.Concat("^", String.Join("$|^", (string[])this.unitTests.ToArray(typeof(string))), "$"), RegexOptions.IgnoreCase | RegexOptions.Singleline);

                // find the unit tests
                foreach (XmlNode node in doc.DocumentElement)
                {
                    if (XmlNodeType.Element == node.NodeType)
                    {
                        switch (node.LocalName)
                        {
                            case "UnitTest":
                                XmlElement unitTestElement = (XmlElement)node;
                                string unitTestName = unitTestElement.GetAttribute("Name");

                                if (selectedUnitTests.IsMatch(unitTestName))
                                {
                                    unitTestElement.SetAttribute("TempDirectory", this.tempFileCollection.BasePath);
                                    this.unitTestElements.Enqueue(node);
                                }
                                break;
                        }
                    }
                }

                if (this.unitTests.Count > 0)
                {
                    this.totalUnitTests = this.unitTestElements.Count;
                    int numThreads;

                    if (this.updateTests || this.singleThreaded)
                    {
                        // If the tests are running with the -update switch, they must run on one thread
                        // so that all execution is paused when the user is prompted to update a test.
                        numThreads = 1;
                    }
                    else
                    {
                        // create a thread for each processor
                        numThreads = Convert.ToInt32(Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS"), CultureInfo.InvariantCulture);
                    }

                    Thread[] threads = new Thread[numThreads];

                    for (int i = 0; i < threads.Length; i++)
                    {
                        threads[i] = new Thread(new ThreadStart(this.RunUnitTests));
                        threads[i].Start();
                    }

                    // wait for all threads to finish
                    foreach (Thread thread in threads)
                    {
                        thread.Join();
                    }

                    // report the results
                    Console.WriteLine();
                    int elapsedTime = (Environment.TickCount - beginTickCount) / 1000;
                    if (0 < this.failedUnitTests.Count)
                    {
                        Console.WriteLine("Summary of failed tests:");
                        Console.WriteLine();

                        // Put the failed tests into an ArrayList, which will get serialized
                        ArrayList serializedFailedTests = new ArrayList();
                        foreach (string failedTest in this.failedUnitTests.Keys)
                        {
                            serializedFailedTests.Add(failedTest);
                            Console.WriteLine("{0}. {1}", this.failedUnitTests[failedTest], failedTest);
                        }

                        Console.WriteLine();
                        Console.WriteLine("Re-run the failed tests with the -rf option");
                        Console.WriteLine();
                        Console.WriteLine("Failed {0} out of {1} unit test{2} ({3} seconds).", this.failedUnitTests.Count, this.totalUnitTests, (1 != this.completedUnitTests ? "s" : ""), elapsedTime);

                        using (XmlWriter writer = XmlWriter.Create(this.failedTestsFile))
                        {
                            XmlSerializer serializer = new XmlSerializer(serializedFailedTests.GetType());
                            serializer.Serialize(writer, serializedFailedTests);
                            writer.Close();
                        }
                    }
                    else
                    {
                        Console.WriteLine("Successful unit tests: {0} ({1} seconds).", this.completedUnitTests, elapsedTime);
                    }
                    Console.WriteLine();
                }
                else
                {
                    Console.WriteLine("No unit tests were selected.");
                }
            }
            catch (WixException we)
            {
                this.messageHandler.Display(this, we.Error);
            }
            catch (Exception e)
            {
                this.messageHandler.Display(this, WixErrors.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace));
                if (e is NullReferenceException)
                {
                    throw;
                }
            }
            finally
            {
                if (this.noTidy)
                {
                    Console.WriteLine();
                    Console.WriteLine("The notidy option was specified, temporary files can be found at:");
                    Console.WriteLine(this.tempFileCollection.BasePath);
                }
                else
                {
                    // try three times and give up with a warning if the temp files aren't gone by then
                    const int RetryLimit = 3;

                    for (int i = 0; i < RetryLimit; i++)
                    {
                        try
                        {
                            Directory.Delete(this.tempFileCollection.BasePath, true);   // toast the whole temp directory
                            break; // no exception means we got success the first time
                        }
                        catch (UnauthorizedAccessException)
                        {
                            if (0 == i) // should only need to unmark readonly once - there's no point in doing it again and again
                            {
                                RecursiveFileAttributes(this.tempFileCollection.BasePath, FileAttributes.ReadOnly, false); // toasting will fail if any files are read-only. Try changing them to not be.
                            }
                            else
                            {
                                break;
                            }
                        }
                        catch (DirectoryNotFoundException)
                        {
                            // if the path doesn't exist, then there is nothing for us to worry about
                            break;
                        }
                        catch (IOException) // directory in use
                        {
                            if (i == (RetryLimit - 1)) // last try failed still, give up
                            {
                                break;
                            }
                            Thread.Sleep(300);  // sleep a bit before trying again
                        }
                    }
                }
            }

            return this.failedUnitTests.Count;
        }
Example #7
0
        /// <summary>
        /// Pushes a file name on the stack of included files.
        /// </summary>
        /// <param name="fileName">Name to push on to the stack of included files.</param>
        private void PushInclude(string fileName)
        {
            if (1023 < this.currentFileStack.Count)
            {
                throw new WixException(WixErrors.TooDeeplyIncluded(this.GetCurrentSourceLineNumbers(), this.currentFileStack.Count));
            }

            this.currentFileStack.Push(fileName);
            this.sourceStack.Push(this.currentLineNumber);
            this.currentLineNumber = new SourceLineNumber(fileName);
            this.includeNextStack.Push(true);
        }
        /// <summary>
        /// Clone the object.
        /// </summary>
        /// <returns>Returns a new instance of the object with the same values.</returns>
        public SourceLineNumber Clone()
        {
            SourceLineNumber newSourceLineNumber = new SourceLineNumber(this.fileName);
            newSourceLineNumber.lineNumber = this.lineNumber;
            newSourceLineNumber.hasLineNumber = this.hasLineNumber;

            return newSourceLineNumber;
        }
Example #9
0
        /// <summary>
        /// Preprocesses a file.
        /// </summary>
        /// <param name="sourcePath">Path to the file to preprocess.</param>
        /// <returns>XmlDocument with the postprocessed data validated by any schemas set in the preprocessor.</returns>
        public XmlDocument Process(string sourcePath)
        {
            FileInfo sourceFile = new FileInfo(sourcePath);
            StringWriter processed = new StringWriter();

            this.currentLineNumberWritten = false;
            this.currentLineNumber = new SourceLineNumber(sourceFile.FullName);
            this.foundError = false;

            // add the current source file and current source path to the system variables
            this.variables["sys.SOURCEFILEPATH"] = sourceFile.FullName;
            this.variables["sys.SOURCEFILEDIR"] = String.Concat(sourceFile.DirectoryName, "\\");

            // open the source file for processing
            using (Stream sourceStream = new FileStream(sourceFile.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                XmlReader reader = new XmlTextReader(sourceStream);
                XmlTextWriter writer = new XmlTextWriter(processed);
                writer.Formatting = Formatting.Indented;

                // process the reader into the writer
                try
                {
                    foreach (PreprocessorExtension extension in this.extensionTypes.Values)
                    {
                        extension.Variables = this.variables;
                        extension.Messages = this.extensionMessages;
                        extension.InitializePreprocess();
                    }
                    this.PreprocessReader(false, reader, writer, 0);
                }
                catch (XmlException e)
                {
                    this.UpdateInformation(reader, 0);
                    throw new WixInvalidXmlException(this.GetCurrentSourceLineNumbers(), e);
                }
                writer.Close();
            }

            foreach (PreprocessorExtension extension in this.extensionTypes.Values)
            {
                processed = extension.PreprocessDocument(processed);
            }

            // do not continue processing if an error was encountered in one of the extensions
            if (this.foundError)
            {
                return null;
            }

            if (this.preprocessOut != null)
            {
                this.preprocessOut.WriteLine(processed.ToString());
                this.preprocessOut.Flush();
            }

            // create an XML Document from the post-processed memory stream
            XmlDocument sourceDocument = new XmlDocument();
            using (StringReader reader = new StringReader(processed.ToString()))
            {
                try
                {
                    sourceDocument.Load(reader);
                }
                catch (XmlException)
                {
                    this.OnMessage(WixErrors.SP1ProbablyNotInstalled());
                }
            }

            return (this.foundError ? null : sourceDocument);
        }