<commit_before>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// hash_join_test.cpp
//
// Identification: tests/executor/hash_join_test.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <memory>

#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include "backend/common/types.h"
#include "backend/executor/logical_tile.h"
#include "backend/executor/logical_tile_factory.h"

#include "backend/executor/hash_join_executor.h"
#include "backend/executor/hash_executor.h"
#include "backend/executor/merge_join_executor.h"
#include "backend/executor/nested_loop_join_executor.h"

#include "backend/expression/abstract_expression.h"
#include "backend/expression/tuple_value_expression.h"
#include "backend/expression/expression_util.h"

#include "backend/planner/hash_join_plan.h"
#include "backend/planner/hash_plan.h"
#include "backend/planner/merge_join_plan.h"
#include "backend/planner/nested_loop_join_plan.h"

#include "backend/storage/data_table.h"

#include "mock_executor.h"
#include "executor/executor_tests_util.h"
#include "executor/join_tests_util.h"
#include "harness.h"

using ::testing::NotNull;
using ::testing::Return;

namespace peloton {
namespace test {

std::vector<planner::MergeJoinPlan::JoinClause> CreateJoinClauses() {
  std::vector<planner::MergeJoinPlan::JoinClause> join_clauses;
  auto left = expression::TupleValueFactory(0, 1);
  auto right = expression::TupleValueFactory(1, 1);
  bool reversed = false;
  join_clauses.emplace_back(left, right, reversed);
  return join_clauses;
}

std::vector<PlanNodeType> join_algorithms = {
    PLAN_NODE_TYPE_NESTLOOP,
    PLAN_NODE_TYPE_MERGEJOIN,
    PLAN_NODE_TYPE_HASHJOIN
};

std::vector<PelotonJoinType> join_types = {
    JOIN_TYPE_INNER,
    JOIN_TYPE_LEFT,
    JOIN_TYPE_RIGHT,
    JOIN_TYPE_OUTER
};

void ExecuteJoinTest(PlanNodeType join_algorithm, PelotonJoinType join_type);

oid_t CountTuplesWithNullFields(executor::LogicalTile *logical_tile);

TEST(JoinTests, JoinPredicateTest) {

  // Go over all join algorithms
  for(auto join_algorithm : join_algorithms) {
    std::cout << "JOIN ALGORITHM :: " << PlanNodeTypeToString(join_algorithm) << "\n";

    // Go over all join types
    for(auto join_type : join_types) {
      std::cout << "JOIN TYPE :: " << join_type << "\n";

      // Execute the join test
      ExecuteJoinTest(join_algorithm, join_type);

    }
  }

}

void ExecuteJoinTest(PlanNodeType join_algorithm, PelotonJoinType join_type) {

  //===--------------------------------------------------------------------===//
  // Mock table scan executors
  //===--------------------------------------------------------------------===//

  MockExecutor left_table_scan_executor, right_table_scan_executor;

  // Create a table and wrap it in logical tile
  size_t tile_group_size = TESTS_TUPLES_PER_TILEGROUP;
  size_t left_table_tile_group_count = 3;
  size_t right_table_tile_group_count = 2;

  // Left table has 3 tile groups
  std::unique_ptr<storage::DataTable> left_table(
      ExecutorTestsUtil::CreateTable(tile_group_size));
  ExecutorTestsUtil::PopulateTable(left_table.get(),
                                   tile_group_size * left_table_tile_group_count,
                                   false,
                                   false, false);

  //std::cout << (*left_table);

  // Right table has 2 tile groups
  std::unique_ptr<storage::DataTable> right_table(
      ExecutorTestsUtil::CreateTable(tile_group_size));
  ExecutorTestsUtil::PopulateTable(right_table.get(),
                                   tile_group_size * right_table_tile_group_count,
                                   false, false, false);

  //std::cout << (*right_table);

  // Wrap the input tables with logical tiles
  std::unique_ptr<executor::LogicalTile> left_table_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(left_table->GetTileGroup(0)));
  std::unique_ptr<executor::LogicalTile> left_table_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(left_table->GetTileGroup(1)));
  std::unique_ptr<executor::LogicalTile> left_table_logical_tile3(
      executor::LogicalTileFactory::WrapTileGroup(left_table->GetTileGroup(2)));

  std::unique_ptr<executor::LogicalTile> right_table_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(
          right_table->GetTileGroup(0)));
  std::unique_ptr<executor::LogicalTile> right_table_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(
          right_table->GetTileGroup(1)));

  // Left scan executor returns logical tiles from the left table

  EXPECT_CALL(left_table_scan_executor, DInit())
  .WillOnce(Return(true));

  EXPECT_CALL(left_table_scan_executor, DExecute())
  .WillOnce(Return(true))
  .WillOnce(Return(true))
  .WillOnce(Return(true))
  .WillOnce(Return(false));

  EXPECT_CALL(left_table_scan_executor, GetOutput())
  .WillOnce(Return(left_table_logical_tile1.release()))
  .WillOnce(Return(left_table_logical_tile2.release()))
  .WillOnce(Return(left_table_logical_tile3.release()));

  // Right scan executor returns logical tiles from the right table

  EXPECT_CALL(right_table_scan_executor, DInit())
  .WillOnce(Return(true));

  EXPECT_CALL(right_table_scan_executor, DExecute())
  .WillOnce(Return(true))
  .WillOnce(Return(true))
  .WillOnce(Return(false));

  EXPECT_CALL(right_table_scan_executor, GetOutput())
  .WillOnce(Return(right_table_logical_tile1.release()))
  .WillOnce(Return(right_table_logical_tile2.release()));

  //===--------------------------------------------------------------------===//
  // Setup join plan nodes and executors and run them
  //===--------------------------------------------------------------------===//

  oid_t result_tuple_count = 0;
  oid_t tuples_with_null = 0;
  auto projection = JoinTestsUtil::CreateProjection();

  // Construct predicate
  expression::AbstractExpression *predicate = JoinTestsUtil::CreateJoinPredicate();

  // Differ based on join algorithm
  switch(join_algorithm) {

    case PLAN_NODE_TYPE_NESTLOOP: {

      // Create nested loop join plan node.
      planner::NestedLoopJoinPlan nested_loop_join_node(join_type, predicate, projection);

      // Run the nested loop join executor
      executor::NestedLoopJoinExecutor nested_loop_join_executor(&nested_loop_join_node, nullptr);

      // Construct the executor tree
      nested_loop_join_executor.AddChild(&left_table_scan_executor);
      nested_loop_join_executor.AddChild(&right_table_scan_executor);

      // Run the nested loop join executor
      EXPECT_TRUE(nested_loop_join_executor.Init());
      while(nested_loop_join_executor.Execute() == true) {
        std::unique_ptr<executor::LogicalTile> result_logical_tile(nested_loop_join_executor.GetOutput());

        if(result_logical_tile != nullptr) {
          result_tuple_count += result_logical_tile->GetTupleCount();
          tuples_with_null += CountTuplesWithNullFields(result_logical_tile.get());
        }
      }

    }
    break;

    case PLAN_NODE_TYPE_MERGEJOIN: {

      // Create join clauses
      std::vector<planner::MergeJoinPlan::JoinClause> join_clauses;
      join_clauses = CreateJoinClauses();

      // Create merge join plan node
      planner::MergeJoinPlan merge_join_node(join_type, predicate, projection, join_clauses);

      // Construct the merge join executor
      executor::MergeJoinExecutor merge_join_executor(&merge_join_node, nullptr);

      // Construct the executor tree
      merge_join_executor.AddChild(&left_table_scan_executor);
      merge_join_executor.AddChild(&right_table_scan_executor);

      // Run the merge join executor
      EXPECT_TRUE(merge_join_executor.Init());
      while(merge_join_executor.Execute() == true) {
        std::unique_ptr<executor::LogicalTile> result_logical_tile(merge_join_executor.GetOutput());

        if(result_logical_tile != nullptr) {
          result_tuple_count += result_logical_tile->GetTupleCount();
          tuples_with_null += CountTuplesWithNullFields(result_logical_tile.get());
          //std::cout << (*result_logical_tile);
        }
      }

    }
    break;

    case PLAN_NODE_TYPE_HASHJOIN: {

      // Create hash plan node
      expression::AbstractExpression *right_table_attr_1 =
          new expression::TupleValueExpression(1, 1);

      std::vector<std::unique_ptr<const expression::AbstractExpression> > hash_keys;
      hash_keys.emplace_back(right_table_attr_1);

      // Create hash plan node
      planner::HashPlan hash_plan_node(hash_keys);

      // Construct the hash executor
      executor::HashExecutor hash_executor(&hash_plan_node, nullptr);

      // Create hash join plan node.
      planner::HashJoinPlan hash_join_plan_node(join_type, predicate, projection);

      // Construct the hash join executor
      executor::HashJoinExecutor hash_join_executor(&hash_join_plan_node, nullptr);

      // Construct the executor tree
      hash_join_executor.AddChild(&left_table_scan_executor);
      hash_join_executor.AddChild(&hash_executor);

      hash_executor.AddChild(&right_table_scan_executor);

      // Run the hash_join_executor
      EXPECT_TRUE(hash_join_executor.Init());
      while(hash_join_executor.Execute() == true) {
        std::unique_ptr<executor::LogicalTile> result_logical_tile(hash_join_executor.GetOutput());

        if(result_logical_tile != nullptr) {
          result_tuple_count += result_logical_tile->GetTupleCount();
          tuples_with_null += CountTuplesWithNullFields(result_logical_tile.get());
          //std::cout << (*result_logical_tile);
        }
      }

    }
    break;

    default:
      throw Exception("Unsupported join algorithm : " + std::to_string(join_algorithm));
      break;
  }

  //===--------------------------------------------------------------------===//
  // Execute test
  //===--------------------------------------------------------------------===//

  // Check output
  switch(join_type) {
    case JOIN_TYPE_INNER:
      EXPECT_EQ(result_tuple_count, 2 * tile_group_size);
      EXPECT_EQ(tuples_with_null, 0 * tile_group_size);
      break;

    case JOIN_TYPE_LEFT:
      EXPECT_EQ(result_tuple_count, 3 * tile_group_size);
      EXPECT_EQ(tuples_with_null, 1 * tile_group_size);
      break;

    case JOIN_TYPE_RIGHT:
      EXPECT_EQ(result_tuple_count, 2 * tile_group_size);
      EXPECT_EQ(tuples_with_null, 0 * tile_group_size);
      break;

    case JOIN_TYPE_OUTER:
      EXPECT_EQ(result_tuple_count, 3 * tile_group_size);
      EXPECT_EQ(tuples_with_null, 1 * tile_group_size);
      break;

    default:
      throw Exception("Unsupported join type : " + std::to_string(join_type));
      break;
  }

}

oid_t CountTuplesWithNullFields(executor::LogicalTile *logical_tile) {
  assert(logical_tile);

  // Get column count
  auto column_count = logical_tile->GetColumnCount();
  oid_t tuples_with_null = 0;

  // Go over the tile
  for (auto logical_tile_itr : *logical_tile) {
    const expression::ContainerTuple<executor::LogicalTile> left_tuple(
        logical_tile, logical_tile_itr);

      // Go over all the fields and check for null values
      for(oid_t col_itr = 0; col_itr < column_count; col_itr++) {
        auto val = left_tuple.GetValue(col_itr);
        if(val.IsNull()) {
          tuples_with_null++;
          break;
        }
      }

  }

  return tuples_with_null;
}

}  // namespace test
}  // namespace peloton
<commit_msg>Removed code<commit_after>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// hash_join_test.cpp
//
// Identification: tests/executor/hash_join_test.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <memory>

