<commit_before>/*
 * bacteria-core, core for cellular automaton
 * Copyright (C) 2016 Pavel Dolgov
 *
 * See the LICENSE file for terms of use.
 */

#include <boost/test/unit_test.hpp>

#include "Model.hpp"

typedef void (Implementation::Model::*OneArgMethod) (
    const Abstract::Point& coordinates
);

typedef void (Implementation::Model::*TwoArgsMethod) (
    const Abstract::Point& coordinates,
    int change
);

typedef void (Implementation::Model::*MultiArgsMethod) (
    const Abstract::Point& coordinates,
    int mass,
    int direction,
    int team,
    int instruction
);

template<typename Func>
void checkModelMethodForThrow(
    Implementation::Model* model,
    Func model_method,
    int arg1,
    int arg2
) {
    BOOST_REQUIRE_THROW(
        ((*model).*model_method)(arg1, arg2), Exception
    );
}

template<>
void checkModelMethodForThrow<OneArgMethod>(
    Implementation::Model* model,
    OneArgMethod model_method,
    int arg1,
    int arg2
) {
    Abstract::Point coordinates(arg1, arg2);
    BOOST_REQUIRE_THROW(
        ((*model).*model_method)(coordinates), Exception
    );
}

template<>
void checkModelMethodForThrow<TwoArgsMethod>(
    Implementation::Model* model,
    TwoArgsMethod model_method,
    int arg1,
    int arg2
) {
    Abstract::Point coordinates(arg1, arg2);
    BOOST_REQUIRE_THROW(
        ((*model).*model_method)(coordinates, 0), Exception
    );
}

template<typename Func>
static void checkErrorHandling(
    Implementation::Model* model,
    Func model_method
) {
    // range errors: test all combinations of
    // "wrong" (outside of correct range) arguments
    // Max_index: 0; min_index: 0
    for (int arg1 = -1; arg1 <= 1; arg1++) {
        for (int arg2 = -1; arg2 <= 1; arg2++) {
            if ((arg1 != 0) || (arg2 != 0)) {
                // (0, 0) is correct
                BOOST_REQUIRE_THROW(
                    ((*model).*model_method)(arg1, arg2), Exception
                );
            }
        }
    }
    // "dead" error
    // (attempt to do something with dead bacterium)
    model->kill(0, 0);
    BOOST_REQUIRE_THROW(
        ((*model).*model_method)(0, 0), Exception
    );
}

#define CREATE_NEW \
    model->createNewByCoordinates( \
        coordinates, \
        DEFAULT_MASS, \
        0, \
        0, \
        0 \
    );

static Abstract::Point createInBaseCoordinates(
    Implementation::Model* model
) {
    Abstract::Point coordinates(0, 0);
    CREATE_NEW
    return coordinates;
}

static void createByCoordinates(
    Implementation::Model* model,
    Abstract::Point coordinates
) {
    CREATE_NEW
}

#undef CREATE_NEW

static Implementation::Model* createBaseModel(
    int bacteria = 0,
    int teams = 1
) {
    Implementation::Model* model =
        Abstract::makeModel<Implementation::Model>(
            MIN_WIDTH,
            MIN_HEIGHT,
            bacteria,
            teams
        );
    return model;
}

BOOST_AUTO_TEST_CASE (bacteria_number_test) {
    Implementation::Model* model = createBaseModel();
    int bacteria_number = model->getBacteriaNumber(0);
    BOOST_REQUIRE(bacteria_number == 0);
    createInBaseCoordinates(model);
    bacteria_number = model->getBacteriaNumber(0);
    BOOST_REQUIRE(bacteria_number == 1);
    // range errors
    BOOST_REQUIRE_THROW(model->getBacteriaNumber(-1), Exception);
    BOOST_REQUIRE_THROW(model->getBacteriaNumber(1), Exception);
    delete model;
}

BOOST_AUTO_TEST_CASE (get_mass_test) {
    Implementation::Model* model = createBaseModel(1, 1);
    int mass = model->getMass(0, 0);
    BOOST_REQUIRE(mass == DEFAULT_MASS);
    checkErrorHandling(model, &Implementation::Model::getMass);
    delete model;
}

BOOST_AUTO_TEST_CASE (height_test) {
    Implementation::Model* model = createBaseModel();
    BOOST_REQUIRE(model->getHeight() == MIN_HEIGHT);
    delete model;
}

BOOST_AUTO_TEST_CASE (width_test) {
    Implementation::Model* model = createBaseModel();
    BOOST_REQUIRE(model->getWidth() == MIN_WIDTH);
    delete model;
}

BOOST_AUTO_TEST_CASE (kill_test) {
    Implementation::Model* model = createBaseModel();
    Abstract::Point coordinates = createInBaseCoordinates(model);
    model->kill(0, 0);
    Abstract::CellState state = model->cellState(coordinates);
    BOOST_REQUIRE(state == Abstract::EMPTY);
    // error handling checks
    createInBaseCoordinates(model);
    // FIXME test doesn't work correctly without this function call.
    // The solution is to use set instead of vector in model.
    model->clearBeforeMove(0);
    checkErrorHandling(model, &Implementation::Model::kill);
    delete model;
}

BOOST_AUTO_TEST_CASE (create_coordinates_test) {
    Implementation::Model* model = createBaseModel();
    Abstract::Point coordinates = createInBaseCoordinates(model);
    Abstract::CellState state = model->cellState(coordinates);
    BOOST_REQUIRE(state == Abstract::BACTERIUM);
    delete model;
}

BOOST_AUTO_TEST_CASE (kill_coordinates_test) {
    Implementation::Model* model = createBaseModel();
    Abstract::Point coordinates = createInBaseCoordinates(model);
    model->killByCoordinates(coordinates);
    Abstract::CellState state = model->cellState(coordinates);
    BOOST_REQUIRE(state == Abstract::EMPTY);
    delete model;
}
<commit_msg>Implement checkModelMethodForThrow MultiArgsMethod<commit_after>/*
 * bacteria-core, core for cellular automaton
 * Copyright (C) 2016 Pavel Dolgov
 *
 * See the LICENSE file for terms of use.
 */

#include <boost/test/unit_test.hpp>

#include "Model.hpp"

typedef void (Implementation::Model::*OneArgMethod) (
    const Abstract::Point& coordinates
);

typedef void (Implementation::Model::*TwoArgsMethod) (
    const Abstract::Point& coordinates,
    int change
);

typedef void (Implementation::Model::*MultiArgsMethod) (
    const Abstract::Point& coordinates,
    int mass,
    int direction,
    int team,
    int instruction
);

template<typename Func>
void checkModelMethodForThrow(
    Implementation::Model* model,
    Func model_method,
    int arg1,
    int arg2
) {
    BOOST_REQUIRE_THROW(
        ((*model).*model_method)(arg1, arg2), Exception
    );
}

template<>
void checkModelMethodForThrow<OneArgMethod>(
    Implementation::Model* model,
    OneArgMethod model_method,
    int arg1,
    int arg2
) {
    Abstract::Point coordinates(arg1, arg2);
    BOOST_REQUIRE_THROW(
        ((*model).*model_method)(coordinates), Exception
    );
}

template<>
void checkModelMethodForThrow<TwoArgsMethod>(
    Implementation::Model* model,
    TwoArgsMethod model_method,
    int arg1,
    int arg2
) {
    Abstract::Point coordinates(arg1, arg2);
    BOOST_REQUIRE_THROW(
        ((*model).*model_method)(coordinates, 0), Exception
    );
}

template<>
void checkModelMethodForThrow<MultiArgsMethod>(
    Implementation::Model* model,
    MultiArgsMethod model_method,
    int arg1,
    int arg2
) {
    Abstract::Point coordinates(arg1, arg2);
    BOOST_REQUIRE_THROW(
        ((*model).*model_method)(
            coordinates,
            DEFAULT_MASS,
            0,
            0,
            0
        ),
        Exception
    );
}

template<typename Func>
static void checkErrorHandling(
    Implementation::Model* model,
    Func model_method
) {
    // range errors: test all combinations of
    // "wrong" (outside of correct range) arguments
    // Max_index: 0; min_index: 0
    for (int arg1 = -1; arg1 <= 1; arg1++) {
        for (int arg2 = -1; arg2 <= 1; arg2++) {
            if ((arg1 != 0) || (arg2 != 0)) {
                // (0, 0) is correct
                BOOST_REQUIRE_THROW(
                    ((*model).*model_method)(arg1, arg2), Exception
                );
            }
        }
    }
    // "dead" error
    // (attempt to do something with dead bacterium)
    model->kill(0, 0);
    BOOST_REQUIRE_THROW(
        ((*model).*model_method)(0, 0), Exception
    );
}

#define CREATE_NEW \
    model->createNewByCoordinates( \
        coordinates, \
        DEFAULT_MASS, \
        0, \
        0, \
        0 \
    );

static Abstract::Point createInBaseCoordinates(
    Implementation::Model* model
) {
    Abstract::Point coordinates(0, 0);
    CREATE_NEW
    return coordinates;
}

static void createByCoordinates(
    Implementation::Model* model,
    Abstract::Point coordinates
) {
    CREATE_NEW
}

#undef CREATE_NEW

static Implementation::Model* createBaseModel(
    int bacteria = 0,
    int teams = 1
) {
    Implementation::Model* model =
        Abstract::makeModel<Implementation::Model>(
            MIN_WIDTH,
            MIN_HEIGHT,
            bacteria,
            teams
        );
    return model;
}

BOOST_AUTO_TEST_CASE (bacteria_number_test) {
    Implementation::Model* model = createBaseModel();
    int bacteria_number = model->getBacteriaNumber(0);
    BOOST_REQUIRE(bacteria_number == 0);
    createInBaseCoordinates(model);
    bacteria_number = model->getBacteriaNumber(0);
    BOOST_REQUIRE(bacteria_number == 1);
    // range errors
    BOOST_REQUIRE_THROW(model->getBacteriaNumber(-1), Exception);
    BOOST_REQUIRE_THROW(model->getBacteriaNumber(1), Exception);
    delete model;
}

BOOST_AUTO_TEST_CASE (get_mass_test) {
    Implementation::Model* model = createBaseModel(1, 1);
    int mass = model->getMass(0, 0);
    BOOST_REQUIRE(mass == DEFAULT_MASS);
    checkErrorHandling(model, &Implementation::Model::getMass);
    delete model;
}

BOOST_AUTO_TEST_CASE (height_test) {
    Implementation::Model* model = createBaseModel();
    BOOST_REQUIRE(model->getHeight() == MIN_HEIGHT);
    delete model;
}

BOOST_AUTO_TEST_CASE (width_test) {
    Implementation::Model* model = createBaseModel();
    BOOST_REQUIRE(model->getWidth() == MIN_WIDTH);
    delete model;
}

BOOST_AUTO_TEST_CASE (kill_test) {
    Implementation::Model* model = createBaseModel();
    Abstract::Point coordinates = createInBaseCoordinates(model);
    model->kill(0, 0);
    Abstract::CellState state = model->cellState(coordinates);
    BOOST_REQUIRE(state == Abstract::EMPTY);
    // error handling checks
    createInBaseCoordinates(model);
    // FIXME test doesn't work correctly without this function call.
    // The solution is to use set instead of vector in model.
    model->clearBeforeMove(0);
    checkErrorHandling(model, &Implementation::Model::kill);
    delete model;
}

BOOST_AUTO_TEST_CASE (create_coordinates_test) {
    Implementation::Model* model = createBaseModel();
    Abstract::Point coordinates = createInBaseCoordinates(model);
    Abstract::CellState state = model->cellState(coordinates);
    BOOST_REQUIRE(state == Abstract::BACTERIUM);
    delete model;
}

