<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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 "paddle/framework/executor.h"

#include <memory>
#include <vector>

#include "gtest/gtest.h"
#include "paddle/framework/attribute.h"
#include "paddle/framework/backward.h"
#include "paddle/framework/block_desc.h"
#include "paddle/framework/op_desc.h"
#include "paddle/framework/op_registry.h"
#include "paddle/framework/operator.h"

USE_OP(elementwise_add);
USE_OP(gaussian_random);
USE_OP(feed);
USE_OP(fetch);
USE_OP(mul);
USE_OP(sum);
USE_OP(squared_l2_distance);
USE_OP(fill_constant);
USE_OP(sgd);

using namespace paddle::platform;
using namespace paddle::framework;

void AddOp(const std::string& type, const VariableNameMap& inputs,
           const VariableNameMap& outputs, AttributeMap attrs,
           paddle::framework::BlockDescBind* block) {
  // insert output
  for (auto kv : outputs) {
    for (auto v : kv.second) {
      auto var = block->NewVar(v);
      var->SetDataType(paddle::framework::DataType::FP32);
    }
  }

  // insert op
  auto op = block->AppendOp();
  op->SetType(type);
  for (auto& kv : inputs) {
    op->SetInput(kv.first, kv.second);
  }
  for (auto& kv : outputs) {
    op->SetOutput(kv.first, kv.second);
  }
  op->SetAttrMap(attrs);
  op->CheckAttrs();
}

// Tensors in feed value variable will only be in CPUPlace
// So we can memcpy the data from vector<T> to feed_value
template <typename T>
void SetFeedVariable(const std::vector<std::vector<T>>& inputs,
                     const std::vector<std::vector<int64_t>>& dims) {
  Variable* g_feed_value = GetGlobalScope().FindVar("feed_value");
  auto& feed_inputs =
      *(g_feed_value->GetMutable<std::vector<paddle::framework::Tensor>>());
  size_t size = inputs.size();
  feed_inputs.resize(size);
  for (size_t i = 0; i < size; i++) {
    T* dst = feed_inputs[i].mutable_data<T>(make_ddim(dims[i]), CPUPlace());
    memcpy(dst, inputs[i].data(), inputs[i].size() * sizeof(T));
  }
}

// Tensors in fetch value variable will only be in CPUPlace
// So we can memcpy the data from fetch_value to vector<T>
template <typename T>
std::vector<std::vector<T>> GetFetchVariable() {
  Variable* g_fetch_value = GetGlobalScope().FindVar("fetch_value");
  auto& fetch_outputs =
      *(g_fetch_value->GetMutable<std::vector<paddle::framework::Tensor>>());

  size_t size = fetch_outputs.size();
  std::vector<std::vector<T>> result;
  result.reserve(size);
  for (size_t i = 0; i < size; i++) {
    std::vector<T> tmp;
    tmp.resize(fetch_outputs[i].numel());
    memcpy(tmp.data(), fetch_outputs[i].data<T>(),
           fetch_outputs[i].numel() * sizeof(T));
    result.push_back(tmp);
  }

  return result;
}