#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include "backend/common/types.h"
#include "backend/executor/logical_tile.h"
#include "backend/executor/logical_tile_factory.h"

#include "backend/executor/hash_join_executor.h"
#include "backend/executor/hash_executor.h"
#include "backend/executor/merge_join_executor.h"
#include "backend/executor/nested_loop_join_executor.h"

#include "backend/expression/abstract_expression.h"
#include "backend/expression/tuple_value_expression.h"
#include "backend/expression/expression_util.h"

#include "backend/planner/hash_join_plan.h"
#include "backend/planner/hash_plan.h"
#include "backend/planner/merge_join_plan.h"
#include "backend/planner/nested_loop_join_plan.h"

#include "backend/storage/data_table.h"

#include "mock_executor.h"
#include "executor/executor_tests_util.h"
#include "executor/join_tests_util.h"
#include "harness.h"

using ::testing::NotNull;
using ::testing::Return;

namespace peloton {
namespace test {

std::vector<planner::MergeJoinPlan::JoinClause> CreateJoinClauses() {
  std::vector<planner::MergeJoinPlan::JoinClause> join_clauses;
  auto left = expression::TupleValueFactory(0, 1);
  auto right = expression::TupleValueFactory(1, 1);
  bool reversed = false;
  join_clauses.emplace_back(left, right, reversed);
  return join_clauses;
}

std::vector<PlanNodeType> join_algorithms = {
    PLAN_NODE_TYPE_NESTLOOP,
    PLAN_NODE_TYPE_MERGEJOIN
    // TODO: Uncomment this to test hash join executor
    //  PLAN_NODE_TYPE_HASHJOIN
};

std::vector<PelotonJoinType> join_types = {
    JOIN_TYPE_INNER,
    JOIN_TYPE_LEFT,
    JOIN_TYPE_RIGHT,
    JOIN_TYPE_OUTER
};

void ExecuteJoinTest(PlanNodeType join_algorithm, PelotonJoinType join_type);

oid_t CountTuplesWithNullFields(executor::LogicalTile *logical_tile);

TEST(JoinTests, JoinPredicateTest) {

  // Go over all join algorithms
  for(auto join_algorithm : join_algorithms) {
    std::cout << "JOIN ALGORITHM :: " << PlanNodeTypeToString(join_algorithm) << "\n";

    // Go over all join types
    for(auto join_type : join_types) {
      std::cout << "JOIN TYPE :: " << join_type << "\n";

      // Execute the join test
      ExecuteJoinTest(join_algorithm, join_type);

    }
  }

}

void ExecuteJoinTest(PlanNodeType join_algorithm, PelotonJoinType join_type) {

  //===--------------------------------------------------------------------===//
  // Mock table scan executors
  //===--------------------------------------------------------------------===//

  MockExecutor left_table_scan_executor, right_table_scan_executor;

  // Create a table and wrap it in logical tile
  size_t tile_group_size = TESTS_TUPLES_PER_TILEGROUP;
  size_t left_table_tile_group_count = 3;
  size_t right_table_tile_group_count = 2;

  // Left table has 3 tile groups
  std::unique_ptr<storage::DataTable> left_table(
      ExecutorTestsUtil::CreateTable(tile_group_size));
  ExecutorTestsUtil::PopulateTable(left_table.get(),
                                   tile_group_size * left_table_tile_group_count,
                                   false,
                                   false, false);

  //std::cout << (*left_table);

  // Right table has 2 tile groups
  std::unique_ptr<storage::DataTable> right_table(
      ExecutorTestsUtil::CreateTable(tile_group_size));
  ExecutorTestsUtil::PopulateTable(right_table.get(),
                                   tile_group_size * right_table_tile_group_count,
                                   false, false, false);

  //std::cout << (*right_table);

  // Wrap the input tables with logical tiles
  std::unique_ptr<executor::LogicalTile> left_table_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(left_table->GetTileGroup(0)));
  std::unique_ptr<executor::LogicalTile> left_table_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(left_table->GetTileGroup(1)));
  std::unique_ptr<executor::LogicalTile> left_table_logical_tile3(
      executor::LogicalTileFactory::WrapTileGroup(left_table->GetTileGroup(2)));

  std::unique_ptr<executor::LogicalTile> right_table_logical_tile1(
      executor::LogicalTileFactory::WrapTileGroup(
          right_table->GetTileGroup(0)));
  std::unique_ptr<executor::LogicalTile> right_table_logical_tile2(
      executor::LogicalTileFactory::WrapTileGroup(
          right_table->GetTileGroup(1)));

  // Left scan executor returns logical tiles from the left table

  EXPECT_CALL(left_table_scan_executor, DInit())
  .WillOnce(Return(true));

  EXPECT_CALL(left_table_scan_executor, DExecute())
  .WillOnce(Return(true))
  .WillOnce(Return(true))
  .WillOnce(Return(true))
  .WillOnce(Return(false));

  EXPECT_CALL(left_table_scan_executor, GetOutput())
  .WillOnce(Return(left_table_logical_tile1.release()))
  .WillOnce(Return(left_table_logical_tile2.release()))
  .WillOnce(Return(left_table_logical_tile3.release()));

  // Right scan executor returns logical tiles from the right table

  EXPECT_CALL(right_table_scan_executor, DInit())
  .WillOnce(Return(true));

  EXPECT_CALL(right_table_scan_executor, DExecute())
  .WillOnce(Return(true))
  .WillOnce(Return(true))
  .WillOnce(Return(false));

  EXPECT_CALL(right_table_scan_executor, GetOutput())
  .WillOnce(Return(right_table_logical_tile1.release()))
  .WillOnce(Return(right_table_logical_tile2.release()));

  //===--------------------------------------------------------------------===//
  // Setup join plan nodes and executors and run them
  //===--------------------------------------------------------------------===//

  oid_t result_tuple_count = 0;
  oid_t tuples_with_null = 0;
  auto projection = JoinTestsUtil::CreateProjection();

  // Construct predicate
  expression::AbstractExpression *predicate = JoinTestsUtil::CreateJoinPredicate();

  // Differ based on join algorithm
  switch(join_algorithm) {

    case PLAN_NODE_TYPE_NESTLOOP: {

      // Create nested loop join plan node.
      planner::NestedLoopJoinPlan nested_loop_join_node(join_type, predicate, projection);

      // Run the nested loop join executor
      executor::NestedLoopJoinExecutor nested_loop_join_executor(&nested_loop_join_node, nullptr);

      // Construct the executor tree
      nested_loop_join_executor.AddChild(&left_table_scan_executor);
      nested_loop_join_executor.AddChild(&right_table_scan_executor);

      // Run the nested loop join executor
      EXPECT_TRUE(nested_loop_join_executor.Init());
      while(nested_loop_join_executor.Execute() == true) {
        std::unique_ptr<executor::LogicalTile> result_logical_tile(nested_loop_join_executor.GetOutput());

        if(result_logical_tile != nullptr) {
          result_tuple_count += result_logical_tile->GetTupleCount();
          tuples_with_null += CountTuplesWithNullFields(result_logical_tile.get());
        }
      }

    }
    break;

    case PLAN_NODE_TYPE_MERGEJOIN: {

      // Create join clauses
      std::vector<planner::MergeJoinPlan::JoinClause> join_clauses;
      join_clauses = CreateJoinClauses();

      // Create merge join plan node
      planner::MergeJoinPlan merge_join_node(join_type, predicate, projection, join_clauses);

      // Construct the merge join executor
      executor::MergeJoinExecutor merge_join_executor(&merge_join_node, nullptr);

      // Construct the executor tree
      merge_join_executor.AddChild(&left_table_scan_executor);
      merge_join_executor.AddChild(&right_table_scan_executor);

      // Run the merge join executor
      EXPECT_TRUE(merge_join_executor.Init());
      while(merge_join_executor.Execute() == true) {
        std::unique_ptr<executor::LogicalTile> result_logical_tile(merge_join_executor.GetOutput());

        if(result_logical_tile != nullptr) {
          result_tuple_count += result_logical_tile->GetTupleCount();
          tuples_with_null += CountTuplesWithNullFields(result_logical_tile.get());
          //std::cout << (*result_logical_tile);
        }
      }

    }
    break;

    case PLAN_NODE_TYPE_HASHJOIN: {

      // Create hash plan node
      expression::AbstractExpression *right_table_attr_1 =
          new expression::TupleValueExpression(1, 1);

      std::vector<std::unique_ptr<const expression::AbstractExpression> > hash_keys;
      hash_keys.emplace_back(right_table_attr_1);

      // Create hash plan node
      planner::HashPlan hash_plan_node(hash_keys);

      // Construct the hash executor
      executor::HashExecutor hash_executor(&hash_plan_node, nullptr);

      // Create hash join plan node.
      planner::HashJoinPlan hash_join_plan_node(join_type, predicate, projection);

      // Construct the hash join executor
      executor::HashJoinExecutor hash_join_executor(&hash_join_plan_node, nullptr);

      // Construct the executor tree
      hash_join_executor.AddChild(&left_table_scan_executor);
      hash_join_executor.AddChild(&hash_executor);

      hash_executor.AddChild(&right_table_scan_executor);

      // Run the hash_join_executor
      EXPECT_TRUE(hash_join_executor.Init());
      while(hash_join_executor.Execute() == true) {
        std::unique_ptr<executor::LogicalTile> result_logical_tile(hash_join_executor.GetOutput());

        if(result_logical_tile != nullptr) {
          result_tuple_count += result_logical_tile->GetTupleCount();
          tuples_with_null += CountTuplesWithNullFields(result_logical_tile.get());
          //std::cout << (*result_logical_tile);
        }
      }

    }
    break;

    default:
      throw Exception("Unsupported join algorithm : " + std::to_string(join_algorithm));
      break;
  }

  //===--------------------------------------------------------------------===//
  // Execute test
  //===--------------------------------------------------------------------===//

  // Check output
  switch(join_type) {
    case JOIN_TYPE_INNER:
      EXPECT_EQ(result_tuple_count, 2 * tile_group_size);
      EXPECT_EQ(tuples_with_null, 0 * tile_group_size);
      break;

    case JOIN_TYPE_LEFT:
      EXPECT_EQ(result_tuple_count, 3 * tile_group_size);
      EXPECT_EQ(tuples_with_null, 1 * tile_group_size);
      break;

    case JOIN_TYPE_RIGHT:
      EXPECT_EQ(result_tuple_count, 2 * tile_group_size);
      EXPECT_EQ(tuples_with_null, 0 * tile_group_size);
      break;

    case JOIN_TYPE_OUTER:
      EXPECT_EQ(result_tuple_count, 3 * tile_group_size);
      EXPECT_EQ(tuples_with_null, 1 * tile_group_size);
      break;

    default:
      throw Exception("Unsupported join type : " + std::to_string(join_type));
      break;
  }

}

oid_t CountTuplesWithNullFields(executor::LogicalTile *logical_tile) {
  assert(logical_tile);

  // Get column count
  auto column_count = logical_tile->GetColumnCount();
  oid_t tuples_with_null = 0;

  // Go over the tile
  for (auto logical_tile_itr : *logical_tile) {
    const expression::ContainerTuple<executor::LogicalTile> left_tuple(
        logical_tile, logical_tile_itr);

      // Go over all the fields and check for null values
      for(oid_t col_itr = 0; col_itr < column_count; col_itr++) {
        auto val = left_tuple.GetValue(col_itr);
        if(val.IsNull()) {
          tuples_with_null++;
          break;
        }
      }

  }

  return tuples_with_null;
}

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


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2012 Couchbase, Inc.
 *
 *   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 <libcbio/cbio.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <gtest/gtest.h>

