diff options
Diffstat (limited to 'tools/tflite_run/src')
-rw-r--r-- | tools/tflite_run/src/args.cc | 125 | ||||
-rw-r--r-- | tools/tflite_run/src/args.h | 55 | ||||
-rw-r--r-- | tools/tflite_run/src/bin_image.cc | 71 | ||||
-rw-r--r-- | tools/tflite_run/src/bin_image.h | 43 | ||||
-rw-r--r-- | tools/tflite_run/src/tensor_dumper.cc | 54 | ||||
-rw-r--r-- | tools/tflite_run/src/tensor_dumper.h | 38 | ||||
-rw-r--r-- | tools/tflite_run/src/tensor_loader.cc | 67 | ||||
-rw-r--r-- | tools/tflite_run/src/tensor_loader.h | 35 | ||||
-rw-r--r-- | tools/tflite_run/src/tflite_run.cc | 253 | ||||
-rw-r--r-- | tools/tflite_run/src/tflite_test.cc | 19 |
10 files changed, 0 insertions, 760 deletions
diff --git a/tools/tflite_run/src/args.cc b/tools/tflite_run/src/args.cc deleted file mode 100644 index 6aebbbbd7..000000000 --- a/tools/tflite_run/src/args.cc +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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. - */ - -#include "args.h" - -#include <iostream> - -#include <boost/filesystem.hpp> - -namespace TFLiteRun -{ - -Args::Args(const int argc, char **argv) -{ - Initialize(); - Parse(argc, argv); -} - -void Args::Initialize(void) -{ - - // General options - po::options_description general("General options"); - - // clang-format off - general.add_options() - ("help,h", "Display available options") - ("input,i", po::value<std::string>(&_input_filename)->default_value(""), "Input filename") - ("dump,d", po::value<std::string>()->default_value(""), "Output filename") - ("compare,c", po::value<std::string>()->default_value(""), "filename to be compared with") - ("tflite", po::value<std::string>()->required()); - // clang-format on - - _options.add(general); - _positional.add("tflite", 1); -} - -void Args::Parse(const int argc, char **argv) -{ - po::variables_map vm; - po::store(po::command_line_parser(argc, argv).options(_options).positional(_positional).run(), - vm); - po::notify(vm); - - { - auto conflicting_options = [&](const std::string &o1, const std::string &o2) { - if ((vm.count(o1) && !vm[o1].defaulted()) && (vm.count(o2) && !vm[o2].defaulted())) - { - throw boost::program_options::error(std::string("Two options '") + o1 + "' and '" + o2 + - "' cannot be given at once."); - } - }; - - conflicting_options("input", "compare"); - } - - if (vm.count("help")) - { - std::cout << "tflite_run\n\n"; - std::cout << "Usage: " << argv[0] << " <.tflite> [<options>]\n\n"; - std::cout << _options; - std::cout << "\n"; - - exit(0); - } - - if (vm.count("input")) - { - _input_filename = vm["input"].as<std::string>(); - - if (!_input_filename.empty()) - { - if (!boost::filesystem::exists(_input_filename)) - { - std::cerr << "input image file not found: " << _input_filename << "\n"; - } - } - } - - if (vm.count("dump")) - { - _dump_filename = vm["dump"].as<std::string>(); - } - - if (vm.count("compare")) - { - _compare_filename = vm["compare"].as<std::string>(); - } - - if (vm.count("tflite")) - { - _tflite_filename = vm["tflite"].as<std::string>(); - - if (_tflite_filename.empty()) - { - // TODO Print usage instead of the below message - std::cerr << "Please specify tflite file. Run with `--help` for usage." - << "\n"; - - exit(1); - } - else - { - if (!boost::filesystem::exists(_tflite_filename)) - { - std::cerr << "tflite file not found: " << _tflite_filename << "\n"; - } - } - } -} - -} // end of namespace TFLiteRun diff --git a/tools/tflite_run/src/args.h b/tools/tflite_run/src/args.h deleted file mode 100644 index 7b270d4ee..000000000 --- a/tools/tflite_run/src/args.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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 __TFLITE_RUN_ARGS_H__ -#define __TFLITE_RUN_ARGS_H__ - -#include <string> -#include <boost/program_options.hpp> - -namespace po = boost::program_options; - -namespace TFLiteRun -{ - -class Args -{ -public: - Args(const int argc, char **argv); - void print(void); - - const std::string &getTFLiteFilename(void) const { return _tflite_filename; } - const std::string &getInputFilename(void) const { return _input_filename; } - const std::string &getDumpFilename(void) const { return _dump_filename; } - const std::string &getCompareFilename(void) const { return _compare_filename; } - -private: - void Initialize(); - void Parse(const int argc, char **argv); - -private: - po::positional_options_description _positional; - po::options_description _options; - - std::string _tflite_filename; - std::string _input_filename; - std::string _dump_filename; - std::string _compare_filename; -}; - -} // end of namespace TFLiteRun - -#endif // __TFLITE_RUN_ARGS_H__ diff --git a/tools/tflite_run/src/bin_image.cc b/tools/tflite_run/src/bin_image.cc deleted file mode 100644 index 16d4c94f7..000000000 --- a/tools/tflite_run/src/bin_image.cc +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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. - */ - -#include <iostream> -#include <fstream> - -#include "bin_image.h" - -BinImage::BinImage(unsigned int width, unsigned int height, unsigned int channels) - : _width(width), _height(height), _channels(channels) -{ -} - -BinImage::~BinImage() {} - -void BinImage::loadImage(const std::string &filename) -{ - std::ifstream fin(filename); - - if (!fin) - { - std::cerr << "image filename is not specified. " - << "Input image will not be set." << std::endl; - return; - } - - _image.reserve(_width * _height * _channels); - - // Assuption: binary image is stored in the order of [H,W,C] - for (unsigned int i = 0; i < _width * _height * _channels; ++i) - _image.push_back(fin.get()); -} - -void BinImage::AssignTensor(TfLiteTensor *t) -{ - float *p = t->data.f; - const int IMAGE_MEAN = 128; - const float IMAGE_STD = 128.0f; - - // to prevent runtime exception - if (_image.size() < _width * _height * _channels) - { - std::cerr << "Input image size is smaller than the size required by the model." - << " Input will not be set." << std::endl; - return; - } - - for (int x = 0; x < _width; ++x) - { - for (int y = 0; y < _height; ++y) - { - for (int c = 0; c < _channels; ++c) - { - *p++ = (_image[y * _width * _channels + x * _channels + c] - IMAGE_MEAN) / IMAGE_STD; - } - } - } -} diff --git a/tools/tflite_run/src/bin_image.h b/tools/tflite_run/src/bin_image.h deleted file mode 100644 index 845011be6..000000000 --- a/tools/tflite_run/src/bin_image.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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 __TFLITE_RUN_LIBJPEG_H__ -#define __TFLITE_RUN_LIBJPEG_H__ - -#include <string> -#include <vector> - -#include "tensorflow/contrib/lite/context.h" - -class BinImage -{ -public: - BinImage(unsigned int width, unsigned int height, unsigned int channel); - ~BinImage(); - - void loadImage(const std::string &filename); - - void AssignTensor(TfLiteTensor *t); - -private: - unsigned int _width; - unsigned int _height; - unsigned int _channels; - - std::vector<unsigned char> _image; -}; - -#endif // __TFLITE_RUN_LIBJPEG_H__ diff --git a/tools/tflite_run/src/tensor_dumper.cc b/tools/tflite_run/src/tensor_dumper.cc deleted file mode 100644 index 8568c9b67..000000000 --- a/tools/tflite_run/src/tensor_dumper.cc +++ /dev/null @@ -1,54 +0,0 @@ -#include "tensor_dumper.h" - -#include <fstream> -#include <iostream> -#include <cstring> - -#include "tensorflow/contrib/lite/interpreter.h" - -namespace TFLiteRun -{ - -TensorDumper::TensorDumper() -{ - // DO NOTHING -} - -void TensorDumper::addTensors(tflite::Interpreter &interpreter, const std::vector<int> &indices) -{ - for (const auto &o : indices) - { - const TfLiteTensor *tensor = interpreter.tensor(o); - int size = tensor->bytes; - std::vector<char> buffer; - buffer.resize(size); - memcpy(buffer.data(), tensor->data.raw, size); - _tensors.emplace_back(o, std::move(buffer)); - } -} - -void TensorDumper::dump(const std::string &filename) const -{ - // TODO Handle file open/write error - std::ofstream file(filename, std::ios::out | std::ios::binary); - - // Write number of tensors - uint32_t num_tensors = static_cast<uint32_t>(_tensors.size()); - file.write(reinterpret_cast<const char *>(&num_tensors), sizeof(num_tensors)); - - // Write tensor indices - for (const auto &t : _tensors) - { - file.write(reinterpret_cast<const char *>(&t._index), sizeof(int)); - } - - // Write data - for (const auto &t : _tensors) - { - file.write(t._data.data(), t._data.size()); - } - - file.close(); -} - -} // end of namespace TFLiteRun diff --git a/tools/tflite_run/src/tensor_dumper.h b/tools/tflite_run/src/tensor_dumper.h deleted file mode 100644 index 2805f1076..000000000 --- a/tools/tflite_run/src/tensor_dumper.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __TFLITE_RUN_TENSOR_DUMPER_H__ -#define __TFLITE_RUN_TENSOR_DUMPER_H__ - -#include <memory> -#include <string> -#include <vector> - -namespace tflite -{ -class Interpreter; -} - -namespace TFLiteRun -{ - -class TensorDumper -{ -private: - struct Tensor - { - int _index; - std::vector<char> _data; - - Tensor(int index, std::vector<char> &&data) : _index(index), _data(std::move(data)) {} - }; - -public: - TensorDumper(); - void addTensors(tflite::Interpreter &interpreter, const std::vector<int> &indices); - void dump(const std::string &filename) const; - -private: - std::vector<Tensor> _tensors; -}; - -} // end of namespace TFLiteRun - -#endif // __TFLITE_RUN_TENSOR_DUMPER_H__ diff --git a/tools/tflite_run/src/tensor_loader.cc b/tools/tflite_run/src/tensor_loader.cc deleted file mode 100644 index 678ff083e..000000000 --- a/tools/tflite_run/src/tensor_loader.cc +++ /dev/null @@ -1,67 +0,0 @@ -#include "tensor_loader.h" - -#include <assert.h> - -#include <fstream> - -#include "util/tensor/Shape.h" - -namespace TFLiteRun -{ - -TensorLoader::TensorLoader(tflite::Interpreter &interpreter) - : _interpreter(interpreter), _raw_data(nullptr) -{ -} - -void TensorLoader::load(const std::string &filename) -{ - // TODO Handle file open/read error - std::ifstream file(filename, std::ios::ate | std::ios::binary); - size_t file_size = file.tellg(); - file.seekg(0, std::ios::beg); - - uint32_t num_tensors = 0; - file.read(reinterpret_cast<char *>(&num_tensors), sizeof(num_tensors)); - - int tensor_indices_raw[num_tensors]; - file.read(reinterpret_cast<char *>(tensor_indices_raw), sizeof(tensor_indices_raw)); - std::vector<int> tensor_indices(tensor_indices_raw, tensor_indices_raw + num_tensors); - - _raw_data = std::unique_ptr<float>(new float[file_size]); - file.read(reinterpret_cast<char *>(_raw_data.get()), file_size); - - size_t offset = 0; - for (const auto &o : tensor_indices) - { - const TfLiteTensor *tensor = _interpreter.tensor(o); - - // Convert tensor shape to `Shape` from `tensor->dims` - nnfw::util::tensor::Shape shape(static_cast<size_t>(tensor->dims->size)); - for (int d = 0; d < tensor->dims->size; d++) - { - shape.dim(d) = tensor->dims->data[d]; - } - - float *base = _raw_data.get() + offset; - - assert(tensor->bytes % sizeof(float) == 0); - offset += (tensor->bytes / sizeof(float)); - - _tensor_map.insert(std::make_pair(o, nnfw::support::tflite::TensorView<float>(shape, base))); - } - - // The file size and total output tensor size must match - assert(file_size == sizeof(num_tensors) + sizeof(tensor_indices_raw) + offset * sizeof(float)); - - file.close(); -} - -const nnfw::support::tflite::TensorView<float> &TensorLoader::get(int tensor_idx) const -{ - auto found = _tensor_map.find(tensor_idx); - assert(found != _tensor_map.end()); - return found->second; -} - -} // end of namespace TFLiteRun diff --git a/tools/tflite_run/src/tensor_loader.h b/tools/tflite_run/src/tensor_loader.h deleted file mode 100644 index f2a699185..000000000 --- a/tools/tflite_run/src/tensor_loader.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __TFLITE_RUN_TENSOR_LOADER_H__ -#define __TFLITE_RUN_TENSOR_LOADER_H__ - -#include <sys/mman.h> - -#include <string> -#include <unordered_map> - -#include "support/tflite/TensorView.h" - -namespace tflite -{ -class Interpreter; -} - -namespace TFLiteRun -{ - -class TensorLoader -{ -public: - TensorLoader(tflite::Interpreter &interpreter); - void load(const std::string &filename); - const nnfw::support::tflite::TensorView<float> &get(int tensor_idx) const; - size_t getNums() const { return _tensor_map.size(); } - -private: - tflite::Interpreter &_interpreter; - std::unique_ptr<float> _raw_data; - std::unordered_map<int, nnfw::support::tflite::TensorView<float>> _tensor_map; -}; - -} // end of namespace TFLiteRun - -#endif // __TFLITE_RUN_TENSOR_LOADER_H__ diff --git a/tools/tflite_run/src/tflite_run.cc b/tools/tflite_run/src/tflite_run.cc deleted file mode 100644 index 23a23809b..000000000 --- a/tools/tflite_run/src/tflite_run.cc +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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. - */ - -#include "support/tflite/kernels/register.h" -#include "tensorflow/contrib/lite/model.h" - -#include "bin_image.h" -#include "args.h" -#include "tensor_dumper.h" -#include "tensor_loader.h" -#include "util/benchmark.h" -#include "util/environment.h" -#include "util/fp32.h" -#include "support/tflite/Diff.h" -#include "support/tflite/Assert.h" -#include "support/tflite/Session.h" -#include "support/tflite/InterpreterSession.h" -#include "support/tflite/NNAPISession.h" -#include "util/tensor/IndexIterator.h" - -#include <iostream> -#include <chrono> -#include <algorithm> - -using namespace tflite; -using namespace tflite::ops::builtin; - -void print_max_idx(float *f, int size) -{ - float *p = std::max_element(f, f + size); - std::cout << "max:" << p - f; -} - -int main(const int argc, char **argv) -{ - bool use_nnapi = false; - - if (std::getenv("USE_NNAPI") != nullptr) - { - use_nnapi = true; - } - - StderrReporter error_reporter; - - TFLiteRun::Args args(argc, argv); - - auto model = FlatBufferModel::BuildFromFile(args.getTFLiteFilename().c_str(), &error_reporter); - std::unique_ptr<Interpreter> interpreter; - - std::chrono::milliseconds t_prepare(0); - std::chrono::milliseconds t_invoke(0); - - nnfw::util::benchmark::measure(t_prepare) << [&](void) { - BuiltinOpResolver resolver; - - InterpreterBuilder builder(*model, resolver); - - TFLITE_ENSURE(builder(&interpreter)) - - interpreter->SetNumThreads(1); - }; - - std::shared_ptr<nnfw::support::tflite::Session> sess; - - if (use_nnapi) - { - sess = std::make_shared<nnfw::support::tflite::NNAPISession>(interpreter.get()); - } - else - { - sess = std::make_shared<nnfw::support::tflite::InterpreterSession>(interpreter.get()); - } - - sess->prepare(); - - TFLiteRun::TensorLoader tensor_loader(*interpreter); - - // Load input from image or dumped tensor file. Two options are exclusive and will be checked - // from Args. - if (args.getInputFilename().size() > 0) - { - BinImage image(299, 299, 3); - image.loadImage(args.getInputFilename()); - - for (const auto &o : interpreter->inputs()) - { - image.AssignTensor(interpreter->tensor(o)); - } - } - else if (!args.getCompareFilename().empty()) - { - tensor_loader.load(args.getCompareFilename()); - - for (const auto &o : interpreter->inputs()) - { - const auto &tensor_view = tensor_loader.get(o); - TfLiteTensor *tensor = interpreter->tensor(o); - - memcpy(reinterpret_cast<void *>(tensor->data.f), - reinterpret_cast<const void *>(tensor_view._base), tensor->bytes); - } - } - else - { - // No input specified. So we fill the input tensors with random values. - for (const auto &o : interpreter->inputs()) - { - TfLiteTensor *tensor = interpreter->tensor(o); - if (tensor->type == kTfLiteInt32) - { - // Generate singed 32-bit integer (s32) input - auto tensor_view = nnfw::support::tflite::TensorView<int32_t>::make(*interpreter, o); - - int32_t value = 0; - - nnfw::util::tensor::iterate(tensor_view.shape()) - << [&](const nnfw::util::tensor::Index &ind) { - // TODO Generate random values - // Gather operation: index should be within input coverage. - tensor_view.at(ind) = value; - value++; - }; - } - else if (tensor->type == kTfLiteUInt8) - { - // Generate unsigned 8-bit integer input - auto tensor_view = nnfw::support::tflite::TensorView<uint8_t>::make(*interpreter, o); - - uint8_t value = 0; - - nnfw::util::tensor::iterate(tensor_view.shape()) - << [&](const nnfw::util::tensor::Index &ind) { - // TODO Generate random values - tensor_view.at(ind) = value; - value = (value + 1) & 0xFF; - }; - } - else - { - assert(tensor->type == kTfLiteFloat32); - - const int seed = 1; /* TODO Add an option for seed value */ - RandomGenerator randgen{seed, 0.0f, 0.2f}; - const float *end = reinterpret_cast<const float *>(tensor->data.raw_const + tensor->bytes); - for (float *ptr = tensor->data.f; ptr < end; ptr++) - { - *ptr = randgen.generate<float>(); - } - } - } - } - - TFLiteRun::TensorDumper tensor_dumper; - // Must be called before `interpreter->Invoke()` - tensor_dumper.addTensors(*interpreter, interpreter->inputs()); - - std::cout << "input tensor indices = ["; - for (const auto &o : interpreter->inputs()) - { - std::cout << o << ","; - } - std::cout << "]" << std::endl; - - nnfw::util::benchmark::measure(t_invoke) << [&sess](void) { - if (!sess->run()) - { - assert(0 && "run failed!"); - } - }; - - sess->teardown(); - - // Must be called after `interpreter->Invoke()` - tensor_dumper.addTensors(*interpreter, interpreter->outputs()); - - std::cout << "output tensor indices = ["; - for (const auto &o : interpreter->outputs()) - { - std::cout << o << "("; - - print_max_idx(interpreter->tensor(o)->data.f, interpreter->tensor(o)->bytes / sizeof(float)); - - std::cout << "),"; - } - std::cout << "]" << std::endl; - - std::cout << "Prepare takes " << t_prepare.count() / 1000.0 << " seconds" << std::endl; - std::cout << "Invoke takes " << t_invoke.count() / 1000.0 << " seconds" << std::endl; - - if (!args.getDumpFilename().empty()) - { - const std::string &dump_filename = args.getDumpFilename(); - tensor_dumper.dump(dump_filename); - std::cout << "Input/output tensors have been dumped to file \"" << dump_filename << "\"." - << std::endl; - } - - if (!args.getCompareFilename().empty()) - { - const std::string &compare_filename = args.getCompareFilename(); - std::cout << "========================================" << std::endl; - std::cout << "Comparing the results with \"" << compare_filename << "\"." << std::endl; - std::cout << "========================================" << std::endl; - - // TODO Code duplication (copied from RandomTestRunner) - - int tolerance = 1; - nnfw::util::env::IntAccessor("TOLERANCE").access(tolerance); - - auto equals = [tolerance](float lhs, float rhs) { - // NOTE Hybrid approach - // TODO Allow users to set tolerance for absolute_epsilon_equal - if (nnfw::util::fp32::absolute_epsilon_equal(lhs, rhs)) - { - return true; - } - - return nnfw::util::fp32::epsilon_equal(lhs, rhs, tolerance); - }; - - nnfw::util::tensor::Comparator comparator(equals); - TfLiteInterpMatchApp app(comparator); - bool res = true; - - for (const auto &o : interpreter->outputs()) - { - auto expected = tensor_loader.get(o); - auto obtained = nnfw::support::tflite::TensorView<float>::make(*interpreter, o); - - res = res && app.compareSingleTensorView(expected, obtained, o); - } - - if (!res) - { - return 255; - } - } - - return 0; -} diff --git a/tools/tflite_run/src/tflite_test.cc b/tools/tflite_run/src/tflite_test.cc deleted file mode 100644 index d0d36c229..000000000 --- a/tools/tflite_run/src/tflite_test.cc +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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. - */ - -#include "gtest/gtest.h" - -TEST(TFLite_test_case, simple_test) { EXPECT_EQ(1, 1); } |