xref: /aosp_15_r20/external/executorch/extension/testing_util/temp_file.h (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
9 #pragma once
10 
11 #include <array>
12 #include <memory>
13 #include <string>
14 
15 #include <fcntl.h> // open()
16 #include <stdio.h> // tmpnam(), remove()
17 #include <unistd.h> // write(), close()
18 
19 #include <gtest/gtest.h>
20 
21 namespace executorch {
22 namespace extension {
23 namespace testing { // Test-only helpers belong in a "testing" sub-namespace.
24 
25 /**
26  * Creates and manages a named temporary file in the file system. Deletes the
27  * file when this instance is destroyed.
28  *
29  * Only for use in gtest tests.
30  */
31 class TempFile {
32  public:
33   /**
34    * Creates a temporary file whose contents are the same as the provided
35    * string.
36    */
TempFile(const std::string & contents)37   explicit TempFile(const std::string& contents)
38       : TempFile(contents.data(), contents.size()) {}
39 
40   /**
41    * Creates a temporary file with the provided contents.
42    */
TempFile(const void * data,size_t size)43   TempFile(const void* data, size_t size) {
44     CreateFile(data, size, &path_);
45   }
46 
~TempFile()47   ~TempFile() {
48     if (!path_.empty()) {
49       std::remove(path_.c_str());
50     }
51   }
52 
53   /**
54    * The absolute path to the temporary file.
55    */
path()56   const std::string& path() const {
57     return path_;
58   }
59 
60  private:
61   // ASSERT_x() macros can only be called from a function returning void, so
62   // this logic can't be directly in the ctor.
CreateFile(const void * data,size_t size,std::string * out_path)63   void CreateFile(const void* data, size_t size, std::string* out_path) {
64     // Find a unique temporary file name.
65     std::string path;
66     {
67       std::array<char, L_tmpnam> buf;
68       const char* ret = std::tmpnam(buf.data());
69       ASSERT_NE(ret, nullptr) << "Coult not generate temp file";
70       buf[L_tmpnam - 1] = '\0';
71       path = std::string(buf.data()) + "-executorch-testing";
72     }
73 
74     // Write the contents to the file.
75     int fd = open(
76         path.c_str(),
77         // O_EXCL ensures that we are the ones creating this file, to help
78         // protect against race conditions.
79         O_CREAT | O_EXCL | O_RDWR,
80         // User can read and write, group can read.
81         S_IRUSR | S_IWUSR | S_IRGRP);
82     ASSERT_GE(fd, 0) << "open(" << path << ") failed: " << strerror(errno);
83 
84     ssize_t nwrite = write(fd, data, size);
85     ASSERT_EQ(nwrite, size) << "Failed to write " << size << " bytes (wrote "
86                             << nwrite << "): " << strerror(errno);
87     close(fd);
88 
89     *out_path = path;
90   }
91 
92   // Not safely copyable/movable.
93   TempFile(const TempFile&) = delete;
94   TempFile& operator=(const TempFile&) = delete;
95   TempFile(TempFile&&) = delete;
96   TempFile& operator=(TempFile&&) = delete;
97 
98   std::string path_;
99 };
100 
101 } // namespace testing
102 } // namespace extension
103 } // namespace executorch
104 
105 namespace torch {
106 namespace executor {
107 namespace testing {
108 // TODO(T197294990): Remove these deprecated aliases once all users have moved
109 // to the new `::executorch` namespaces.
110 using ::executorch::extension::testing::TempFile;
111 } // namespace testing
112 } // namespace executor
113 } // namespace torch
114