using namespace std;

static const char dbfile[] = "testcase.couch";

class LibcbioTest : public ::testing::Test
{
protected:
    LibcbioTest() {}
    virtual ~LibcbioTest() {}
    virtual void SetUp(void) {
        removeDb();
    }
    virtual void TearDown(void) {
        removeDb();
    }

protected:
    void removeDb(void) {
        EXPECT_EQ(0, (remove(dbfile) == -1 && errno != ENOENT));
    }
};

class LibcbioOpenTest : public LibcbioTest {};

TEST_F(LibcbioOpenTest, HandleEmptyNameOpenRDONLY)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_ENOENT,
              cbio_open_handle("", CBIO_OPEN_RDONLY, &handle));
}

TEST_F(LibcbioOpenTest, HandleNullNameOpenRDONLY)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_EINVAL,
              cbio_open_handle(NULL, CBIO_OPEN_RDONLY, &handle));
}

TEST_F(LibcbioOpenTest, HandleNonexistentNameOpenRDONLY)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_ENOENT,
              cbio_open_handle("/this/path/should/not/exist",
                               CBIO_OPEN_RDONLY, &handle));
}

TEST_F(LibcbioOpenTest, HandleEmptyNameOpenRW)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_ENOENT,
              cbio_open_handle("", CBIO_OPEN_RW, &handle));
}

TEST_F(LibcbioOpenTest, HandleNullNameOpenRW)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_EINVAL,
              cbio_open_handle(NULL, CBIO_OPEN_RW, &handle));
}

TEST_F(LibcbioOpenTest, HandleNonexistentNameOpenRW)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_ENOENT,
              cbio_open_handle("/this/path/should/not/exist",
                               CBIO_OPEN_RW, &handle));
}

TEST_F(LibcbioOpenTest, HandleEmptyNameOpenCREATE)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_ENOENT,
              cbio_open_handle("", CBIO_OPEN_CREATE, &handle));
}

TEST_F(LibcbioOpenTest, HandleNullNameOpenCREATE)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_EINVAL,
              cbio_open_handle(NULL, CBIO_OPEN_CREATE, &handle));
}

TEST_F(LibcbioOpenTest, HandleNonexistentNameOpenCREATE)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_ENOENT,
              cbio_open_handle("/this/path/should/not/exist",
                               CBIO_OPEN_CREATE, &handle));
}

class LibcbioCreateDatabaseTest : public LibcbioTest {};

TEST_F(LibcbioCreateDatabaseTest, createDatabase)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_CREATE, &handle));

    cbio_close_handle(handle);
}

TEST_F(LibcbioCreateDatabaseTest, reopenDatabaseReadOnly)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_CREATE, &handle));
    cbio_close_handle(handle);

    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_RDONLY, &handle));

    cbio_close_handle(handle);
}

TEST_F(LibcbioCreateDatabaseTest, reopenDatabaseReadWrite)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_CREATE, &handle));
    cbio_close_handle(handle);

    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_RW, &handle));

    cbio_close_handle(handle);
}

TEST_F(LibcbioCreateDatabaseTest, reopenDatabaseCreate)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_CREATE, &handle));
    cbio_close_handle(handle);

    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_CREATE, &handle));

    cbio_close_handle(handle);
}

class LibcbioDataAccessTest : public LibcbioTest
{
public:
    LibcbioDataAccessTest() {
        blob = new char[8192];
        blobsize = 8192;
    }

    virtual ~LibcbioDataAccessTest() {
        delete []blob;
    }

    virtual void SetUp(void) {
        removeDb();
        ASSERT_EQ(CBIO_SUCCESS,
                  cbio_open_handle(dbfile, CBIO_OPEN_CREATE, &handle));
    }
    virtual void TearDown(void) {
        cbio_close_handle(handle);
        removeDb();
    }

protected:

    void storeSingleDocument(const string &key, const string &value) {
        libcbio_document_t doc;
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_create_empty_document(handle, &doc));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_set_id(doc, key.data(), key.length(), 0));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_set_value(doc, value.data(),
                                          value.length(), 0));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_store_document(handle, doc));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_commit(handle));
        cbio_document_release(doc);
    }

    void deleteSingleDocument(const string &key) {
        libcbio_document_t doc;
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_create_empty_document(handle, &doc));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_set_id(doc, key.data(), key.length(), 0));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_set_deleted(doc, 1));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_store_document(handle, doc));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_commit(handle));
        cbio_document_release(doc);
    }

    void validateExistingDocument(const string &key, const string &value) {
        libcbio_document_t doc;
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_get_document(handle, key.data(), key.length(), &doc));
        const void *ptr;
        size_t nbytes;
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_get_value(doc, &ptr, &nbytes));
        EXPECT_EQ(value.length(), nbytes);
        EXPECT_EQ(0, memcmp(value.data(), ptr, nbytes));
    }

    void validateNonExistingDocument(const string &key) {
        libcbio_document_t doc;
        EXPECT_EQ(CBIO_ERROR_ENOENT,
                  cbio_get_document(handle, key.data(), key.length(), &doc));
    }

    string generateKey(int id) {
        stringstream ss;
        ss << "mykey-" << id;
        return ss.str();
    }

    libcbio_document_t generateRandomDocument(int id) {
        libcbio_document_t doc;
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_create_empty_document(handle, &doc));
        string key = generateKey(id);

        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_set_id(doc, key.data(), key.length(), 1));

        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_set_value(doc, blob, random() % blobsize, 0));

        return doc;
    }

    void bulkStoreDocuments(int maxdoc) {
        const unsigned int chunksize = 1000;
        libcbio_document_t *docs = new libcbio_document_t[chunksize];
        int total = 0;
        do {
            unsigned int currtx = static_cast<unsigned int>(random()) % chunksize;

            if (total + currtx > maxdoc) {
                currtx = maxdoc - total;
            }

            for (int ii = 0; ii < currtx; ++ii) {
                docs[ii] = generateRandomDocument(total + ii);
            }

            EXPECT_EQ(CBIO_SUCCESS, cbio_store_documents(handle, docs, currtx));
            EXPECT_EQ(CBIO_SUCCESS, cbio_commit(handle));
            total += currtx;

            for (unsigned int ii = 0; ii < currtx; ++ii) {
                cbio_document_release(docs[ii]);
            }
        } while (total < maxdoc);

        for (int ii = 0; ii < maxdoc; ++ii) {
            libcbio_document_t doc;
            string key = generateKey(ii);
            EXPECT_EQ(CBIO_SUCCESS,
                      cbio_get_document(handle, key.data(), key.length(), &doc));
            cbio_document_release(doc);
        }
    }

    char *blob;
    size_t blobsize;
    libcbio_t handle;
};

TEST_F(LibcbioDataAccessTest, getMiss)
{
    validateNonExistingDocument("key");
}

TEST_F(LibcbioDataAccessTest, storeSingleDocument)
{
    storeSingleDocument("key", "value");
}

TEST_F(LibcbioDataAccessTest, getHit)
{
    storeSingleDocument("key", "value");
    validateExistingDocument("key", "value");
}

TEST_F(LibcbioDataAccessTest, deleteNonExistingDocument)
{
    string key = "key";
    deleteSingleDocument(key);
    validateNonExistingDocument(key);
}

TEST_F(LibcbioDataAccessTest, deleteExistingDocument)
{
    string key = "key";
    string value = "value";
    storeSingleDocument(key, value);
    validateExistingDocument(key, value);
    deleteSingleDocument(key);
    validateNonExistingDocument(key);

    libcbio_document_t doc;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_get_document_ex(handle, key.data(), key.length(), &doc));

    int deleted;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_document_get_deleted(doc, &deleted));
    EXPECT_EQ(1, deleted);
    cbio_document_release(doc);
}

TEST_F(LibcbioDataAccessTest, testBulkStoreDocuments)
{
    bulkStoreDocuments(30000);
}

extern "C" {
    static int count_callback(libcbio_t handle,
                              libcbio_document_t doc,
                              void *ctx)
    {
        (void)handle;
        (void)doc;
        int *count = static_cast<int *>(ctx);
        (*count)++;
        return 0;
    }
}

TEST_F(LibcbioDataAccessTest, testChangesSinceDocuments)
{
    uint64_t offset = (uint64_t)cbio_get_header_position(handle);
    bulkStoreDocuments(5000);
    int total = 0;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_changes_since(handle, offset, count_callback,
                                 static_cast<void *>(&total)));
    EXPECT_EQ(5000, total);
}

class LibcbioLocalDocumentTest : public LibcbioDataAccessTest
{
};

TEST_F(LibcbioLocalDocumentTest, testStoreLocalDocuments)
{
    string key = "_local/hi-there";
    string value = "{ foo:true }";
    storeSingleDocument(key, value);
    validateExistingDocument(key, value);
}

TEST_F(LibcbioLocalDocumentTest, testDeleteLocalDocuments)
{
    string key = "_local/hi-there";
    deleteSingleDocument(key);
}

TEST_F(LibcbioLocalDocumentTest, testChangesLocalDocuments)
{
    uint64_t offset = (uint64_t)cbio_get_header_position(handle);
    string key = "_local/hi-there";
    string value = "{ foo:true }";
    storeSingleDocument(key, value);
    validateExistingDocument(key, value);
    deleteSingleDocument(key);
    validateNonExistingDocument(key);
    int total = 0;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_changes_since(handle, offset, count_callback,
                                 static_cast<void *>(&total)));
    EXPECT_EQ(0, total);
    storeSingleDocument("hi", "there");

    EXPECT_EQ(CBIO_SUCCESS,
              cbio_changes_since(handle, offset, count_callback,
                                 static_cast<void *>(&total)));
    EXPECT_EQ(1, total);
}
<commit_msg>Fix warnings reported by gcc about sign comparison<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2012 Couchbase, Inc.
 *
 *   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 <libcbio/cbio.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <gtest/gtest.h>

using namespace std;

static const char dbfile[] = "testcase.couch";

class LibcbioTest : public ::testing::Test
{
protected:
    LibcbioTest() {}
    virtual ~LibcbioTest() {}
    virtual void SetUp(void) {
        removeDb();
    }
    virtual void TearDown(void) {
        removeDb();
    }

protected:
    void removeDb(void) {
        EXPECT_EQ(0, (remove(dbfile) == -1 && errno != ENOENT));
    }
};

class LibcbioOpenTest : public LibcbioTest {};

TEST_F(LibcbioOpenTest, HandleEmptyNameOpenRDONLY)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_ENOENT,
              cbio_open_handle("", CBIO_OPEN_RDONLY, &handle));
}

TEST_F(LibcbioOpenTest, HandleNullNameOpenRDONLY)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_EINVAL,
              cbio_open_handle(NULL, CBIO_OPEN_RDONLY, &handle));
}

TEST_F(LibcbioOpenTest, HandleNonexistentNameOpenRDONLY)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_ENOENT,
              cbio_open_handle("/this/path/should/not/exist",
                               CBIO_OPEN_RDONLY, &handle));
}

TEST_F(LibcbioOpenTest, HandleEmptyNameOpenRW)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_ENOENT,
              cbio_open_handle("", CBIO_OPEN_RW, &handle));
}

TEST_F(LibcbioOpenTest, HandleNullNameOpenRW)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_EINVAL,
              cbio_open_handle(NULL, CBIO_OPEN_RW, &handle));
}