BOOST_AUTO_TEST_CASE (kill_coordinates_test) {
    Implementation::Model* model = createBaseModel();
    Abstract::Point coordinates = createInBaseCoordinates(model);
    model->killByCoordinates(coordinates);
    Abstract::CellState state = model->cellState(coordinates);
    BOOST_REQUIRE(state == Abstract::EMPTY);
    delete model;
}
<|endoftext|>


<commit_before><commit_msg>Add missing include, start at event 0<commit_after><|endoftext|>


<commit_before>#include "board.hpp"

#include <cstring>

#include "exception.hpp"

namespace Quoridor {

Wall::Wall(int orientation, int line, int start_pos, int cnt)
    : orientation_(orientation), line_(line), start_pos_(start_pos), cnt_(cnt)
{
}

Wall::~Wall()
{
}

Board::Board(int row_num, int col_num) : row_num_(), col_num_(),
        occ_fields_(), pawn_pos_(), sides_(), pawn_sides_(), walls_()
{
    set_size(row_num, col_num);
    sides_.push_back(std::pair<int, int>(0, 0));
    sides_.push_back(std::pair<int, int>(2, 0));
    sides_.push_back(std::pair<int, int>(1, 0));
    sides_.push_back(std::pair<int, int>(3, 0));
}

Board::~Board()
{
}

void Board::set_size(int row_num, int col_num)
{
    if (row_num <= 0) {
        throw Exception();
    }
    if (col_num <= 0) {
        throw Exception();
    }
    row_num_ = row_num;
    col_num_ = col_num;
}

int Board::next_side() const
{
    for (auto &side : sides_) {
        if (side.second == 0) {
            side.second = 1;
            return side.first;
        }
    }
    return -1;
}

int Board::add_pawn(std::shared_ptr<Pawn> pawn)
{
    pawn_sides_[pawn] = next_side();
    pos_t pos;

    switch (pawn_sides_[pawn]) {
    case 0:
        pos.row = 0;
        pos.col = 4;
        break;
    case 1:
        pos.row = 4;
        pos.col = 0;
        break;
    case 2:
        pos.row = 8;
        pos.col = 4;
        break;
    case 3:
        pos.row = 4;
        pos.col = 8;
        break;
    default:
        throw Exception();
    }

    occ_fields_[pos] = pawn;
    pawn_pos_[pawn] = pos;

    return 0;
}

void Board::add_occupied(const pos_t &pos, std::shared_ptr<Pawn> pawn)
{
    if (occ_fields_.count(pos) > 0) {
        throw Exception();
    }
    occ_fields_[pos] = pawn;
    pawn_pos_[pawn] = pos;
}

void Board::rm_occupied(const pos_t &pos)
{
    occ_fields_.erase(pos);
}

pos_t Board::pawn_pos(std::shared_ptr<Pawn> pawn) const
{
    return pawn_pos_.at(pawn);
}

int Board::make_move(BoardMoves move, std::shared_ptr<Pawn> pawn)
{
    if (move < kPutWall) {
        return make_walking_move(move, pawn);
    }
    else if (move == kPutWall) {
        return -1;
    }
    else {
        return -1;
    }
}

bool Board::is_at_opposite_side(std::shared_ptr<Pawn> pawn) const
{
    switch (pawn_sides_.at(pawn)) {
    case 0:
        return pawn_pos_.at(pawn).row == row_num() - 1;
    case 1:
        return pawn_pos_.at(pawn).col == col_num() - 1;
    case 2:
        return pawn_pos_.at(pawn).row == 0;
    case 3:
        return pawn_pos_.at(pawn).col == 0;
    default:
        throw Exception();
    }
}

BoardMoves Board::recalc_move(BoardMoves move, std::shared_ptr<Pawn> pawn)
{
    int m = (move + pawn_sides_[pawn]) % 4;
    if (m >= kEND) {
        return kEND;
    }
    return static_cast<BoardMoves>(m);
}

int Board::make_walking_move(BoardMoves move, std::shared_ptr<Pawn> pawn)
{
    move = recalc_move(move, pawn);
    pos_t pos = pawn_pos_[pawn];
    pos_t inc_pos;
    pos_t lim_pos = pos;

    switch (move) {
    case kForward:
        lim_pos.row = row_num() - 1;
        inc_pos.row = 1;
        break;
    case kRight:
        lim_pos.col = col_num() - 1;
        inc_pos.col = 1;
        break;
    case kBackward:
        lim_pos.row = 0;
        inc_pos.row = -1;
        break;
    case kLeft:
        lim_pos.col = 0;
        inc_pos.col = -1;
        break;
    case kPutWall:
    case kEND:
    default:
        return -1;
    }

    // error, pawn is already at the opposite side
    if (pos == lim_pos) {
        return -1;
    }

    if (is_possible_move(pos, inc_pos)) {
        pos_t possible_pos = pos + inc_pos;
        if (occ_fields_.count(possible_pos) == 0) {
            pos += inc_pos;
        }
        else {
            if (is_possible_move(possible_pos, inc_pos)) {
                pos += inc_pos;
                pos += inc_pos;
            }
            else {
                return -1;
            }
        }
    }
    else {
        return -1;
    }

    // pawn cannot make specified move
    if (is_outside_board(pos)) {
        return -1;
    }

    // update pawn's position
    occ_fields_.erase(pawn_pos_[pawn]);
    pawn_pos_[pawn] = pos;
    occ_fields_[pos] = pawn;

    return 0;
}

int Board::add_wall(const Wall &wall)
{
    int line_lim = wall.orientation() ? col_num() : row_num();
    int start_pos_lim = wall.orientation() ? row_num() : col_num();
    if ((wall.line() >= line_lim)
            || (wall.start_pos() + wall.cnt() >= start_pos_lim)) {
        return -1;
    }

    if (wall_intersects(wall)) {
        return -2;
    }

    walls_[wall.orientation()].insert(std::map<int, Wall>::value_type(wall.line(), Wall(wall)));

    return 0;
}

bool Board::wall_intersects(const Wall &wall) const
{
    // check intersections
    if (walls_.count(1 - wall.orientation()) > 0) {
        for (int i = 1; i < wall.cnt(); ++i) {
            if (walls_.at(1 - wall.orientation()).count(wall.start_pos() - i) != 0) {
                return true;
            }
        }
    }
    // check overlaps
    if (walls_.count(wall.orientation()) > 0) {
        for (int i = 1 - wall.cnt(); i < wall.cnt(); ++i) {
            if (walls_.at(wall.orientation()).count(wall.start_pos() + i) != 0) {
                return true;
            }
        }
    }
    return false;
}

bool Board::is_outside_board(const pos_t &pos) const
{
    if ((pos.row >= row_num()) || (pos.row < 0)
            || (pos.col >= col_num()) || (pos.col < 0))
        return true;
    return false;
}

bool Board::is_possible_move(const pos_t &pos, const pos_t &inc_pos) const
{
    int orientation;
    int st;

    if (inc_pos.row != 0) {
        orientation = 1;
        st = pos.col;
    }
    else if (inc_pos.col != 0) {
        orientation = 0;
        st = pos.row;
    }
    else {
        throw Exception();
    }

    if (walls_.count(orientation) == 0) {
        return true;
    }

    for (int i = 0; i <= st; ++i) {
        if (walls_.at(orientation).count(i)) {
            if (i + walls_.at(orientation).at(i).cnt() >= st) {
                return false;
            }
        }
    }

    return true;
}

}  /* namespace Quoridor */
<commit_msg>Fix returning code in Board::make_walking_move.<commit_after>#include "board.hpp"

#include <cstring>

#include "exception.hpp"

namespace Quoridor {

Wall::Wall(int orientation, int line, int start_pos, int cnt)
    : orientation_(orientation), line_(line), start_pos_(start_pos), cnt_(cnt)
{
}

Wall::~Wall()
{
}

Board::Board(int row_num, int col_num) : row_num_(), col_num_(),
        occ_fields_(), pawn_pos_(), sides_(), pawn_sides_(), walls_()
{
    set_size(row_num, col_num);
    sides_.push_back(std::pair<int, int>(0, 0));
    sides_.push_back(std::pair<int, int>(2, 0));
    sides_.push_back(std::pair<int, int>(1, 0));
    sides_.push_back(std::pair<int, int>(3, 0));
}

Board::~Board()
{
}

void Board::set_size(int row_num, int col_num)
{
    if (row_num <= 0) {
        throw Exception();
    }
    if (col_num <= 0) {
        throw Exception();
    }
    row_num_ = row_num;
    col_num_ = col_num;
}

int Board::next_side() const
{
    for (auto &side : sides_) {
        if (side.second == 0) {
            side.second = 1;
            return side.first;
        }
    }
    return -1;
}

int Board::add_pawn(std::shared_ptr<Pawn> pawn)
{
    pawn_sides_[pawn] = next_side();
    pos_t pos;

    switch (pawn_sides_[pawn]) {
    case 0:
        pos.row = 0;
        pos.col = 4;
        break;
    case 1:
        pos.row = 4;
        pos.col = 0;
        break;
    case 2:
        pos.row = 8;
        pos.col = 4;
        break;
    case 3:
        pos.row = 4;
        pos.col = 8;
        break;
    default:
        throw Exception();
    }

    occ_fields_[pos] = pawn;
    pawn_pos_[pawn] = pos;

    return 0;
}

void Board::add_occupied(const pos_t &pos, std::shared_ptr<Pawn> pawn)
{
    if (occ_fields_.count(pos) > 0) {
        throw Exception();
    }
    occ_fields_[pos] = pawn;
    pawn_pos_[pawn] = pos;
}

void Board::rm_occupied(const pos_t &pos)
{
    occ_fields_.erase(pos);
}

pos_t Board::pawn_pos(std::shared_ptr<Pawn> pawn) const
{
    return pawn_pos_.at(pawn);
}

int Board::make_move(BoardMoves move, std::shared_ptr<Pawn> pawn)
{
    if (move < kPutWall) {
        return make_walking_move(move, pawn);
    }
    else if (move == kPutWall) {
        return -1;
    }
    else {
        return -1;
    }
}

bool Board::is_at_opposite_side(std::shared_ptr<Pawn> pawn) const
{
    switch (pawn_sides_.at(pawn)) {
    case 0:
        return pawn_pos_.at(pawn).row == row_num() - 1;
    case 1:
        return pawn_pos_.at(pawn).col == col_num() - 1;
    case 2:
        return pawn_pos_.at(pawn).row == 0;
    case 3:
        return pawn_pos_.at(pawn).col == 0;
    default:
        throw Exception();
    }
}

BoardMoves Board::recalc_move(BoardMoves move, std::shared_ptr<Pawn> pawn)
{
    int m = (move + pawn_sides_[pawn]) % 4;
    if (m >= kEND) {
        return kEND;
    }
    return static_cast<BoardMoves>(m);
}

int Board::make_walking_move(BoardMoves move, std::shared_ptr<Pawn> pawn)
{
    move = recalc_move(move, pawn);
    pos_t pos = pawn_pos_[pawn];
    pos_t inc_pos;
    pos_t lim_pos = pos;

    switch (move) {
    case kForward:
        lim_pos.row = row_num() - 1;
        inc_pos.row = 1;
        break;
    case kRight:
        lim_pos.col = col_num() - 1;
        inc_pos.col = 1;
        break;
    case kBackward:
        lim_pos.row = 0;
        inc_pos.row = -1;
        break;
    case kLeft:
        lim_pos.col = 0;
        inc_pos.col = -1;
        break;
    case kPutWall:
    case kEND:
    default:
        return -1;
    }

    // error, pawn is already at the opposite side
    if (pos == lim_pos) {
        return -1;
    }

    if (is_possible_move(pos, inc_pos)) {
        pos_t possible_pos = pos + inc_pos;
        if (occ_fields_.count(possible_pos) == 0) {
            pos += inc_pos;
        }
        else {
            if (is_possible_move(possible_pos, inc_pos)) {
                pos += inc_pos;
                pos += inc_pos;
            }
            else {
                return -2;
            }
        }
    }
    else {
        return -1;
    }

    // pawn cannot make specified move
    if (is_outside_board(pos)) {
        return -1;
    }

    // update pawn's position
    occ_fields_.erase(pawn_pos_[pawn]);
    pawn_pos_[pawn] = pos;
    occ_fields_[pos] = pawn;

    return 0;
}

int Board::add_wall(const Wall &wall)
{
    int line_lim = wall.orientation() ? col_num() : row_num();
    int start_pos_lim = wall.orientation() ? row_num() : col_num();
    if ((wall.line() >= line_lim)
            || (wall.start_pos() + wall.cnt() >= start_pos_lim)) {
        return -1;
    }

    if (wall_intersects(wall)) {
        return -2;
    }

    walls_[wall.orientation()].insert(std::map<int, Wall>::value_type(wall.line(), Wall(wall)));

    return 0;
}

bool Board::wall_intersects(const Wall &wall) const
{
    // check intersections
    if (walls_.count(1 - wall.orientation()) > 0) {
        for (int i = 1; i < wall.cnt(); ++i) {
            if (walls_.at(1 - wall.orientation()).count(wall.start_pos() - i) != 0) {
                return true;
            }
        }
    }
    // check overlaps
    if (walls_.count(wall.orientation()) > 0) {
        for (int i = 1 - wall.cnt(); i < wall.cnt(); ++i) {
            if (walls_.at(wall.orientation()).count(wall.start_pos() + i) != 0) {
                return true;
            }
        }
    }
    return false;
}

bool Board::is_outside_board(const pos_t &pos) const
{
    if ((pos.row >= row_num()) || (pos.row < 0)
            || (pos.col >= col_num()) || (pos.col < 0))
        return true;
    return false;
}

bool Board::is_possible_move(const pos_t &pos, const pos_t &inc_pos) const
{
    int orientation;
    int st;

    if (inc_pos.row != 0) {
        orientation = 1;
        st = pos.col;
    }
    else if (inc_pos.col != 0) {
        orientation = 0;
        st = pos.row;
    }
    else {
        throw Exception();
    }

    if (walls_.count(orientation) == 0) {
        return true;
    }

    for (int i = 0; i <= st; ++i) {
        if (walls_.at(orientation).count(i)) {
            if (i + walls_.at(orientation).at(i).cnt() >= st) {
                return false;
            }
        }
    }

    return true;
}

}  /* namespace Quoridor */
<|endoftext|>


