<commit_before>#include <QTimer>

#include "seafile-applet.h"
#include "account-mgr.h"
#include "api/requests.h"
#include "events-service.h"

namespace {

const int kRefreshEventsInterval = 1000 * 60 * 5; // 5 min

} // namespace

EventsService* EventsService::singleton_;

EventsService* EventsService::instance()
{
    if (singleton_ == NULL) {
        singleton_ = new EventsService;
    }

    return singleton_;
}

EventsService::EventsService(QObject *parent)
    : QObject(parent)
{
    refresh_timer_ = new QTimer(this);
    connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refresh()));
    get_events_req_ = NULL;
    in_refresh_ = false;
    more_offset_ = -1;
}

void EventsService::start()
{
    refresh_timer_->start(kRefreshEventsInterval);
}

void EventsService::refresh()
{
    if (in_refresh_) {
        return;
    }

    AccountManager *account_mgr = seafApplet->accountManager();

    const Account& account = seafApplet->accountManager()->currentAccount();
    if (!account.isValid()) {
        in_refresh_ = false;
        return;
    }

    in_refresh_ = true;

    if (get_events_req_) {
        delete get_events_req_;
    }

    get_events_req_ = new GetEventsRequest(account, more_offset_);

    connect(get_events_req_, SIGNAL(success(const std::vector<SeafEvent>&, int)),
            this, SLOT(onRefreshSuccess(const std::vector<SeafEvent>&, int)));

    connect(get_events_req_, SIGNAL(failed(const ApiError&)),
            this, SLOT(onRefreshFailed(const ApiError&)));

    get_events_req_->send();
}

void EventsService::loadMore()
{
    refresh();
}

void EventsService::onRefreshSuccess(const std::vector<SeafEvent>& events, int new_offset)
{
    in_refresh_ = false;

    const std::vector<SeafEvent> new_events = handleEventsOffset(events);

    bool is_loading_more = more_offset_ > 0;
    bool has_more = new_offset > 0;

    more_offset_ = new_offset;

    emit refreshSuccess(new_events, is_loading_more, has_more);
}

// We use the "offset" param as the starting point of loading more events, but
// if there are new events on the server, the offset would be inaccurate.
const std::vector<SeafEvent>
EventsService::handleEventsOffset(const std::vector<SeafEvent>& new_events)
{
    if (events_.empty()) {
        events_ = new_events;
        return events_;
    }

    const SeafEvent& last = events_[events_.size() - 1];

    int i = 0, n = new_events.size();

    for (i = 0; i < n; i++) {
        const SeafEvent& event = new_events[i];
        if (event.timestamp < last.timestamp) {
            break;
        } else if (event.commit_id == last.commit_id) {
            continue;
        } else {
            continue;
        }
    }

    std::vector<SeafEvent> ret;

    while (i < n) {
        SeafEvent event = new_events[i++];
        events_.push_back(event);
        ret.push_back(event);
    }

    return ret;
}

void EventsService::onRefreshFailed(const ApiError& error)
{
    in_refresh_ = false;

    emit refreshFailed(error);
}

void EventsService::refresh(bool force)
{
    if (force) {
        events_.clear();
        more_offset_ = -1;
        in_refresh_ = false;
    }

    refresh();
}
<commit_msg>fixed loading events<commit_after>#include <QTimer>

#include "seafile-applet.h"
#include "account-mgr.h"
#include "api/requests.h"
#include "events-service.h"

namespace {

const int kRefreshEventsInterval = 1000 * 60 * 5; // 5 min

} // namespace

EventsService* EventsService::singleton_;

EventsService* EventsService::instance()
{
    if (singleton_ == NULL) {
        singleton_ = new EventsService;
    }

    return singleton_;
}

EventsService::EventsService(QObject *parent)
    : QObject(parent)
{
    refresh_timer_ = new QTimer(this);
    connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refresh()));
    get_events_req_ = NULL;
    in_refresh_ = false;
    more_offset_ = -1;
}

void EventsService::start()
{
    refresh_timer_->start(kRefreshEventsInterval);
}

void EventsService::refresh()
{
    if (in_refresh_) {
        return;
    }

    AccountManager *account_mgr = seafApplet->accountManager();

    const Account& account = seafApplet->accountManager()->currentAccount();
    if (!account.isValid()) {
        in_refresh_ = false;
        return;
    }

    in_refresh_ = true;

    if (get_events_req_) {
        delete get_events_req_;
    }

    get_events_req_ = new GetEventsRequest(account, more_offset_);

    connect(get_events_req_, SIGNAL(success(const std::vector<SeafEvent>&, int)),
            this, SLOT(onRefreshSuccess(const std::vector<SeafEvent>&, int)));

    connect(get_events_req_, SIGNAL(failed(const ApiError&)),
            this, SLOT(onRefreshFailed(const ApiError&)));

    get_events_req_->send();
}

void EventsService::loadMore()
{
    refresh();
}

void EventsService::onRefreshSuccess(const std::vector<SeafEvent>& events, int new_offset)
{
    in_refresh_ = false;

    // XXX: uncomment this when we need "load more events feature"
    /*
    const std::vector<SeafEvent> new_events = handleEventsOffset(events);

    bool is_loading_more = more_offset_ > 0;
    bool has_more = new_offset > 0;

    more_offset_ = new_offset;

    emit refreshSuccess(new_events, is_loading_more, has_more);
    */

    emit refreshSuccess(events, false, false);
}

// We use the "offset" param as the starting point of loading more events, but
// if there are new events on the server, the offset would be inaccurate.
const std::vector<SeafEvent>
EventsService::handleEventsOffset(const std::vector<SeafEvent>& new_events)
{
    if (events_.empty()) {
        events_ = new_events;
        return events_;
    }

    const SeafEvent& last = events_[events_.size() - 1];

    int i = 0, n = new_events.size();

    for (i = 0; i < n; i++) {
        const SeafEvent& event = new_events[i];
        if (event.timestamp < last.timestamp) {
            break;
        } else if (event.commit_id == last.commit_id) {
            continue;
        } else {
            continue;
        }
    }

    std::vector<SeafEvent> ret;

    while (i < n) {
        SeafEvent event = new_events[i++];
        events_.push_back(event);
        ret.push_back(event);
    }

    return ret;
}

void EventsService::onRefreshFailed(const ApiError& error)
{
    in_refresh_ = false;

    emit refreshFailed(error);
}

