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