<commit_before>#include "editor.hh"

#include "exception.hh"
#include "utils.hh"
#include "register.hh"
#include "register_manager.hh"

#include "utf8_iterator.hh"

#include <array>

namespace Kakoune
{

Editor::Editor(Buffer& buffer)
    : m_buffer(&buffer),
      m_edition_level(0)
{
    m_selections.push_back(Selection(buffer.begin(), buffer.begin()));
}

void Editor::erase()
{
    scoped_edition edition(*this);
    for (auto& sel : m_selections)
    {
        m_buffer->erase(sel.begin(), sel.end());
        sel.selection.avoid_eol();
    }
}

static BufferIterator prepare_insert(Buffer& buffer, const Selection& sel,
                                     InsertMode mode)
{
    switch (mode)
    {
    case InsertMode::Insert:
    case InsertMode::Replace:
        return sel.begin();
    case InsertMode::Append:
        return sel.end();
    case InsertMode::InsertAtLineBegin:
        return buffer.iterator_at_line_begin(sel.begin());
    case InsertMode::AppendAtLineEnd:
        return buffer.iterator_at_line_end(sel.end()-1);
    case InsertMode::OpenLineBelow:
    {
        auto pos = buffer.iterator_at_line_end(sel.end() - 1);
        buffer.insert(pos, "\n");
        return buffer.iterator_at_line_begin(pos.line() + 1);
    }
    case InsertMode::OpenLineAbove:
    {
        auto pos = buffer.iterator_at_line_begin(sel.begin());
        buffer.insert(pos, "\n");
        return pos;
    }
    }
    assert(false);
    return BufferIterator{};
}

void Editor::insert(const String& string, InsertMode mode)
{
    scoped_edition edition(*this);
    if (mode == InsertMode::Replace)
        erase();

    for (auto& sel : m_selections)
    {
        BufferIterator pos = prepare_insert(*m_buffer, sel.selection, mode);
        m_buffer->insert(pos, string);
    }
}

void Editor::insert(const memoryview<String>& strings, InsertMode mode)
{
    scoped_edition edition(*this);
    if (mode == InsertMode::Replace)
        erase();

    if (strings.empty())
        return;

    for (size_t i = 0; i < selections().size(); ++i)
    {
        BufferIterator pos = prepare_insert(*m_buffer, m_selections[i].selection, mode);
        size_t index = std::min(i, strings.size()-1);
        m_buffer->insert(pos, strings[index]);
    }
}

std::vector<String> Editor::selections_content() const
{
    std::vector<String> contents;
    for (auto& sel : m_selections)
        contents.push_back(m_buffer->string(sel.begin(),
                                           sel.end()));
    return contents;
}

static bool overlaps(const SelectionAndCaptures& lhs,
                     const SelectionAndCaptures& rhs)
{
    return (lhs.first() <= rhs.first() and lhs.last() >= rhs.first()) or
           (lhs.first() <= rhs.last()  and lhs.last() >= rhs.last());
}

static void merge_overlapping(SelectionAndCapturesList& selections)
{
    for (size_t i = 0; i < selections.size(); ++i)
    {
        for (size_t j = i+1; j < selections.size();)
        {
            if (overlaps(selections[i], selections[j]))
            {
                selections[i].selection.merge_with(selections[j].selection);
                selections.erase(selections.begin() + j);
            }
            else
               ++j;
        }
    }
}

void Editor::move_selections(CharCount offset, SelectMode mode)
{
    assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
    for (auto& sel : m_selections)
    {
        auto last = sel.last();
        auto limit = offset < 0 ? buffer().iterator_at_line_begin(last)
                                : utf8::previous(buffer().iterator_at_line_end(last));
        last = utf8::advance(last, limit, offset);
        sel.selection = Selection(mode == SelectMode::Extend ? sel.first() : last, last);
        sel.selection.avoid_eol();
    }
    merge_overlapping(m_selections);
}

void Editor::move_selections(LineCount offset, SelectMode mode)
{
    assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
    for (auto& sel : m_selections)
    {
        BufferCoord pos = m_buffer->line_and_column_at(sel.last());
        pos.line += offset;
        BufferIterator last = utf8::finish(m_buffer->iterator_at(pos, true));
        sel.selection = Selection(mode == SelectMode::Extend ? sel.first() : last, last);
        sel.selection.avoid_eol();
    }
    merge_overlapping(m_selections);
}

void Editor::clear_selections()
{
    check_invariant();
    BufferIterator pos = m_selections.back().last();

    if (*pos == '\n' and not pos.is_begin() and *utf8::previous(pos) != '\n')
        pos = utf8::previous(pos);

    Selection sel = Selection(pos, pos);
    m_selections.clear();
    m_selections.push_back(std::move(sel));
}

void Editor::keep_selection(int index)
{
    check_invariant();

    if (index < m_selections.size())
    {
        SelectionAndCaptures sel = std::move(m_selections[index]);
        m_selections.clear();
        m_selections.push_back(std::move(sel));
    }
}

void Editor::remove_selection(int index)
{
    check_invariant();

    if (m_selections.size() > 1 and index < m_selections.size())
        m_selections.erase(m_selections.begin() + index);
}

void Editor::select(const BufferIterator& iterator)
{
    m_selections.clear();
    m_selections.push_back(Selection(iterator, iterator));
}

void Editor::select(SelectionAndCapturesList selections)
{
    if (selections.empty())
        throw runtime_error("no selections");
    m_selections = std::move(selections);
}

void Editor::select(const Selector& selector, SelectMode mode)
{
    check_invariant();

    if (mode == SelectMode::Append)
    {
        auto& sel = m_selections.back();
        SelectionAndCaptures res = selector(sel.selection);
        if (res.captures.empty())
            res.captures = sel.captures;
        m_selections.push_back(res);
    }
    else
    {
        for (auto& sel : m_selections)
        {
            SelectionAndCaptures res = selector(sel.selection);
            if (mode == SelectMode::Extend)
                sel.selection.merge_with(res.selection);
            else
                sel.selection = std::move(res.selection);

            if (not res.captures.empty())
                sel.captures = std::move(res.captures);
        }
    }
    merge_overlapping(m_selections);
}

struct nothing_selected : public runtime_error
{
    nothing_selected() : runtime_error("nothing was selected") {}
};

void Editor::multi_select(const MultiSelector& selector)
{
    check_invariant();

    SelectionAndCapturesList new_selections;
    for (auto& sel : m_selections)
    {
        SelectionAndCapturesList res = selector(sel.selection);
        for (auto& sel_and_cap : res)
        {
            // preserve captures when selectors captures nothing.
            if (sel_and_cap.captures.empty())
                new_selections.emplace_back(sel_and_cap.selection, sel.captures);
            else
                new_selections.push_back(std::move(sel_and_cap));
        }
    }
    if (new_selections.empty())
        throw nothing_selected();

    merge_overlapping(new_selections);
    m_selections = std::move(new_selections);
}

class LastModifiedRangeListener : public BufferChangeListener
{
public:
    LastModifiedRangeListener(Buffer& buffer)
       : m_buffer(buffer)
    { m_buffer.add_change_listener(*this); }

    ~LastModifiedRangeListener()
    { m_buffer.remove_change_listener(*this); }

    void on_insert(const BufferIterator& begin, const BufferIterator& end)
    {
        m_first = begin;
        m_last = utf8::previous(end);
    }

    void on_erase(const BufferIterator& begin, const BufferIterator& end)
    {
        m_first = begin;
        if (m_first >= m_buffer.end())
            m_first = utf8::previous(m_buffer.end());
        m_last = m_first;
    }