void EventsService::refresh(bool force)
{
    if (force) {
        events_.clear();
        more_offset_ = -1;
        in_refresh_ = false;
    }

    refresh();
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2013-2014 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>

#include "accounts.hpp"
#include "budget_exception.hpp"
#include "args.hpp"
#include "data.hpp"
#include "guid.hpp"
#include "config.hpp"
#include "utils.hpp"
#include "console.hpp"
#include "earnings.hpp"
#include "expenses.hpp"

using namespace budget;

namespace {

static data_handler<account> accounts;

void show_accounts(){
    std::vector<std::string> columns = {"ID", "Name", "Amount"};
    std::vector<std::vector<std::string>> contents;

    money total;

    for(auto& account : accounts.data){
        if(account.until == budget::date(2099,12,31)){
            contents.push_back({to_string(account.id), account.name, to_string(account.amount)});

            total += account.amount;
        }
    }

    contents.push_back({"", "Total", to_string(total)});

    display_table(columns, contents);
}

void show_all_accounts(){
    std::vector<std::string> columns = {"ID", "Name", "Amount", "Since", "Until"};
    std::vector<std::vector<std::string>> contents;

    for(auto& account : accounts.data){
        contents.push_back({to_string(account.id), account.name, to_string(account.amount), to_string(account.since), to_string(account.until)});
    }

    display_table(columns, contents);
}

budget::date find_new_since(){
    budget::date date(1400,1,1);

    for(auto& account : all_accounts()){
        if(account.until != budget::date(2099,12,31)){
            if(account.until - days(1) > date){
                date = account.until - days(1);
            }
        }
    }

    return date;
}

std::size_t get_account_id(std::string name, budget::year year, budget::month month){
    budget::date date(year, month, 5);

    for(auto& account : accounts.data){
        if(account.since < date && account.until > date && account.name == name){
            return account.id;
        }
    }

    return 0;
}

template<typename Values>
void adapt(Values& values, std::size_t old, std::size_t id){
    for(auto& value : values){
        if(value.account == old){
            value.account = id;
        }
    }
}

} //end of anonymous namespace

void budget::accounts_module::load(){
    load_accounts();
    load_expenses();
    load_earnings();
}

void budget::accounts_module::unload(){
    save_accounts();
    save_expenses();
    save_earnings();
}

void budget::accounts_module::handle(const std::vector<std::string>& args){
    if(args.size() == 1){
        show_accounts();
    } else {
        auto& subcommand = args[1];

        if(subcommand == "show"){
            show_accounts();
        } else if(subcommand == "all"){
            show_all_accounts();
        } else if(subcommand == "add"){
            account account;
            account.guid = generate_guid();
            account.since = find_new_since();
            account.until = budget::date(2099,12,31);

            edit_string(account.name, "Name", not_empty_checker());
            edit_money(account.amount, "Amount", not_negative_checker());

            if(account_exists(account.name)){
                throw budget_exception("An account with this name already exists");
            }

            auto id = add_data(accounts, std::move(account));
            std::cout << "Account " << id << " has been created" << std::endl;
        } else if(subcommand == "delete"){
            std::size_t id = 0;

            if(args.size() >= 3){
                enough_args(args, 3);

                id = to_number<std::size_t>(args[2]);

                if(!exists(accounts, id)){
                    throw budget_exception("There are no account with id " + args[2]);
                }
            } else {
                std::string name;
                edit_string(name, "Account", not_empty_checker(), account_checker());

                auto today = budget::local_day();
                id = get_account(name, today.year(), today.month()).id;
            }

            for(auto& expense : all_expenses()){
                if(expense.account == id){
                    throw budget_exception("There are still some expenses linked to this account, cannot delete it");
                }
            }

            for(auto& earning : all_earnings()){
                if(earning.account == id){
                    throw budget_exception("There are still some earnings linked to this account, cannot delete it");
                }
            }

            remove(accounts, id);

            std::cout << "Account " << id << " has been deleted" << std::endl;
        } else if(subcommand == "edit"){
            std::size_t id = 0;

            if(args.size() >= 3){
                enough_args(args, 3);

                id = to_number<std::size_t>(args[2]);

                if(!exists(accounts, id)){
                    throw budget_exception("There are no account with id " + args[2]);
                }
            } else {
                std::string name;
                edit_string(name, "Account", not_empty_checker(), account_checker());

                auto today = budget::local_day();
                id = get_account(name, today.year(), today.month()).id;
            }

            auto& account = get(accounts, id);

            edit_string(account.name, "Name", not_empty_checker());
            edit_money(account.amount, "Amount", not_negative_checker());

            //TODO Verify that there are no OTHER account with this name
            //in the current set of accounts (taking archiving into account)

            std::cout << "Account " << id << " has been modified" << std::endl;

            accounts.changed = true;
        } else if(subcommand == "transfer"){
            std::string from_name;
            edit_string(from_name, "Transfer from", not_empty_checker(), account_checker());

            std::string to_name;
            edit_string(to_name, "Transfer to", not_empty_checker(), account_checker());

            if(from_name == to_name){
                throw budget_exception("Cannot transfer to an from the same account");
            }

            std::string name = "Transfer";
            edit_string(name, "Transfer Name", not_empty_checker());

            money amount;
            edit_money(amount, "Amount", not_negative_checker(), not_zero_checker());

            expense expense;
            expense.guid = generate_guid();
            expense.date = budget::local_day();
            expense.name = name;
            expense.amount = amount;
            expense.account = get_account(from_name, expense.date.year(), expense.date.month()).id;

            add_expense(std::move(expense));

            earning earning;
            earning.guid = generate_guid();
            earning.date = budget::local_day();
            earning.name = name;
            earning.amount = amount;
            earning.account = get_account(to_name, expense.date.year(), expense.date.month()).id;

            add_earning(std::move(earning));
        } else if(subcommand == "migrate"){
            std::string source_account_name;
            edit_string(source_account_name, "Source Account", not_empty_checker(), account_checker());

            std::string destination_account_name;
            edit_string(destination_account_name, "Destination Account", not_empty_checker(), account_checker());

            std::cout << "This command will move all expenses and earnings from \"" << source_account_name
                << "\" to \"" << destination_account_name <<"\" and delete \"" << source_account_name
                << "\". Are you sure you want to proceed ? [yes/no] ? ";

            std::string answer;
            std::getline(std::cin, answer);

            if(answer == "yes" || answer == "y"){
                if(source_account_name == destination_account_name){
                    std::cout << "Migrating an account to itself has no effect" << std::endl;
                } else {
                    //Make sure that we find the destination for
                    //each source accounts

                    for(auto& account : all_accounts()){
                        if(account.name == source_account_name){
                            auto destination_id = get_account_id(destination_account_name, account.since.year(), account.since.month());

                            if(!destination_id){
                                std::cout << "Impossible to find the corresponding account for account " << account.id
                                    << ". This may come from a migration issue. Open an issue on Github if you think that this is a bug" << std::endl;

                                return;
                            }
                        }
                    }

                    std::vector<std::size_t> deleted;

                    //Perform the migration

                    for(auto& account : all_accounts()){
                        if(account.name == source_account_name){
                            auto source_id = account.id;
                            auto& destination_account = get_account(destination_account_name, account.since.year(), account.since.month());
                            auto destination_id = destination_account.id;

                            std::cout << "Migrate account " << source_id << " to account " << destination_id << std::endl;

                            destination_account.amount += account.amount;

                            adapt(all_expenses(), source_id, destination_id);
                            adapt(all_earnings(), source_id, destination_id);

                            deleted.push_back(source_id);
                        }
                    }

                    set_expenses_changed();
                    set_earnings_changed();

                    //Delete the source accounts

                    for(auto& id : deleted){
                        std::cout << "Delete account " << id << std::endl;

                        remove(accounts, id);
                    }

                    set_accounts_changed();

                    std::cout << "Migration done" << std::endl;
                }
            }
        } else if(subcommand == "archive"){
            std::cout << "This command will create new accounts that will be used starting from the beginning of the current month. Are you sure you want to proceed ? [yes/no] ? ";

            std::string answer;
            std::cin >> answer;

            if(answer == "yes" || answer == "y"){
                std::vector<std::size_t> sources;
                std::vector<budget::account> copies;

                auto today = budget::local_day();

                auto tmp = budget::local_day() - months(1);
                budget::date until_date(tmp.year(), tmp.month(), tmp.end_of_month().day());

                for(auto& account : all_accounts()){
                    if(account.until == budget::date(2099,12,31)){
                        budget::account copy;
                        copy.guid = generate_guid();
                        copy.name = account.name;
                        copy.amount = account.amount;
                        copy.until = budget::date(2099,12,31);
                        copy.since = until_date + days(1);

                        account.until = until_date;

                        copies.push_back(std::move(copy));

                        sources.push_back(account.id);
                    }
                }

                std::unordered_map<std::size_t, std::size_t> mapping;

                for(std::size_t i = 0; i < copies.size(); ++i){
                    auto& copy = copies[i];

                    auto id = add_data(accounts, std::move(copy));

                    mapping[sources[i]] = id;
                }

                for(auto& expense : all_expenses()){
                    if(expense.date.month() == today.month() && expense.date.year() == today.year()){
                        if(mapping.find(expense.account) != mapping.end()){
                            expense.account = mapping[expense.account];
                            set_expenses_changed();
                        }
                    }
                }

                for(auto& earning : all_earnings()){
                    if(earning.date.month() == today.month() && earning.date.year() == today.year()){
                        if(mapping.find(earning.account) != mapping.end()){
                            earning.account = mapping[earning.account];
                            set_earnings_changed();
                        }
                    }
                }

                accounts.changed = true;
            }
        } else {
            throw budget_exception("Invalid subcommand \"" + subcommand + "\"");
        }
    }
}

void budget::load_accounts(){
    load_data(accounts, "accounts.data");
}

void budget::save_accounts(){
    save_data(accounts, "accounts.data");
}

budget::account& budget::get_account(std::size_t id){
    return get(accounts, id);
}

budget::account& budget::get_account(std::string name, budget::year year, budget::month month){
    budget::date date(year, month, 5);

    for(auto& account : accounts.data){
        if(account.since < date && account.until > date && account.name == name){
            return account;
        }
    }

    cpp_unreachable("The account does not exist");
}

std::ostream& budget::operator<<(std::ostream& stream, const account& account){
    return stream << account.id  << ':' << account.guid << ':' << account.name << ':' << account.amount << ':' << to_string(account.since) << ':' << to_string(account.until);
}

void budget::operator>>(const std::vector<std::string>& parts, account& account){
    account.id = to_number<std::size_t>(parts[0]);
    account.guid = parts[1];
    account.name = parts[2];
    account.amount = parse_money(parts[3]);
    account.since = from_string(parts[4]);
    account.until = from_string(parts[5]);
}

bool budget::account_exists(const std::string& name){
    for(auto& account : accounts.data){
        if(account.name == name){
            return true;
        }
    }

    return false;
}

std::vector<account>& budget::all_accounts(){
    return accounts.data;
}

std::vector<account> budget::all_accounts(budget::year year, budget::month month){
    std::vector<account> accounts;

    budget::date date(year, month, 5);

    for(auto& account : all_accounts()){
        if(account.since < date && account.until > date){
            accounts.push_back(account);
        }
    }

    return std::move(accounts);
}

void budget::set_accounts_changed(){
    accounts.changed = true;
}

void budget::set_accounts_next_id(std::size_t next_id){
    accounts.next_id = next_id;
}
<commit_msg>Compute percentage of each account<commit_after>//=======================================================================
// Copyright (c) 2013-2014 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>

#include "accounts.hpp"
#include "budget_exception.hpp"
#include "args.hpp"
#include "data.hpp"
#include "guid.hpp"
#include "config.hpp"
#include "utils.hpp"
#include "console.hpp"
#include "earnings.hpp"
#include "expenses.hpp"

using namespace budget;

namespace {

static data_handler<account> accounts;

void show_accounts(){
    std::vector<std::string> columns = {"ID", "Name", "Amount", "Part"};
    std::vector<std::vector<std::string>> contents;

    // Compute the total

    money total;

    for(auto& account : accounts.data){
        if(account.until == budget::date(2099,12,31)){
            total += account.amount;
        }
    }

    // Display the accounts

    for(auto& account : accounts.data){
        if(account.until == budget::date(2099,12,31)){
            float part = 100.0 * (account.amount.value / float(total.value));

            char buffer[32];
            snprintf(buffer, 32, "%.2f%%", part);

            contents.push_back({to_string(account.id), account.name,
                to_string(account.amount),
                buffer});
        }
    }

    contents.push_back({"", "Total", to_string(total), ""});

    display_table(columns, contents);
}

void show_all_accounts(){
    std::vector<std::string> columns = {"ID", "Name", "Amount", "Since", "Until"};
    std::vector<std::vector<std::string>> contents;

    for(auto& account : accounts.data){
        contents.push_back({to_string(account.id), account.name, to_string(account.amount), to_string(account.since), to_string(account.until)});
    }

    display_table(columns, contents);
}

budget::date find_new_since(){
    budget::date date(1400,1,1);

    for(auto& account : all_accounts()){
        if(account.until != budget::date(2099,12,31)){
            if(account.until - days(1) > date){
                date = account.until - days(1);
            }
        }
    }

    return date;
}

std::size_t get_account_id(std::string name, budget::year year, budget::month month){
    budget::date date(year, month, 5);

    for(auto& account : accounts.data){
        if(account.since < date && account.until > date && account.name == name){
            return account.id;
        }
    }

    return 0;
}

template<typename Values>
void adapt(Values& values, std::size_t old, std::size_t id){
    for(auto& value : values){
        if(value.account == old){
            value.account = id;
        }
    }
}

} //end of anonymous namespace

void budget::accounts_module::load(){
    load_accounts();
    load_expenses();
    load_earnings();
}

void budget::accounts_module::unload(){
    save_accounts();
    save_expenses();
    save_earnings();
}

void budget::accounts_module::handle(const std::vector<std::string>& args){
    if(args.size() == 1){
        show_accounts();
    } else {
        auto& subcommand = args[1];

        if(subcommand == "show"){
            show_accounts();
        } else if(subcommand == "all"){
            show_all_accounts();
        } else if(subcommand == "add"){
            account account;
            account.guid = generate_guid();
            account.since = find_new_since();
            account.until = budget::date(2099,12,31);

            edit_string(account.name, "Name", not_empty_checker());
            edit_money(account.amount, "Amount", not_negative_checker());

            if(account_exists(account.name)){
                throw budget_exception("An account with this name already exists");
            }

            auto id = add_data(accounts, std::move(account));
            std::cout << "Account " << id << " has been created" << std::endl;
        } else if(subcommand == "delete"){
            std::size_t id = 0;

            if(args.size() >= 3){
                enough_args(args, 3);

                id = to_number<std::size_t>(args[2]);

                if(!exists(accounts, id)){
                    throw budget_exception("There are no account with id " + args[2]);
                }
            } else {
                std::string name;
                edit_string(name, "Account", not_empty_checker(), account_checker());

                auto today = budget::local_day();
                id = get_account(name, today.year(), today.month()).id;
            }

            for(auto& expense : all_expenses()){
                if(expense.account == id){
                    throw budget_exception("There are still some expenses linked to this account, cannot delete it");
                }
            }

            for(auto& earning : all_earnings()){
                if(earning.account == id){
                    throw budget_exception("There are still some earnings linked to this account, cannot delete it");
                }
            }

            remove(accounts, id);

            std::cout << "Account " << id << " has been deleted" << std::endl;
        } else if(subcommand == "edit"){
            std::size_t id = 0;

            if(args.size() >= 3){
                enough_args(args, 3);

                id = to_number<std::size_t>(args[2]);

                if(!exists(accounts, id)){
                    throw budget_exception("There are no account with id " + args[2]);
                }
            } else {
                std::string name;
                edit_string(name, "Account", not_empty_checker(), account_checker());

                auto today = budget::local_day();
                id = get_account(name, today.year(), today.month()).id;
            }

            auto& account = get(accounts, id);

            edit_string(account.name, "Name", not_empty_checker());
            edit_money(account.amount, "Amount", not_negative_checker());

            //TODO Verify that there are no OTHER account with this name
            //in the current set of accounts (taking archiving into account)

            std::cout << "Account " << id << " has been modified" << std::endl;

            accounts.changed = true;
        } else if(subcommand == "transfer"){
            std::string from_name;
            edit_string(from_name, "Transfer from", not_empty_checker(), account_checker());

            std::string to_name;
            edit_string(to_name, "Transfer to", not_empty_checker(), account_checker());

            if(from_name == to_name){
                throw budget_exception("Cannot transfer to an from the same account");
            }

            std::string name = "Transfer";
            edit_string(name, "Transfer Name", not_empty_checker());

            money amount;
            edit_money(amount, "Amount", not_negative_checker(), not_zero_checker());

            expense expense;
            expense.guid = generate_guid();
            expense.date = budget::local_day();
            expense.name = name;
            expense.amount = amount;
            expense.account = get_account(from_name, expense.date.year(), expense.date.month()).id;

            add_expense(std::move(expense));

            earning earning;
            earning.guid = generate_guid();
            earning.date = budget::local_day();
            earning.name = name;
            earning.amount = amount;
            earning.account = get_account(to_name, expense.date.year(), expense.date.month()).id;

            add_earning(std::move(earning));
        } else if(subcommand == "migrate"){
            std::string source_account_name;
            edit_string(source_account_name, "Source Account", not_empty_checker(), account_checker());

            std::string destination_account_name;
            edit_string(destination_account_name, "Destination Account", not_empty_checker(), account_checker());

            std::cout << "This command will move all expenses and earnings from \"" << source_account_name
                << "\" to \"" << destination_account_name <<"\" and delete \"" << source_account_name
                << "\". Are you sure you want to proceed ? [yes/no] ? ";

            std::string answer;
            std::getline(std::cin, answer);

            if(answer == "yes" || answer == "y"){
                if(source_account_name == destination_account_name){
                    std::cout << "Migrating an account to itself has no effect" << std::endl;
                } else {
                    //Make sure that we find the destination for
                    //each source accounts

                    for(auto& account : all_accounts()){
                        if(account.name == source_account_name){
                            auto destination_id = get_account_id(destination_account_name, account.since.year(), account.since.month());

                            if(!destination_id){
                                std::cout << "Impossible to find the corresponding account for account " << account.id
                                    << ". This may come from a migration issue. Open an issue on Github if you think that this is a bug" << std::endl;

                                return;
                            }
                        }
                    }

                    std::vector<std::size_t> deleted;

                    //Perform the migration

                    for(auto& account : all_accounts()){
                        if(account.name == source_account_name){
                            auto source_id = account.id;
                            auto& destination_account = get_account(destination_account_name, account.since.year(), account.since.month());
                            auto destination_id = destination_account.id;

                            std::cout << "Migrate account " << source_id << " to account " << destination_id << std::endl;

                            destination_account.amount += account.amount;

                            adapt(all_expenses(), source_id, destination_id);
                            adapt(all_earnings(), source_id, destination_id);

                            deleted.push_back(source_id);
                        }
                    }

                    set_expenses_changed();
                    set_earnings_changed();

                    //Delete the source accounts

                    for(auto& id : deleted){
                        std::cout << "Delete account " << id << std::endl;

                        remove(accounts, id);
                    }

                    set_accounts_changed();

                    std::cout << "Migration done" << std::endl;
                }
            }
        } else if(subcommand == "archive"){
            std::cout << "This command will create new accounts that will be used starting from the beginning of the current month. Are you sure you want to proceed ? [yes/no] ? ";

            std::string answer;
            std::cin >> answer;

            if(answer == "yes" || answer == "y"){
                std::vector<std::size_t> sources;
                std::vector<budget::account> copies;

                auto today = budget::local_day();

                auto tmp = budget::local_day() - months(1);
                budget::date until_date(tmp.year(), tmp.month(), tmp.end_of_month().day());

                for(auto& account : all_accounts()){
                    if(account.until == budget::date(2099,12,31)){
                        budget::account copy;
                        copy.guid = generate_guid();
                        copy.name = account.name;
                        copy.amount = account.amount;
                        copy.until = budget::date(2099,12,31);
                        copy.since = until_date + days(1);

                        account.until = until_date;

                        copies.push_back(std::move(copy));

                        sources.push_back(account.id);
                    }
                }

                std::unordered_map<std::size_t, std::size_t> mapping;

                for(std::size_t i = 0; i < copies.size(); ++i){
                    auto& copy = copies[i];

                    auto id = add_data(accounts, std::move(copy));

                    mapping[sources[i]] = id;
                }

                for(auto& expense : all_expenses()){
                    if(expense.date.month() == today.month() && expense.date.year() == today.year()){
                        if(mapping.find(expense.account) != mapping.end()){
                            expense.account = mapping[expense.account];
                            set_expenses_changed();
                        }
                    }
                }

                for(auto& earning : all_earnings()){
                    if(earning.date.month() == today.month() && earning.date.year() == today.year()){
                        if(mapping.find(earning.account) != mapping.end()){
                            earning.account = mapping[earning.account];
                            set_earnings_changed();
                        }
                    }
                }

                accounts.changed = true;
            }
        } else {
            throw budget_exception("Invalid subcommand \"" + subcommand + "\"");
        }
    }
}

void budget::load_accounts(){
    load_data(accounts, "accounts.data");
}

void budget::save_accounts(){
    save_data(accounts, "accounts.data");
}

budget::account& budget::get_account(std::size_t id){
    return get(accounts, id);
}

budget::account& budget::get_account(std::string name, budget::year year, budget::month month){
    budget::date date(year, month, 5);

    for(auto& account : accounts.data){
        if(account.since < date && account.until > date && account.name == name){
            return account;
        }
    }

    cpp_unreachable("The account does not exist");
}

std::ostream& budget::operator<<(std::ostream& stream, const account& account){
    return stream << account.id  << ':' << account.guid << ':' << account.name << ':' << account.amount << ':' << to_string(account.since) << ':' << to_string(account.until);
}

void budget::operator>>(const std::vector<std::string>& parts, account& account){
    account.id = to_number<std::size_t>(parts[0]);
    account.guid = parts[1];
    account.name = parts[2];
    account.amount = parse_money(parts[3]);
    account.since = from_string(parts[4]);
    account.until = from_string(parts[5]);
}

bool budget::account_exists(const std::string& name){
    for(auto& account : accounts.data){
        if(account.name == name){
            return true;
        }
    }

    return false;
}

std::vector<account>& budget::all_accounts(){
    return accounts.data;
}

std::vector<account> budget::all_accounts(budget::year year, budget::month month){
    std::vector<account> accounts;

    budget::date date(year, month, 5);

    for(auto& account : all_accounts()){
        if(account.since < date && account.until > date){
            accounts.push_back(account);
        }
    }

    return std::move(accounts);
}

void budget::set_accounts_changed(){
    accounts.changed = true;
}

void budget::set_accounts_next_id(std::size_t next_id){
    accounts.next_id = next_id;
}
<|endoftext|>


<commit_before>#include "menu.hpp"
#include "button.hpp"
#include "game.hpp"
#include "event.hpp"
#include "SDL_opengl.h"
#include <stdio.h>

UI::Menu::Menu()
    : initted_(false)
{ }

UI::Menu::~Menu()
{ }

void UI::Menu::handleEvent(Event const &evt)
{
    switch (evt.type) {
    case MouseDown:
    case MouseUp:
    case MouseMove:
        handleMouseEvent(evt.mouseEvent());
        break;
    default:
        break;
    }
}

void UI::Menu::draw(unsigned int ticks)
{
    if (!initted_) {
        initted_ = true;
        static char const *const MENU_ITEMS[4] = {
            "Single Player",
            "Multiplayer",
            "Options",
            "Quit"
        };
        for (int i = 0; i < 4; ++i) {
            menu_[i].setText(MENU_ITEMS[i]);
            menu_[i].setLoc(145, 345 - 50 * i);
            scene_.addObject(&menu_[i]);
        }
        menu_[0].setAction(Action(this, static_cast<Action::Method>
                                  (&Menu::newGame)));
        menu_[1].setAction(Action(this, static_cast<Action::Method>
                                  (&Menu::multiplayer)));
        menu_[2].setAction(Action(this, static_cast<Action::Method>
                                  (&Menu::options)));
        menu_[3].setAction(Action(this, static_cast<Action::Method>
                                  (&Menu::quit)));
    }

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, 640.0, 0.0, 480.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);

    scene_.draw(ticks);
}

