//===--- iwyu_output_test.cc - test iwyu_output.{h,cc} --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// Tests iwyu_output.{h,cc}

#include "iwyu_output.h"

#include <stddef.h>
#include <set>

#include "iwyu_ast_util.h"
#include "iwyu_globals.h"
#include "iwyu_verrs.h"
#include "testing/base/public/gunit.h"

#undef ATTRIBUTE_UNUSED
#include "clang/Basic/SourceLocation.h"

using clang::NamedDecl;
using clang::SourceLocation;

namespace include_what_you_use {

namespace internal {
// Internal routines from iwyu_output.cc exposed for testing purposes.

string MungedForwardDeclareLine(const NamedDecl* decl);

set<string> CalculateMinimalIncludes(
    const set<string>& direct_includes,
    const set<string>& associated_direct_includes,
    vector<OneUse>* uses);

void ProcessForwardDeclare(OneUse* use);

void ProcessFullUse(OneUse* use);

void ProcessSymbolUse(OneUse* use);

void CalculateIwyuForForwardDeclareUse(OneUse* use,
                                       const set<string>& actual_includes,
                                       const set<string>& desired_includes);

void CalculateIwyuForFullUse(OneUse* use,
                             const set<string>& actual_includes,
                             const set<string>& desired_includes);

void CalculateDesiredIncludesAndForwardDeclares(
    const vector<OneUse>& uses,
    const set<string> associated_desired_includes,
    vector<OneIncludeOrForwardDeclareLine>* lines);

string PrintableIncludeOrForwardDeclareLine(
    const OneIncludeOrForwardDeclareLine& line,
    const set<string>& associated_quoted_includes);

string PrintableDiffs(const string& filename,
                      const set<string>& associated_quoted_includes,
                      const vector<OneIncludeOrForwardDeclareLine>& lines);

struct FakeSourceLocation : public SourceLocation {
  FakeSourceLocation(const string& fp, int ln)
      : SourceLocation(), filepath(fp), linenum(ln) { }
  string filepath;
  int linenum;
};

}  // namespace internal

using internal::FakeNamedDecl;   // from iwyu_output.h
using internal::FakeSourceLocation;


// Some helper routines on fakes.
// TODO(csilvers): these don't get called where we want them to. :-(
string GetFilePath(const FakeSourceLocation& fake_loc) {
  return fake_loc.filepath;
}

string GetFilePath(const FakeNamedDecl* fake_decl) {
  return fake_decl->decl_filepath();
}

// Note these return a string, not a FileEntry*.
string GetFileEntry(const FakeSourceLocation& fake_loc) {
  return fake_loc.filepath;
}

string GetFileEntry(const FakeNamedDecl* fake_decl) {
  return fake_decl->decl_filepath();
}

// DynCasting a fake always fails.
inline internal::DynCastPtr<FakeNamedDecl> DynCastFrom(FakeNamedDecl* ptr) {
  return internal::DynCastPtr<FakeNamedDecl>(NULL);
}

namespace {

// A helper for creating an IncludeLineData object.
template <int N>
OneIncludeOrForwardDeclareLine MakeDesiredIncludeLine(
    const string& quoted_includee, const char* (&used_symbols)[N]) {
  OneIncludeOrForwardDeclareLine retval(quoted_includee, 1);
  retval.set_desired();
  for (int i = 0; i < N; i++)
    retval.AddSymbolUse(used_symbols[i]);
  return retval;
}

// Common case where we only need one symbol.
OneIncludeOrForwardDeclareLine MakeDesiredIncludeLine(
    const string& quoted_includee, const char* used_symbol) {
  const char* used_symbols[1] = { used_symbol };
  return MakeDesiredIncludeLine(quoted_includee, used_symbols);
}

TEST(MungedForwardDeclareLineTest, Works) {
  // TODO(csilvers): figure out how to test on a real RecordDecl/etc.
}

TEST(CalculateMinimalIncludes, Works) {
  // TODO(csilvers): add tests here
}

TEST(ProcessForwardDeclareTest, A1) {
  // TODO(csilvers): figure out how to test with a real record_decl/tpl_decl
}

TEST(ProcessForwardDeclareTest, A2) {
  // TODO(csilvers): figure out how to test with a real class_tpl_decl
}

TEST(ProcessForwardDeclareTest, A3) {
  // TODO(csilvers): figure out how to test with a real record_decl
}

TEST(ProcessForwardDeclareTest, A4) {
  // TODO(csilvers): figure out how to test with a real record_decl
}

TEST(ProcessFullUseTest, B1) {
  return;  // TODO(csilvers): re-enable when we can fake the SourceLoc and decl
  FakeNamedDecl decl("class", "MyClass", "src/includes/myclass.h", 10);
  // Test the use being *before* the definition in the file (shouldn't matter)
  OneUse samefile_use(&decl, FakeSourceLocation("src/includes/myclass.h", 5),
                      OneUse::kFullUse, false, NULL);
  OneUse difffile_use(&decl, FakeSourceLocation("src/myclass.cc", 10),
                      OneUse::kFullUse, false, NULL);
  internal::ProcessFullUse(&samefile_use);
  internal::ProcessFullUse(&difffile_use);
  EXPECT_TRUE(samefile_use.ignore_use());
  EXPECT_FALSE(difffile_use.ignore_use());
}

TEST(ProcessFullUseTest, B2) {
  // TODO(csilvers): figure out how to test with a real fn_decl
}

TEST(ProcessFullUseTest, B3) {
  return;  // TODO(csilvers): re-enable when we can fake the SourceLoc and decl
  FakeNamedDecl cc_decl("class", "MyClass", "src/myclass.cc", 10);
  // Test the use being *before* the definition in the file (shouldn't matter)
  OneUse h_use(&cc_decl, FakeSourceLocation("src/includes/myclass.h", 5),
               OneUse::kFullUse, false, NULL);
  OneUse cc_use(&cc_decl, FakeSourceLocation("src/main.cc", 10),
                OneUse::kFullUse, false, NULL);
  internal::ProcessFullUse(&h_use);
  internal::ProcessFullUse(&cc_use);
  EXPECT_TRUE(h_use.ignore_use());
  EXPECT_FALSE(cc_use.ignore_use());
}

TEST(ProcessFullUseTest, B4) {
  // TODO(csilvers): figure out how to test with a real cxx_method_decl
}

TEST(ProcessSymbolUseTest, B5) {
  return;  // TODO(csilvers): re-enable when we can fake the SourceLoc and decl
  // Test the use being *before* the definition in the file (shouldn't matter)
  OneUse samefile_use("mysym", "src/includes/myclass.h",
                      FakeSourceLocation("src/includes/myclass.h", 5));
  OneUse difffile_use("sym2", "src/includes/myclass.h",
                      FakeSourceLocation("src/myclass.cc", 5));
  internal::ProcessSymbolUse(&samefile_use);
  internal::ProcessSymbolUse(&difffile_use);
  EXPECT_TRUE(samefile_use.ignore_use());
  EXPECT_FALSE(difffile_use.ignore_use());
}

TEST(CalculateIwyuForForwardDeclareUseTest, D1) {
  // TODO(csilvers): figure out how to test with a real record_decl
}

TEST(CalculateIwyuForForwardDeclareUseTest, D2) {
  // TODO(csilvers): figure out how to test with a real record_decl
}

TEST(CalculateIwyuForFullUse, E1) {
  OneUse iwyu_violation("mysym", "src/includes/myclass.h",
                        FakeSourceLocation("src/myclass.cc", 5));
  OneUse iwyu_ok("mysym", "src/includes/myclass.h",
                 FakeSourceLocation("src/myclass.cc", 5));
  iwyu_violation.set_suggested_header("<myclass.h>");
  iwyu_ok.set_suggested_header("\"includes/myclass.h\"");

  set<string> actual_includes;
  actual_includes.insert("\"includes/myclass.h\"");
  actual_includes.insert("<stdio.h>");
  const set<string> empty;   // desired includes: doesn't matter for this test

  internal::CalculateIwyuForFullUse(&iwyu_violation, actual_includes, empty);
  internal::CalculateIwyuForFullUse(&iwyu_ok, actual_includes, empty);
  EXPECT_TRUE(iwyu_violation.is_iwyu_violation());
  EXPECT_FALSE(iwyu_ok.is_iwyu_violation());
}

TEST(SanitizeSymbolTest, Works) {
  // TODO(csilvers): Do this when we can create non-trivial test decls.
}

TEST(CalculateDesiredIncludesAndForwardDeclaresTest, Works) {
  // TODO(csilvers): Implement.
}

// This test fixture automatically saves/restores the verbose level
// between tests to prevent leaking side effects.
class VerboseTest : public ::testing::Test {
 protected:
  VerboseTest() : old_verbose_level_(GetVerboseLevel()) {
    // 2 is the default verbose level for tests that don't care much
    // about the level.
    SetVerboseLevel(2);
  }