    const BufferIterator& first() const { return m_first; }
    const BufferIterator& last() const { return m_last; }

private:
    BufferIterator m_first;
    BufferIterator m_last;
    Buffer& m_buffer;
};

bool Editor::undo()
{
    LastModifiedRangeListener listener(buffer());
    bool res = m_buffer->undo();
    if (res)
    {
        m_selections.clear();
        m_selections.push_back(Selection(listener.first(),
                                         listener.last()));
    }
    return res;
}

bool Editor::redo()
{
    LastModifiedRangeListener listener(buffer());
    bool res = m_buffer->redo();
    if (res)
    {
        m_selections.clear();
        m_selections.push_back(Selection(listener.first(),
                                         listener.last()));
    }
    return res;
}

void Editor::check_invariant() const
{
    assert(not m_selections.empty());
}

void Editor::begin_edition()
{
    ++m_edition_level;

    if (m_edition_level == 1)
        m_buffer->begin_undo_group();
}

void Editor::end_edition()
{
    assert(m_edition_level > 0);
    if (m_edition_level == 1)
        m_buffer->end_undo_group();

    --m_edition_level;
}

using utf8_it = utf8::utf8_iterator<BufferIterator, utf8::InvalidBytePolicy::Pass>;

IncrementalInserter::IncrementalInserter(Editor& editor, InsertMode mode)
    : m_editor(editor), m_edition(editor), m_mode(mode)
{
    m_editor.on_incremental_insertion_begin();
    Buffer& buffer = *editor.m_buffer;

    if (mode == InsertMode::Replace)
    {
        for (auto& sel : editor.m_selections)
            buffer.erase(sel.begin(), sel.end());
    }

    for (auto& sel : m_editor.m_selections)
    {
        utf8_it first, last;
        switch (mode)
        {
        case InsertMode::Insert:  first = utf8_it(sel.end()) - 1; last = sel.begin(); break;
        case InsertMode::Replace: first = utf8_it(sel.end()) - 1; last = sel.begin(); break;
        case InsertMode::Append:  first = sel.begin(); last = sel.end(); break;

        case InsertMode::OpenLineBelow:
        case InsertMode::AppendAtLineEnd:
            first = utf8_it(buffer.iterator_at_line_end(utf8::previous(sel.end()))) - 1;
            last  = first;
            break;

        case InsertMode::OpenLineAbove:
        case InsertMode::InsertAtLineBegin:
            first = buffer.iterator_at_line_begin(sel.begin());
            if (mode == InsertMode::OpenLineAbove)
                --first;
            else
            {
                auto first_non_blank = first;
                while (*first_non_blank == ' ' or *first_non_blank == '\t')
                    ++first_non_blank;
                if (*first_non_blank != '\n')
                    first = first_non_blank;
            }
            last = first;
            break;
        }
        if (first.underlying_iterator().is_end())
           --first;
        if (last.underlying_iterator().is_end())
           --last;
        sel.selection = Selection(first.underlying_iterator(), last.underlying_iterator());
    }
    if (mode == InsertMode::OpenLineBelow or mode == InsertMode::OpenLineAbove)
    {
        insert("\n");
        if (mode == InsertMode::OpenLineAbove)
        {
            for (auto& sel : m_editor.m_selections)
            {
                // special case, the --first line above did nothing, so we need to compensate now
                if (sel.first() == utf8::next(buffer.begin()))
                    sel.selection = Selection(buffer.begin(), buffer.begin());
            }
        }
    }
}

IncrementalInserter::~IncrementalInserter()
{
    for (auto& sel : m_editor.m_selections)
    {
        if (m_mode == InsertMode::Append)
            sel = Selection(sel.first(), utf8::previous(sel.last()));
         sel.selection.avoid_eol();
    }

    m_editor.on_incremental_insertion_end();
}

void IncrementalInserter::insert(const String& string)
{
    Buffer& buffer = m_editor.buffer();
    for (auto& sel : m_editor.m_selections)
    {
        BufferIterator position = sel.last();
        String content = string;
        m_editor.filters()(buffer, position, content);
        m_editor.buffer().insert(position, content);
    }
}

void IncrementalInserter::insert(const memoryview<String>& strings)
{
    m_editor.insert(strings);
}

void IncrementalInserter::erase()
{
    for (auto& sel : m_editor.m_selections)
    {
        BufferIterator pos = sel.last();
        m_editor.buffer().erase(utf8::previous(pos), pos);
    }
}

void IncrementalInserter::move_cursors(const BufferCoord& offset)
{
    for (auto& sel : m_editor.m_selections)
    {
        BufferCoord pos = m_editor.m_buffer->line_and_column_at(sel.last());
        BufferIterator it = m_editor.m_buffer->iterator_at(pos + offset);
        sel = Selection(it, it);
    }
}

}
<commit_msg>Fix IncrementalInserter::insert(memoryview<String>) so that inserting registers works as intended<commit_after>#include "editor.hh"

#include "exception.hh"
#include "utils.hh"
#include "register.hh"
#include "register_manager.hh"

#include "utf8_iterator.hh"

#include <array>

namespace Kakoune
{

Editor::Editor(Buffer& buffer)
    : m_buffer(&buffer),
      m_edition_level(0)
{
    m_selections.push_back(Selection(buffer.begin(), buffer.begin()));
}

void Editor::erase()
{
    scoped_edition edition(*this);
    for (auto& sel : m_selections)
    {
        m_buffer->erase(sel.begin(), sel.end());
        sel.selection.avoid_eol();
    }
}

static BufferIterator prepare_insert(Buffer& buffer, const Selection& sel,
                                     InsertMode mode)
{
    switch (mode)
    {
    case InsertMode::Insert:
    case InsertMode::Replace:
        return sel.begin();
    case InsertMode::Append:
        return sel.end();
    case InsertMode::InsertAtLineBegin:
        return buffer.iterator_at_line_begin(sel.begin());
    case InsertMode::AppendAtLineEnd:
        return buffer.iterator_at_line_end(sel.end()-1);
    case InsertMode::OpenLineBelow:
    {
        auto pos = buffer.iterator_at_line_end(sel.end() - 1);
        buffer.insert(pos, "\n");
        return buffer.iterator_at_line_begin(pos.line() + 1);
    }
    case InsertMode::OpenLineAbove:
    {
        auto pos = buffer.iterator_at_line_begin(sel.begin());
        buffer.insert(pos, "\n");
        return pos;
    }
    }
    assert(false);
    return BufferIterator{};
}

void Editor::insert(const String& string, InsertMode mode)
{
    scoped_edition edition(*this);
    if (mode == InsertMode::Replace)
        erase();

    for (auto& sel : m_selections)
    {
        BufferIterator pos = prepare_insert(*m_buffer, sel.selection, mode);
        m_buffer->insert(pos, string);
    }
}

void Editor::insert(const memoryview<String>& strings, InsertMode mode)
{
    scoped_edition edition(*this);
    if (mode == InsertMode::Replace)
        erase();

    if (strings.empty())
        return;

    for (size_t i = 0; i < selections().size(); ++i)
    {
        BufferIterator pos = prepare_insert(*m_buffer, m_selections[i].selection, mode);
        size_t index = std::min(i, strings.size()-1);
        m_buffer->insert(pos, strings[index]);
    }
}

std::vector<String> Editor::selections_content() const
{
    std::vector<String> contents;
    for (auto& sel : m_selections)
        contents.push_back(m_buffer->string(sel.begin(),
                                           sel.end()));
    return contents;
}

static bool overlaps(const SelectionAndCaptures& lhs,
                     const SelectionAndCaptures& rhs)
{
    return (lhs.first() <= rhs.first() and lhs.last() >= rhs.first()) or
           (lhs.first() <= rhs.last()  and lhs.last() >= rhs.last());
}

static void merge_overlapping(SelectionAndCapturesList& selections)
{
    for (size_t i = 0; i < selections.size(); ++i)
    {
        for (size_t j = i+1; j < selections.size();)
        {
            if (overlaps(selections[i], selections[j]))
            {
                selections[i].selection.merge_with(selections[j].selection);
                selections.erase(selections.begin() + j);
            }
            else
               ++j;
        }
    }
}

void Editor::move_selections(CharCount offset, SelectMode mode)
{
    assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
    for (auto& sel : m_selections)
    {
        auto last = sel.last();
        auto limit = offset < 0 ? buffer().iterator_at_line_begin(last)
                                : utf8::previous(buffer().iterator_at_line_end(last));
        last = utf8::advance(last, limit, offset);
        sel.selection = Selection(mode == SelectMode::Extend ? sel.first() : last, last);
        sel.selection.avoid_eol();
    }
    merge_overlapping(m_selections);
}

void Editor::move_selections(LineCount offset, SelectMode mode)
{
    assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
    for (auto& sel : m_selections)
    {
        BufferCoord pos = m_buffer->line_and_column_at(sel.last());
        pos.line += offset;
        BufferIterator last = utf8::finish(m_buffer->iterator_at(pos, true));
        sel.selection = Selection(mode == SelectMode::Extend ? sel.first() : last, last);
        sel.selection.avoid_eol();
    }
    merge_overlapping(m_selections);
}

void Editor::clear_selections()
{
    check_invariant();
    BufferIterator pos = m_selections.back().last();

    if (*pos == '\n' and not pos.is_begin() and *utf8::previous(pos) != '\n')
        pos = utf8::previous(pos);

    Selection sel = Selection(pos, pos);
    m_selections.clear();
    m_selections.push_back(std::move(sel));
}

void Editor::keep_selection(int index)
{
    check_invariant();

    if (index < m_selections.size())
    {
        SelectionAndCaptures sel = std::move(m_selections[index]);
        m_selections.clear();
        m_selections.push_back(std::move(sel));
    }
}

void Editor::remove_selection(int index)
{
    check_invariant();

    if (m_selections.size() > 1 and index < m_selections.size())
        m_selections.erase(m_selections.begin() + index);
}

void Editor::select(const BufferIterator& iterator)
{
    m_selections.clear();
    m_selections.push_back(Selection(iterator, iterator));
}

void Editor::select(SelectionAndCapturesList selections)
{
    if (selections.empty())
        throw runtime_error("no selections");
    m_selections = std::move(selections);
}

void Editor::select(const Selector& selector, SelectMode mode)
{
    check_invariant();

    if (mode == SelectMode::Append)
    {
        auto& sel = m_selections.back();
        SelectionAndCaptures res = selector(sel.selection);
        if (res.captures.empty())
            res.captures = sel.captures;
        m_selections.push_back(res);
    }
    else
    {
        for (auto& sel : m_selections)
        {
            SelectionAndCaptures res = selector(sel.selection);
            if (mode == SelectMode::Extend)
                sel.selection.merge_with(res.selection);
            else
                sel.selection = std::move(res.selection);

            if (not res.captures.empty())
                sel.captures = std::move(res.captures);
        }
    }
    merge_overlapping(m_selections);
}

struct nothing_selected : public runtime_error
{
    nothing_selected() : runtime_error("nothing was selected") {}
};

void Editor::multi_select(const MultiSelector& selector)
{
    check_invariant();

    SelectionAndCapturesList new_selections;
    for (auto& sel : m_selections)
    {
        SelectionAndCapturesList res = selector(sel.selection);
        for (auto& sel_and_cap : res)
        {
            // preserve captures when selectors captures nothing.
            if (sel_and_cap.captures.empty())
                new_selections.emplace_back(sel_and_cap.selection, sel.captures);
            else
                new_selections.push_back(std::move(sel_and_cap));
        }
    }
    if (new_selections.empty())
        throw nothing_selected();

    merge_overlapping(new_selections);
    m_selections = std::move(new_selections);
}

class LastModifiedRangeListener : public BufferChangeListener
{
public:
    LastModifiedRangeListener(Buffer& buffer)
       : m_buffer(buffer)
    { m_buffer.add_change_listener(*this); }

    ~LastModifiedRangeListener()
    { m_buffer.remove_change_listener(*this); }

    void on_insert(const BufferIterator& begin, const BufferIterator& end)
    {
        m_first = begin;
        m_last = utf8::previous(end);
    }

    void on_erase(const BufferIterator& begin, const BufferIterator& end)
    {
        m_first = begin;
        if (m_first >= m_buffer.end())
            m_first = utf8::previous(m_buffer.end());
        m_last = m_first;
    }

