1 // Copyright 2021 The Tint Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef SRC_TRANSFORM_TEST_HELPER_H_ 16 #define SRC_TRANSFORM_TEST_HELPER_H_ 17 18 #include <memory> 19 #include <string> 20 #include <utility> 21 #include <vector> 22 23 #include "gtest/gtest.h" 24 #include "src/reader/wgsl/parser.h" 25 #include "src/transform/manager.h" 26 #include "src/writer/wgsl/generator.h" 27 28 namespace tint { 29 namespace transform { 30 31 /// Helper class for testing transforms 32 template <typename BASE> 33 class TransformTestBase : public BASE { 34 public: 35 /// Transforms and returns the WGSL source `in`, transformed using 36 /// `transform`. 37 /// @param transform the transform to apply 38 /// @param in the input WGSL source 39 /// @param data the optional DataMap to pass to Transform::Run() 40 /// @return the transformed output 41 Output Run(std::string in, 42 std::unique_ptr<transform::Transform> transform, 43 const DataMap& data = {}) { 44 std::vector<std::unique_ptr<transform::Transform>> transforms; 45 transforms.emplace_back(std::move(transform)); 46 return Run(std::move(in), std::move(transforms), data); 47 } 48 49 /// Transforms and returns the WGSL source `in`, transformed using 50 /// a transform of type `TRANSFORM`. 51 /// @param in the input WGSL source 52 /// @param data the optional DataMap to pass to Transform::Run() 53 /// @return the transformed output 54 template <typename... TRANSFORMS> 55 Output Run(std::string in, const DataMap& data = {}) { 56 auto file = std::make_unique<Source::File>("test", in); 57 auto program = reader::wgsl::Parse(file.get()); 58 59 // Keep this pointer alive after Transform() returns 60 files_.emplace_back(std::move(file)); 61 62 return Run<TRANSFORMS...>(std::move(program), data); 63 } 64 65 /// Transforms and returns program `program`, transformed using a transform of 66 /// type `TRANSFORM`. 67 /// @param program the input Program 68 /// @param data the optional DataMap to pass to Transform::Run() 69 /// @return the transformed output 70 template <typename... TRANSFORMS> 71 Output Run(Program&& program, const DataMap& data = {}) { 72 if (!program.IsValid()) { 73 return Output(std::move(program)); 74 } 75 76 Manager manager; 77 for (auto* transform_ptr : 78 std::initializer_list<Transform*>{new TRANSFORMS()...}) { 79 manager.append(std::unique_ptr<Transform>(transform_ptr)); 80 } 81 return manager.Run(&program, data); 82 } 83 84 /// @param output the output of the transform 85 /// @returns the output program as a WGSL string, or an error string if the 86 /// program is not valid. str(const Output & output)87 std::string str(const Output& output) { 88 diag::Formatter::Style style; 89 style.print_newline_at_end = false; 90 91 if (!output.program.IsValid()) { 92 return diag::Formatter(style).format(output.program.Diagnostics()); 93 } 94 95 writer::wgsl::Options options; 96 auto result = writer::wgsl::Generate(&output.program, options); 97 if (!result.success) { 98 return "WGSL writer failed:\n" + result.error; 99 } 100 101 auto res = result.wgsl; 102 if (res.empty()) { 103 return res; 104 } 105 // The WGSL sometimes has two trailing newlines. Strip them 106 while (res.back() == '\n') { 107 res.pop_back(); 108 } 109 if (res.empty()) { 110 return res; 111 } 112 return "\n" + res + "\n"; 113 } 114 115 private: 116 std::vector<std::unique_ptr<Source::File>> files_; 117 }; 118 119 using TransformTest = TransformTestBase<testing::Test>; 120 121 template <typename T> 122 using TransformTestWithParam = TransformTestBase<testing::TestWithParam<T>>; 123 124 } // namespace transform 125 } // namespace tint 126 127 #endif // SRC_TRANSFORM_TEST_HELPER_H_ 128