// Copyright 2018 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef BAZEL_TOOLS_TEST_WINDOWS_TW_H_ #define BAZEL_TOOLS_TEST_WINDOWS_TW_H_ #define WIN32_LEAN_AND_MEAN #include #include #include #include #include namespace bazel { namespace windows { class AutoHandle; } // namespace windows namespace tools { namespace test_wrapper { // Info about a file/directory in the results of TestOnly_GetFileListRelativeTo. class FileInfo { public: // C'tor for a directory. FileInfo(const std::wstring& rel_path) : rel_path_(rel_path), size_(0), is_dir_(true) {} // C'tor for a file. // Marked "explicit" because `size` is just a `int`. explicit FileInfo(const std::wstring& rel_path, int size) : rel_path_(rel_path), size_(size), is_dir_(false) {} inline const std::wstring& RelativePath() const { return rel_path_; } inline int Size() const { return size_; } inline bool IsDirectory() const { return is_dir_; } private: // The file's path, relative to the traversal root. std::wstring rel_path_; // The file's size, in bytes. // // Unfortunately this field has to be `int`, so it can only describe files up // to 2 GiB in size. The reason is, devtools_ijar::Stat::total_size is // declared as `int`, which is what we ultimately store the file size in, // therefore this field is also `int`. int size_; // Whether this is a directory (true) or a regular file (false). bool is_dir_; }; // Zip entry paths for devtools_ijar::ZipBuilder. // The function signatures mirror the signatures of ZipBuilder's functions. class ZipEntryPaths { public: // Initialize the strings in this object. // `root` must be an absolute mixed-style path (Windows path with "/" // separators). // `files` must be relative, Unix-style paths. void Create(const std::string& root, const std::vector& files); // Returns the number of paths in `AbsPathPtrs` and `EntryPathPtrs`. size_t Size() const { return size_; } // Returns a mutable array of const pointers to const char data. // Each pointer points to an absolute path: the file to archive. // The pointers are owned by this object and become invalid when the object is // destroyed. // Each entry corresponds to the entry at the same index in `EntryPathPtrs`. char const* const* AbsPathPtrs() const { return abs_path_ptrs_.get(); } // Returns a mutable array of const pointers to const char data. // Each pointer points to a relative path: an entry in the zip file. // The pointers are owned by this object and become invalid when the object is // destroyed. // Each entry corresponds to the entry at the same index in `AbsPathPtrs`. char const* const* EntryPathPtrs() const { return entry_path_ptrs_.get(); } private: size_t size_; std::unique_ptr abs_paths_; std::unique_ptr abs_path_ptrs_; std::unique_ptr entry_path_ptrs_; }; // Streams data from an input to two outputs. // Inspired by tee(1) in the GNU coreutils. class Tee { public: virtual ~Tee() {} protected: Tee() {} Tee(const Tee&) = delete; Tee& operator=(const Tee&) = delete; }; // Buffered input stream (based on a HANDLE) with peek-ahead support. class IFStream { public: enum { kIFStreamErrorEOF = 256, kIFStreamErrorIO = 257, }; virtual ~IFStream() {} // Reads one byte from the stream, and moves the cursor ahead. // Returns: // 0..255: success, the value of the read byte // 256 (kIFStreamErrorEOF): failure, EOF was reached // 257 (kIFStreamErrorIO): failure, I/O error virtual int Get() = 0; // Peeks at 'n' bytes starting at the current cursor position. // Writes into 'out' the 0..'n' successfully peeked bytes. // Returns: // 0..n: the number of successfully peeked bytes virtual DWORD Peek(DWORD n, uint8_t* out) const = 0; protected: IFStream() {} private: IFStream(const IFStream&) = delete; IFStream& operator=(const IFStream&) = delete; }; // The main function of the test wrapper. int TestWrapperMain(int argc, wchar_t** argv); // The main function of the test XML writer. int XmlWriterMain(int argc, wchar_t** argv); // The "testing" namespace contains functions that should only be used by tests. namespace testing { // Retrieves an environment variable. bool TestOnly_GetEnv(const wchar_t* name, std::wstring* result); // Lists all files under `abs_root`, with paths relative to `abs_root`. // Limits the directory depth to `depth_limit` many directories below // `abs_root`. // A negative depth means unlimited depth. 0 depth means searching only // `abs_root`, while a positive depth limit allows matches in up to that many // subdirectories. bool TestOnly_GetFileListRelativeTo(const std::wstring& abs_root, std::vector* result, int depth_limit = -1); // Converts a list of files to ZIP file entry paths.a bool TestOnly_ToZipEntryPaths( const std::wstring& abs_root, const std::vector& files, ZipEntryPaths* result); // Archives `files` into a zip file at `abs_zip` (absolute path to the zip). bool TestOnly_CreateZip(const std::wstring& abs_root, const std::vector& files, const std::wstring& abs_zip); // Returns the MIME type of a file. The file does not need to exist. std::string TestOnly_GetMimeType(const std::string& filename); // Returns the contents of the Undeclared Outputs manifest. bool TestOnly_CreateUndeclaredOutputsManifest( const std::vector& files, std::string* result); bool TestOnly_CreateUndeclaredOutputsAnnotations( const std::wstring& abs_root, const std::wstring& abs_output); bool TestOnly_AsMixedPath(const std::wstring& path, std::string* result); // Creates a Tee object. See the Tee class declaration for more info. bool TestOnly_CreateTee(bazel::windows::AutoHandle* input, bazel::windows::AutoHandle* output1, bazel::windows::AutoHandle* output2, std::unique_ptr* result); bool TestOnly_CdataEncode(IFStream* in_stm, std::basic_ostream* out_stm); IFStream* TestOnly_CreateIFStream(HANDLE handle, DWORD page_size); } // namespace testing } // namespace test_wrapper } // namespace tools } // namespace bazel #endif // BAZEL_TOOLS_TEST_WINDOWS_TW_H_