• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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