public void IncrementalParse_Whitespace()
        {
            CssTree     doc    = new CssTree(null);
            DebugWriter writer = new DebugWriter();

            // Start with some rules
            doc.TextProvider = new StringTextProvider("a { } b { }");
            Assert.AreEqual(2, doc.StyleSheet.Children.Count);
            string origTree = writer.Serialize(doc.TextProvider, doc.StyleSheet);

            // Add space between them
            doc.OnTextChange(new StringTextProvider("a { } \r\n b { }"), 6, 0, 3);
            Assert.AreEqual(2, doc.StyleSheet.Children.Count);
            Assert.AreEqual(origTree, writer.Serialize(doc.TextProvider, doc.StyleSheet));

            // Delete spaces between them
            doc.OnTextChange(new StringTextProvider("a { } b { }"), 6, 3, 0);
            Assert.AreEqual(2, doc.StyleSheet.Children.Count);
            Assert.AreEqual(origTree, writer.Serialize(doc.TextProvider, doc.StyleSheet));

            // Change all the text, but only really add one more space
            doc.OnTextChange(new StringTextProvider("a { } b {  }"), 0, 11, 12);
            Assert.AreEqual(2, doc.StyleSheet.Children.Count);
            Assert.AreEqual(origTree, writer.Serialize(doc.TextProvider, doc.StyleSheet));
        }
        private void VerifyTreeAfterIncrementalParse(ITextProvider newText, TokenList newTokens, StyleSheet newStyleSheet)
        {
            ICssParser parser          = _parserFactory.CreateParser();
            StyleSheet validStyleSheet = parser.Parse(newText, newTokens, insertComments: true);

            // By the way, this is the slowest and most lame way to compare two trees
            DebugWriter writer        = new DebugWriter();
            string      validTreeText = writer.Serialize(newText, validStyleSheet);
            string      newTreeText   = writer.Serialize(newText, newStyleSheet);

            Debug.Assert(validTreeText == newTreeText, "Bad tree after incremental parsing");
        }
        public void ParseFile(string name)
        {
            StreamReader streamReader = null;
            StreamWriter streamWriter = null;
            string       file         = name + ".tree";

            try
            {
                string        text         = Helpers.LoadFileAsString(name);
                ITextProvider textProvider = new StringTextProvider(text);
                CssParser     parser       = new CssParser();

#if TEST_MEM_USAGE
                long startMem        = GC.GetTotalMemory(true);
                long totalTokenizeMS = 0;
                long totalParseMS    = 0;

                StyleSheet[] styleSheets = new StyleSheet[32];
                for (int i = 0; i < styleSheets.Length; i++)
                {
                    styleSheets[i] = parser.Parse(textProvider, insertComments: true);

                    totalTokenizeMS += parser.LastTokenizeMilliseconds;
                    totalParseMS    += parser.LastParseMilliseconds;
                }

                StyleSheet styleSheet = styleSheets[0];
                long       items      = 0;

                styleSheet.Accept(new CssTreeVisitor((ParseItem) =>
                {
                    items++;
                    return(VisitItemResult.Continue);
                }));

                long endMem   = GC.GetTotalMemory(true);
                long totalMem = endMem - startMem;
                long avgMem   = totalMem / styleSheets.Length;

                totalTokenizeMS /= styleSheets.Length;
                totalParseMS    /= styleSheets.Length;

                _totalMemParseFile   += avgMem;
                _totalCharsParseFile += text.Length;
                _totalItemsParseFile += items;
                _totalTokenizeMS     += totalTokenizeMS;
                _totalParseMS        += totalParseMS;

                System.Diagnostics.Debug.WriteLine("CSS parse file: {0}", file);
                System.Diagnostics.Debug.WriteLine("----------------------------------------------------------------------");
                System.Diagnostics.Debug.WriteLine("    Mem usage: {0} bytes for {1} chars ({2} bytes per char)", avgMem, text.Length, avgMem / text.Length);
                System.Diagnostics.Debug.WriteLine("    Mem usage: {0} bytes for {1} items ({2} bytes per item)", avgMem, items, avgMem / items);
                System.Diagnostics.Debug.WriteLine("    Perf: Tokenize:{0}ms, Parse:{1}ms, Total:{2}ms", totalTokenizeMS, totalParseMS, totalTokenizeMS + totalParseMS);

                System.Diagnostics.Debug.WriteLine(
                    "    Running mem usage average: {0} bytes per char. {1} bytes per item.",
                    _totalMemParseFile / _totalCharsParseFile,
                    _totalMemParseFile / _totalItemsParseFile);
#else
                StyleSheet styleSheet = parser.Parse(text, insertComments: true);
#endif

                DebugWriter debugWriter = new DebugWriter();
                string      actual      = debugWriter.Serialize(textProvider, styleSheet);

                if (s_regenerateBaselineFiles)
                {
                    if (File.Exists(file))
                    {
                        File.SetAttributes(file, FileAttributes.Normal);
                    }

                    streamWriter = new StreamWriter(file);
                    streamWriter.Write(actual);
                    streamWriter.Close();
                    streamWriter = null;
                }
                else
                {
                    streamReader = new StreamReader(file);
                    string expected = streamReader.ReadToEnd();
                    streamReader.Close();
                    streamReader = null;

                    // trim whitescpase in the end to avoid false positives b/c file
                    // has extra line break or whitespace at the end.
                    expected = expected.TrimEnd(new char[] { ' ', '\r', '\n', '\t' });
                    actual   = actual.TrimEnd(new char[] { ' ', '\r', '\n', '\t' });

                    Assert.AreEqual(expected, actual);
                }
            }
            catch (Exception exception)
            {
                Assert.Fail(string.Format("Test {0} has thrown an exception: {1}", name.Substring(name.LastIndexOf('\\') + 1), exception.Message));
            }
            finally
            {
                if (streamReader != null)
                {
                    streamReader.Close();
                }

                if (streamWriter != null)
                {
                    streamWriter.Close();
                }
            }
        }