UI::Widget *UI::Menu::traceMouse(UI::Point pt)
{
    std::vector<Scene::LeafObject *> t;
    scene_.trace(t, pt);
    std::vector<Scene::LeafObject *>::iterator
        i = t.begin(), e = t.end();
    for (; i != e; ++i) {
        Widget *w = dynamic_cast<Widget *>(*i);
        if (w)
            return w;
    }
    return 0;
}

void UI::Menu::newGame()
{
    setActive(new Game);
}

void UI::Menu::multiplayer()
{ }

void UI::Menu::options()
{ }

void UI::Menu::quit()
{
    setActive(NULL);
}
<commit_msg>Fixed bug where menu was drawn in the wrong place.<commit_after>#include "menu.hpp"
#include "button.hpp"
#include "game.hpp"
#include "event.hpp"
#include "SDL_opengl.h"
#include <stdio.h>

UI::Menu::Menu()
    : initted_(false)
{ }

UI::Menu::~Menu()
{ }

void UI::Menu::handleEvent(Event const &evt)
{
    switch (evt.type) {
    case MouseDown:
    case MouseUp:
    case MouseMove:
        handleMouseEvent(evt.mouseEvent());
        break;
    default:
        break;
    }
}

void UI::Menu::draw(unsigned int ticks)
{
    if (!initted_) {
        initted_ = true;
        static char const *const MENU_ITEMS[4] = {
            "Single Player",
            "Multiplayer",
            "Options",
            "Quit"
        };
        for (int i = 0; i < 4; ++i) {
            menu_[i].setText(MENU_ITEMS[i]);
            menu_[i].setLoc(145, 345 - 50 * i);
            scene_.addObject(&menu_[i]);
        }
        menu_[0].setAction(Action(this, static_cast<Action::Method>
                                  (&Menu::newGame)));
        menu_[1].setAction(Action(this, static_cast<Action::Method>
                                  (&Menu::multiplayer)));
        menu_[2].setAction(Action(this, static_cast<Action::Method>
                                  (&Menu::options)));
        menu_[3].setAction(Action(this, static_cast<Action::Method>
                                  (&Menu::quit)));
    }

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, 640.0, 0.0, 480.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    scene_.draw(ticks);
}

UI::Widget *UI::Menu::traceMouse(UI::Point pt)
{
    std::vector<Scene::LeafObject *> t;
    scene_.trace(t, pt);
    std::vector<Scene::LeafObject *>::iterator
        i = t.begin(), e = t.end();
    for (; i != e; ++i) {
        Widget *w = dynamic_cast<Widget *>(*i);
        if (w)
            return w;
    }
    return 0;
}