    const BufferIterator& first() const { return m_first; }
    const BufferIterator& last() const { return m_last; }

private:
    BufferIterator m_first;
    BufferIterator m_last;
    Buffer& m_buffer;
};

bool Editor::undo()
{
    LastModifiedRangeListener listener(buffer());
    bool res = m_buffer->undo();
    if (res)
    {
        m_selections.clear();
        m_selections.push_back(Selection(listener.first(),
                                         listener.last()));
    }
    return res;
}

bool Editor::redo()
{
    LastModifiedRangeListener listener(buffer());
    bool res = m_buffer->redo();
    if (res)
    {
        m_selections.clear();
        m_selections.push_back(Selection(listener.first(),
                                         listener.last()));
    }
    return res;
}

void Editor::check_invariant() const
{
    assert(not m_selections.empty());
}

void Editor::begin_edition()
{
    ++m_edition_level;

    if (m_edition_level == 1)
        m_buffer->begin_undo_group();
}

void Editor::end_edition()
{
    assert(m_edition_level > 0);
    if (m_edition_level == 1)
        m_buffer->end_undo_group();

    --m_edition_level;
}

using utf8_it = utf8::utf8_iterator<BufferIterator, utf8::InvalidBytePolicy::Pass>;

IncrementalInserter::IncrementalInserter(Editor& editor, InsertMode mode)
    : m_editor(editor), m_edition(editor), m_mode(mode)
{
    m_editor.on_incremental_insertion_begin();
    Buffer& buffer = *editor.m_buffer;

    if (mode == InsertMode::Replace)
    {
        for (auto& sel : editor.m_selections)
            buffer.erase(sel.begin(), sel.end());
    }

    for (auto& sel : m_editor.m_selections)
    {
        utf8_it first, last;
        switch (mode)
        {
        case InsertMode::Insert:  first = utf8_it(sel.end()) - 1; last = sel.begin(); break;
        case InsertMode::Replace: first = utf8_it(sel.end()) - 1; last = sel.begin(); break;
        case InsertMode::Append:  first = sel.begin(); last = sel.end(); break;

        case InsertMode::OpenLineBelow:
        case InsertMode::AppendAtLineEnd:
            first = utf8_it(buffer.iterator_at_line_end(utf8::previous(sel.end()))) - 1;
            last  = first;
            break;

        case InsertMode::OpenLineAbove:
        case InsertMode::InsertAtLineBegin:
            first = buffer.iterator_at_line_begin(sel.begin());
            if (mode == InsertMode::OpenLineAbove)
                --first;
            else
            {
                auto first_non_blank = first;
                while (*first_non_blank == ' ' or *first_non_blank == '\t')
                    ++first_non_blank;
                if (*first_non_blank != '\n')
                    first = first_non_blank;
            }
            last = first;
            break;
        }
        if (first.underlying_iterator().is_end())
           --first;
        if (last.underlying_iterator().is_end())
           --last;
        sel.selection = Selection(first.underlying_iterator(), last.underlying_iterator());
    }
    if (mode == InsertMode::OpenLineBelow or mode == InsertMode::OpenLineAbove)
    {
        insert("\n");
        if (mode == InsertMode::OpenLineAbove)
        {
            for (auto& sel : m_editor.m_selections)
            {
                // special case, the --first line above did nothing, so we need to compensate now
                if (sel.first() == utf8::next(buffer.begin()))
                    sel.selection = Selection(buffer.begin(), buffer.begin());
            }
        }
    }
}

IncrementalInserter::~IncrementalInserter()
{
    for (auto& sel : m_editor.m_selections)
    {
        if (m_mode == InsertMode::Append)
            sel = Selection(sel.first(), utf8::previous(sel.last()));
         sel.selection.avoid_eol();
    }

    m_editor.on_incremental_insertion_end();
}

void IncrementalInserter::insert(const String& string)
{
    Buffer& buffer = m_editor.buffer();
    for (auto& sel : m_editor.m_selections)
    {
        BufferIterator position = sel.last();
        String content = string;
        m_editor.filters()(buffer, position, content);
        buffer.insert(position, content);
    }
}

void IncrementalInserter::insert(const memoryview<String>& strings)
{
    for (size_t i = 0; i < m_editor.m_selections.size(); ++i)
    {
        size_t index = std::min(i, strings.size()-1);
        m_editor.buffer().insert(m_editor.m_selections[i].last(),
                                 strings[index]);
    }
}

void IncrementalInserter::erase()
{
    for (auto& sel : m_editor.m_selections)
    {
        BufferIterator pos = sel.last();
        m_editor.buffer().erase(utf8::previous(pos), pos);
    }
}

void IncrementalInserter::move_cursors(const BufferCoord& offset)
{
    for (auto& sel : m_editor.m_selections)
    {
        BufferCoord pos = m_editor.m_buffer->line_and_column_at(sel.last());
        BufferIterator it = m_editor.m_buffer->iterator_at(pos + offset);
        sel = Selection(it, it);
    }
}

}
<|endoftext|>


<commit_before>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2010  Belledonne Communications SARL.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef configmanager_hh
#define configmanager_hh

#include <string>
#include <list>
#include <cstdlib>

#include "common.hh"

enum ConfigValueType{
	Boolean,
	Integer,
	String,
	StringList,
	Struct
};

struct ConfigItemDescriptor {
	ConfigValueType type;
	const char *name;
	const char *help;
	const char *default_value;
};

static const ConfigItemDescriptor config_item_end={Boolean,NULL,NULL,NULL};

class ConfigEntry{
	public:
		const std::string & getName()const{
			return mName;
		}
		ConfigValueType getType()const{
			return mType;
		}
		const std::string &getHelp()const{
			return mHelp;
		}
		ConfigEntry *getParent()const{
			return mParent;
		}
		virtual ~ConfigEntry(){
		}
		void setParent(ConfigEntry *parent);
	protected:
		ConfigEntry(const std::string &name, ConfigValueType type, const std::string &help);
	private:
		const std::string mName;
		const std::string mHelp;
		ConfigValueType mType;
		ConfigEntry *mParent;
};

class ConfigValue;

class ConfigStruct : public ConfigEntry{
	public:
		ConfigStruct(const std::string &name, const std::string &help);
		ConfigEntry * addChild(ConfigEntry *c);
		void addChildrenValues(ConfigItemDescriptor *items);
		std::list<ConfigEntry*> &getChildren();
		template <typename _retType>
		_retType *get(const char *name)const;
		~ConfigStruct();
		ConfigEntry *find(const char *name)const;
		ConfigEntry *findApproximate(const char *name)const;
	private:
		std::list<ConfigEntry*> mEntries;
};

class ConfigValue : public ConfigEntry{
	public:
		ConfigValue(const std::string &name, ConfigValueType  vt, const std::string &help, const std::string &default_value);
		void set(const std::string &value);
		const std::string &get()const;
		const std::string &getDefault()const;
		void setDefault(const std::string &value);
	private:
		std::string mValue;
		std::string mDefaultValue;
};

class ConfigBoolean : public ConfigValue{
	public:
		ConfigBoolean(const std::string &name, const std::string &help, const std::string &default_value);
		bool read()const;
};

class ConfigInt : public ConfigValue{
	public:
		ConfigInt(const std::string &name, const std::string &help, const std::string &default_value);
		int read()const;
};

class ConfigString : public ConfigValue{
	public:
		ConfigString(const std::string &name, const std::string &help, const std::string &default_value);
		const std::string & read()const;
};

class ConfigStringList : public ConfigValue{
	public:
		ConfigStringList(const std::string &name, const std::string &help, const std::string &default_value);
		std::list<std::string> read()const;
	private:
};

template <typename _retType>
_retType *ConfigStruct::get(const char *name)const{
	ConfigEntry *e=find(name);
	if (e==NULL) {
		LOGA("No ConfigEntry with name %s in struct %s",name,getName().c_str());
		return NULL;
	}
	_retType *ret=dynamic_cast<_retType *>(e);
	if (ret==NULL){
		LOGA("Config entry %s in struct %s does not have the expected type",name,e->getParent()->getName().c_str());
		return NULL;
	}
	return ret;
};

class FileConfigReader{
	public:
		FileConfigReader(ConfigStruct *root) : mRoot(root), mHaveUnreads(false){
		}
		int read(const char *filename);
		int reload();
		void checkUnread();
		~FileConfigReader();
	private:
		int read2(ConfigEntry *entry, int level);
		static void onUnreadItem(void *p, const char *secname, const char *key, int lineno);
		void onUnreadItem(const char *secname, const char *key, int lineno);
		ConfigStruct *mRoot;
		struct _LpConfig *mCfg;
		bool mHaveUnreads;
};

class ConfigManager{
	friend class ConfigArea;
	public:
		static ConfigManager *get();
		void declareArea(const char *area_name, const char *help, ConfigItemDescriptor *items);
		int load(const char* configFile);
		ConfigStruct *getRoot();
		const ConfigStruct *getGlobal();
		void loadStrict();
	private:
		ConfigManager();
		static void atexit(); // Don't call directly!
		ConfigStruct mConfigRoot;
		FileConfigReader mReader;
		static ConfigManager *sInstance;
};

class FileConfigDumper{
	public:
		FileConfigDumper(ConfigStruct *root){
			mRoot=root;
		}
		std::ostream &dump(std::ostream & ostr)const;
	private:
		std::ostream & printHelp(std::ostream &os, const std::string &help, const std::string &comment_prefix)const;
		std::ostream &dump2(std::ostream & ostr, ConfigEntry *entry, int level)const;
		ConfigStruct *mRoot;
};

inline std::ostream & operator<<(std::ostream &ostr, const FileConfigDumper &dumper){
	return dumper.dump(ostr);
}

#endif
<commit_msg>Initialize mCfg<commit_after>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2010  Belledonne Communications SARL.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef configmanager_hh
#define configmanager_hh

#include <string>
#include <list>
#include <cstdlib>

#include "common.hh"

enum ConfigValueType{
	Boolean,
	Integer,
	String,
	StringList,
	Struct
};

struct ConfigItemDescriptor {
	ConfigValueType type;
	const char *name;
	const char *help;
	const char *default_value;
};

static const ConfigItemDescriptor config_item_end={Boolean,NULL,NULL,NULL};

class ConfigEntry{
	public:
		const std::string & getName()const{
			return mName;
		}
		ConfigValueType getType()const{
			return mType;
		}
		const std::string &getHelp()const{
			return mHelp;
		}
		ConfigEntry *getParent()const{
			return mParent;
		}
		virtual ~ConfigEntry(){
		}
		void setParent(ConfigEntry *parent);
	protected:
		ConfigEntry(const std::string &name, ConfigValueType type, const std::string &help);
	private:
		const std::string mName;
		const std::string mHelp;
		ConfigValueType mType;
		ConfigEntry *mParent;
};

class ConfigValue;

class ConfigStruct : public ConfigEntry{
	public:
		ConfigStruct(const std::string &name, const std::string &help);
		ConfigEntry * addChild(ConfigEntry *c);
		void addChildrenValues(ConfigItemDescriptor *items);
		std::list<ConfigEntry*> &getChildren();
		template <typename _retType>
		_retType *get(const char *name)const;
		~ConfigStruct();
		ConfigEntry *find(const char *name)const;
		ConfigEntry *findApproximate(const char *name)const;
	private:
		std::list<ConfigEntry*> mEntries;
};

class ConfigValue : public ConfigEntry{
	public:
		ConfigValue(const std::string &name, ConfigValueType  vt, const std::string &help, const std::string &default_value);
		void set(const std::string &value);
		const std::string &get()const;
		const std::string &getDefault()const;
		void setDefault(const std::string &value);
	private:
		std::string mValue;
		std::string mDefaultValue;
};

class ConfigBoolean : public ConfigValue{
	public:
		ConfigBoolean(const std::string &name, const std::string &help, const std::string &default_value);
		bool read()const;
};

class ConfigInt : public ConfigValue{
	public:
		ConfigInt(const std::string &name, const std::string &help, const std::string &default_value);
		int read()const;
};

class ConfigString : public ConfigValue{
	public:
		ConfigString(const std::string &name, const std::string &help, const std::string &default_value);
		const std::string & read()const;
};

class ConfigStringList : public ConfigValue{
	public:
		ConfigStringList(const std::string &name, const std::string &help, const std::string &default_value);
		std::list<std::string> read()const;
	private:
};

template <typename _retType>
_retType *ConfigStruct::get(const char *name)const{
	ConfigEntry *e=find(name);
	if (e==NULL) {
		LOGA("No ConfigEntry with name %s in struct %s",name,getName().c_str());
		return NULL;
	}
	_retType *ret=dynamic_cast<_retType *>(e);
	if (ret==NULL){
		LOGA("Config entry %s in struct %s does not have the expected type",name,e->getParent()->getName().c_str());
		return NULL;
	}
	return ret;
};

