Home | History | Annotate | Download | only in gn
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <vector>
      6 
      7 #include "testing/gtest/include/gtest/gtest.h"
      8 #include "tools/gn/header_checker.h"
      9 #include "tools/gn/scheduler.h"
     10 #include "tools/gn/target.h"
     11 #include "tools/gn/test_with_scope.h"
     12 
     13 namespace {
     14 
     15 class HeaderCheckerTest : public testing::Test {
     16  public:
     17   HeaderCheckerTest()
     18       : a_(setup_.settings(), Label(SourceDir("//a/"), "a")),
     19         b_(setup_.settings(), Label(SourceDir("//b/"), "a")),
     20         c_(setup_.settings(), Label(SourceDir("//c/"), "c")) {
     21     a_.deps().push_back(LabelTargetPair(&b_));
     22     b_.deps().push_back(LabelTargetPair(&c_));
     23 
     24     // Start with all public visibility.
     25     a_.visibility().SetPublic();
     26     b_.visibility().SetPublic();
     27     c_.visibility().SetPublic();
     28 
     29     targets_.push_back(&a_);
     30     targets_.push_back(&b_);
     31     targets_.push_back(&c_);
     32   }
     33 
     34  protected:
     35   Scheduler scheduler_;
     36 
     37   TestWithScope setup_;
     38 
     39   // Some headers that are automatically set up with a dependency chain.
     40   // a -> b -> c
     41   Target a_;
     42   Target b_;
     43   Target c_;
     44 
     45   std::vector<const Target*> targets_;
     46 };
     47 
     48 }  // namespace
     49 
     50 TEST_F(HeaderCheckerTest, IsDependencyOf) {
     51   scoped_refptr<HeaderChecker> checker(
     52       new HeaderChecker(setup_.build_settings(), targets_));
     53 
     54   std::vector<const Target*> chain;
     55   EXPECT_FALSE(checker->IsDependencyOf(&a_, &a_, &chain));
     56 
     57   chain.clear();
     58   EXPECT_TRUE(checker->IsDependencyOf(&b_, &a_, &chain));
     59   ASSERT_EQ(2u, chain.size());
     60   EXPECT_EQ(&b_, chain[0]);
     61   EXPECT_EQ(&a_, chain[1]);
     62 
     63   chain.clear();
     64   EXPECT_TRUE(checker->IsDependencyOf(&c_, &a_, &chain));
     65   ASSERT_EQ(3u, chain.size());
     66   EXPECT_EQ(&c_, chain[0]);
     67   EXPECT_EQ(&b_, chain[1]);
     68   EXPECT_EQ(&a_, chain[2]);
     69 
     70   chain.clear();
     71   EXPECT_FALSE(checker->IsDependencyOf(&a_, &c_, &chain));
     72   EXPECT_TRUE(chain.empty());
     73 }
     74 
     75 TEST_F(HeaderCheckerTest, CheckInclude) {
     76   InputFile input_file(SourceFile("//some_file.cc"));
     77   input_file.SetContents(std::string());
     78   LocationRange range;  // Dummy value.
     79 
     80   // Add a disconnected target d with a header to check that you have to have
     81   // to depend on a target listing a header.
     82   Target d(setup_.settings(), Label(SourceDir("//"), "d"));
     83   SourceFile d_header("//d_header.h");
     84   d.sources().push_back(SourceFile(d_header));
     85 
     86   // Add a header on B and say everything in B is public.
     87   SourceFile b_public("//b_public.h");
     88   b_.sources().push_back(b_public);
     89   c_.set_all_headers_public(true);
     90 
     91   // Add a public and private header on C.
     92   SourceFile c_public("//c_public.h");
     93   SourceFile c_private("//c_private.h");
     94   c_.sources().push_back(c_private);
     95   c_.public_headers().push_back(c_public);
     96   c_.set_all_headers_public(false);
     97 
     98   targets_.push_back(&d);
     99   scoped_refptr<HeaderChecker> checker(
    100       new HeaderChecker(setup_.build_settings(), targets_));
    101 
    102   // A file in target A can't include a header from D because A has no
    103   // dependency on D.
    104   Err err;
    105   EXPECT_FALSE(checker->CheckInclude(&a_, input_file, d_header, range, &err));
    106   EXPECT_TRUE(err.has_error());
    107 
    108   // A can include the public header in B.
    109   err = Err();
    110   EXPECT_TRUE(checker->CheckInclude(&a_, input_file, b_public, range, &err));
    111   EXPECT_FALSE(err.has_error());
    112 
    113   // Check A depending on the public and private headers in C.
    114   err = Err();
    115   EXPECT_TRUE(checker->CheckInclude(&a_, input_file, c_public, range, &err));
    116   EXPECT_FALSE(err.has_error());
    117   EXPECT_FALSE(checker->CheckInclude(&a_, input_file, c_private, range, &err));
    118   EXPECT_TRUE(err.has_error());
    119 
    120   // A can depend on a random file unknown to the build.
    121   err = Err();
    122   EXPECT_TRUE(checker->CheckInclude(&a_, input_file, SourceFile("//random.h"),
    123                                     range, &err));
    124   EXPECT_FALSE(err.has_error());
    125 
    126   // If C is not visible from A, A can't include public headers even if there
    127   // is a dependency path.
    128   c_.visibility().SetPrivate(c_.label().dir());
    129   err = Err();
    130   EXPECT_FALSE(checker->CheckInclude(&a_, input_file, c_public, range, &err));
    131   EXPECT_TRUE(err.has_error());
    132 }
    133 
    134 TEST_F(HeaderCheckerTest, DoDirectDependentConfigsApply) {
    135   // Assume we have a chain A -> B -> C -> D.
    136   Target target_a(setup_.settings(), Label(SourceDir("//a/"), "a"));
    137   Target target_b(setup_.settings(), Label(SourceDir("//b/"), "b"));
    138   Target target_c(setup_.settings(), Label(SourceDir("//c/"), "c"));
    139   Target target_d(setup_.settings(), Label(SourceDir("//d/"), "d"));
    140 
    141   // C is a group, and B forwards deps from C, so A should get configs from D.
    142   target_a.set_output_type(Target::SOURCE_SET);
    143   target_b.set_output_type(Target::SOURCE_SET);
    144   target_c.set_output_type(Target::GROUP);
    145   target_d.set_output_type(Target::SOURCE_SET);
    146   target_b.forward_dependent_configs().push_back(
    147       LabelTargetPair(&target_c));
    148 
    149   // Dependency chain goes from bottom to top.
    150   std::vector<const Target*> chain;
    151   chain.push_back(&target_d);
    152   chain.push_back(&target_c);
    153   chain.push_back(&target_b);
    154   chain.push_back(&target_a);
    155 
    156   // This chain should be valid.
    157   size_t badone = 0;
    158   EXPECT_TRUE(HeaderChecker::DoDirectDependentConfigsApply(chain, &badone));
    159 
    160   // If C is not a group, it shouldn't work anymore.
    161   target_c.set_output_type(Target::SOURCE_SET);
    162   EXPECT_FALSE(HeaderChecker::DoDirectDependentConfigsApply(chain, &badone));
    163   EXPECT_EQ(1u, badone);
    164 
    165   // Or if B stops forwarding from C, it shouldn't work anymore.
    166   target_c.set_output_type(Target::GROUP);
    167   badone = 0;
    168   target_b.forward_dependent_configs().clear();
    169   EXPECT_FALSE(HeaderChecker::DoDirectDependentConfigsApply(chain, &badone));
    170   EXPECT_EQ(2u, badone);
    171 }
    172