License cpp jun13 (#170620)

Still executing around 35s. It still doesn't match licenses against the
database. I don't expect that to add much time considering how we plan
to do it.

1) fixes the way c strings strip out comments
1) started handling LICENSE files more correctly

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
gaaclarke 2025-06-16 14:11:36 -07:00 committed by GitHub
parent 1cc9fcb587
commit b0735bfa73
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 301 additions and 113 deletions

View File

@ -3,3 +3,7 @@
.*\/test\/.*
.*\/testing\/.*
.*\/tests\/.*
.*/third_party/swiftshader/third_party/llvm-16.0/.*
.*/third_party/swiftshader/third_party/llvm-10.0/.*
.*/third_party/llvm-project/.*
.*/third_party/ocmock/.*

View File

@ -349,9 +349,9 @@ struct yy_trans_info {
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
static const flex_int16_t yy_accept[28] = {0, 0, 0, 0, 0, 0, 0, 9, 7, 7,
1, 7, 4, 4, 6, 6, 0, 1, 0, 1,
2, 3, 0, 5, 0, 2, 5, 0};
static const flex_int16_t yy_accept[37] = {
0, 0, 0, 0, 0, 0, 0, 9, 7, 7, 1, 7, 8, 4, 8, 6, 6, 0, 1,
0, 1, 2, 0, 4, 0, 0, 0, 5, 0, 2, 2, 0, 3, 0, 5, 0, 0};
static const YY_CHAR yy_ec[256] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -371,23 +371,27 @@ static const YY_CHAR yy_ec[256] = {
static const YY_CHAR yy_meta[7] = {0, 1, 1, 2, 1, 1, 3};
static const flex_int16_t yy_base[36] = {
0, 0, 0, 27, 24, 14, 12, 10, 34, 5, 0, 7, 34, 0, 34, 12, 0, 0,
0, 0, 0, 34, 0, 0, 0, 34, 0, 34, 18, 21, 24, 27, 5, 3, 30, 0};
static const flex_int16_t yy_base[45] = {
0, 0, 0, 4, 7, 18, 13, 14, 62, 11, 0, 13, 17, 62, 20,
62, 25, 0, 0, 0, 0, 29, 5, 62, 0, 32, 0, 0, 0, 62,
0, 35, 62, 2, 0, 0, 62, 40, 43, 46, 49, 52, 55, 58, 0};
static const flex_int16_t yy_def[36] = {
0, 28, 28, 29, 29, 30, 30, 27, 27, 27, 31, 27, 27, 32, 27, 27, 9, 31,
11, 31, 33, 27, 15, 34, 35, 27, 34, 0, 27, 27, 27, 27, 27, 27, 27, 27};
static const flex_int16_t yy_def[45] = {
0, 37, 37, 38, 38, 39, 39, 36, 36, 36, 40, 36, 41, 36, 41,
36, 36, 9, 40, 11, 40, 36, 14, 36, 14, 42, 16, 43, 44, 36,
21, 42, 36, 31, 43, 31, 0, 36, 36, 36, 36, 36, 36, 36, 36};
static const flex_int16_t yy_nxt[41] = {
0, 27, 9, 23, 10, 25, 11, 16, 21, 17, 27, 18, 20, 17,
22, 15, 23, 15, 24, 8, 8, 8, 12, 12, 12, 14, 14, 14,
19, 13, 19, 26, 13, 26, 7, 27, 27, 27, 27, 27, 27};
static const flex_int16_t yy_nxt[69] = {
0, 36, 9, 27, 10, 36, 11, 13, 35, 14, 13, 22, 14, 17, 36, 18, 16, 19,
21, 18, 23, 16, 24, 23, 36, 24, 25, 26, 36, 27, 36, 28, 29, 36, 30, 32,
36, 33, 32, 36, 33, 8, 8, 8, 12, 12, 12, 15, 15, 15, 20, 36, 20, 22,
22, 22, 31, 31, 31, 34, 36, 34, 7, 36, 36, 36, 36, 36, 36};
static const flex_int16_t yy_chk[41] = {
0, 0, 2, 35, 2, 33, 2, 9, 32, 9, 7, 9, 11, 11,
15, 6, 15, 5, 15, 28, 28, 28, 29, 29, 29, 30, 30, 30,
31, 4, 31, 34, 3, 34, 27, 27, 27, 27, 27, 27, 27};
static const flex_int16_t yy_chk[69] = {
0, 0, 2, 44, 2, 0, 2, 3, 33, 3, 4, 22, 4, 9, 7, 9, 6, 9,
11, 11, 12, 5, 12, 14, 0, 14, 14, 16, 0, 16, 0, 16, 21, 0, 21, 25,
0, 25, 31, 0, 31, 37, 37, 37, 38, 38, 38, 39, 39, 39, 40, 0, 40, 41,
41, 41, 42, 42, 42, 43, 0, 43, 36, 36, 36, 36, 36, 36, 36};
/* The intent behind this definition is that it'll catch
* any uses of REJECT which flex missed.
@ -421,9 +425,9 @@ struct LexerContext {
std::function<void(std::string_view)> callback;
std::string buffer;
};
#line 462 "comments.cc"
#line 471 "comments.cc"
#line 464 "comments.cc"
#line 473 "comments.cc"
#define INITIAL 0
#define C_COMMENT 1
@ -681,7 +685,7 @@ YY_DECL {
{
#line 40 "comments.l"
#line 729 "comments.cc"
#line 738 "comments.cc"
while (/*CONSTCOND*/ 1) /* loops until end-of-file is reached */
{
@ -706,12 +710,12 @@ YY_DECL {
}
while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) {
yy_current_state = (int)yy_def[yy_current_state];
if (yy_current_state >= 28)
if (yy_current_state >= 37)
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
++yy_cp;
} while (yy_base[yy_current_state] != 34);
} while (yy_base[yy_current_state] != 62);
yy_find_action:
yy_act = yy_accept[yy_current_state];
@ -751,10 +755,12 @@ YY_DECL {
YY_BREAK
case 3:
/* rule 3 can match eol */
YY_RULE_SETUP
#line 50 "comments.l"
{
BEGIN(INITIAL);
CommentsUtil::AddCEndTrimLine(&yyextra->buffer, yytext, yyleng - 2);
yyextra->callback(yyextra->buffer);
yyextra->buffer.clear();
}
@ -762,16 +768,16 @@ YY_DECL {
case 4:
/* rule 4 can match eol */
YY_RULE_SETUP
#line 55 "comments.l"
#line 56 "comments.l"
{
yyextra->buffer.append(yytext, yyleng);
CommentsUtil::AddCTrimLine(&yyextra->buffer, yytext, yyleng);
}
YY_BREAK
case 5:
/* rule 5 can match eol */
YY_RULE_SETUP
#line 61 "comments.l"
#line 62 "comments.l"
{
yyextra->buffer.append("\n", 1);
CommentsUtil::AddTrimLine(&yyextra->buffer, yytext + 1, yyleng - 1);
@ -780,7 +786,7 @@ YY_DECL {
case 6:
/* rule 6 can match eol */
YY_RULE_SETUP
#line 65 "comments.l"
#line 66 "comments.l"
{
BEGIN(INITIAL);
yyextra->callback(yyextra->buffer);
@ -791,16 +797,16 @@ YY_DECL {
case 7:
/* rule 7 can match eol */
YY_RULE_SETUP
#line 72 "comments.l"
#line 73 "comments.l"
{
}
YY_BREAK
case 8:
YY_RULE_SETUP
#line 73 "comments.l"
#line 74 "comments.l"
ECHO;
YY_BREAK
#line 854 "comments.cc"
#line 865 "comments.cc"
case YY_STATE_EOF(INITIAL):
case YY_STATE_EOF(C_COMMENT):
case YY_STATE_EOF(BLOCK):
@ -1080,7 +1086,7 @@ static yy_state_type yy_get_previous_state(yyscan_t yyscanner) {
}
while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) {
yy_current_state = (int)yy_def[yy_current_state];
if (yy_current_state >= 28)
if (yy_current_state >= 37)
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
@ -1108,11 +1114,11 @@ static yy_state_type yy_try_NUL_trans(yy_state_type yy_current_state,
}
while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) {
yy_current_state = (int)yy_def[yy_current_state];
if (yy_current_state >= 28)
if (yy_current_state >= 37)
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
yy_is_jam = (yy_current_state == 27);
yy_is_jam = (yy_current_state == 36);
(void)yyg;
return yy_is_jam ? 0 : yy_current_state;
@ -1909,7 +1915,7 @@ void yyfree(void* ptr, yyscan_t yyscanner) {
#define YYTABLES_NAME "yytables"
#line 73 "comments.l"
#line 74 "comments.l"
void IterateComments(const char* buffer,
size_t size,

View File

@ -42,18 +42,19 @@ COMMENT_START (\/\/|#)
BEGIN(BLOCK);
CommentsUtil::AddTrimLine(&yyextra->buffer, yytext, yyleng);
}
^[ \t]*\/\*[\n]? {
^[ \t]*\/\*[\*]*[\n]? {
BEGIN(C_COMMENT);
}
<C_COMMENT>{
\*\/ {
.*\*\/.*\n {
BEGIN(INITIAL);
CommentsUtil::AddCEndTrimLine(&yyextra->buffer, yytext, yyleng - 2);
yyextra->callback(yyextra->buffer);
yyextra->buffer.clear();
}
\n|. {
yyextra->buffer.append(yytext, yyleng);
.*\n {
CommentsUtil::AddCTrimLine(&yyextra->buffer, yytext, yyleng);
}
}

View File

@ -66,3 +66,35 @@ daa
ASSERT_EQ(comments.size(), 1u);
EXPECT_EQ(comments[0], "hello\nworld");
}
TEST(CommentsTest, CWithLeadingStars) {
std::string test = R"test(
/*************
* hello
* world
*/
)test";
std::vector<std::string> comments;
IterateComments(test.c_str(), test.size(), [&](std::string_view comment) {
comments.push_back(std::string(comment));
});
ASSERT_EQ(comments.size(), 1u);
EXPECT_EQ(comments[0], "hello\nworld\n");
}
TEST(CommentsTest, CTextOnEndingLine) {
std::string test = R"test(
/*hello
world*/
)test";
std::vector<std::string> comments;
IterateComments(test.c_str(), test.size(), [&](std::string_view comment) {
comments.push_back(std::string(comment));
});
ASSERT_EQ(comments.size(), 1u);
EXPECT_EQ(comments[0], "hello\nworld");
}

View File

@ -13,3 +13,21 @@ void CommentsUtil::AddTrimLine(std::string* buffer,
RE2::FullMatch(re2::StringPiece(text), regex, &captured_content);
buffer->append(captured_content);
}
void CommentsUtil::AddCTrimLine(std::string* buffer,
const char* text,
size_t length) {
std::string chopped(text, length);
RE2 regex(R"regex(^\s*\**\s?)regex");
RE2::Replace(&chopped, regex, "");
buffer->append(chopped);
}
void CommentsUtil::AddCEndTrimLine(std::string* buffer,
const char* text,
size_t length) {
RE2 regex(R"regex(^\s*(.*?)\*/)regex");
re2::StringPiece captured_content;
RE2::PartialMatch(re2::StringPiece(text), regex, &captured_content);
buffer->append(captured_content);
}

View File

@ -11,6 +11,12 @@
class CommentsUtil {
public:
static void AddTrimLine(std::string* buffer, const char* text, size_t length);
static void AddCTrimLine(std::string* buffer,
const char* text,
size_t length);
static void AddCEndTrimLine(std::string* buffer,
const char* text,
size_t length);
};
#endif // FLUTTER_TOOLS_LICENSES_CPP_SRC_COMMENTS_UTIL_H_

View File

@ -6,6 +6,7 @@
#include <unistd.h>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <vector>
@ -67,15 +68,14 @@ absl::StatusOr<std::vector<std::string>> GitLsFiles(const fs::path& repo_path) {
return files;
}
absl::Status CheckLicense(const fs::path& git_repo) {
std::optional<fs::path> FindLicense(const fs::path& path) {
for (std::string_view license_name : kLicenseFileNames) {
fs::path license_path = git_repo / license_name;
fs::path license_path = path / license_name;
if (fs::exists(license_path)) {
return absl::UnimplementedError("");
return license_path;
}
}
return absl::NotFoundError(
absl::StrCat("Expected LICENSE at ", git_repo.string()));
return std::nullopt;
}
void PrintProgress(size_t idx, size_t count) {
@ -124,20 +124,76 @@ class LicensesWriter {
bool first_write_ = true;
};
std::string GetPackageName(const fs::path& full_path) {
std::optional<std::string> result;
struct Package {
std::string name;
std::optional<fs::path> license_file;
};
Package GetPackage(const fs::path& working_dir, const fs::path& full_path) {
Package result = {
.name = "engine",
.license_file = FindLicense(working_dir),
};
fs::path relative = fs::relative(full_path, working_dir);
bool after_third_party = false;
for (const fs::path& component : full_path) {
fs::path current = working_dir;
for (const fs::path& component : relative) {
current /= component;
if (after_third_party) {
result = component;
result.name = component;
after_third_party = false;
result.license_file = FindLicense(current);
} else if (component.string() == "third_party") {
after_third_party = true;
result.license_file = std::nullopt;
}
}
return result.has_value() ? result.value() : "engine";
return result;
}
std::string ReadFile(const fs::path& path) {
std::ifstream stream(path);
assert(stream.good());
std::string license((std::istreambuf_iterator<char>(stream)),
std::istreambuf_iterator<char>());
if (license[license.size() - 1] == '\n') {
license.pop_back();
}
return license;
}
class LicenseMap {
public:
void Add(std::string_view package, std::string_view license) {
auto package_emplace_result =
map_.try_emplace(license, absl::flat_hash_set<std::string>());
absl::flat_hash_set<std::string>& comment_set =
package_emplace_result.first->second;
if (comment_set.find(package) == comment_set.end()) {
// License is already seen.
comment_set.emplace(std::string(package));
}
}
void AddFile(std::string_view package, const fs::path& path) {
if (!license_files_.contains(path.string())) {
Add(package, ReadFile(path));
license_files_.insert(path);
}
}
void Write(std::ostream& licenses) {
LicensesWriter writer(licenses);
for (const auto& comment_entry : map_) {
writer.Write(comment_entry.second, comment_entry.first);
}
}
private:
absl::btree_map<std::string, absl::flat_hash_set<std::string>> map_;
absl::flat_hash_set<std::string> license_files_;
};
} // namespace
std::vector<absl::Status> LicenseChecker::Run(std::string_view working_dir,
@ -145,27 +201,22 @@ std::vector<absl::Status> LicenseChecker::Run(std::string_view working_dir,
const Data& data) {
std::vector<absl::Status> errors;
std::vector<fs::path> git_repos = GetGitRepos(working_dir);
fs::path working_dir_path(working_dir);
RE2 pattern(kHeaderLicenseRegex);
size_t count = 0;
LicenseMap license_map;
for (const fs::path& git_repo : git_repos) {
if (IsStdoutTerminal()) {
PrintProgress(count++, git_repos.size());
}
absl::Status license_status = CheckLicense(git_repo);
if (!license_status.ok() &&
license_status.code() != absl::StatusCode::kUnimplemented) {
errors.push_back(license_status);
}
absl::StatusOr<std::vector<std::string>> git_files = GitLsFiles(git_repo);
if (!git_files.ok()) {
errors.push_back(git_files.status());
return errors;
}
LicensesWriter writer(licenses);
absl::btree_map<std::string, absl::flat_hash_set<std::string>> license_map;
for (const std::string& git_file : git_files.value()) {
bool did_find_copyright = false;
fs::path full_path = git_repo / git_file;
@ -175,7 +226,10 @@ std::vector<absl::Status> LicenseChecker::Run(std::string_view working_dir,
continue;
}
std::string package = GetPackageName(full_path);
Package package = GetPackage(working_dir_path, full_path);
if (package.license_file.has_value()) {
license_map.AddFile(package.name, package.license_file.value());
}
VLOG(1) << full_path.string();
absl::StatusOr<MMapFile> file = MMapFile::Make(full_path.string());
@ -196,27 +250,18 @@ std::vector<absl::Status> LicenseChecker::Run(std::string_view working_dir,
if (RE2::PartialMatch(comment, pattern, &match)) {
did_find_copyright = true;
VLOG(1) << comment;
auto package_emplace_result = license_map.try_emplace(
comment, absl::flat_hash_set<std::string>());
absl::flat_hash_set<std::string>& comment_set =
package_emplace_result.first->second;
if (comment_set.find(package) != comment_set.end()) {
// License is already seen.
return;
if (!package.license_file.has_value()) {
license_map.Add(package.name, comment);
}
comment_set.emplace(std::string(package));
}
});
if (!did_find_copyright) {
if (!did_find_copyright && !package.license_file.has_value()) {
errors.push_back(
absl::NotFoundError("Expected copyright in " + full_path.string()));
}
}
for (const auto& comment_entry : license_map) {
writer.Write(comment_entry.second, comment_entry.first);
}
}
license_map.Write(licenses);
if (IsStdoutTerminal()) {
PrintProgress(count++, git_repos.size());
std::cout << std::endl;

View File

@ -65,8 +65,7 @@ void main() {
}
)header";
const char* kLicense = R"lic(
Test License
const char* kLicense = R"lic(Test License
v2.0
)lic";
@ -109,6 +108,30 @@ bool FindError(const std::vector<absl::Status>& errors,
RE2::PartialMatch(status.message(), regex);
}) != errors.end();
}
class Repo {
public:
void Add(const std::string& file) { files_.emplace_back(std::string(file)); }
absl::Status Commit() {
if (std::system("git init") != 0) {
return absl::InternalError("git init failed");
}
for (const std::string& file : files_) {
if (std::system(("git add " + file).c_str()) != 0) {
return absl::InternalError("git add failed: " + file);
}
}
if (std::system("git commit -m \"test\"") != 0) {
return absl::InternalError("git commit failed");
}
return absl::OkStatus();
}
private:
std::vector<std::string> files_;
};
} // namespace
TEST_F(LicenseCheckerTest, SimplePass) {
@ -119,12 +142,12 @@ TEST_F(LicenseCheckerTest, SimplePass) {
ASSERT_TRUE(data.ok());
fs::current_path(*temp_path);
ASSERT_EQ(std::system("git init"), 0);
ASSERT_TRUE(WriteFile(kHeader, *temp_path / "main.cc").ok());
ASSERT_TRUE(WriteFile(kLicense, *temp_path / "LICENSE").ok());
ASSERT_EQ(std::system("git add main.cc"), 0);
ASSERT_EQ(std::system("git add LICENSE"), 0);
ASSERT_EQ(std::system("git commit -m \"test\""), 0);
Repo repo;
repo.Add(*temp_path / "main.cc");
repo.Add(*temp_path / "LICENSE");
ASSERT_TRUE(repo.Commit().ok());
std::stringstream ss;
std::vector<absl::Status> errors =
@ -132,7 +155,7 @@ TEST_F(LicenseCheckerTest, SimplePass) {
EXPECT_EQ(errors.size(), 0u);
}
TEST_F(LicenseCheckerTest, SimpleMissingLicense) {
TEST_F(LicenseCheckerTest, SimpleMissingFileLicense) {
absl::StatusOr<fs::path> temp_path = MakeTempDir();
ASSERT_TRUE(temp_path.ok());
@ -140,22 +163,20 @@ TEST_F(LicenseCheckerTest, SimpleMissingLicense) {
ASSERT_TRUE(data.ok());
fs::current_path(*temp_path);
ASSERT_EQ(std::system("git init"), 0);
ASSERT_EQ(std::system("echo \"Hello world!\" > main.cc"), 0);
ASSERT_EQ(std::system("git add main.cc"), 0);
ASSERT_EQ(std::system("git commit -m \"test\""), 0);
Repo repo;
repo.Add(*temp_path / "main.cc");
ASSERT_TRUE(repo.Commit().ok());
std::stringstream ss;
std::vector<absl::Status> errors =
LicenseChecker::Run(temp_path->string(), ss, *data);
EXPECT_EQ(errors.size(), 2u);
EXPECT_TRUE(
FindError(errors, absl::StatusCode::kNotFound, "Expected LICENSE at"));
EXPECT_EQ(errors.size(), 1u);
EXPECT_TRUE(FindError(errors, absl::StatusCode::kNotFound,
"Expected copyright in.*main.cc"));
}
TEST_F(LicenseCheckerTest, SimpleWritesLicensesFile) {
TEST_F(LicenseCheckerTest, SimpleWritesFileLicensesFile) {
absl::StatusOr<fs::path> temp_path = MakeTempDir();
ASSERT_TRUE(temp_path.ok());
@ -163,12 +184,10 @@ TEST_F(LicenseCheckerTest, SimpleWritesLicensesFile) {
ASSERT_TRUE(data.ok());
fs::current_path(*temp_path);
ASSERT_EQ(std::system("git init"), 0);
ASSERT_TRUE(WriteFile(kHeader, *temp_path / "main.cc").ok());
ASSERT_TRUE(WriteFile(kLicense, *temp_path / "LICENSE").ok());
ASSERT_EQ(std::system("git add main.cc"), 0);
ASSERT_EQ(std::system("git add LICENSE"), 0);
ASSERT_EQ(std::system("git commit -m \"test\""), 0);
Repo repo;
repo.Add(*temp_path / "main.cc");
ASSERT_TRUE(repo.Commit().ok());
std::stringstream ss;
std::vector<absl::Status> errors =
@ -181,7 +200,7 @@ Copyright Test
)output");
}
TEST_F(LicenseCheckerTest, SimpleWritesTwoLicensesFiles) {
TEST_F(LicenseCheckerTest, SimpleWritesTwoFileLicensesFiles) {
absl::StatusOr<fs::path> temp_path = MakeTempDir();
ASSERT_TRUE(temp_path.ok());
@ -189,14 +208,12 @@ TEST_F(LicenseCheckerTest, SimpleWritesTwoLicensesFiles) {
ASSERT_TRUE(data.ok());
fs::current_path(*temp_path);
ASSERT_EQ(std::system("git init"), 0);
ASSERT_TRUE(WriteFile(kHeader, *temp_path / "main.cc").ok());
ASSERT_TRUE(WriteFile(kCHeader, *temp_path / "cmain.cc").ok());
ASSERT_TRUE(WriteFile(kLicense, *temp_path / "LICENSE").ok());
ASSERT_EQ(std::system("git add main.cc"), 0);
ASSERT_EQ(std::system("git add cmain.cc"), 0);
ASSERT_EQ(std::system("git add LICENSE"), 0);
ASSERT_EQ(std::system("git commit -m \"test\""), 0);
Repo repo;
repo.Add("main.cc");
repo.Add("cmain.cc");
ASSERT_TRUE(repo.Commit().ok());
std::stringstream ss;
std::vector<absl::Status> errors =
@ -214,7 +231,7 @@ Copyright Test
)output");
}
TEST_F(LicenseCheckerTest, SimpleWritesDuplicateLicensesFiles) {
TEST_F(LicenseCheckerTest, SimpleWritesDuplicateFileLicensesFiles) {
absl::StatusOr<fs::path> temp_path = MakeTempDir();
ASSERT_TRUE(temp_path.ok());
@ -222,14 +239,12 @@ TEST_F(LicenseCheckerTest, SimpleWritesDuplicateLicensesFiles) {
ASSERT_TRUE(data.ok());
fs::current_path(*temp_path);
ASSERT_EQ(std::system("git init"), 0);
ASSERT_TRUE(WriteFile(kHeader, *temp_path / "a.cc").ok());
ASSERT_TRUE(WriteFile(kHeader, *temp_path / "b.cc").ok());
ASSERT_TRUE(WriteFile(kLicense, *temp_path / "LICENSE").ok());
ASSERT_EQ(std::system("git add a.cc"), 0);
ASSERT_EQ(std::system("git add b.cc"), 0);
ASSERT_EQ(std::system("git add LICENSE"), 0);
ASSERT_EQ(std::system("git commit -m \"test\""), 0);
Repo repo;
repo.Add("a.cc");
repo.Add("b.cc");
ASSERT_TRUE(repo.Commit().ok());
std::stringstream ss;
std::vector<absl::Status> errors =
@ -242,7 +257,7 @@ Copyright Test
)output");
}
TEST_F(LicenseCheckerTest, MultiplePackages) {
TEST_F(LicenseCheckerTest, FileLicenseMultiplePackages) {
absl::StatusOr<fs::path> temp_path = MakeTempDir();
ASSERT_TRUE(temp_path.ok());
@ -251,19 +266,13 @@ TEST_F(LicenseCheckerTest, MultiplePackages) {
fs::current_path(*temp_path);
ASSERT_EQ(std::system("mkdir -p third_party/foobar"), 0);
ASSERT_EQ(std::system("git init"), 0);
ASSERT_TRUE(WriteFile(kHeader, *temp_path / "a.cc").ok());
ASSERT_TRUE(
WriteFile(kHeader, *temp_path / "third_party" / "foobar" / "b.cc").ok());
ASSERT_TRUE(WriteFile(kLicense, *temp_path / "LICENSE").ok());
ASSERT_TRUE(
WriteFile(kLicense, *temp_path / "third_party" / "foobar" / "LICENSE")
.ok());
ASSERT_EQ(std::system("git add a.cc"), 0);
ASSERT_EQ(std::system("git add third_party/foobar/b.cc"), 0);
ASSERT_EQ(std::system("git add third_party/foobar/LICENSE"), 0);
ASSERT_EQ(std::system("git add LICENSE"), 0);
ASSERT_EQ(std::system("git commit -m \"test\""), 0);
Repo repo;
repo.Add("a.cc");
repo.Add("third_party/foobar/b.cc");
ASSERT_TRUE(repo.Commit().ok());
std::stringstream ss;
std::vector<absl::Status> errors =
@ -276,3 +285,66 @@ foobar
Copyright Test
)output");
}
TEST_F(LicenseCheckerTest, SimpleDirectoryLicense) {
absl::StatusOr<fs::path> temp_path = MakeTempDir();
ASSERT_TRUE(temp_path.ok());
absl::StatusOr<Data> data = MakeTestData();
ASSERT_TRUE(data.ok());
fs::current_path(*temp_path);
ASSERT_EQ(std::system("echo \"Hello world!\" > main.cc"), 0);
ASSERT_TRUE(WriteFile(kLicense, *temp_path / "LICENSE").ok());
Repo repo;
repo.Add("main.cc");
repo.Add("LICENSE");
ASSERT_TRUE(repo.Commit().ok());
std::stringstream ss;
std::vector<absl::Status> errors =
LicenseChecker::Run(temp_path->string(), ss, *data);
EXPECT_EQ(errors.size(), 0u);
EXPECT_EQ(ss.str(), R"output(engine
Test License
v2.0
)output");
}
TEST_F(LicenseCheckerTest, ThirdyPartyDirectoryLicense) {
absl::StatusOr<fs::path> temp_path = MakeTempDir();
ASSERT_TRUE(temp_path.ok());
absl::StatusOr<Data> data = MakeTestData();
ASSERT_TRUE(data.ok());
fs::current_path(*temp_path);
ASSERT_EQ(std::system("mkdir -p third_party/foobar"), 0);
ASSERT_EQ(std::system("echo \"Hello world!\" > main.cc"), 0);
ASSERT_EQ(std::system("echo \"Hello world!\" > third_party/foobar/foo.cc"),
0);
ASSERT_TRUE(WriteFile(kLicense, *temp_path / "LICENSE").ok());
ASSERT_TRUE(
WriteFile(kLicense, *temp_path / "third_party" / "foobar" / "LICENSE")
.ok());
Repo repo;
repo.Add("main.cc");
repo.Add("LICENSE");
repo.Add("third_party/foobar/foo.cc");
repo.Add("third_party/foobar/LICENSE");
ASSERT_TRUE(repo.Commit().ok());
std::stringstream ss;
std::vector<absl::Status> errors =
LicenseChecker::Run(temp_path->string(), ss, *data);
EXPECT_EQ(errors.size(), 0u);
EXPECT_EQ(ss.str(), R"output(engine
foobar
Test License
v2.0
)output");
}

View File

@ -34,7 +34,7 @@ int main(int argc, char** argv) {
absl::SetGlobalVLogLevel(absl::GetFlag(FLAGS_v));
std::optional<std::string> working_dir = absl::GetFlag(FLAGS_working_dir);
std::optional<std::string> data_dir = absl::GetFlag(FLAGS_working_dir);
std::optional<std::string> data_dir = absl::GetFlag(FLAGS_data_dir);
std::optional<std::string> licenses_path = absl::GetFlag(FLAGS_licenses_path);
if (working_dir.has_value() && data_dir.has_value() &&
licenses_path.has_value()) {
@ -51,6 +51,10 @@ int main(int argc, char** argv) {
std::cerr << "Expected --working_dir flag." << std::endl;
}
if (!licenses_path.has_value()) {
std::cerr << "Expected --licenses_path flag." << std::endl;
}
if (!data_dir.has_value()) {
std::cerr << "Expected --data_dir flag." << std::endl;
}