//===- unittests/Lex/DependencyDirectivesSourceMinimizer.cpp - -----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "clang/Lex/DependencyDirectivesSourceMinimizer.h" #include "llvm/ADT/SmallString.h" #include "gtest/gtest.h" using namespace llvm; using namespace clang; using namespace clang::minimize_source_to_dependency_directives; namespace clang { bool minimizeSourceToDependencyDirectives(StringRef Input, SmallVectorImpl &Out) { SmallVector Tokens; return minimizeSourceToDependencyDirectives(Input, Out, Tokens); } } // end namespace clang namespace { TEST(MinimizeSourceToDependencyDirectivesTest, Empty) { SmallVector Out; SmallVector Tokens; ASSERT_FALSE(minimizeSourceToDependencyDirectives("", Out, Tokens)); EXPECT_TRUE(Out.empty()); ASSERT_EQ(1u, Tokens.size()); ASSERT_EQ(pp_eof, Tokens.back().K); ASSERT_FALSE( minimizeSourceToDependencyDirectives("abc def\nxyz", Out, Tokens)); EXPECT_TRUE(Out.empty()); ASSERT_EQ(1u, Tokens.size()); ASSERT_EQ(pp_eof, Tokens.back().K); } TEST(MinimizeSourceToDependencyDirectivesTest, AllTokens) { SmallVector Out; SmallVector Tokens; ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define A\n" "#undef A\n" "#endif\n" "#if A\n" "#ifdef A\n" "#ifndef A\n" "#elif A\n" "#else\n" "#include \n" "#include_next \n" "#__include_macros \n" "#import \n" "@import A;\n" "#pragma clang module import A\n" "export module m;\n" "import m;\n", Out, Tokens)); EXPECT_EQ(pp_define, Tokens[0].K); EXPECT_EQ(pp_undef, Tokens[1].K); EXPECT_EQ(pp_endif, Tokens[2].K); EXPECT_EQ(pp_if, Tokens[3].K); EXPECT_EQ(pp_ifdef, Tokens[4].K); EXPECT_EQ(pp_ifndef, Tokens[5].K); EXPECT_EQ(pp_elif, Tokens[6].K); EXPECT_EQ(pp_else, Tokens[7].K); EXPECT_EQ(pp_include, Tokens[8].K); EXPECT_EQ(pp_include_next, Tokens[9].K); EXPECT_EQ(pp___include_macros, Tokens[10].K); EXPECT_EQ(pp_import, Tokens[11].K); EXPECT_EQ(decl_at_import, Tokens[12].K); EXPECT_EQ(pp_pragma_import, Tokens[13].K); EXPECT_EQ(cxx_export_decl, Tokens[14].K); EXPECT_EQ(cxx_module_decl, Tokens[15].K); EXPECT_EQ(cxx_import_decl, Tokens[16].K); EXPECT_EQ(pp_eof, Tokens[17].K); } TEST(MinimizeSourceToDependencyDirectivesTest, Define) { SmallVector Out; SmallVector Tokens; ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO", Out, Tokens)); EXPECT_STREQ("#define MACRO\n", Out.data()); ASSERT_EQ(2u, Tokens.size()); ASSERT_EQ(pp_define, Tokens.front().K); } TEST(MinimizeSourceToDependencyDirectivesTest, DefineSpacing) { SmallVector Out; ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO\n\n\n", Out)); EXPECT_STREQ("#define MACRO\n", Out.data()); ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO \n\n\n", Out)); EXPECT_STREQ("#define MACRO\n", Out.data()); ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO a \n\n\n", Out)); EXPECT_STREQ("#define MACRO a\n", Out.data()); ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO\n\n\n", Out)); EXPECT_STREQ("#define MACRO\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, DefineMacroArguments) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define MACRO()", Out)); EXPECT_STREQ("#define MACRO()\n", Out.data()); ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO(a, b...)", Out)); EXPECT_STREQ("#define MACRO(a,b...)\n", Out.data()); ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO content", Out)); EXPECT_STREQ("#define MACRO content\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives( "#define MACRO con tent ", Out)); EXPECT_STREQ("#define MACRO con tent\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives( "#define MACRO() con tent ", Out)); EXPECT_STREQ("#define MACRO() con tent\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, DefineInvalidMacroArguments) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define MACRO((a))", Out)); EXPECT_STREQ("#define MACRO(/* invalid */\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define MACRO(", Out)); EXPECT_STREQ("#define MACRO(/* invalid */\n", Out.data()); ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO(a * b)", Out)); EXPECT_STREQ("#define MACRO(/* invalid */\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, DefineHorizontalWhitespace) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives( "#define MACRO(\t)\tcon \t tent\t", Out)); EXPECT_STREQ("#define MACRO() con \t tent\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives( "#define MACRO(\f)\fcon \f tent\f", Out)); EXPECT_STREQ("#define MACRO() con \f tent\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives( "#define MACRO(\v)\vcon \v tent\v", Out)); EXPECT_STREQ("#define MACRO() con \v tent\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives( "#define MACRO \t\v\f\v\t con\f\t\vtent\v\f \v", Out)); EXPECT_STREQ("#define MACRO con\f\t\vtent\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, DefineMultilineArgs) { SmallVector Out; ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO(a \\\n" " )", Out)); EXPECT_STREQ("#define MACRO(a)\n", Out.data()); ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO(a, \\\n" " b) \\\n" " call((a), \\\n" " (b))", Out)); EXPECT_STREQ("#define MACRO(a,b) call((a), (b))\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, DefineMultilineArgsCarriageReturn) { SmallVector Out; ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO(a, \\\r" " b) \\\r" " call((a), \\\r" " (b))", Out)); EXPECT_STREQ("#define MACRO(a,b) call((a), (b))\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, DefineMultilineArgsStringize) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define MACRO(a,b) \\\n" " #a \\\n" " #b", Out)); EXPECT_STREQ("#define MACRO(a,b) #a #b\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, DefineMultilineArgsCarriageReturnNewline) { SmallVector Out; ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO(a, \\\r\n" " b) \\\r\n" " call((a), \\\r\n" " (b))", Out)); EXPECT_STREQ("#define MACRO(a,b) call((a), (b))\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, DefineMultilineArgsNewlineCarriageReturn) { SmallVector Out; ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO(a, \\\n\r" " b) \\\n\r" " call((a), \\\n\r" " (b))", Out)); EXPECT_STREQ("#define MACRO(a,b) call((a), (b))\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, DefineNumber) { SmallVector Out; ASSERT_TRUE(minimizeSourceToDependencyDirectives("#define 0\n", Out)); } TEST(MinimizeSourceToDependencyDirectivesTest, DefineNoName) { SmallVector Out; ASSERT_TRUE(minimizeSourceToDependencyDirectives("#define &\n", Out)); } TEST(MinimizeSourceToDependencyDirectivesTest, DefineNoWhitespace) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define AND&\n", Out)); EXPECT_STREQ("#define AND &\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define AND\\\n" "&\n", Out)); EXPECT_STREQ("#define AND &\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, MultilineComment) { SmallVector Out; ASSERT_FALSE( minimizeSourceToDependencyDirectives("#define MACRO a/*\n" " /*\n" "#define MISSING abc\n" " /*\n" " /* something */ \n" "#include /* \"def\" */ \n", Out)); EXPECT_STREQ("#define MACRO a\n" "#include \n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, MultilineCommentInStrings) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define MACRO1 \"/*\"\n" "#define MACRO2 \"*/\"\n", Out)); EXPECT_STREQ("#define MACRO1 \"/*\"\n" "#define MACRO2 \"*/\"\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, Ifdef) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("#ifdef A\n" "#define B\n" "#endif\n", Out)); EXPECT_STREQ("#ifdef A\n" "#define B\n" "#endif\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("#ifdef A\n" "#define B\n" "#elif B\n" "#define C\n" "#elif C\n" "#define D\n" "#else\n" "#define E\n" "#endif\n", Out)); EXPECT_STREQ("#ifdef A\n" "#define B\n" "#elif B\n" "#define C\n" "#elif C\n" "#define D\n" "#else\n" "#define E\n" "#endif\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, EmptyIfdef) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("#ifdef A\n" "#elif B\n" "#elif C\n" "#else D\n" "#endif\n", Out)); EXPECT_STREQ("", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, Pragma) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("#pragma A\n", Out)); EXPECT_STREQ("", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("#pragma clang\n", Out)); EXPECT_STREQ("", Out.data()); ASSERT_FALSE( minimizeSourceToDependencyDirectives("#pragma clang module\n", Out)); EXPECT_STREQ("", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives( "#pragma clang module impor\n", Out)); EXPECT_STREQ("", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives( "#pragma clang module import\n", Out)); EXPECT_STREQ("#pragma clang module import\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, Include) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("#include \"A\"\n", Out)); EXPECT_STREQ("#include \"A\"\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("#include \n", Out)); EXPECT_STREQ("#include \n", Out.data()); ASSERT_FALSE( minimizeSourceToDependencyDirectives("#include_next \n", Out)); EXPECT_STREQ("#include_next \n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("#import \n", Out)); EXPECT_STREQ("#import \n", Out.data()); ASSERT_FALSE( minimizeSourceToDependencyDirectives("#__include_macros \n", Out)); EXPECT_STREQ("#__include_macros \n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, AtImport) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import A;\n", Out)); EXPECT_STREQ("@import A;\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives(" @ import A;\n", Out)); EXPECT_STREQ("@import A;\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import A\n;", Out)); EXPECT_STREQ("@import A;\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import A.B;\n", Out)); EXPECT_STREQ("@import A.B;\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives( "@import /*x*/ A /*x*/ . /*x*/ B /*x*/ \n /*x*/ ; /*x*/", Out)); EXPECT_STREQ("@import A.B;\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, AtImportFailures) { SmallVector Out; ASSERT_TRUE(minimizeSourceToDependencyDirectives("@import A\n", Out)); ASSERT_TRUE(minimizeSourceToDependencyDirectives("@import MACRO(A);\n", Out)); ASSERT_TRUE(minimizeSourceToDependencyDirectives("@import \" \";\n", Out)); } TEST(MinimizeSourceToDependencyDirectivesTest, RawStringLiteral) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("#ifndef GUARD\n" "#define GUARD\n" "R\"()\"\n" "#endif\n", Out)); EXPECT_STREQ("#ifndef GUARD\n" "#define GUARD\n" "#endif\n", Out.data()); bool RawStringLiteralResult = minimizeSourceToDependencyDirectives( "#ifndef GUARD\n" "#define GUARD\n" R"raw(static constexpr char bytes[] = R"(-?:\,[]{}#&*!|>'"%@`)";)raw" "\n" "#endif\n", Out); ASSERT_FALSE(RawStringLiteralResult); EXPECT_STREQ("#ifndef GUARD\n" "#define GUARD\n" "#endif\n", Out.data()); bool RawStringLiteralResult2 = minimizeSourceToDependencyDirectives( "#ifndef GUARD\n" "#define GUARD\n" R"raw(static constexpr char bytes[] = R"abc(-?:\,[]{}#&*!|>'"%@`)abc";)raw" "\n" "#endif\n", Out); ASSERT_FALSE(RawStringLiteralResult2); EXPECT_STREQ("#ifndef GUARD\n" "#define GUARD\n" "#endif\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, SplitIdentifier) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("#if\\\n" "ndef GUARD\n" "#define GUARD\n" "#endif\n", Out)); EXPECT_STREQ("#ifndef GUARD\n" "#define GUARD\n" "#endif\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define GUA\\\n" "RD\n", Out)); EXPECT_STREQ("#define GUARD\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define GUA\\\r" "RD\n", Out)); EXPECT_STREQ("#define GUARD\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define GUA\\\n" " RD\n", Out)); EXPECT_STREQ("#define GUA RD\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, WhitespaceAfterLineContinuationSlash) { SmallVector Out; ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define A 1 + \\ \n" "2 + \\\t\n" "3\n", Out)); EXPECT_STREQ("#define A 1 + 2 + 3\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, PoundWarningAndError) { SmallVector Out; for (auto Source : { "#warning '\n#include \n", "#warning \"\n#include \n", "#warning /*\n#include \n", "#warning \\\n#include \n#include \n", "#error '\n#include \n", "#error \"\n#include \n", "#error /*\n#include \n", "#error \\\n#include \n#include \n", }) { ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); EXPECT_STREQ("#include \n", Out.data()); } for (auto Source : { "#warning \\\n#include \n", "#error \\\n#include \n", "#if MACRO\n#warning '\n#endif\n", "#if MACRO\n#warning \"\n#endif\n", "#if MACRO\n#warning /*\n#endif\n", "#if MACRO\n#error '\n#endif\n", "#if MACRO\n#error \"\n#endif\n", "#if MACRO\n#error /*\n#endif\n", }) { ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); EXPECT_STREQ("", Out.data()); } } TEST(MinimizeSourceToDependencyDirectivesTest, CharacterLiteral) { SmallVector Out; StringRef Source = R"( #include int a = 0'1; int b = 0xfa'af'fa; int c = 12 ' '; #include )"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); EXPECT_STREQ("#include \n#include \n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, CharacterLiteralPrefixL) { SmallVector Out; StringRef Source = R"(L'P' #if DEBUG // ' #endif #include )"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); EXPECT_STREQ("#include \n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, CharacterLiteralPrefixU) { SmallVector Out; StringRef Source = R"(int x = U'P'; #include // ' )"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); EXPECT_STREQ("#include \n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, CharacterLiteralPrefixu) { SmallVector Out; StringRef Source = R"(int x = u'b'; int y = u8'a'; int z = 128'78; #include // ' )"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); EXPECT_STREQ("#include \n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, PragmaOnce) { SmallVector Out; SmallVector Tokens; StringRef Source = R"(// comment #pragma once // another comment #include )"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out, Tokens)); EXPECT_STREQ("#pragma once\n#include \n", Out.data()); ASSERT_EQ(Tokens.size(), 3u); EXPECT_EQ(Tokens[0].K, minimize_source_to_dependency_directives::pp_pragma_once); Source = R"(// comment #pragma once extra tokens // another comment #include )"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); EXPECT_STREQ("#pragma once\n#include \n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, SkipLineStringCharLiteralsUntilNewline) { SmallVector Out; StringRef Source = R"(#if NEVER_ENABLED #define why(fmt, ...) #error don't try me #endif void foo(); )"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); EXPECT_STREQ( "#if NEVER_ENABLED\n#define why(fmt,...) #error don't try me\n#endif\n", Out.data()); Source = R"(#if NEVER_ENABLED #define why(fmt, ...) "quote dropped #endif void foo(); )"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); EXPECT_STREQ( "#if NEVER_ENABLED\n#define why(fmt,...) \"quote dropped\n#endif\n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, SupportWhitespaceBeforeLineContinuationInStringSkipping) { SmallVector Out; StringRef Source = "#define X '\\ \t\nx'\nvoid foo() {}"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); EXPECT_STREQ("#define X '\\ \t\nx'\n", Out.data()); Source = "#define X \"\\ \r\nx\"\nvoid foo() {}"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); EXPECT_STREQ("#define X \"\\ \r\nx\"\n", Out.data()); Source = "#define X \"\\ \r\nx\n#include \n"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out)); EXPECT_STREQ("#define X \"\\ \r\nx\n#include \n", Out.data()); } TEST(MinimizeSourceToDependencyDirectivesTest, CxxModules) { SmallVector Out; SmallVector Tokens; StringRef Source = R"( module; #include "textual-header.h" export module m; exp\ ort \ import \ :l [[rename]]; export void f(); void h() { import.a = 3; import = 3; import <<= 3; import->a = 3; import(); import . a(); import a b d e d e f e; import foo [[no_unique_address]]; import foo(); import f(:sefse); import f(->a = 3); } )"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out, Tokens)); EXPECT_STREQ("#include \"textual-header.h\"\nexport module m;\n" "export import :l [[rename]];\n" "import <<= 3;\nimport a b d e d e f e;\n" "import foo [[no_unique_address]];\nimport foo();\n" "import f(:sefse);\nimport f(->a = 3);\n", Out.data()); ASSERT_EQ(Tokens.size(), 12u); EXPECT_EQ(Tokens[0].K, minimize_source_to_dependency_directives::pp_include); EXPECT_EQ(Tokens[2].K, minimize_source_to_dependency_directives::cxx_module_decl); } TEST(MinimizeSourceToDependencyDirectivesTest, SkippedPPRangesBasic) { SmallString<128> Out; SmallVector Toks; StringRef Source = "#ifndef GUARD\n" "#define GUARD\n" "void foo();\n" "#endif\n"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out, Toks)); SmallVector Ranges; ASSERT_FALSE(computeSkippedRanges(Toks, Ranges)); EXPECT_EQ(Ranges.size(), 1u); EXPECT_EQ(Ranges[0].Offset, 0); EXPECT_EQ(Ranges[0].Length, (int)Out.find("#endif")); } TEST(MinimizeSourceToDependencyDirectivesTest, SkippedPPRangesNested) { SmallString<128> Out; SmallVector Toks; StringRef Source = "#ifndef GUARD\n" "#define GUARD\n" "#if FOO\n" "#include hello\n" "#elif BAR\n" "#include bye\n" "#endif\n" "#else\n" "#include nothing\n" "#endif\n"; ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out, Toks)); SmallVector Ranges; ASSERT_FALSE(computeSkippedRanges(Toks, Ranges)); EXPECT_EQ(Ranges.size(), 4u); EXPECT_EQ(Ranges[0].Offset, (int)Out.find("#if FOO")); EXPECT_EQ(Ranges[0].Offset + Ranges[0].Length, (int)Out.find("#elif")); EXPECT_EQ(Ranges[1].Offset, (int)Out.find("#elif BAR")); EXPECT_EQ(Ranges[1].Offset + Ranges[1].Length, (int)Out.find("#endif")); EXPECT_EQ(Ranges[2].Offset, 0); EXPECT_EQ(Ranges[2].Length, (int)Out.find("#else")); EXPECT_EQ(Ranges[3].Offset, (int)Out.find("#else")); EXPECT_EQ(Ranges[3].Offset + Ranges[3].Length, (int)Out.rfind("#endif")); } } // end anonymous namespace