class FileConfigReader{
	public:
		FileConfigReader(ConfigStruct *root) : mRoot(root), mHaveUnreads(false), mCfg(NULL){
		}
		int read(const char *filename);
		int reload();
		void checkUnread();
		~FileConfigReader();
	private:
		int read2(ConfigEntry *entry, int level);
		static void onUnreadItem(void *p, const char *secname, const char *key, int lineno);
		void onUnreadItem(const char *secname, const char *key, int lineno);
		ConfigStruct *mRoot;
		struct _LpConfig *mCfg;
		bool mHaveUnreads;
};

class ConfigManager{
	friend class ConfigArea;
	public:
		static ConfigManager *get();
		void declareArea(const char *area_name, const char *help, ConfigItemDescriptor *items);
		int load(const char* configFile);
		ConfigStruct *getRoot();
		const ConfigStruct *getGlobal();
		void loadStrict();
	private:
		ConfigManager();
		static void atexit(); // Don't call directly!
		ConfigStruct mConfigRoot;
		FileConfigReader mReader;
		static ConfigManager *sInstance;
};

class FileConfigDumper{
	public:
		FileConfigDumper(ConfigStruct *root){
			mRoot=root;
		}
		std::ostream &dump(std::ostream & ostr)const;
	private:
		std::ostream & printHelp(std::ostream &os, const std::string &help, const std::string &comment_prefix)const;
		std::ostream &dump2(std::ostream & ostr, ConfigEntry *entry, int level)const;
		ConfigStruct *mRoot;
};

inline std::ostream & operator<<(std::ostream &ostr, const FileConfigDumper &dumper){
	return dumper.dump(ostr);
}

#endif
<|endoftext|>


<commit_before>// Copyright 2013 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/common/extensions/manifest_handlers/settings_overrides_handler.h"

#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/permissions/settings_override_permission.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/feature_switch.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/permissions/api_permission_set.h"
#include "extensions/common/permissions/manifest_permission.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/permissions/permissions_info.h"
#include "grit/generated_resources.h"
#include "ipc/ipc_message.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"

using extensions::api::manifest_types::ChromeSettingsOverrides;

namespace extensions {
namespace {

const char* kWwwPrefix = "www.";

scoped_ptr<GURL> CreateManifestURL(const std::string& url) {
  scoped_ptr<GURL> manifest_url(new GURL(url));
  if (!manifest_url->is_valid() ||
      !manifest_url->SchemeIsHTTPOrHTTPS())
    return scoped_ptr<GURL>();
  return manifest_url.Pass();
}

scoped_ptr<GURL> ParseHomepage(const ChromeSettingsOverrides& overrides,
                               base::string16* error) {
  if (!overrides.homepage)
    return scoped_ptr<GURL>();
  scoped_ptr<GURL> manifest_url = CreateManifestURL(*overrides.homepage);
  if (!manifest_url) {
    *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
        manifest_errors::kInvalidHomepageOverrideURL, *overrides.homepage);
  }
  return manifest_url.Pass();
}

std::vector<GURL> ParseStartupPage(const ChromeSettingsOverrides& overrides,
                                   base::string16* error) {
  std::vector<GURL> urls;
  if (!overrides.startup_pages)
    return urls;

  for (std::vector<std::string>::const_iterator i =
       overrides.startup_pages->begin(); i != overrides.startup_pages->end();
       ++i) {
    scoped_ptr<GURL> manifest_url = CreateManifestURL(*i);
    if (!manifest_url) {
      *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
          manifest_errors::kInvalidStartupOverrideURL, *i);
    } else {
      urls.push_back(GURL());
      urls.back().Swap(manifest_url.get());
    }
  }
  return urls;
}

scoped_ptr<ChromeSettingsOverrides::Search_provider> ParseSearchEngine(
    ChromeSettingsOverrides* overrides,
    base::string16* error) {
  if (!overrides->search_provider)
    return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
  if (!CreateManifestURL(overrides->search_provider->favicon_url)) {
    *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
        manifest_errors::kInvalidSearchEngineURL,
        overrides->search_provider->favicon_url);
    return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
  }
  if (!CreateManifestURL(overrides->search_provider->search_url)) {
    *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
        manifest_errors::kInvalidSearchEngineURL,
        overrides->search_provider->search_url);
    return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
  }
  return overrides->search_provider.Pass();
}

// A www. prefix is not informative and thus not worth the limited real estate
// in the permissions UI.
std::string RemoveWwwPrefix(const std::string& url) {
  if (StartsWithASCII(url, kWwwPrefix, false))
    return url.substr(strlen(kWwwPrefix));
  return url;
}

}  // namespace

// The manifest permission implementation supports a permission for overriding
// the bookmark UI.
class SettingsOverridesHandler::ManifestPermissionImpl
    : public ManifestPermission {
 public:
  explicit ManifestPermissionImpl(bool override_bookmarks_ui_permission)
      : override_bookmarks_ui_permission_(override_bookmarks_ui_permission) {}

  // extensions::ManifestPermission overrides.
  virtual std::string name() const OVERRIDE {
    return manifest_keys::kBookmarkUI;
  }

  virtual std::string id() const OVERRIDE {
    return name();
  }

  virtual bool HasMessages() const OVERRIDE {
    return override_bookmarks_ui_permission_;
  }

  virtual PermissionMessages GetMessages() const OVERRIDE {
    PermissionMessages result;
    if (override_bookmarks_ui_permission_) {
      result.push_back(PermissionMessage(
          PermissionMessage::kOverrideBookmarksUI,
          l10n_util::GetStringUTF16(
              IDS_EXTENSION_PROMPT_WARNING_OVERRIDE_BOOKMARKS_UI)));
    }
    return result;
  }

  virtual bool FromValue(const base::Value* value) OVERRIDE {
    return value && value->GetAsBoolean(&override_bookmarks_ui_permission_);
  }

  virtual scoped_ptr<base::Value> ToValue() const OVERRIDE {
    return scoped_ptr<base::Value>(
        new base::FundamentalValue(override_bookmarks_ui_permission_)).Pass();
  }

  virtual ManifestPermission* Clone() const OVERRIDE {
    return scoped_ptr<ManifestPermissionImpl>(
        new ManifestPermissionImpl(
            override_bookmarks_ui_permission_)).release();
  }

  virtual ManifestPermission* Diff(const ManifestPermission* rhs) const
      OVERRIDE {
    const ManifestPermissionImpl* other =
        static_cast<const ManifestPermissionImpl*>(rhs);

    return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl(
        override_bookmarks_ui_permission_ &&
        !other->override_bookmarks_ui_permission_)).release();
  }

  virtual ManifestPermission* Union(const ManifestPermission* rhs) const
      OVERRIDE {
    const ManifestPermissionImpl* other =
        static_cast<const ManifestPermissionImpl*>(rhs);

    return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl(
        override_bookmarks_ui_permission_ ||
        other->override_bookmarks_ui_permission_)).release();
  }

  virtual ManifestPermission* Intersect(const ManifestPermission* rhs) const
      OVERRIDE {
    const ManifestPermissionImpl* other =
        static_cast<const ManifestPermissionImpl*>(rhs);

    return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl(
        override_bookmarks_ui_permission_ &&
        other->override_bookmarks_ui_permission_)).release();
  }

  virtual bool Contains(const ManifestPermission* rhs) const OVERRIDE {
    const ManifestPermissionImpl* other =
        static_cast<const ManifestPermissionImpl*>(rhs);

    return !other->override_bookmarks_ui_permission_ ||
        override_bookmarks_ui_permission_;
  }

  virtual bool Equal(const ManifestPermission* rhs) const OVERRIDE {
    const ManifestPermissionImpl* other =
        static_cast<const ManifestPermissionImpl*>(rhs);

    return override_bookmarks_ui_permission_ ==
        other->override_bookmarks_ui_permission_;
  }

  virtual void Write(IPC::Message* m) const OVERRIDE {
    IPC::WriteParam(m, override_bookmarks_ui_permission_);
  }

  virtual bool Read(const IPC::Message* m, PickleIterator* iter) OVERRIDE {
    return IPC::ReadParam(m, iter, &override_bookmarks_ui_permission_);
  }

  virtual void Log(std::string* log) const OVERRIDE {
    IPC::LogParam(override_bookmarks_ui_permission_, log);
  }

 private:
  bool override_bookmarks_ui_permission_;
};

SettingsOverrides::SettingsOverrides() {}

SettingsOverrides::~SettingsOverrides() {}

const SettingsOverrides* SettingsOverrides::Get(
    const Extension* extension) {
  return static_cast<SettingsOverrides*>(
      extension->GetManifestData(manifest_keys::kSettingsOverride));
}

bool SettingsOverrides::RemovesBookmarkButton() const {
  return bookmarks_ui && bookmarks_ui->remove_button &&
      *bookmarks_ui->remove_button;
}

SettingsOverridesHandler::SettingsOverridesHandler() {}

SettingsOverridesHandler::~SettingsOverridesHandler() {}

bool SettingsOverridesHandler::Parse(Extension* extension,
                                     base::string16* error) {
  const base::Value* dict = NULL;
  CHECK(extension->manifest()->Get(manifest_keys::kSettingsOverride, &dict));
  scoped_ptr<ChromeSettingsOverrides> settings(
      ChromeSettingsOverrides::FromValue(*dict, error));
  if (!settings)
    return false;

  scoped_ptr<SettingsOverrides> info(new SettingsOverrides);
  info->bookmarks_ui.swap(settings->bookmarks_ui);
  // Support backward compatibility for deprecated key
  // chrome_settings_overrides.bookmarks_ui.hide_bookmark_button.
  if (info->bookmarks_ui && !info->bookmarks_ui->remove_button &&
      info->bookmarks_ui->hide_bookmark_button) {
    info->bookmarks_ui->remove_button.reset(
        new bool(*info->bookmarks_ui->hide_bookmark_button));
  }
  info->homepage = ParseHomepage(*settings, error);
  info->search_engine = ParseSearchEngine(settings.get(), error);
  info->startup_pages = ParseStartupPage(*settings, error);
  if (!info->bookmarks_ui && !info->homepage &&
      !info->search_engine && info->startup_pages.empty()) {
    *error =
        base::ASCIIToUTF16(manifest_errors::kInvalidEmptySettingsOverrides);
    return false;
  }
  info->manifest_permission.reset(new ManifestPermissionImpl(
      info->RemovesBookmarkButton()));

  APIPermissionSet* permission_set =
      PermissionsData::GetInitialAPIPermissions(extension);
  DCHECK(permission_set);
  if (info->search_engine) {
    permission_set->insert(new SettingsOverrideAPIPermission(
        PermissionsInfo::GetInstance()->GetByID(APIPermission::kSearchProvider),
        RemoveWwwPrefix(CreateManifestURL(info->search_engine->search_url)->
            GetOrigin().host())));
  }
  if (!info->startup_pages.empty()) {
    permission_set->insert(new SettingsOverrideAPIPermission(
        PermissionsInfo::GetInstance()->GetByID(APIPermission::kStartupPages),
        // We only support one startup page even though the type of the manifest
        // property is a list, only the first one is used.
        RemoveWwwPrefix(info->startup_pages[0].GetContent())));
  }
  if (info->homepage) {
    permission_set->insert(new SettingsOverrideAPIPermission(
        PermissionsInfo::GetInstance()->GetByID(APIPermission::kHomepage),
        RemoveWwwPrefix(info->homepage.get()->GetContent())));
  }
  extension->SetManifestData(manifest_keys::kSettingsOverride,
                             info.release());
  return true;
}