void UI::Menu::newGame()
{
    setActive(new Game);
}

void UI::Menu::multiplayer()
{ }

void UI::Menu::options()
{ }

void UI::Menu::quit()
{
    setActive(NULL);
}
<|endoftext|>


<commit_before>//===-- TargetData.cpp - Data size & alignment routines --------------------==//
//
// This file defines target properties related to datatype size/offset/alignment
// information.  It uses lazy annotations to cache information about how
// structure types are laid out and used.
//
// This structure should be created once, filled in if the defaults are not
// correct and then passed around by const&.  None of the members functions
// require modification to the object.
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/TargetData.h"
#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Constants.h"

// Handle the Pass registration stuff neccesary to use TargetData's.
namespace {
  // Register the default SparcV9 implementation...
  RegisterPass<TargetData> X("targetdata", "Target Data Layout");
}

static inline void getTypeInfo(const Type *Ty, const TargetData *TD,
			       uint64_t &Size, unsigned char &Alignment);

//===----------------------------------------------------------------------===//
// Support for StructLayout Annotation
//===----------------------------------------------------------------------===//

StructLayout::StructLayout(const StructType *ST, const TargetData &TD)
  : Annotation(TD.getStructLayoutAID()) {
  StructAlignment = 0;
  StructSize = 0;

  // Loop over each of the elements, placing them in memory...
  for (StructType::ElementTypes::const_iterator
	 TI = ST->getElementTypes().begin(),
	 TE = ST->getElementTypes().end(); TI != TE; ++TI) {
    const Type *Ty = *TI;
    unsigned char A;
    unsigned TyAlign;
    uint64_t TySize;
    getTypeInfo(Ty, &TD, TySize, A);
    TyAlign = A;

    // Add padding if neccesary to make the data element aligned properly...
    if (StructSize % TyAlign != 0)
      StructSize = (StructSize/TyAlign + 1) * TyAlign;   // Add padding...

    // Keep track of maximum alignment constraint
    StructAlignment = std::max(TyAlign, StructAlignment);

    MemberOffsets.push_back(StructSize);
    StructSize += TySize;                 // Consume space for this data item
  }

  // Empty structures have alignment of 1 byte.
  if (StructAlignment == 0) StructAlignment = 1;

  // Add padding to the end of the struct so that it could be put in an array
  // and all array elements would be aligned correctly.
  if (StructSize % StructAlignment != 0)
    StructSize = (StructSize/StructAlignment + 1) * StructAlignment;
}

Annotation *TargetData::TypeAnFactory(AnnotationID AID, const Annotable *T,
				      void *D) {
  const TargetData &TD = *(const TargetData*)D;
  assert(AID == TD.AID && "Target data annotation ID mismatch!");
  const Type *Ty = cast<const Type>((const Value *)T);
  assert(isa<StructType>(Ty) &&
	 "Can only create StructLayout annotation on structs!");
  return new StructLayout((const StructType *)Ty, TD);
}

//===----------------------------------------------------------------------===//
//                       TargetData Class Implementation
//===----------------------------------------------------------------------===//

TargetData::TargetData(const std::string &TargetName,
                       bool isLittleEndian, unsigned char PtrSize,
                       unsigned char PtrAl, unsigned char DoubleAl,
                       unsigned char FloatAl, unsigned char LongAl,
                       unsigned char IntAl, unsigned char ShortAl,
                       unsigned char ByteAl)
  : AID(AnnotationManager::getID("TargetData::" + TargetName)) {
  AnnotationManager::registerAnnotationFactory(AID, TypeAnFactory, this);

  // If this assert triggers, a pass "required" TargetData information, but the
  // top level tool did not provide once for it.  We do not want to default
  // construct, or else we might end up using a bad endianness or pointer size!
  //
  assert(!TargetName.empty() &&
         "ERROR: Tool did not specify a target data to use!");

  LittleEndian     = isLittleEndian;
  PointerSize      = PtrSize;
  PointerAlignment = PtrAl;
  DoubleAlignment  = DoubleAl;
  assert(DoubleAlignment == PtrAl &&
         "Double alignment and pointer alignment agree for now!");
  FloatAlignment   = FloatAl;
  LongAlignment    = LongAl;
  IntAlignment     = IntAl;
  ShortAlignment   = ShortAl;
  ByteAlignment    = ByteAl;
}

TargetData::TargetData(const std::string &ToolName, const Module *M)
  : AID(AnnotationManager::getID("TargetData::" + ToolName)) {
  AnnotationManager::registerAnnotationFactory(AID, TypeAnFactory, this);

  LittleEndian     = M->isLittleEndian();
  PointerSize      = M->has32BitPointers() ? 4 : 8;
  PointerAlignment = PointerSize;
  DoubleAlignment  = PointerSize;
  FloatAlignment   = 4;
  LongAlignment    = 8;
  IntAlignment     = 4;
  ShortAlignment   = 2;
  ByteAlignment    = 1;
}

TargetData::~TargetData() {
  AnnotationManager::registerAnnotationFactory(AID, 0);   // Deregister factory
}

static inline void getTypeInfo(const Type *Ty, const TargetData *TD,
			       uint64_t &Size, unsigned char &Alignment) {
  assert(Ty->isSized() && "Cannot getTypeInfo() on a type that is unsized!");
  switch (Ty->getPrimitiveID()) {
  case Type::VoidTyID:
  case Type::BoolTyID:
  case Type::UByteTyID:
  case Type::SByteTyID:  Size = 1; Alignment = TD->getByteAlignment(); return;
  case Type::UShortTyID:
  case Type::ShortTyID:  Size = 2; Alignment = TD->getShortAlignment(); return;
  case Type::UIntTyID:
  case Type::IntTyID:    Size = 4; Alignment = TD->getIntAlignment(); return;
  case Type::ULongTyID:
  case Type::LongTyID:   Size = 8; Alignment = TD->getLongAlignment(); return;
  case Type::FloatTyID:  Size = 4; Alignment = TD->getFloatAlignment(); return;
  case Type::DoubleTyID: Size = 8; Alignment = TD->getDoubleAlignment(); return;
  case Type::LabelTyID:
  case Type::PointerTyID:
    Size = TD->getPointerSize(); Alignment = TD->getPointerAlignment();
    return;
  case Type::ArrayTyID: {
    const ArrayType *ATy = (const ArrayType *)Ty;
    getTypeInfo(ATy->getElementType(), TD, Size, Alignment);
    Size *= ATy->getNumElements();
    return;
  }
  case Type::StructTyID: {
    // Get the layout annotation... which is lazily created on demand.
    const StructLayout *Layout = TD->getStructLayout((const StructType*)Ty);
    Size = Layout->StructSize; Alignment = Layout->StructAlignment;
    return;
  }

  case Type::TypeTyID:
  default:
    assert(0 && "Bad type for getTypeInfo!!!");
    return;
  }
}

uint64_t TargetData::getTypeSize(const Type *Ty) const {
  uint64_t Size;
  unsigned char Align;
  getTypeInfo(Ty, this, Size, Align);
  return Size;
}

unsigned char TargetData::getTypeAlignment(const Type *Ty) const {
  uint64_t Size;
  unsigned char Align;
  getTypeInfo(Ty, this, Size, Align);
  return Align;
}

uint64_t TargetData::getIndexedOffset(const Type *ptrTy,
				      const std::vector<Value*> &Idx) const {
  const Type *Ty = ptrTy;
  assert(isa<PointerType>(Ty) && "Illegal argument for getIndexedOffset()");
  uint64_t Result = 0;

  for (unsigned CurIDX = 0; CurIDX != Idx.size(); ++CurIDX) {
    if (Idx[CurIDX]->getType() == Type::LongTy) {
      // Update Ty to refer to current element
      Ty = cast<SequentialType>(Ty)->getElementType();

      // Get the array index and the size of each array element.
      // Both must be known constants, or the index shd be 0; else this fails.
      int64_t arrayIdx = cast<ConstantSInt>(Idx[CurIDX])->getValue();
      Result += arrayIdx * (int64_t)getTypeSize(Ty);

    } else {
      const StructType *STy = cast<StructType>(Ty);
      assert(Idx[CurIDX]->getType() == Type::UByteTy && "Illegal struct idx");
      unsigned FieldNo = cast<ConstantUInt>(Idx[CurIDX])->getValue();

      // Get structure layout information...
      const StructLayout *Layout = getStructLayout(STy);

      // Add in the offset, as calculated by the structure layout info...
      assert(FieldNo < Layout->MemberOffsets.size() &&"FieldNo out of range!");
      Result += Layout->MemberOffsets[FieldNo];

      // Update Ty to refer to current element
      Ty = STy->getElementTypes()[FieldNo];
    }
  }

  return Result;
}
<commit_msg>Undo one of those last fixes -- it was incorrect.<commit_after>//===-- TargetData.cpp - Data size & alignment routines --------------------==//
//
// This file defines target properties related to datatype size/offset/alignment
// information.  It uses lazy annotations to cache information about how
// structure types are laid out and used.
//
// This structure should be created once, filled in if the defaults are not
// correct and then passed around by const&.  None of the members functions
// require modification to the object.
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/TargetData.h"
#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Constants.h"

// Handle the Pass registration stuff neccesary to use TargetData's.
namespace {
  // Register the default SparcV9 implementation...
  RegisterPass<TargetData> X("targetdata", "Target Data Layout");
}

static inline void getTypeInfo(const Type *Ty, const TargetData *TD,
			       uint64_t &Size, unsigned char &Alignment);

//===----------------------------------------------------------------------===//
// Support for StructLayout Annotation
//===----------------------------------------------------------------------===//

StructLayout::StructLayout(const StructType *ST, const TargetData &TD)
  : Annotation(TD.getStructLayoutAID()) {
  StructAlignment = 0;
  StructSize = 0;

  // Loop over each of the elements, placing them in memory...
  for (StructType::ElementTypes::const_iterator
	 TI = ST->getElementTypes().begin(),
	 TE = ST->getElementTypes().end(); TI != TE; ++TI) {
    const Type *Ty = *TI;
    unsigned char A;
    unsigned TyAlign;
    uint64_t TySize;
    getTypeInfo(Ty, &TD, TySize, A);
    TyAlign = A;

    // Add padding if neccesary to make the data element aligned properly...
    if (StructSize % TyAlign != 0)
      StructSize = (StructSize/TyAlign + 1) * TyAlign;   // Add padding...

    // Keep track of maximum alignment constraint
    StructAlignment = std::max(TyAlign, StructAlignment);

    MemberOffsets.push_back(StructSize);
    StructSize += TySize;                 // Consume space for this data item
  }

  // Empty structures have alignment of 1 byte.
  if (StructAlignment == 0) StructAlignment = 1;

  // Add padding to the end of the struct so that it could be put in an array
  // and all array elements would be aligned correctly.
  if (StructSize % StructAlignment != 0)
    StructSize = (StructSize/StructAlignment + 1) * StructAlignment;
}

Annotation *TargetData::TypeAnFactory(AnnotationID AID, const Annotable *T,
				      void *D) {
  const TargetData &TD = *(const TargetData*)D;
  assert(AID == TD.AID && "Target data annotation ID mismatch!");
  const Type *Ty = cast<const Type>((const Value *)T);
  assert(isa<StructType>(Ty) &&
	 "Can only create StructLayout annotation on structs!");
  return new StructLayout((const StructType *)Ty, TD);
}

