| // 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 <windows.h> |
| |
| #include <memory> |
| #include <ostream> |
| #include <string> |
| #include <vector> |
| |
| 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<std::string>& 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<char[]> abs_paths_; |
| std::unique_ptr<char*[]> abs_path_ptrs_; |
| std::unique_ptr<char*[]> 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: |
| virtual ~IFStream() {} |
| |
| // Gets the current byte under the read cursor. |
| // Returns true upon success, returns false if there's no more data to read. |
| virtual bool Get(uint8_t* result) const = 0; |
| |
| // Advances the read cursor one byte ahead. May fetch data from the underlying |
| // HANDLE. |
| // Returns true if the cursor could be moved. Returns false if EOF was reached |
| // or if there was an I/O error. |
| virtual bool Advance() = 0; |
| |
| // Peeks at the next byte after the read cursor. Returns true if there's at |
| // least one more byte in the stream. |
| bool Peek1(uint8_t* result) const { return PeekN(1, result); } |
| |
| // Peeks at the next two bytes after the read cursor. Returns true if there |
| // are at least two more byte in the stream. |
| bool Peek2(uint8_t* result) const { return PeekN(2, result); } |
| |
| // Peeks at the next three bytes after the read cursor. Returns true if there |
| // are at least three more byte in the stream. |
| bool Peek3(uint8_t* result) const { return PeekN(3, result); } |
| |
| protected: |
| IFStream() {} |
| IFStream(const IFStream&) = delete; |
| IFStream& operator=(const IFStream&) = delete; |
| |
| // Peeks ahead N bytes, writing them to 'result'. Returns true if successful. |
| // The result does not include the byte currently under the read cursor. |
| virtual bool PeekN(DWORD n, uint8_t* result) const = 0; |
| }; |
| |
| // 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<FileInfo>* 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<bazel::tools::test_wrapper::FileInfo>& 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<FileInfo>& 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<FileInfo>& 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<Tee>* result); |
| |
| bool TestOnly_CdataEncode(const uint8_t* buffer, const DWORD size, |
| std::basic_ostream<char>* out_stm); |
| |
| IFStream* TestOnly_CreateIFStream(bazel::windows::AutoHandle* handle, |
| DWORD page_size); |
| |
| } // namespace testing |
| |
| } // namespace test_wrapper |
| } // namespace tools |
| } // namespace bazel |
| |
| #endif // BAZEL_TOOLS_TEST_WINDOWS_TW_H_ |