bool SettingsOverridesHandler::Validate(
    const Extension* extension,
    std::string* error,
    std::vector<InstallWarning>* warnings) const {
  const SettingsOverrides* settings_overrides =
      SettingsOverrides::Get(extension);

  if (settings_overrides && settings_overrides->bookmarks_ui) {
    if (!FeatureSwitch::enable_override_bookmarks_ui()->IsEnabled()) {
      warnings->push_back(InstallWarning(
          ErrorUtils::FormatErrorMessage(
              manifest_errors::kUnrecognizedManifestKey,
              manifest_keys::kBookmarkUI)));
    } else if (settings_overrides->bookmarks_ui->hide_bookmark_button) {
      warnings->push_back(InstallWarning(
            ErrorUtils::FormatErrorMessage(
                manifest_errors::kKeyIsDeprecatedWithReplacement,
                manifest_keys::kHideBookmarkButton,
                manifest_keys::kRemoveButton)));
    }
  }

  return true;
}

ManifestPermission* SettingsOverridesHandler::CreatePermission() {
  return new ManifestPermissionImpl(false);
}

ManifestPermission* SettingsOverridesHandler::CreateInitialRequiredPermission(
    const Extension* extension) {
  const SettingsOverrides* data = SettingsOverrides::Get(extension);
  if (data)
    return data->manifest_permission->Clone();
  return NULL;
}
const std::vector<std::string> SettingsOverridesHandler::Keys() const {
  return SingleKey(manifest_keys::kSettingsOverride);
}

}  // namespace extensions
<commit_msg>Fix serialization for chrome_settings_overrides manifest permission<commit_after>// Copyright 2013 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/common/extensions/manifest_handlers/settings_overrides_handler.h"

#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/permissions/settings_override_permission.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/feature_switch.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/permissions/api_permission_set.h"
#include "extensions/common/permissions/manifest_permission.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/permissions/permissions_info.h"
#include "grit/generated_resources.h"
#include "ipc/ipc_message.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"

using extensions::api::manifest_types::ChromeSettingsOverrides;

namespace extensions {
namespace {

const char* kWwwPrefix = "www.";

scoped_ptr<GURL> CreateManifestURL(const std::string& url) {
  scoped_ptr<GURL> manifest_url(new GURL(url));
  if (!manifest_url->is_valid() ||
      !manifest_url->SchemeIsHTTPOrHTTPS())
    return scoped_ptr<GURL>();
  return manifest_url.Pass();
}

scoped_ptr<GURL> ParseHomepage(const ChromeSettingsOverrides& overrides,
                               base::string16* error) {
  if (!overrides.homepage)
    return scoped_ptr<GURL>();
  scoped_ptr<GURL> manifest_url = CreateManifestURL(*overrides.homepage);
  if (!manifest_url) {
    *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
        manifest_errors::kInvalidHomepageOverrideURL, *overrides.homepage);
  }
  return manifest_url.Pass();
}

std::vector<GURL> ParseStartupPage(const ChromeSettingsOverrides& overrides,
                                   base::string16* error) {
  std::vector<GURL> urls;
  if (!overrides.startup_pages)
    return urls;

  for (std::vector<std::string>::const_iterator i =
       overrides.startup_pages->begin(); i != overrides.startup_pages->end();
       ++i) {
    scoped_ptr<GURL> manifest_url = CreateManifestURL(*i);
    if (!manifest_url) {
      *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
          manifest_errors::kInvalidStartupOverrideURL, *i);
    } else {
      urls.push_back(GURL());
      urls.back().Swap(manifest_url.get());
    }
  }
  return urls;
}

scoped_ptr<ChromeSettingsOverrides::Search_provider> ParseSearchEngine(
    ChromeSettingsOverrides* overrides,
    base::string16* error) {
  if (!overrides->search_provider)
    return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
  if (!CreateManifestURL(overrides->search_provider->favicon_url)) {
    *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
        manifest_errors::kInvalidSearchEngineURL,
        overrides->search_provider->favicon_url);
    return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
  }
  if (!CreateManifestURL(overrides->search_provider->search_url)) {
    *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
        manifest_errors::kInvalidSearchEngineURL,
        overrides->search_provider->search_url);
    return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
  }
  return overrides->search_provider.Pass();
}

// A www. prefix is not informative and thus not worth the limited real estate
// in the permissions UI.
std::string RemoveWwwPrefix(const std::string& url) {
  if (StartsWithASCII(url, kWwwPrefix, false))
    return url.substr(strlen(kWwwPrefix));
  return url;
}

}  // namespace

// The manifest permission implementation supports a permission for overriding
// the bookmark UI.
class SettingsOverridesHandler::ManifestPermissionImpl
    : public ManifestPermission {
 public:
  explicit ManifestPermissionImpl(bool override_bookmarks_ui_permission)
      : override_bookmarks_ui_permission_(override_bookmarks_ui_permission) {}

  // extensions::ManifestPermission overrides.
  virtual std::string name() const OVERRIDE {
    return manifest_keys::kSettingsOverride;
  }

  virtual std::string id() const OVERRIDE {
    return name();
  }

  virtual bool HasMessages() const OVERRIDE {
    return override_bookmarks_ui_permission_;
  }

  virtual PermissionMessages GetMessages() const OVERRIDE {
    PermissionMessages result;
    if (override_bookmarks_ui_permission_) {
      result.push_back(PermissionMessage(
          PermissionMessage::kOverrideBookmarksUI,
          l10n_util::GetStringUTF16(
              IDS_EXTENSION_PROMPT_WARNING_OVERRIDE_BOOKMARKS_UI)));
    }
    return result;
  }

  virtual bool FromValue(const base::Value* value) OVERRIDE {
    return value && value->GetAsBoolean(&override_bookmarks_ui_permission_);
  }

  virtual scoped_ptr<base::Value> ToValue() const OVERRIDE {
    return scoped_ptr<base::Value>(
        new base::FundamentalValue(override_bookmarks_ui_permission_)).Pass();
  }

  virtual ManifestPermission* Clone() const OVERRIDE {
    return scoped_ptr<ManifestPermissionImpl>(
        new ManifestPermissionImpl(
            override_bookmarks_ui_permission_)).release();
  }

  virtual ManifestPermission* Diff(const ManifestPermission* rhs) const
      OVERRIDE {
    const ManifestPermissionImpl* other =
        static_cast<const ManifestPermissionImpl*>(rhs);

    return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl(
        override_bookmarks_ui_permission_ &&
        !other->override_bookmarks_ui_permission_)).release();
  }

  virtual ManifestPermission* Union(const ManifestPermission* rhs) const
      OVERRIDE {
    const ManifestPermissionImpl* other =
        static_cast<const ManifestPermissionImpl*>(rhs);

    return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl(
        override_bookmarks_ui_permission_ ||
        other->override_bookmarks_ui_permission_)).release();
  }

  virtual ManifestPermission* Intersect(const ManifestPermission* rhs) const
      OVERRIDE {
    const ManifestPermissionImpl* other =
        static_cast<const ManifestPermissionImpl*>(rhs);

    return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl(
        override_bookmarks_ui_permission_ &&
        other->override_bookmarks_ui_permission_)).release();
  }

  virtual bool Contains(const ManifestPermission* rhs) const OVERRIDE {
    const ManifestPermissionImpl* other =
        static_cast<const ManifestPermissionImpl*>(rhs);

    return !other->override_bookmarks_ui_permission_ ||
        override_bookmarks_ui_permission_;
  }

  virtual bool Equal(const ManifestPermission* rhs) const OVERRIDE {
    const ManifestPermissionImpl* other =
        static_cast<const ManifestPermissionImpl*>(rhs);

    return override_bookmarks_ui_permission_ ==
        other->override_bookmarks_ui_permission_;
  }

  virtual void Write(IPC::Message* m) const OVERRIDE {
    IPC::WriteParam(m, override_bookmarks_ui_permission_);
  }

  virtual bool Read(const IPC::Message* m, PickleIterator* iter) OVERRIDE {
    return IPC::ReadParam(m, iter, &override_bookmarks_ui_permission_);
  }

  virtual void Log(std::string* log) const OVERRIDE {
    IPC::LogParam(override_bookmarks_ui_permission_, log);
  }

 private:
  bool override_bookmarks_ui_permission_;
};

SettingsOverrides::SettingsOverrides() {}

SettingsOverrides::~SettingsOverrides() {}

const SettingsOverrides* SettingsOverrides::Get(
    const Extension* extension) {
  return static_cast<SettingsOverrides*>(
      extension->GetManifestData(manifest_keys::kSettingsOverride));
}

bool SettingsOverrides::RemovesBookmarkButton() const {
  return bookmarks_ui && bookmarks_ui->remove_button &&
      *bookmarks_ui->remove_button;
}

SettingsOverridesHandler::SettingsOverridesHandler() {}

SettingsOverridesHandler::~SettingsOverridesHandler() {}

bool SettingsOverridesHandler::Parse(Extension* extension,
                                     base::string16* error) {
  const base::Value* dict = NULL;
  CHECK(extension->manifest()->Get(manifest_keys::kSettingsOverride, &dict));
  scoped_ptr<ChromeSettingsOverrides> settings(
      ChromeSettingsOverrides::FromValue(*dict, error));
  if (!settings)
    return false;

  scoped_ptr<SettingsOverrides> info(new SettingsOverrides);
  info->bookmarks_ui.swap(settings->bookmarks_ui);
  // Support backward compatibility for deprecated key
  // chrome_settings_overrides.bookmarks_ui.hide_bookmark_button.
  if (info->bookmarks_ui && !info->bookmarks_ui->remove_button &&
      info->bookmarks_ui->hide_bookmark_button) {
    info->bookmarks_ui->remove_button.reset(
        new bool(*info->bookmarks_ui->hide_bookmark_button));
  }
  info->homepage = ParseHomepage(*settings, error);
  info->search_engine = ParseSearchEngine(settings.get(), error);
  info->startup_pages = ParseStartupPage(*settings, error);
  if (!info->bookmarks_ui && !info->homepage &&
      !info->search_engine && info->startup_pages.empty()) {
    *error =
        base::ASCIIToUTF16(manifest_errors::kInvalidEmptySettingsOverrides);
    return false;
  }
  info->manifest_permission.reset(new ManifestPermissionImpl(
      info->RemovesBookmarkButton()));

  APIPermissionSet* permission_set =
      PermissionsData::GetInitialAPIPermissions(extension);
  DCHECK(permission_set);
  if (info->search_engine) {
    permission_set->insert(new SettingsOverrideAPIPermission(
        PermissionsInfo::GetInstance()->GetByID(APIPermission::kSearchProvider),
        RemoveWwwPrefix(CreateManifestURL(info->search_engine->search_url)->
            GetOrigin().host())));
  }
  if (!info->startup_pages.empty()) {
    permission_set->insert(new SettingsOverrideAPIPermission(
        PermissionsInfo::GetInstance()->GetByID(APIPermission::kStartupPages),
        // We only support one startup page even though the type of the manifest
        // property is a list, only the first one is used.
        RemoveWwwPrefix(info->startup_pages[0].GetContent())));
  }
  if (info->homepage) {
    permission_set->insert(new SettingsOverrideAPIPermission(
        PermissionsInfo::GetInstance()->GetByID(APIPermission::kHomepage),
        RemoveWwwPrefix(info->homepage.get()->GetContent())));
  }
  extension->SetManifestData(manifest_keys::kSettingsOverride,
                             info.release());
  return true;
}

