Edit

kc3-lang/angle/src/tests/preprocessor_tests/define_test.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2019-02-01 14:16:32
    Hash : c09ae15c
    Message : Enable -Wextra-semi and -Wextra-semi-stmt. This will prevent users from accidentally making semicolon errors in the future. Bug: chromium:926235 Change-Id: I79a6fa376fb1ad8f0fcf1b65b1f572a035d1f4e9 Reviewed-on: https://chromium-review.googlesource.com/c/1446493 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Nico Weber <thakis@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>

  • src/tests/preprocessor_tests/define_test.cpp
  • //
    // Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    #include <sstream>
    
    #include "PreprocessorTest.h"
    #include "compiler/preprocessor/Token.h"
    
    namespace angle
    {
    
    using testing::_;
    
    class DefineTest : public SimplePreprocessorTest
    {};
    
    TEST_F(DefineTest, NonIdentifier)
    {
        const char *input =
            "#define 2 foo\n"
            "2\n";
        const char *expected =
            "\n"
            "2\n";
    
        EXPECT_CALL(mDiagnostics,
                    print(pp::Diagnostics::PP_UNEXPECTED_TOKEN, pp::SourceLocation(0, 1), "2"));
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, RedefinePredefined)
    {
        const char *input =
            "#define __LINE__ 10\n"
            "__LINE__\n"
            "#define __FILE__ 20\n"
            "__FILE__\n"
            "#define __VERSION__ 200\n"
            "__VERSION__\n"
            "#define GL_ES 0\n"
            "GL_ES\n";
        const char *expected =
            "\n"
            "2\n"
            "\n"
            "0\n"
            "\n"
            "100\n"
            "\n"
            "1\n";
    
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
                                        pp::SourceLocation(0, 1), "__LINE__"));
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
                                        pp::SourceLocation(0, 3), "__FILE__"));
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
                                        pp::SourceLocation(0, 5), "__VERSION__"));
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
                                        pp::SourceLocation(0, 7), "GL_ES"));
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ReservedUnderScore1)
    {
        const char *input =
            "#define __foo bar\n"
            "__foo\n";
        const char *expected =
            "\n"
            "bar\n";
    
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_WARNING_MACRO_NAME_RESERVED,
                                        pp::SourceLocation(0, 1), "__foo"));
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ReservedUnderScore2)
    {
        const char *input =
            "#define foo__bar baz\n"
            "foo__bar\n";
        const char *expected =
            "\n"
            "baz\n";
    
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_WARNING_MACRO_NAME_RESERVED,
                                        pp::SourceLocation(0, 1), "foo__bar"));
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ReservedGL)
    {
        const char *input =
            "#define GL_foo bar\n"
            "GL_foo\n";
        const char *expected =
            "\n"
            "GL_foo\n";
    
        EXPECT_CALL(mDiagnostics,
                    print(pp::Diagnostics::PP_MACRO_NAME_RESERVED, pp::SourceLocation(0, 1), "GL_foo"));
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjRedefineValid)
    {
        const char *input =
            "#define foo (1-1)\n"
            "#define foo /* whitespace */ (1-1) /* other */ \n"
            "foo\n";
        const char *expected =
            "\n"
            "\n"
            "(1-1)\n";
        // No error or warning.
        using testing::_;
        EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjRedefineInvalid)
    {
        const char *input =
            "#define foo (0)\n"
            "#define foo (1-1)\n"
            "foo\n";
        const char *expected =
            "\n"
            "\n"
            "(0)\n";
    
        EXPECT_CALL(mDiagnostics,
                    print(pp::Diagnostics::PP_MACRO_REDEFINED, pp::SourceLocation(0, 2), "foo"));
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncRedefineValid)
    {
        const char *input =
            "#define foo(a) ( a )\n"
            "#define foo( a )( /* whitespace */ a /* other */ )\n"
            "foo(b)\n";
        const char *expected =
            "\n"
            "\n"
            "( b )\n";
        // No error or warning.
        using testing::_;
        EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncRedefineInvalid)
    {
        const char *input =
            "#define foo(b) ( a )\n"
            "#define foo(b) ( b )\n"
            "foo(1)\n";
        const char *expected =
            "\n"
            "\n"
            "( a )\n";
    
        EXPECT_CALL(mDiagnostics,
                    print(pp::Diagnostics::PP_MACRO_REDEFINED, pp::SourceLocation(0, 2), "foo"));
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjBasic)
    {
        const char *input =
            "#define foo 1\n"
            "foo\n";
        const char *expected =
            "\n"
            "1\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjEmpty)
    {
        const char *input =
            "#define foo\n"
            "foo\n";
        const char *expected =
            "\n"
            "\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjChain)
    {
        const char *input =
            "#define foo 1\n"
            "#define bar foo\n"
            "bar\n";
        const char *expected =
            "\n"
            "\n"
            "1\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjChainReverse)
    {
        const char *input =
            "#define bar foo\n"
            "#define foo 1\n"
            "bar\n";
        const char *expected =
            "\n"
            "\n"
            "1\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjRecursive)
    {
        const char *input =
            "#define foo bar\n"
            "#define bar baz\n"
            "#define baz foo\n"
            "foo\n"
            "bar\n"
            "baz\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "foo\n"
            "bar\n"
            "baz\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjCompositeChain)
    {
        const char *input =
            "#define foo 1\n"
            "#define bar a foo\n"
            "bar\n";
        const char *expected =
            "\n"
            "\n"
            "a 1\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjCompositeChainReverse)
    {
        const char *input =
            "#define bar a foo\n"
            "#define foo 1\n"
            "bar\n";
        const char *expected =
            "\n"
            "\n"
            "a 1\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjCompositeRecursive)
    {
        const char *input =
            "#define foo a bar\n"
            "#define bar b baz\n"
            "#define baz c foo\n"
            "foo\n"
            "bar\n"
            "baz\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "a b c foo\n"
            "b c a bar\n"
            "c a b baz\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjChainSelfRecursive)
    {
        const char *input =
            "#define foo foo\n"
            "#define bar foo\n"
            "bar\n";
        const char *expected =
            "\n"
            "\n"
            "foo\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjectLikeWithParens)
    {
        const char *input =
            "#define foo ()1\n"
            "foo()\n"
            "#define bar ()2\n"
            "bar()\n";
        const char *expected =
            "\n"
            "()1()\n"
            "\n"
            "()2()\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncEmpty)
    {
        const char *input =
            "#define foo()\n"
            "foo()\n";
        const char *expected =
            "\n"
            "\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncNoArgs)
    {
        const char *input =
            "#define foo() bar\n"
            "foo()\n";
        const char *expected =
            "\n"
            "bar\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncOneArgUnused)
    {
        const char *input =
            "#define foo(x) 1\n"
            "foo(bar)\n";
        const char *expected =
            "\n"
            "1\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncTwoArgsUnused)
    {
        const char *input =
            "#define foo(x,y) 1\n"
            "foo(bar,baz)\n";
        const char *expected =
            "\n"
            "1\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncOneArg)
    {
        const char *input =
            "#define foo(x) ((x)+1)\n"
            "foo(bar)\n";
        const char *expected =
            "\n"
            "((bar)+1)\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncTwoArgs)
    {
        const char *input =
            "#define foo(x,y) ((x)*(y))\n"
            "foo(bar,baz)\n";
        const char *expected =
            "\n"
            "((bar)*(baz))\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncEmptyArgs)
    {
        const char *input =
            "#define zero() pass\n"
            "#define one(x) pass\n"
            "#define two(x,y) pass\n"
            "zero()\n"
            "one()\n"
            "two(,)\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "pass\n"
            "pass\n"
            "pass\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncMacroAsParam)
    {
        const char *input =
            "#define x 0\n"
            "#define foo(x) x\n"
            "foo(1)\n";
        const char *expected =
            "\n"
            "\n"
            "1\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncOneArgMulti)
    {
        const char *input =
            "#define foo(x) (x)\n"
            "foo(this is a multi-word argument)\n";
        const char *expected =
            "\n"
            "(this is a multi-word argument)\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncTwoArgsMulti)
    {
        const char *input =
            "#define foo(x,y) x,two fish,red fish,y\n"
            "foo(one fish, blue fish)\n";
        const char *expected =
            "\n"
            "one fish,two fish,red fish,blue fish\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncCompose)
    {
        const char *input =
            "#define bar(x) (1+(x))\n"
            "#define foo(y) (2*(y))\n"
            "foo(bar(3))\n";
        const char *expected =
            "\n"
            "\n"
            "(2*((1+(3))))\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncArgWithParens)
    {
        const char *input =
            "#define foo(x) (x)\n"
            "foo(argument(with parens) FTW)\n";
        const char *expected =
            "\n"
            "(argument(with parens) FTW)\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncMacroAsNonMacro)
    {
        const char *input =
            "#define foo(bar) bar\n"
            "foo bar\n";
        const char *expected =
            "\n"
            "foo bar\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncExtraNewlines)
    {
        const char *input =
            "#define foo(a) (a)\n"
            "foo\n"
            "(\n"
            "1\n"
            ")\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "\n"
            "(1)\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ChainObjToFunc)
    {
        const char *input =
            "#define foo() pass\n"
            "#define bar foo()\n"
            "bar\n";
        const char *expected =
            "\n"
            "\n"
            "pass\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ChainObjToNonFunc)
    {
        const char *input =
            "#define pass() fail\n"
            "#define bar pass\n"
            "bar\n";
        const char *expected =
            "\n"
            "\n"
            "pass\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ChainObjToFuncWithArgs)
    {
        const char *input =
            "#define foo(fail) fail\n"
            "#define bar foo(pass)\n"
            "bar\n";
        const char *expected =
            "\n"
            "\n"
            "pass\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ChainObjToFuncCompose)
    {
        const char *input =
            "#define baz(fail) fail\n"
            "#define bar(fail) fail\n"
            "#define foo bar(baz(pass))\n"
            "foo\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "pass\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ChainObjToFuncParensInText1)
    {
        const char *input =
            "#define fail() pass\n"
            "#define foo fail\n"
            "foo()\n";
        const char *expected =
            "\n"
            "\n"
            "pass\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ChainObjToFuncParensInText2)
    {
        const char *input =
            "#define bar with,embedded,commas\n"
            "#define func(x) pass\n"
            "#define foo func\n"
            "foo(bar)\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "pass\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ChainObjToFuncMultiLevel)
    {
        const char *input =
            "#define foo(x) pass\n"
            "#define bar foo\n"
            "#define baz bar\n"
            "#define joe baz\n"
            "joe (fail)\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "\n"
            "pass\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ObjToFuncRecursive)
    {
        const char *input =
            "#define A(a,b) B(a,b)\n"
            "#define C A(0,C)\n"
            "C\n";
        const char *expected =
            "\n"
            "\n"
            "B(0,C)\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, ChainFuncToFuncCompose)
    {
        const char *input =
            "#define baz(fail) fail\n"
            "#define bar(fail) fail\n"
            "#define foo() bar(baz(pass))\n"
            "foo()\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "pass\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncSelfRecursive)
    {
        const char *input =
            "#define foo(a) foo(2*(a))\n"
            "foo(3)\n";
        const char *expected =
            "\n"
            "foo(2*(3))\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncSelfCompose)
    {
        const char *input =
            "#define foo(a) foo(2*(a))\n"
            "foo(foo(3))\n";
        const char *expected =
            "\n"
            "foo(2*(foo(2*(3))))\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncSelfComposeNonFunc)
    {
        const char *input =
            "#define foo(bar) bar\n"
            "foo(foo)\n";
        const char *expected =
            "\n"
            "foo\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncSelfComposeNonFuncMultiTokenArg)
    {
        const char *input =
            "#define foo(bar) bar\n"
            "foo(1+foo)\n";
        const char *expected =
            "\n"
            "1+foo\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FinalizeUnexpandedMacro)
    {
        const char *input =
            "#define expand(x) expand(x once)\n"
            "#define foo(x) x\n"
            "foo(expand(just))\n";
        const char *expected =
            "\n"
            "\n"
            "expand(just once)\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncArgWithCommas)
    {
        const char *input =
            "#define foo(x) pass\n"
            "foo(argument (with,embedded, commas) -- baz)\n";
        const char *expected =
            "\n"
            "pass\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncArgObjMaroWithComma)
    {
        const char *input =
            "#define foo(a) (a)\n"
            "#define bar two,words\n"
            "foo(bar)\n";
        const char *expected =
            "\n"
            "\n"
            "(two,words)\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncLeftParenInMacroRightParenInText)
    {
        const char *input =
            "#define bar(a) a*2\n"
            "#define foo bar(\n"
            "foo b)\n";
        const char *expected =
            "\n"
            "\n"
            "b*2\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, RepeatedArg)
    {
        const char *input =
            "#define double(x) x x\n"
            "double(1)\n";
        const char *expected =
            "\n"
            "1 1\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncMissingRightParen)
    {
        const char *input =
            "#define foo(x) (2*(x))\n"
            "foo(3\n";
        const char *expected =
            "\n"
            "\n";
    
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_UNTERMINATED_INVOCATION,
                                        pp::SourceLocation(0, 2), "foo"));
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, FuncIncorrectArgCount)
    {
        const char *input =
            "#define foo(x,y) ((x)+(y))\n"
            "foo()\n"
            "foo(1)\n"
            "foo(1,2,3)\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "\n";
    
        EXPECT_CALL(mDiagnostics,
                    print(pp::Diagnostics::PP_MACRO_TOO_FEW_ARGS, pp::SourceLocation(0, 2), "foo"));
        EXPECT_CALL(mDiagnostics,
                    print(pp::Diagnostics::PP_MACRO_TOO_FEW_ARGS, pp::SourceLocation(0, 3), "foo"));
        EXPECT_CALL(mDiagnostics,
                    print(pp::Diagnostics::PP_MACRO_TOO_MANY_ARGS, pp::SourceLocation(0, 4), "foo"));
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, Undef)
    {
        const char *input =
            "#define foo 1\n"
            "foo\n"
            "#undef foo\n"
            "foo\n";
        const char *expected =
            "\n"
            "1\n"
            "\n"
            "foo\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, UndefPredefined)
    {
        const char *input =
            "#undef __LINE__\n"
            "__LINE__\n"
            "#undef __FILE__\n"
            "__FILE__\n"
            "#undef __VERSION__\n"
            "__VERSION__\n"
            "#undef GL_ES\n"
            "GL_ES\n";
        const char *expected =
            "\n"
            "2\n"
            "\n"
            "0\n"
            "\n"
            "100\n"
            "\n"
            "1\n";
    
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
                                        pp::SourceLocation(0, 1), "__LINE__"));
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
                                        pp::SourceLocation(0, 3), "__FILE__"));
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
                                        pp::SourceLocation(0, 5), "__VERSION__"));
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
                                        pp::SourceLocation(0, 7), "GL_ES"));
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, UndefRedefine)
    {
        const char *input =
            "#define foo 1\n"
            "foo\n"
            "#undef foo\n"
            "foo\n"
            "#define foo 2\n"
            "foo\n";
        const char *expected =
            "\n"
            "1\n"
            "\n"
            "foo\n"
            "\n"
            "2\n";
    
        preprocess(input, expected);
    }
    
    // Example from C99 standard section 6.10.3.5 Scope of macro definitions
    TEST_F(DefineTest, C99Example)
    {
        const char *input =
            "#define x    3          \n"
            "#define f(a) f(x * (a)) \n"
            "#undef  x               \n"
            "#define x    2          \n"
            "#define g    f          \n"
            "#define z    z[0]       \n"
            "#define h    g(~        \n"
            "#define m(a) a(w)       \n"
            "#define w    0,1        \n"
            "#define t(a) a          \n"
            "#define p()  int        \n"
            "#define q(x) x          \n"
            "                        \n"
            "f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);\n"
            "g(x+(3,4)-w) | h 5) & m\n"
            "    (f)^m(m);\n"
            "p() i[q()] = { q(1), 23, 4, 5, };\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "\n"
            "\n"
            "\n"
            "\n"
            "\n"
            "\n"
            "\n"
            "\n"
            "\n"
            "\n"
            "f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);\n"
            "f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) &\n"
            " f(2 * (0,1))^m(0,1);\n"
            "int i[] = { 1, 23, 4, 5, };\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, Predefined_GL_ES)
    {
        const char *input    = "GL_ES\n";
        const char *expected = "1\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, Predefined_VERSION)
    {
        const char *input    = "__VERSION__\n";
        const char *expected = "100\n";
    
        preprocess(input, expected);
    }
    
    TEST_F(DefineTest, Predefined_LINE1)
    {
        const char *str = "\n\n__LINE__";
    
        pp::Token token;
        lexSingleToken(str, &token);
        EXPECT_EQ(pp::Token::CONST_INT, token.type);
        EXPECT_EQ("3", token.text);
    }
    
    TEST_F(DefineTest, Predefined_LINE2)
    {
        const char *str =
            "#line 10\n"
            "__LINE__\n";
    
        pp::Token token;
        lexSingleToken(str, &token);
        EXPECT_EQ(pp::Token::CONST_INT, token.type);
        EXPECT_EQ("10", token.text);
    }
    
    TEST_F(DefineTest, Predefined_FILE1)
    {
        const char *const str[] = {"", "", "__FILE__"};
    
        pp::Token token;
        lexSingleToken(3, str, &token);
        EXPECT_EQ(pp::Token::CONST_INT, token.type);
        EXPECT_EQ("2", token.text);
    }
    
    TEST_F(DefineTest, Predefined_FILE2)
    {
        const char *const str[] = {"#line 10 20\n", "__FILE__"};
    
        pp::Token token;
        lexSingleToken(2, str, &token);
        EXPECT_EQ(pp::Token::CONST_INT, token.type);
        EXPECT_EQ("21", token.text);
    }
    
    // Defined operator produced by macro expansion should be parsed inside #if directives
    TEST_F(DefineTest, ExpandedDefinedParsedInsideIf)
    {
        const char *input =
            "#define bar 1\n"
            "#define foo defined(bar)\n"
            "#if foo\n"
            "bar\n"
            "#endif\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "1\n"
            "\n";
        preprocess(input, expected);
    }
    
    // Defined operator produced by macro expansion should not be parsed outside #if directives
    TEST_F(DefineTest, ExpandedDefinedNotParsedOutsideIf)
    {
        const char *input =
            "#define foo defined(bar)\n"
            "foo\n";
        const char *expected =
            "\n"
            "defined(bar)\n";
        preprocess(input, expected);
    }
    
    // Test that line directive expressions give errors on negative or undefined shifts.
    TEST_F(DefineTest, NegativeShiftInLineDirective)
    {
        const char *input =
            "#line 1 << -1\n"
            "#line 1 >> -1\n"
            "#line 1 << x\n"
            "#line 1 >> x\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "\n";
    
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_UNDEFINED_SHIFT, _, _)).Times(4);
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_INVALID_LINE_NUMBER, _, _)).Times(2);
        preprocess(input, expected);
    }
    
    // Undefining a macro in its invocation parameters produces and error
    TEST_F(DefineTest, UndefineInInvocation)
    {
        const char *input =
            "#define G(a, b) a b\n"
            "G(\n"
            "#undef G\n"
            "1, 2)\n";
        const char *expected = "\n\n\n1 2\n";
    
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED,
                                        pp::SourceLocation(0, 3), _));
    
        preprocess(input, expected);
    }
    
    // Undefining a macro before its invocation parameters produces and error
    TEST_F(DefineTest, UndefineInInvocationPreLParen)
    {
        const char *input =
            "#define G(a, b) a b\n"
            "G\n"
            "#undef G\n"
            "(1, 2)\n";
        const char *expected = "\n\n\n1 2\n";
    
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED,
                                        pp::SourceLocation(0, 3), _));
    
        preprocess(input, expected);
    }
    
    // The name of the macro "a" is inside an incomplete macro invocation of macro "m()" in its own
    // expansion. This should not result in infinite recursion.
    TEST_F(DefineTest, RecursiveMacroNameInsideIncompleteMacroInvocationInMacroExpansion)
    {
        const char *input =
            "#define m(a)\n"
            "#define a m((a)\n"
            "a)\n";
        const char *expected =
            "\n"
            "\n"
            "\n";
        preprocess(input, expected);
    }
    
    // The name of the macro "a" is inside an incomplete macro invocation of macro "m()" in its own
    // expansion. Then the macro "a" is undef'd. This is a regression test for a memory management bug
    // where macro "a" would be freed on undef even though cleaning up the recursive macro invocation
    // would still need to refer to macro "a".
    TEST_F(DefineTest, UndefInsideRecursiveMacroInvocation)
    {
        const char *input =
            "#define m(a)\n"
            "#define a m((a)\n"
            "a\n"
            "#undef a\n"
            ")\n";
        const char *expected =
            "\n"
            "\n"
            "\n"
            "\n"
            "\n";
        preprocess(input, expected);
    }
    
    // The macro invocations form a long chain. The macro expander should protect against stack overflow
    // and generate an error in this case.
    TEST_F(DefineTest, LongMacroInvocationChain)
    {
        std::stringstream inputStream;
        std::stringstream expectedStream;
    
        inputStream << "#define b(x) x\n";
        inputStream << "#define a0(x) foo x\n";
        for (int i = 1; i < 20; ++i)
        {
            inputStream << "#define a" << i << "(x) b(a" << (i - 1) << "(x))\n";
        }
        inputStream << "a19(y)\n";
    
        EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_MACRO_INVOCATION_CHAIN_TOO_DEEP,
                                        pp::SourceLocation(0, 22), _));
    
        pp::PreprocessorSettings settings(SH_GLES2_SPEC);
        settings.maxMacroExpansionDepth = 19;
    
        preprocess(inputStream.str().c_str(), settings);
    }
    
    }  // namespace angle