TEST_F(LibcbioOpenTest, HandleNonexistentNameOpenRW)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_ENOENT,
              cbio_open_handle("/this/path/should/not/exist",
                               CBIO_OPEN_RW, &handle));
}

TEST_F(LibcbioOpenTest, HandleEmptyNameOpenCREATE)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_ENOENT,
              cbio_open_handle("", CBIO_OPEN_CREATE, &handle));
}

TEST_F(LibcbioOpenTest, HandleNullNameOpenCREATE)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_EINVAL,
              cbio_open_handle(NULL, CBIO_OPEN_CREATE, &handle));
}

TEST_F(LibcbioOpenTest, HandleNonexistentNameOpenCREATE)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_ERROR_ENOENT,
              cbio_open_handle("/this/path/should/not/exist",
                               CBIO_OPEN_CREATE, &handle));
}

class LibcbioCreateDatabaseTest : public LibcbioTest {};

TEST_F(LibcbioCreateDatabaseTest, createDatabase)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_CREATE, &handle));

    cbio_close_handle(handle);
}

TEST_F(LibcbioCreateDatabaseTest, reopenDatabaseReadOnly)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_CREATE, &handle));
    cbio_close_handle(handle);

    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_RDONLY, &handle));

    cbio_close_handle(handle);
}

TEST_F(LibcbioCreateDatabaseTest, reopenDatabaseReadWrite)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_CREATE, &handle));
    cbio_close_handle(handle);

    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_RW, &handle));

    cbio_close_handle(handle);
}

TEST_F(LibcbioCreateDatabaseTest, reopenDatabaseCreate)
{
    libcbio_t handle;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_CREATE, &handle));
    cbio_close_handle(handle);

    EXPECT_EQ(CBIO_SUCCESS,
              cbio_open_handle(dbfile, CBIO_OPEN_CREATE, &handle));

    cbio_close_handle(handle);
}

class LibcbioDataAccessTest : public LibcbioTest
{
public:
    LibcbioDataAccessTest() {
        blob = new char[8192];
        blobsize = 8192;
    }

    virtual ~LibcbioDataAccessTest() {
        delete []blob;
    }

    virtual void SetUp(void) {
        removeDb();
        ASSERT_EQ(CBIO_SUCCESS,
                  cbio_open_handle(dbfile, CBIO_OPEN_CREATE, &handle));
    }
    virtual void TearDown(void) {
        cbio_close_handle(handle);
        removeDb();
    }

protected:

    void storeSingleDocument(const string &key, const string &value) {
        libcbio_document_t doc;
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_create_empty_document(handle, &doc));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_set_id(doc, key.data(), key.length(), 0));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_set_value(doc, value.data(),
                                          value.length(), 0));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_store_document(handle, doc));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_commit(handle));
        cbio_document_release(doc);
    }

    void deleteSingleDocument(const string &key) {
        libcbio_document_t doc;
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_create_empty_document(handle, &doc));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_set_id(doc, key.data(), key.length(), 0));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_set_deleted(doc, 1));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_store_document(handle, doc));
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_commit(handle));
        cbio_document_release(doc);
    }

    void validateExistingDocument(const string &key, const string &value) {
        libcbio_document_t doc;
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_get_document(handle, key.data(), key.length(), &doc));
        const void *ptr;
        size_t nbytes;
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_get_value(doc, &ptr, &nbytes));
        EXPECT_EQ(value.length(), nbytes);
        EXPECT_EQ(0, memcmp(value.data(), ptr, nbytes));
    }

    void validateNonExistingDocument(const string &key) {
        libcbio_document_t doc;
        EXPECT_EQ(CBIO_ERROR_ENOENT,
                  cbio_get_document(handle, key.data(), key.length(), &doc));
    }

    string generateKey(int id) {
        stringstream ss;
        ss << "mykey-" << id;
        return ss.str();
    }

    libcbio_document_t generateRandomDocument(int id) {
        libcbio_document_t doc;
        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_create_empty_document(handle, &doc));
        string key = generateKey(id);

        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_set_id(doc, key.data(), key.length(), 1));

        EXPECT_EQ(CBIO_SUCCESS,
                  cbio_document_set_value(doc, blob, random() % blobsize, 0));

        return doc;
    }

    void bulkStoreDocuments(int maxdoc) {
        const unsigned int chunksize = 1000;
        libcbio_document_t *docs = new libcbio_document_t[chunksize];
        int total = 0;
        do {
            unsigned int currtx = static_cast<unsigned int>(random()) % chunksize;

            if (total + (int)currtx > maxdoc) {
                currtx = maxdoc - total;
            }

            for (int ii = 0; ii < (int)currtx; ++ii) {
                docs[ii] = generateRandomDocument(total + ii);
            }

            EXPECT_EQ(CBIO_SUCCESS, cbio_store_documents(handle, docs, currtx));
            EXPECT_EQ(CBIO_SUCCESS, cbio_commit(handle));
            total += currtx;

            for (unsigned int ii = 0; ii < currtx; ++ii) {
                cbio_document_release(docs[ii]);
            }
        } while (total < maxdoc);

        for (int ii = 0; ii < maxdoc; ++ii) {
            libcbio_document_t doc;
            string key = generateKey(ii);
            EXPECT_EQ(CBIO_SUCCESS,
                      cbio_get_document(handle, key.data(), key.length(), &doc));
            cbio_document_release(doc);
        }
    }

    char *blob;
    size_t blobsize;
    libcbio_t handle;
};

TEST_F(LibcbioDataAccessTest, getMiss)
{
    validateNonExistingDocument("key");
}

TEST_F(LibcbioDataAccessTest, storeSingleDocument)
{
    storeSingleDocument("key", "value");
}

TEST_F(LibcbioDataAccessTest, getHit)
{
    storeSingleDocument("key", "value");
    validateExistingDocument("key", "value");
}

TEST_F(LibcbioDataAccessTest, deleteNonExistingDocument)
{
    string key = "key";
    deleteSingleDocument(key);
    validateNonExistingDocument(key);
}

TEST_F(LibcbioDataAccessTest, deleteExistingDocument)
{
    string key = "key";
    string value = "value";
    storeSingleDocument(key, value);
    validateExistingDocument(key, value);
    deleteSingleDocument(key);
    validateNonExistingDocument(key);

    libcbio_document_t doc;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_get_document_ex(handle, key.data(), key.length(), &doc));

    int deleted;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_document_get_deleted(doc, &deleted));
    EXPECT_EQ(1, deleted);
    cbio_document_release(doc);
}

TEST_F(LibcbioDataAccessTest, testBulkStoreDocuments)
{
    bulkStoreDocuments(30000);
}

extern "C" {
    static int count_callback(libcbio_t handle,
                              libcbio_document_t doc,
                              void *ctx)
    {
        (void)handle;
        (void)doc;
        int *count = static_cast<int *>(ctx);
        (*count)++;
        return 0;
    }
}

TEST_F(LibcbioDataAccessTest, testChangesSinceDocuments)
{
    uint64_t offset = (uint64_t)cbio_get_header_position(handle);
    bulkStoreDocuments(5000);
    int total = 0;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_changes_since(handle, offset, count_callback,
                                 static_cast<void *>(&total)));
    EXPECT_EQ(5000, total);
}

class LibcbioLocalDocumentTest : public LibcbioDataAccessTest
{
};

TEST_F(LibcbioLocalDocumentTest, testStoreLocalDocuments)
{
    string key = "_local/hi-there";
    string value = "{ foo:true }";
    storeSingleDocument(key, value);
    validateExistingDocument(key, value);
}

TEST_F(LibcbioLocalDocumentTest, testDeleteLocalDocuments)
{
    string key = "_local/hi-there";
    deleteSingleDocument(key);
}

