File: LexicalAndXml\PreprocessorTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Syntax\Microsoft.CodeAnalysis.CSharp.Syntax.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Syntax.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    #region Local types for verification
 
    [Flags]
    public enum NodeStatus
    {
        None = 0,
        IsError = 1,
        IsWarning = 2,
        IsActive = 4,
        IsNotActive = 8, // used for #if etc.
        Unspecified = 8, // used for #def/und
        TrueValue = 16,
        Defined = 16, // used for #def/und
        FalseValue = 32,
        Undefined = 32, // used for #def/und
        BranchTaken = 64,
        NotBranchTaken = 128,
    }
 
    internal struct DirectiveInfo
    {
        public SyntaxKind Kind;
        public NodeStatus Status;
        public string Text;
        public int Number;
    }
 
    internal struct PragmaInfo
    {
        public SyntaxKind PragmaKind;
        public SyntaxKind WarningOrChecksumKind;
        public SyntaxKind DisableOrRestoreKind;
        public string[] WarningList;
        public string[] FileGuidByte;
    }
 
    internal struct MemberInfo
    {
        public SyntaxKind Kind;
        public NodeStatus Status;
        public NodeStatus Status2;
        public string Text;
    }
 
    #endregion
 
    public class PreprocessorTests : TestBase
    {
        public PreprocessorTests()
        {
        }
 
        #region Helpers
 
        private CSharpParseOptions GetOptions(SourceCodeKind kind, string[] defines)
        {
            return new CSharpParseOptions(languageVersion: LanguageVersion.CSharp4, kind: kind, preprocessorSymbols: defines);
        }
 
        private CompilationUnitSyntax Parse(string text, params string[] defines)
        {
            return Parse(text, SourceCodeKind.Regular, defines);
        }
 
        private CompilationUnitSyntax Parse(string text, SourceCodeKind kind, params string[] defines)
        {
            var options = this.GetOptions(kind, defines);
            return Parse(text, options);
        }
 
        private CompilationUnitSyntax Parse(string text, CSharpParseOptions options)
        {
            var itext = SourceText.From(text);
            return SyntaxFactory.ParseSyntaxTree(itext, options).GetCompilationUnitRoot();
        }
 
        private SyntaxTree ParseTree(string text, params string[] defines)
        {
            var options = this.GetOptions(SourceCodeKind.Regular, defines);
            var itext = SourceText.From(text);
            return SyntaxFactory.ParseSyntaxTree(itext, options);
        }
 
        private void TestRoundTripping(CompilationUnitSyntax node, string text, bool disallowErrors = true)
        {
            Assert.NotNull(node);
            var fullText = node.ToFullString();
            Assert.Equal(text, fullText);
 
            if (disallowErrors)
            {
                Assert.Empty(node.GetDiagnostics());
            }
            else
            {
                Assert.NotEmpty(node.GetDiagnostics());
            }
        }
 
        private void VerifyDirectives(CSharpSyntaxNode node, params SyntaxKind[] expected)
        {
            var directives = node.GetDirectives();
            Assert.Equal(expected.Length, directives.Count);
            if (expected.Length == 0)
            {
                return;
            }
 
            List<SyntaxKind> actual = new List<SyntaxKind>();
            foreach (var dt in directives)
            {
                actual.Add(dt.Kind());
            }
 
            int idx = 0;
            foreach (var ek in expected)
            {
                // Assert.True(actualKinds.Contains(kind)); // no order 
                Assert.Equal(ek, actual[idx++]); // exact order
            }
        }
 
        private void VerifyDirectivesSpecial(CSharpSyntaxNode node, params DirectiveInfo[] expected)
        {
            var directives = node.GetDirectives();
            Assert.Equal(expected.Length, directives.Count);
 
            List<SyntaxKind> actual = new List<SyntaxKind>();
            foreach (var dt in directives)
            {
                actual.Add(dt.Kind());
            }
 
            int idx = 0;
            foreach (var exp in expected)
            {
                Assert.Equal(exp.Kind, actual[idx]); // exact order
 
                // need to know what to expected here
                var dt = directives[idx++];
 
                if (NodeStatus.IsActive == (exp.Status & NodeStatus.IsActive))
                {
                    Assert.True(dt.IsActive);
                }
                else if (NodeStatus.IsNotActive == (exp.Status & NodeStatus.IsNotActive))
                {
                    Assert.False(dt.IsActive);
                }
 
                if (NodeStatus.BranchTaken == (exp.Status & NodeStatus.BranchTaken))
                {
                    Assert.True(((BranchingDirectiveTriviaSyntax)dt).BranchTaken);
                }
                else if (NodeStatus.NotBranchTaken == (exp.Status & NodeStatus.NotBranchTaken))
                {
                    Assert.False(((BranchingDirectiveTriviaSyntax)dt).BranchTaken);
                }
 
                if (NodeStatus.TrueValue == (exp.Status & NodeStatus.TrueValue))
                {
                    Assert.True(((ConditionalDirectiveTriviaSyntax)dt).ConditionValue);
                }
                else if (NodeStatus.FalseValue == (exp.Status & NodeStatus.FalseValue))
                {
                    Assert.False(((ConditionalDirectiveTriviaSyntax)dt).ConditionValue);
                }
 
                switch (exp.Kind)
                {
                    case SyntaxKind.DefineDirectiveTrivia:
                        if (null != exp.Text)
                        {
                            Assert.Equal(exp.Text, ((DefineDirectiveTriviaSyntax)dt).Name.ValueText); // Text
                        }
                        break;
                    case SyntaxKind.ErrorDirectiveTrivia:
                        if (null != exp.Text)
                        {
                            Assert.Equal(exp.Text, ((ErrorDirectiveTriviaSyntax)dt).EndOfDirectiveToken.ToFullString());
                        }
                        break;
                    case SyntaxKind.LoadDirectiveTrivia:
                        if (null != exp.Text)
                        {
                            Assert.Equal(exp.Text, ((LoadDirectiveTriviaSyntax)dt).File.ValueText);
                        }
                        break;
                    case SyntaxKind.UndefDirectiveTrivia:
                        if (null != exp.Text)
                        {
                            Assert.Equal(exp.Text, ((UndefDirectiveTriviaSyntax)dt).Name.ValueText);
                        }
                        break;
                    case SyntaxKind.ReferenceDirectiveTrivia:
                        if (null != exp.Text)
                        {
                            Assert.Equal(exp.Text, ((ReferenceDirectiveTriviaSyntax)dt).File.ValueText);
                        }
                        break;
                    case SyntaxKind.LineDirectiveTrivia:
                        var ld = (LineDirectiveTriviaSyntax)dt;
 
                        // default number = 0 - no number
                        if (exp.Number == -1)
                        {
                            Assert.Equal(SyntaxKind.LineKeyword, ld.LineKeyword.Kind());
                            Assert.Equal(SyntaxKind.DefaultKeyword, ld.Line.Kind());
                        }
                        else if (exp.Number == -2)
                        {
                            Assert.Equal(SyntaxKind.LineKeyword, ld.LineKeyword.Kind());
                            Assert.Equal(SyntaxKind.HiddenKeyword, ld.Line.Kind());
                        }
                        else if (exp.Number == 0)
                        {
                            Assert.Equal(String.Empty, ld.Line.Text);
                        }
                        else if (exp.Number > 0)
                        {
                            Assert.Equal(exp.Number, ld.Line.Value); // Number
                            Assert.Equal(exp.Number, Int32.Parse(ld.Line.Text));
                        }
 
                        if (null == exp.Text)
                        {
                            Assert.Equal(SyntaxKind.None, ld.File.Kind());
                        }
                        else
                        {
                            Assert.NotEqual(SyntaxKind.None, ld.File.Kind());
                            Assert.Equal(exp.Text, ld.File.Value);
                        }
                        break;
                    case SyntaxKind.NullableDirectiveTrivia:
                        var nn = (NullableDirectiveTriviaSyntax)dt;
                        var setting = nn.SettingToken;
                        var target = nn.TargetToken;
                        if (null == exp.Text)
                        {
                            Assert.True(setting.IsMissing);
                            Assert.True(target.IsMissing);
                        }
                        else
                        {
                            var actualText = setting.ValueText;
                            if (!string.IsNullOrEmpty(target.ValueText))
                            {
                                actualText += " " + target.ValueText;
                            }
 
                            Assert.Equal(exp.Text, actualText);
                            Assert.True(target.Kind() == SyntaxKind.WarningsKeyword || target.Kind() == SyntaxKind.AnnotationsKeyword ||
                                        target.Kind() == SyntaxKind.None);
 
                            Assert.True(setting.Kind() == SyntaxKind.EnableKeyword || setting.Kind() == SyntaxKind.DisableKeyword ||
                                        setting.Kind() == SyntaxKind.RestoreKeyword);
                        }
                        Assert.Equal(SyntaxKind.NullableKeyword, nn.DirectiveNameToken.Kind());
                        Assert.True(SyntaxFacts.IsPreprocessorDirective(SyntaxKind.NullableDirectiveTrivia));
                        Assert.True(SyntaxFacts.IsPreprocessorKeyword(SyntaxKind.NullableKeyword));
                        break;
                    default:
                        if (null != exp.Text)
                        {
                            Assert.True(false, String.Format("You are expecting some text in the directive, but this method doesn't know how to verify it for `{0}`.", exp.Kind));
                        }
                        break;
                } // switch
            }
        }
 
        private void VerifyDirectivePragma(CSharpSyntaxNode node, PragmaInfo expected)
        {
            var directives = node.GetDirectives();
            Assert.Equal(1, directives.Count);
            var dt = directives[0];
            VerifyDirectivePragma(dt, expected);
        }
 
        private void VerifyDirectivePragma(DirectiveTriviaSyntax dt, PragmaInfo expected)
        {
            Assert.Equal(expected.PragmaKind, dt.Kind());
 
            if (dt is PragmaWarningDirectiveTriviaSyntax)
            {
                var pwd = (PragmaWarningDirectiveTriviaSyntax)dt;
                Assert.Equal(SyntaxKind.PragmaKeyword, pwd.PragmaKeyword.Kind());
                if (SyntaxKind.None == expected.WarningOrChecksumKind)
                {
                    Assert.True(pwd.WarningKeyword.IsMissing);
                }
                else
                {
                    Assert.Equal(SyntaxKind.WarningKeyword, pwd.WarningKeyword.Kind());
                }
 
                if (SyntaxKind.None == expected.DisableOrRestoreKind)
                {
                    Assert.True(pwd.DisableOrRestoreKeyword.IsMissing);
                }
                else
                {
                    Assert.Equal(expected.DisableOrRestoreKind, pwd.DisableOrRestoreKeyword.Kind());
                }
 
                if (expected.WarningList == null || expected.WarningList.Length == 0)
                {
                    Assert.Equal(0, pwd.ErrorCodes.Count);
                }
                else
                {
                    Assert.Equal(expected.WarningList.Length, pwd.ErrorCodes.Count);
                    int idx = 0;
                    foreach (var warningNumber in expected.WarningList)
                    {
                        var actualWarningNumber = pwd.ErrorCodes[idx++];
                        if (actualWarningNumber.Kind() == SyntaxKind.NumericLiteralExpression)
                        {
                            var token = (actualWarningNumber as LiteralExpressionSyntax).Token;
                            Assert.Equal(warningNumber, token.ValueText);
                        }
                        else if (actualWarningNumber.Kind() == SyntaxKind.IdentifierName)
                        {
                            var token = (actualWarningNumber as IdentifierNameSyntax).Identifier;
                            Assert.Equal(warningNumber, token.ValueText);
                        }
                        else
                        {
                            Assert.True(false, "Warning ID must be an identifier or numeric literal");
                        }
                    }
                }
            }
            else if (dt is PragmaChecksumDirectiveTriviaSyntax)
            {
                var pcd = (PragmaChecksumDirectiveTriviaSyntax)dt;
                Assert.Equal(SyntaxKind.PragmaKeyword, pcd.PragmaKeyword.Kind());
                Assert.Equal(SyntaxKind.ChecksumKeyword, pcd.ChecksumKeyword.Kind()); // no missing
                // always 3
                Assert.Equal(3, expected.FileGuidByte.Length);
                if (expected.FileGuidByte[0] == null)
                {
                    Assert.True(pcd.File.IsMissing);
                }
 
                Assert.Equal(expected.FileGuidByte[0], pcd.File.Value);
                if (expected.FileGuidByte[1] == null)
                {
                    Assert.True(pcd.Guid.IsMissing);
                }
 
                Assert.Equal(expected.FileGuidByte[1], pcd.Guid.Value);
                if (expected.FileGuidByte[2] == null)
                {
                    Assert.True(pcd.Bytes.IsMissing);
                }
 
                Assert.Equal(expected.FileGuidByte[2], pcd.Bytes.Value);
            }
            else
            {
                throw new NotImplementedException(dt.Kind().ToString());
            }
        }
 
        private void VerifyErrorCode(CSharpSyntaxNode node, params int[] expected)
        {
            var actual = node.ErrorsAndWarnings().Select(e => e.Code).ToList();
 
            // no error
            if ((expected.Length == 0) && (actual.Count == 0))
            {
                return;
            }
 
            // Parser might give more errors than expected & that's fine
            Assert.InRange(actual.Count, expected.Length, int.MaxValue);
 
            // necessary?
            if (actual.Count < expected.Length)
            {
                return;
            }
 
            foreach (int i in expected)
            {
                Assert.Contains(i, actual); // no order
            }
        }
 
        private void VerifyErrorSpecial(CSharpSyntaxNode node, DirectiveInfo expected)
        {
            var diags = node.ErrorsAndWarnings();
            Assert.Equal(1, diags.Length);
            var actual = diags[0];
            Assert.Equal(expected.Number, actual.Code);
 
            // warning or not
            if (NodeStatus.IsWarning == (expected.Status & NodeStatus.IsWarning))
            {
                Assert.Equal(DiagnosticSeverity.Warning, actual.Severity);
            }
 
            // error message
            if (expected.Text != null)
            {
                Assert.Equal(expected.Text, actual.GetMessage(CultureInfo.InvariantCulture));
            }
        }
 
        /// <summary>
        /// Not sure if this is good idea
        /// </summary>
        /// <param name="memberInfo"></param>
        private void VerifyMembers(CompilationUnitSyntax node, params MemberInfo[] memberInfo)
        {
            Assert.Equal(memberInfo.Length, node.Members.Count);
            var actual = node.Members;
            int idx = 0;
            foreach (var exp in memberInfo)
            {
                var mem = actual[idx++];
                Assert.Equal(exp.Kind, mem.Kind());
 
#if false
                var td = (TypeDeclarationSyntax)mem;
                // #define/undef
                if ((exp.Status & NodeStatus.Defined) == NodeStatus.Defined)
                {
                    Assert.Equal(DefineState.Defined, td.IsDefined(exp.Text));
                }
                else if ((exp.Status & NodeStatus.Undefined) == NodeStatus.Undefined)
                {
                    Assert.Equal(DefineState.Undefined, td.IsDefined(exp.Text));
                }
                else if ((exp.Status & NodeStatus.Unspecified) == NodeStatus.Unspecified)
                {
                    Assert.Equal(DefineState.Unspecified, td.IsDefined(exp.Text));
                }
                else
                {
                    Assert.Equal(exp.Text, td.Name.GetText());
                }
                // check cond-symbol in Member
                if ((exp.Status2 & NodeStatus.TrueValue) == NodeStatus.TrueValue)
                {
                    Assert.Equal(DefineState.Defined, td.Name.IsDefined(exp.Text));
                }
                else if ((exp.Status2 & NodeStatus.FalseValue) == NodeStatus.FalseValue)
                {
                    Assert.Equal(DefineState.Undefined, td.Name.IsDefined(exp.Text));
                }
                else if ((exp.Status2 & NodeStatus.IsNotActive) == NodeStatus.IsNotActive) // reuse same flag for different meaning:(
                {
                    Assert.Equal(DefineState.Unspecified, td.Name.IsDefined(exp.Text));
                }
#endif
            }
        }
 
        #endregion
 
        #region General
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegBadDirectiveName()
        {
            var text = @"#goo";
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_PPDirectiveExpected);
            VerifyDirectives(node, SyntaxKind.BadDirectiveTrivia);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegBadDirectiveNoName()
        {
            var text = @"#";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_PPDirectiveExpected);
            VerifyDirectives(node, SyntaxKind.BadDirectiveTrivia);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDirectiveWithLeadingSpace()
        {
            var text = @"    #define XYZ";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDirectiveWithSpaceAfterHash()
        {
            var text = @"#   define XYZ";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDirectiveInsideMultilineComment()
        {
            var text = @"
/* 
#define XYZ
*/
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectives(node);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDirectiveAfterSingleLineComment()
        {
            var text = @"
// yada #define XYZ
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectives(node);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDirectiveInsideMultilineString()
        {
            var text = @"
class A
{
   string X = @""
#define XYZ
"";
}
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectives(node);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDirectiveInsideExcludedMultilineComment()
        {
            var text = @"
#if false
/*
#define XYZ
*/
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [WorkItem(906872, "DevDiv/Personal")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegressNegDirectiveInExcludedSingleLineComment()
        {
            var text = @"
#if false
// #define XYZ
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDirectiveInExcludedMultilineString()
        {
            var text = @"
#if false
class A
{
   string X = @""
#define XYZ
"";
}
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [WorkItem(906894, "DevDiv/Personal")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegressDirectiveInsideExcludedSingleLineString()
        {
            var text = @"
#if false
class A
{
   string X = ""#define XYZ"";
}
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        #endregion
 
        #region Conditional
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfTrueEndif()
        {
            var text = @"
#if true
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseEndif()
        {
            var text = @"
#if false
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfNotTakenWithEndIfLeadingWhitespace()
        {
            var text =
@"#if DBG
  class A { }
       #endif";
 
            // whitespace preceding '#' is important for this test.
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfWithBadTokens()
        {
            var text =
@"#if true GARBAGE
#endif";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndOfPPLineExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfTrueElseEndif()
        {
            var text = @"
#if true
  class A { }
#else
  class B { }
#endif
  class C { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node,
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "A" },
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "C" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseElseEndif()
        {
            var text = @"
#if false
  class A { }
#else
  class B { }
#endif
  class C { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node,
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "B" },
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "C" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfTrueElifTrueEndif()
        {
            var text = @"
#if true
  class A { }
#elif true
  class B { }
#endif
  class C { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node,
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "A" },
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "C" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseElifTrueEndif()
        {
            var text = @"
#if false
  class A { }
#elif true
  class B { }
#endif
  class C { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node,
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "B" },
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "C" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfTrueElifFalseEndif()
        {
            var text = @"
#if true
  class A { }
#elif false
  class B { }
#endif
  class C { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node,
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "A" },
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "C" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseElifFalseEndif()
        {
            var text = @"
#if false
  class A { }
#elif false
  class B { }
#endif
  class C { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "C" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfTrueElifTrueElseEndif()
        {
            var text = @"
#if true
  class A { }
#elif true
  class B { }
#else 
  class C { }
#endif
  class D { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "A" },
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "D" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseElifTrueElseEndif()
        {
            var text = @"
#if false
  class A { }
#elif true
  class B { }
#else 
  class C { }
#endif
  class D { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "B" }, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "D" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseElifFalseElseEndif()
        {
            var text = @"
#if false
  class A { }
#elif false
  class B { }
#else 
  class C { }
#endif
  class D { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "C" }, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "D" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfTrueElifFalseElseEndif()
        {
            var text = @"
#if true
  class A { }
#elif false
  class B { }
#else 
  class C { }
#endif
  class D { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "A" }, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "D" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfTrueElifFalseElifTrueElseEndif()
        {
            var text = @"
#if true
  class A { }
#elif false
  class B { }
#elif true
  class C { }
#else
  class D { }
#endif
  class E { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "A" }, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "E" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseElifFalseElifTrueElseEndif()
        {
            var text = @"
#if false
  class A { }
#elif false
  class B { }
#elif true
  class C { }
#else
  class D { }
#endif
  class E { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "C" },
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "E" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseElifFalseElifFalseElseEndif()
        {
            var text = @"
#if false
  class A { }
#elif false
  class B { }
#elif false
  class C { }
#else
  class D { }
#endif
  class E { }
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "D" },
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "E" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfTrueIfTrueEndIfEndIf()
        {
            var text = @"
#if true
#if true
#endif
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseIfTrueEndIfEndIf()
        {
            var text = @"
#if false
#if true
#endif
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsNotActive | NodeStatus.NotBranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfTrueIfFalseEndIfEndIf()
        {
            var text = @"
#if true
#if false
#endif
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfTrueElseIfTrueEndIfEndIf()
        {
            var text = @"
#if true
#else
#if true
#endif
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsNotActive | NodeStatus.NotBranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfTrueElifTrueIfTrueEndIfEndIf()
        {
            var text = @"
#if true
#elif true
#if true
#endif
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsNotActive | NodeStatus.NotBranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseElifTrueElseIfTrueEndIfEndIf()
        {
            var text = @"
#if false
#elif true
#else
#if true
#endif
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsNotActive | NodeStatus.NotBranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseIfFalseElseEndIfEndIf()
        {
            var text = @"
#if false
#if false
#endif
#if false
#else
#endif
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsNotActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsNotActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsNotActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithNameDefined()
        {
            var text = @"
#if XYZ
#endif
";
            var node = Parse(text, "XYZ"); // define XYZ
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithNameUndefined()
        {
            var text = @"
#if XYZ
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithLogicalOr()
        {
            var text =
@"#if ABC || XYZ
#endif
";
            var node = Parse(text, "ABC", "XYZ");
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithLogicalOrWhenOnlyOneDefined()
        {
            var text =
@"#if ABC || XYZ
#endif
";
            var node = Parse(text, "ABC");
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithLogicalAnd()
        {
            var text =
@"#if ABC && XYZ
#endif
";
            var node = Parse(text, "ABC", "XYZ");
 
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithLogicalAndWhenOnlyOneDefined()
        {
            var text =
@"#if ABC && XYZ
#endif
";
            var node = Parse(text, "ABC");
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithLogicalNotOnDefined()
        {
            var text =
@"#if !ABC
#endif
";
            var node = Parse(text, "ABC");
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithLogicalNotOnUndefined()
        {
            var text =
@"#if !ABC
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithParens()
        {
            var text =
@"#if (ABC)
#endif
";
            var node = Parse(text, "ABC");
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithEqualsAndBothDefined()
        {
            var text =
@"#if ABC == XYZ
#endif
";
            var node = Parse(text, "ABC", "XYZ");
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithEqualsAndBothNotDefined()
        {
            var text =
@"#if ABC == XYZ
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithEqualsAndOneDefined()
        {
            var text =
@"#if ABC == XYZ
#endif
";
            var node = Parse(text, "ABC");
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithNotEqualsAndBothDefined()
        {
            var text =
@"#if ABC != XYZ
#endif
";
            var node = Parse(text, "ABC", "XYZ");
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithNotEqualsAndBothUndefined()
        {
            var text =
@"#if ABC != XYZ
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfWithNotEqualsAndOneDefined()
        {
            var text =
@"#if ABC != XYZ
#endif
";
            var node = Parse(text, "ABC");
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [WorkItem(541898, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541898")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfNoEmptyTrivia()
        {
            var text = @"
#if YES
#pragma warning disable 0219
#pragma warning restore 0219
#elif NO
#pragma warning disable 0219
#pragma warning restore 0219
#else
#pragma warning disable 0219
#pragma warning restore 0219
#endif
";
            var node = Parse(text, "YES");
            TestRoundTripping(node, text);
            Assert.True(node.DescendantTrivia().All(trivia => trivia.Width > 0));
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfTrueWithNoEndif()
        {
            var text =
@"#if true
";
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndifDirectiveExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfFalseWithNoEndif()
        {
            var text =
@"#if false
";
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndifDirectiveExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfTrueWithEOF()
        {
            var text = @"#if true";
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndifDirectiveExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfFalseWithEOF()
        {
            var text = @"#if false";
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndifDirectiveExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfWithNoCondition()
        {
            var text =
@"#if 
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_InvalidPreprocExpr);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfTrueWithMissingParen()
        {
            var text =
@"#if (true
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_CloseParenExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfFalseWithMissingParen()
        {
            var text =
@"#if (false
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_CloseParenExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfTrueWithElifAfterElse()
        {
            var text =
@"#if true
#else
#elif true
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndifDirectiveExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.BadDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfWithElseAfterElse()
        {
            var text =
@"#if true
#else
#else
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndifDirectiveExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.BadDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfTrueEndRegionEndIf()
        {
            var text =
@"#if true
#endregion
#endif
";
 
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndifDirectiveExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.BadDirectiveTrivia, Status = NodeStatus.IsActive }, // ?
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegEndIfWithoutIf()
        {
            var text = @"#endif";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_UnexpectedDirective);
            VerifyDirectives(node, SyntaxKind.BadDirectiveTrivia);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegElseWithoutIf()
        {
            var text = @"#else";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_UnexpectedDirective);
            VerifyDirectives(node, SyntaxKind.BadDirectiveTrivia);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegElifWithoutIf()
        {
            var text = @"#elif";
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_UnexpectedDirective);
            VerifyDirectives(node, SyntaxKind.BadDirectiveTrivia);
        }
 
        [WorkItem(542198, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542198")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegElifWithoutIfWithSkipped()
        {
            var text = @"#elif ! defined X";
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_UnexpectedDirective);
            VerifyDirectives(node, SyntaxKind.BadDirectiveTrivia);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfTrueCodeElseCodeEndIf()
        {
            var text = @"
#if true
  class A { }
#else
  class B { }
#endif
";
            var node = Parse(text);
 
            TestRoundTripping(node, text);
 
            // TODO
            Assert.Equal(1, node.Members.Count);
            Assert.Equal(SyntaxKind.ClassDeclaration, node.Members[0].Kind());
            var td = (TypeDeclarationSyntax)node.Members[0];
            Assert.Equal("A", td.Identifier.ToString());
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseCodeElseCodeEndif()
        {
            var text = @"
#if false
  class A { }
#else
  class B { }
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectives(node, SyntaxKind.IfDirectiveTrivia, SyntaxKind.ElseDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia);
            VerifyMembers(node, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Text = "B" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfEndifDirectivesWithBadCode()
        {
            var text =
@"#if true
#else
#endif
aeu";
 
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyDirectives(node, SyntaxKind.IfDirectiveTrivia, SyntaxKind.ElseDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfElifWithBoolExpression()
        {
            var text = @"#define True1
#define True2
 
#define False1
#undef False1
#undef False1
#undef False2
 
using System;
 
public class Test
{
    public static int Main(string [] args)
    {
		int i = 6;
 
 #if True1 == true
		i--;
 #endif
 
#if False1 == false
		i--;
#endif
 
# if false
	#error #elif True2 == True1
#elif True2 == True1
		i--;
#else
	#error #else #elif True2 == True1
 #endif
 
#if (True1 != false) && ((False1) == False2) && (true || false)
		i--;
# else
	#error #if (True != false) && ((False1) == False2) && (true || false)
# endif
 
#if ((true == True1) != (false && true))
		i--;
#else
#error ((true == True1) != (false && true))
#endif
 
#if !(!(!!(true))) != false
		i--;
#else
#error !(!(!!(true))) != false
#endif
 
		return(i > 0 ? 1 : 0);
    }
}";
 
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectives(node, SyntaxKind.DefineDirectiveTrivia, SyntaxKind.DefineDirectiveTrivia, SyntaxKind.DefineDirectiveTrivia,
                SyntaxKind.UndefDirectiveTrivia, SyntaxKind.UndefDirectiveTrivia, SyntaxKind.UndefDirectiveTrivia,
                SyntaxKind.IfDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia, SyntaxKind.IfDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia,
                SyntaxKind.IfDirectiveTrivia, SyntaxKind.ErrorDirectiveTrivia, SyntaxKind.ElifDirectiveTrivia, SyntaxKind.ElseDirectiveTrivia, SyntaxKind.ErrorDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia,
                SyntaxKind.IfDirectiveTrivia, SyntaxKind.ElseDirectiveTrivia, SyntaxKind.ErrorDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia,
                SyntaxKind.IfDirectiveTrivia, SyntaxKind.ElseDirectiveTrivia, SyntaxKind.ErrorDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia,
                SyntaxKind.IfDirectiveTrivia, SyntaxKind.ElseDirectiveTrivia, SyntaxKind.ErrorDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia);
        }
 
        [WorkItem(921726, "DevDiv/Personal")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfElifWithBadNumericalName()
        {
            var text = @"class A
{
#if 0
    int x = 0;
#elif 1
    int x = 1;
#else
    int x = -1;
#endif
}
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_InvalidPreprocExpr, (int)ErrorCode.ERR_InvalidPreprocExpr);
            VerifyDirectives(node, SyntaxKind.IfDirectiveTrivia, SyntaxKind.ElifDirectiveTrivia, SyntaxKind.ElseDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia);
        }
 
        [WorkItem(911446, "DevDiv/Personal")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegressIfNestedExcludedBody()
        {
            var text = @"using System;
public class Test
{
public static int Main()
{
int i = 0;
#if false
aaa
#if true
this shouldn't even be looked at.
#else
Except for counting up the #if/ #endif pairs
#endif
This should be skipped too!
#endif
return (i);
}
}
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectives(node, SyntaxKind.IfDirectiveTrivia, SyntaxKind.IfDirectiveTrivia, SyntaxKind.ElseDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia);
        }
 
        [WorkItem(911464, "DevDiv/Personal")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegressIfFalseHashExcludedEndIf()
        {
            var text = @"
#if false
 // Bug#911464
#endif
 
#if false
 class X { void f() { R(""# s""); } }
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [WorkItem(913373, "DevDiv/Personal")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegressNestedIfWithUndefinedSymbols()
        {
            var text = @"class A
    {
#if AAA
        static void M()
        {
            int x = 0;
#if BBB
            x =1;
#endif
            x =2;
        }
#endif
}";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsNotActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        #endregion
 
        #region #region/#endregion
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegionEndRegion()
        {
            var text =
@"#region
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                    new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                    new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegionRegionEndRegionEndRegion()
        {
            var text =
@"#region
#region
#endregion
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                    new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                    new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                    new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive },
                    new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegionIfTrueEndIfEndRegion()
        {
            var text =
@"#region
#if true
#endif
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                    new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                    new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                    new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive },
                    new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegRegionEndIfEndRegion()
        {
            var text =
@"#region
#endif
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndRegionDirectiveExpected);
            VerifyDirectivesSpecial(node,
                    new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                    new DirectiveInfo { Kind = SyntaxKind.BadDirectiveTrivia, Status = NodeStatus.IsActive },
                    new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegRegionElifEndRegion()
        {
            var text =
@"#region
#elif
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndRegionDirectiveExpected);
            VerifyDirectives(node, SyntaxKind.RegionDirectiveTrivia, SyntaxKind.BadDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegRegionElseEndRegion()
        {
            var text =
@"#region
#else
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndRegionDirectiveExpected);
            VerifyDirectives(node, SyntaxKind.RegionDirectiveTrivia, SyntaxKind.BadDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfTrueRegionEndIf()
        {
            var text =
@"#if true
#region
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndRegionDirectiveExpected, (int)ErrorCode.ERR_EndRegionDirectiveExpected);
            VerifyDirectivesSpecial(node,
                    new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                    new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                    new DirectiveInfo { Kind = SyntaxKind.BadDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfTrueRegionEndIfEndRegion()
        {
            var text =
@"#if true
#region
#endif
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndRegionDirectiveExpected, (int)ErrorCode.ERR_EndifDirectiveExpected);
            VerifyDirectivesSpecial(node,
                    new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                    new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                    new DirectiveInfo { Kind = SyntaxKind.BadDirectiveTrivia, Status = NodeStatus.IsActive },
                    new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfFalseRegionEndIf()
        {
            var text =
@"#if false
#region
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndRegionDirectiveExpected, (int)ErrorCode.ERR_EndRegionDirectiveExpected);
            VerifyDirectivesSpecial(node,
                    new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                    new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsNotActive },
                    new DirectiveInfo { Kind = SyntaxKind.BadDirectiveTrivia, Status = NodeStatus.IsNotActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfFalseRegionEndIfEndRegion()
        {
            var text =
@"#if false
#region
#endif
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndRegionDirectiveExpected, (int)ErrorCode.ERR_EndifDirectiveExpected);
            VerifyDirectivesSpecial(node,
        new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
        new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsNotActive },
        new DirectiveInfo { Kind = SyntaxKind.BadDirectiveTrivia, Status = NodeStatus.IsNotActive },
        new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsNotActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegionWithTrailingTokens()
        {
            var text =
@"#region -- Some Cool Region --
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [WorkItem(2958, "DevDiv_Projects/Roslyn")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegionWithSingleLineComment()
        {
            var text =
@"#region A//B
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
 
            var regionDirective = (RegionDirectiveTriviaSyntax)node.GetFirstDirective();
            Assert.Equal($"#region A//B{Environment.NewLine}", regionDirective.ToFullString());
            var regionText = regionDirective.EndOfDirectiveToken.LeadingTrivia.Single();
            Assert.Equal(SyntaxKind.PreprocessingMessageTrivia, regionText.Kind());
            Assert.Equal("A//B", regionText.ToFullString());
        }
 
        [WorkItem(2958, "DevDiv_Projects/Roslyn")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegionWithInvalidSingleLineComment()
        {
            var text =
@"#region A/\B
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
 
            var regionDirective = (RegionDirectiveTriviaSyntax)node.GetFirstDirective();
            Assert.Equal($"#region A/\\B{Environment.NewLine}", regionDirective.ToFullString());
            var regionText = regionDirective.EndOfDirectiveToken.LeadingTrivia.Single();
            Assert.Equal(SyntaxKind.PreprocessingMessageTrivia, regionText.Kind());
            Assert.Equal("A/\\B", regionText.ToFullString());
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegRegionWithMultilineComment()
        {
            var text = @"
class Test
{
#region /* This is a 
    multilines 
        comment */
#endregion 
}
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_SemicolonExpected); // CS1003 (Extra), CS1002
            VerifyDirectives(node, SyntaxKind.RegionDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia);
        }
 
        [WorkItem(906835, "DevDiv/Personal")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegressNegRegionWithInvalidEscapeString()
        {
            // Dev10 compiler gives errors CS1009
            var text = @"
#region \u01
#endregion
#region \U000A
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectives(node, SyntaxKind.RegionDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia, SyntaxKind.RegionDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegionEndedWithEscapedNewline()
        {
            var text = @"
#region \u000D\u000A class A { }
#endregion
#region \U
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectives(node, SyntaxKind.RegionDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia, SyntaxKind.RegionDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia);
            VerifyMembers(node);
        }
 
        [WorkItem(527079, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/527079")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegressRegionWithEscapeUnicodePrefixOnly()
        {
            // [Breaking Change] Dev10 compiler gives errors CS1009
            var text = @"#region \u
#endregion \U
";
 
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectives(node, SyntaxKind.RegionDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia);
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestRegionWithMessage1()
        {
            var text =
@"#region ""
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
 
            var regionDirective = (RegionDirectiveTriviaSyntax)node.GetFirstDirective();
            Assert.Equal($"#region \"{Environment.NewLine}", regionDirective.ToFullString());
            var regionText = regionDirective.EndOfDirectiveToken.LeadingTrivia.Single();
            Assert.Equal(SyntaxKind.PreprocessingMessageTrivia, regionText.Kind());
            Assert.Equal("\"", regionText.ToFullString());
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestRegionWithMessage1B()
        {
            var text =
@"#region "" 
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
 
            var regionDirective = (RegionDirectiveTriviaSyntax)node.GetFirstDirective();
            Assert.Equal($"#region \" {Environment.NewLine}", regionDirective.ToFullString());
            var regionText = regionDirective.EndOfDirectiveToken.LeadingTrivia.Single();
            Assert.Equal(SyntaxKind.PreprocessingMessageTrivia, regionText.Kind());
            Assert.Equal("\" ", regionText.ToFullString());
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestRegionWithMessage2()
        {
            var text =
@"#region ""goo""
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
 
            var regionDirective = (RegionDirectiveTriviaSyntax)node.GetFirstDirective();
            Assert.Equal($"#region \"goo\"{Environment.NewLine}", regionDirective.ToFullString());
            var regionText = regionDirective.EndOfDirectiveToken.LeadingTrivia.Single();
            Assert.Equal(SyntaxKind.PreprocessingMessageTrivia, regionText.Kind());
            Assert.Equal("\"goo\"", regionText.ToFullString());
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestRegionWithMessage2B()
        {
            var text =
@"#region ""goo"" 
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
 
            var regionDirective = (RegionDirectiveTriviaSyntax)node.GetFirstDirective();
            Assert.Equal($"#region \"goo\" {Environment.NewLine}", regionDirective.ToFullString());
            var regionText = regionDirective.EndOfDirectiveToken.LeadingTrivia.Single();
            Assert.Equal(SyntaxKind.PreprocessingMessageTrivia, regionText.Kind());
            Assert.Equal("\"goo\" ", regionText.ToFullString());
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestRegionWithMessage3()
        {
            var text =
@"#region """"
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
 
            var regionDirective = (RegionDirectiveTriviaSyntax)node.GetFirstDirective();
            Assert.Equal($"#region \"\"{Environment.NewLine}", regionDirective.ToFullString());
            var regionText = regionDirective.EndOfDirectiveToken.LeadingTrivia.Single();
            Assert.Equal(SyntaxKind.PreprocessingMessageTrivia, regionText.Kind());
            Assert.Equal("\"\"", regionText.ToFullString());
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestRegionWithMessage3B()
        {
            var text =
@"#region """" 
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
 
            var regionDirective = (RegionDirectiveTriviaSyntax)node.GetFirstDirective();
            Assert.Equal($"#region \"\" {Environment.NewLine}", regionDirective.ToFullString());
            var regionText = regionDirective.EndOfDirectiveToken.LeadingTrivia.Single();
            Assert.Equal(SyntaxKind.PreprocessingMessageTrivia, regionText.Kind());
            Assert.Equal("\"\" ", regionText.ToFullString());
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestRegionWithMessage4()
        {
            var text =
@"#region """"""
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
 
            var regionDirective = (RegionDirectiveTriviaSyntax)node.GetFirstDirective();
            Assert.Equal($"#region \"\"\"{Environment.NewLine}", regionDirective.ToFullString());
            var regionText = regionDirective.EndOfDirectiveToken.LeadingTrivia.Single();
            Assert.Equal(SyntaxKind.PreprocessingMessageTrivia, regionText.Kind());
            Assert.Equal("\"\"\"", regionText.ToFullString());
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestRegionWithMessage4B()
        {
            var text =
@"#region """""" 
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.RegionDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndRegionDirectiveTrivia, Status = NodeStatus.IsActive });
 
            var regionDirective = (RegionDirectiveTriviaSyntax)node.GetFirstDirective();
            Assert.Equal($"#region \"\"\" {Environment.NewLine}", regionDirective.ToFullString());
            var regionText = regionDirective.EndOfDirectiveToken.LeadingTrivia.Single();
            Assert.Equal(SyntaxKind.PreprocessingMessageTrivia, regionText.Kind());
            Assert.Equal("\"\"\" ", regionText.ToFullString());
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestRegionWithMessage5()
        {
            var text =
@"#region Region Process Information after the Grid """"""""""""""""""""""""""""""""""""""""""""""""""
class C
{
}
#endregion
";
            var node = Parse(text);
            TestRoundTripping(node, text, disallowErrors: true);
 
            // ensure that we don't see those quotes as the start of a raw string that consumes the class decl.
            var classDeclaration = node.ChildNodes().Single(n => n is ClassDeclarationSyntax);
        }
 
        #endregion
 
        #region #define/#undefine
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDefineBeforeFirstToken()
        {
            var text = @"
#define XXX
class A { }
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            string defSym = "XXX";
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = defSym });
            VerifyMembers(node,
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Status = NodeStatus.Unspecified, Status2 = NodeStatus.Defined, Text = defSym });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegDefineAfterFirstToken()
        {
            var text = @"
class A { }
#define XXX
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_PPDefFollowsToken); // CS1032
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "XXX" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegDefineAfterTokenOnSameLine()
        {
            var text = @"
class A { } #define XXX
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_BadDirectivePlacement); // CS1040
            VerifyDirectivesSpecial(node);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDefineInIfBeforeFirstToken()
        {
            // defines after other directives are okay
            var text = @"
#if true
#define XXX
#endif
class A { }
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "XXX" },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDefineInIfExclusionAfterFirstToken()
        {
            // bad defines after first token in exclusion zone should not be errors
            var text = @"
class A { }
#if false
#define XXX
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = "XXX" },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDefineInsideIfFalse()
        {
            var text = @"
#if false
#define ZZZ
#endif
  class A { }
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            string defSym = "ZZZ";
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = defSym },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node,
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Status = NodeStatus.Unspecified, Status2 = NodeStatus.Unspecified, Text = defSym });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDefineInsideIfTrue()
        {
            var text = @"
#if true
#define ZZZ
#endif
  class A { }
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            string defSym = "ZZZ";
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = defSym },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node,
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Status = NodeStatus.Unspecified, Text = defSym, Status2 = NodeStatus.Defined });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegDefineWithNoName()
        {
            var text = @"#define";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_IdentifierExpected); // CS1001
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = string.Empty });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegDefineWithBadTokenForName()
        {
            var text = @"# define  true
class A {}";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_IdentifierExpected); // CS1001
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = string.Empty });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegDefineWithBadTokensAfterName()
        {
            var text = @"#define GOO(";
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndOfPPLineExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "GOO" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestUndefBeforeFirstToken()
        {
            var text = @"
#undef XXX
class A { }
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            string defSym = "XXX";
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = defSym });
            VerifyMembers(node,
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Status = NodeStatus.Unspecified, Status2 = NodeStatus.Undefined, Text = defSym });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegUndefAfterFirstToken()
        {
            var text = @"
class A { }
#undef XXX
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_PPDefFollowsToken);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = "XXX" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegUndefAfterTokenOnSameLine()
        {
            var text = @"
class A { } #undef XXX
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_BadDirectivePlacement);
            VerifyDirectivesSpecial(node);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestUndefInIfBeforeFirstToken()
        {
            // defines after other directives are okay
            var text = @"
#if true
#undef XXX
#endif
class A { }
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = "XXX" },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact, WorkItem(869243, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/869243")]
        [Trait("Feature", "Directives")]
        public void Bug869243_01()
        {
            var text = @"
#if false
    #define Z
#else
    #if Z
 ?1 // no errors here
    #endif
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = "Z" },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact, WorkItem(869243, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/869243")]
        [Trait("Feature", "Directives")]
        public void Bug869243_02()
        {
            var text = @"
#if false
    #define A
#elif false
    #define B
#else
    #if A
 ?1 // no errors here
    #endif
    #if B
 ?2 // no errors here
    #endif
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = "A" },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = "B" },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact, WorkItem(869243, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/869243")]
        [Trait("Feature", "Directives")]
        public void Bug869243_03()
        {
            var text = @"
#if false
    #define Z
    #if true
        #define Z
    #endif
#else
    #if Z
 ?1 // no errors here
    #endif
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = "Z" },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsNotActive | NodeStatus.NotBranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = "Z" },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact, WorkItem(869243, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/869243")]
        [Trait("Feature", "Directives")]
        public void Bug869243_04()
        {
            var text = @"
#if false
    #define Z
#else
    #if false
        #define Z
    #elif true
        #if Z
     ?1 // no errors here
        #endif
    #endif
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = "Z" },
                new DirectiveInfo { Kind = SyntaxKind.ElseDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = "Z" },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestUndefInIfExclusionAfterFirstToken()
        {
            // bad defines after first token in exclusion zone should not be errors
            var text = @"
class A { }
#if false
#undef XXX
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = "XXX" },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestUndefInsideIfFalse()
        {
            var text = @"
#if false
#undef ZZZ
#endif
  class A { }
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.NotBranchTaken | NodeStatus.FalseValue },
                new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = "ZZZ" },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node, new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Status = NodeStatus.Unspecified, Text = "ZZZ" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestUndefInsideIfTrue()
        {
            var text = @"
#if true
#undef ZZZ
#endif
  class A { }
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            string defSym = "ZZZ";
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive | NodeStatus.BranchTaken | NodeStatus.TrueValue },
                new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = defSym },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
            VerifyMembers(node,
                new MemberInfo { Kind = SyntaxKind.ClassDeclaration, Status = NodeStatus.Unspecified, Status2 = NodeStatus.Undefined, Text = defSym });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegUndefWithNoName()
        {
            var text = @"#undef";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_IdentifierExpected);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = string.Empty });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegUndefWithBadTokenForName()
        {
            var text = @"#undef (";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_IdentifierExpected);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = string.Empty });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegUndefWithBadTokensAfterName()
        {
            var text = @"#undef GOO(";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndOfPPLineExpected);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = "GOO" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegDefWithBadCommentsTokensAfterName()
        {
            var text = @"#define A_1 /**
*
*/";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndOfPPLineExpected);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "A_1" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegUndefWithBadNumericalName()
        {
            var text = @"#undef 1234 /// <!@#$%^&*()_+-=>";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_IdentifierExpected);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = "" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDefKeyword()
        {
            var text = @"#define error
#if error
#warning W1
#endif
 
#undef error
#if error
#warning W2
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.WRN_WarningDirective, Text = "#warning: 'W1'" });
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "error" },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.WarningDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive },
 
                new DirectiveInfo { Kind = SyntaxKind.UndefDirectiveTrivia, Status = NodeStatus.IsActive, Text = "error" },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.WarningDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDefKeywordExhaustive()
        {
            var text = @"#define if
#define else
#define elif
#define endif
#define region
#define endregion
#define define
#define undef
#define warning
#define error
#define line
#define pragma
#define reference
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "if" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "else" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "elif" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "endif" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "region" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "endregion" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "define" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "undef" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "warning" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "error" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "line" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "pragma" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "reference" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegDefKeywordExhaustive()
        {
            var text = @"#define true
#define false
#define default
#define hidden
#define checksum
#define disable
#define restore
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node,
                (int)ErrorCode.ERR_IdentifierExpected,
                (int)ErrorCode.ERR_IdentifierExpected,
                (int)ErrorCode.ERR_IdentifierExpected,
                (int)ErrorCode.ERR_IdentifierExpected,
                (int)ErrorCode.ERR_IdentifierExpected,
                (int)ErrorCode.ERR_IdentifierExpected,
                (int)ErrorCode.ERR_IdentifierExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "" },
                new DirectiveInfo { Kind = SyntaxKind.DefineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "" });
        }
 
        #endregion
 
        #region #error/#warning
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestError()
        {
            var text = @"#error Your monkey is alive";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_ErrorDirective, Text = "#error: 'Your monkey is alive'" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestWarning()
        {
            var text = @"#warning Your monkey is alive";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.WRN_WarningDirective, Text = "#warning: 'Your monkey is alive'" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.WarningDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseErrorEndIf()
        {
            var text = @"
#if false
#error Your monkey is alive
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfFalseWarningEndIf()
        {
            var text = @"
#if false
#warning Your monkey is alive
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.WarningDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfKeyword()
        {
            var text = @"
#if if
#warning W1
#elif elif
#warning W2
#elif endif
#warning W3
#elif !error
#warning W4
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.WRN_WarningDirective, Text = "#warning: 'W4'" });
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.WarningDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.WarningDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.WarningDirectiveTrivia, Status = NodeStatus.IsNotActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.WarningDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestIfKeywordExhaustive()
        {
            var text = @"
#if true
#elif false
#elif if
#elif else
#elif elif
#elif endif
#elif region
#elif endregion
#elif define
#elif undef
#elif warning
#elif error
#elif line
#elif pragma
#elif reference
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegIfKeywordExhaustive()
        {
            var text = @"
#if default
#elif hidden
#elif checksum
#elif disable
#elif restore
#endif
";
            var node = Parse(text);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyErrorCode(node,
                (int)ErrorCode.ERR_EndOfPPLineExpected,
                (int)ErrorCode.ERR_EndOfPPLineExpected,
                (int)ErrorCode.ERR_EndOfPPLineExpected,
                (int)ErrorCode.ERR_EndOfPPLineExpected,
                (int)ErrorCode.ERR_EndOfPPLineExpected);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.ElifDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestErrorWithNoMessage()
        {
            var text = @"#error";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_ErrorDirective, Text = "#error: ''" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestWarningWithNoMessage()
        {
            var text = @"#warning";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.WRN_WarningDirective, Text = "#warning: ''" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.WarningDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestErrorWithLeadingWhitespace()
        {
            var text = @"#error  abc def";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_ErrorDirective, Text = "#error: 'abc def'" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestErrorWithTrailingWhitespace()
        {
            var text = @"#error abc def ";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_ErrorDirective, Text = "#error: 'abc def '" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestErrorWithSingleLineComment()
        {
            var text = @"#error  /*abc def*/ ";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_ErrorDirective, Text = "#error: '/*abc def*/ '" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestErrorWithMultiLineComment()
        {
            var text = @"#error  /*abc def*/ ";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_ErrorDirective, Text = "#error: '/*abc def*/ '" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestErrorWithUnterminatedMultiLineComment()
        {
            var text = @"#error  /*abc def ";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_ErrorDirective, Text = "#error: '/*abc def '" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [WorkItem(541954, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541954")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestErrorWithNonLatinChars()
        {
            var errorText = "\u0444\u0430\u0439\u043B";
            var text = @"#error " + errorText;
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_ErrorDirective, Text = string.Format("#error: '{0}'", errorText) });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [WorkItem(541953, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541953")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestDiagnosticStringFileName()
        {
            CheckDiagnosticStringFileName("a.cs", "", "a.cs");
            CheckDiagnosticStringFileName("b\\a.cs", "", "b\\a.cs"); //path not trimmed
            CheckDiagnosticStringFileName("c:\\b\\a.cs", "", "c:\\b\\a.cs"); //path not trimmed
            CheckDiagnosticStringFileName("<file>", "", "<file>"); //invalid path characters - verbatim
 
            CheckDiagnosticStringFileName("z.cs", "#line 1 \"a.cs\"\r\n", "a.cs");
            CheckDiagnosticStringFileName("z.cs", "#line 1 \"b\\a.cs\"\r\n", "b\\a.cs"); //path not trimmed
            CheckDiagnosticStringFileName("z.cs", "#line 1 \"c:\\b\\a.cs\"\r\n", "c:\\b\\a.cs"); //path not trimmed
            CheckDiagnosticStringFileName("z.cs", "#line 1 \"<file>\"\r\n", "<file>"); //invalid path characters - verbatim
        }
 
        private void CheckDiagnosticStringFileName(string compilationFileName, string lineDirective, string expectedErrorStringFileName)
        {
            var text = lineDirective + "#error ERROR\r\n";
            var tree = SyntaxFactory.ParseSyntaxTree(text, path: compilationFileName);
            TestRoundTripping(tree.GetCompilationUnitRoot(), text, false);
            var error = tree.GetDiagnostics().Single();
            Assert.Equal((int)ErrorCode.ERR_ErrorDirective, error.Code);
            string errorString = error.ToString();
            string actualErrorStringFileName = errorString.Substring(0, errorString.IndexOf('('));
            Assert.Equal(expectedErrorStringFileName, actualErrorStringFileName);
        }
 
        [Theory]
        [InlineData(LanguageVersion.CSharp4, "4")]
        [InlineData(LanguageVersion.CSharp9, "9.0")]
        [InlineData(LanguageVersion.Latest, "latest (13.0)")]
        [InlineData(LanguageVersion.LatestMajor, "latestmajor (13.0)")]
        [InlineData(LanguageVersion.Default, "default (13.0)")]
        [InlineData(LanguageVersion.Preview, "preview")]
        public void TestErrorWithVersion(LanguageVersion version, string expectedLanguageVersion)
        {
            var text = "#error version";
            var node = Parse(text, new CSharpParseOptions(version));
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyDirectivesSpecial(node, new DirectiveInfo
            {
                Kind = SyntaxKind.ErrorDirectiveTrivia,
                Status = NodeStatus.IsActive,
                Text = "version"
            });
 
            node.GetDiagnostics().Verify(
                // (1,8): error CS1029: #error: 'version'
                // #error version
                Diagnostic(ErrorCode.ERR_ErrorDirective, "version").WithArguments("version").WithLocation(1, 8),
                // (1,8): error CS8304: Compiler version: '42.42.42.42424 (<developer build>)'. Language version: <expectedLanguageVersion>.
                // #error version
                Diagnostic(ErrorCode.ERR_CompilerAndLanguageVersion, "version").WithArguments(GetExpectedVersion(), expectedLanguageVersion).WithLocation(1, 8)
                );
        }
 
        [Fact]
        public void TestErrorWithVersionNumber()
        {
            var text = "#error version:7.1";
            var node = Parse(text, SourceCodeKind.Regular);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyDirectivesSpecial(node, new DirectiveInfo
            {
                Kind = SyntaxKind.ErrorDirectiveTrivia,
                Status = NodeStatus.IsActive,
                Text = "version:7.1"
            });
 
            node.GetDiagnostics().Verify(
                // (1,8): error CS1029: #error: 'version:7.1'
                // #error version:7.1
                Diagnostic(ErrorCode.ERR_ErrorDirective, "version:7.1").WithArguments("version:7.1"),
                // (1,8): error CS8025: Feature 'version' is not available in C# 4. Please use language version 7.1 or greater.
                // #error version:7.1
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion4, "version:7.1").WithArguments("version", "7.1").WithLocation(1, 8)
                );
        }
 
        [Fact]
        public void TestErrorWithInvalidVersion()
        {
            var text = "#error version:A.B";
            var node = Parse(text, SourceCodeKind.Regular);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyDirectivesSpecial(node, new DirectiveInfo
            {
                Kind = SyntaxKind.ErrorDirectiveTrivia,
                Status = NodeStatus.IsActive,
                Text = "version:A.B"
            });
 
            node.GetDiagnostics().Verify(
                // (1,8): error CS1029: #error: 'version:A.B'
                // #error version:A.B
                Diagnostic(ErrorCode.ERR_ErrorDirective, "version:A.B").WithArguments("version:A.B").WithLocation(1, 8)
                );
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestErrorWithStringMessage1()
        {
            var text = @"#error """;
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_ErrorDirective, Text = "#error: '\"'" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestErrorWithStringMessage2()
        {
            var text = @"#error ""goo""";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_ErrorDirective, Text = "#error: '\"goo\"'" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestErrorWithStringMessage3()
        {
            var text = @"#error """"";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_ErrorDirective, Text = "#error: '\"\"'" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact, WorkItem(1549726, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1549726")]
        [Trait("Feature", "Directives")]
        public void TestErrorWithStringMessage4()
        {
            var text = @"#error """"""";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_ErrorDirective, Text = "#error: '\"\"\"'" });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ErrorDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        #endregion
 
        #region #line
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestLine()
        {
            var text = @"#line 1000";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = 1000 });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestLineAndFile()
        {
            var text = @"#line 1000 ""bogus.cs""";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = 1000, Text = "bogus.cs" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestLineDefault()
        {
            var text = @"#line default";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = -1 });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineDefaultWithFile()
        {
            var text = @"#line default ""bogus.cs""";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndOfPPLineExpected);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = -1 });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestLineDefaultWithComment()
        {
            var text = @"#line default // GOO";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = -1 });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestLineHidden()
        {
            var text = @"#line hidden";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = -2 });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineHiddenWithFile()
        {
            var text = @"#line hidden ""bogus.cs""";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndOfPPLineExpected);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = -2 });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestLineHiddenWithComment()
        {
            var text = @"#line hidden // GOO";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = -2 });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineWithBadNumber()
        {
            var text = @"#line Goo";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_InvalidLineNumber);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineWithNoNumberOrFile()
        {
            var text = @"#line";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_InvalidLineNumber);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineWithOnlyFile()
        {
            var text = @"#line ""bogus.cs""";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_InvalidLineNumber);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Text = "bogus.cs" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegMoreLineNumThenPDBCanHandle()
        {
            var text = @"#line 16707566 ""XYZ""";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.WRN_TooManyLinesForDebugger);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = 16707566, Text = "XYZ" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineNumberInvalidZero()
        {
            var text = @"#line 0 ""XYZ""";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_InvalidLineNumber);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineNumberInvalidNegative()
        {
            var text = @"#line -1 ""XYZ""";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_InvalidLineNumber);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineNumberInvalidBiggerThanMaxInt()
        {
            var text = @"#line 2147483649 ""XYZ""";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_InvalidLineNumber);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineWithExtraTokens()
        {
            var text = @"#line 1000 XYZ";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_MissingPPFile);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = 1000 });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestLineWithComment()
        {
            var text = @"#line 1000 // XYZ";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = 1000 });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineWithFileAndExtraTokens()
        {
            var text = @"#line 1000 ""bogus.cs"" XYZ";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndOfPPLineExpected);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = 1000, Text = "bogus.cs" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestLineWithFileAndComment()
        {
            var text = @"#line 12345 ""bogus.cs"" // XYZ";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = 12345, Text = "bogus.cs" });
        }
 
        [WorkItem(536699, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/536699")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegressNegLineWithErrorMessage()
        {
            var text = @"class A
{
#line 100 ""test.cs""
x = 1;
}";
            var tree = ParseTree(text);
            TestRoundTripping(tree.GetCompilationUnitRoot(), text, false);
 
            // err TODO: check line number in error
            VerifyErrorCode(tree.GetCompilationUnitRoot(), (int)ErrorCode.ERR_InvalidMemberDecl); // CS1519 - parser gives Two
            VerifyDirectivesSpecial(tree.GetCompilationUnitRoot(), new DirectiveInfo { Kind = SyntaxKind.LineDirectiveTrivia, Status = NodeStatus.IsActive, Number = 100, Text = "test.cs" });
 
            var diagnostics = tree.GetDiagnostics();
            Assert.Contains("100", diagnostics.First().ToString(), StringComparison.Ordinal); // one-based line number
 
            var lineSpan = diagnostics.First().Location.GetMappedLineSpan();
            Assert.Equal(99, lineSpan.StartLinePosition.Line); // zero-based line number
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineWithTooLargeNumber()
        {
            var text = @"
public class Test
{
    # line 999999999999999999999
}
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_IntOverflow); // CS1021, CS1576 (not in parser) ErrorCode.ERR_InvalidLineNumber
            VerifyDirectives(node, SyntaxKind.LineDirectiveTrivia);
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineWithZero()
        {
            var text = @"
public class Test
{
    # line 0
}
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_InvalidLineNumber); // CS1021, CS1576 (not in parser) ErrorCode.ERR_InvalidLineNumber
            VerifyDirectives(node, SyntaxKind.LineDirectiveTrivia);
        }
 
        [WorkItem(537981, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537981")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineWithoutSpaceBeforeFile()
        {
            var text = @"
public class Test
{
    # line 1""File""
}
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_MissingPPFile);
            VerifyDirectives(node, SyntaxKind.LineDirectiveTrivia);
        }
 
        [WorkItem(537981, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537981")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegLineWithZeroWidthSpaceBeforeFile()
        {
            var text = @"
public class Test
{
    # line 1\u200B""File""
}
";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node); //zero width space is still a space
            VerifyDirectives(node, SyntaxKind.LineDirectiveTrivia);
        }
 
        [WorkItem(907010, "DevDiv/Personal")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegressLineWithVariousFileNameFormats()
        {
            var text = @"public class LineTests
{
	public static void Main() 
	{
		#line 10 ""ftp://test.cs""
		#line 20 ""ftps://test.cs""
		#line 30 ""http://test.cs""
		#line 40 ""https://test.cs""
		#line 50 ""gopher://test.cs""
		#line 60 ""telnet://test.cs""
		#line 70 ""dict://test.cs""
		#line 80 ""file://goo.aspx""
		#line 90 ""ldap://test.cs""
		#line 100 ""news://test.cs""
		#line 110 ""\\ddrelqa\logs\whidbey\2003-07-01\BVT64002\fx.Xml.XSLT\TESTPROCESSED20030701082505866.xml"" // parser error
		#line 120 ""C:\Documents and Settings\someuser\Local Settings\Temp\{f0a37341-d692-11d4-a984-009027ec0a9c}\test.cs"" // parser error
		#line 130 ""mailto://someuser@microsoft.com""
	}
}
";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectives(node, SyntaxKind.LineDirectiveTrivia, SyntaxKind.LineDirectiveTrivia, SyntaxKind.LineDirectiveTrivia,
                SyntaxKind.LineDirectiveTrivia, SyntaxKind.LineDirectiveTrivia, SyntaxKind.LineDirectiveTrivia, SyntaxKind.LineDirectiveTrivia, SyntaxKind.LineDirectiveTrivia,
                SyntaxKind.LineDirectiveTrivia, SyntaxKind.LineDirectiveTrivia, SyntaxKind.LineDirectiveTrivia, SyntaxKind.LineDirectiveTrivia, SyntaxKind.LineDirectiveTrivia);
        }
 
        #endregion
 
        #region #pragma
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningDisable()
        {
            var text = @"#pragma warning disable 114";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.DisableKeyword,
                WarningList = new[] { "114" }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningEnable_Error()
        {
            var text = @"#pragma warning enable 114";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.WRN_IllegalPPWarning); // CS1634
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.DisableKeyword
            });
        }
 
        [Fact(Skip = "https://github.com/dotnet/roslyn/issues/36550")]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningEnable()
        {
            var text = @"#pragma warning enable 114";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.EnableKeyword,
                WarningList = new[] { "114" }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningDisableNullable()
        {
            var text = @"#pragma warning disable nullable";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.DisableKeyword,
                WarningList = new[] { "nullable" }
            });
        }
 
        [Fact(Skip = "https://github.com/dotnet/roslyn/issues/36550")]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningEnableNullable()
        {
            var text = @"#pragma warning enable nullable";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.EnableKeyword,
                WarningList = new[] { "nullable" }
            });
        }
 
        [Fact(Skip = "https://github.com/dotnet/roslyn/issues/36550")]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningEnableCSharp7_3()
        {
            var text = @"#pragma warning enable 114";
            var node = Parse(text, options: TestOptions.Regular7_3);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.WRN_ErrorOverride, Status = NodeStatus.IsWarning });
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.EnableKeyword,
                WarningList = new[] { "114" }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningDisableWithMultipleCodes_01()
        {
            var text = @"#pragma warning disable 114, CS0162, 168";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.DisableKeyword,
                WarningList = new[] { "114", "CS0162", "168" }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningDisableWithMultipleCodes_02()
        {
            var text = @"#pragma warning disable 114, nullable";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.DisableKeyword,
                WarningList = new[] { "114", "nullable" }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningDisableWithMultipleCodes_03()
        {
            var text = @"#pragma warning disable nullable, 114";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.DisableKeyword,
                WarningList = new[] { "nullable", "114" }
            });
        }
 
        [Fact(Skip = "https://github.com/dotnet/roslyn/issues/36550")]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningEnableWithMultipleCodes_01()
        {
            var text = @"#pragma warning enable 114, CS0162, 168";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.EnableKeyword,
                WarningList = new[] { "114", "CS0162", "168" }
            });
        }
 
        [Fact(Skip = "https://github.com/dotnet/roslyn/issues/36550")]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningEnableWithMultipleCodes_02()
        {
            var text = @"#pragma warning enable 114, nullable";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.EnableKeyword,
                WarningList = new[] { "114", "nullable" }
            });
        }
 
        [Fact(Skip = "https://github.com/dotnet/roslyn/issues/36550")]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningEnableWithMultipleCodes_03()
        {
            var text = @"#pragma warning enable nullable, CS0162";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.EnableKeyword,
                WarningList = new[] { "nullable", "CS0162" }
            });
        }
 
        [Fact, WorkItem(536701, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/536701"), WorkItem(530051, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530051")]
        [Trait("Feature", "Directives")]
        public void TestRegressPragmaWarningDisableWithWarningCode()
        {
            var text = @"
class A
{
    static void Main(int i)
    {
#pragma warning disable 1633
#pragma something // warning CS1633: Unrecognized #pragma directive
    }
}
";
            // verify that error still appears in GetDiagnostics
            var tree = SyntaxFactory.ParseSyntaxTree(text);
            var diagnostic = tree.GetDiagnostics().Single();
            Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity);
            Assert.Equal(1633, diagnostic.Code);
 
            // verify pragma information
            var node = tree.GetCompilationUnitRoot();
            VerifyDirectivePragma(node.GetDirectives().First(), new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.DisableKeyword,
                WarningList = new[] { "1633" }
            });
 
            // verify that GetParseDiagnostics filters disabled warning
            var comp = CSharpCompilation.Create("Test", syntaxTrees: new[] { tree });
            Assert.Empty(comp.GetParseDiagnostics());
        }
 
        [WorkItem(908125, "DevDiv/Personal")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNoWarningForUnrecognizedCode()
        {
            var text = @"#pragma warning disable 99999";
            var node = Parse(text);
 
            // Previous versions of the compiler used to report a warning (CS1691)
            // whenever an unrecognized warning code was supplied in a #pragma directive.
            // We no longer generate a warning in such cases.
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.DisableKeyword,
                WarningList = new[] { "99999" }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningRestore()
        {
            var text = @"#pragma warning restore CS0114";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.RestoreKeyword,
                WarningList = new[] { "CS0114" }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningRestoreWithMultipleCodes_01()
        {
            var text = @"#pragma warning restore CS0114, 162, Something // Multiple codes";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.RestoreKeyword,
                WarningList = new[] { "CS0114", "162", "Something" }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningRestoreWithMultipleCodes_02()
        {
            var text = @"#pragma warning restore CS0114, nullable";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.RestoreKeyword,
                WarningList = new[] { "CS0114", "nullable" }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningRestoreWithMultipleCodes_03()
        {
            var text = @"#pragma warning restore nullable, CS0114";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.RestoreKeyword,
                WarningList = new[] { "nullable", "CS0114" }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestStringLiteralsAreDisallowed()
        {
            var text = @"#pragma warning restore ""CS0114"", 162, ""CS0168"" // Mixed string & numeric codes";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.WRN_IdentifierOrNumericLiteralExpected, Status = NodeStatus.IsWarning }); // CS1072
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.RestoreKeyword,
                WarningList = new[] { string.Empty }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegPragmaWarningWithBadStyle()
        {
            var text = @"#pragma warning GOO";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.WRN_IllegalPPWarning, Status = NodeStatus.IsWarning }); // CS1634
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.None,
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegPragmaWarningWithBadStyleAndCodes()
        {
            var text = @"#pragma warning GOO 114";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.WRN_IllegalPPWarning, Status = NodeStatus.IsWarning }); // CS1634
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.None
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegPragmaWarningWithNoStyle()
        {
            var text = @"#pragma warning 114";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.WRN_IllegalPPWarning, Status = NodeStatus.IsWarning }); // CS1634
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.None
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningDisableWithNoCodes()
        {
            var text = @"#pragma warning disable";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.DisableKeyword
            });
        }
 
        [Fact(Skip = "https://github.com/dotnet/roslyn/issues/36550")]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningEnableWithNoCodes()
        {
            var text = @"#pragma warning enable";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.EnableKeyword
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaWarningRestoreWithNoCodes()
        {
            var text = @"#pragma warning restore";
            var node = Parse(text);
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.WarningKeyword,
                DisableOrRestoreKind = SyntaxKind.RestoreKeyword
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegPragmaWithoutWarningOrChecksum()
        {
            var text = @"#pragma";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.WRN_IllegalPragma); // CS1633
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.None,
                DisableOrRestoreKind = SyntaxKind.None
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegPragmaWithBadToken()
        {
            var text = @"#pragma GOO";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.WRN_IllegalPragma);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaWarningDirectiveTrivia,
                WarningOrChecksumKind = SyntaxKind.None,
                DisableOrRestoreKind = SyntaxKind.None
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaChecksum()
        {
            var file = "bogus.cs";
            var guid = "{" + Guid.Empty + "}";
            var bytes = "ab007f1d23d9";
            var text = string.Format(@"#pragma checksum ""{0}"" ""{1}"" ""{2}""", file, guid, bytes);
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaChecksumDirectiveTrivia,
                FileGuidByte = new string[] { file, guid, bytes }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegPragmaChecksumWithNoBytes()
        {
            var file = "bogus.cs";
            var guid = "{" + Guid.Empty + "}";
            var text = string.Format(@"#pragma checksum ""{0}"" ""{1}""", file, guid);
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.WRN_IllegalPPChecksum); // CS1695
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaChecksumDirectiveTrivia,
                FileGuidByte = new string[] { file, guid, null }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegPragmaChecksumWithNoGuidAndNoBytes()
        {
            var file = "bogus.cs";
            var text = string.Format(@"#pragma checksum ""{0}""", file);
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.WRN_IllegalPPChecksum);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaChecksumDirectiveTrivia,
                FileGuidByte = new string[] { file, null, null }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegPragmaChecksumWithNothingElse()
        {
            var text = @"#pragma checksum";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.WRN_IllegalPPChecksum);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaChecksumDirectiveTrivia,
                FileGuidByte = new string[] { null, null, null }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestPragmaChecksumWithNoBracesOnGuid()
        {
            var file = "bogus.cs";
            var guid = Guid.Empty.ToString();
            var bytes = "ab007f1d23d9";
            var text = string.Format(@"#pragma checksum ""{0}"" ""{1}"" ""{2}""", file, guid, bytes);
            var node = Parse(text);
 
            TestRoundTripping(node, text);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaChecksumDirectiveTrivia,
                FileGuidByte = new string[] { file, guid, bytes }
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegPragmaChecksumWithBadGuid()
        {
            var file = "bogus.cs";
            var guid = "{abc-123}";
            var bytes = "ab007f1d23d9";
            var text = string.Format(@"#pragma checksum ""{0}"" ""{1}"" ""{2}""", file, guid, bytes);
            var node = Parse(text);
 
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.WRN_IllegalPPChecksum);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaChecksumDirectiveTrivia,
                FileGuidByte = new string[] { file, guid, bytes }
            });
        }
 
        [WorkItem(909445, "DevDiv/Personal")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegressNegPragmaChecksumWithMLineComment()
        {
            var file = "test.cs";
            var guid = "{406EA660-64CF-4C82-B6F0-42D48172A799}";
            var bytes = string.Empty;
            var text = string.Format(@"#pragma checksum ""{0}"" ""{1}"" ""{2}"" /* Test Comment */", file, guid, bytes);
 
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.WRN_EndOfPPLineExpected); // CS1696
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaChecksumDirectiveTrivia,
                FileGuidByte = new string[] { file, guid, bytes }
            });
        }
 
        [WorkItem(909445, "DevDiv/Personal")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegressNegPragmaChecksumWithComma()
        {
            var file = "test.cs";
            var guid = "{406EA660-64CF-4C82-B6F0-42D48172A799}";
            var bytes = string.Empty;
            var text = string.Format(@"#pragma checksum ""{0}"", ""{1}"" ""{2}"" ", file, guid, bytes);
 
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.WRN_IllegalPPChecksum);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaChecksumDirectiveTrivia,
                FileGuidByte = new string[] { file, null/*guid*/, null/*bytes*/ }
            });
        }
 
        [WorkItem(922889, "DevDiv/Personal")]
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestRegressNegPragmaChecksumWithBadBytesInMethod()
        {
            var file = "test.cs";
            var guid = "{406EA660-64CF-4C82-B6F0-42D48172A799}";
            var bytes = "A";
            var text = string.Format(@"class Test {{
    static int Main() 
    {{
#pragma checksum ""{0}"" ""{1}"" ""{2}"" 
 return 0;
    }} }}", file, guid, bytes);
 
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.WRN_IllegalPPChecksum);
            VerifyDirectivePragma(node, new PragmaInfo
            {
                PragmaKind = SyntaxKind.PragmaChecksumDirectiveTrivia,
                FileGuidByte = new string[] { file, guid, bytes }
            });
        }
 
        #endregion
 
        #region #r
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestReference()
        {
            var text = @"#r ""bogus""";
            var node = Parse(text, SourceCodeKind.Script);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo
            {
                Kind = SyntaxKind.ReferenceDirectiveTrivia,
                Status = NodeStatus.IsActive,
                Text = "bogus"
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestReferenceWithComment()
        {
            var text = @"#r ""bogus"" // GOO";
            var node = Parse(text, SourceCodeKind.Script);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo
            {
                Kind = SyntaxKind.ReferenceDirectiveTrivia,
                Status = NodeStatus.IsActive,
                Text = "bogus"
            });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestReferenceNumber()
        {
            var text = @"#r 123";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_ExpectedPPFile);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ReferenceDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestReferenceWithoutQuotes()
        {
            var text = @"#r Goo";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_ExpectedPPFile);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ReferenceDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestReferenceWithoutFileWithComment()
        {
            var text = @"#r //comment";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_ExpectedPPFile);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ReferenceDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestNegReferenceWithoutFile()
        {
            var text = @"#r";
            var node = Parse(text);
            TestRoundTripping(node, text, false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_ExpectedPPFile);
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.ReferenceDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void TestReferenceWithVariousFileNameFormats()
        {
            var text = @"
#r ""ftp://test.cs""
#r ""ftps://test.cs""
#r ""http://test.cs""
#r ""https://test.cs""
#r ""gopher://test.cs""
#r ""telnet://test.cs""
#r ""dict://test.cs""
#r ""file://goo.aspx""
#r ""ldap://test.cs""
#r ""news://test.cs""
#r ""\\ddrelqa\logs\whidbey\2003-07-01\BVT64002\fx.Xml.XSLT\TESTPROCESSED20030701082505866.xml"" // comment
#r ""C:\Documents and Settings\someuser\Local Settings\Temp\{f0a37341-d692-11d4-a984-009027ec0a9c}\test.cs"" // comment
#r ""mailto://someuser@microsoft.com""
";
            var node = Parse(text, SourceCodeKind.Script);
            TestRoundTripping(node, text);
            VerifyDirectives(node, SyntaxKind.ReferenceDirectiveTrivia, SyntaxKind.ReferenceDirectiveTrivia, SyntaxKind.ReferenceDirectiveTrivia,
                SyntaxKind.ReferenceDirectiveTrivia, SyntaxKind.ReferenceDirectiveTrivia, SyntaxKind.ReferenceDirectiveTrivia, SyntaxKind.ReferenceDirectiveTrivia, SyntaxKind.ReferenceDirectiveTrivia,
                SyntaxKind.ReferenceDirectiveTrivia, SyntaxKind.ReferenceDirectiveTrivia, SyntaxKind.ReferenceDirectiveTrivia, SyntaxKind.ReferenceDirectiveTrivia, SyntaxKind.ReferenceDirectiveTrivia);
        }
 
        #endregion
 
        #region #load
 
        [Fact]
        public void TestLoad()
        {
            var text = "#load \"bogus\"";
            var node = Parse(text, SourceCodeKind.Script);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo
            {
                Kind = SyntaxKind.LoadDirectiveTrivia,
                Status = NodeStatus.IsActive,
                Text = "bogus"
            });
        }
 
        [Fact]
        public void TestLoadWithoutFile()
        {
            var text = "#load";
            var node = Parse(text, SourceCodeKind.Script);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_ExpectedPPFile);
            VerifyDirectivesSpecial(node, new DirectiveInfo
            {
                Kind = SyntaxKind.LoadDirectiveTrivia,
                Status = NodeStatus.IsActive,
            });
            Assert.True(node.GetLoadDirectives().Single().File.IsMissing);
        }
 
        [Fact]
        public void TestLoadWithSemicolon()
        {
            var text = "#load \"\";";
            var node = Parse(text, SourceCodeKind.Script);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyErrorCode(node, (int)ErrorCode.ERR_EndOfPPLineExpected);
            VerifyDirectivesSpecial(node, new DirectiveInfo
            {
                Kind = SyntaxKind.LoadDirectiveTrivia,
                Status = NodeStatus.IsActive,
                Text = ""
            });
        }
 
        [Fact]
        public void TestLoadWithComment()
        {
            var text = "#load \"bogus\" // comment";
            var node = Parse(text, SourceCodeKind.Script);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node, new DirectiveInfo
            {
                Kind = SyntaxKind.LoadDirectiveTrivia,
                Status = NodeStatus.IsActive,
                Text = "bogus"
            });
        }
 
        #endregion
 
        #region #nullable
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableCSharp7_3()
        {
            var text = @"#nullable enable";
            var node = Parse(text, options: TestOptions.Regular7_3);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_FeatureNotAvailableInVersion7_3, Status = NodeStatus.IsError });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "enable" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableRestore()
        {
            var text = @"#nullable restore";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyErrorCode(node); // no errors
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "restore" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableEnable()
        {
            var text = @"#nullable enable";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyErrorCode(node); // no errors
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "enable" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableDisable()
        {
            var text = @"#nullable disable // comment";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyErrorCode(node); // no errors
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "disable" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableEnableWarnings()
        {
            var text = @"#nullable enable warnings";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyErrorCode(node); // no errors
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "enable warnings" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableEnableAnnotations()
        {
            var text = @"#nullable enable annotations";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyErrorCode(node); // no errors
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "enable annotations" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableDisableWarnings()
        {
            var text = @"#nullable disable warnings // comment";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyErrorCode(node); // no errors
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "disable warnings" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableDisableBadTarget()
        {
            var text = @"#nullable disable errors";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_NullableDirectiveTargetExpected, Status = NodeStatus.IsError });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "disable" });
        }
 
        /// <summary>
        /// "enable" should be a keyword within the directive only.
        /// </summary>
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableEnableKeyword()
        {
            var text =
@"#nullable enable
class enable
{
}";
            var tree = ParseTree(text);
            var root = tree.GetCompilationUnitRoot();
            TestRoundTripping(root, text, false);
            VerifyErrorCode(root); // no errors
            VerifyDirectivesSpecial(root, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "enable" });
            var nodes = root.DescendantNodes(descendIntoTrivia: true);
            SyntaxToken token = nodes.OfType<NullableDirectiveTriviaSyntax>().Single().SettingToken;
            Assert.Equal(SyntaxKind.EnableKeyword, token.Kind());
            token = nodes.OfType<ClassDeclarationSyntax>().Single().Identifier;
            Assert.Equal(SyntaxKind.IdentifierToken, token.Kind());
            Assert.Equal(SyntaxKind.IdentifierToken, token.ContextualKind());
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableWithoutDisableOrRestore()
        {
            var text = @"#nullable";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_NullableDirectiveQualifierExpected, Status = NodeStatus.IsError });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableExtraToken()
        {
            var text = @"#nullable disable true";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_NullableDirectiveTargetExpected, Status = NodeStatus.IsError });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "disable" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableUnrecognizedSetting()
        {
            var text = @"#nullable disabled";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_NullableDirectiveQualifierExpected, Status = NodeStatus.IsError });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableUnrecognizedSettingExtraToken()
        {
            var text = @"#nullable disabled true";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text, disallowErrors: false);
            VerifyErrorSpecial(node, new DirectiveInfo { Number = (int)ErrorCode.ERR_NullableDirectiveQualifierExpected, Status = NodeStatus.IsError });
            VerifyDirectivesSpecial(node, new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableExcluded()
        {
            var text =
@"#nullable enable
#if false
#nullable enable
#endif
#nullable disable
";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "enable" },
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = "enable" },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsActive, Text = "disable" });
        }
 
        [Fact]
        [Trait("Feature", "Directives")]
        public void NullableExcludedUnrecognizedSetting()
        {
            var text =
@"#if false
#nullable disabled
#endif
";
            var node = Parse(text, options: TestOptions.Regular);
            TestRoundTripping(node, text);
            VerifyDirectivesSpecial(node,
                new DirectiveInfo { Kind = SyntaxKind.IfDirectiveTrivia, Status = NodeStatus.IsActive },
                new DirectiveInfo { Kind = SyntaxKind.NullableDirectiveTrivia, Status = NodeStatus.IsNotActive, Text = "" },
                new DirectiveInfo { Kind = SyntaxKind.EndIfDirectiveTrivia, Status = NodeStatus.IsActive });
        }
 
        #endregion
 
        private static string GetExpectedVersion()
        {
            return CommonCompiler.GetProductVersion(typeof(CSharpCompiler));
        }
    }
}