//===----------------------------------------------------------------------===//
//                       TargetData Class Implementation
//===----------------------------------------------------------------------===//

TargetData::TargetData(const std::string &TargetName,
                       bool isLittleEndian, unsigned char PtrSize,
                       unsigned char PtrAl, unsigned char DoubleAl,
                       unsigned char FloatAl, unsigned char LongAl,
                       unsigned char IntAl, unsigned char ShortAl,
                       unsigned char ByteAl)
  : AID(AnnotationManager::getID("TargetData::" + TargetName)) {
  AnnotationManager::registerAnnotationFactory(AID, TypeAnFactory, this);

  // If this assert triggers, a pass "required" TargetData information, but the
  // top level tool did not provide once for it.  We do not want to default
  // construct, or else we might end up using a bad endianness or pointer size!
  //
  assert(!TargetName.empty() &&
         "ERROR: Tool did not specify a target data to use!");

  LittleEndian     = isLittleEndian;
  PointerSize      = PtrSize;
  PointerAlignment = PtrAl;
  DoubleAlignment  = DoubleAl;
  assert(DoubleAlignment == PtrAl &&
         "Double alignment and pointer alignment agree for now!");
  FloatAlignment   = FloatAl;
  LongAlignment    = LongAl;
  IntAlignment     = IntAl;
  ShortAlignment   = ShortAl;
  ByteAlignment    = ByteAl;
}

TargetData::TargetData(const std::string &ToolName, const Module *M)
  : AID(AnnotationManager::getID("TargetData::" + ToolName)) {
  AnnotationManager::registerAnnotationFactory(AID, TypeAnFactory, this);

  LittleEndian     = M->isLittleEndian();
  PointerSize      = M->has32BitPointers() ? 4 : 8;
  PointerAlignment = PointerSize;
  DoubleAlignment  = PointerSize;
  FloatAlignment   = 4;
  LongAlignment    = 8;
  IntAlignment     = 4;
  ShortAlignment   = 2;
  ByteAlignment    = 1;
}

TargetData::~TargetData() {
  AnnotationManager::registerAnnotationFactory(AID, 0);   // Deregister factory
}

static inline void getTypeInfo(const Type *Ty, const TargetData *TD,
			       uint64_t &Size, unsigned char &Alignment) {
  assert(Ty->isSized() && "Cannot getTypeInfo() on a type that is unsized!");
  switch (Ty->getPrimitiveID()) {
  case Type::VoidTyID:
  case Type::BoolTyID:
  case Type::UByteTyID:
  case Type::SByteTyID:  Size = 1; Alignment = TD->getByteAlignment(); return;
  case Type::UShortTyID:
  case Type::ShortTyID:  Size = 2; Alignment = TD->getShortAlignment(); return;
  case Type::UIntTyID:
  case Type::IntTyID:    Size = 4; Alignment = TD->getIntAlignment(); return;
  case Type::ULongTyID:
  case Type::LongTyID:   Size = 8; Alignment = TD->getLongAlignment(); return;
  case Type::FloatTyID:  Size = 4; Alignment = TD->getFloatAlignment(); return;
  case Type::DoubleTyID: Size = 8; Alignment = TD->getDoubleAlignment(); return;
  case Type::LabelTyID:
  case Type::PointerTyID:
    Size = TD->getPointerSize(); Alignment = TD->getPointerAlignment();
    return;
  case Type::ArrayTyID: {
    const ArrayType *ATy = (const ArrayType *)Ty;
    getTypeInfo(ATy->getElementType(), TD, Size, Alignment);
    Size *= ATy->getNumElements();
    return;
  }
  case Type::StructTyID: {
    // Get the layout annotation... which is lazily created on demand.
    const StructLayout *Layout = TD->getStructLayout((const StructType*)Ty);
    Size = Layout->StructSize; Alignment = Layout->StructAlignment;
    return;
  }

  case Type::TypeTyID:
  default:
    assert(0 && "Bad type for getTypeInfo!!!");
    return;
  }
}

uint64_t TargetData::getTypeSize(const Type *Ty) const {
  uint64_t Size;
  unsigned char Align;
  getTypeInfo(Ty, this, Size, Align);
  return Size;
}

unsigned char TargetData::getTypeAlignment(const Type *Ty) const {
  uint64_t Size;
  unsigned char Align;
  getTypeInfo(Ty, this, Size, Align);
  return Align;
}

uint64_t TargetData::getIndexedOffset(const Type *ptrTy,
				      const std::vector<Value*> &Idx) const {
  const Type *Ty = ptrTy;
  assert(isa<PointerType>(Ty) && "Illegal argument for getIndexedOffset()");
  uint64_t Result = 0;

  for (unsigned CurIDX = 0; CurIDX != Idx.size(); ++CurIDX) {
    if (Idx[CurIDX]->getType() == Type::LongTy) {
      // Update Ty to refer to current element
      Ty = cast<SequentialType>(Ty)->getElementType();

      // Get the array index and the size of each array element.
      // The size must be a known value, except if arrayIdx is 0.
      // In particular, don't try to get the type size if the arrayIdx is 0:
      // 0 index into an unsized type is legal and should be allowed.
      int64_t arrayIdx = cast<ConstantSInt>(Idx[CurIDX])->getValue();
      Result += arrayIdx == 0? 0
                             : arrayIdx * (int64_t)getTypeSize(Ty);
    } else {
      const StructType *STy = cast<StructType>(Ty);
      assert(Idx[CurIDX]->getType() == Type::UByteTy && "Illegal struct idx");
      unsigned FieldNo = cast<ConstantUInt>(Idx[CurIDX])->getValue();

      // Get structure layout information...
      const StructLayout *Layout = getStructLayout(STy);

      // Add in the offset, as calculated by the structure layout info...
      assert(FieldNo < Layout->MemberOffsets.size() &&"FieldNo out of range!");
      Result += Layout->MemberOffsets[FieldNo];

      // Update Ty to refer to current element
      Ty = STy->getElementTypes()[FieldNo];
    }
  }

  return Result;
}
<|endoftext|>


<commit_before>#include "Context.h"

#include <cmath>
#include <iostream>

#ifdef OPENGL
#include <glm/glm.hpp>
#endif

using namespace std;
using namespace canvas;

void
Context::resize(unsigned int _width, unsigned int _height) {
   getDefaultSurface().resize(_width, _height, (unsigned int)(_width * getDisplayScale()), (unsigned int)(_height * getDisplayScale()));
}

void
Context::rect(double x, double y, double w, double h) {
  moveTo(x, y);
  lineTo(x + w, y);
  lineTo(x + w, y + h);
  lineTo(x, y + h);
  closePath();
}

void
Context::fillRect(double x, double y, double w, double h) {
  beginPath();
  rect(x, y, w, h);
  fill();
}

void
Context::strokeRect(double x, double y, double w, double h) {
  beginPath();
  rect(x, y, w, h);
  stroke();
}

void
Context::renderText(RenderMode mode, const Style & style, const std::string & text, double x, double y) {
  if (hasShadow()) {
    float b = shadowBlur, bs = shadowBlur * getDisplayScale();
    int bi = int(ceil(b));
    auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, true);
    Style shadow_style = shadowColor;
    float shadow_alpha = shadowColor.alpha;
    shadow_style.color.alpha = 1.0f;
    shadow->renderText(mode, font, shadow_style, textBaseline, textAlign, text, x + shadowOffsetX + bi, y + shadowOffsetY + bi, lineWidth, getDisplayScale());
    shadow->gaussianBlur(bs, bs, shadow_alpha);
    getDefaultSurface().drawImage(*shadow, -bi, -bi, shadow->getActualWidth(), shadow->getActualHeight());
  }
  getDefaultSurface().renderText(mode, font, style, textBaseline, textAlign, text, x, y, lineWidth, getDisplayScale());
}

void
Context::renderPath(RenderMode mode, const Style & style) {
  if (hasShadow()) {
    float b = shadowBlur, bs = shadowBlur * getDisplayScale();
    float bi = int(ceil(b));
    auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, true);
    Style shadow_style = shadowColor;
    Path tmp_path = current_path;
    tmp_path.offset(shadowOffsetX + bi, shadowOffsetY + bi);

    shadow->renderPath(mode, tmp_path, shadow_style, lineWidth, getDisplayScale());
    shadow->gaussianBlur(bs, bs);

    getDefaultSurface().drawImage(*shadow, -bi, -bi, shadow->getActualWidth(), shadow->getActualHeight());
  }
  getDefaultSurface().renderPath(mode, current_path, style, getDisplayScale(), getDisplayScale());
}

void
Context::drawImage(Surface & img, double x, double y, double w, double h) {
  if (hasShadow()) {
    float b = shadowBlur, bs = shadowBlur * getDisplayScale();
    float bi = int(ceil(b));
    auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, true);

    shadow->drawImage(img, (x + bi + shadowOffsetX) * getDisplayScale(), (y + bi + shadowOffsetY) * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), globalAlpha, imageSmoothingEnabled);
    shadow->colorFill(shadowColor);
    shadow->gaussianBlur(bs, bs);

    getDefaultSurface().drawImage(*shadow, -bi, -bi, shadow->getActualWidth(), shadow->getActualHeight());
  }
  getDefaultSurface().drawImage(img, x * getDisplayScale(), y * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), globalAlpha, imageSmoothingEnabled);
}

void
Context::save() {
  restore_stack.push_back(SavedContext());
  auto & data = restore_stack.back();
  data.globalAlpha = globalAlpha;
  data.current_path = current_path;
  getDefaultSurface().save();
}

void
Context::restore() {
  if (!restore_stack.empty()) {
    auto & data = restore_stack.back();
    globalAlpha = data.globalAlpha;
    current_path = data.current_path;
  }
  getDefaultSurface().restore();
}
<commit_msg>add has_alpha parameter to resize<commit_after>#include "Context.h"

#include <cmath>
#include <iostream>

#ifdef OPENGL
#include <glm/glm.hpp>
#endif

using namespace std;
using namespace canvas;

void
Context::resize(unsigned int _width, unsigned int _height) {
   getDefaultSurface().resize(_width, _height, (unsigned int)(_width * getDisplayScale()), (unsigned int)(_height * getDisplayScale()), getDefaultSurface().hasAlpha());
}

void
Context::rect(double x, double y, double w, double h) {
  moveTo(x, y);
  lineTo(x + w, y);
  lineTo(x + w, y + h);
  lineTo(x, y + h);
  closePath();
}

void
Context::fillRect(double x, double y, double w, double h) {
  beginPath();
  rect(x, y, w, h);
  fill();
}

void
Context::strokeRect(double x, double y, double w, double h) {
  beginPath();
  rect(x, y, w, h);
  stroke();
}