TEST_F(LibcbioLocalDocumentTest, testChangesLocalDocuments)
{
    uint64_t offset = (uint64_t)cbio_get_header_position(handle);
    string key = "_local/hi-there";
    string value = "{ foo:true }";
    storeSingleDocument(key, value);
    validateExistingDocument(key, value);
    deleteSingleDocument(key);
    validateNonExistingDocument(key);
    int total = 0;
    EXPECT_EQ(CBIO_SUCCESS,
              cbio_changes_since(handle, offset, count_callback,
                                 static_cast<void *>(&total)));
    EXPECT_EQ(0, total);
    storeSingleDocument("hi", "there");

    EXPECT_EQ(CBIO_SUCCESS,
              cbio_changes_since(handle, offset, count_callback,
                                 static_cast<void *>(&total)));
    EXPECT_EQ(1, total);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <libport/bind.hh>
#include <libport/lexical-cast.hh>
#include <libport/test.hh>

#include <libport/unistd.h>
#include <libport/thread-pool.hh>

// For atomic increment
#include <boost/interprocess/detail/atomic.hpp>

using boost::interprocess::detail::atomic_inc32;
using boost::interprocess::detail::atomic_read32;

using libport::test_suite;

typedef libport::ThreadPool ThreadPool;

/* Determinism warning: Do not use rand outside main thread!
*/
volatile boost::uint32_t counter;

// Divisor for number of iterations
static boost::uint32_t dfactor = 1;

static void task_sleep_inc(int delay)
{
  usleep(delay);
  atomic_inc32(&counter);
}

// Just start a bunch of tasks and ensure they are all executed.
// In slowInject, inject slower to trigger the IDLE thread code more often.
static void test_many(bool slowInject)
{
  ThreadPool tp(10);
  counter = 0;
  std::vector<ThreadPool::rTaskLock> v;
  for(int i=0; i<10; ++i)
    v.push_back(new ThreadPool::TaskLock);
  // Start many tasks with random delay and lock
  static const boost::uint32_t nTasks = 8000 / dfactor;
  for (unsigned i=0; i<nTasks; ++i)
  {
    ThreadPool::rTaskLock lock;
    long delay = rand() % 5000;
    if (rand()%100 > 20)
      lock = v[rand()%v.size()];
    tp.queueTask(boost::bind(&task_sleep_inc, delay), lock);
    usleep(rand()%(slowInject?5000:50));
  }
  // Give it 10s to finish, check regularly.
  boost::uint32_t val;
  for (int i=0; i<20; ++i)
  {
    val = atomic_read32(&counter);
    if (val == nTasks)
      break;
    usleep(500000);
  }
  BOOST_CHECK_EQUAL(nTasks, val);
}

static void test_many_slow()
{
  test_many(true);
}

static void test_many_fast()
{
  test_many(false);
}

std::vector<unsigned> lockCheck;

boost::uint32_t errors = 0;

static void task_sleep_check_lock(int delay, unsigned lockid, unsigned lockval)
{
  lockCheck[lockid] = lockval;
  for (int i=0; i<10; ++i)
  {
    usleep(delay/10);
    if (lockCheck[lockid] != lockval)
      atomic_inc32(&errors);
    lockCheck[lockid] = lockval;
  }
  atomic_inc32(&counter);
}

// Test that no two tasks with same lock are executed in parallel.
static void test_lock()
{
  ThreadPool tp(10);
  counter = 0;
  std::vector<ThreadPool::rTaskLock> v;
  for(int i=0; i<10; ++i)
    v.push_back(new ThreadPool::TaskLock);
  lockCheck.resize(v.size());
  static const boost::uint32_t nTasks = 4000 / (dfactor * ((dfactor!=1)+1));
  for (unsigned i=0; i<nTasks; ++i)
  {
    unsigned lockid = rand()%v.size();
    long delay = rand() % 5000;
    tp.queueTask(boost::bind(&task_sleep_check_lock, delay, lockid, i),
                 v[lockid]);
  }
  boost::uint32_t val;
  for (int i=0; i<40; ++i)
  {
    val = atomic_read32(&counter);
    if (val == nTasks)
      break;
    usleep(500000);
  }
  BOOST_CHECK_EQUAL(nTasks, val);
  BOOST_CHECK_EQUAL(errors, 0);
}

test_suite*
init_test_suite()
{
  unsigned int seed = time(0);
  if (char * sseed = getenv("RAND_SEED"))
    seed = boost::lexical_cast<unsigned int>(sseed);
  test_suite* suite = BOOST_TEST_SUITE("libport::ThreadPool test suite");
  BOOST_TEST_MESSAGE("Seed is " << seed);
  if (running("Wine"))
    dfactor = 10;
  srand(seed);
  suite->add(BOOST_TEST_CASE(test_many_slow));
  suite->add(BOOST_TEST_CASE(test_many_fast));
  suite->add(BOOST_TEST_CASE(test_lock));
  return suite;
}
<commit_msg>test thread-pool: Silence a warning.<commit_after>/*
 * Copyright (C) 2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <libport/bind.hh>
#include <libport/lexical-cast.hh>
#include <libport/test.hh>

#include <libport/unistd.h>
#include <libport/thread-pool.hh>

// For atomic increment
#include <boost/interprocess/detail/atomic.hpp>

using boost::interprocess::detail::atomic_inc32;
using boost::interprocess::detail::atomic_read32;

using libport::test_suite;

typedef libport::ThreadPool ThreadPool;

/* Determinism warning: Do not use rand outside main thread!
*/
volatile boost::uint32_t counter;

// Divisor for number of iterations
static boost::uint32_t dfactor = 1;

static void task_sleep_inc(int delay)
{
  usleep(delay);
  atomic_inc32(&counter);
}

// Just start a bunch of tasks and ensure they are all executed.
// In slowInject, inject slower to trigger the IDLE thread code more often.
static void test_many(bool slowInject)
{
  ThreadPool tp(10);
  counter = 0;
  std::vector<ThreadPool::rTaskLock> v;
  for(int i=0; i<10; ++i)
    v.push_back(new ThreadPool::TaskLock);
  // Start many tasks with random delay and lock
  static const boost::uint32_t nTasks = 8000 / dfactor;
  for (unsigned i=0; i<nTasks; ++i)
  {
    ThreadPool::rTaskLock lock;
    long delay = rand() % 5000;
    if (rand()%100 > 20)
      lock = v[rand()%v.size()];
    tp.queueTask(boost::bind(&task_sleep_inc, delay), lock);
    usleep(rand()%(slowInject?5000:50));
  }
  // Give it 10s to finish, check regularly.
  boost::uint32_t val;
  for (int i=0; i<20; ++i)
  {
    val = atomic_read32(&counter);
    if (val == nTasks)
      break;
    usleep(500000);
  }
  BOOST_CHECK_EQUAL(nTasks, val);
}

static void test_many_slow()
{
  test_many(true);
}

static void test_many_fast()
{
  test_many(false);
}

std::vector<unsigned> lockCheck;

boost::uint32_t errors = 0;

static void task_sleep_check_lock(int delay, unsigned lockid, unsigned lockval)
{
  lockCheck[lockid] = lockval;
  for (int i=0; i<10; ++i)
  {
    usleep(delay/10);
    if (lockCheck[lockid] != lockval)
      atomic_inc32(&errors);
    lockCheck[lockid] = lockval;
  }
  atomic_inc32(&counter);
}

// Test that no two tasks with same lock are executed in parallel.
static void test_lock()
{
  ThreadPool tp(10);
  counter = 0;
  std::vector<ThreadPool::rTaskLock> v;
  for(int i=0; i<10; ++i)
    v.push_back(new ThreadPool::TaskLock);
  lockCheck.resize(v.size());
  static const boost::uint32_t nTasks = 4000 / (dfactor * ((dfactor!=1)+1));
  for (unsigned i=0; i<nTasks; ++i)
  {
    unsigned lockid = rand()%v.size();
    long delay = rand() % 5000;
    tp.queueTask(boost::bind(&task_sleep_check_lock, delay, lockid, i),
                 v[lockid]);
  }
  boost::uint32_t val;
  for (int i=0; i<40; ++i)
  {
    val = atomic_read32(&counter);
    if (val == nTasks)
      break;
    usleep(500000);
  }
  BOOST_CHECK_EQUAL(nTasks, val);
  BOOST_CHECK_EQUAL(errors, 0U);
}

test_suite*
init_test_suite()
{
  unsigned int seed = time(0);
  if (char * sseed = getenv("RAND_SEED"))
    seed = boost::lexical_cast<unsigned int>(sseed);
  test_suite* suite = BOOST_TEST_SUITE("libport::ThreadPool test suite");
  BOOST_TEST_MESSAGE("Seed is " << seed);
  if (running("Wine"))
    dfactor = 10;
  srand(seed);
  suite->add(BOOST_TEST_CASE(test_many_slow));
  suite->add(BOOST_TEST_CASE(test_many_fast));
  suite->add(BOOST_TEST_CASE(test_lock));
  return suite;
}
<|endoftext|>


<commit_before>#ifdef TREE_HPP

#include <cstddef>
#include <cstdlib>

int compare( const int left, const int right );

template < class T >
Tree< T >::Tree() {
    this->root = nullptr;
}

template < class T >
Tree< T >::~Tree() {
    destroy( &( this->root ) );
}

template < class T >
void Tree< T >::destroy( Node< T >** node ) {
    if( *node != nullptr ) {
        destroy( &( *node )->left );
        destroy( &( *node )->right );
        delete( *node );
        node = nullptr;
    }
    return;
}

template < class T >
std::ostream& Tree< T >::display( std::ostream& out, Node< T >* const node ) const {
    if( node != nullptr ) {
        display( out, node->left );
        out << node->getValue() << ' ';
        display( out, node->right );
    }
    return out;
}

template < class T >
void Tree< T >::insert( const int& key, const T& value ) {
    insert( &( this->root ), key, value );
}

template < class T >
void Tree< T >::insert( Node< T >** node, const int& key, const T& value ) {
    if( *node == nullptr ) {
        *node = new Node< T >( key, value, nullptr, nullptr );
        return;

    } else if( key < ( *node )->getKey() ) {
        insert( &( ( *node )->left ), key, value );
    } else if( key > ( *node )->getKey() ) {
        insert( &( ( *node )->right ), key, value );
    } else {
        throw std::runtime_error( "Duplicate key" );
    }
}

template < class T >
bool Tree< T >::searchByKey( const int& key ) const {
    Node< T >* node = this->root;

    while( node != nullptr && key != node->getKey() ) {
        if( key < node->getKey() ) {
            node = node->left;
        } else {
            node = node->right;
        }
    }

    return node != nullptr;
}

template < class T >
int Tree< T >::searchByValue( const T& value ) const {
    Node< T >* node = searchByValue( this->root, value );

    if( node == nullptr ) {
        throw std::runtime_error( "No search results found" );
    }

    return node->getKey();
}

template < class T >
Node< T >* Tree< T >::searchByValue( Node< T >* const node, const T& value ) const {
    if( node == nullptr || value == node->getValue() ) {
        return node;
    }

    Node< T >* left  = searchByValue( node->left, value );
    Node< T >* right = searchByValue( node->right, value );

    if( left != nullptr && value == left->getValue() ) {
        return left;
    } else if( right != nullptr && value == right->getValue() ) {
        return right;
    } else {
        return nullptr;
    }
}

template < class T >
void Tree< T >::rotateLeft( Node< T >** root ) {
    Node< T >* node  = ( *root )->right;
    ( *root )->right = node->left;

    node->left = *root;

    *root->height = compare( *root->left->height, *root->right->height ) + 1;
    node->height  = compare( node->right->height, *root->height ) + 1;

    *root = node;
}

template < class T >
void Tree< T >::rotateRight( Node< T >** root ) {
    Node< T >* node = ( *root )->left;
    ( *root )->left = node->right;

    node->right = *root;

    *root->height = compare( *root->left->height, *root->right->height ) + 1;
    node->height  = compare( node->left->height, *root->height ) + 1;

    *root = node;
}

template < class T >
void Tree< T >::doubleRotateLeft( Node< T >** root ) {
    if( *root == nullptr ) {
        return;
    }

    rotateRight( &( *root )->right );
    rotateLeft( root );
}

template < class T >
void Tree< T >::doubleRotateRight( Node< T >** root ) {
    if( *root == nullptr ) {
        return;
    }

    rotateLeft( &( *root )->left );
    rotateRight( root );
}

template < class T >
int Tree< T >::factor( Node< T >* node ) {
    if( node->left != nullptr && node->right != nullptr ) {
        return abs( node->left->height - node->right->height );
    } else if( node->left != nullptr && node->right == nullptr ) {
        return abs( node->left->height - 0 );
    } else if( node->left == nullptr && node->right != nullptr ) {
        return abs( 0 - node->right->height );
    } else {
        return 0;
    }
}

int compare( const int left, const int right ) {
    if( left > right ) {
        return left;
    } else {
        return right;
    }
}

#endif<commit_msg>Criada função para pegar altura do nó, corrigidas as funções de calcular fator de labanceamento, rotação a direita, rotação a esquerda e fazendo rotação durante a inserção<commit_after>#ifdef TREE_HPP

#include <cstddef>
#include <cstdlib>

int compare( const int left, const int right );
template < class T >
int heightNode( Node< T >* node );

template < class T >
Tree< T >::Tree() {
    this->root = nullptr;
}

template < class T >
Tree< T >::~Tree() {
    destroy( &( this->root ) );
}

template < class T >
void Tree< T >::destroy( Node< T >** node ) {
    if( *node != nullptr ) {
        destroy( &( *node )->left );
        destroy( &( *node )->right );
        delete( *node );
        node = nullptr;
    }
    return;
}

template < class T >
std::ostream& Tree< T >::display( std::ostream& out, Node< T >* const node ) const {
    if( node != nullptr ) {
        display( out, node->left );
        out << node->getValue() << ' ';
        display( out, node->right );
    }
    return out;
}

template < class T >
void Tree< T >::insert( const int& key, const T& value ) {
    insert( &( this->root ), key, value );
}

template < class T >
void Tree< T >::insert( Node< T >** node, const int& key, const T& value ) {
    if( *node == nullptr ) {
        *node = new Node< T >( key, value, nullptr, nullptr );
        return;
    } else if( key < ( *node )->getKey() ) {
        insert( &( ( *node )->left ), key, value );
        if( factor( *node ) >= 2 ) {
            if( key < ( *node )->left->getKey() ) {
                rotateRight( node );
            } else {
                doubleRotateRight( node );
            }
        }
    } else if( key > ( *node )->getKey() ) {
        insert( &( ( *node )->right ), key, value );
        if( factor( *node ) >= 2 ) {
            if( key > ( *node )->right->getKey() ) {
                rotateLeft( node );
            } else {
                doubleRotateLeft( node );
            }
        }
    } else {
        throw std::runtime_error( "Duplicate key" );
    }

    ( *node )->height =
        compare( heightNode( ( *node )->left ), heightNode( ( *node )->right ) ) + 1;
}

template < class T >
bool Tree< T >::searchByKey( const int& key ) const {
    Node< T >* node = this->root;

    while( node != nullptr && key != node->getKey() ) {
        if( key < node->getKey() ) {
            node = node->left;
        } else {
            node = node->right;
        }
    }

    return node != nullptr;
}

template < class T >
int Tree< T >::searchByValue( const T& value ) const {
    Node< T >* node = searchByValue( this->root, value );

    if( node == nullptr ) {
        throw std::runtime_error( "No search results found" );
    }

    return node->getKey();
}

template < class T >
Node< T >* Tree< T >::searchByValue( Node< T >* const node, const T& value ) const {
    if( node == nullptr || value == node->getValue() ) {
        return node;
    }

    Node< T >* left  = searchByValue( node->left, value );
    Node< T >* right = searchByValue( node->right, value );

    if( left != nullptr && value == left->getValue() ) {
        return left;
    } else if( right != nullptr && value == right->getValue() ) {
        return right;
    } else {
        return nullptr;
    }
}

template < class T >
void Tree< T >::rotateLeft( Node< T >** root ) {
    Node< T >* node  = ( *root )->right;
    ( *root )->right = node->left;

    node->left = *root;

    ( *root )->height =
        compare( heightNode( ( *root )->left ), heightNode( ( *root )->right ) ) + 1;
    node->height = compare( heightNode( node->right ), ( *root )->height ) + 1;

    *root = node;
}

template < class T >
void Tree< T >::rotateRight( Node< T >** root ) {
    Node< T >* node = ( *root )->left;
    ( *root )->left = node->right;

    node->right = *root;

    ( *root )->height =
        compare( heightNode( ( *root )->left ), heightNode( ( *root )->right ) ) + 1;
    node->height = compare( heightNode( node->left ), ( *root )->height ) + 1;

    *root = node;
}

template < class T >
void Tree< T >::doubleRotateLeft( Node< T >** root ) {
    if( *root == nullptr ) {
        return;
    }

    rotateRight( &( *root )->right );
    rotateLeft( root );
}

template < class T >
void Tree< T >::doubleRotateRight( Node< T >** root ) {
    if( *root == nullptr ) {
        return;
    }

    rotateLeft( &( *root )->left );
    rotateRight( root );
}

template < class T >
int Tree< T >::factor( Node< T >* node ) {
    return abs( heightNode( node->left ) - heightNode( node->right ) );
}

int compare( const int left, const int right ) {
    if( left > right ) {
        return left;
    } else {
        return right;
    }
}

template < class T >
int heightNode( Node< T >* node ) {
    if( node == nullptr ) {
        return -1;
    } else {
        return node->height;
    }
}

#endif<|endoftext|>


<commit_before>// Copyright (C) 2010-2012 Joshua Boyce.
// See the file COPYING for copying permission.

#include "hadesmem/pelib/section_list.hpp"

#include <sstream>
#include <utility>

#define BOOST_TEST_MODULE section_list
#include "hadesmem/detail/warning_disable_prefix.hpp"
#include <boost/test/unit_test.hpp>
#include "hadesmem/detail/warning_disable_suffix.hpp"

#include "hadesmem/read.hpp"
#include "hadesmem/error.hpp"
#include "hadesmem/config.hpp"
#include "hadesmem/module.hpp"
#include "hadesmem/process.hpp"
#include "hadesmem/module_list.hpp"
#include "hadesmem/pelib/pe_file.hpp"
#include "hadesmem/pelib/section.hpp"
#include "hadesmem/pelib/nt_headers.hpp"

// Boost.Test causes the following warning under GCC:
// error: base class 'struct boost::unit_test::ut_detail::nil_t' has a
// non-virtual destructor [-Werror=effc++]
#if defined(HADESMEM_GCC)
#pragma GCC diagnostic ignored "-Weffc++"
#endif // #if defined(HADESMEM_GCC)

// Boost.Test causes the following warning under Clang:
// error: declaration requires a global constructor
// [-Werror,-Wglobal-constructors]
#if defined(HADESMEM_CLANG)
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#endif // #if defined(HADESMEM_CLANG)

BOOST_AUTO_TEST_CASE(section_list)
{
  hadesmem::Process const process(::GetCurrentProcessId());

  hadesmem::PeFile pe_file_1(process, GetModuleHandle(nullptr),
    hadesmem::PeFileType::Image);

  hadesmem::NtHeaders nt_headers_1(process, pe_file_1);

  BOOST_CHECK(nt_headers_1.GetNumberOfSections() >= 1);

  hadesmem::Section section_1(process, pe_file_1, 0);

  hadesmem::Section section_2(section_1);
  BOOST_CHECK_EQUAL(section_1, section_2);
  section_1 = section_2;
  BOOST_CHECK_EQUAL(section_1, section_2);
  hadesmem::Section section_3(std::move(section_2));
  BOOST_CHECK_EQUAL(section_3, section_1);
  section_2 = std::move(section_3);
  BOOST_CHECK_EQUAL(section_1, section_2);

  hadesmem::ModuleList modules(process);
  for (auto const& mod : modules)
  {
    // TODO: Also test FileType_Data
    hadesmem::PeFile const pe_file(process, mod.GetHandle(),
      hadesmem::PeFileType::Data);

    hadesmem::NtHeaders const nt_headers(process, pe_file);
    WORD const num_sections = nt_headers.GetNumberOfSections();

    // Assume every module has at least one section.
    // TODO: Better tests.
    hadesmem::SectionList sections(process, pe_file);
    WORD section_count = 0;
    for (auto const& section : sections)
    {
      section_count += 1;

      auto const section_header_raw = hadesmem::Read<IMAGE_SECTION_HEADER>(
        process, section.GetBase());

      section.SetName(section.GetName());
      section.SetVirtualAddress(section.GetVirtualAddress());
      section.SetVirtualSize(section.GetVirtualSize());
      section.SetSizeOfRawData(section.GetSizeOfRawData());
      section.SetPointerToRawData(section.GetPointerToRawData());
      section.SetPointerToRelocations(section.GetPointerToRelocations());
      section.SetPointerToLinenumbers(section.GetPointerToLinenumbers());
      section.SetNumberOfRelocations(section.GetNumberOfRelocations());
      section.SetNumberOfLinenumbers(section.GetNumberOfLinenumbers());
      section.SetCharacteristics(section.GetCharacteristics());

      auto const section_header_raw_new = hadesmem::Read<IMAGE_SECTION_HEADER>(
        process, section.GetBase());

      BOOST_CHECK_EQUAL(std::memcmp(&section_header_raw,
        &section_header_raw_new, sizeof(section_header_raw)), 0);

      std::stringstream test_str_1;
      test_str_1.imbue(std::locale::classic());
      test_str_1 << section;
      std::stringstream test_str_2;
      test_str_2.imbue(std::locale::classic());
      test_str_2 << section.GetBase();
      BOOST_CHECK_EQUAL(test_str_1.str(), test_str_2.str());
      if (mod.GetHandle() != GetModuleHandle(L"ntdll"))
      {
        hadesmem::PeFile const pe_file_ntdll(process,
          GetModuleHandle(L"ntdll"), hadesmem::PeFileType::Image);
        hadesmem::Section const section_ntdll(process, pe_file_ntdll, 0);
        std::stringstream test_str_3;
        test_str_3.imbue(std::locale::classic());
        test_str_3 << section_ntdll.GetBase();
        BOOST_CHECK_NE(test_str_1.str(), test_str_3.str());
      }
    }
    BOOST_CHECK(section_count == num_sections);

    // Assume every module has a '.text' section.
    // TODO: Better tests.
    auto text_iter = std::find_if(std::begin(sections), std::end(sections),
      [] (hadesmem::Section const& section)
      {
        return section.GetName() == ".text";
      });
    BOOST_CHECK(text_iter != std::end(sections));
  }
}
<commit_msg>* Change test to one that would've caught the previous SectionList bug.<commit_after>// Copyright (C) 2010-2012 Joshua Boyce.
// See the file COPYING for copying permission.

#include "hadesmem/pelib/section_list.hpp"

#include <sstream>
#include <utility>

#define BOOST_TEST_MODULE section_list
#include "hadesmem/detail/warning_disable_prefix.hpp"
#include <boost/test/unit_test.hpp>
#include "hadesmem/detail/warning_disable_suffix.hpp"

#include "hadesmem/read.hpp"
#include "hadesmem/error.hpp"
#include "hadesmem/config.hpp"
#include "hadesmem/module.hpp"
#include "hadesmem/process.hpp"
#include "hadesmem/module_list.hpp"
#include "hadesmem/pelib/pe_file.hpp"
#include "hadesmem/pelib/section.hpp"
#include "hadesmem/pelib/nt_headers.hpp"

// Boost.Test causes the following warning under GCC:
// error: base class 'struct boost::unit_test::ut_detail::nil_t' has a
// non-virtual destructor [-Werror=effc++]
#if defined(HADESMEM_GCC)
#pragma GCC diagnostic ignored "-Weffc++"
#endif // #if defined(HADESMEM_GCC)

// Boost.Test causes the following warning under Clang:
// error: declaration requires a global constructor
// [-Werror,-Wglobal-constructors]
#if defined(HADESMEM_CLANG)
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#endif // #if defined(HADESMEM_CLANG)

BOOST_AUTO_TEST_CASE(section_list)
{
  hadesmem::Process const process(::GetCurrentProcessId());

  hadesmem::PeFile pe_file_1(process, GetModuleHandle(nullptr),
    hadesmem::PeFileType::Image);

  hadesmem::NtHeaders nt_headers_1(process, pe_file_1);

  BOOST_CHECK(nt_headers_1.GetNumberOfSections() >= 1);

  hadesmem::Section section_1(process, pe_file_1, 0);

  hadesmem::Section section_2(section_1);
  BOOST_CHECK_EQUAL(section_1, section_2);
  section_1 = section_2;
  BOOST_CHECK_EQUAL(section_1, section_2);
  hadesmem::Section section_3(std::move(section_2));
  BOOST_CHECK_EQUAL(section_3, section_1);
  section_2 = std::move(section_3);
  BOOST_CHECK_EQUAL(section_1, section_2);

  hadesmem::ModuleList modules(process);
  for (auto const& mod : modules)
  {
    // TODO: Also test FileType_Data
    hadesmem::PeFile const pe_file(process, mod.GetHandle(),
      hadesmem::PeFileType::Data);

    hadesmem::NtHeaders const nt_headers(process, pe_file);
    WORD const num_sections = nt_headers.GetNumberOfSections();

    // Assume every module has at least one section.
    // TODO: Better tests.
    hadesmem::SectionList sections(process, pe_file);
    WORD section_count = 0;
    for (auto const& section : sections)
    {
      section_count += 1;

      auto const section_header_raw = hadesmem::Read<IMAGE_SECTION_HEADER>(
        process, section.GetBase());

      section.SetName(section.GetName());
      section.SetVirtualAddress(section.GetVirtualAddress());
      section.SetVirtualSize(section.GetVirtualSize());
      section.SetSizeOfRawData(section.GetSizeOfRawData());
      section.SetPointerToRawData(section.GetPointerToRawData());
      section.SetPointerToRelocations(section.GetPointerToRelocations());
      section.SetPointerToLinenumbers(section.GetPointerToLinenumbers());
      section.SetNumberOfRelocations(section.GetNumberOfRelocations());
      section.SetNumberOfLinenumbers(section.GetNumberOfLinenumbers());
      section.SetCharacteristics(section.GetCharacteristics());

      auto const section_header_raw_new = hadesmem::Read<IMAGE_SECTION_HEADER>(
        process, section.GetBase());

      BOOST_CHECK_EQUAL(std::memcmp(&section_header_raw,
        &section_header_raw_new, sizeof(section_header_raw)), 0);

      std::stringstream test_str_1;
      test_str_1.imbue(std::locale::classic());
      test_str_1 << section;
      std::stringstream test_str_2;
      test_str_2.imbue(std::locale::classic());
      test_str_2 << section.GetBase();
      BOOST_CHECK_EQUAL(test_str_1.str(), test_str_2.str());
      if (mod.GetHandle() != GetModuleHandle(L"ntdll"))
      {
        hadesmem::PeFile const pe_file_ntdll(process,
          GetModuleHandle(L"ntdll"), hadesmem::PeFileType::Image);
        hadesmem::Section const section_ntdll(process, pe_file_ntdll, 0);
        std::stringstream test_str_3;
        test_str_3.imbue(std::locale::classic());
        test_str_3 << section_ntdll.GetBase();
        BOOST_CHECK_NE(test_str_1.str(), test_str_3.str());
      }
    }
    BOOST_CHECK(section_count == num_sections);

    // Assume every module has a '.text' section.
    // TODO: Better tests.
    auto text_iter = std::find_if(std::begin(sections), std::end(sections),
      [] (hadesmem::Section const& section)
      {
        return section.GetName() == ".data";
      });
    BOOST_CHECK(text_iter != std::end(sections));
  }
}
<|endoftext|>


<commit_before>#ifndef MJOLNIR_BOUNDARY_CONDITION
#define MJOLNIR_BOUNDARY_CONDITION
#include <cassert>

namespace mjolnir
{

template<typename realT, typename coordT>
struct UnlimitedBoundary
{
    typedef realT  real_type;
    typedef coordT coordiante_type;

    UnlimitedBoundary() = default;
    ~UnlimitedBoundary() = default;

    coordinate_type adjust_direction(coordinate_type dr) const {return dr;}
    coordinate_type adjust_position (coordinate_type r ) const {return r;}
};

template<typename realT, typename coordT>
struct CubicPeriodicBoundary
{
  public:
    typedef realT  real_type;
    typedef coordT coordiante_type;

  public:
    CubicPeriodicBoundary() = default;
    ~CubicPeriodicBoundary() = default;
    CubicPeriodicBoundary(const coordinate_type& lw, const coordinate_type& up)
    : lower(lw), upper(up), system_size(up-lw), system_size_half(0.5*(up-lw))
    {}

    coordinate_type adjust_direction(coordinate_type dr) const
    {
             if(dr[0] < -system_size_half[0]) dr[0] += system_size[0];
        else if(dr[0] >  system_size_half[0]) dr[0] -= system_size[0];
             if(dr[1] < -system_size_half[1]) dr[1] += system_size[1];
        else if(dr[1] >  system_size_half[1]) dr[1] -= system_size[1];
             if(dr[2] < -system_size_half[2]) dr[2] += system_size[2];
        else if(dr[2] >  system_size_half[2]) dr[2] -= system_size[2];
        return dr;
    }

    coordinate_type adjust_position(coordinate_type pos) const
    {
             if(pos[0] < lower[0]) pos[0] += system_size_[0];
        else if(pos[0] > upper[0]) pos[0] -= system_size_[0];
             if(pos[1] < lower[1]) pos[1] += system_size_[1];
        else if(pos[1] > upper[1]) pos[1] -= system_size_[1];
             if(pos[2] < lower[2]) pos[2] += system_size_[2];
        else if(pos[2] > upper[2]) pos[2] -= system_size_[2];
        return pos;
    }

    coordinate_type&       lower_bound()       {return lower;}
    coordinate_type const& lower_bound() const {return lower;}
    coordinate_type&       upper_bound()       {return upper;}
    coordinate_type const& upper_bound() const {return upper;}
    coordinate_type const& range() const {return system_size;}

  private:

    coordinate_type lower;
    coordinate_type upper;
    coordinate_type system_size;
    coordinate_type system_size_half;
};

}//mjolnir
#endif /* MJOLNIR_BOUNDARY_CONDITION */
<commit_msg>add noexcept to boundary<commit_after>#ifndef MJOLNIR_BOUNDARY_CONDITION
#define MJOLNIR_BOUNDARY_CONDITION
#include <cassert>

namespace mjolnir
{

template<typename realT, typename coordT>
struct UnlimitedBoundary
{
    typedef realT  real_type;
    typedef coordT coord_type;

    UnlimitedBoundary() = default;
    ~UnlimitedBoundary() = default;

    coord_type adjust_direction(coord_type dr) const noexcept {return dr;}
    coord_type adjust_position (coord_type r ) const noexcept {return r;}
};

template<typename realT, typename coordT>
struct CubicPeriodicBoundary
{
  public:
    typedef realT  real_type;
    typedef coordT coordiante_type;

  public:
    CubicPeriodicBoundary() = default;
    ~CubicPeriodicBoundary() = default;
    CubicPeriodicBoundary(const coordinate_type& lw, const coordinate_type& up)
    : lower(lw), upper(up), system_size(up-lw), system_size_half(0.5*(up-lw))
    {}

    coordinate_type adjust_direction(coordinate_type dr) const noexcept
    {
             if(dr[0] < -system_size_half[0]) dr[0] += system_size[0];
        else if(dr[0] >  system_size_half[0]) dr[0] -= system_size[0];
             if(dr[1] < -system_size_half[1]) dr[1] += system_size[1];
        else if(dr[1] >  system_size_half[1]) dr[1] -= system_size[1];
             if(dr[2] < -system_size_half[2]) dr[2] += system_size[2];
        else if(dr[2] >  system_size_half[2]) dr[2] -= system_size[2];
        return dr;
    }

    coordinate_type adjust_position(coordinate_type pos) const noexcept
    {
             if(pos[0] < lower[0]) pos[0] += system_size_[0];
        else if(pos[0] > upper[0]) pos[0] -= system_size_[0];
             if(pos[1] < lower[1]) pos[1] += system_size_[1];
        else if(pos[1] > upper[1]) pos[1] -= system_size_[1];
             if(pos[2] < lower[2]) pos[2] += system_size_[2];
        else if(pos[2] > upper[2]) pos[2] -= system_size_[2];
        return pos;
    }

    coordinate_type&       lower_bound()       {return lower;}
    coordinate_type const& lower_bound() const {return lower;}
    coordinate_type&       upper_bound()       {return upper;}
    coordinate_type const& upper_bound() const {return upper;}
    coordinate_type const& range() const {return system_size;}

  private:

    coordinate_type lower;
    coordinate_type upper;
    coordinate_type system_size;
    coordinate_type system_size_half;
};

}//mjolnir
#endif /* MJOLNIR_BOUNDARY_CONDITION */
<|endoftext|>


<commit_before>#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE libmace
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>
#include "ContextService.h"
#include "AccessLine.h"
#include "MaceKey.h"
#include "HeadEventDispatch.h"

namespace mace{
  class __ServiceStackEvent__;
  class __ScopedTransition__;
  class __ScopedRoutine__;
};
// LocalService is for non-distributed service.
class __LocalTransition__;
class LocalService: public ContextService {
friend class __LocalTransition__;
public:
  LocalService():  ContextService()
  {
    mace::map<mace::MaceAddr ,mace::list<mace::string > > servContext;
    loadContextMapping( servContext);
  }
protected:
  virtual void dispatchDeferredMessages(MaceKey const& dest, mace::string const& message,  registration_uid_t const rid ) {}// no messages
  virtual void executeDeferredUpcall( mace::Message* const upcall, mace::string& returnValue ) { }
};
class __LocalTransition__{
public:
    __LocalTransition__( LocalService* service, int8_t const eventType, mace::string const& targetContextName = "", mace::vector< mace::string > const& snapshotContextNames = mace::vector< mace::string >() ) {
      mace::vector< uint32_t > snapshotContextIDs;
      mace::__ServiceStackEvent__ sse( eventType, service, targetContextName );
      const mace::ContextMapping& currentMapping = service->contextMapping.getSnapshot();
      const uint32_t targetContextID = currentMapping.findIDByName( targetContextName );
      for_each( snapshotContextNames.begin(), snapshotContextNames.end(), mace::addSnapshotContextID( currentMapping, snapshotContextIDs ) );
      mace::AccessLine al( service->instanceUniqueID, targetContextID, currentMapping );

      p = new mace::__ScopedTransition__( service, targetContextID );
    }
    ~__LocalTransition__(){
      delete p;
    }

private:
  mace::__ScopedTransition__* p;
};

// InContextService is similar to mace-incontext system
template< class GlobalContextType >
class InContextService: public LocalService {
friend class mace::__ServiceStackEvent__;
public:
  InContextService():  LocalService(), globalContext(NULL) { }
private:
  GlobalContextType* globalContext;
  mace::ContextBaseClass* createContextObject( mace::string const& contextTypeName ){
    ASSERT( contextTypeName.empty() );
    ASSERT( globalContext == NULL );

    globalContext = new GlobalContextType();
    return globalContext;

  }
};
namespace mace {
  // a specialized message type. This message is used for storing information and passed around between threads, therefore it will not do serialization
  class LocalMessage: public mace::AsyncEvent_Message, public mace::PrintPrintable{
    virtual void print( std::ostream& __out ) const {
      __out << "LocalMessage()";
    }
    virtual void serialize( std::string& str ) const{ } // empty
    virtual int deserialize( std::istream& __in ) throw (mace::SerializationException){ return 0;}
  };

}
struct __async_req: public mace::LocalMessage{
  static const uint8_t messageType =12;
  uint8_t getType() const{ return messageType; }
  __asyncExtraField& getExtra() { return extra; }
  mace::Event& getEvent() { return event; }
  mace::Event event;
  mace::__asyncExtraField extra;
};
template< class GlobalContextType >
class Test1Service: public InContextService< GlobalContextType > {
public:
  Test1Service():  InContextService< GlobalContextType >() { }
  void maceInit(){ // access the global context
    this->registerInstanceID();
    __LocalTransition__ lt( this, mace::Event::STARTEVENT );
    __real_maceInit();

  }
  void maceExit(){ // access the global context
    __LocalTransition__ lt( this, mace::Event::ENDEVENT );
    __real_maceExit();
  }
private:
  void __real_maceInit(){
    async_test();
  }
  void __real_maceExit(){

  }
  void async_test(){

    __async_req* req = new __async_req;
    this->addEventRequest( req );
  }
  void test( __async_req* msg){

    {
      this->__beginRemoteMethod( msg->event );
      mace::__ScopedTransition__ (this, msg->extra );

      async_test();
    }

    delete msg;
  }
  int deserializeMethod( std::istream& is, mace::Message*& eventObject   )  {
    uint8_t msgNum_s = static_cast<uint8_t>(is.peek() ) ;
    switch( msgNum_s  ){
      case __async_req::messageType: {
        eventObject = new __async_req;
        return mace::deserialize( is, eventObject );
        break;
      }
      default:
        ABORT("message type not found");
    }
  };
  void executeEvent( mace::AsyncEvent_Message* __param ){
    mace::Message *msg = static_cast< mace::Message* >( __param ) ;
    switch( msg->getType()  ){
      case __async_req::messageType: {
        __async_req* __msg = static_cast< __async_req *>( msg ) ;
        test( __msg );
        break;
      }
    }
  }
  void executeRoutine(mace::Routine_Message* __param, mace::MaceAddr const & source){

  }

};
class GlobalContext: public mace::ContextBaseClass{
public:
  GlobalContext( const mace::string& contextName="", const uint64_t eventID=0, const uint8_t instanceUniqueID=0, const uint32_t contextID=0 ):
    mace::ContextBaseClass( contextName, eventID, instanceUniqueID, contextID ){
  }
private:
  // declare context variables here
};

int main(int argc, char* argv[]){
  mace::Init( argc, argv );
  const char *_argv[] = {""};
  int _argc = 1;
  ::boost::unit_test::unit_test_main( &init_unit_test, _argc, const_cast<char**>(_argv) );

  mace::Shutdown();
}

BOOST_AUTO_TEST_SUITE( lib_ContextService )

BOOST_AUTO_TEST_CASE( Case1 )
{ // test single services
  // test: create start event, async event, timer event, message delivery event, downcall event, upcall event,
  //       test routines (local)
  BOOST_TEST_CHECKPOINT("Constructor");
  Test1Service<GlobalContext> service1;
  BOOST_TEST_CHECKPOINT("maceInit");
  service1.maceInit();
  SysUtil::sleep( 10 );
  BOOST_TEST_CHECKPOINT("maceExit");
  service1.maceExit();
}
BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Fixed a bug in ContextService_test and make it conformant to the current runtime.<commit_after>#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE libmace
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>
#include "ContextService.h"
#include "AccessLine.h"
#include "MaceKey.h"
#include "HeadEventDispatch.h"

namespace mace{
  class __ServiceStackEvent__;
  class __ScopedTransition__;
  class __ScopedRoutine__;
};
// LocalService is for non-distributed service.
using mace::__CheckTransition__;
class __LocalTransition__;
class LocalService: public ContextService {
friend class __LocalTransition__;
public:
  LocalService():  ContextService()
  {
    mace::map<mace::MaceAddr ,mace::list<mace::string > > servContext;
    loadContextMapping( servContext);
  }
protected:
  virtual void dispatchDeferredMessages(MaceKey const& dest, mace::string const& message,  registration_uid_t const rid ) {}// no messages
  virtual void executeDeferredUpcall( mace::Message* const upcall, mace::string& returnValue ) { }
};
class __LocalTransition__{
public:
    __LocalTransition__( LocalService* service, int8_t const eventType, mace::string const& targetContextName = "", mace::vector< mace::string > const& snapshotContextNames = mace::vector< mace::string >() ) {
      mace::vector< uint32_t > snapshotContextIDs;
      mace::__ServiceStackEvent__ sse( eventType, service, targetContextName );
      const mace::ContextMapping& currentMapping = service->contextMapping.getSnapshot();
      const uint32_t targetContextID = currentMapping.findIDByName( targetContextName );
      for_each( snapshotContextNames.begin(), snapshotContextNames.end(), mace::addSnapshotContextID( currentMapping, snapshotContextIDs ) );
      mace::AccessLine al( service->instanceUniqueID, targetContextID, currentMapping );

      p = new mace::__ScopedTransition__( service, targetContextID );
    }
    ~__LocalTransition__(){
      delete p;
    }

private:
  mace::__ScopedTransition__* p;
};

// InContextService is similar to mace-incontext system
template< class GlobalContextType >
class InContextService: public LocalService {
friend class mace::__ServiceStackEvent__;
public:
  InContextService():  LocalService(), globalContext(NULL) { }
private:
  GlobalContextType* globalContext;
  mace::ContextBaseClass* createContextObject( mace::string const& contextTypeName ){
    ASSERT( contextTypeName.empty() );
    ASSERT( globalContext == NULL );

    globalContext = new GlobalContextType();
    return globalContext;

  }
};
namespace mace {
  // a specialized message type. This message is used for storing information and passed around between threads, therefore it will not do serialization
  class LocalMessage: public mace::AsyncEvent_Message, public mace::PrintPrintable{
    virtual void print( std::ostream& __out ) const {
      __out << "LocalMessage()";
    }
    virtual void serialize( std::string& str ) const{ } // empty
    virtual int deserialize( std::istream& __in ) throw (mace::SerializationException){ return 0;}
  };

}
struct __async_req: public mace::LocalMessage{
  static const uint8_t messageType =12;
  uint8_t getType() const{ return messageType; }
  __asyncExtraField& getExtra() { return extra; }
  mace::Event& getEvent() { return event; }
  mace::Event event;
  mace::__asyncExtraField extra;
};
template< class GlobalContextType >
class Test1Service: public InContextService< GlobalContextType > {
public:
  Test1Service():  InContextService< GlobalContextType >() { }
  void maceInit(){ // access the global context
    this->registerInstanceID();
    //__LocalTransition__ lt( this, mace::Event::STARTEVENT );
    __CheckTransition__ cm( this, mace::Event::STARTEVENT, "" );
    __real_maceInit();

  }
  void maceExit(){ // access the global context
    //__LocalTransition__ lt( this, mace::Event::ENDEVENT );
    __CheckTransition__ cm( this, mace::Event::ENDEVENT, "" );
    __real_maceExit();
  }
private:
  void __real_maceInit(){
    async_test();
  }
  void __real_maceExit(){

  }
  void async_test(){

    __async_req* req = new __async_req;
    this->addEventRequest( req );
  }
  void test( __async_req* msg){

    async_test();

  }
  int deserializeMethod( std::istream& is, mace::Message*& eventObject   )  {
    uint8_t msgNum_s = static_cast<uint8_t>(is.peek() ) ;
    switch( msgNum_s  ){
      case __async_req::messageType: {
        eventObject = new __async_req;
        return mace::deserialize( is, eventObject );
        break;
      }
      default:
        ABORT("message type not found");
    }
  };
  void executeEvent( mace::AsyncEvent_Message* __param ){
    this->__beginRemoteMethod( __param->getEvent() );
    mace::__ScopedTransition__ st(this, __param->getExtra() );

    mace::Message *msg = static_cast< mace::Message* >( __param ) ;
    switch( msg->getType()  ){
      case __async_req::messageType: {
        __async_req* __msg = static_cast< __async_req *>( msg ) ;
        test( __msg );
        break;
      }
    }
    delete __param;
  }
  void executeRoutine(mace::Routine_Message* __param, mace::MaceAddr const & source){

  }

};
class GlobalContext: public mace::ContextBaseClass{
public:
  GlobalContext( const mace::string& contextName="", const uint64_t eventID=0, const uint8_t instanceUniqueID=0, const uint32_t contextID=0 ):
    mace::ContextBaseClass( contextName, eventID, instanceUniqueID, contextID ){
  }
private:
  // declare context variables here
};

int main(int argc, char* argv[]){
  mace::Init( argc, argv );
  const char *_argv[] = {""};
  int _argc = 1;
  ::boost::unit_test::unit_test_main( &init_unit_test, _argc, const_cast<char**>(_argv) );

  mace::Shutdown();
}

BOOST_AUTO_TEST_SUITE( lib_ContextService )

BOOST_AUTO_TEST_CASE( Case1 )
{ // test single services
  // test: create start event, async event, timer event, message delivery event, downcall event, upcall event,
  //       test routines (local)
  BOOST_TEST_CHECKPOINT("Constructor");
  Test1Service<GlobalContext> service1;
  BOOST_TEST_CHECKPOINT("maceInit");
  service1.maceInit();
  SysUtil::sleep( 10 );
  BOOST_TEST_CHECKPOINT("maceExit");
  service1.maceExit();
}
BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>// Copyright (c) 2010 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/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/browser_action_test_util.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoNoScript) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(StartHTTPServer());

  // Loads a simple extension which attempts to change the title of every page
  // that loads to "modified".
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("incognito").AppendASCII("content_scripts")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* otr_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);
  TabContents* tab = otr_browser->GetSelectedTabContents();

  // Verify the script didn't run.
  bool result = false;
  ui_test_utils::ExecuteJavaScriptAndExtractBool(
      tab->render_view_host(), L"",
      L"window.domAutomationController.send(document.title == 'Unmodified')",
      &result);
  EXPECT_TRUE(result);
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoYesScript) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(StartHTTPServer());

  // Load a dummy extension. This just tests that we don't regress a
  // crash fix when multiple incognito- and non-incognito-enabled extensions
  // are mixed.
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("content_scripts").AppendASCII("all_frames")));

  // Loads a simple extension which attempts to change the title of every page
  // that loads to "modified".
  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("incognito").AppendASCII("content_scripts")));

  // Dummy extension #2.
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("content_scripts").AppendASCII("isolated_world1")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* otr_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);
  TabContents* tab = otr_browser->GetSelectedTabContents();

  // Verify the script ran.
  bool result = false;
  ui_test_utils::ExecuteJavaScriptAndExtractBool(
      tab->render_view_host(), L"",
      L"window.domAutomationController.send(document.title == 'modified')",
      &result);
  EXPECT_TRUE(result);
}