  ~VerboseTest() {
    SetVerboseLevel(old_verbose_level_);
  }

 private:
  const int old_verbose_level_;
};

class PrintableIncludeOrForwardDeclareLineTest : public VerboseTest { };

TEST_F(PrintableIncludeOrForwardDeclareLineTest, CutsOffAt80Columns) {
  const set<string> empty;
  OneIncludeOrForwardDeclareLine foo_line("<foo.h>", 1);
  foo_line.AddSymbolUse("FOO");
  foo_line.AddSymbolUse("FooClass");
  foo_line.AddSymbolUse("FooClass::a");
  foo_line.AddSymbolUse("FooClass::~FooClass");
  foo_line.AddSymbolUse("FunctionOnFoo");
  foo_line.AddSymbolUse("Foo_Enum");
  foo_line.AddSymbolUse("Foo_Typedef");
  foo_line.set_desired();
  EXPECT_EQ("#include <foo.h>"
            "                        // for FOO, FooClass, FooClass::a, etc\n",
            internal::PrintableIncludeOrForwardDeclareLine(foo_line, empty));

  OneIncludeOrForwardDeclareLine bar_line("<bar.h>", 2);
  bar_line.AddSymbolUse("this_symbol_is_so_big_there_is_no_room_for_it_at_all");
  bar_line.set_desired();
  EXPECT_EQ("#include <bar.h>\n",
            internal::PrintableIncludeOrForwardDeclareLine(bar_line, empty));

  OneIncludeOrForwardDeclareLine long_line(
      "\"deep/enough/to/go/past/the/indent.h\"", 3);
  long_line.AddSymbolUse("DeepFn");
  long_line.AddSymbolUse("Deep_Typedef");
  long_line.AddSymbolUse("DEEP");
  long_line.AddSymbolUse("TheInkyDeeps");
  long_line.set_desired();

  EXPECT_EQ("#include \"deep/enough/to/go/past/the/indent.h\""
            "  // for DEEP, DeepFn, etc\n",
            internal::PrintableIncludeOrForwardDeclareLine(long_line, empty));
}

TEST_F(PrintableIncludeOrForwardDeclareLineTest, SortsSymbolsByFreqThenAlpha) {
  SetVerboseLevel(3);   // so we see a printout of *all* the symbols
  const set<string> empty;
  OneIncludeOrForwardDeclareLine line("<foo.h>", 2);
  line.AddSymbolUse("FOO");
  line.AddSymbolUse("FooClass");
  line.AddSymbolUse("FooClass::a");
  line.AddSymbolUse("Foo_Enum");
  line.AddSymbolUse("FooClass::~FooClass");
  line.AddSymbolUse("FunctionOnFoo");
  line.AddSymbolUse("FooClass");
  line.AddSymbolUse("Foo_Typedef");
  line.AddSymbolUse("FooClass");
  line.AddSymbolUse("Foo_Typedef");
  line.AddSymbolUse("FunctionOnFoo");
  line.set_desired();
  EXPECT_EQ("#include <foo.h>"
            "                        // for FooClass, Foo_Typedef,"
            " FunctionOnFoo, FOO, FooClass::a, FooClass::~FooClass, Foo_Enum\n",
            internal::PrintableIncludeOrForwardDeclareLine(line, empty));
}

TEST(PrintableDiffsTest, PrintsEmptyIncludes) {
  vector<OneIncludeOrForwardDeclareLine> no_lines;
  EXPECT_EQ("\n"
            "(baz.cc has correct #includes/fwd-decls)\n",
            internal::PrintableDiffs("baz.cc", set<string>(), no_lines));
}

TEST(PrintableDiffsTest, ProperlyOrdersIncludeLines) {
  set<string> associated_includes;
  associated_includes.insert("\"baz.h\"");
  associated_includes.insert("\"baz-inl.h\"");
  vector<OneIncludeOrForwardDeclareLine> lines;
  lines.push_back(MakeDesiredIncludeLine("\"foo.h\"", "FOO"));
  lines.push_back(MakeDesiredIncludeLine("\"bar.h\"", "BAR"));
  lines.push_back(MakeDesiredIncludeLine("\"baz.h\"", "BAZ"));
  lines.push_back(MakeDesiredIncludeLine("\"foo-inl.h\"", "FooFn"));
  lines.push_back(MakeDesiredIncludeLine("\"bar-inl.h\"", "BarFn"));
  lines.push_back(MakeDesiredIncludeLine("\"baz-inl.h\"", "BazFn"));
  lines.push_back(MakeDesiredIncludeLine("<stdio.h>", "printf"));
  lines.push_back(MakeDesiredIncludeLine("<string>", "string::iterator"));
  lines.push_back(MakeDesiredIncludeLine("<sstring>", "sstring"));
  lines.push_back(MakeDesiredIncludeLine("<ctype.h>", "isascii"));
  EXPECT_EQ("\n"
            "baz.cc should add these lines:\n"
            "#include \"baz.h\"\n"
            "#include \"baz-inl.h\"\n"
            "#include <ctype.h>                      // for isascii\n"
            "#include <stdio.h>                      // for printf\n"
            "#include <sstring>                      // for sstring\n"
            "#include <string>                       // for string::iterator\n"
            "#include \"bar-inl.h\"                    // for BarFn\n"
            "#include \"bar.h\"                        // for BAR\n"
            "#include \"foo-inl.h\"                    // for FooFn\n"
            "#include \"foo.h\"                        // for FOO\n"
            "\n"
            "baz.cc should remove these lines:\n"
            "\n"
            "The full include-list for baz.cc:\n"
            "#include \"baz.h\"\n"
            "#include \"baz-inl.h\"\n"
            "#include <ctype.h>                      // for isascii\n"
            "#include <stdio.h>                      // for printf\n"
            "#include <sstring>                      // for sstring\n"
            "#include <string>                       // for string::iterator\n"
            "#include \"bar-inl.h\"                    // for BarFn\n"
            "#include \"bar.h\"                        // for BAR\n"
            "#include \"foo-inl.h\"                    // for FooFn\n"
            "#include \"foo.h\"                        // for FOO\n"
            "---\n",
            internal::PrintableDiffs("baz.cc", associated_includes, lines));
}

TEST(PrintableDiffsTest, ShowLineNumbersForDeletedIncludesEvenWithUses) {
  const set<string> empty;
  vector<OneIncludeOrForwardDeclareLine> lines;
  OneIncludeOrForwardDeclareLine line("\"foo.h\"", 1);
  line.set_present();   // *not* desired
  line.AddSymbolUse("Foo (ptr only)");
  lines.push_back(line);
  EXPECT_EQ("\n"
            "baz.cc should add these lines:\n"
            "\n"
            "baz.cc should remove these lines:\n"
            "- #include \"foo.h\"  // lines 1-1\n"
            "\n"
            "The full include-list for baz.cc:\n"
            "---\n",
            internal::PrintableDiffs("baz.cc", empty, lines));
}

#if 0

TEST_F(IwyuFileInfo_PrintableIncludeInformation, PrintsForwardDeclares) {
  IwyuFileInfo f("baz.cc");
  f.AddDesiredIncludeNeededBySymbol("\"foo.h\"", "FOO");
  f.AddDesiredIncludeNeededBySymbol("\"bar.h\"", "BAR");
  f.AddDesiredIncludeNeededBySymbol("\"baz.h\"", "BAZ");
  f.AddDesiredIncludeNeededBySymbol("<string>", "string::iterator");
  f.AddDesiredIncludeNeededBySymbol("<stdio.h>", "printf");
  FakeNamedDecl record1("struct", "Foo");
  f.AddDesiredForwardDeclare("\"record1.h\"", &record1);
  f.NormalizeDesiredSetsForCc(set<string>());
  EXPECT_EQ("\n"
            "baz.cc should add these lines:\n"
            "#include \"baz.h\"\n"
            "#include <stdio.h>                      // for printf\n"
            "#include <string>                       // for string::iterator\n"
            "#include \"bar.h\"                        // for BAR\n"
            "#include \"foo.h\"                        // for FOO\n"
            "struct Foo;\n"
            "\n"
            "baz.cc should remove these lines:\n"
            "\n"
            "The full include-list for baz.cc:\n"
            "#include \"baz.h\"\n"
            "#include <stdio.h>                      // for printf\n"
            "#include <string>                       // for string::iterator\n"
            "#include \"bar.h\"                        // for BAR\n"
            "#include \"foo.h\"                        // for FOO\n"
            "struct Foo;\n"
            "---\n",
            f.PrintableIncludeInformation());
}

using internal::PrintableIncludeOrForwardDeclareLine;

// This test fixture automatically saves/restores the verbose level
// between tests to prevent leaking side effects.
class PrintableIncludeOrForwardDeclareLineTest : public VerboseTest { };

TEST_F(PrintableIncludeOrForwardDeclareLineTest,
       ShowsReasonForNonMainCUHeaders) {
  // The reason should be printed even at a low verbose level.
  SetVerboseLevel(1);
  const char* symbols[] = { "Foo" };
  EXPECT_EQ("#include \"foo.h\"                        "
            "// for Foo\n",  // single symbol
            PrintableIncludeOrForwardDeclareLine(
                "bar.cc", MakeIncludeLine("\"foo.h\"", symbols)));
  const char* symbols2[] = { "Foo", "Bar" };
  EXPECT_EQ("#include \"foo.h\"                        "
            "// for Foo, Bar\n",  // multiple symbols
            PrintableIncludeOrForwardDeclareLine(
                "x.h", MakeIncludeLine("\"foo.h\"", symbols2)));
}

TEST_F(PrintableIncludeOrForwardDeclareLineTest, HidesReasonForMainCUHeaders) {
  // The reason should be hidden even at a high verbose level.
  SetVerboseLevel(5);
  const char* symbols[] = { "Foo" };
  EXPECT_EQ("#include \"foo.h\"\n",
            PrintableIncludeOrForwardDeclareLine(
                "foo.cc", MakeIncludeLine("\"foo.h\"", symbols)));
  EXPECT_EQ("#include \"foo.h\"\n",
            PrintableIncludeOrForwardDeclareLine(
                "foo_test.cc", MakeIncludeLine("\"foo.h\"", symbols)));
  EXPECT_EQ("#include \"foo-inl.h\"\n",
            PrintableIncludeOrForwardDeclareLine(
                "foo.cc", MakeIncludeLine("\"foo-inl.h\"", symbols)));
}

TEST_F(PrintableIncludeOrForwardDeclareLineTest,
       TruncatesLongSymbolListAtLowVerbosityLevels) {
  SetVerboseLevel(2);
  const char* symbols[] = { "Foo", "Bar", "SomeA", "SomeB", "SomeC", "BigX",
                            "BigY", "BigZ", "What", "Which", "Where" };
  EXPECT_EQ("#include <foo.h>         "
            "               // for Foo, Bar, SomeA, SomeB, etc\n",
            PrintableIncludeOrForwardDeclareLine(
                "bar.cc", MakeIncludeLine("<foo.h>", symbols)));

  EXPECT_EQ(
     "#include <some/really/really/really/really/long/path/abc.h>  "
     "// for Foo, etc\n",
     PrintableIncludeOrForwardDeclareLine(
         "a.cc",
         MakeIncludeLine("<some/really/really/really/really/long/path/abc.h>",
                         symbols)));

 EXPECT_EQ(
     // This line is exactly 80-character long, including the \n.
     "#include <some/really/really/really/really/long/path/abcdef.h>  "
     "// for Foo, etc\n",
     PrintableIncludeOrForwardDeclareLine(
         "foo.cc",
         MakeIncludeLine(
             "<some/really/really/really/really/long/path/abcdef.h>",
             symbols)));

 EXPECT_EQ(
     // There's no space on this line for " // for Foo, etc".  We
     // should cut off the comment entirely instead of printing
     // "  // for etc" or "  // for ".
     "#include <some/really/really/really/really/long/path/abcdefg.h>\n",
     PrintableIncludeOrForwardDeclareLine(
         "foo.cc",
         MakeIncludeLine(
             "<some/really/really/really/really/long/path/abcdefg.h>",
             symbols)));
}

TEST_F(PrintableIncludeOrForwardDeclareLineTest,
       PreservesLongSymbolListAtHighVerbosityLevels) {
  SetVerboseLevel(3);
  const char* symbols[] = { "Foo", "Bar", "SomeA", "SomeB", "SomeC", "BigX",
                            "BigY", "BigZ", "What", "Which", "Where" };
  EXPECT_EQ("#include <foo.h>                        "
            "// for Foo, Bar, SomeA, SomeB, SomeC, BigX, BigY, BigZ, What, "
            "Which, Where\n",
            PrintableIncludeOrForwardDeclareLine(
                "bar.cc", MakeIncludeLine("<foo.h>", symbols)));
}

TEST_F(PrintableIncludeOrForwardDeclareLineTest,
       OmitsReasonForSuperLongPathsAtLowVerbosityLevels) {
  SetVerboseLevel(2);
  const char* symbols[] = { "Foo" };
  EXPECT_EQ("#include \"some/really/really/really/really/really/deeply/buried/"
            "package/foo.h\"\n",
            PrintableIncludeOrForwardDeclareLine(
                "bar.cc",
                MakeIncludeLine("\"some/really/really/really/really/really/"
                                "deeply/buried/package/foo.h\"", symbols)));
}

TEST_F(PrintableIncludeOrForwardDeclareLineTest,
       PreservesReasonForSuperLongPathsAtHighVerbosityLevels) {
  SetVerboseLevel(3);
  const char* symbols[] = { "Foo" };
  EXPECT_EQ("#include \"some/really/really/really/really/really/deeply/buried/"
            "package/foo.h\"  // for Foo\n",
            PrintableIncludeOrForwardDeclareLine(
                "bar.cc",
                MakeIncludeLine("\"some/really/really/really/really/really/"
                                "deeply/buried/package/foo.h\"", symbols)));
}

TEST_F(PrintableIncludeOrForwardDeclareLineTest, PadsSpacesForShortPaths) {
  const char* symbols[] = { "Foo" };
  EXPECT_EQ("#include \"foo.h\"                        // for Foo\n",
            PrintableIncludeOrForwardDeclareLine(
                "bar.cc", MakeIncludeLine("\"foo.h\"", symbols)));
  EXPECT_EQ("#include \"foo/bar/b.h\"                  // for Foo\n",
            PrintableIncludeOrForwardDeclareLine(
                "bar.cc", MakeIncludeLine("\"foo/bar/b.h\"", symbols)));
}

TEST_F(PrintableIncludeOrForwardDeclareLineTest, DoesNotPadSpacesForLongPaths) {
  const char* symbols[] = { "Foo" };
  EXPECT_EQ("#include \"foo/bar/bluh.h\"               // for Foo\n",
            PrintableIncludeOrForwardDeclareLine(
                "bar.cc", MakeIncludeLine("\"foo/bar/bluh.h\"", symbols)));
  EXPECT_EQ("#include \"foo/bar/bluh-bluh.h\"          // for Foo\n",
            PrintableIncludeOrForwardDeclareLine(
                "bar.cc", MakeIncludeLine("\"foo/bar/bluh-bluh.h\"", symbols)));
}

TEST_F(PrintableIncludeOrForwardDeclareLineTest,
       PrintsLineNumbersWhenThereIsNoUsedSymbol) {
  IncludeOrForwardDeclareLineData data;
  data.line = "#include <foo.h>";
  data.line_num_range = make_pair(12, 12);
  // data.used_symbols is intentionally left empty.
  // We don't really care about .is_present and .is_desired.
  EXPECT_EQ("#include <foo.h>  // lines 12-12\n",
            PrintableIncludeOrForwardDeclareLine("bar.cc", data));
}

TEST_F(PrintableIncludeOrForwardDeclareLineTest,
       PrintsForwardDeclaresProperlyWithLineNumbers) {
  IncludeOrForwardDeclareLineData data;
  data.line = "class Foo;";
  data.line_num_range = make_pair(7, 8);
  EXPECT_EQ("class Foo;  // lines 7-8\n",
            PrintableIncludeOrForwardDeclareLine("bar.cc", data));
}

TEST_F(PrintableIncludeOrForwardDeclareLineTest,
       PrintsForwardDeclaresProperlyWithNoLineNumbers) {
  IncludeOrForwardDeclareLineData data;
  data.line = "class Foo;";
  data.line_num_range = make_pair(-1, -1);
  EXPECT_EQ("class Foo;\n",
            PrintableIncludeOrForwardDeclareLine("bar.cc", data));
}

#endif

}  // unnamed namespace
}  // namespace include_what_you_use


int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  include_what_you_use::InitGlobalsAndFlagsForTesting();
  return RUN_ALL_TESTS();
}