void
Context::renderText(RenderMode mode, const Style & style, const std::string & text, double x, double y) {
  if (hasShadow()) {
    float b = shadowBlur, bs = shadowBlur * getDisplayScale();
    int bi = int(ceil(b));
    auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, true);
    Style shadow_style = shadowColor;
    float shadow_alpha = shadowColor.alpha;
    shadow_style.color.alpha = 1.0f;
    shadow->renderText(mode, font, shadow_style, textBaseline, textAlign, text, x + shadowOffsetX + bi, y + shadowOffsetY + bi, lineWidth, getDisplayScale());
    shadow->gaussianBlur(bs, bs, shadow_alpha);
    getDefaultSurface().drawImage(*shadow, -bi, -bi, shadow->getActualWidth(), shadow->getActualHeight());
  }
  getDefaultSurface().renderText(mode, font, style, textBaseline, textAlign, text, x, y, lineWidth, getDisplayScale());
}

void
Context::renderPath(RenderMode mode, const Style & style) {
  if (hasShadow()) {
    float b = shadowBlur, bs = shadowBlur * getDisplayScale();
    float bi = int(ceil(b));
    auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, true);
    Style shadow_style = shadowColor;
    Path tmp_path = current_path;
    tmp_path.offset(shadowOffsetX + bi, shadowOffsetY + bi);

    shadow->renderPath(mode, tmp_path, shadow_style, lineWidth, getDisplayScale());
    shadow->gaussianBlur(bs, bs);

    getDefaultSurface().drawImage(*shadow, -bi, -bi, shadow->getActualWidth(), shadow->getActualHeight());
  }
  getDefaultSurface().renderPath(mode, current_path, style, getDisplayScale(), getDisplayScale());
}

void
Context::drawImage(Surface & img, double x, double y, double w, double h) {
  if (hasShadow()) {
    float b = shadowBlur, bs = shadowBlur * getDisplayScale();
    float bi = int(ceil(b));
    auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, true);

    shadow->drawImage(img, (x + bi + shadowOffsetX) * getDisplayScale(), (y + bi + shadowOffsetY) * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), globalAlpha, imageSmoothingEnabled);
    shadow->colorFill(shadowColor);
    shadow->gaussianBlur(bs, bs);

    getDefaultSurface().drawImage(*shadow, -bi, -bi, shadow->getActualWidth(), shadow->getActualHeight());
  }
  getDefaultSurface().drawImage(img, x * getDisplayScale(), y * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), globalAlpha, imageSmoothingEnabled);
}

void
Context::save() {
  restore_stack.push_back(SavedContext());
  auto & data = restore_stack.back();
  data.globalAlpha = globalAlpha;
  data.current_path = current_path;
  getDefaultSurface().save();
}

void
Context::restore() {
  if (!restore_stack.empty()) {
    auto & data = restore_stack.back();
    globalAlpha = data.globalAlpha;
    current_path = data.current_path;
  }
  getDefaultSurface().restore();
}
<|endoftext|>


<commit_before>/* ****************************************************************
 *
 * Copyright 2014 Samsung Electronics All Rights Reserved.
 *
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************/

#include "gtest/gtest.h"
#include "cainterface.h"
#include "cautilinterface.h"
#include "cacommon.h"

#define CA_TRANSPORT_ADAPTER_SCOPE  1000

class CATests : public testing::Test {
    protected:
    virtual void SetUp() {
        CAInitialize();
    }

    virtual void TearDown()
    {
        CATerminate();
    }
};

void request_handler(CAEndpoint_t* object, CARequestInfo_t* requestInfo);
void response_handler(CAEndpoint_t* object, CAResponseInfo_t* responseInfo);
void error_handler(const CAEndpoint_t *object, const CAErrorInfo_t* errorInfo);
void adapter_handler(CATransportAdapter_t adapter, bool enabled);
void connection_handler(CATransportAdapter_t adapter, const char *remote_address, bool connected);
CAResult_t checkGetNetworkInfo();
CAResult_t checkSelectNetwork();

void request_handler(const CAEndpoint_t * /*object*/,
                     const CARequestInfo_t * /*requestInfo*/)
{

}

void response_handler(const CAEndpoint_t * /*object*/,
                      const CAResponseInfo_t * /*responseInfo*/)
{

}

void error_handler(const CAEndpoint_t *object, const CAErrorInfo_t* errorInfo)
{
    if(!object || !errorInfo)
    {
        return;
    }

    //error handling shall be added
    return;
}

void adapter_handler(CATransportAdapter_t /*adapter*/,
                     bool /*enabled*/)
{
}

void connection_handler(CATransportAdapter_t /*adapter*/,
                        const char * /*remote_address*/,
                        bool /*connected*/)
{
}

static char* addr = NULL;
static CAEndpoint_t* tempRep = NULL;
static CARequestInfo_t requestInfo;
static CAInfo_t requestData;
static CAInfo_t responseData;
static CAResponseInfo_t responseInfo;
static CAToken_t tempToken = NULL;
static uint8_t tokenLength = CA_MAX_TOKEN_LEN;
static const char ADDRESS[] = "10.11.12.13";
static const uint16_t PORT = 4545;

static const char NORMAL_INFO_DATA[] =
                                    "{\"oc\":[{\"href\":\"%s\",\"prop\":{\"rt\":[\"core.led\"],"
                                     "\"if\":[\"oc.mi.def\"],\"obs\":1}}]}";

#ifdef __WITH_DTLS__

// Iotivity Device Identity.
const unsigned char IDENTITY[] = ("1111111111111111");

// PSK between this device and peer device.
const unsigned char RS_CLIENT_PSK[] = ("AAAAAAAAAAAAAAAA");

// Internal API. Invoked by CA stack to retrieve credentials from this module
int32_t CAGetDtlsPskCredentials( CADtlsPskCredType_t type,
              const unsigned char *desc, size_t desc_len,
              unsigned char *result, size_t result_length)
{
    printf("CAGetDtlsPskCredentials IN\n");

    int32_t ret = -1;

    if (NULL == result)
    {
        return ret;
    }

    switch (type)
    {
        case CA_DTLS_PSK_HINT:
        case CA_DTLS_PSK_IDENTITY:

            if (result_length < sizeof(IDENTITY))
            {
                printf("ERROR : Wrong value for result for storing IDENTITY");
                return ret;
            }

            memcpy(result, IDENTITY, sizeof(IDENTITY));
            ret = sizeof(IDENTITY);
            break;

        case CA_DTLS_PSK_KEY:

            if ((desc_len == sizeof(IDENTITY)) &&
                memcmp(desc, IDENTITY, sizeof(IDENTITY)) == 0)
            {
                if (result_length < sizeof(RS_CLIENT_PSK))
                {
                    printf("ERROR : Wrong value for result for storing RS_CLIENT_PSK");
                    return ret;
                }

                memcpy(result, RS_CLIENT_PSK, sizeof(RS_CLIENT_PSK));
                ret = sizeof(RS_CLIENT_PSK);
            }
            break;

        default:

            printf("Wrong value passed for PSK_CRED_TYPE.");
            ret = -1;
    }

    printf("CAGetDtlsPskCredentials OUT\n");
    return ret;
}
#endif  //__WITH_DTLS__

int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

// CAInitialize TC
// check return value
TEST(InitializeTest, TC_01_Positive_01)
{
    EXPECT_EQ(CA_STATUS_OK, CAInitialize());
    CATerminate();
}

//CATerminate TC
TEST_F(CATests, TerminateTest)
{
    CATerminate();

    char* check = (char *) "terminate success";
    EXPECT_STREQ(check, "terminate success");

    CAInitialize();
}
// CAStartListeningServer TC
// check return value
TEST(StartListeningServerTest, DISABLED_TC_03_Positive_01)
{
    CASelectNetwork(CA_ADAPTER_IP);
    EXPECT_EQ(CA_STATUS_OK, CAStartListeningServer());
}

// CAStartDiscoveryServer TC
// check return value
TEST(StartDiscoveryServerTest, DISABLED_TC_04_Positive_01)
{
    EXPECT_EQ(CA_STATUS_OK, CAStartDiscoveryServer());
}

// CARegisterHandlerTest TC
// check return value
TEST_F(CATests, RegisterHandlerTest)
{
    CARegisterHandler(request_handler, response_handler, error_handler);
    char* check = (char *) "registerHandler success";
    EXPECT_STREQ(check, "registerHandler success");
}

// CACreateRemoteEndpoint TC
// check return value
TEST_F(CATests, CreateRemoteEndpointTestGood)
{
    addr = (char *) ADDRESS;

    EXPECT_EQ(CA_STATUS_OK, CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr,
                                             PORT, &tempRep));

    CADestroyEndpoint(tempRep);
    tempRep = NULL;
}

// check remoteEndpoint and values of remoteEndpoint
TEST_F(CATests, CreateRemoteEndpointTestValues)
{
    addr = (char *) ADDRESS;

    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr, PORT, &tempRep);

    EXPECT_TRUE(tempRep != NULL);

    CADestroyEndpoint(tempRep);
    tempRep = NULL;
}

// CAGerateToken TC
// check return value
TEST_F(CATests, GenerateTokenTestGood)
{
    EXPECT_EQ(CA_STATUS_OK, CAGenerateToken(&tempToken, tokenLength));

    CADestroyToken(tempToken);
}

// check return value when CAGenerateToken is passed a NULL instead a valid pointer
TEST_F(CATests, GenerateTokenTestBad)
{
    EXPECT_EQ(CA_STATUS_INVALID_PARAM, CAGenerateToken(NULL, tokenLength));
}

// CADestroyToken TC
// check destroyed token
TEST_F(CATests, DestroyTokenTest)
{
    CAGenerateToken(&tempToken, tokenLength);
    CADestroyToken(tempToken);

    char * check = (char *) "destroy success";
    EXPECT_STREQ(check, "destroy success");
}

// CASendRequest TC
// check return value
TEST(SendRequestTest, DISABLED_TC_16_Positive_01)
{
    addr = (char *) ADDRESS;
    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr, PORT, &tempRep);

    memset(&requestData, 0, sizeof(CAInfo_t));
    CAGenerateToken(&tempToken, tokenLength);
    requestData.token = tempToken;
    requestData.tokenLength = tokenLength;

    int length = strlen(NORMAL_INFO_DATA) + strlen("a/light");
    requestData.payload = (CAPayload_t) calloc(length, sizeof(char));
    if(!requestData.payload)
    {
        CADestroyToken(tempToken);
        FAIL() << "requestData.payload allocation failed";
    }
    snprintf((char*)requestData.payload, length, NORMAL_INFO_DATA, "a/light");
    requestData.payloadSize = length + 1;
    requestData.type = CA_MSG_NONCONFIRM;

    memset(&requestInfo, 0, sizeof(CARequestInfo_t));
    requestInfo.method = CA_GET;
    requestInfo.info = requestData;

    EXPECT_EQ(CA_STATUS_OK, CASendRequest(tempRep, &requestInfo));

    CADestroyToken(tempToken);
    CADestroyEndpoint(tempRep);
    free(requestData.payload);
    tempRep = NULL;
}

// check return value when a NULL is passed instead of a valid CARequestInfo_t address
TEST_F(CATests, SendRequestTestWithNullAddr)
{
    addr = (char *) ADDRESS;
    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr, PORT, &tempRep);

    EXPECT_EQ(CA_STATUS_INVALID_PARAM, CASendRequest(tempRep, NULL));

    CADestroyEndpoint(tempRep);
    tempRep = NULL;
}

