// Copyright 2014 The Chromium 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 #include "base/files/file.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/functions.h" #include "tools/gn/scheduler.h" #include "tools/gn/test_with_scope.h" namespace { // Returns true on success, false if write_file signaled an error. bool CallWriteFile(Scope* scope, const std::string& filename, const Value& data) { Err err; std::vector args; args.push_back(Value(nullptr, filename)); args.push_back(data); FunctionCallNode function_call; Value result = functions::RunWriteFile(scope, &function_call, args, &err); EXPECT_EQ(Value::NONE, result.type()); // Should always return none. return !err.has_error(); } } // namespace TEST(WriteFile, WithData) { Scheduler scheduler; TestWithScope setup; // Make a real directory for writing the files. base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); setup.build_settings()->SetRootPath(temp_dir.path()); setup.build_settings()->SetBuildDir(SourceDir("//out/")); Value some_string(nullptr, "some string contents"); // Should refuse to write files outside of the output dir. EXPECT_FALSE(CallWriteFile(setup.scope(), "//in_root.txt", some_string)); EXPECT_FALSE(CallWriteFile(setup.scope(), "//other_dir/foo.txt", some_string)); // Should be able to write to a new dir inside the out dir. EXPECT_TRUE(CallWriteFile(setup.scope(), "//out/foo.txt", some_string)); base::FilePath foo_name = temp_dir.path().Append(FILE_PATH_LITERAL("out")) .Append(FILE_PATH_LITERAL("foo.txt")); std::string result_contents; EXPECT_TRUE(base::ReadFileToString(foo_name, &result_contents)); EXPECT_EQ(some_string.string_value(), result_contents); // Update the contents with a list of a string and a number. Value some_list(nullptr, Value::LIST); some_list.list_value().push_back(Value(nullptr, "line 1")); some_list.list_value().push_back(Value(nullptr, static_cast(2))); EXPECT_TRUE(CallWriteFile(setup.scope(), "//out/foo.txt", some_list)); EXPECT_TRUE(base::ReadFileToString(foo_name, &result_contents)); EXPECT_EQ("line 1\n2\n", result_contents); // Test that the file is not rewritten if the contents are not changed. // Start by setting the modified time to something old to avoid clock // resolution issues. base::Time old_time = base::Time::Now() - base::TimeDelta::FromDays(1); base::File foo_file(foo_name, base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE); ASSERT_TRUE(foo_file.IsValid()); foo_file.SetTimes(old_time, old_time); // Read the current time to avoid timer resolution issues when comparing // below. base::File::Info original_info; foo_file.GetInfo(&original_info); EXPECT_TRUE(CallWriteFile(setup.scope(), "//out/foo.txt", some_list)); // Verify that the last modified time is the same as before. base::File::Info new_info; foo_file.GetInfo(&new_info); EXPECT_EQ(original_info.last_modified, new_info.last_modified); }