• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdint.h>
6 
7 #include "base/files/file.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "gn/functions.h"
11 #include "gn/scheduler.h"
12 #include "gn/test_with_scheduler.h"
13 #include "gn/test_with_scope.h"
14 #include "util/test/test.h"
15 
16 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_HAIKU) || \
17     defined(OS_MSYS) || defined(OS_SERENITY)
18 #include <sys/time.h>
19 #elif defined(OS_ZOS)
20 #include <utime.h>
21 #endif
22 
23 #if defined(OS_WIN)
24 #include <windows.h>
25 #endif
26 
27 namespace {
28 
29 // Returns true on success, false if write_file signaled an error.
CallWriteFile(Scope * scope,const std::string & filename,const Value & data)30 bool CallWriteFile(Scope* scope,
31                    const std::string& filename,
32                    const Value& data) {
33   Err err;
34 
35   std::vector<Value> args;
36   args.push_back(Value(nullptr, filename));
37   args.push_back(data);
38 
39   FunctionCallNode function_call;
40   Value result = functions::RunWriteFile(scope, &function_call, args, &err);
41   EXPECT_EQ(Value::NONE, result.type());  // Should always return none.
42 
43   return !err.has_error();
44 }
45 
46 }  // namespace
47 
48 using WriteFileTest = TestWithScheduler;
49 
TEST_F(WriteFileTest,WithData)50 TEST_F(WriteFileTest, WithData) {
51   TestWithScope setup;
52 
53   // Make a real directory for writing the files.
54   base::ScopedTempDir temp_dir;
55   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
56   setup.build_settings()->SetRootPath(temp_dir.GetPath());
57   setup.build_settings()->SetBuildDir(SourceDir("//out/"));
58 
59   Value some_string(nullptr, "some string contents");
60 
61   // Should refuse to write files outside of the output dir.
62   EXPECT_FALSE(CallWriteFile(setup.scope(), "//in_root.txt", some_string));
63   EXPECT_FALSE(
64       CallWriteFile(setup.scope(), "//other_dir/foo.txt", some_string));
65 
66   // Should be able to write to a new dir inside the out dir.
67   EXPECT_TRUE(CallWriteFile(setup.scope(), "//out/foo.txt", some_string));
68   base::FilePath foo_name = temp_dir.GetPath()
69                                 .Append(FILE_PATH_LITERAL("out"))
70                                 .Append(FILE_PATH_LITERAL("foo.txt"));
71   std::string result_contents;
72   EXPECT_TRUE(base::ReadFileToString(foo_name, &result_contents));
73   EXPECT_EQ(some_string.string_value(), result_contents);
74 
75   // Update the contents with a list of a string and a number.
76   Value some_list(nullptr, Value::LIST);
77   some_list.list_value().push_back(Value(nullptr, "line 1"));
78   some_list.list_value().push_back(Value(nullptr, static_cast<int64_t>(2)));
79   EXPECT_TRUE(CallWriteFile(setup.scope(), "//out/foo.txt", some_list));
80   EXPECT_TRUE(base::ReadFileToString(foo_name, &result_contents));
81   EXPECT_EQ("line 1\n2\n", result_contents);
82 
83   // Test that the file is not rewritten if the contents are not changed.
84   base::File foo_file(foo_name, base::File::FLAG_OPEN | base::File::FLAG_READ |
85                                     base::File::FLAG_WRITE);
86   ASSERT_TRUE(foo_file.IsValid());
87 
88   // Start by setting the modified time to something old to avoid clock
89   // resolution issues.
90 #if defined(OS_WIN)
91   FILETIME last_access_filetime = {};
92   FILETIME last_modified_filetime = {};
93   ASSERT_TRUE(::SetFileTime(foo_file.GetPlatformFile(), nullptr,
94                             &last_access_filetime, &last_modified_filetime));
95 #elif defined(OS_AIX) || defined(OS_HAIKU) || defined(OS_SOLARIS)
96   struct timeval times[2] = {};
97   ASSERT_EQ(utimes(foo_name.value().c_str(), times), 0);
98 #elif defined(OS_ZOS)
99   ASSERT_EQ(utime(foo_name.value().c_str(), NULL), 0);
100 #else
101   struct timeval times[2] = {};
102   ASSERT_EQ(futimes(foo_file.GetPlatformFile(), times), 0);
103 #endif
104 
105   // Read the current time to avoid timer resolution issues when comparing
106   // below.
107   base::File::Info original_info;
108   foo_file.GetInfo(&original_info);
109 
110   EXPECT_TRUE(CallWriteFile(setup.scope(), "//out/foo.txt", some_list));
111 
112   // Verify that the last modified time is the same as before.
113   base::File::Info new_info;
114   foo_file.GetInfo(&new_info);
115   EXPECT_EQ(original_info.last_modified, new_info.last_modified);
116 }
117