// CASendResponse TC
// check return value
TEST(SendResponseTest, DISABLED_TC_19_Positive_01)
{
    addr = (char *) ADDRESS;
    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr, PORT, &tempRep);

    memset(&responseData, 0, sizeof(CAInfo_t));
    responseData.type = CA_MSG_NONCONFIRM;
    responseData.messageId = 1;
    responseData.payload = (CAPayload_t)malloc(sizeof("response payload"));

    EXPECT_TRUE(responseData.payload != NULL);
    if(!responseData.payload)
    {
        CADestroyEndpoint(tempRep);
        return;
    }

    memcpy(responseData.payload, "response payload", sizeof("response payload"));
    responseData.payloadSize = sizeof("response payload");

    CAGenerateToken(&tempToken, tokenLength);
    requestData.token = tempToken;
    requestData.tokenLength = tokenLength;

    memset(&responseInfo, 0, sizeof(CAResponseInfo_t));
    responseInfo.result = CA_CONTENT;
    responseInfo.info = responseData;

    EXPECT_EQ(CA_STATUS_OK, CASendResponse(tempRep, &responseInfo));

    CADestroyToken(tempToken);
    CADestroyEndpoint(tempRep);
    free(responseData.payload);
    tempRep = NULL;
}

// check return value when address is NULL as multicast
TEST(SendResponseTest, DISABLED_TC_20_Negative_01)
{
    addr = NULL;
    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr, 0, &tempRep);

    memset(&responseData, 0, sizeof(CAInfo_t));
    responseData.type = CA_MSG_NONCONFIRM;
    responseData.messageId = 1;
    responseData.payload = (CAPayload_t)malloc(sizeof("response payload"));
    EXPECT_TRUE(responseData.payload != NULL);

    if(!responseData.payload)
    {
        CADestroyEndpoint(tempRep);
        return;
    }

    memcpy(responseData.payload, "response payload", sizeof("response payload"));
    responseData.payloadSize = sizeof("response payload");

    CAGenerateToken(&tempToken, tokenLength);
    requestData.token = tempToken;
    requestData.tokenLength = tokenLength;

    memset(&responseInfo, 0, sizeof(CAResponseInfo_t));
    responseInfo.result = CA_CONTENT;
    responseInfo.info = responseData;

    EXPECT_EQ(CA_STATUS_OK, CASendResponse(tempRep, &responseInfo));

    CADestroyToken(tempToken);
    CADestroyEndpoint(tempRep);
    free (responseData.payload);
    tempRep = NULL;
}

// check return value NULL is passed instead of a valid CAResponseInfo_t address
TEST_F(CATests, SendResponseTest)
{
    addr = (char *) ADDRESS;
    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr, PORT, &tempRep);

    EXPECT_EQ(CA_STATUS_INVALID_PARAM, CASendResponse(tempRep, NULL));

    CADestroyEndpoint(tempRep);
    tempRep = NULL;
}

// CASelectNewwork TC
// check return value
TEST_F(CATests, SelectNetworkTestGood)
{
    EXPECT_EQ(CA_STATUS_OK, checkSelectNetwork());
}

CAResult_t checkSelectNetwork()
{
    CAResult_t res = CASelectNetwork(CA_ADAPTER_IP);

    if (CA_STATUS_OK == res)
    {
        EXPECT_EQ(CA_STATUS_OK, CAUnSelectNetwork(CA_ADAPTER_IP));
        return CA_STATUS_OK;
    }
    if (CA_NOT_SUPPORTED == res)
    {
        EXPECT_EQ(CA_STATUS_FAILED, CAUnSelectNetwork(CA_ADAPTER_IP));
        return CA_STATUS_OK;
    }

    return res;
}

// check return value when selected network is disable
TEST_F(CATests, SelectNetworkTestBad)
{
    //Select disable network
    EXPECT_EQ(CA_NOT_SUPPORTED, CASelectNetwork((CATransportAdapter_t)
                                                CA_TRANSPORT_ADAPTER_SCOPE));
}

// check return value when selected network is disable
TEST_F(CATests, UnSelectNetworkTest)
{
    //UnSelect disable network
    EXPECT_EQ(CA_STATUS_FAILED, CAUnSelectNetwork((CATransportAdapter_t)
                                                  CA_TRANSPORT_ADAPTER_SCOPE));
}

// CAHandlerRequestResponse TC
// check return value
TEST_F(CATests, HandlerRequestResponseTest)
{
    EXPECT_EQ(CA_STATUS_OK, CAHandleRequestResponse());
}

// CAGetNetworkInformation TC
// check return value
TEST_F (CATests, GetNetworkInformationTestGood)
{
    EXPECT_EQ(CA_STATUS_OK, checkGetNetworkInfo());
}

TEST_F(CATests, RegisterDTLSCredentialsHandlerTest)
{
#ifdef __WITH_DTLS__
    EXPECT_EQ(CA_STATUS_OK, CARegisterDTLSCredentialsHandler(CAGetDtlsPskCredentials));
#endif
}

// CARegisterNetworkMonitorHandler TC
// check return value
TEST_F(CATests, RegisterNetworkMonitorHandler)
{
#ifdef LE_ADAPTER
    EXPECT_EQ(CA_STATUS_OK, CARegisterNetworkMonitorHandler(adapter_handler,
                                                            connection_handler));
#else
    EXPECT_EQ(CA_NOT_SUPPORTED, CARegisterNetworkMonitorHandler(adapter_handler,
                                                                connection_handler));
#endif
}

// CASetAutoConnectionDeviceInfo TC
// check return value
TEST_F(CATests, SetAutoConnectionDeviceInfo)
{
    addr = (char *) ADDRESS;

#if defined(__ANDROID__) && defined(LE_ADAPTER)
    EXPECT_EQ(CA_STATUS_OK, CASetAutoConnectionDeviceInfo(addr));
#else
    EXPECT_EQ(CA_NOT_SUPPORTED, CASetAutoConnectionDeviceInfo(addr));
#endif
}

// CAUnsetAutoConnectionDeviceInfo TC
// check return value
TEST_F(CATests, UnsetAutoConnectionDeviceInfo)
{
    addr = (char *) ADDRESS;

#if defined(__ANDROID__) && defined(LE_ADAPTER)
    EXPECT_EQ(CA_STATUS_OK, CAUnsetAutoConnectionDeviceInfo(addr));
#else
    EXPECT_EQ(CA_NOT_SUPPORTED, CAUnsetAutoConnectionDeviceInfo(addr));
#endif
}

CAResult_t checkGetNetworkInfo()
{
    CAEndpoint_t *tempInfo = NULL;
    uint32_t tempSize = 0;

    CAResult_t res = CAGetNetworkInformation(&tempInfo, &tempSize);

    free(tempInfo);

    if (CA_STATUS_OK == res || CA_ADAPTER_NOT_ENABLED == res ||
            CA_NOT_SUPPORTED == res)
    {
        return CA_STATUS_OK;
    }
    else
    {
        return CA_STATUS_FAILED;
    }
}
<commit_msg>Updated unit test case for CASetNetworkMonitorCallbacks<commit_after>/* ****************************************************************
 *
 * Copyright 2014 Samsung Electronics All Rights Reserved.
 *
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************/

#include "gtest/gtest.h"
#include "cainterface.h"
#include "cautilinterface.h"
#include "cacommon.h"

#define CA_TRANSPORT_ADAPTER_SCOPE  1000

class CATests : public testing::Test {
    protected:
    virtual void SetUp() {
        CAInitialize();
    }

    virtual void TearDown()
    {
        CATerminate();
    }
};

void request_handler(CAEndpoint_t* object, CARequestInfo_t* requestInfo);
void response_handler(CAEndpoint_t* object, CAResponseInfo_t* responseInfo);
void error_handler(const CAEndpoint_t *object, const CAErrorInfo_t* errorInfo);
void adapter_handler(CATransportAdapter_t adapter, bool enabled);
void connection_handler(CATransportAdapter_t adapter, const char *remote_address, bool connected);
CAResult_t checkGetNetworkInfo();
CAResult_t checkSelectNetwork();

void request_handler(const CAEndpoint_t * /*object*/,
                     const CARequestInfo_t * /*requestInfo*/)
{

}

void response_handler(const CAEndpoint_t * /*object*/,
                      const CAResponseInfo_t * /*responseInfo*/)
{

}

void error_handler(const CAEndpoint_t *object, const CAErrorInfo_t* errorInfo)
{
    if(!object || !errorInfo)
    {
        return;
    }

    //error handling shall be added
    return;
}

void adapter_handler(CATransportAdapter_t /*adapter*/,
                     bool /*enabled*/)
{
}

void connection_handler(CATransportAdapter_t /*adapter*/,
                        const char * /*remote_address*/,
                        bool /*connected*/)
{
}

static char* addr = NULL;
static CAEndpoint_t* tempRep = NULL;
static CARequestInfo_t requestInfo;
static CAInfo_t requestData;
static CAInfo_t responseData;
static CAResponseInfo_t responseInfo;
static CAToken_t tempToken = NULL;
static uint8_t tokenLength = CA_MAX_TOKEN_LEN;
static const char ADDRESS[] = "10.11.12.13";
static const uint16_t PORT = 4545;

static const char NORMAL_INFO_DATA[] =
                                    "{\"oc\":[{\"href\":\"%s\",\"prop\":{\"rt\":[\"core.led\"],"
                                     "\"if\":[\"oc.mi.def\"],\"obs\":1}}]}";

#ifdef __WITH_DTLS__

// Iotivity Device Identity.
const unsigned char IDENTITY[] = ("1111111111111111");

// PSK between this device and peer device.
const unsigned char RS_CLIENT_PSK[] = ("AAAAAAAAAAAAAAAA");

// Internal API. Invoked by CA stack to retrieve credentials from this module
int32_t CAGetDtlsPskCredentials( CADtlsPskCredType_t type,
              const unsigned char *desc, size_t desc_len,
              unsigned char *result, size_t result_length)
{
    printf("CAGetDtlsPskCredentials IN\n");

    int32_t ret = -1;

    if (NULL == result)
    {
        return ret;
    }

    switch (type)
    {
        case CA_DTLS_PSK_HINT:
        case CA_DTLS_PSK_IDENTITY:

            if (result_length < sizeof(IDENTITY))
            {
                printf("ERROR : Wrong value for result for storing IDENTITY");
                return ret;
            }

            memcpy(result, IDENTITY, sizeof(IDENTITY));
            ret = sizeof(IDENTITY);
            break;

        case CA_DTLS_PSK_KEY:

            if ((desc_len == sizeof(IDENTITY)) &&
                memcmp(desc, IDENTITY, sizeof(IDENTITY)) == 0)
            {
                if (result_length < sizeof(RS_CLIENT_PSK))
                {
                    printf("ERROR : Wrong value for result for storing RS_CLIENT_PSK");
                    return ret;
                }

                memcpy(result, RS_CLIENT_PSK, sizeof(RS_CLIENT_PSK));
                ret = sizeof(RS_CLIENT_PSK);
            }
            break;

        default:

            printf("Wrong value passed for PSK_CRED_TYPE.");
            ret = -1;
    }

    printf("CAGetDtlsPskCredentials OUT\n");
    return ret;
}
#endif  //__WITH_DTLS__