// Tests that the APIs in an incognito-enabled extension work properly.
// Flaky, http://crbug.com/42844.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_Incognito) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(StartHTTPServer());

  ResultCatcher catcher;

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("apis")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Tests that the APIs in an incognito-disabled extension don't see incognito
// events or callbacks.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoDisabled) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(StartHTTPServer());

  ResultCatcher catcher;

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtension(test_data_dir_
      .AppendASCII("incognito").AppendASCII("apis_disabled")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Test that opening a popup from an incognito browser window works properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoPopup) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(StartHTTPServer());

  ResultCatcher catcher;

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("popup")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* incognito_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);

  // Simulate the incognito's browser action being clicked.
  BrowserActionTestUtil(incognito_browser).Press(0);

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
<commit_msg>Mark ExtensionApiTest.Incognito as not FLAKY. According to the flakiness dashboard, it has been passing consistently.<commit_after>// Copyright (c) 2010 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/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/browser_action_test_util.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoNoScript) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(StartHTTPServer());

  // Loads a simple extension which attempts to change the title of every page
  // that loads to "modified".
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("incognito").AppendASCII("content_scripts")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* otr_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);
  TabContents* tab = otr_browser->GetSelectedTabContents();

  // Verify the script didn't run.
  bool result = false;
  ui_test_utils::ExecuteJavaScriptAndExtractBool(
      tab->render_view_host(), L"",
      L"window.domAutomationController.send(document.title == 'Unmodified')",
      &result);
  EXPECT_TRUE(result);
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoYesScript) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(StartHTTPServer());

  // Load a dummy extension. This just tests that we don't regress a
  // crash fix when multiple incognito- and non-incognito-enabled extensions
  // are mixed.
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("content_scripts").AppendASCII("all_frames")));

  // Loads a simple extension which attempts to change the title of every page
  // that loads to "modified".
  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("incognito").AppendASCII("content_scripts")));

  // Dummy extension #2.
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("content_scripts").AppendASCII("isolated_world1")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* otr_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);
  TabContents* tab = otr_browser->GetSelectedTabContents();

  // Verify the script ran.
  bool result = false;
  ui_test_utils::ExecuteJavaScriptAndExtractBool(
      tab->render_view_host(), L"",
      L"window.domAutomationController.send(document.title == 'modified')",
      &result);
  EXPECT_TRUE(result);
}

// Tests that the APIs in an incognito-enabled extension work properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Incognito) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(StartHTTPServer());

  ResultCatcher catcher;

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("apis")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Tests that the APIs in an incognito-disabled extension don't see incognito
// events or callbacks.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoDisabled) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(StartHTTPServer());

  ResultCatcher catcher;

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtension(test_data_dir_
      .AppendASCII("incognito").AppendASCII("apis_disabled")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Test that opening a popup from an incognito browser window works properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoPopup) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(StartHTTPServer());

  ResultCatcher catcher;

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("popup")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* incognito_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);

  // Simulate the incognito's browser action being clicked.
  BrowserActionTestUtil(incognito_browser).Press(0);

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
<|endoftext|>