Beispiel #1
0
        public void DapperCommand_Usage()
        {
            var tree = ExcessMock.Compile(@"
                class SomeClass
                {
                    void SomeMethod(int SomeInt)
                    {
                        sql
                        {
                            insert into SomeTable
                            values(@SomeInt)
                        }
                    }
                }", builder: (compiler) => DapperExtension.Apply(compiler));

            //must have a call to __connection.Execute
            var invocation = (tree.GetRoot()
                              .DescendantNodes()
                              .OfType <MethodDeclarationSyntax>()
                              .Single()
                              .Body
                              .Statements
                              .Single() as ExpressionStatementSyntax)
                             .Expression as InvocationExpressionSyntax;

            Assert.IsNotNull(invocation);
            Assert.IsTrue(invocation is InvocationExpressionSyntax);
            Assert.IsTrue((invocation as InvocationExpressionSyntax)
                          .Expression
                          .ToString()
                          .StartsWith("__connection1.Execute"));

            //must have added a literal string @"...query..."
            var literal = tree.GetRoot()
                          .DescendantNodes()
                          .OfType <LiteralExpressionSyntax>()
                          .Single()
                          .ToString();

            Assert.IsTrue(literal.Contains("@\""));
            Assert.IsTrue(literal.Contains("values(@SomeInt)"));

            //must have added parameters as an anonymous object
            var parameters = tree.GetRoot()
                             .DescendantNodes()
                             .OfType <AnonymousObjectCreationExpressionSyntax>()
                             .Single();

            Assert.IsTrue(parameters
                          .Initializers
                          .Any(init => init
                               .NameEquals
                               .Name
                               .ToString() == "SomeInt"));
        }
Beispiel #2
0
        public void R_Statement_Usage()
        {
            var tree = ExcessMock.Compile(@"
                void main()
                {
                    R()
                    {
                        x <- 1
                        y <- 2
                        z <- NA

                        if (x == 1) 
                            3 -> z
                                                    
                        if (y == 1) 
                        {
                            3 -> z
                        }
                        else
                        {
                            z1 <- 4
                            z <- z1 
                        }

                        while(z < 10)  c(a, z) -> a

                        for(i in z)
                        {
                            a <- c(a, i);
                        }

                        repeat
                        {
                            b <- a   
                            a <- c(b, b);
                            if (length(a) > 10) break;
                        }
                    }
                }", builder: (compiler) => RExtension.Apply(compiler));

            Assert.IsTrue(tree.GetRoot()
                          .DescendantNodes()
                          .OfType <WhileStatementSyntax>()
                          .Count() == 2); //must have replaced a while and a repeat

            Assert.IsTrue(tree.GetRoot()
                          .DescendantNodes()
                          .OfType <StatementSyntax>()
                          .Where(ss => !(ss is ExpressionStatementSyntax || ss is LocalDeclarationStatementSyntax || ss is BlockSyntax))
                          .Count() == 7); //3 if, 2 whiles, a foreach, a break
        }
Beispiel #3
0
        public void NamespaceFunction_ScopeKeyword_ShouldCreateANewContext()
        {
            var tree = ExcessMock.Link(@"
                namespace SomeNamespace
                {
                    function Function1()
                    {
                        scope
                        {
                            var InjectedValue = ""Hello"";
                            Function2();
                        }
                    }

                    function Function2()
                    {
                        inject
                        {
                            string InjectedValue;
                        }

                        Console.WriteLine(InjectedValue);
                    }
                }",
                                       (compiler) =>
            {
                Functions.Apply(compiler);
                DependencyInjection.Apply(compiler);
            });

            var root = tree
                       ?.GetRoot()
                       ?.NormalizeWhitespace();

            //the injected value must be read from the context
            Assert.IsTrue(root
                          .DescendantNodes()
                          .OfType <StatementSyntax>()
                          .Where(statement => statement.ToString() == "string InjectedValue = __scope.get<string>(\"InjectedValue\");")
                          .Any());

            //as well as be saved to a different context
            Assert.IsTrue(root
                          .DescendantNodes()
                          .OfType <StatementSyntax>()
                          .Where(statement => statement.ToString() == "__newScope.set(\"InjectedValue\", InjectedValue);")
                          .Any());
        }
Beispiel #4
0
        public void Model_Usage()
        {
            var tree = ExcessMock.Compile(@"
            namespace SomeNS
            {
                model SomeModel
                {
                    int Property1;
                    string Property2 = ""SomeValue"";
                }
            }", builder: (compiler) => ModelExtension.Apply(compiler));

            Assert.IsNotNull(tree);

            //an struct should have been added
            var @class = tree
                         .GetRoot()
                         .DescendantNodes()
                         .OfType <ClassDeclarationSyntax>()
                         .Single();

            //with one constructor
            var constructor = @class
                              .DescendantNodes()
                              .OfType <ConstructorDeclarationSyntax>()
                              .Single();

            //must have 2 parameters and 2 assignments
            Assert.AreEqual(2, constructor.ParameterList.Parameters.Count);
            Assert.AreEqual(2, constructor
                            .DescendantNodes()
                            .OfType <AssignmentExpressionSyntax>()
                            .Count());

            //must have 2 properties with private sets
            Assert.AreEqual(2, @class
                            .DescendantNodes()
                            .OfType <PropertyDeclarationSyntax>()
                            .Where(property => property
                                   .AccessorList
                                   .Accessors
                                   .Any(accessor =>
                                        accessor.Keyword.IsKind(SyntaxKind.SetKeyword) &&
                                        accessor
                                        .Modifiers
                                        .Any(modifier => modifier.IsKind(SyntaxKind.PrivateKeyword))))
                            .Count());
        }
Beispiel #5
0
        public void TypeCodeExtensions_KeywordIdentifierParameters()
        {
            var tree = ExcessMock.Compile(@"
                SomeExtension SomeIdentifier(int SomeParam)
                {
                    SomeCall();
                }",
                                          (compiler) => compiler.extension(
                                              "SomeExtension",
                                              TypeCodeExtensions_Transform(
                                                  expectsIdentifier: true,
                                                  expectsParameters: true)));

            Assert.IsNotNull(tree);
            TypeCodeExtensions_Assertions(tree, expectedArguments: 1);
        }
Beispiel #6
0
        public void TypeCodeExtensions_Keyword()
        {
            var tree = ExcessMock.Compile(@"
                SomeExtension
                {
                    SomeCall();
                }",
                                          (compiler) => compiler.extension(
                                              "SomeExtension",
                                              TypeCodeExtensions_Transform(
                                                  expectsIdentifier: false,
                                                  expectsParameters: false)));

            Assert.IsNotNull(tree);
            TypeCodeExtensions_Assertions(tree);
        }
Beispiel #7
0
        public void TypeExtensions_KeywordParameters()
        {
            var tree = ExcessMock.Compile(@"
                SomeExtension(int SomeParameter)
                {
                    void SomeMethod()
                    {
                    }
                }",
                                          (compiler) => compiler.extension(
                                              "SomeExtension",
                                              TypeExtensions_Transform(
                                                  expectsIdentifier: false,
                                                  expectsParameters: true)));

            Assert.IsNotNull(tree);
            TypeExtensions_Assertions(tree, expectedArguments: 1);
        }
Beispiel #8
0
        public void Contract_WhenUsingInvocationThenException_ShouldSucceed()
        {
            var tree = ExcessMock.Compile(@"
                class SomeClass
                {
                    void SomeMethod()
                    {
                        contract
                        {
                            SomeObject.SomeOtherMethod()
                                >> SomeException();
                        }
                    }
                }", builder: (compiler) => ContractExtension.Apply(compiler));

            Assert.IsNotNull(tree);
            Assert.IsFalse(tree.GetDiagnostics().Any());
        }
Beispiel #9
0
        public void MemberExtensions_KeywordParameters()
        {
            var tree = ExcessMock.Compile(@"
                class SomeClass
                {
                    SomeExtension(int SomeParam)
                    {
                        SomeCall();                
                    }    
                }",
                                          (compiler) => compiler.extension(
                                              "SomeExtension",
                                              MemberExtensions_Transform(
                                                  expectsIdentifier: false,
                                                  expectsParameters: true)));

            Assert.IsNotNull(tree);
            MemberExtensions_Assertions(tree, expectedArguments: 1);
        }
Beispiel #10
0
        public void Settings_Usage()
        {
            var tree = ExcessMock.Compile(@"
            namespace SomeNS
            {
                settings
                {
                    [SomeSection]
                        SomeIntValue = 12
                        SomeStringValue = ""Hello""
                    [SomeOtherSection]
                        SomeOtherValue = ""World""
                }
            }", builder: (compiler) => SettingExtension.Apply(compiler));

            Assert.IsNotNull(tree);

            //must have created a class
            var @class = tree
                         .GetRoot()
                         .DescendantNodes()
                         .OfType <ClassDeclarationSyntax>()
                         .Single();

            //with an "__init" method
            var method = @class
                         .DescendantNodes()
                         .OfType <MethodDeclarationSyntax>()
                         .Single();

            Assert.AreEqual("__init", method.Identifier.ToString());

            //with 3 statements
            Assert.AreEqual(3, method.Body.Statements.Count);

            //all containing a call to ConfigurationManager
            Assert.AreEqual(3, method
                            .Body
                            .DescendantNodes()
                            .OfType <MemberAccessExpressionSyntax>()
                            .Where(inv => inv.Expression.ToString() == "ConfigurationManager")
                            .Count());
        }
Beispiel #11
0
        public void NamespaceFunction_Injected_Requirements()
        {
            var tree = ExcessMock.Link(@"
                namespace SomeNamespace
                {
                    interface SomeInterface
                    {
                        void SomeMethod();
                    }

                    function SomeFunction()
                    {
                        inject
                        {
                            SomeInterface someInterface;
                        }

                        someInterface.SomeMethod();
                    }
                }",
                                       (compiler) =>
            {
                Functions.Apply(compiler);
                DependencyInjection.Apply(compiler);
            });

            var root = tree
                       ?.GetRoot()
                       ?.NormalizeWhitespace();

            //the injection must transform in a variable assignment
            //essentially asking the context to resolve the requested instance
            Assert.IsTrue(root
                          .DescendantNodes()
                          .OfType <LocalDeclarationStatementSyntax>()
                          .Single()
                          .Declaration
                          .Variables
                          .Single()
                          .Initializer
                          .Value.ToString().StartsWith("__scope"));
        }
Beispiel #12
0
        public void FreeFormExtensions_KeywordParameters()
        {
            var tree = ExcessMock.Compile(@"
                class SomeClass
                {
                    void SomeMethod()
                    {
                        SomeExtension(int SomeIdentifier) 
                        {
                            SomeCall();                
                        }    
                    }
                }",
                                          (compiler) => compiler.Lexical().extension(
                                              "SomeExtension", ExtensionKind.Code,
                                              FreeFormExtensions__Transform));

            Assert.IsNotNull(tree);
            FreeFormExtensions_Validation(tree, true);
        }
Beispiel #13
0
        public void Model_WithMultiTokenType_ShouldSucceed()
        {
            var tree = ExcessMock.Compile(@"
                namespace SomeNamespace
                {
	                public model SomeModel 
	                {
                        IEnumerable<int> SomeGeneric;
		                Guid[] SomeArray;
	                }
                }", builder: (compiler) => ModelExtension.Apply(compiler));

            Assert.IsNotNull(tree);

            //must have transform both fields into properties
            Assert.AreEqual(2, tree
                            .GetRoot()
                            .DescendantNodes()
                            .OfType <PropertyDeclarationSyntax>()
                            .Count());
        }
Beispiel #14
0
        public void MemberTypeExtensions_KeywordIdentifier()
        {
            var tree = ExcessMock.Compile(@"
                class SomeClass
                {
                    SomeExtension SomeIdentifier
                    {
                        void SomeMethod()
                        {
                        }
                    }    
                }",
                                          (compiler) => compiler.extension(
                                              "SomeExtension",
                                              MemberTypeExtensions_Transform(
                                                  expectsIdentifier: true,
                                                  expectsParameters: false)));

            Assert.IsNotNull(tree);
            MemberTypeExtensions_Assertions(tree);
        }
Beispiel #15
0
        public void R_Sequence_Usage()
        {
            var tree = ExcessMock.Compile(@"
                void main()
                {
                    R()
                    {
                        x <- 1:30
                        y <- 2*1:15
                        seq(-5, 5, by=.2) -> s3
                        s4 <- seq(length=51, from=-5, by=.2)
                        s5 <- rep(x, times=5)
                    }
                }", builder: (compiler) => RExtension.Apply(compiler));

            Assert.IsTrue(tree.GetRoot()
                          .DescendantNodes()
                          .OfType <InvocationExpressionSyntax>()
                          .Where(invocation => invocation.Expression.ToString().Contains("RR"))
                          .Count() == 6); //must have replaced all operators
        }
Beispiel #16
0
        public void TypeExtensions_Keyword()
        {
            var tree = ExcessMock.Compile(@"
                namespace SomeNamespace
                {
                    SomeExtension
                    {
                        void SomeMethod()
                        {
                        }
                    }
                }",
                                          (compiler) => compiler.extension(
                                              "SomeExtension",
                                              TypeExtensions_Transform(
                                                  expectsIdentifier: false,
                                                  expectsParameters: false)));

            Assert.IsNotNull(tree);
            TypeExtensions_Assertions(tree);
        }
Beispiel #17
0
        public void Debug()
        {
            var tree = ExcessMock.Link(@"
                using xs.server;
                using xs.concurrent;

                using demo_transpiler;

                namespace Home
                { 
	                public function Transpile(string text)
	                {
		                inject 
		                {
			                ITranspiler	_transpiler;
		                }      

		                return _transpiler.Process(text);       
	                }

	                public function TranspileGraph(string text)
	                {
		                inject 
		                {
			                IGraphTranspiler _graphTranspiler;
		                }      

		                return _graphTranspiler.Process(text);      
	                } 
                }",
                                       (compiler) =>
            {
                DependencyInjection.Apply(compiler);
                Functions.Apply(compiler);
            });

            //the result must contain one class (testing the temp class is removed)
            Assert.AreNotEqual(null, tree);
        }
Beispiel #18
0
        public void NamespaceFunction_Usage()
        {
            var tree = ExcessMock.Link(@"
                namespace SomeNamespace
                {
                    function SomeFunction()
                    {
                        return 10;
                    }
                }", (compiler) => Functions.Apply(compiler));

            var root = tree
                       ?.GetRoot()
                       ?.NormalizeWhitespace();

            //a class must have been created
            var @class = root
                         .DescendantNodes()
                         .OfType <ClassDeclarationSyntax>()
                         .Single();

            //named with the "Functions" convention
            Assert.AreEqual(@class.Identifier.ToString(), "Functions");

            //the method must remain
            var method = root
                         .DescendantNodes()
                         .OfType <MethodDeclarationSyntax>()
                         .Single();

            //inside the class
            Assert.AreEqual(method.Parent, @class);

            //with its type calculated to int
            Assert.IsTrue(method
                          .ReturnType.ToString().ToLower()
                          .StartsWith("int"));
        }
Beispiel #19
0
        public void Mapping_Usage()
        {
            var tree = ExcessMock.CompileWithMapping(@"  
                class SomeClass
                {
                    //one line comment                        
                    public void SomeMehod()
                    {
                        //two line comment                        
                        //two line comment
                        someCall();    
                    }    
                }");

            Assert.IsNotNull(tree);

            var root   = tree.GetRoot();
            var @class = root
                         .DescendantNodes()
                         .OfType <ClassDeclarationSyntax>()
                         .Single();

            //the class declaration must exist and be on the first line
            Assert.IsNotNull(@class);
            var filePos = @class.GetLocation().GetMappedLineSpan();

            Assert.AreEqual(1, filePos.StartLinePosition.Line);

            var method = root
                         .DescendantNodes()
                         .OfType <MethodDeclarationSyntax>()
                         .Single();

            //the method must exist and be on the right line
            Assert.IsNotNull(method);
            filePos = method.GetLocation().GetMappedLineSpan();
            Assert.AreEqual(4, filePos.StartLinePosition.Line);
        }
Beispiel #20
0
        public void CodeExtensions_KeywordIdentifierParameters()
        {
            var tree = ExcessMock.Compile(@"
                class SomeClass
                {
                    void SomeMethod()
                    {
                        SomeExtension SomeIdentifier(int SomeParam, SomeArgument)
                        {
                            SomeCall();                
                        }    
                    }
                }",
                                          (compiler) => compiler.extension(
                                              "SomeExtension",
                                              CodeExtensions_Transform(
                                                  expectsIdentifier: true,
                                                  expectsParameters: true)));

            Assert.IsNotNull(tree);
            CodeExtensions_Assertions(tree,
                                      expectedArguments: 4);
        }
Beispiel #21
0
        public void FreeFormExtensions_KeywordIdentifierParameters()
        {
            var tree = ExcessMock.Compile(@"
                class SomeClass
                {
                    void SomeMethod()
                    {
                        SomeExtension SomeIdentifier(int SomeParam) 
                        {
                            SomeCall();                
                        }    
                    }
                }",
                                          (compiler) => compiler.Lexical().extension(
                                              "SomeExtension", ExtensionKind.None,
                                              FreeFormExtensions__Transform));

            Assert.IsNotNull(tree);
            FreeFormExtensions_Validation(tree, false);

            //must have added 2 arguments
            var arguments = tree
                            .GetRoot()
                            .DescendantNodes()
                            .OfType <ArgumentListSyntax>()
                            .Where(args => args.Arguments.Count == 2)
                            .Single();

            //with 2 arguments, one for SomeIdentifier one for SomeParam
            var SomeIdentifier = arguments.Arguments.First();

            Assert.AreEqual("SomeIdentifier", SomeIdentifier.ToString());

            var SomeParam = arguments.Arguments.Last();

            Assert.AreEqual("SomeParam", SomeParam.ToString());
        }
Beispiel #22
0
        public void NamespaceFunction_SeveralFunctions_ShouldBeInvokedWithContext()
        {
            var tree = ExcessMock.Link(@"
                namespace SomeNamespace
                {
                    function Function1()
                    {
                        Function2(10);
                    }

                    function Function2(int value)
                    {
                        Console.WriteLine(value);
                    }
                }",
                                       (compiler) => Functions.Apply(compiler));

            var root = tree
                       ?.GetRoot()
                       ?.NormalizeWhitespace();

            //two partial classes must have been created
            Assert.AreEqual(root
                            .DescendantNodes()
                            .OfType <ClassDeclarationSyntax>()
                            .Count(), 2);

            //the call from Function1 to Function2 must be made with an internal scope
            Assert.AreEqual(root
                            .DescendantNodes()
                            .OfType <InvocationExpressionSyntax>()
                            .Where(invocation => invocation.Expression.ToString() == "Function2")
                            .Single()
                            .ArgumentList
                            .Arguments[1].ToString(), "__scope");
        }
Beispiel #23
0
        public void Debug()
        {
            var tree = ExcessMock.Compile(@"
                using xs.server;
                using xs.concurrent;

                using demo_transpiler;

                namespace Home
                { 
	                function Transpile(string text)
	                {
		                return _transpiler.Process(text);       
	                }

	                public function TranspileGraph(string text)
	                {
		                return _graphTranspiler.Process(text);      
	                } 
                }", (compiler) => DependencyInjection.Apply(compiler));

            //this is a placeholder to do some debuggin'
            Assert.AreNotEqual(null, tree);
        }
Beispiel #24
0
        public void IndentedGrammar_Usage()
        {
            var tree = ExcessMock.Compile(@"
                class TestClass
                {
                    void TestMethod()
                    {
                        var TestVar = ""World"";        
                        var TestArray = new [] {""Hello"", ""World""};
                        someExtension()
                        {
                            [Header1]
                                Value1 = 10
                                Value2 = ""SomeValue""
                            [Header2]
                                Value3 = ""Hello "" + TestVar
                            [ContactHeader]
                                Call Someone at 1-800-WAT-EVER
                                    Or else at 1-800-456-7890
                                    Less likely at (877) 789-1234
                            [Location]
                                Now at 9th and Hennepin, Minneapolis
                            //some code
                            for i in TestArray
                                Console.Write(i);
                        }
                    }
                }", (compiler) => MockIndentGrammar.Apply(compiler));

            Assert.IsNotNull(tree);

            //must have add 3 calls in the form SetHeaderValue("[Header]", "Value", Value);
            Assert.AreEqual(3, tree
                            .GetRoot()
                            .DescendantNodes()
                            .OfType <InvocationExpressionSyntax>()
                            .Where(invocation => invocation
                                   .Expression
                                   .ToString()
                                   .StartsWith("SetHeaderValue"))
                            .Count());

            //must have added a call in the form SetContact("[Header]", "Name", "Telephone");
            Assert.AreEqual(1, tree
                            .GetRoot()
                            .DescendantNodes()
                            .OfType <InvocationExpressionSyntax>()
                            .Where(invocation => invocation
                                   .Expression
                                   .ToString()
                                   .StartsWith("SetContact"))
                            .Count());

            //must refer to the supplied number
            Assert.AreEqual(1, tree
                            .GetRoot()
                            .DescendantNodes()
                            .OfType <LiteralExpressionSyntax>()
                            .Where(literal => literal
                                   .ToString()
                                   .Equals("\"1-800-WAT-EVER\""))
                            .Count());

            //must have added extra numbers in the form AddContactNumber("Header", "Name", AreaCode, First 3 numbers, Last 4 numbers)
            Assert.AreEqual(2, tree
                            .GetRoot()
                            .DescendantNodes()
                            .OfType <InvocationExpressionSyntax>()
                            .Where(invocation => invocation
                                   .Expression
                                   .ToString()
                                   .Equals("AddContactNumber"))
                            .Count());

            //must have parsed correctly and include all secondary telephones
            var numbers = new[] { 800, 456, 7890, 877, 789, 1234 };

            Assert.AreEqual(numbers.Length, tree
                            .GetRoot()
                            .DescendantNodes()
                            .OfType <LiteralExpressionSyntax>()
                            .Where(number => number.IsKind(SyntaxKind.NumericLiteralExpression) &&
                                   numbers.Contains(int.Parse(number.ToString())))
                            .Count());

            //must have added a location call
            Assert.AreEqual(1, tree
                            .GetRoot()
                            .DescendantNodes()
                            .OfType <InvocationExpressionSyntax>()
                            .Where(invocation => invocation.Expression.ToString() == "SetLocation")
                            .Count());

            //must have added a foreach statement
            Assert.AreEqual(1, tree
                            .GetRoot()
                            .DescendantNodes()
                            .OfType <ForEachStatementSyntax>()
                            .Count());
        }
Beispiel #25
0
        public void DapperQuery_Usage()
        {
            var tree = ExcessMock.Compile(@"
                function SomeFunction(int SomeInt, int SomeId)
                {
                    IEnumerable<SomeModel> result = sql
                    {
                        select * from SomeTable
                        where SomeColumn > @SomeInt
                    }

                    SomeModel anotherResult = sql
                    {
                        select * from SomeTable
                        where IdColumn > @SomeId
                    }
                }",
                                          builder: compiler =>
            {
                Functions.Apply(compiler);
                DapperExtension.Apply(compiler);
            });

            //must have a call to __connection1.Query
            var invocation = (tree.GetRoot()
                              .DescendantNodes()
                              .OfType <MethodDeclarationSyntax>()
                              .Single()
                              .Body
                              .Statements
                              .Skip(2) //connection declarations
                              .First() as LocalDeclarationStatementSyntax)
                             .Declaration
                             .Variables
                             .Single()
                             .Initializer
                             .Value as InvocationExpressionSyntax;

            Assert.IsNotNull(invocation);
            Assert.IsTrue(invocation is InvocationExpressionSyntax);
            Assert.IsTrue((invocation as InvocationExpressionSyntax)
                          .Expression
                          .ToString()
                          .StartsWith("__connection1.Query"));

            //must have added a literal string @"...query..."
            var literal = tree.GetRoot()
                          .DescendantNodes()
                          .OfType <LiteralExpressionSyntax>()
                          .First()
                          .ToString();

            Assert.IsTrue(literal.Contains("@\""));
            Assert.IsTrue(literal.Contains("where SomeColumn > @SomeInt"));

            //must have added parameters as an anonymous object
            var parameters = tree.GetRoot()
                             .DescendantNodes()
                             .OfType <AnonymousObjectCreationExpressionSyntax>()
                             .First();

            Assert.IsTrue(parameters
                          .Initializers
                          .Any(init => init
                               .NameEquals
                               .Name
                               .ToString() == "SomeInt"));

            //must have added a second call
            invocation = (tree.GetRoot()
                          .DescendantNodes()
                          .OfType <MethodDeclarationSyntax>()
                          .Single()
                          .Body
                          .Statements
                          .Last() as LocalDeclarationStatementSyntax)
                         .Declaration
                         .Variables
                         .Single()
                         .Initializer
                         .Value as InvocationExpressionSyntax;

            //containing a Single() call
            Assert.AreEqual(1, invocation
                            .DescendantTokens()
                            .Count(token => token.ToString() == "Single"));
        }