int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

// CAInitialize TC
// check return value
TEST(InitializeTest, TC_01_Positive_01)
{
    EXPECT_EQ(CA_STATUS_OK, CAInitialize());
    CATerminate();
}

//CATerminate TC
TEST_F(CATests, TerminateTest)
{
    CATerminate();

    char* check = (char *) "terminate success";
    EXPECT_STREQ(check, "terminate success");

    CAInitialize();
}
// CAStartListeningServer TC
// check return value
TEST(StartListeningServerTest, DISABLED_TC_03_Positive_01)
{
    CASelectNetwork(CA_ADAPTER_IP);
    EXPECT_EQ(CA_STATUS_OK, CAStartListeningServer());
}

// CAStartDiscoveryServer TC
// check return value
TEST(StartDiscoveryServerTest, DISABLED_TC_04_Positive_01)
{
    EXPECT_EQ(CA_STATUS_OK, CAStartDiscoveryServer());
}

// CARegisterHandlerTest TC
// check return value
TEST_F(CATests, RegisterHandlerTest)
{
    CARegisterHandler(request_handler, response_handler, error_handler);
    char* check = (char *) "registerHandler success";
    EXPECT_STREQ(check, "registerHandler success");
}

// CACreateRemoteEndpoint TC
// check return value
TEST_F(CATests, CreateRemoteEndpointTestGood)
{
    addr = (char *) ADDRESS;

    EXPECT_EQ(CA_STATUS_OK, CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr,
                                             PORT, &tempRep));

    CADestroyEndpoint(tempRep);
    tempRep = NULL;
}

// check remoteEndpoint and values of remoteEndpoint
TEST_F(CATests, CreateRemoteEndpointTestValues)
{
    addr = (char *) ADDRESS;

    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr, PORT, &tempRep);

    EXPECT_TRUE(tempRep != NULL);

    CADestroyEndpoint(tempRep);
    tempRep = NULL;
}

// CAGerateToken TC
// check return value
TEST_F(CATests, GenerateTokenTestGood)
{
    EXPECT_EQ(CA_STATUS_OK, CAGenerateToken(&tempToken, tokenLength));

    CADestroyToken(tempToken);
}

// check return value when CAGenerateToken is passed a NULL instead a valid pointer
TEST_F(CATests, GenerateTokenTestBad)
{
    EXPECT_EQ(CA_STATUS_INVALID_PARAM, CAGenerateToken(NULL, tokenLength));
}

// CADestroyToken TC
// check destroyed token
TEST_F(CATests, DestroyTokenTest)
{
    CAGenerateToken(&tempToken, tokenLength);
    CADestroyToken(tempToken);

    char * check = (char *) "destroy success";
    EXPECT_STREQ(check, "destroy success");
}

// CASendRequest TC
// check return value
TEST(SendRequestTest, DISABLED_TC_16_Positive_01)
{
    addr = (char *) ADDRESS;
    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr, PORT, &tempRep);

    memset(&requestData, 0, sizeof(CAInfo_t));
    CAGenerateToken(&tempToken, tokenLength);
    requestData.token = tempToken;
    requestData.tokenLength = tokenLength;

    int length = strlen(NORMAL_INFO_DATA) + strlen("a/light");
    requestData.payload = (CAPayload_t) calloc(length, sizeof(char));
    if(!requestData.payload)
    {
        CADestroyToken(tempToken);
        FAIL() << "requestData.payload allocation failed";
    }
    snprintf((char*)requestData.payload, length, NORMAL_INFO_DATA, "a/light");
    requestData.payloadSize = length + 1;
    requestData.type = CA_MSG_NONCONFIRM;

    memset(&requestInfo, 0, sizeof(CARequestInfo_t));
    requestInfo.method = CA_GET;
    requestInfo.info = requestData;

    EXPECT_EQ(CA_STATUS_OK, CASendRequest(tempRep, &requestInfo));

    CADestroyToken(tempToken);
    CADestroyEndpoint(tempRep);
    free(requestData.payload);
    tempRep = NULL;
}

// check return value when a NULL is passed instead of a valid CARequestInfo_t address
TEST_F(CATests, SendRequestTestWithNullAddr)
{
    addr = (char *) ADDRESS;
    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr, PORT, &tempRep);

    EXPECT_EQ(CA_STATUS_INVALID_PARAM, CASendRequest(tempRep, NULL));

    CADestroyEndpoint(tempRep);
    tempRep = NULL;
}

// CASendResponse TC
// check return value
TEST(SendResponseTest, DISABLED_TC_19_Positive_01)
{
    addr = (char *) ADDRESS;
    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr, PORT, &tempRep);

    memset(&responseData, 0, sizeof(CAInfo_t));
    responseData.type = CA_MSG_NONCONFIRM;
    responseData.messageId = 1;
    responseData.payload = (CAPayload_t)malloc(sizeof("response payload"));

    EXPECT_TRUE(responseData.payload != NULL);
    if(!responseData.payload)
    {
        CADestroyEndpoint(tempRep);
        return;
    }

    memcpy(responseData.payload, "response payload", sizeof("response payload"));
    responseData.payloadSize = sizeof("response payload");

    CAGenerateToken(&tempToken, tokenLength);
    requestData.token = tempToken;
    requestData.tokenLength = tokenLength;

    memset(&responseInfo, 0, sizeof(CAResponseInfo_t));
    responseInfo.result = CA_CONTENT;
    responseInfo.info = responseData;

    EXPECT_EQ(CA_STATUS_OK, CASendResponse(tempRep, &responseInfo));

    CADestroyToken(tempToken);
    CADestroyEndpoint(tempRep);
    free(responseData.payload);
    tempRep = NULL;
}

// check return value when address is NULL as multicast
TEST(SendResponseTest, DISABLED_TC_20_Negative_01)
{
    addr = NULL;
    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr, 0, &tempRep);

    memset(&responseData, 0, sizeof(CAInfo_t));
    responseData.type = CA_MSG_NONCONFIRM;
    responseData.messageId = 1;
    responseData.payload = (CAPayload_t)malloc(sizeof("response payload"));
    EXPECT_TRUE(responseData.payload != NULL);

    if(!responseData.payload)
    {
        CADestroyEndpoint(tempRep);
        return;
    }

    memcpy(responseData.payload, "response payload", sizeof("response payload"));
    responseData.payloadSize = sizeof("response payload");

    CAGenerateToken(&tempToken, tokenLength);
    requestData.token = tempToken;
    requestData.tokenLength = tokenLength;

    memset(&responseInfo, 0, sizeof(CAResponseInfo_t));
    responseInfo.result = CA_CONTENT;
    responseInfo.info = responseData;

    EXPECT_EQ(CA_STATUS_OK, CASendResponse(tempRep, &responseInfo));

    CADestroyToken(tempToken);
    CADestroyEndpoint(tempRep);
    free (responseData.payload);
    tempRep = NULL;
}

// check return value NULL is passed instead of a valid CAResponseInfo_t address
TEST_F(CATests, SendResponseTest)
{
    addr = (char *) ADDRESS;
    CACreateEndpoint(CA_DEFAULT_FLAGS, CA_ADAPTER_IP, addr, PORT, &tempRep);

    EXPECT_EQ(CA_STATUS_INVALID_PARAM, CASendResponse(tempRep, NULL));

    CADestroyEndpoint(tempRep);
    tempRep = NULL;
}

// CASelectNewwork TC
// check return value
TEST_F(CATests, SelectNetworkTestGood)
{
    EXPECT_EQ(CA_STATUS_OK, checkSelectNetwork());
}

CAResult_t checkSelectNetwork()
{
    CAResult_t res = CASelectNetwork(CA_ADAPTER_IP);

    if (CA_STATUS_OK == res)
    {
        EXPECT_EQ(CA_STATUS_OK, CAUnSelectNetwork(CA_ADAPTER_IP));
        return CA_STATUS_OK;
    }
    if (CA_NOT_SUPPORTED == res)
    {
        EXPECT_EQ(CA_STATUS_FAILED, CAUnSelectNetwork(CA_ADAPTER_IP));
        return CA_STATUS_OK;
    }

    return res;
}

// check return value when selected network is disable
TEST_F(CATests, SelectNetworkTestBad)
{
    //Select disable network
    EXPECT_EQ(CA_NOT_SUPPORTED, CASelectNetwork((CATransportAdapter_t)
                                                CA_TRANSPORT_ADAPTER_SCOPE));
}

// check return value when selected network is disable
TEST_F(CATests, UnSelectNetworkTest)
{
    //UnSelect disable network
    EXPECT_EQ(CA_STATUS_FAILED, CAUnSelectNetwork((CATransportAdapter_t)
                                                  CA_TRANSPORT_ADAPTER_SCOPE));
}

// CAHandlerRequestResponse TC
// check return value
TEST_F(CATests, HandlerRequestResponseTest)
{
    EXPECT_EQ(CA_STATUS_OK, CAHandleRequestResponse());
}

// CAGetNetworkInformation TC
// check return value
TEST_F (CATests, GetNetworkInformationTestGood)
{
    EXPECT_EQ(CA_STATUS_OK, checkGetNetworkInfo());
}

TEST_F(CATests, RegisterDTLSCredentialsHandlerTest)
{
#ifdef __WITH_DTLS__
    EXPECT_EQ(CA_STATUS_OK, CARegisterDTLSCredentialsHandler(CAGetDtlsPskCredentials));
#endif
}

// CARegisterNetworkMonitorHandler TC
// check return value
TEST_F(CATests, RegisterNetworkMonitorHandler)
{
    EXPECT_EQ(CA_STATUS_OK, CARegisterNetworkMonitorHandler(adapter_handler,
                                                            connection_handler));
}

// CASetAutoConnectionDeviceInfo TC
// check return value
TEST_F(CATests, SetAutoConnectionDeviceInfo)
{
    addr = (char *) ADDRESS;

#if defined(__ANDROID__) && defined(LE_ADAPTER)
    EXPECT_EQ(CA_STATUS_OK, CASetAutoConnectionDeviceInfo(addr));
#else
    EXPECT_EQ(CA_NOT_SUPPORTED, CASetAutoConnectionDeviceInfo(addr));
#endif
}

// CAUnsetAutoConnectionDeviceInfo TC
// check return value
TEST_F(CATests, UnsetAutoConnectionDeviceInfo)
{
    addr = (char *) ADDRESS;

#if defined(__ANDROID__) && defined(LE_ADAPTER)
    EXPECT_EQ(CA_STATUS_OK, CAUnsetAutoConnectionDeviceInfo(addr));
#else
    EXPECT_EQ(CA_NOT_SUPPORTED, CAUnsetAutoConnectionDeviceInfo(addr));
#endif
}

CAResult_t checkGetNetworkInfo()
{
    CAEndpoint_t *tempInfo = NULL;
    uint32_t tempSize = 0;

    CAResult_t res = CAGetNetworkInformation(&tempInfo, &tempSize);

    free(tempInfo);

    if (CA_STATUS_OK == res || CA_ADAPTER_NOT_ENABLED == res ||
            CA_NOT_SUPPORTED == res)
    {
        return CA_STATUS_OK;
    }
    else
    {
        return CA_STATUS_FAILED;
    }
}
<|endoftext|>