class ExecutorTesterRandom : public ::testing::Test {
 public:
  virtual void SetUp() override {
    int input_dim = 3, batch_size = 2, embed_dim = 5;

    auto temp_init_root_block = init_pdesc_.add_blocks();
    temp_init_root_block->set_idx(0);
    temp_init_root_block->set_parent_idx(-1);
    paddle::framework::ProgramDescBind& init_program =
        paddle::framework::ProgramDescBind::Instance(&init_pdesc_);
    paddle::framework::BlockDescBind* init_root_block = init_program.Block(0);

    AddOp("gaussian_random", {}, {{"Out", {"w1"}}},
          {{"dims", std::vector<int>{input_dim, embed_dim}}}, init_root_block);
    AddOp("gaussian_random", {}, {{"Out", {"w2"}}},
          {{"dims", std::vector<int>{embed_dim, input_dim}}}, init_root_block);
    AddOp("fetch", {{"Input", {"w1"}}}, {}, {{"col", 0}}, init_root_block);
    AddOp("fetch", {{"Input", {"w2"}}}, {}, {{"col", 1}}, init_root_block);

    // flush
    init_program.Proto();

    // run block
    auto temp_root_block = pdesc_.add_blocks();
    temp_root_block->set_idx(0);
    temp_root_block->set_parent_idx(-1);
    paddle::framework::ProgramDescBind& program =
        paddle::framework::ProgramDescBind::Instance(&pdesc_);
    paddle::framework::BlockDescBind* root_block = program.Block(0);

    // feed data
    inputs_.push_back({1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
    dims_.push_back({batch_size, input_dim});
    AddOp("feed", {}, {{"Out", {"a"}}},
          {{"dims", std::vector<int>{batch_size, input_dim}}, {"col", 0}},
          root_block);

    // forward
    AddOp("mul", {{"X", {"a"}}, {"Y", {"w1"}}}, {{"Out", {"b"}}}, {},
          root_block);
    AddOp("mul", {{"X", {"b"}}, {"Y", {"w2"}}}, {{"Out", {"a_out"}}}, {},
          root_block);
    AddOp("squared_l2_distance", {{"X", {"a"}}, {"Y", {"a_out"}}},
          {{"Out", {"l2_distance"}}, {"sub_result", {"l2_distance_sub"}}}, {},
          root_block);

    // backward
    AddOp("fill_constant", {}, {{"Out", {"l2_distance@GRAD"}}},
          {{"shape", std::vector<int>{batch_size, 1}}, {"value", float(1.0)}},
          root_block);
    AppendBackward(program, {});

    // update
    AddOp("fill_constant", {}, {{"Out", {"learning_rate"}}},
          {{"shape", std::vector<int>{1}}, {"value", float(0.001)}},
          root_block);
    AddOp("sgd", {{"Param", {"w1"}},
                  {"LearningRate", {"learning_rate"}},
                  {"Grad", {"w1@GRAD"}}},
          {{"ParamOut", {"w1"}}}, {}, root_block);
    AddOp("sgd", {{"Param", {"w2"}},
                  {"LearningRate", {"learning_rate"}},
                  {"Grad", {"w2@GRAD"}}},
          {{"ParamOut", {"w2"}}}, {}, root_block);

    AddOp("fetch", {{"Input", {"w1"}}}, {}, {{"col", 0}}, root_block);
    AddOp("fetch", {{"Input", {"w2"}}}, {}, {{"col", 1}}, root_block);
    AddOp("fetch", {{"Input", {"l2_distance"}}}, {}, {{"col", 0}}, root_block);

    // flush
    program.Proto();
  }

 protected:
  ProgramDesc init_pdesc_;
  ProgramDesc pdesc_;
  std::vector<std::vector<float>> inputs_;
  std::vector<std::vector<int64_t>> dims_;
};

class ExecutorTesterFeedAndFetch : public ::testing::Test {
 public:
  virtual void SetUp() override {
    auto temp_root_block = pdesc_.add_blocks();
    temp_root_block->set_idx(0);
    temp_root_block->set_parent_idx(-1);

    // wrap to BlockDescBind
    paddle::framework::ProgramDescBind& program =
        paddle::framework::ProgramDescBind::Instance(&pdesc_);
    paddle::framework::BlockDescBind* root_block = program.Block(0);

    std::vector<int> dim{6};

    AddOp("feed", {}, {{"Out", {"a"}}}, {{"dims", dim}, {"col", 0}},
          root_block);
    AddOp("feed", {}, {{"Out", {"b"}}}, {{"dims", dim}, {"col", 1}},
          root_block);
    AddOp("fetch", {{"Input", {"a"}}}, {}, {{"col", 0}}, root_block);
    AddOp("fetch", {{"Input", {"b"}}}, {}, {{"col", 1}}, root_block);

    // flush
    program.Proto();

    std::vector<float> vec1 = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
    std::vector<float> vec2 = {4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
    inputs_.push_back(vec1);
    inputs_.push_back(vec2);
    dims_.push_back({static_cast<int64_t>(vec1.size())});
    dims_.push_back({static_cast<int64_t>(vec2.size())});
  }

 protected:
  ProgramDesc pdesc_;
  std::vector<std::vector<float>> inputs_;
  std::vector<std::vector<int64_t>> dims_;
};

#ifndef PADDLE_WITH_CUDA
TEST_F(ExecutorTesterRandom, CPU) {
  std::vector<Place> places;
  CPUPlace cpu_place;
  places.push_back(cpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  paddle::memory::Used(cpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  executor->Run(init_pdesc_, &GetGlobalScope(), 0);
  SetFeedVariable<float>(inputs_, dims_);
  executor->Run(pdesc_, &GetGlobalScope(), 0);
  std::vector<std::vector<float>> result = GetFetchVariable<float>();
}

TEST_F(ExecutorTesterFeedAndFetch, CPU) {
  std::vector<Place> places;
  CPUPlace cpu_place;
  places.push_back(cpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  paddle::memory::Used(cpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  for (int batch_id = 0; batch_id < 3; batch_id++) {
    SetFeedVariable<float>(inputs_, dims_);
    executor->Run(pdesc_, &GetGlobalScope(), 0);
    std::vector<std::vector<float>> result = GetFetchVariable<float>();
    PADDLE_ENFORCE_EQ(result.size(), inputs_.size());
    for (size_t i = 0; i < result.size(); ++i) {
      PADDLE_ENFORCE_EQ(result[i].size(), inputs_[i].size());
      for (size_t j = 0; j < result[i].size(); ++j) {
        PADDLE_ENFORCE_EQ(result[i][j], inputs_[i][j]);
      }
    }
  }
}
#else
TEST_F(ExecutorTesterRandom, GPU) {
  std::vector<Place> places;
  GPUPlace gpu_place(0);
  places.push_back(gpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  // If paddle is compiled with GPU, both CPU and GPU BuddyAllocator
  // need to be used at first.
  paddle::memory::Used(CPUPlace());
  paddle::memory::Used(gpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  executor->Run(init_pdesc_, &GetGlobalScope(), 0);
  for (int batch_id = 0; batch_id < 3; batch_id++) {
    SetFeedVariable<float>(inputs_, dims_);
    executor->Run(pdesc_, &GetGlobalScope(), 0);
  }
}

TEST_F(ExecutorTesterFeedAndFetch, GPU) {
  std::vector<Place> places;
  GPUPlace gpu_place(0);
  places.push_back(gpu_place);
  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  // If paddle is compiled with GPU, both CPU and GPU BuddyAllocator
  // need to be used at first.
  paddle::memory::Used(CPUPlace());
  paddle::memory::Used(gpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  for (int batch_id = 0; batch_id < 3; batch_id++) {
    SetFeedVariable<float>(inputs_, dims_);
    executor->Run(pdesc_, &GetGlobalScope(), 0);
    std::vector<std::vector<float>> result = GetFetchVariable<float>();
    PADDLE_ENFORCE_EQ(result.size(), inputs_.size());
    for (size_t i = 0; i < result.size(); ++i) {
      PADDLE_ENFORCE_EQ(result[i].size(), inputs_[i].size());
      for (size_t j = 0; j < result[i].size(); ++j) {
        PADDLE_ENFORCE_EQ(result[i][j], inputs_[i][j]);
      }
    }
  }
}
#endif
<commit_msg>Stablize executor_test (#4774)<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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 "paddle/framework/executor.h"

#include <memory>
#include <vector>

#include "gflags/gflags.h"
#include "gtest/gtest.h"
#include "paddle/framework/attribute.h"
#include "paddle/framework/backward.h"
#include "paddle/framework/block_desc.h"
#include "paddle/framework/op_desc.h"
#include "paddle/framework/op_registry.h"
#include "paddle/framework/operator.h"

USE_OP(elementwise_add);
USE_OP(gaussian_random);
USE_OP(feed);
USE_OP(fetch);
USE_OP(mul);
USE_OP(sum);
USE_OP(squared_l2_distance);
USE_OP(fill_constant);
USE_OP(sgd);

using namespace paddle::platform;
using namespace paddle::framework;

void AddOp(const std::string& type, const VariableNameMap& inputs,
           const VariableNameMap& outputs, AttributeMap attrs,
           paddle::framework::BlockDescBind* block) {
  // insert output
  for (auto kv : outputs) {
    for (auto v : kv.second) {
      auto var = block->NewVar(v);
      var->SetDataType(paddle::framework::DataType::FP32);
    }
  }

  // insert op
  auto op = block->AppendOp();
  op->SetType(type);
  for (auto& kv : inputs) {
    op->SetInput(kv.first, kv.second);
  }
  for (auto& kv : outputs) {
    op->SetOutput(kv.first, kv.second);
  }
  op->SetAttrMap(attrs);
  op->CheckAttrs();
}

// Tensors in feed value variable will only be in CPUPlace
// So we can memcpy the data from vector<T> to feed_value
template <typename T>
void SetFeedVariable(const std::vector<std::vector<T>>& inputs,
                     const std::vector<std::vector<int64_t>>& dims) {
  Variable* g_feed_value = GetGlobalScope().FindVar("feed_value");
  auto& feed_inputs =
      *(g_feed_value->GetMutable<std::vector<paddle::framework::Tensor>>());
  size_t size = inputs.size();
  feed_inputs.resize(size);
  for (size_t i = 0; i < size; i++) {
    T* dst = feed_inputs[i].mutable_data<T>(make_ddim(dims[i]), CPUPlace());
    memcpy(dst, inputs[i].data(), inputs[i].size() * sizeof(T));
  }
}

// Tensors in fetch value variable will only be in CPUPlace
// So we can memcpy the data from fetch_value to vector<T>
template <typename T>
std::vector<std::vector<T>> GetFetchVariable() {
  Variable* g_fetch_value = GetGlobalScope().FindVar("fetch_value");
  auto& fetch_outputs =
      *(g_fetch_value->GetMutable<std::vector<paddle::framework::Tensor>>());

  size_t size = fetch_outputs.size();
  std::vector<std::vector<T>> result;
  result.reserve(size);
  for (size_t i = 0; i < size; i++) {
    std::vector<T> tmp;
    tmp.resize(fetch_outputs[i].numel());
    memcpy(tmp.data(), fetch_outputs[i].data<T>(),
           fetch_outputs[i].numel() * sizeof(T));
    result.push_back(tmp);
  }

  return result;
}

class ExecutorTesterRandom : public ::testing::Test {
 public:
  virtual void SetUp() override {
    int input_dim = 3, batch_size = 2, embed_dim = 5;

    auto temp_init_root_block = init_pdesc_.add_blocks();
    temp_init_root_block->set_idx(0);
    temp_init_root_block->set_parent_idx(-1);
    paddle::framework::ProgramDescBind& init_program =
        paddle::framework::ProgramDescBind::Instance(&init_pdesc_);
    paddle::framework::BlockDescBind* init_root_block = init_program.Block(0);

    AddOp("gaussian_random", {}, {{"Out", {"w1"}}},
          {{"dims", std::vector<int>{input_dim, embed_dim}}}, init_root_block);
    AddOp("gaussian_random", {}, {{"Out", {"w2"}}},
          {{"dims", std::vector<int>{embed_dim, input_dim}}}, init_root_block);
    AddOp("fetch", {{"Input", {"w1"}}}, {}, {{"col", 0}}, init_root_block);
    AddOp("fetch", {{"Input", {"w2"}}}, {}, {{"col", 1}}, init_root_block);

    // flush
    init_program.Proto();

    // run block
    auto temp_root_block = pdesc_.add_blocks();
    temp_root_block->set_idx(0);
    temp_root_block->set_parent_idx(-1);
    paddle::framework::ProgramDescBind& program =
        paddle::framework::ProgramDescBind::Instance(&pdesc_);
    paddle::framework::BlockDescBind* root_block = program.Block(0);

    // feed data
    inputs_.push_back({1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
    dims_.push_back({batch_size, input_dim});
    AddOp("feed", {}, {{"Out", {"a"}}},
          {{"dims", std::vector<int>{batch_size, input_dim}}, {"col", 0}},
          root_block);

    // forward
    AddOp("mul", {{"X", {"a"}}, {"Y", {"w1"}}}, {{"Out", {"b"}}}, {},
          root_block);
    AddOp("mul", {{"X", {"b"}}, {"Y", {"w2"}}}, {{"Out", {"a_out"}}}, {},
          root_block);
    AddOp("squared_l2_distance", {{"X", {"a"}}, {"Y", {"a_out"}}},
          {{"Out", {"l2_distance"}}, {"sub_result", {"l2_distance_sub"}}}, {},
          root_block);

    // backward
    AddOp("fill_constant", {}, {{"Out", {"l2_distance@GRAD"}}},
          {{"shape", std::vector<int>{batch_size, 1}}, {"value", float(1.0)}},
          root_block);
    AppendBackward(program, {});

    // update
    AddOp("fill_constant", {}, {{"Out", {"learning_rate"}}},
          {{"shape", std::vector<int>{1}}, {"value", float(0.001)}},
          root_block);
    AddOp("sgd", {{"Param", {"w1"}},
                  {"LearningRate", {"learning_rate"}},
                  {"Grad", {"w1@GRAD"}}},
          {{"ParamOut", {"w1"}}}, {}, root_block);
    AddOp("sgd", {{"Param", {"w2"}},
                  {"LearningRate", {"learning_rate"}},
                  {"Grad", {"w2@GRAD"}}},
          {{"ParamOut", {"w2"}}}, {}, root_block);

    AddOp("fetch", {{"Input", {"w1"}}}, {}, {{"col", 0}}, root_block);
    AddOp("fetch", {{"Input", {"w2"}}}, {}, {{"col", 1}}, root_block);
    AddOp("fetch", {{"Input", {"l2_distance"}}}, {}, {{"col", 0}}, root_block);

    // flush
    program.Proto();
  }

 protected:
  ProgramDesc init_pdesc_;
  ProgramDesc pdesc_;
  std::vector<std::vector<float>> inputs_;
  std::vector<std::vector<int64_t>> dims_;
};

class ExecutorTesterFeedAndFetch : public ::testing::Test {
 public:
  virtual void SetUp() override {
    auto temp_root_block = pdesc_.add_blocks();
    temp_root_block->set_idx(0);
    temp_root_block->set_parent_idx(-1);

    // wrap to BlockDescBind
    paddle::framework::ProgramDescBind& program =
        paddle::framework::ProgramDescBind::Instance(&pdesc_);
    paddle::framework::BlockDescBind* root_block = program.Block(0);

    std::vector<int> dim{6};

    AddOp("feed", {}, {{"Out", {"a"}}}, {{"dims", dim}, {"col", 0}},
          root_block);
    AddOp("feed", {}, {{"Out", {"b"}}}, {{"dims", dim}, {"col", 1}},
          root_block);
    AddOp("fetch", {{"Input", {"a"}}}, {}, {{"col", 0}}, root_block);
    AddOp("fetch", {{"Input", {"b"}}}, {}, {{"col", 1}}, root_block);

    // flush
    program.Proto();

    std::vector<float> vec1 = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
    std::vector<float> vec2 = {4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
    inputs_.push_back(vec1);
    inputs_.push_back(vec2);
    dims_.push_back({static_cast<int64_t>(vec1.size())});
    dims_.push_back({static_cast<int64_t>(vec2.size())});
  }

 protected:
  ProgramDesc pdesc_;
  std::vector<std::vector<float>> inputs_;
  std::vector<std::vector<int64_t>> dims_;
};

#ifndef PADDLE_WITH_CUDA
TEST_F(ExecutorTesterRandom, CPU) {
  std::vector<Place> places;
  CPUPlace cpu_place;
  places.push_back(cpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  paddle::memory::Used(cpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  executor->Run(init_pdesc_, &GetGlobalScope(), 0);
  SetFeedVariable<float>(inputs_, dims_);
  executor->Run(pdesc_, &GetGlobalScope(), 0);
  std::vector<std::vector<float>> result = GetFetchVariable<float>();
}

TEST_F(ExecutorTesterFeedAndFetch, CPU) {
  std::vector<Place> places;
  CPUPlace cpu_place;
  places.push_back(cpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  paddle::memory::Used(cpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  for (int batch_id = 0; batch_id < 3; batch_id++) {
    SetFeedVariable<float>(inputs_, dims_);
    executor->Run(pdesc_, &GetGlobalScope(), 0);
    std::vector<std::vector<float>> result = GetFetchVariable<float>();
    PADDLE_ENFORCE_EQ(result.size(), inputs_.size());
    for (size_t i = 0; i < result.size(); ++i) {
      PADDLE_ENFORCE_EQ(result[i].size(), inputs_[i].size());
      for (size_t j = 0; j < result[i].size(); ++j) {
        PADDLE_ENFORCE_EQ(result[i][j], inputs_[i][j]);
      }
    }
  }
}
#else
TEST_F(ExecutorTesterRandom, GPU) {
  std::vector<Place> places;
  GPUPlace gpu_place(0);
  places.push_back(gpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  // If paddle is compiled with GPU, both CPU and GPU BuddyAllocator
  // need to be used at first.
  paddle::memory::Used(CPUPlace());
  paddle::memory::Used(gpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  executor->Run(init_pdesc_, &GetGlobalScope(), 0);
  for (int batch_id = 0; batch_id < 3; batch_id++) {
    SetFeedVariable<float>(inputs_, dims_);
    executor->Run(pdesc_, &GetGlobalScope(), 0);
  }
}

TEST_F(ExecutorTesterFeedAndFetch, GPU) {
  std::vector<Place> places;
  GPUPlace gpu_place(0);
  places.push_back(gpu_place);
  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  // If paddle is compiled with GPU, both CPU and GPU BuddyAllocator
  // need to be used at first.
  paddle::memory::Used(CPUPlace());
  paddle::memory::Used(gpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  for (int batch_id = 0; batch_id < 3; batch_id++) {
    SetFeedVariable<float>(inputs_, dims_);
    executor->Run(pdesc_, &GetGlobalScope(), 0);
    std::vector<std::vector<float>> result = GetFetchVariable<float>();
    PADDLE_ENFORCE_EQ(result.size(), inputs_.size());
    for (size_t i = 0; i < result.size(); ++i) {
      PADDLE_ENFORCE_EQ(result[i].size(), inputs_[i].size());
      for (size_t j = 0; j < result[i].size(); ++j) {
        PADDLE_ENFORCE_EQ(result[i][j], inputs_[i][j]);
      }
    }
  }
}
#endif

DECLARE_double(fraction_of_gpu_memory_to_use);

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  // Use less GPU memory for unittest.
  FLAGS_fraction_of_gpu_memory_to_use = 0.25;
  return RUN_ALL_TESTS();
}<|endoftext|>


<commit_before>#include "testplugin.hpp"
#include <QOpenGLExtraFunctions>
#include <QOpenGLShaderProgram>
#include <QQmlComponent>
#include <QQuickItem>

bool TestPlugin::init(QOpenGLExtraFunctions* f, QQmlEngine* qmlEngine) {
    Q_UNUSED(f)

    Q_INIT_RESOURCE(testplugin);

    shader = new QOpenGLShaderProgram;

    shader->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/glsl/plugin.vsh");
    shader->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/glsl/plugin.fsh");

    shader->link();

    /* Bind so we set the texture sampler uniform values. */
    shader->bind();

    /* Left image is TEXTURE0. */
    shader->setUniformValue("textureL", 0);
    /* Right image is TEXTURE1. */
    shader->setUniformValue("textureR", 1);

    QQmlComponent component(qmlEngine);

    component.loadUrl(QUrl(QStringLiteral("qrc:/TestPlugin/Config.qml")));

    /* Wait for it to load... */
    while(component.isLoading());

    /* The program can't run if there was an error. */
    if (component.isError()) {
        qDebug(qPrintable(component.errorString()));
        return false;
    }

    configMenuObject = qobject_cast<QQuickItem*>(component.create());

    /* Critical error! abort! abort! */
    if (configMenuObject == nullptr)
        return false;

    logRenderStart = QQmlProperty(configMenuObject, "logRenderStart");
    logRenderEnd = QQmlProperty(configMenuObject, "logRenderEnd");
    logFrameSwap = QQmlProperty(configMenuObject, "logFrameSwap");

    qDebug("inited");

    return true;
}

bool TestPlugin::deinit() {
    delete shader;

    qDebug("deinited");

    return true;
}

bool TestPlugin::render(const QString& drawModeName, QOpenGLExtraFunctions* f) {
    Q_UNUSED(drawModeName)

    if (logRenderStart.isValid() && logRenderStart.read().toBool())
        qDebug("Plugin rendering start.");

    /* This is just the default fullscreen quad from the built-in modes. */
    shader->bind();

    static const float quad[] {
       -1.0f,-1.0f,
        1.0f,-1.0f,
        1.0f, 1.0f,
       -1.0f, 1.0f
    };

    static const float quadUV[] {
        0.0f, 0.0f,
        1.0f, 0.0f,
        1.0f, 1.0f,
        0.0f, 1.0f
    };

    /* Enable the vertex and UV arrays, must be done every frame because of QML resetting things. */
    f->glEnableVertexAttribArray(0);
    f->glEnableVertexAttribArray(1);

    f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, quad);
    f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, quadUV);

    f->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

    if (logRenderEnd.isValid() && logRenderEnd.read().toBool())
        qDebug("Plugin rendering end.");

    return true;
}

void TestPlugin::frameSwapped(QOpenGLExtraFunctions* f) {
    Q_UNUSED(f)

    if (logFrameSwap.isValid() && logFrameSwap.read().toBool())
        qDebug("Plugin frame swapped.");
}

QStringList TestPlugin::drawModeNames() {
    return QStringList("Test Plugin Mode");
}

QQuickItem* TestPlugin::getConfigMenuObject() {
    return configMenuObject;
}

bool TestPlugin::shouldLockMouse() {
    return false;
}

QSize TestPlugin::getRenderSize(const QSize& windowSize) {
    return windowSize;
}

<commit_msg>Missed TestPlugin shader paths in 2212674.<commit_after>#include "testplugin.hpp"
#include <QOpenGLExtraFunctions>
#include <QOpenGLShaderProgram>
#include <QQmlComponent>
#include <QQuickItem>

bool TestPlugin::init(QOpenGLExtraFunctions* f, QQmlEngine* qmlEngine) {
    Q_UNUSED(f)

    Q_INIT_RESOURCE(testplugin);

    shader = new QOpenGLShaderProgram;

    shader->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/TestPlugin/glsl/plugin.vsh");
    shader->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/TestPlugin/glsl/plugin.fsh");

    shader->link();

    /* Bind so we set the texture sampler uniform values. */
    shader->bind();

    /* Left image is TEXTURE0. */
    shader->setUniformValue("textureL", 0);
    /* Right image is TEXTURE1. */
    shader->setUniformValue("textureR", 1);

    QQmlComponent component(qmlEngine);

    component.loadUrl(QUrl(QStringLiteral("qrc:/TestPlugin/Config.qml")));

    /* Wait for it to load... */
    while(component.isLoading());

    /* The program can't run if there was an error. */
    if (component.isError()) {
        qDebug(qPrintable(component.errorString()));
        return false;
    }

    configMenuObject = qobject_cast<QQuickItem*>(component.create());

    /* Critical error! abort! abort! */
    if (configMenuObject == nullptr)
        return false;

    logRenderStart = QQmlProperty(configMenuObject, "logRenderStart");
    logRenderEnd = QQmlProperty(configMenuObject, "logRenderEnd");
    logFrameSwap = QQmlProperty(configMenuObject, "logFrameSwap");

    qDebug("inited");

    return true;
}

bool TestPlugin::deinit() {
    delete shader;

    qDebug("deinited");

    return true;
}

bool TestPlugin::render(const QString& drawModeName, QOpenGLExtraFunctions* f) {
    Q_UNUSED(drawModeName)

    if (logRenderStart.isValid() && logRenderStart.read().toBool())
        qDebug("Plugin rendering start.");

    /* This is just the default fullscreen quad from the built-in modes. */
    shader->bind();

    static const float quad[] {
       -1.0f,-1.0f,
        1.0f,-1.0f,
        1.0f, 1.0f,
       -1.0f, 1.0f
    };

    static const float quadUV[] {
        0.0f, 0.0f,
        1.0f, 0.0f,
        1.0f, 1.0f,
        0.0f, 1.0f
    };

    /* Enable the vertex and UV arrays, must be done every frame because of QML resetting things. */
    f->glEnableVertexAttribArray(0);
    f->glEnableVertexAttribArray(1);

    f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, quad);
    f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, quadUV);

    f->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

    if (logRenderEnd.isValid() && logRenderEnd.read().toBool())
        qDebug("Plugin rendering end.");

    return true;
}

void TestPlugin::frameSwapped(QOpenGLExtraFunctions* f) {
    Q_UNUSED(f)

    if (logFrameSwap.isValid() && logFrameSwap.read().toBool())
        qDebug("Plugin frame swapped.");
}

QStringList TestPlugin::drawModeNames() {
    return QStringList("Test Plugin Mode");
}

QQuickItem* TestPlugin::getConfigMenuObject() {
    return configMenuObject;
}

bool TestPlugin::shouldLockMouse() {
    return false;
}

QSize TestPlugin::getRenderSize(const QSize& windowSize) {
    return windowSize;
}

<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/gfx/rect.h"
#include "base/sys_info.h"
#include "base/string_util.h"
#include "chrome/renderer/render_process.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

class RenderProcessTest : public testing::Test {
 public:
  virtual void SetUp() {
    RenderProcess::GlobalInit(L"render_process_unittest");
  }

  virtual void TearDown() {
    RenderProcess::GlobalCleanup();
  }

  private:
   MessageLoopForIO message_loop_;
};

TEST_F(RenderProcessTest, TestTransportDIBAllocation) {
  const gfx::Rect rect(0, 0, 100, 100);
  TransportDIB* dib;
  skia::PlatformCanvas* canvas = RenderProcess::GetDrawingCanvas(&dib, rect);
  ASSERT_TRUE(dib);
  ASSERT_TRUE(canvas);
  RenderProcess::ReleaseTransportDIB(dib);
  delete canvas;
}

}  // namespace
<commit_msg>Unit tests fix<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/gfx/rect.h"
#include "base/sys_info.h"
#include "base/string_util.h"
#include "chrome/renderer/render_process.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

class RenderProcessTest : public testing::Test {
 public:
  virtual void SetUp() {
    RenderProcess::GlobalInit(L"render_process_unittest");
  }

  virtual void TearDown() {
    RenderProcess::GlobalCleanup();
  }

  private:
   MessageLoopForIO message_loop_;
};

TEST_F(RenderProcessTest, TestTransportDIBAllocation) {
  // On Mac, we allocate in the browser so this test is invalid.
#if !defined(OS_MACOSX)
  const gfx::Rect rect(0, 0, 100, 100);
  TransportDIB* dib;
  skia::PlatformCanvas* canvas = RenderProcess::GetDrawingCanvas(&dib, rect);
  ASSERT_TRUE(dib);
  ASSERT_TRUE(canvas);
  RenderProcess::ReleaseTransportDIB(dib);
  delete canvas;
#endif
}

}  // namespace
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/renderer/spellchecker/spellcheck.h"

#include "base/file_util.h"
#include "base/metrics/histogram.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/spellcheck_common.h"
#include "chrome/common/spellcheck_messages.h"
#include "content/public/renderer/render_thread.h"
#include "third_party/hunspell/src/hunspell/hunspell.hxx"

using base::TimeTicks;
using content::RenderThread;

SpellCheck::SpellCheck()
    : file_(base::kInvalidPlatformFileValue),
      auto_spell_correct_turned_on_(false),
      is_using_platform_spelling_engine_(false),
      initialized_(false) {
  // Wait till we check the first word before doing any initializing.
}

SpellCheck::~SpellCheck() {
}

bool SpellCheck::OnControlMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(SpellCheck, message)
    IPC_MESSAGE_HANDLER(SpellCheckMsg_Init, OnInit)
    IPC_MESSAGE_HANDLER(SpellCheckMsg_WordAdded, OnWordAdded)
    IPC_MESSAGE_HANDLER(SpellCheckMsg_EnableAutoSpellCorrect,
                        OnEnableAutoSpellCorrect)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()

  return handled;
}

void SpellCheck::OnInit(IPC::PlatformFileForTransit bdict_file,
                        const std::vector<std::string>& custom_words,
                        const std::string& language,
                        bool auto_spell_correct) {
  Init(IPC::PlatformFileForTransitToPlatformFile(bdict_file),
       custom_words, language);
  auto_spell_correct_turned_on_ = auto_spell_correct;
}

void SpellCheck::OnWordAdded(const std::string& word) {
  if (is_using_platform_spelling_engine_)
    return;

  if (!hunspell_.get()) {
    // Save it for later---add it when hunspell is initialized.
    custom_words_.push_back(word);
  } else {
    AddWordToHunspell(word);
  }
}

void SpellCheck::OnEnableAutoSpellCorrect(bool enable) {
  auto_spell_correct_turned_on_ = enable;
}

void SpellCheck::Init(base::PlatformFile file,
                      const std::vector<std::string>& custom_words,
                      const std::string& language) {
  initialized_ = true;
  hunspell_.reset();
  bdict_file_.reset();
  file_ = file;
  is_using_platform_spelling_engine_ =
      file == base::kInvalidPlatformFileValue && !language.empty();

  character_attributes_.SetDefaultLanguage(language);

  custom_words_.insert(custom_words_.end(),
                       custom_words.begin(), custom_words.end());

  // We delay the actual initialization of hunspell until it is needed.
}

bool SpellCheck::SpellCheckWord(
    const char16* in_word,
    int in_word_len,
    int tag,
    int* misspelling_start,
    int* misspelling_len,
    std::vector<string16>* optional_suggestions) {
  DCHECK(in_word_len >= 0);
  DCHECK(misspelling_start && misspelling_len) << "Out vars must be given.";

  // Do nothing if we need to delay initialization. (Rather than blocking,
  // report the word as correctly spelled.)
  if (InitializeIfNeeded())
    return true;

  // Do nothing if spell checking is disabled.
  if (initialized_ && file_ == base::kInvalidPlatformFileValue &&
      !is_using_platform_spelling_engine_) {
    return true;
  }

  *misspelling_start = 0;
  *misspelling_len = 0;
  if (in_word_len == 0)
    return true;  // No input means always spelled correctly.

  string16 word;
  int word_start;
  int word_length;
  if (!text_iterator_.IsInitialized())
    text_iterator_.Initialize(&character_attributes_, true);
  text_iterator_.SetText(in_word, in_word_len);
  while (text_iterator_.GetNextWord(&word, &word_start, &word_length)) {
    // Found a word (or a contraction) that the spellchecker can check the
    // spelling of.
    if (CheckSpelling(word, tag))
      continue;

    // If the given word is a concatenated word of two or more valid words
    // (e.g. "hello:hello"), we should treat it as a valid word.
    if (IsValidContraction(word, tag))
      continue;

    *misspelling_start = word_start;
    *misspelling_len = word_length;

    // Get the list of suggested words.
    if (optional_suggestions)
      FillSuggestionList(word, optional_suggestions);
    return false;
  }

  return true;
}

string16 SpellCheck::GetAutoCorrectionWord(const string16& word, int tag) {
  string16 autocorrect_word;
  if (!auto_spell_correct_turned_on_)
    return autocorrect_word;  // Return the empty string.

  int word_length = static_cast<int>(word.size());
  if (word_length < 2 || word_length > SpellCheckCommon::kMaxAutoCorrectWordSize)
    return autocorrect_word;

  if (InitializeIfNeeded())
    return autocorrect_word;

  char16 misspelled_word[SpellCheckCommon::kMaxAutoCorrectWordSize + 1];
  const char16* word_char = word.c_str();
  for (int i = 0; i <= SpellCheckCommon::kMaxAutoCorrectWordSize; i++) {
    if (i >= word_length)
      misspelled_word[i] = 0;
    else
      misspelled_word[i] = word_char[i];
  }

  // Swap adjacent characters and spellcheck.
  int misspelling_start, misspelling_len;
  for (int i = 0; i < word_length - 1; i++) {
    // Swap.
    std::swap(misspelled_word[i], misspelled_word[i + 1]);

    // Check spelling.
    misspelling_start = misspelling_len = 0;
    SpellCheckWord(misspelled_word, word_length, tag, &misspelling_start,
        &misspelling_len, NULL);

    // Make decision: if only one swap produced a valid word, then we want to
    // return it. If we found two or more, we don't do autocorrection.
    if (misspelling_len == 0) {
      if (autocorrect_word.empty()) {
        autocorrect_word.assign(misspelled_word);
      } else {
        autocorrect_word.clear();
        break;
      }
    }

    // Restore the swapped characters.
    std::swap(misspelled_word[i], misspelled_word[i + 1]);
  }
  return autocorrect_word;
}

void SpellCheck::InitializeHunspell() {
  if (hunspell_.get())
    return;

  bdict_file_.reset(new file_util::MemoryMappedFile);

  if (bdict_file_->Initialize(file_)) {
    TimeTicks debug_start_time = base::Histogram::DebugNow();

    hunspell_.reset(
        new Hunspell(bdict_file_->data(), bdict_file_->length()));

    // Add custom words to Hunspell.
    for (std::vector<std::string>::iterator it = custom_words_.begin();
         it != custom_words_.end(); ++it) {
      AddWordToHunspell(*it);
    }

    DHISTOGRAM_TIMES("Spellcheck.InitTime",
                     base::Histogram::DebugNow() - debug_start_time);
  } else {
    NOTREACHED() << "Could not mmap spellchecker dictionary.";
  }
}

void SpellCheck::AddWordToHunspell(const std::string& word) {
  if (!word.empty() && word.length() < MAXWORDUTF8LEN)
    hunspell_->add(word.c_str());
}

bool SpellCheck::InitializeIfNeeded() {
  if (is_using_platform_spelling_engine_)
    return false;

  if (!initialized_) {
    RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary);
    initialized_ = true;
    return true;
  }

  // Don't initialize if hunspell is disabled.
  if (file_ != base::kInvalidPlatformFileValue)
    InitializeHunspell();

  return false;
}

// When called, relays the request to check the spelling to the proper
// backend, either hunspell or a platform-specific backend.
bool SpellCheck::CheckSpelling(const string16& word_to_check, int tag) {
  bool word_correct = false;

  if (is_using_platform_spelling_engine_) {
    RenderThread::Get()->Send(new SpellCheckHostMsg_PlatformCheckSpelling(
        word_to_check, tag, &word_correct));
  } else {
    std::string word_to_check_utf8(UTF16ToUTF8(word_to_check));
    // Hunspell shouldn't let us exceed its max, but check just in case
    if (word_to_check_utf8.length() < MAXWORDUTF8LEN) {
      if (hunspell_.get()) {
        // |hunspell_->spell| returns 0 if the word is spelled correctly and
        // non-zero otherwsie.
        word_correct = (hunspell_->spell(word_to_check_utf8.c_str()) != 0);
      } else {
        // If |hunspell_| is NULL here, an error has occurred, but it's better
        // to check rather than crash.
        word_correct = true;
      }
    }
  }

  return word_correct;
}

void SpellCheck::FillSuggestionList(
    const string16& wrong_word,
    std::vector<string16>* optional_suggestions) {
  if (is_using_platform_spelling_engine_) {
    RenderThread::Get()->Send(new SpellCheckHostMsg_PlatformFillSuggestionList(
        wrong_word, optional_suggestions));
    return;
  }

  // If |hunspell_| is NULL here, an error has occurred, but it's better
  // to check rather than crash.
  if (!hunspell_.get())
    return;

  char** suggestions;
  int number_of_suggestions =
      hunspell_->suggest(&suggestions, UTF16ToUTF8(wrong_word).c_str());

  // Populate the vector of WideStrings.
  for (int i = 0; i < number_of_suggestions; i++) {
    if (i < SpellCheckCommon::kMaxSuggestions)
      optional_suggestions->push_back(UTF8ToUTF16(suggestions[i]));
    free(suggestions[i]);
  }
  if (suggestions != NULL)
    free(suggestions);
}

// Returns whether or not the given string is a valid contraction.
// This function is a fall-back when the SpellcheckWordIterator class
// returns a concatenated word which is not in the selected dictionary
// (e.g. "in'n'out") but each word is valid.
bool SpellCheck::IsValidContraction(const string16& contraction, int tag) {
  if (!contraction_iterator_.IsInitialized())
    contraction_iterator_.Initialize(&character_attributes_, false);
  contraction_iterator_.SetText(contraction.c_str(), contraction.length());

  string16 word;
  int word_start;
  int word_length;
  while (contraction_iterator_.GetNextWord(&word, &word_start, &word_length)) {
    if (!CheckSpelling(word, tag))
      return false;
  }
  return true;
}
<commit_msg>Do not crash if SpellcheckWordIterator fails to initialize.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/renderer/spellchecker/spellcheck.h"

#include "base/file_util.h"
#include "base/metrics/histogram.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/spellcheck_common.h"
#include "chrome/common/spellcheck_messages.h"
#include "content/public/renderer/render_thread.h"
#include "third_party/hunspell/src/hunspell/hunspell.hxx"

using base::TimeTicks;
using content::RenderThread;

SpellCheck::SpellCheck()
    : file_(base::kInvalidPlatformFileValue),
      auto_spell_correct_turned_on_(false),
      is_using_platform_spelling_engine_(false),
      initialized_(false) {
  // Wait till we check the first word before doing any initializing.
}

SpellCheck::~SpellCheck() {
}

bool SpellCheck::OnControlMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(SpellCheck, message)
    IPC_MESSAGE_HANDLER(SpellCheckMsg_Init, OnInit)
    IPC_MESSAGE_HANDLER(SpellCheckMsg_WordAdded, OnWordAdded)
    IPC_MESSAGE_HANDLER(SpellCheckMsg_EnableAutoSpellCorrect,
                        OnEnableAutoSpellCorrect)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()

  return handled;
}

void SpellCheck::OnInit(IPC::PlatformFileForTransit bdict_file,
                        const std::vector<std::string>& custom_words,
                        const std::string& language,
                        bool auto_spell_correct) {
  Init(IPC::PlatformFileForTransitToPlatformFile(bdict_file),
       custom_words, language);
  auto_spell_correct_turned_on_ = auto_spell_correct;
}

void SpellCheck::OnWordAdded(const std::string& word) {
  if (is_using_platform_spelling_engine_)
    return;

  if (!hunspell_.get()) {
    // Save it for later---add it when hunspell is initialized.
    custom_words_.push_back(word);
  } else {
    AddWordToHunspell(word);
  }
}

void SpellCheck::OnEnableAutoSpellCorrect(bool enable) {
  auto_spell_correct_turned_on_ = enable;
}

void SpellCheck::Init(base::PlatformFile file,
                      const std::vector<std::string>& custom_words,
                      const std::string& language) {
  initialized_ = true;
  hunspell_.reset();
  bdict_file_.reset();
  file_ = file;
  is_using_platform_spelling_engine_ =
      file == base::kInvalidPlatformFileValue && !language.empty();

  character_attributes_.SetDefaultLanguage(language);

  custom_words_.insert(custom_words_.end(),
                       custom_words.begin(), custom_words.end());

  // We delay the actual initialization of hunspell until it is needed.
}

bool SpellCheck::SpellCheckWord(
    const char16* in_word,
    int in_word_len,
    int tag,
    int* misspelling_start,
    int* misspelling_len,
    std::vector<string16>* optional_suggestions) {
  DCHECK(in_word_len >= 0);
  DCHECK(misspelling_start && misspelling_len) << "Out vars must be given.";

  // Do nothing if we need to delay initialization. (Rather than blocking,
  // report the word as correctly spelled.)
  if (InitializeIfNeeded())
    return true;

  // Do nothing if spell checking is disabled.
  if (initialized_ && file_ == base::kInvalidPlatformFileValue &&
      !is_using_platform_spelling_engine_) {
    return true;
  }

  *misspelling_start = 0;
  *misspelling_len = 0;
  if (in_word_len == 0)
    return true;  // No input means always spelled correctly.

  string16 word;
  int word_start;
  int word_length;
  if (!text_iterator_.IsInitialized() &&
      !text_iterator_.Initialize(&character_attributes_, true)) {
      // We failed to initialize text_iterator_, return as spelled correctly.
      VLOG(1) << "Failed to initialize SpellcheckWordIterator";
      return true;
  }

  text_iterator_.SetText(in_word, in_word_len);
  while (text_iterator_.GetNextWord(&word, &word_start, &word_length)) {
    // Found a word (or a contraction) that the spellchecker can check the
    // spelling of.
    if (CheckSpelling(word, tag))
      continue;

    // If the given word is a concatenated word of two or more valid words
    // (e.g. "hello:hello"), we should treat it as a valid word.
    if (IsValidContraction(word, tag))
      continue;

    *misspelling_start = word_start;
    *misspelling_len = word_length;

    // Get the list of suggested words.
    if (optional_suggestions)
      FillSuggestionList(word, optional_suggestions);
    return false;
  }

  return true;
}

string16 SpellCheck::GetAutoCorrectionWord(const string16& word, int tag) {
  string16 autocorrect_word;
  if (!auto_spell_correct_turned_on_)
    return autocorrect_word;  // Return the empty string.

  int word_length = static_cast<int>(word.size());
  if (word_length < 2 || word_length > SpellCheckCommon::kMaxAutoCorrectWordSize)
    return autocorrect_word;

  if (InitializeIfNeeded())
    return autocorrect_word;

  char16 misspelled_word[SpellCheckCommon::kMaxAutoCorrectWordSize + 1];
  const char16* word_char = word.c_str();
  for (int i = 0; i <= SpellCheckCommon::kMaxAutoCorrectWordSize; i++) {
    if (i >= word_length)
      misspelled_word[i] = 0;
    else
      misspelled_word[i] = word_char[i];
  }

  // Swap adjacent characters and spellcheck.
  int misspelling_start, misspelling_len;
  for (int i = 0; i < word_length - 1; i++) {
    // Swap.
    std::swap(misspelled_word[i], misspelled_word[i + 1]);

    // Check spelling.
    misspelling_start = misspelling_len = 0;
    SpellCheckWord(misspelled_word, word_length, tag, &misspelling_start,
        &misspelling_len, NULL);

    // Make decision: if only one swap produced a valid word, then we want to
    // return it. If we found two or more, we don't do autocorrection.
    if (misspelling_len == 0) {
      if (autocorrect_word.empty()) {
        autocorrect_word.assign(misspelled_word);
      } else {
        autocorrect_word.clear();
        break;
      }
    }

    // Restore the swapped characters.
    std::swap(misspelled_word[i], misspelled_word[i + 1]);
  }
  return autocorrect_word;
}

void SpellCheck::InitializeHunspell() {
  if (hunspell_.get())
    return;

  bdict_file_.reset(new file_util::MemoryMappedFile);

  if (bdict_file_->Initialize(file_)) {
    TimeTicks debug_start_time = base::Histogram::DebugNow();

    hunspell_.reset(
        new Hunspell(bdict_file_->data(), bdict_file_->length()));

    // Add custom words to Hunspell.
    for (std::vector<std::string>::iterator it = custom_words_.begin();
         it != custom_words_.end(); ++it) {
      AddWordToHunspell(*it);
    }

    DHISTOGRAM_TIMES("Spellcheck.InitTime",
                     base::Histogram::DebugNow() - debug_start_time);
  } else {
    NOTREACHED() << "Could not mmap spellchecker dictionary.";
  }
}

void SpellCheck::AddWordToHunspell(const std::string& word) {
  if (!word.empty() && word.length() < MAXWORDUTF8LEN)
    hunspell_->add(word.c_str());
}

bool SpellCheck::InitializeIfNeeded() {
  if (is_using_platform_spelling_engine_)
    return false;

  if (!initialized_) {
    RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary);
    initialized_ = true;
    return true;
  }

  // Don't initialize if hunspell is disabled.
  if (file_ != base::kInvalidPlatformFileValue)
    InitializeHunspell();

  return false;
}

// When called, relays the request to check the spelling to the proper
// backend, either hunspell or a platform-specific backend.
bool SpellCheck::CheckSpelling(const string16& word_to_check, int tag) {
  bool word_correct = false;

  if (is_using_platform_spelling_engine_) {
    RenderThread::Get()->Send(new SpellCheckHostMsg_PlatformCheckSpelling(
        word_to_check, tag, &word_correct));
  } else {
    std::string word_to_check_utf8(UTF16ToUTF8(word_to_check));
    // Hunspell shouldn't let us exceed its max, but check just in case
    if (word_to_check_utf8.length() < MAXWORDUTF8LEN) {
      if (hunspell_.get()) {
        // |hunspell_->spell| returns 0 if the word is spelled correctly and
        // non-zero otherwsie.
        word_correct = (hunspell_->spell(word_to_check_utf8.c_str()) != 0);
      } else {
        // If |hunspell_| is NULL here, an error has occurred, but it's better
        // to check rather than crash.
        word_correct = true;
      }
    }
  }

  return word_correct;
}

void SpellCheck::FillSuggestionList(
    const string16& wrong_word,
    std::vector<string16>* optional_suggestions) {
  if (is_using_platform_spelling_engine_) {
    RenderThread::Get()->Send(new SpellCheckHostMsg_PlatformFillSuggestionList(
        wrong_word, optional_suggestions));
    return;
  }

  // If |hunspell_| is NULL here, an error has occurred, but it's better
  // to check rather than crash.
  if (!hunspell_.get())
    return;

  char** suggestions;
  int number_of_suggestions =
      hunspell_->suggest(&suggestions, UTF16ToUTF8(wrong_word).c_str());

  // Populate the vector of WideStrings.
  for (int i = 0; i < number_of_suggestions; i++) {
    if (i < SpellCheckCommon::kMaxSuggestions)
      optional_suggestions->push_back(UTF8ToUTF16(suggestions[i]));
    free(suggestions[i]);
  }
  if (suggestions != NULL)
    free(suggestions);
}

// Returns whether or not the given string is a valid contraction.
// This function is a fall-back when the SpellcheckWordIterator class
// returns a concatenated word which is not in the selected dictionary
// (e.g. "in'n'out") but each word is valid.
bool SpellCheck::IsValidContraction(const string16& contraction, int tag) {
  if (!contraction_iterator_.IsInitialized() &&
      !contraction_iterator_.Initialize(&character_attributes_, false)) {
    // We failed to initialize the word iterator, return as spelled correctly.
    VLOG(1) << "Failed to initialize contraction_iterator_";
    return true;
  }

  contraction_iterator_.SetText(contraction.c_str(), contraction.length());

  string16 word;
  int word_start;
  int word_length;
  while (contraction_iterator_.GetNextWord(&word, &word_start, &word_length)) {
    if (!CheckSpelling(word, tag))
      return false;
  }
  return true;
}
<|endoftext|>


<commit_before>#pragma once
#include <stdint.h>
#include <algorithm>

namespace Util
{
    class Pointer
    {
    public:
        Pointer() = delete;

        Pointer(void* Pointer)
            :
            Address(
                reinterpret_cast<std::uintptr_t>(Pointer)
            )
        {
        }

        Pointer(std::uintptr_t Address) : Address(Address)
        {
        }

        // Accessors
        inline std::uintptr_t GetAddress() const
        {
            return Address;
        }

        inline void SetAddress(const std::uintptr_t Address)
        {
            this->Address = Address;
        }

        // Operators

        inline Pointer operator[](const ptrdiff_t Offset) const
        {
            return Pointer(Pointer(Address + Offset).Read<std::uintptr_t>());
        }

        inline Pointer operator()(const ptrdiff_t Offset) const
        {
            return Pointer(Address + Offset);
        }

        inline Pointer operator+ (std::ptrdiff_t Offset) const
        {
            return Pointer(Address + Offset);
        }

        inline Pointer operator- (std::ptrdiff_t Offset) const
        {
            return Pointer(Address - Offset);
        }

        // Casting

        inline operator std::uintptr_t() const
        {
            return Address;
        }

        template <typename T>
        inline T* Point() const
        {
            return reinterpret_cast<T*>(Address);
        }

        // Templated Read/Write

        template <typename T>
        inline T& Get() const
        {
            return *(reinterpret_cast<T*>(Address));
        }

        template <typename T>
        inline const T& Read() const
        {
            return *(reinterpret_cast<T*>(Address));
        }

        template <typename T>
        inline void Write(const T& Data) const
        {
            *Point<T>() = Data;
        }

        inline void Write(const void* Data, size_t Size) const
        {
            std::copy(
                reinterpret_cast<const uint8_t*>(Data),
                reinterpret_cast<const uint8_t*>(Data) + Size,
                Point<uint8_t>()
            );
        }

        template <typename T>
        void Fill(const T& Data, const std::size_t Count)
        {
            std::fill_n(Point<T>(), Count, Data);
        }

    private:
        std::uintptr_t Address;
    };
}<commit_msg>Refactor: Pointer class<commit_after>#pragma once
#include <stdint.h>
#include <algorithm>

namespace Util
{
    class Pointer
    {
    public:
        Pointer() = delete;

        Pointer(void* Pointer)
            :
            Address(
                reinterpret_cast<std::uintptr_t>(Pointer)
            )
        {
        }

        Pointer(std::uintptr_t Address) : Address(Address)
        {
        }

        // Accessors
        inline std::uintptr_t GetAddress() const
        {
            return Address;
        }

        inline void SetAddress(const std::uintptr_t Address)
        {
            this->Address = Address;
        }

        // Operators

        inline Pointer operator[](const ptrdiff_t Offset) const
        {
            return Pointer(Pointer(Address + Offset).Read<std::uintptr_t>());
        }

        inline Pointer operator()(const ptrdiff_t Offset) const
        {
            return Pointer(Address + Offset);
        }

        inline Pointer operator+ (std::ptrdiff_t Offset) const
        {
            return Pointer(Address + Offset);
        }

        inline Pointer operator- (std::ptrdiff_t Offset) const
        {
            return Pointer(Address - Offset);
        }

        // Casting

        inline operator std::uintptr_t() const
        {
            return Address;
        }

        template <typename T>
        inline T* Point() const
        {
            return reinterpret_cast<T*>(Address);
        }

        // Templated Read/Write

        template <typename T>
        inline T& Get() const
        {
            return *Point<T>();
        }

        template <typename T>
        inline const T& Read() const
        {
            return Get<T>();
        }

        inline void Read(void *Destination, size_t Count) const
        {
            std::copy_n(
                Point<uint8_t>(),
                Count,
                reinterpret_cast<uint8_t*>(Destination)
            );
        }

        template <typename T>
        inline void Write(const T& Data) const
        {
            Get<T>() = Data;
        }

        inline void Write(const void *Data, size_t Size) const
        {
            std::copy_n(
                reinterpret_cast<const uint8_t*>(Data),
                Size,
                Point<uint8_t>()
            );
        }

        template <typename T>
        void Fill(const T& Data, const std::size_t Count)
        {
            std::fill_n(Point<T>(), Count, Data);
        }

    private:
        std::uintptr_t Address;
    };
}<|endoftext|>


<commit_before><commit_msg>coverity#1226481 Dereference after null check<commit_after><|endoftext|>


<commit_before>#include "HalideRuntime.h"

#include <math.h>
#include <stdio.h>
#include <vector>

#include "static_image.h"

// Provide a simple mock implementation of matlab's API so we can test the mexFunction.
enum mxClassID {
    mxSINGLE_CLASS = 7,
    mxINT32_CLASS = 12,
};

enum mxComplexity {
    mxREAL = 0,
    mxCOMPLEX,
};

template <typename T> mxClassID get_class_id();
template <> mxClassID get_class_id<float>() { return mxSINGLE_CLASS; }
template <> mxClassID get_class_id<int32_t>() { return mxINT32_CLASS; }

class mxArray {
public:
    virtual void *get_data() = 0;
    virtual const void *get_data() const = 0;
    virtual const size_t *get_dimensions() const = 0;
    virtual size_t get_number_of_dimensions() const = 0;
    virtual mxClassID get_class_id() const = 0;
    virtual double get_scalar() const = 0;
    virtual size_t get_element_size() const = 0;

    virtual ~mxArray() {}
};

template <typename T>
class mxArrayImpl : public mxArray {
    std::vector<T> data;
    std::vector<size_t> dims;

public:
    mxArrayImpl(size_t M, size_t N) : data(M * N), dims({M, N}) {}

    void *get_data() { return &data[0]; }
    const void *get_data() const { return &data[0]; }
    const size_t *get_dimensions() const { return &dims[0]; }
    size_t get_number_of_dimensions() const { return dims.size(); }
    mxClassID get_class_id() const { return ::get_class_id<T>(); }
    double get_scalar() const { return data[0]; }
    size_t get_element_size() const { return sizeof(T); }

    T &operator () (int i, int j) { return data[i * dims[0] + j]; }
    T operator () (int i, int j) const { return data[i * dims[0] + j]; }
};

extern "C" {

int mexWarnMsgTxt(const char *msg) {
    // Don't bother with the varargs.
    printf("%s\n", msg);
    return 0;
}

size_t mxGetNumberOfDimensions_730(const mxArray *a) {
    return a->get_number_of_dimensions();
}

int mxGetNumberOfDimensions_700(const mxArray *a) {
    return a->get_number_of_dimensions();
}

const size_t *mxGetDimensions_730(const mxArray *a) {
    return a->get_dimensions();
}

const int *mxGetDimensions_700(const mxArray *a) {
    assert(sizeof(size_t) == sizeof(int));
    return reinterpret_cast<const int *>(a->get_dimensions());
}

mxClassID mxGetClassID(const mxArray *a) {
    return a->get_class_id();
}

void *mxGetData(const mxArray *a) {
    return const_cast<mxArray *>(a)->get_data();
}

size_t mxGetElementSize(const mxArray *a) {
    return a->get_element_size();
}

// We only support real, numeric classes in this mock implementation.
bool mxIsNumeric(const mxArray *a) {
    return true;
}
bool mxIsLogical(const mxArray *a) {
    return false;
}
bool mxIsComplex(const mxArray *a) {
    return false;
}

double mxGetScalar(const mxArray *a) {
    return a->get_scalar();
}

mxArray *mxCreateNumericMatrix_730(size_t M, size_t N, mxClassID type, mxComplexity complexity) {
    assert(complexity == mxREAL);
    switch (type) {
    case mxSINGLE_CLASS: return new mxArrayImpl<float>(M, N);
    case mxINT32_CLASS: return new mxArrayImpl<int32_t>(M, N);
    default: return NULL;
    }
}

mxArray *mxCreateNumericMatrix_700(int M, int N, mxClassID type, mxComplexity complexity) {
    return mxCreateNumericMatrix_730(M, N, type, complexity);
}

void mexFunction(int, mxArray**, int, mxArray**);

}

int main(int argc, char **argv) {
    mxArray *lhs[1] = { NULL };
    mxArray *rhs[4] = { NULL, };

    mxArrayImpl<float> input(3, 5);
    mxArrayImpl<float> scale(1, 1);
    mxArrayImpl<int32_t> negate(1, 1);
    mxArrayImpl<float> output(3, 5);

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 5; j++) {
            input(i, j) = i * 5 + j;
        }
    }

    scale(0, 0) = 3.0f;
    negate(0, 0) = 1;

    rhs[0] = &input;
    rhs[1] = &scale;
    rhs[2] = &negate;
    rhs[3] = &output;

    mexFunction(1, lhs, 4, rhs);

    assert(lhs[0]->get_scalar() == 0);
    delete lhs[0];
    lhs[0] = NULL;

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 5; j++) {
            float in = input(i, j);
            float expected = in * scale(0, 0) * (negate(0, 0) ? -1.0f : 1.0f);
            assert(output(i, j) == expected);
        }
    }

    printf("Success!\n");
    return 0;
}
<commit_msg>Added dllexport to mock Matlab API.<commit_after>#include "HalideRuntime.h"

#include <math.h>
#include <stdio.h>
#include <vector>

#include "static_image.h"

// Provide a simple mock implementation of matlab's API so we can test the mexFunction.

#ifdef _WIN32
#define EXPORT __declspec(dllexport)
#endif

enum mxClassID {
    mxSINGLE_CLASS = 7,
    mxINT32_CLASS = 12,
};

enum mxComplexity {
    mxREAL = 0,
    mxCOMPLEX,
};

template <typename T> mxClassID get_class_id();
template <> mxClassID get_class_id<float>() { return mxSINGLE_CLASS; }
template <> mxClassID get_class_id<int32_t>() { return mxINT32_CLASS; }

class mxArray {
public:
    virtual void *get_data() = 0;
    virtual const void *get_data() const = 0;
    virtual const size_t *get_dimensions() const = 0;
    virtual size_t get_number_of_dimensions() const = 0;
    virtual mxClassID get_class_id() const = 0;
    virtual double get_scalar() const = 0;
    virtual size_t get_element_size() const = 0;

    virtual ~mxArray() {}
};

template <typename T>
class mxArrayImpl : public mxArray {
    std::vector<T> data;
    std::vector<size_t> dims;

public:
    mxArrayImpl(size_t M, size_t N) : data(M * N), dims({M, N}) {}

    void *get_data() { return &data[0]; }
    const void *get_data() const { return &data[0]; }
    const size_t *get_dimensions() const { return &dims[0]; }
    size_t get_number_of_dimensions() const { return dims.size(); }
    mxClassID get_class_id() const { return ::get_class_id<T>(); }
    double get_scalar() const { return data[0]; }
    size_t get_element_size() const { return sizeof(T); }

    T &operator () (int i, int j) { return data[i * dims[0] + j]; }
    T operator () (int i, int j) const { return data[i * dims[0] + j]; }
};

extern "C" {

EXPORT int mexWarnMsgTxt(const char *msg) {
    // Don't bother with the varargs.
    printf("%s\n", msg);
    return 0;
}

EXPORT size_t mxGetNumberOfDimensions_730(const mxArray *a) {
    return a->get_number_of_dimensions();
}

EXPORT int mxGetNumberOfDimensions_700(const mxArray *a) {
    return a->get_number_of_dimensions();
}

EXPORT const size_t *mxGetDimensions_730(const mxArray *a) {
    return a->get_dimensions();
}

EXPORT const int *mxGetDimensions_700(const mxArray *a) {
    assert(sizeof(size_t) == sizeof(int));
    return reinterpret_cast<const int *>(a->get_dimensions());
}

EXPORT mxClassID mxGetClassID(const mxArray *a) {
    return a->get_class_id();
}

EXPORT void *mxGetData(const mxArray *a) {
    return const_cast<mxArray *>(a)->get_data();
}

EXPORT size_t mxGetElementSize(const mxArray *a) {
    return a->get_element_size();
}

// We only support real, numeric classes in this mock implementation.
EXPORT bool mxIsNumeric(const mxArray *a) {
    return true;
}
EXPORT bool mxIsLogical(const mxArray *a) {
    return false;
}
EXPORT bool mxIsComplex(const mxArray *a) {
    return false;
}

EXPORT double mxGetScalar(const mxArray *a) {
    return a->get_scalar();
}

EXPORT mxArray *mxCreateNumericMatrix_730(size_t M, size_t N, mxClassID type, mxComplexity complexity) {
    assert(complexity == mxREAL);
    switch (type) {
    case mxSINGLE_CLASS: return new mxArrayImpl<float>(M, N);
    case mxINT32_CLASS: return new mxArrayImpl<int32_t>(M, N);
    default: return NULL;
    }
}

EXPORT mxArray *mxCreateNumericMatrix_700(int M, int N, mxClassID type, mxComplexity complexity) {
    return mxCreateNumericMatrix_730(M, N, type, complexity);
}

void mexFunction(int, mxArray**, int, mxArray**);

}

int main(int argc, char **argv) {
    mxArray *lhs[1] = { NULL };
    mxArray *rhs[4] = { NULL, };

    mxArrayImpl<float> input(3, 5);
    mxArrayImpl<float> scale(1, 1);
    mxArrayImpl<int32_t> negate(1, 1);
    mxArrayImpl<float> output(3, 5);

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 5; j++) {
            input(i, j) = i * 5 + j;
        }
    }

    scale(0, 0) = 3.0f;
    negate(0, 0) = 1;

    rhs[0] = &input;
    rhs[1] = &scale;
    rhs[2] = &negate;
    rhs[3] = &output;

    mexFunction(1, lhs, 4, rhs);

    assert(lhs[0]->get_scalar() == 0);
    delete lhs[0];
    lhs[0] = NULL;

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 5; j++) {
            float in = input(i, j);
            float expected = in * scale(0, 0) * (negate(0, 0) ? -1.0f : 1.0f);
            assert(output(i, j) == expected);
        }
    }

    printf("Success!\n");
    return 0;
}
<|endoftext|>


<commit_before><commit_msg>Application test for int vectors<commit_after><|endoftext|>


<commit_before>// Copyright 2018 The Crashpad 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.

#include "test/multiprocess_exec.h"

#include <lib/fdio/io.h>
#include <lib/fdio/spawn.h>
#include <lib/zx/process.h>
#include <lib/zx/time.h>
#include <zircon/processargs.h>

#include "base/files/scoped_file.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "gtest/gtest.h"

namespace crashpad {
namespace test {

namespace {

void AddPipe(fdio_spawn_action_t* action, int target_fd, int* fd_out) {
  zx_handle_t handle;
  uint32_t id;
  zx_status_t status = fdio_pipe_half(&handle, &id);
  ZX_CHECK(status >= 0, status) << "fdio_pipe_half";
  action->action = FDIO_SPAWN_ACTION_ADD_HANDLE;
  action->h.id = PA_HND(PA_HND_TYPE(id), target_fd);
  action->h.handle = handle;
  *fd_out = status;
}

}  // namespace

namespace internal {

struct MultiprocessInfo {
  MultiprocessInfo() {}
  base::ScopedFD stdin_write;
  base::ScopedFD stdout_read;
  zx::process child;
};

}  // namespace internal

Multiprocess::Multiprocess()
    : info_(nullptr), code_(EXIT_SUCCESS), reason_(kTerminationNormal) {}

void Multiprocess::Run() {
  // Set up and spawn the child process.
  ASSERT_NO_FATAL_FAILURE(PreFork());
  RunChild();

  // And then run the parent actions in this process.
  RunParent();

  // Wait until the child exits.
  zx_signals_t signals;
  ASSERT_EQ(
      info_->child.wait_one(ZX_TASK_TERMINATED, zx::time::infinite(), &signals),
      ZX_OK);
  ASSERT_EQ(signals, ZX_TASK_TERMINATED);

  // Get the child's exit code.
  zx_info_process_t proc_info;
  zx_status_t status = info_->child.get_info(
      ZX_INFO_PROCESS, &proc_info, sizeof(proc_info), nullptr, nullptr);
  if (status != ZX_OK) {
    ZX_LOG(ERROR, status) << "zx_object_get_info";
    ADD_FAILURE() << "Unable to get exit code of child";
  } else {
    if (code_ != proc_info.return_code) {
      ADD_FAILURE() << "Child exited with code " << proc_info.return_code
                    << ", expected exit with code " << code_;
    }
  }
}

void Multiprocess::SetExpectedChildTermination(TerminationReason reason,
                                               ReturnCodeType code) {
  EXPECT_EQ(info_, nullptr)
      << "SetExpectedChildTermination() must be called before Run()";
  reason_ = reason;
  code_ = code;
}

void Multiprocess::SetExpectedChildTerminationBuiltinTrap() {
  constexpr ReturnCodeType kExpectedReturnCode = ZX_TASK_RETCODE_EXCEPTION_KILL;
  SetExpectedChildTermination(kTerminationNormal, kExpectedReturnCode);
}

Multiprocess::~Multiprocess() {
  delete info_;
}

FileHandle Multiprocess::ReadPipeHandle() const {
  return info_->stdout_read.get();
}

FileHandle Multiprocess::WritePipeHandle() const {
  return info_->stdin_write.get();
}

void Multiprocess::CloseReadPipe() {
  info_->stdout_read.reset();
}

void Multiprocess::CloseWritePipe() {
  info_->stdin_write.reset();
}

void Multiprocess::RunParent() {
  MultiprocessParent();

  info_->stdout_read.reset();
  info_->stdin_write.reset();
}

void Multiprocess::RunChild() {
  MultiprocessChild();
}

MultiprocessExec::MultiprocessExec()
    : Multiprocess(), command_(), arguments_(), argv_() {}

void MultiprocessExec::SetChildCommand(
    const base::FilePath& command,
    const std::vector<std::string>* arguments) {
  command_ = command;
  if (arguments) {
    arguments_ = *arguments;
  } else {
    arguments_.clear();
  }
}

MultiprocessExec::~MultiprocessExec() {}

void MultiprocessExec::PreFork() {
  ASSERT_FALSE(command_.empty());

  ASSERT_TRUE(argv_.empty());

  argv_.push_back(command_.value().c_str());
  for (const std::string& argument : arguments_) {
    argv_.push_back(argument.c_str());
  }
  argv_.push_back(nullptr);

  ASSERT_EQ(info(), nullptr);
  set_info(new internal::MultiprocessInfo());
}

void MultiprocessExec::MultiprocessChild() {
  constexpr size_t kActionCount = 3;
  fdio_spawn_action_t actions[kActionCount];

  int stdin_parent_side = -1;
  AddPipe(&actions[0], STDIN_FILENO, &stdin_parent_side);
  info()->stdin_write.reset(stdin_parent_side);

  int stdout_parent_side = -1;
  AddPipe(&actions[1], STDOUT_FILENO, &stdout_parent_side);
  info()->stdout_read.reset(stdout_parent_side);

  actions[2].action = FDIO_SPAWN_ACTION_CLONE_FD;
  actions[2].fd.local_fd = STDERR_FILENO;
  actions[2].fd.target_fd = STDERR_FILENO;

  // Pass the filesystem namespace, parent environment, and default job to the
  // child, but don't include any other file handles, preferring to set them
  // up explicitly below.
  uint32_t flags = FDIO_SPAWN_CLONE_ALL & ~FDIO_SPAWN_CLONE_STDIO;

  char error_message[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
  zx::process child;
  zx_status_t status = fdio_spawn_etc(ZX_HANDLE_INVALID,
                                      flags,
                                      command_.value().c_str(),
                                      argv_.data(),
                                      nullptr,
                                      kActionCount,
                                      actions,
                                      child.reset_and_get_address(),
                                      error_message);
  ZX_CHECK(status == ZX_OK, status) << "fdio_spawn_etc: " << error_message;
  info()->child = std::move(child);
}

ProcessType MultiprocessExec::ChildProcess() {
  return zx::unowned_process(info()->child);
}

}  // namespace test
}  // namespace crashpad
<commit_msg>[fuchsia] Update to fdio_pipe_half2<commit_after>// Copyright 2018 The Crashpad 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.

#include "test/multiprocess_exec.h"

#include <lib/fdio/io.h>
#include <lib/fdio/spawn.h>
#include <lib/zx/process.h>
#include <lib/zx/time.h>
#include <zircon/processargs.h>

#include "base/files/scoped_file.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "gtest/gtest.h"

namespace crashpad {
namespace test {

namespace {

void AddPipe(fdio_spawn_action_t* action, int target_fd, int* fd_out) {
  zx_handle_t handle = ZX_HANDLE_INVALID;
  zx_status_t status = fdio_pipe_half2(fd_out, &handle);
  ZX_CHECK(status == ZX_OK, status) << "fdio_pipe_half2";
  action->action = FDIO_SPAWN_ACTION_ADD_HANDLE;
  action->h.id = PA_HND(PA_FD, target_fd);
  action->h.handle = handle;
}

}  // namespace

namespace internal {

struct MultiprocessInfo {
  MultiprocessInfo() {}
  base::ScopedFD stdin_write;
  base::ScopedFD stdout_read;
  zx::process child;
};

}  // namespace internal

Multiprocess::Multiprocess()
    : info_(nullptr), code_(EXIT_SUCCESS), reason_(kTerminationNormal) {}

void Multiprocess::Run() {
  // Set up and spawn the child process.
  ASSERT_NO_FATAL_FAILURE(PreFork());
  RunChild();

  // And then run the parent actions in this process.
  RunParent();

  // Wait until the child exits.
  zx_signals_t signals;
  ASSERT_EQ(
      info_->child.wait_one(ZX_TASK_TERMINATED, zx::time::infinite(), &signals),
      ZX_OK);
  ASSERT_EQ(signals, ZX_TASK_TERMINATED);

  // Get the child's exit code.
  zx_info_process_t proc_info;
  zx_status_t status = info_->child.get_info(
      ZX_INFO_PROCESS, &proc_info, sizeof(proc_info), nullptr, nullptr);
  if (status != ZX_OK) {
    ZX_LOG(ERROR, status) << "zx_object_get_info";
    ADD_FAILURE() << "Unable to get exit code of child";
  } else {
    if (code_ != proc_info.return_code) {
      ADD_FAILURE() << "Child exited with code " << proc_info.return_code
                    << ", expected exit with code " << code_;
    }
  }
}

void Multiprocess::SetExpectedChildTermination(TerminationReason reason,
                                               ReturnCodeType code) {
  EXPECT_EQ(info_, nullptr)
      << "SetExpectedChildTermination() must be called before Run()";
  reason_ = reason;
  code_ = code;
}

void Multiprocess::SetExpectedChildTerminationBuiltinTrap() {
  constexpr ReturnCodeType kExpectedReturnCode = ZX_TASK_RETCODE_EXCEPTION_KILL;
  SetExpectedChildTermination(kTerminationNormal, kExpectedReturnCode);
}

Multiprocess::~Multiprocess() {
  delete info_;
}

FileHandle Multiprocess::ReadPipeHandle() const {
  return info_->stdout_read.get();
}

FileHandle Multiprocess::WritePipeHandle() const {
  return info_->stdin_write.get();
}

void Multiprocess::CloseReadPipe() {
  info_->stdout_read.reset();
}

void Multiprocess::CloseWritePipe() {
  info_->stdin_write.reset();
}

void Multiprocess::RunParent() {
  MultiprocessParent();

  info_->stdout_read.reset();
  info_->stdin_write.reset();
}

void Multiprocess::RunChild() {
  MultiprocessChild();
}

MultiprocessExec::MultiprocessExec()
    : Multiprocess(), command_(), arguments_(), argv_() {}

void MultiprocessExec::SetChildCommand(
    const base::FilePath& command,
    const std::vector<std::string>* arguments) {
  command_ = command;
  if (arguments) {
    arguments_ = *arguments;
  } else {
    arguments_.clear();
  }
}

MultiprocessExec::~MultiprocessExec() {}

void MultiprocessExec::PreFork() {
  ASSERT_FALSE(command_.empty());

  ASSERT_TRUE(argv_.empty());

  argv_.push_back(command_.value().c_str());
  for (const std::string& argument : arguments_) {
    argv_.push_back(argument.c_str());
  }
  argv_.push_back(nullptr);

  ASSERT_EQ(info(), nullptr);
  set_info(new internal::MultiprocessInfo());
}

void MultiprocessExec::MultiprocessChild() {
  constexpr size_t kActionCount = 3;
  fdio_spawn_action_t actions[kActionCount];

  int stdin_parent_side = -1;
  AddPipe(&actions[0], STDIN_FILENO, &stdin_parent_side);
  info()->stdin_write.reset(stdin_parent_side);

  int stdout_parent_side = -1;
  AddPipe(&actions[1], STDOUT_FILENO, &stdout_parent_side);
  info()->stdout_read.reset(stdout_parent_side);

  actions[2].action = FDIO_SPAWN_ACTION_CLONE_FD;
  actions[2].fd.local_fd = STDERR_FILENO;
  actions[2].fd.target_fd = STDERR_FILENO;

  // Pass the filesystem namespace, parent environment, and default job to the
  // child, but don't include any other file handles, preferring to set them
  // up explicitly below.
  uint32_t flags = FDIO_SPAWN_CLONE_ALL & ~FDIO_SPAWN_CLONE_STDIO;

  char error_message[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
  zx::process child;
  zx_status_t status = fdio_spawn_etc(ZX_HANDLE_INVALID,
                                      flags,
                                      command_.value().c_str(),
                                      argv_.data(),
                                      nullptr,
                                      kActionCount,
                                      actions,
                                      child.reset_and_get_address(),
                                      error_message);
  ZX_CHECK(status == ZX_OK, status) << "fdio_spawn_etc: " << error_message;
  info()->child = std::move(child);
}

ProcessType MultiprocessExec::ChildProcess() {
  return zx::unowned_process(info()->child);
}

}  // namespace test
}  // namespace crashpad
<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "tstrings_cpp/tstrings.h"

#include <string>
#include <unordered_map>
#include <fstream>
#include <locale>

using std::string;
using std::wstring;
using std::u16string;
using std::u32string;

namespace templates
{
    const string no_vars     = "Hello World!";
    const string fox         = "The quick ${color} fox.";
    const string fox_utf8    = u8"The quiĉk ${воасл} fox.";
    const string fox_spaces  = "The quick ${ color } fox.";
    const string fox_numeric = "The ${0} ${1} fox.";
    const string fox_numeric_invalid = "The ${123} ${456} ${abcd} fox.";
    const wstring fox_wstr   = L"The quiĉk ${cȌlor} fox.";
}

namespace strings
{
    const string tqbf = "The quick brown fox.";
}

namespace files
{
    const string small_utf8 = "data/small_utf8.template";
    const string small_utf8_expect = "data/small_utf8.expected";

    const string small_utf16 = "data/small_utf16.template";
    const string small_utf16_expect = "data/small_utf16.expected";
}

TEST(tstrings, interpolate_empty)
{
    const std::unordered_map<string, string> vars = {};
    EXPECT_EQ("", tstrings::interpolate_braces<string>("", vars));
}

TEST(tstrings, interpolate_no_vars)
{
    const std::unordered_map<string, string> vars = {};
    EXPECT_EQ(templates::no_vars, tstrings::interpolate_braces(templates::no_vars, vars));
}

TEST(tstrings, interpolate)
{
    const std::unordered_map<string, string> vars = {
        { "color", "brown" }
    };

    EXPECT_EQ(
        strings::tqbf,
        tstrings::interpolate_braces(templates::fox, vars)
    );
}

TEST(tstrings, interpolate_utf8)
{
    const std::unordered_map<string, string> vars = {
        { u8"воасл", u8"brʘwn" }
    };

    EXPECT_EQ(
        u8"The quiĉk brʘwn fox.",
        tstrings::interpolate_braces(templates::fox_utf8, vars)
    );
}

TEST(tstrings, interpolate_wstr)
{
    const std::unordered_map<wstring, wstring> vars = {
        { L"cȌlor", L"brʘwn" }
    };

    EXPECT_EQ(
        L"The quiĉk brʘwn fox.",
        tstrings::interpolate_braces<wstring>(templates::fox_wstr, vars)
    );
}

TEST(tstrings, interpolate_numeric_map)
{
    const std::unordered_map<string, string> vars = {
        { "0", "quick" },
        { "1", "brown" }
    };

    EXPECT_EQ(
        strings::tqbf,
        tstrings::interpolate_braces(templates::fox_numeric, vars)
    );
}

TEST(tstrings, interpolate_numeric)
{
    const std::vector<string> vars { "quick", "brown" };
    EXPECT_EQ(
        strings::tqbf,
        tstrings::interpolate_braces(templates::fox_numeric, vars)
    );

    EXPECT_EQ(
        "The    fox.",
        tstrings::interpolate_braces(templates::fox_numeric_invalid, vars)
    );
}

TEST(tstrings, interpolate_empty_variable)
{
    const std::unordered_map<string, string> vars = {
        { "color", "" }
    };

    EXPECT_EQ(
        "The quick  fox.",
        tstrings::interpolate_braces(templates::fox, vars)
    );
}

TEST(tstrings, interpolate_with_whitespace)
{
    const std::unordered_map<string, string> vars = {
        { "color", "brown" }
    };

    EXPECT_EQ(
        strings::tqbf,
        tstrings::interpolate_braces(templates::fox_spaces, vars)
    );
}

TEST(tstrings, interpolate_stream_small)
{
    const std::unordered_map<string, string> vars = {
        { "color", "brown" }
    };

    std::stringstream output;
    // returns an output stream writing to `output`
    auto out = tstrings::interpolate_braces(vars, output);

    // wrap the streambuf in a ostream
    out << templates::fox << std::flush;

    EXPECT_EQ(
        strings::tqbf,
        output.str()
    );
}

template<typename Ch>
void interp_and_compare_files (
    std::basic_ifstream<Ch>& template_file,
    std::basic_ifstream<Ch>& expect_file,
    std::unordered_map<
        std::basic_string<Ch>,
        std::basic_string<Ch>
    > vars)
{
    std::basic_stringstream<Ch> output;
    {
        if (template_file) {
            // read the entire file to the output stream
            tstrings::interpolate_braces(vars, output)
                << template_file.rdbuf()
                << std::flush;
        }
        else {
            FAIL() << "file not open";
        }
    }

    // test the result
    if (expect_file)
    {
        // simple equality test
        if (!std::equal(std::istreambuf_iterator<Ch>(output),
                std::istreambuf_iterator<Ch>(),
                std::istreambuf_iterator<Ch>(expect_file)))
        {
            FAIL() << "files not identical after interpolation:\n" << output.str();
        }

        // check streams are same length
        expect_file.seekg(0, std::ios::end);
        output.seekg(0, std::ios::end);

        // note: use .gcount(), not tellg(), because we
        // want to compare the number of characters, not bytes;
        EXPECT_EQ(expect_file.gcount(), output.gcount())
            << "files are not the same length";
    }
    else {
        FAIL() << "file not open";
    }
}

TEST(tstrings, interpolate_stream_file_utf8)
{
    const std::unordered_map<string, string> vars = {
        { "color", "brown" },
        { "animal", "fox" },
        { "dog", "dalmatian" },
    };

    std::ifstream template_file(files::small_utf8, std::ios::binary);
    std::ifstream expect_file(files::small_utf8_expect, std::ios::binary);

    interp_and_compare_files(
        template_file,
        expect_file,
        vars);
}

TEST(tstrings, interpolate_stream_file_utf16)
{
    const std::unordered_map<wstring, wstring> vars = {
        { L"color", L"brown" },
        { L"animal", L"fox" },
        { L"dog", L"dalmatian" },
    };

    std::wifstream template_file(files::small_utf8, std::ios::binary);
    std::wifstream expect_file(files::small_utf8_expect, std::ios::binary);

    template_file.imbue(
        std::locale(
            std::locale(""),
            new std::codecvt_utf8<wchar_t>)
        );

    expect_file.imbue(
        std::locale(
            std::locale(""),
            new std::codecvt_utf8<wchar_t>)
        );

    interp_and_compare_files<wchar_t>(
        template_file,
        expect_file,
        vars);
}<commit_msg>clarify unit-test intention<commit_after>#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "tstrings_cpp/tstrings.h"

#include <string>
#include <unordered_map>
#include <fstream>
#include <locale>

using std::string;
using std::wstring;
using std::u16string;
using std::u32string;

namespace templates
{
    const string no_vars     = "Hello World!";
    const string fox         = "The quick ${color} fox.";
    const string fox_utf8    = u8"The quiĉk ${воасл} fox.";
    const string fox_spaces  = "The quick ${ color } fox.";
    const string fox_numeric = "The ${0} ${1} fox.";
    const string fox_numeric_invalid = "The ${123} ${456} ${abcd} fox.";
    const wstring fox_wstr   = L"The quiĉk ${cȌlor} fox.";
}

namespace strings
{
    const string tqbf = "The quick brown fox.";
}

namespace files
{
    const string small_utf8 = "data/small_utf8.template";
    const string small_utf8_expect = "data/small_utf8.expected";

    const string small_utf16 = "data/small_utf16.template";
    const string small_utf16_expect = "data/small_utf16.expected";
}

TEST(tstrings, interpolate_empty)
{
    const std::unordered_map<string, string> vars = {};
    EXPECT_EQ("", tstrings::interpolate_braces<string>("", vars));
}

TEST(tstrings, interpolate_no_vars)
{
    const std::unordered_map<string, string> vars = {};
    EXPECT_EQ(templates::no_vars, tstrings::interpolate_braces(templates::no_vars, vars));
}

TEST(tstrings, interpolate)
{
    const std::unordered_map<string, string> vars = {
        { "color", "brown" }
    };

    EXPECT_EQ(
        strings::tqbf,
        tstrings::interpolate_braces(templates::fox, vars)
    );
}

TEST(tstrings, interpolate_utf8)
{
    const std::unordered_map<string, string> vars = {
        { u8"воасл", u8"brʘwn" }
    };

    EXPECT_EQ(
        u8"The quiĉk brʘwn fox.",
        tstrings::interpolate_braces(templates::fox_utf8, vars)
    );
}

TEST(tstrings, interpolate_wstr)
{
    const std::unordered_map<wstring, wstring> vars = {
        { L"cȌlor", L"brʘwn" }
    };

    EXPECT_EQ(
        L"The quiĉk brʘwn fox.",
        tstrings::interpolate_braces<wstring>(templates::fox_wstr, vars)
    );
}

TEST(tstrings, interpolate_numeric_map)
{
    const std::unordered_map<string, string> vars = {
        { "0", "quick" },
        { "1", "brown" }
    };

    EXPECT_EQ(
        strings::tqbf,
        tstrings::interpolate_braces(templates::fox_numeric, vars)
    );
}

TEST(tstrings, interpolate_numeric)
{
    const std::vector<string> vars { "quick", "brown" };
    EXPECT_EQ(
        strings::tqbf,
        tstrings::interpolate_braces(templates::fox_numeric, vars)
    );

    EXPECT_EQ(
        "The    fox.",
        tstrings::interpolate_braces(templates::fox_numeric_invalid, vars)
    );
}

TEST(tstrings, interpolate_empty_variable)
{
    const std::unordered_map<string, string> vars = {
        { "color", "" }
    };

    EXPECT_EQ(
        "The quick  fox.",
        tstrings::interpolate_braces(templates::fox, vars)
    );
}

TEST(tstrings, interpolate_with_whitespace)
{
    const std::unordered_map<string, string> vars = {
        { "color", "brown" }
    };

    EXPECT_EQ(
        strings::tqbf,
        tstrings::interpolate_braces(templates::fox_spaces, vars)
    );
}

TEST(tstrings, interpolate_stream_small)
{
    const std::unordered_map<string, string> vars = {
        { "color", "brown" }
    };

    std::stringstream output;
    // returns an output stream writing to `output`
    auto out = tstrings::interpolate_braces(vars, output);

    // wrap the streambuf in a ostream
    out << templates::fox << std::flush;

    EXPECT_EQ(
        strings::tqbf,
        output.str()
    );
}

template<typename Ch>
void interp_and_compare_files (
    std::basic_ifstream<Ch>& template_file,
    std::basic_ifstream<Ch>& expect_file,
    std::unordered_map<
        std::basic_string<Ch>,
        std::basic_string<Ch>
    > vars)
{
    std::basic_stringstream<Ch> output;
    {
        if (template_file) {
            // read the entire file to the output stream
            tstrings::interpolate_braces(vars, output)
                << template_file.rdbuf()
                << std::flush;
        }
        else {
            FAIL() << "file not open";
        }
    }

    // test the result
    if (expect_file)
    {
        // simple equality test
        if (!std::equal(std::istreambuf_iterator<Ch>(output),
                std::istreambuf_iterator<Ch>(),
                std::istreambuf_iterator<Ch>(expect_file)))
        {
            FAIL() << "files not identical after interpolation:\n" << output.str();
        }

        // check streams are same length
        expect_file.seekg(0, std::ios::end);
        output.seekg(0, std::ios::end);

        // note: use .gcount(), not tellg(), because we
        // want to compare the number of characters, not bytes;
        EXPECT_EQ(expect_file.gcount(), output.gcount())
            << "files are not the same length";
    }
    else {
        FAIL() << "file not open";
    }
}

TEST(tstrings, interpolate_stream_file_ascii)
{
    const std::unordered_map<string, string> vars = {
        { "color", "brown" },
        { "animal", "fox" },
        { "dog", "dalmatian" },
    };

    std::ifstream template_file(files::small_utf8, std::ios::binary);
    std::ifstream expect_file(files::small_utf8_expect, std::ios::binary);

    interp_and_compare_files(
        template_file,
        expect_file,
        vars);
}

/**
 * Reads a template file as UF8, converts characters
 * to wchar_t's, then interpolates.
 */
TEST(tstrings, interpolate_stream_file_utf8)
{
    const std::unordered_map<wstring, wstring> vars = {
        { L"color", L"brown" },
        { L"animal", L"fox" },
        { L"dog", L"dalmatian" },
    };

    std::wifstream template_file(files::small_utf8, std::ios::binary);
    std::wifstream expect_file(files::small_utf8_expect, std::ios::binary);

    template_file.imbue(
        std::locale(
            std::locale(""),
            new std::codecvt_utf8<wchar_t>)
        );

    expect_file.imbue(
        std::locale(
            std::locale(""),
            new std::codecvt_utf8<wchar_t>)
        );

    interp_and_compare_files<wchar_t>(
        template_file,
        expect_file,
        vars);
}<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include <iostream>

#include "json.h"

using namespace share_me_utils;

TEST(json_unittest, two_equal_two) { EXPECT_EQ(2, 2); }

class JsonUnittest : public testing::Test {
protected:
  virtual void SetUp() {
    std::cout << "JsonUnittest SetUp ..." << std::endl;
    m_json = new Json();
    m_text = "{\"a\": \"d\"}";
  }
  virtual void TearDown() {
    if (m_json) {
      delete m_json;
      m_json = nullptr;
    }
    std::cout << "JsonUnittest TearDown finish..." << std::endl;
  }

  Json *m_json;
  char* m_text;
};

TEST_F(JsonUnittest, OneEqual) { EXPECT_EQ(1, 1); }
TEST_F(JsonUnittest, hson_test) {
  ASSERT_NE(m_json, nullptr);
  m_json->Set(m_text, strlen(m_text);
  ASSERT_EQ(m_json->Paser(), true);
}

int main(int argc, char *argv[]) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}<commit_msg>json test build pass<commit_after>#include "gtest/gtest.h"
#include <iostream>

#include "json.h"

using namespace share_me_utils;

TEST(json_unittest, two_equal_two) { EXPECT_EQ(2, 2); }

class JsonUnittest : public testing::Test {
protected:
  virtual void SetUp() {
    std::cout << "JsonUnittest SetUp ..." << std::endl;
    m_json = new Json();
    m_text = "{\"a\": \"d\"}";
  }
  virtual void TearDown() {
    if (m_json) {
      delete m_json;
      m_json = nullptr;
    }
    std::cout << "JsonUnittest TearDown finish..." << std::endl;
  }

  Json *m_json;
  char* m_text;
};

TEST_F(JsonUnittest, OneEqual) { EXPECT_EQ(1, 1); }
TEST_F(JsonUnittest, hson_test) {
  ASSERT_NE(m_json, nullptr);
  m_json->Set(m_text, strlen(m_text));
  ASSERT_EQ(m_json->Paser(), true);
}

int main(int argc, char *argv[]) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}<|endoftext|>