bool SettingsOverridesHandler::Validate(
    const Extension* extension,
    std::string* error,
    std::vector<InstallWarning>* warnings) const {
  const SettingsOverrides* settings_overrides =
      SettingsOverrides::Get(extension);

  if (settings_overrides && settings_overrides->bookmarks_ui) {
    if (!FeatureSwitch::enable_override_bookmarks_ui()->IsEnabled()) {
      warnings->push_back(InstallWarning(
          ErrorUtils::FormatErrorMessage(
              manifest_errors::kUnrecognizedManifestKey,
              manifest_keys::kBookmarkUI)));
    } else if (settings_overrides->bookmarks_ui->hide_bookmark_button) {
      warnings->push_back(InstallWarning(
            ErrorUtils::FormatErrorMessage(
                manifest_errors::kKeyIsDeprecatedWithReplacement,
                manifest_keys::kHideBookmarkButton,
                manifest_keys::kRemoveButton)));
    }
  }

  return true;
}

ManifestPermission* SettingsOverridesHandler::CreatePermission() {
  return new ManifestPermissionImpl(false);
}

ManifestPermission* SettingsOverridesHandler::CreateInitialRequiredPermission(
    const Extension* extension) {
  const SettingsOverrides* data = SettingsOverrides::Get(extension);
  if (data)
    return data->manifest_permission->Clone();
  return NULL;
}
const std::vector<std::string> SettingsOverridesHandler::Keys() const {
  return SingleKey(manifest_keys::kSettingsOverride);
}

}  // namespace extensions
<|endoftext|>


<commit_before>#include <ostream>
#include <gtest/gtest.h>
#include "keycode.hpp"
#include "FlagStatus.hpp"

using namespace org_pqrs_KeyRemap4MacBook;

std::ostream& operator<<(std::ostream& os, const EventType& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const KeyboardType& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const ModifierFlag& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const Flags& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const KeyCode& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const ConsumerKeyCode& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const PointingButton& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const Buttons& v) { return os << v.get(); }

TEST(FlagStatus, makeFlags) {
  ASSERT_TRUE(FlagStatus::initialize());

  EXPECT_EQ(Flags(), FlagStatus::makeFlags());

  FlagStatus::set();
  EXPECT_EQ(Flags(), FlagStatus::makeFlags());

  FlagStatus::set(KeyCode::A, 0);
  EXPECT_EQ(Flags(), FlagStatus::makeFlags());

  // down SHIFT_L
  FlagStatus::set(KeyCode::SHIFT_L, ModifierFlag::SHIFT_L);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_L), FlagStatus::makeFlags());

  // no effect with ModifierFlag::NONE
  FlagStatus::set(KeyCode::A, ModifierFlag::NONE);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_L), FlagStatus::makeFlags());

  // down CONTROL_
  FlagStatus::set(KeyCode::CONTROL_L, ModifierFlag::CONTROL_L | ModifierFlag::SHIFT_L);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  // down A
  FlagStatus::set(KeyCode::A, ModifierFlag::CONTROL_L | ModifierFlag::SHIFT_L);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  // up SHIFT_L
  FlagStatus::set(KeyCode::SHIFT_L, ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  // up CONTROL_L
  FlagStatus::set(KeyCode::CONTROL_L, 0);
  EXPECT_EQ(Flags(), FlagStatus::makeFlags());

  // All flags
  FlagStatus::reset();
  FlagStatus::set(KeyCode::CAPSLOCK, ModifierFlag::CAPSLOCK);
  EXPECT_EQ(Flags(ModifierFlag::CAPSLOCK), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::SHIFT_L, ModifierFlag::SHIFT_L);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_L), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::SHIFT_R, ModifierFlag::SHIFT_R);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_R), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::CONTROL_L, ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::CONTROL_R, ModifierFlag::CONTROL_R);
  EXPECT_EQ(Flags(ModifierFlag::CONTROL_R), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::OPTION_L, ModifierFlag::OPTION_L);
  EXPECT_EQ(Flags(ModifierFlag::OPTION_L), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::OPTION_R, ModifierFlag::OPTION_R);
  EXPECT_EQ(Flags(ModifierFlag::OPTION_R), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::COMMAND_L, ModifierFlag::COMMAND_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::COMMAND_R, ModifierFlag::COMMAND_R);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_R), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::FN, ModifierFlag::FN);
  EXPECT_EQ(Flags(ModifierFlag::FN), FlagStatus::makeFlags());
}

TEST(FlagStatus, increase) {
  ASSERT_TRUE(FlagStatus::initialize());

  FlagStatus::increase(ModifierFlag::SHIFT_L);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_L), FlagStatus::makeFlags());

  FlagStatus::increase(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L | ModifierFlag::SHIFT_L), FlagStatus::makeFlags());
}

TEST(FlagStatus, decrease) {
  ASSERT_TRUE(FlagStatus::initialize());

  FlagStatus::increase(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  FlagStatus::decrease(ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L), FlagStatus::makeFlags());
}

TEST(FlagStatus, temporary_increase) {
  ASSERT_TRUE(FlagStatus::initialize());

  FlagStatus::increase(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  FlagStatus::temporary_increase(ModifierFlag::OPTION_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L | ModifierFlag::OPTION_L), FlagStatus::makeFlags());

  // temporary_increase will reset by FlagStatus::set
  FlagStatus::set(KeyCode::COMMAND_L, ModifierFlag::COMMAND_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());
}

TEST(FlagStatus, temporary_decrease) {
  ASSERT_TRUE(FlagStatus::initialize());

  FlagStatus::increase(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  FlagStatus::temporary_decrease(ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L), FlagStatus::makeFlags());

  // temporary_increase will reset by FlagStatus::set
  FlagStatus::set(KeyCode::COMMAND_L, ModifierFlag::COMMAND_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());
}

TEST(FlagStatus, lock_increase) {
  ASSERT_TRUE(FlagStatus::initialize());

  FlagStatus::lock_increase(ModifierFlag::COMMAND_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L), FlagStatus::makeFlags());
}

TEST(FlagStatus, CapsLock) {
  ASSERT_TRUE(FlagStatus::initialize());

  FlagStatus::set(KeyCode::CAPSLOCK, ModifierFlag::CAPSLOCK);
  EXPECT_EQ(Flags(ModifierFlag::CAPSLOCK), FlagStatus::makeFlags());

  FlagStatus::set(KeyCode::A, ModifierFlag::CAPSLOCK);
  EXPECT_EQ(Flags(ModifierFlag::CAPSLOCK), FlagStatus::makeFlags());
}
<commit_msg>update Tests/kext/FlagStatus<commit_after>#include <ostream>
#include <gtest/gtest.h>
#include "keycode.hpp"
#include "FlagStatus.hpp"

using namespace org_pqrs_KeyRemap4MacBook;

std::ostream& operator<<(std::ostream& os, const EventType& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const KeyboardType& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const ModifierFlag& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const Flags& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const KeyCode& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const ConsumerKeyCode& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const PointingButton& v) { return os << v.get(); }
std::ostream& operator<<(std::ostream& os, const Buttons& v) { return os << v.get(); }

TEST(FlagStatus, makeFlags) {
  ASSERT_TRUE(FlagStatus::initialize());

  EXPECT_EQ(Flags(), FlagStatus::makeFlags());

  FlagStatus::set();
  EXPECT_EQ(Flags(), FlagStatus::makeFlags());

  FlagStatus::set(KeyCode::A, 0);
  EXPECT_EQ(Flags(), FlagStatus::makeFlags());

  // down SHIFT_L
  FlagStatus::set(KeyCode::SHIFT_L, ModifierFlag::SHIFT_L);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_L), FlagStatus::makeFlags());

  // no effect with ModifierFlag::NONE
  FlagStatus::set(KeyCode::A, ModifierFlag::NONE);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_L), FlagStatus::makeFlags());

  // down CONTROL_
  FlagStatus::set(KeyCode::CONTROL_L, ModifierFlag::CONTROL_L | ModifierFlag::SHIFT_L);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  // down A
  FlagStatus::set(KeyCode::A, ModifierFlag::CONTROL_L | ModifierFlag::SHIFT_L);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  // up SHIFT_L
  FlagStatus::set(KeyCode::SHIFT_L, ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  // up CONTROL_L
  FlagStatus::set(KeyCode::CONTROL_L, 0);
  EXPECT_EQ(Flags(), FlagStatus::makeFlags());

  // All flags
  FlagStatus::reset();
  FlagStatus::set(KeyCode::CAPSLOCK, ModifierFlag::CAPSLOCK);
  EXPECT_EQ(Flags(ModifierFlag::CAPSLOCK), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::SHIFT_L, ModifierFlag::SHIFT_L);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_L), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::SHIFT_R, ModifierFlag::SHIFT_R);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_R), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::CONTROL_L, ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::CONTROL_R, ModifierFlag::CONTROL_R);
  EXPECT_EQ(Flags(ModifierFlag::CONTROL_R), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::OPTION_L, ModifierFlag::OPTION_L);
  EXPECT_EQ(Flags(ModifierFlag::OPTION_L), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::OPTION_R, ModifierFlag::OPTION_R);
  EXPECT_EQ(Flags(ModifierFlag::OPTION_R), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::COMMAND_L, ModifierFlag::COMMAND_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::COMMAND_R, ModifierFlag::COMMAND_R);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_R), FlagStatus::makeFlags());

  FlagStatus::reset();
  FlagStatus::set(KeyCode::FN, ModifierFlag::FN);
  EXPECT_EQ(Flags(ModifierFlag::FN), FlagStatus::makeFlags());
}

TEST(FlagStatus, increase) {
  ASSERT_TRUE(FlagStatus::initialize());

  FlagStatus::increase(ModifierFlag::SHIFT_L);
  EXPECT_EQ(Flags(ModifierFlag::SHIFT_L), FlagStatus::makeFlags());

  FlagStatus::increase(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L | ModifierFlag::SHIFT_L), FlagStatus::makeFlags());
}

TEST(FlagStatus, decrease) {
  ASSERT_TRUE(FlagStatus::initialize());

  FlagStatus::increase(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  FlagStatus::decrease(ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L), FlagStatus::makeFlags());
}

TEST(FlagStatus, temporary_increase) {
  ASSERT_TRUE(FlagStatus::initialize());

  FlagStatus::increase(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  FlagStatus::temporary_increase(ModifierFlag::OPTION_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L | ModifierFlag::OPTION_L), FlagStatus::makeFlags());

  // temporary_increase will reset by FlagStatus::set
  FlagStatus::set(KeyCode::COMMAND_L, ModifierFlag::COMMAND_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());
}

TEST(FlagStatus, temporary_decrease) {
  ASSERT_TRUE(FlagStatus::initialize());

  FlagStatus::increase(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());

  FlagStatus::temporary_decrease(ModifierFlag::CONTROL_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L), FlagStatus::makeFlags());

  // temporary_increase will reset by FlagStatus::set
  FlagStatus::set(KeyCode::COMMAND_L, ModifierFlag::COMMAND_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L | ModifierFlag::CONTROL_L), FlagStatus::makeFlags());
}

TEST(FlagStatus, lock_increase) {
  ASSERT_TRUE(FlagStatus::initialize());

  FlagStatus::lock_increase(ModifierFlag::COMMAND_L);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L), FlagStatus::makeFlags());

  // lock don't cancel by reset & set.
  FlagStatus::reset();
  FlagStatus::set(KeyCode::A, 0);
  EXPECT_EQ(Flags(ModifierFlag::COMMAND_L), FlagStatus::makeFlags());
}

TEST(FlagStatus, CapsLock) {
  ASSERT_TRUE(FlagStatus::initialize());

  FlagStatus::set(KeyCode::CAPSLOCK, ModifierFlag::CAPSLOCK);
  EXPECT_EQ(Flags(ModifierFlag::CAPSLOCK), FlagStatus::makeFlags());

  FlagStatus::set(KeyCode::A, ModifierFlag::CAPSLOCK);
  EXPECT_EQ(Flags(ModifierFlag::CAPSLOCK), FlagStatus::makeFlags());
}
<|endoftext|>