<commit_before>#include "hider.h"
#include "misc.h"

static HIDE_ENTRY* HideEntries=0;
static int TotalHideEntries=0;

//simple locking library
static bool locked=false;

static void lock()
{
    while(locked);
    locked=true;
}

static void unlock()
{
    locked=false;
}

//entry management
static void EntryAdd(HIDE_ENTRY* NewEntry)
{
    lock();
    int NewTotalHideEntries=TotalHideEntries+1;
    HIDE_ENTRY* NewHideEntries=(HIDE_ENTRY*)RtlAllocateMemory(true, NewTotalHideEntries*sizeof(HIDE_ENTRY));
    if(!NewHideEntries)
    {
        unlock();
        return;
    }
    RtlCopyMemory(&NewHideEntries[0], &HideEntries[0], TotalHideEntries*sizeof(HIDE_ENTRY));
    RtlCopyMemory(&NewHideEntries[TotalHideEntries], &NewEntry[0], sizeof(HIDE_ENTRY));
    if(HideEntries)
        RtlFreeMemory(HideEntries);
    HideEntries=NewHideEntries;
    TotalHideEntries=NewTotalHideEntries;
    unlock();
}

static void EntryClear()
{
    lock();
    TotalHideEntries=0;
    if(HideEntries)
        RtlFreeMemory(HideEntries);
    HideEntries=0;
    unlock();
}

static void EntryDel(int EntryIndex)
{
    lock();
    if(EntryIndex<TotalHideEntries && HideEntries)
    {
        int NewTotalHideEntries=TotalHideEntries-1;
        if(!NewTotalHideEntries) //nothing left
        {
            unlock();
            EntryClear();
            return;
        }
        HIDE_ENTRY* NewHideEntries=(HIDE_ENTRY*)RtlAllocateMemory(true, NewTotalHideEntries*sizeof(HIDE_ENTRY));
        if(!NewHideEntries)
        {
            unlock();
            return;
        }
        if(!EntryIndex)
            RtlCopyMemory(&NewHideEntries[0], &HideEntries[1], NewTotalHideEntries*sizeof(HIDE_ENTRY));
        else
        {
            RtlCopyMemory(&NewHideEntries[0], &HideEntries[0], EntryIndex*sizeof(HIDE_ENTRY));
            RtlCopyMemory(&NewHideEntries[EntryIndex], &HideEntries[EntryIndex+1], (NewTotalHideEntries-EntryIndex)*sizeof(HIDE_ENTRY));
        }
        RtlCopyMemory(NewHideEntries, HideEntries, TotalHideEntries*sizeof(HIDE_ENTRY));
        RtlFreeMemory(HideEntries);
        HideEntries=NewHideEntries;
        TotalHideEntries=NewTotalHideEntries;
    }
    unlock();
}

static int EntryFind(ULONG Pid)
{
    lock();
    if(!HideEntries)
    {
        unlock();
        return -1;
    }
    for(int i=0; i<TotalHideEntries; i++)
    {
        if(HideEntries[i].Pid==Pid)
        {
            unlock();
            return i;
        }
    }
    unlock();
    return -1;
}

static ULONG EntryGet(int EntryIndex)
{
    lock();
    ULONG Type=0;
    if(EntryIndex<TotalHideEntries && HideEntries)
    {
        Type=HideEntries[EntryIndex].Type;
    }
    unlock();
    return Type;
}

static void EntrySet(int EntryIndex, ULONG Type)
{
    lock();
    if(EntryIndex<TotalHideEntries && HideEntries)
    {
        HideEntries[EntryIndex].Type|=Type;
    }
    unlock();
}

static void EntryUnset(int EntryIndex, ULONG Type)
{
    lock();
    if(EntryIndex<TotalHideEntries && HideEntries)
    {
        HideEntries[EntryIndex].Type&=~Type;
    }
    unlock();
}

//usable functions
bool HiderProcessData(PVOID Buffer, ULONG Size)
{
    if(Size%sizeof(HIDE_INFO))
        return false;
    int HideInfoCount=Size/sizeof(HIDE_INFO);
    HIDE_INFO* HideInfo=(HIDE_INFO*)Buffer;
    for(int i=0; i<HideInfoCount; i++)
    {
        switch(HideInfo[i].Command)
        {
        case HidePid:
        {
            int FoundEntry=EntryFind(HideInfo[i].Pid);
            if(FoundEntry==-1)
            {
                HIDE_ENTRY HideEntry;
                HideEntry.Pid=HideInfo[i].Pid;
                HideEntry.Type=HideInfo[i].Type;
                EntryAdd(&HideEntry);
            }
            else
            {
                EntrySet(FoundEntry, HideInfo[i].Type);
            }
        }
        break;

        case UnhidePid:
        {
            int FoundEntry=EntryFind(HideInfo[i].Pid);
            if(FoundEntry!=-1)
            {
                EntryUnset(FoundEntry, HideInfo[i].Type);
                if(!EntryGet(FoundEntry)) //nothing left to hide for PID
                    EntryDel(FoundEntry);
            }
        }
        break;

        case UnhideAll:
        {
            EntryClear();
        }
        break;
        }
    }
    return true;
}

bool HiderIsHidden(ULONG Pid, HIDE_TYPE Type)
{
    int FoundEntry=EntryFind(Pid);
    if(FoundEntry==-1)
        return false;
    ULONG uType=(ULONG)Type;
    if((EntryGet(FoundEntry)&uType)==uType)
        return true;
    return false;
}<commit_msg>- fixed a deadlock (thanks to mcp!)<commit_after>#include "hider.h"
#include "misc.h"

static HIDE_ENTRY* HideEntries=0;
static int TotalHideEntries=0;

//simple locking library
static volatile bool locked=false;

static void lock()
{
    while(locked);
    locked=true;
}

static void unlock()
{
    locked=false;
}

//entry management
static void EntryAdd(HIDE_ENTRY* NewEntry)
{
    lock();
    int NewTotalHideEntries=TotalHideEntries+1;
    HIDE_ENTRY* NewHideEntries=(HIDE_ENTRY*)RtlAllocateMemory(true, NewTotalHideEntries*sizeof(HIDE_ENTRY));
    if(!NewHideEntries)
    {
        unlock();
        return;
    }
    RtlCopyMemory(&NewHideEntries[0], &HideEntries[0], TotalHideEntries*sizeof(HIDE_ENTRY));
    RtlCopyMemory(&NewHideEntries[TotalHideEntries], &NewEntry[0], sizeof(HIDE_ENTRY));
    if(HideEntries)
        RtlFreeMemory(HideEntries);
    HideEntries=NewHideEntries;
    TotalHideEntries=NewTotalHideEntries;
    unlock();
}

static void EntryClear()
{
    lock();
    TotalHideEntries=0;
    if(HideEntries)
        RtlFreeMemory(HideEntries);
    HideEntries=0;
    unlock();
}

static void EntryDel(int EntryIndex)
{
    lock();
    if(EntryIndex<TotalHideEntries && HideEntries)
    {
        int NewTotalHideEntries=TotalHideEntries-1;
        if(!NewTotalHideEntries) //nothing left
        {
            unlock();
            EntryClear();
            return;
        }
        HIDE_ENTRY* NewHideEntries=(HIDE_ENTRY*)RtlAllocateMemory(true, NewTotalHideEntries*sizeof(HIDE_ENTRY));
        if(!NewHideEntries)
        {
            unlock();
            return;
        }
        if(!EntryIndex)
            RtlCopyMemory(&NewHideEntries[0], &HideEntries[1], NewTotalHideEntries*sizeof(HIDE_ENTRY));
        else
        {
            RtlCopyMemory(&NewHideEntries[0], &HideEntries[0], EntryIndex*sizeof(HIDE_ENTRY));
            RtlCopyMemory(&NewHideEntries[EntryIndex], &HideEntries[EntryIndex+1], (NewTotalHideEntries-EntryIndex)*sizeof(HIDE_ENTRY));
        }
        RtlCopyMemory(NewHideEntries, HideEntries, TotalHideEntries*sizeof(HIDE_ENTRY));
        RtlFreeMemory(HideEntries);
        HideEntries=NewHideEntries;
        TotalHideEntries=NewTotalHideEntries;
    }
    unlock();
}

static int EntryFind(ULONG Pid)
{
    lock();
    if(!HideEntries)
    {
        unlock();
        return -1;
    }
    for(int i=0; i<TotalHideEntries; i++)
    {
        if(HideEntries[i].Pid==Pid)
        {
            unlock();
            return i;
        }
    }
    unlock();
    return -1;
}

static ULONG EntryGet(int EntryIndex)
{
    lock();
    ULONG Type=0;
    if(EntryIndex<TotalHideEntries && HideEntries)
    {
        Type=HideEntries[EntryIndex].Type;
    }
    unlock();
    return Type;
}

static void EntrySet(int EntryIndex, ULONG Type)
{
    lock();
    if(EntryIndex<TotalHideEntries && HideEntries)
    {
        HideEntries[EntryIndex].Type|=Type;
    }
    unlock();
}

static void EntryUnset(int EntryIndex, ULONG Type)
{
    lock();
    if(EntryIndex<TotalHideEntries && HideEntries)
    {
        HideEntries[EntryIndex].Type&=~Type;
    }
    unlock();
}

//usable functions
bool HiderProcessData(PVOID Buffer, ULONG Size)
{
    if(Size%sizeof(HIDE_INFO))
        return false;
    int HideInfoCount=Size/sizeof(HIDE_INFO);
    HIDE_INFO* HideInfo=(HIDE_INFO*)Buffer;
    for(int i=0; i<HideInfoCount; i++)
    {
        switch(HideInfo[i].Command)
        {
        case HidePid:
        {
            int FoundEntry=EntryFind(HideInfo[i].Pid);
            if(FoundEntry==-1)
            {
                HIDE_ENTRY HideEntry;
                HideEntry.Pid=HideInfo[i].Pid;
                HideEntry.Type=HideInfo[i].Type;
                EntryAdd(&HideEntry);
            }
            else
            {
                EntrySet(FoundEntry, HideInfo[i].Type);
            }
        }
        break;

        case UnhidePid:
        {
            int FoundEntry=EntryFind(HideInfo[i].Pid);
            if(FoundEntry!=-1)
            {
                EntryUnset(FoundEntry, HideInfo[i].Type);
                if(!EntryGet(FoundEntry)) //nothing left to hide for PID
                    EntryDel(FoundEntry);
            }
        }
        break;

        case UnhideAll:
        {
            EntryClear();
        }
        break;
        }
    }
    return true;
}

bool HiderIsHidden(ULONG Pid, HIDE_TYPE Type)
{
    int FoundEntry=EntryFind(Pid);
    if(FoundEntry==-1)
        return false;
    ULONG uType=(ULONG)Type;
    if((EntryGet(FoundEntry)&uType)==uType)
        return true;
    return false;
}<|endoftext|>


<commit_before>#include <Game.h>

Game& Game::getGame(const std::string& _name) {
    static Game* instance = new Game(_name);
    INFO("Getting Game instance");
    return *instance;
}

Game::Game(const std::string& _name) {
    INFO("Initializing new Game: %s", _name.c_str());
    config.name = _name;

    std::string iniFilename = config.name;
    iniFilename.append(".ini");

    INIReader reader(iniFilename);
    INFO("Reading config from '%s'", iniFilename.c_str());
    if (reader.ParseError() < 0) {
        ERR("Can't load '%s', using defaults", iniFilename.c_str());
    } else {
        // 1200x675 is a 16:9 window that fits inside a 1366x768 screen on most systems
        config.width = (unsigned int) std::abs(reader.GetInteger("game", "width", config.width));
        config.height = (unsigned int) std::abs(reader.GetInteger("game", "height", config.height));
        config.fullscreen = reader.GetBoolean("game", "fullscreen", config.fullscreen);
        config.useDesktopSize = reader.GetBoolean("game", "useDesktopSize", config.useDesktopSize);
        config.deadZone = static_cast<float>(reader.GetReal("game", "deadZone", config.deadZone));
        config.keySpeed = static_cast<float>(reader.GetReal("game", "keySpeed", config.keySpeed));
    }
    INFO("--Config--");
    INFO("width = %d", config.width);
    INFO("height = %d", config.height);
    INFO("fullscreen = %s", (config.fullscreen ? "true" : "false"));
    INFO("useDesktopSize = %s", (config.useDesktopSize ? "true" : "false"));
    INFO("deadZone = %f", config.deadZone);
    INFO("keySpeed = %f", config.keySpeed);
    INFO("--End config--");

    INFO("Creating %dx%d render target", renderWidth, renderHeight);
    screen.create(renderWidth, renderHeight);

    createWindow(config.fullscreen);

    player = new GamePlayer;
    player->setPosition(renderWidth * 1 / 2, renderHeight * 3 / 4);
    sprites.push_back(player);
    INFO("Loaded player");

    isReady = true;
    INFO("Initialized");
}

bool Game::ready() {
    return isReady;
}

void Game::createWindow(bool shouldFullscreen) {
    unsigned int flags = 0;
    sf::VideoMode mode;
    config.fullscreen = shouldFullscreen;
    if (config.fullscreen) {
        INFO("Going fullscreen");
        window.setMouseCursorVisible(false);
        if (config.useDesktopSize) {
            INFO("Setting fullscreen mode (using desktop size): %dx%d",
                 sf::VideoMode::getDesktopMode().width,
                 sf::VideoMode::getDesktopMode().height);
            mode = sf::VideoMode::getDesktopMode();
        } else {
            INFO("Setting fullscreen mode: %dx%d", config.width, config.height);
            mode = sf::VideoMode(config.width, config.height);
        }
        flags = sf::Style::Fullscreen;
    } else {
        INFO("Setting windowed mode: %dx%d", config.width, config.height);
        window.setMouseCursorVisible(true);
        mode = sf::VideoMode(config.width, config.height);
        flags = sf::Style::Titlebar | sf::Style::Close | sf::Style::Resize;
    }
    window.create(mode, config.name, flags);
    if (!window.isOpen()) {
        ERR("Could not create main window");
        exit(EXIT_FAILURE);
    }
    sf::ContextSettings settings = window.getSettings();
    INFO("Using OpenGL %d.%d", settings.majorVersion, settings.minorVersion);

    // initialize the view
    view = window.getDefaultView();
    view.setSize(renderWidth, renderHeight);
    view.setCenter(renderWidth / 2, renderHeight / 2);
    window.setView(view);
    INFO("Enabling V-sync");
    window.setVerticalSyncEnabled(true);
    // scale the viewport to maintain good aspect
    adjustAspect(window.getSize());
}

void Game::adjustAspect(sf::Event::SizeEvent newSize) {
    // save the new window size since this came from a resize event
    // not from initialization or a fullscreen toggle
    config.width = newSize.width;
    config.height = newSize.height;
    // do the calculation
    adjustAspect(sf::Vector2u(newSize.width, newSize.height));
}

void Game::adjustAspect(sf::Vector2u newSize) {
    // compute the current aspect
    float currentRatio = (float) newSize.x / (float) newSize.y;
    // used to offset and scale the viewport to maintain 16:9 aspect
    float widthScale = 1.0f;
    float widthOffset = 0.0f;
    float heightScale = 1.0f;
    float heightOffset = 0.0f;
    // used to compare and compute aspect ratios
    // for logging
    std::string isSixteenNine = "16:9";
    if (currentRatio > 16.0f / 9.0f) {
        // we are wider
        isSixteenNine = "wide";
        widthScale = newSize.y * (16.0f / 9.0f) / newSize.x;
        widthOffset = (1.0f - widthScale) / 2.0f;
    } else if (currentRatio < 16.0f / 9.0f) {
        // we are narrower
        isSixteenNine = "narrow";
        heightScale = newSize.x * (9.0f / 16.0f) / newSize.y;
        heightOffset = (1.0f - heightScale) / 2.0f;
    }
    INFO("Adjusting aspect for window size ", newSize.x, newSize.y);
    INFO("Setting %s viewport (wo:%f, ho:%f; ws:%f, hs: %f", isSixteenNine.c_str(),
         widthOffset, heightOffset, widthScale, heightScale);
    view.setViewport(sf::FloatRect(widthOffset, heightOffset, widthScale, heightScale));
    window.setView(view);
}

void Game::processEvents() {
    static sf::Event event;

    while (window.pollEvent(event)) {
        switch (event.type) {
            case sf::Event::Closed:
                INFO("Window closed");
                window.close();
                break;
            case sf::Event::Resized:
                adjustAspect(event.size);
                break;
            case sf::Event::KeyPressed:
                handleKeyPress(event);
                break;
            case sf::Event::KeyReleased:
                handleKeyRelease(event);
                break;
            default:
                break;
        }
    }
}

void Game::handleKeyPress(const sf::Event& event) {
    switch (event.key.code) {
        case sf::Keyboard::Escape:
            INFO("GamePlayer exited");
            window.close();
            break;
        case sf::Keyboard::Return:
            if (event.key.alt) {
                createWindow(!config.fullscreen);
            }
            break;
        default:
            break;
    }
}

void Game::handleKeyRelease(const sf::Event& event) const {
    switch (event.key.code) {
        default:
            break;
    }
}

void Game::updateControls() {
    float x, y = 0;

    float joy0_X = sf::Joystick::getAxisPosition(0, sf::Joystick::X);
    float joy0_y = sf::Joystick::getAxisPosition(0, sf::Joystick::Y);
    x = fabs(joy0_X) < config.deadZone ? 0 : joy0_X;
    y = fabs(joy0_y) < config.deadZone ? 0 : joy0_y;

    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
        y += -config.keySpeed;
    }
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
        x += config.keySpeed;
    }
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
        y += config.keySpeed;
    }
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
        x += -config.keySpeed;
    }
    player->moveBy(x, y);
}

void Game::updateWorld(sf::Time elapsed) {
    const int millis = elapsed.asMilliseconds();
    for (auto sprite : sprites) {
        sprite->update(millis);
    }
}

void Game::renderWorld() {
    // blank the window to gray
    window.clear(sf::Color(128, 128, 128));
    // blank the render target
    screen.clear(sf::Color::Black);
    // render all the normal sprites
    for (const auto sprite : sprites) {
        screen.draw(*sprite);
    }
    // show everything rendered so far
    screen.display();
    // copy render target to window
    window.draw(sf::Sprite(screen.getTexture()));
    // display everything
    window.display();
}

void Game::run(void) {
    sf::Clock gameClock;
    sf::Time elapsed;
    INFO("Starting %s", config.name.c_str());
    while (window.isOpen()) {
        elapsed = gameClock.restart();
        processEvents();
        updateControls();
        updateWorld(elapsed);
        renderWorld();
    }
    INFO("Stopped");
}
<commit_msg>Cast config defaults to avoid warnings<commit_after>#include <Game.h>

Game& Game::getGame(const std::string& _name) {
    static Game* instance = new Game(_name);
    INFO("Getting Game instance");
    return *instance;
}

Game::Game(const std::string& _name) {
    INFO("Initializing new Game: %s", _name.c_str());
    config.name = _name;

    std::string iniFilename = config.name;
    iniFilename.append(".ini");

    INIReader reader(iniFilename);
    INFO("Reading config from '%s'", iniFilename.c_str());
    if (reader.ParseError() < 0) {
        ERR("Can't load '%s', using defaults", iniFilename.c_str());
    } else {
        // 1200x675 is a 16:9 window that fits inside a 1366x768 screen on most systems
        config.width = (unsigned int) std::abs(reader.GetInteger("game", "width", (long) config.width));
        config.height = (unsigned int) std::abs(reader.GetInteger("game", "height", (long) config.height));
        config.fullscreen = reader.GetBoolean("game", "fullscreen", config.fullscreen);
        config.useDesktopSize = reader.GetBoolean("game", "useDesktopSize", config.useDesktopSize);
        config.deadZone = static_cast<float>(reader.GetReal("game", "deadZone", config.deadZone));
        config.keySpeed = static_cast<float>(reader.GetReal("game", "keySpeed", config.keySpeed));
    }
    INFO("--Config--");
    INFO("width = %d", config.width);
    INFO("height = %d", config.height);
    INFO("fullscreen = %s", (config.fullscreen ? "true" : "false"));
    INFO("useDesktopSize = %s", (config.useDesktopSize ? "true" : "false"));
    INFO("deadZone = %f", config.deadZone);
    INFO("keySpeed = %f", config.keySpeed);
    INFO("--End config--");

    INFO("Creating %dx%d render target", renderWidth, renderHeight);
    screen.create(renderWidth, renderHeight);

    createWindow(config.fullscreen);

    player = new GamePlayer;
    player->setPosition(renderWidth * 1 / 2, renderHeight * 3 / 4);
    sprites.push_back(player);
    INFO("Loaded player");

    isReady = true;
    INFO("Initialized");
}

bool Game::ready() {
    return isReady;
}

void Game::createWindow(bool shouldFullscreen) {
    unsigned int flags = 0;
    sf::VideoMode mode;
    config.fullscreen = shouldFullscreen;
    if (config.fullscreen) {
        INFO("Going fullscreen");
        window.setMouseCursorVisible(false);
        if (config.useDesktopSize) {
            INFO("Setting fullscreen mode (using desktop size): %dx%d",
                 sf::VideoMode::getDesktopMode().width,
                 sf::VideoMode::getDesktopMode().height);
            mode = sf::VideoMode::getDesktopMode();
        } else {
            INFO("Setting fullscreen mode: %dx%d", config.width, config.height);
            mode = sf::VideoMode(config.width, config.height);
        }
        flags = sf::Style::Fullscreen;
    } else {
        INFO("Setting windowed mode: %dx%d", config.width, config.height);
        window.setMouseCursorVisible(true);
        mode = sf::VideoMode(config.width, config.height);
        flags = sf::Style::Titlebar | sf::Style::Close | sf::Style::Resize;
    }
    window.create(mode, config.name, flags);
    if (!window.isOpen()) {
        ERR("Could not create main window");
        exit(EXIT_FAILURE);
    }
    sf::ContextSettings settings = window.getSettings();
    INFO("Using OpenGL %d.%d", settings.majorVersion, settings.minorVersion);

    // initialize the view
    view = window.getDefaultView();
    view.setSize(renderWidth, renderHeight);
    view.setCenter(renderWidth / 2, renderHeight / 2);
    window.setView(view);
    INFO("Enabling V-sync");
    window.setVerticalSyncEnabled(true);
    // scale the viewport to maintain good aspect
    adjustAspect(window.getSize());
}

void Game::adjustAspect(sf::Event::SizeEvent newSize) {
    // save the new window size since this came from a resize event
    // not from initialization or a fullscreen toggle
    config.width = newSize.width;
    config.height = newSize.height;
    // do the calculation
    adjustAspect(sf::Vector2u(newSize.width, newSize.height));
}

void Game::adjustAspect(sf::Vector2u newSize) {
    // compute the current aspect
    float currentRatio = (float) newSize.x / (float) newSize.y;
    // used to offset and scale the viewport to maintain 16:9 aspect
    float widthScale = 1.0f;
    float widthOffset = 0.0f;
    float heightScale = 1.0f;
    float heightOffset = 0.0f;
    // used to compare and compute aspect ratios
    // for logging
    std::string isSixteenNine = "16:9";
    if (currentRatio > 16.0f / 9.0f) {
        // we are wider
        isSixteenNine = "wide";
        widthScale = newSize.y * (16.0f / 9.0f) / newSize.x;
        widthOffset = (1.0f - widthScale) / 2.0f;
    } else if (currentRatio < 16.0f / 9.0f) {
        // we are narrower
        isSixteenNine = "narrow";
        heightScale = newSize.x * (9.0f / 16.0f) / newSize.y;
        heightOffset = (1.0f - heightScale) / 2.0f;
    }
    INFO("Adjusting aspect for window size ", newSize.x, newSize.y);
    INFO("Setting %s viewport (wo:%f, ho:%f; ws:%f, hs: %f", isSixteenNine.c_str(),
         widthOffset, heightOffset, widthScale, heightScale);
    view.setViewport(sf::FloatRect(widthOffset, heightOffset, widthScale, heightScale));
    window.setView(view);
}

void Game::processEvents() {
    static sf::Event event;

    while (window.pollEvent(event)) {
        switch (event.type) {
            case sf::Event::Closed:
                INFO("Window closed");
                window.close();
                break;
            case sf::Event::Resized:
                adjustAspect(event.size);
                break;
            case sf::Event::KeyPressed:
                handleKeyPress(event);
                break;
            case sf::Event::KeyReleased:
                handleKeyRelease(event);
                break;
            default:
                break;
        }
    }
}

void Game::handleKeyPress(const sf::Event& event) {
    switch (event.key.code) {
        case sf::Keyboard::Escape:
            INFO("GamePlayer exited");
            window.close();
            break;
        case sf::Keyboard::Return:
            if (event.key.alt) {
                createWindow(!config.fullscreen);
            }
            break;
        default:
            break;
    }
}

void Game::handleKeyRelease(const sf::Event& event) const {
    switch (event.key.code) {
        default:
            break;
    }
}

void Game::updateControls() {
    float x, y = 0;

    float joy0_X = sf::Joystick::getAxisPosition(0, sf::Joystick::X);
    float joy0_y = sf::Joystick::getAxisPosition(0, sf::Joystick::Y);
    x = fabs(joy0_X) < config.deadZone ? 0 : joy0_X;
    y = fabs(joy0_y) < config.deadZone ? 0 : joy0_y;

    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
        y += -config.keySpeed;
    }
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
        x += config.keySpeed;
    }
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
        y += config.keySpeed;
    }
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
        x += -config.keySpeed;
    }
    player->moveBy(x, y);
}

void Game::updateWorld(sf::Time elapsed) {
    const int millis = elapsed.asMilliseconds();
    for (auto sprite : sprites) {
        sprite->update(millis);
    }
}

void Game::renderWorld() {
    // blank the window to gray
    window.clear(sf::Color(128, 128, 128));
    // blank the render target
    screen.clear(sf::Color::Black);
    // render all the normal sprites
    for (const auto sprite : sprites) {
        screen.draw(*sprite);
    }
    // show everything rendered so far
    screen.display();
    // copy render target to window
    window.draw(sf::Sprite(screen.getTexture()));
    // display everything
    window.display();
}

void Game::run(void) {
    sf::Clock gameClock;
    sf::Time elapsed;
    INFO("Starting %s", config.name.c_str());
    while (window.isOpen()) {
        elapsed = gameClock.restart();
        processEvents();
        updateControls();
        updateWorld(elapsed);
        renderWorld();
    }
    INFO("Stopped");
}
<|endoftext|>


<commit_before>#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include <functional>
#include <unordered_map>
#include <utility>
#include <typeinfo>

#include "global.hpp"
#include "operators.hpp"
#include "tokens.hpp"
#include "nodes.hpp"
#include "builtins.hpp"

class Parser {
private:
  std::vector<Token> tokens {};
  inline void skipCharacters(unsigned int& i, int by) {i += by;}
  // If we're already at the next character, but the loop will increment i by 1
  inline void preventIncrement(unsigned int& i) {i--;}

  std::vector<std::string> typeIdentifiers {"Integer"}; // TODO: add this
  std::vector<std::string> keywords {"define", "if", "while"};
public:
  nodes::AST tree = nodes::AST();

  Parser(std::string code) {
    if (PARSER_PRINT_INPUT) print(code, "\n");
    try {
      tokenize(code);
      if (PARSER_PRINT_TOKENS) for (auto tok : tokens) print(tok, "\n");
      if (PARSER_PRINT_AS_EXPR) for (auto tok : nodes::ExpressionNode(tokens).getRPNOutput()) print(tok.data, " ");
      buildTree();
    } catch (SyntaxError &e) {
      print(e.getMessage(), "\n");
    }
  }

  void tokenize(std::string code) {
    unsigned int lines = 0;
    for (unsigned int i = 0; i < code.length(); ++i) {
      if (code[i] == '\n') lines++;

      // Ignore whitespace
      if (isspace(code[i])) continue;

      // Block begin/end
      // Parenthesis
      // Semicolons
      if (code[i] == '{' || code[i] == '}' ||
          code[i] == '(' || code[i] == ')' ||
          code[i] == ';') {
        tokens.push_back(Token(std::string(1, code[i]), CONSTRUCT, lines));
        continue;
      }

      // Operators
      auto initTokSize = tokens.size();
      std::for_each(ops::opList.begin(), ops::opList.end(), [this, initTokSize, code, i, lines](ops::Operator& op) {
        if (initTokSize < tokens.size()) return; // If there are more tokens than before for_each, the operator was already added, so return.
        if (op.getName().length() + i > code.length()) return; // If the operator is longer than the source string, ignore it.
        if (op.getName() == code.substr(i, op.getName().length())) {
          ops::Operator* tmp = &op;
          // TODO: apply DRY on these ifs
          if (tmp->getName() == "++" || tmp->getName() == "--") {
            // Prefix version
            if (tokens.back().type == OPERATOR || tokens.back().type == CONSTRUCT) tmp = new ops::Operator(tmp->getName(), 12, ops::ASSOCIATE_FROM_RIGHT, ops::UNARY);
            // Postfix version
            else tmp = new ops::Operator(tmp->getName(), 13, ops::ASSOCIATE_FROM_RIGHT, ops::UNARY);
          }
          if (tmp->getName() == "+" || tmp->getName() == "-") {
            // Unary version
            if (tokens.back().type == OPERATOR || tokens.back().type == CONSTRUCT) tmp = new ops::Operator(tmp->getName(), 12, ops::ASSOCIATE_FROM_RIGHT, ops::UNARY);
            // Binary version
            else tmp = new ops::Operator(tmp->getName(), 10);
          }
          if (PARSER_PRINT_OPERATOR_TOKENS) print("Parser found Token with Operator ", *tmp, ", at address ", tmp, "\n");
          tokens.push_back(Token(tmp, OPERATOR, lines));
        }
      });

      if (initTokSize < tokens.size()) {
        skipCharacters(i, tokens.back().data.length() - 1);
        continue; // Token added, continue.
      }

      // Numbers
      if (isdigit(code[i])) {
        int base = 10;
        std::string current = "";
        if (code[i] == '0') {
          switch (code[i + 1]) {
            case 'x': base = 16; skipCharacters(i, 2); break;
            case 'b': base = 2;  skipCharacters(i, 2); break;
            case 'o': base = 8;  skipCharacters(i, 2); break;
            default: break;
          }
        }
        bool isFloat = false;
        while (isdigit(code[i]) || code[i] == '.') {
          current += code[i];
          if (code[i] == '.') {
            if (isFloat) throw SyntaxError("Malformed float, multiple decimal points: \"" + current + "\"", lines);
            isFloat = true;
          }
          skipCharacters(i, 1);
        }
        preventIncrement(i);
        if (current[current.length() - 1] == '.') throw SyntaxError("Malformed float, missing digits after decimal point: \"" + current + "\"", lines);
        if (base != 10 && isFloat) throw SyntaxError("Floating point numbers must be used with base 10 numbers: \"" + current + "\"", lines);
        Token t;
        if (isFloat) t = Token(new builtins::Float(current), FLOAT, lines);
        else t = Token(new builtins::Integer(current, base), INTEGER, lines);
        tokens.push_back(t);//TODO here go to exprnode and things then interpreter
        continue;
      }

      // String literals
      if (code[i] == '"') {
        skipCharacters(i, 1); // Skip the double quote
        std::string current = "";
        while (code[i] != '"') {
          // TODO: add escape sequences
          current += code[i];
          skipCharacters(i, 1);
        }
        // Don't call preventIncrement here so the other double quote is skipped
        tokens.push_back(Token(current, STRING, lines));
        continue;
      }

      // Others
      Token token = Token();
      while (!isspace(code[i])) {
        if (ops::isReservedChar(code[i]) || code[i] == '\0') break;
        token.data += code[i];
        skipCharacters(i, 1);
      }
      // Check if the thing is a keyword
      if (contains(token.data, keywords)) token.type = KEYWORD;
      preventIncrement(i);
      token.line = lines;
      tokens.push_back(token);
    }
  }

  void buildTree() {
    std::function<bool(Token)> isNewLine = [](Token tok) {return tok.data == ";" && tok.type == CONSTRUCT;};
    auto logicalLines = splitVector(tokens, isNewLine);
    for (auto toks : logicalLines) {
      if (toks.size() == 0) continue;
      if (toks[0].data == "define" && toks[0].type == KEYWORD) {
        toks[1].type = VARIABLE;
        nodes::DeclarationNode* decl = new nodes::DeclarationNode("define", toks[1]);
        if (toks[2].data != ";" || toks[2].type != CONSTRUCT) {
          nodes::ExpressionNode* expr = new nodes::ExpressionNode(toks);
          expr->buildSubtree();
          decl->addChild(expr);
        }
        decl->printTree(0);
        tree.addRootChild(decl);
      } else {
        nodes::ExpressionNode* expr = new nodes::ExpressionNode(toks);
        expr->buildSubtree();
        expr->printTree(0);
        tree.addRootChild(expr);
      }
    }
  }

  std::vector<Token> getTokens() {
    return tokens;
  }

};

class Interpreter {
private:
  typedef builtins::Object Object;
  nodes::AST tree;
  std::unordered_map<std::string, nodes::DeclarationNode*> variables();
public:
  Interpreter(nodes::AST tree): tree(tree) {
    interpret();
  }
private:
  void interpret() {
    nodes::ChildrenNodes nodes = tree.getRootChildren();
    for (uint64 i = 0; i < nodes.size(); ++i) {
      if (nodes[i]->getNodeType() == "ExpressionNode") {
        nodes[i]->getChildren()[0] = interpretExpression(dynamic_cast<nodes::ExpressionChildNode*>(nodes[i]->getChildren()[0]));
        print("\n\n");
        dynamic_cast<nodes::ExpressionChildNode*>(nodes[i]->getChildren()[0])->printTree(0);
      }
    }
  }

  nodes::ExpressionChildNode* interpretExpression(nodes::ExpressionChildNode* node) {
    if (node->getChildren().size() == 0) return node;
    if (node->t.type == OPERATOR) {
      ops::Operator* op = static_cast<ops::Operator*>(node->t.typeData);
      auto ch = node->getChildren();
      std::for_each(ch.begin(), ch.end(), [this](nodes::ASTNode*& n) {
        auto node = dynamic_cast<nodes::ExpressionChildNode*>(n);
        if (node->getChildren().size() != 0) n = interpretExpression(node);
      });
      if (dynamic_cast<nodes::ExpressionChildNode*>(ch.back())->t.type == INTEGER) {
        if (op->getArity() == ops::BINARY) {
          auto fun = *static_cast<builtins::Integer::BinaryOp*>(builtins::Integer::operators[*op]);
          auto result = fun(
           static_cast<builtins::Integer*>(static_cast<nodes::ExpressionChildNode*>(ch[1])->t.typeData),
           static_cast<builtins::Integer*>(static_cast<nodes::ExpressionChildNode*>(ch[0])->t.typeData)
          );
          return new nodes::ExpressionChildNode(Token(result, INTEGER, -2));
        }

      }
    }
    return nullptr;
  }

};

int main() {
  getConstants();
  Parser* a;
  switch (TEST_INPUT) {
    case 1: a = new Parser("6 >> 1"); break;
    case 2: a = new Parser("(1 + 2) * 3 / (2 << 1)"); break;
    case 3: a = new Parser("define a = \"abc123\";"); break;
    case 4: a = new Parser("define a = 132;\na+=1+123*(1 + 32/2);"); break;
    case 5: a = new Parser("1+ a*(-19-1++)==Integer.MAX_INT"); break;
    case 6: a = new Parser("define a = 1 + 2 * (76 - 123 - (43 + 12) / 5) % 10;\nInteger n = 1;"); break;
    case 7: a = new Parser("1 + 2 * 3 << 2"); break;
    case 8: a = new Parser("Test.test.abc.df23.asdasf ()"); break;
    case 9: a = new Parser("define a = 1 + 2;\nb = 2 * 3"); break;
    default: break;
  }
  Interpreter in(a->tree);

  return 0;
}
<commit_msg>Cleaned code<commit_after>#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <unordered_map>

#include "global.hpp"
#include "operators.hpp"
#include "tokens.hpp"
#include "nodes.hpp"
#include "builtins.hpp"

class Parser {
private:
  std::vector<Token> tokens {};
  inline void skipCharacters(unsigned int& i, int by) {i += by;}
  // If we're already at the next character, but the loop will increment i by 1
  inline void preventIncrement(unsigned int& i) {i--;}

  std::vector<std::string> keywords {"define", "if", "while"};
public:
  nodes::AST tree = nodes::AST();

  Parser(std::string code) {
    if (PARSER_PRINT_INPUT) print(code, "\n");
    try {
      tokenize(code);
      if (PARSER_PRINT_TOKENS) for (auto tok : tokens) print(tok, "\n");
      if (PARSER_PRINT_AS_EXPR) for (auto tok : nodes::ExpressionNode(tokens).getRPNOutput()) print(tok.data, " ");
      buildTree();
    } catch (SyntaxError &e) {
      print(e.getMessage(), "\n");
    }
  }

  void tokenize(std::string code) {
    unsigned int lines = 0;
    for (unsigned int i = 0; i < code.length(); ++i) {
      if (code[i] == '\n') lines++;

      // Ignore whitespace
      if (isspace(code[i])) continue;

      // Block begin/end
      // Parenthesis
      // Semicolons
      if (code[i] == '{' || code[i] == '}' ||
          code[i] == '(' || code[i] == ')' ||
          code[i] == ';') {
        tokens.push_back(Token(std::string(1, code[i]), CONSTRUCT, lines));
        continue;
      }

      // Operators
      auto initTokSize = tokens.size();
      std::for_each(ops::opList.begin(), ops::opList.end(), [this, initTokSize, code, i, lines](ops::Operator& op) {
        if (initTokSize < tokens.size()) return; // If there are more tokens than before for_each, the operator was already added, so return.
        if (op.getName().length() + i > code.length()) return; // If the operator is longer than the source string, ignore it.
        if (op.getName() == code.substr(i, op.getName().length())) {
          ops::Operator* tmp = &op;
          // TODO: apply DRY on these ifs
          if (tmp->getName() == "++" || tmp->getName() == "--") {
            // Prefix version
            if (tokens.back().type == OPERATOR || tokens.back().type == CONSTRUCT) tmp = new ops::Operator(tmp->getName(), 12, ops::ASSOCIATE_FROM_RIGHT, ops::UNARY);
            // Postfix version
            else tmp = new ops::Operator(tmp->getName(), 13, ops::ASSOCIATE_FROM_RIGHT, ops::UNARY);
          }
          if (tmp->getName() == "+" || tmp->getName() == "-") {
            // Unary version
            if (tokens.back().type == OPERATOR || tokens.back().type == CONSTRUCT) tmp = new ops::Operator(tmp->getName(), 12, ops::ASSOCIATE_FROM_RIGHT, ops::UNARY);
            // Binary version
            else tmp = new ops::Operator(tmp->getName(), 10);
          }
          if (PARSER_PRINT_OPERATOR_TOKENS) print("Parser found Token with Operator ", *tmp, ", at address ", tmp, "\n");
          tokens.push_back(Token(tmp, OPERATOR, lines));
        }
      });

      if (initTokSize < tokens.size()) {
        skipCharacters(i, tokens.back().data.length() - 1);
        continue; // Token added, continue.
      }

      // Numbers
      if (isdigit(code[i])) {
        int base = 10;
        std::string current = "";
        if (code[i] == '0') {
          switch (code[i + 1]) {
            case 'x': base = 16; skipCharacters(i, 2); break;
            case 'b': base = 2;  skipCharacters(i, 2); break;
            case 'o': base = 8;  skipCharacters(i, 2); break;
            default: break;
          }
        }
        bool isFloat = false;
        while (isdigit(code[i]) || code[i] == '.') {
          current += code[i];
          if (code[i] == '.') {
            if (isFloat) throw SyntaxError("Malformed float, multiple decimal points: \"" + current + "\"", lines);
            isFloat = true;
          }
          skipCharacters(i, 1);
        }
        preventIncrement(i);
        if (current[current.length() - 1] == '.') throw SyntaxError("Malformed float, missing digits after decimal point: \"" + current + "\"", lines);
        if (base != 10 && isFloat) throw SyntaxError("Floating point numbers must be used with base 10 numbers: \"" + current + "\"", lines);
        Token t;
        if (isFloat) t = Token(new builtins::Float(current), FLOAT, lines);
        else t = Token(new builtins::Integer(current, base), INTEGER, lines);
        tokens.push_back(t);
        continue;
      }

      // String literals
      if (code[i] == '"') {
        skipCharacters(i, 1); // Skip the double quote
        std::string current = "";
        while (code[i] != '"') {
          // TODO: add escape sequences
          current += code[i];
          skipCharacters(i, 1);
        }
        // Don't call preventIncrement here so the other double quote is skipped
        tokens.push_back(Token(current, STRING, lines));
        continue;
      }

      // Others
      Token token = Token();
      while (!isspace(code[i])) {
        if (ops::isReservedChar(code[i]) || code[i] == '\0') break;
        token.data += code[i];
        skipCharacters(i, 1);
      }
      // Check if the thing is a keyword
      if (contains(token.data, keywords)) token.type = KEYWORD;
      preventIncrement(i);
      token.line = lines;
      tokens.push_back(token);
    }
  }

  void buildTree() {
    std::function<bool(Token)> isNewLine = [](Token tok) {return tok.data == ";" && tok.type == CONSTRUCT;};
    auto logicalLines = splitVector(tokens, isNewLine);
    for (auto toks : logicalLines) {
      if (toks.size() == 0) continue;
      // TODO: check for solid types here as well
      if (toks[0].data == "define" && toks[0].type == KEYWORD) {
        toks[1].type = VARIABLE;
        nodes::DeclarationNode* decl = new nodes::DeclarationNode("define", toks[1]);
        if (toks[2].data != ";" || toks[2].type != CONSTRUCT) {
          nodes::ExpressionNode* expr = new nodes::ExpressionNode(toks);
          expr->buildSubtree();
          decl->addChild(expr);
        }
        decl->printTree(0);
        tree.addRootChild(decl);
      } else {
        nodes::ExpressionNode* expr = new nodes::ExpressionNode(toks);
        expr->buildSubtree();
        expr->printTree(0);
        tree.addRootChild(expr);
      }
    }
  }

  std::vector<Token> getTokens() {
    return tokens;
  }

};

class Interpreter {
private:
  typedef builtins::Object Object;
  nodes::AST tree;
  std::unordered_map<std::string, nodes::DeclarationNode*> variables();
public:
  Interpreter(nodes::AST tree): tree(tree) {
    interpret();
  }
private:
  void interpret() {
    nodes::ChildrenNodes nodes = tree.getRootChildren();
    for (uint64 i = 0; i < nodes.size(); ++i) {
      if (nodes[i]->getNodeType() == "ExpressionNode") {
        nodes[i]->getChildren()[0] = interpretExpression(dynamic_cast<nodes::ExpressionChildNode*>(nodes[i]->getChildren()[0]));
        print("\n\n");
        dynamic_cast<nodes::ExpressionChildNode*>(nodes[i]->getChildren()[0])->printTree(0);
      }
    }
  }

  nodes::ExpressionChildNode* interpretExpression(nodes::ExpressionChildNode* node) {
    if (node->getChildren().size() == 0) return node;
    if (node->t.type == OPERATOR) {
      ops::Operator* op = static_cast<ops::Operator*>(node->t.typeData);
      auto ch = node->getChildren();
      std::for_each(ch.begin(), ch.end(), [this](nodes::ASTNode*& n) {
        auto node = dynamic_cast<nodes::ExpressionChildNode*>(n);
        if (node->getChildren().size() != 0) n = interpretExpression(node);
      });
      if (dynamic_cast<nodes::ExpressionChildNode*>(ch.back())->t.type == INTEGER) {
        if (op->getArity() == ops::BINARY) {
          auto fun = *static_cast<builtins::Integer::BinaryOp*>(builtins::Integer::operators[*op]);
          auto result = fun(
           static_cast<builtins::Integer*>(static_cast<nodes::ExpressionChildNode*>(ch[1])->t.typeData),
           static_cast<builtins::Integer*>(static_cast<nodes::ExpressionChildNode*>(ch[0])->t.typeData)
          );
          return new nodes::ExpressionChildNode(Token(result, INTEGER, -2));
        }

      }
    }
    return nullptr;
  }

};

int main() {
  getConstants();
  Parser* a;
  switch (TEST_INPUT) {
    case 1: a = new Parser("6 >> 1"); break;
    case 2: a = new Parser("(1 + 2) * 3 / (2 << 1)"); break;
    case 3: a = new Parser("define a = \"abc123\";"); break;
    case 4: a = new Parser("define a = 132;\na+=1+123*(1 + 32/2);"); break;
    case 5: a = new Parser("1+ a*(-19-1++)==Integer.MAX_INT"); break;
    case 6: a = new Parser("define a = 1 + 2 * (76 - 123 - (43 + 12) / 5) % 10;\nInteger n = 1;"); break;
    case 7: a = new Parser("1 + 2 * 3 << 2"); break;
    case 8: a = new Parser("Test.test.abc.df23.asdasf ()"); break;
    case 9: a = new Parser("define a = 1 + 2;\nb = 2 * 3"); break;
    default: break;
  }
  Interpreter in(a->tree);

  return 0;
}
<|endoftext|>


<commit_before>#include <cmath>

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

#include "DistanceCar.hpp"
#include "MockControl.hpp"
#include "MockOdometer.hpp"
#include "MockRuntime.hpp"

using namespace ::testing;
using namespace smartcarlib::constants::control;
using namespace smartcarlib::constants::car;

class DistanceCarTest : public Test
{
public:
    DistanceCarTest()
        : mDistanceCar{ mControl, mOdometerLeft, mOdometerRight, mRuntime }
    {
    }

    NiceMock<MockControl> mControl;
    NiceMock<MockOdometer> mOdometerLeft;
    NiceMock<MockOdometer> mOdometerRight;
    NiceMock<MockRuntime> mRuntime;
    DistanceCar mDistanceCar;
};

class DistanceCarSingleOdometerTest : public Test
{
public:
    DistanceCarSingleOdometerTest()
        : mDistanceCar{ mControl, mOdometer, mRuntime }
    {
    }

    virtual void SetUp()
    {
        ON_CALL(mOdometer, isAttached()).WillByDefault(Return(true));
    }

    NiceMock<MockControl> mControl;
    NiceMock<MockOdometer> mOdometer;
    NiceMock<MockRuntime> mRuntime;
    DistanceCar mDistanceCar;
};

class DistanceCarOdometersAttachedTest : public DistanceCarTest
{
public:
    virtual void SetUp()
    {
        ON_CALL(mOdometerLeft, isAttached()).WillByDefault(Return(true));
        ON_CALL(mOdometerRight, isAttached()).WillByDefault(Return(true));
    }
};

class DistanceCarCruiseControlTest : public DistanceCarTest
{
public:
    DistanceCarCruiseControlTest()
        : mNumberOfCurrentTimeMillisCalls{ 0 }
    {
    }

    virtual void SetUp()
    {
        auto validCallTimer
            = [this]() { return ++mNumberOfCurrentTimeMillisCalls * kDefaultPidFrequency; };
        ON_CALL(mRuntime, currentTimeMillis()).WillByDefault(InvokeWithoutArgs(validCallTimer));
        ON_CALL(mOdometerLeft, isAttached()).WillByDefault(Return(true));
        ON_CALL(mOdometerRight, isAttached()).WillByDefault(Return(true));

        mDistanceCar.enableCruiseControl();
    }

    int mNumberOfCurrentTimeMillisCalls;
};

TEST_F(DistanceCarTest, getDistance_WhenOdometersNotAttached_WillReturnError)
{
    EXPECT_CALL(mOdometerLeft, isAttached()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerRight, isAttached()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerLeft, getDistance()).Times(0);
    EXPECT_CALL(mOdometerRight, getDistance()).Times(0);

    ASSERT_EQ(mDistanceCar.getDistance(), static_cast<long>(kOdometersNotAttachedError));
}

TEST_F(DistanceCarTest, getDistance_WhenOdometersAttached_WillReturnAverageDistance)
{
    unsigned long leftOdometerDistance  = 205;
    unsigned long rightOdometerDistance = 180;
    unsigned long expectedDistance      = (leftOdometerDistance + rightOdometerDistance) / 2;
    EXPECT_CALL(mOdometerLeft, isAttached()).WillOnce(Return(true));
    EXPECT_CALL(mOdometerRight, isAttached()).WillOnce(Return(true));
    EXPECT_CALL(mOdometerLeft, getDistance()).WillOnce(Return(leftOdometerDistance));
    EXPECT_CALL(mOdometerRight, getDistance()).WillOnce(Return(rightOdometerDistance));

    ASSERT_EQ(mDistanceCar.getDistance(), expectedDistance);
}

TEST_F(DistanceCarTest, getDistance_WhenOneOdometerAttached_WillReturnItsDistance)
{
    unsigned long leftOdometerDistance = 400;
    EXPECT_CALL(mOdometerLeft, isAttached()).Times(2).WillRepeatedly(Return(true));
    EXPECT_CALL(mOdometerLeft, getDistance()).Times(2).WillRepeatedly(Return(leftOdometerDistance));

    DistanceCar distanceCar(mControl, mOdometerLeft, mOdometerLeft, mRuntime);
    EXPECT_EQ(distanceCar.getDistance(), leftOdometerDistance);
}

TEST_F(DistanceCarTest, setSpeed_WhenNotAttached_WillNotConsiderCruiseControlAndSetOnlySpeed)
{
    float speed = 50.0;

    EXPECT_CALL(mOdometerLeft, isAttached()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerRight, isAttached()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerLeft, providesDirection()).Times(0);
    EXPECT_CALL(mOdometerRight, providesDirection()).Times(0);
    EXPECT_CALL(mControl, setSpeed(speed));

    mDistanceCar.setSpeed(speed);
}

TEST_F(
    DistanceCarOdometersAttachedTest,
    setSpeed_WhenOdometersAreDirectionalAndCruiseControlIsEnabled_WillNotBrakeWhenChangingSpeedDirection)
{
    float speed = 50.0;
    ON_CALL(mOdometerLeft, providesDirection()).WillByDefault(Return(true));
    ON_CALL(mOdometerRight, providesDirection()).WillByDefault(Return(true));
    // The speed should be taken care only by the PID controller
    EXPECT_CALL(mControl, setSpeed(_)).Times(0);

    mDistanceCar.enableCruiseControl();
    mDistanceCar.setSpeed(speed);
    mDistanceCar.setSpeed(-speed);
}

TEST_F(DistanceCarOdometersAttachedTest, setSpeed_WhenCarShouldStop_WillBrake)
{
    auto initialSpeed = 50.0;
    mDistanceCar.setSpeed(initialSpeed);

    EXPECT_CALL(mControl, setSpeed(-initialSpeed));
    EXPECT_CALL(mControl, setSpeed(static_cast<float>(kIdleControlSpeed)));

    mDistanceCar.setSpeed(static_cast<float>(kIdleControlSpeed));
}

TEST_F(DistanceCarOdometersAttachedTest, setSpeed_WhenDirectionChangesInCruiseControl_WillBrake)
{
    auto initialSpeed = 50.0;
    mDistanceCar.enableCruiseControl();
    mDistanceCar.setSpeed(initialSpeed);
    // When braking we will sample the distance at least two times (to determine a dX)
    // and will eventually set the speed to idle
    EXPECT_CALL(mOdometerLeft, getDistance()).Times(AtLeast(2));
    EXPECT_CALL(mOdometerRight, getDistance()).Times(AtLeast(2));
    EXPECT_CALL(mControl, setSpeed(static_cast<float>(kIdleControlSpeed))).Times(AtLeast(1));

    mDistanceCar.setSpeed(-initialSpeed / 2);
}

TEST_F(DistanceCarOdometersAttachedTest, setSpeed_WhenNotMoving_WillNotBrake)
{
    // Speed might be set to idle but without sampling the dX or other attempts to stop the car
    EXPECT_CALL(mOdometerLeft, getDistance()).Times(0);
    EXPECT_CALL(mOdometerRight, getDistance()).Times(0);
    EXPECT_CALL(mControl, setSpeed(static_cast<float>(kIdleControlSpeed))).Times(AtMost(1));

    mDistanceCar.setSpeed(static_cast<float>(kIdleControlSpeed));
}

TEST_F(DistanceCarOdometersAttachedTest,
       setSpeed_WhenCruiseControlAndNoBrake_WillSetSpeedInPidController)
{
    auto speed = -30.0;
    // Speed should be set via the PID controller algorithm and not directly here
    EXPECT_CALL(mControl, setSpeed(_)).Times(0);

    mDistanceCar.enableCruiseControl();
    mDistanceCar.setSpeed(speed);
}

TEST_F(DistanceCarOdometersAttachedTest, setSpeed_WhenNoCruiseControlAndNoBrake_WillSetSpeed)
{
    auto speed = 10.0;
    EXPECT_CALL(mControl, setSpeed(speed));

    mDistanceCar.setSpeed(speed);
}

TEST_F(DistanceCarTest, getSpeed_WhenOdometersNotAttaached_WillReturnError)
{
    EXPECT_CALL(mOdometerLeft, isAttached()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerRight, isAttached()).Times(AtMost(1)).WillOnce(Return(false));

    EXPECT_EQ(mDistanceCar.getSpeed(), static_cast<float>(kOdometersNotAttachedError));
}

TEST_F(DistanceCarOdometersAttachedTest, getSpeed_WhenOdometersAttached_WillReturnAverageSpeed)
{
    float leftSpeed    = 2.1;
    float rightSpeed   = 1.8;
    auto expectedSpeed = (leftSpeed + rightSpeed) / 2;
    EXPECT_CALL(mOdometerLeft, getSpeed()).WillOnce(Return(leftSpeed));
    EXPECT_CALL(mOdometerRight, getSpeed()).WillOnce(Return(rightSpeed));

    EXPECT_EQ(mDistanceCar.getSpeed(), expectedSpeed);
}

TEST_F(DistanceCarTest, overrideMotorSpeed_WhenCruiseControlEnabled_WillNotSetSpeed)
{
    auto leftSpeed  = 0;
    auto rightSpeed = 90;
    EXPECT_CALL(mControl, overrideMotorSpeed(_, _)).Times(0);

    mDistanceCar.enableCruiseControl();
    mDistanceCar.overrideMotorSpeed(leftSpeed, rightSpeed);
}

TEST_F(DistanceCarTest, overrideMotorSpeed_WhenCruiseControlNotEnabled_WillSetSpeed)
{
    auto leftSpeed  = -20;
    auto rightSpeed = -100;

    EXPECT_CALL(mControl, overrideMotorSpeed(leftSpeed, rightSpeed));
    mDistanceCar.overrideMotorSpeed(leftSpeed, rightSpeed);
}

TEST_F(DistanceCarTest, enableCruiseControl_WhenCalled_WillEnableCruiseControl)
{
    auto leftSpeed  = 0;
    auto rightSpeed = 10;

    EXPECT_CALL(mControl, overrideMotorSpeed(_, _)).Times(0);
    mDistanceCar.enableCruiseControl();
    mDistanceCar.overrideMotorSpeed(leftSpeed, rightSpeed);
}

TEST_F(DistanceCarTest, disableCruiseControl_WhenCalled_WillDisableCruiseControl)
{
    auto leftSpeed  = 20;
    auto rightSpeed = -30;

    EXPECT_CALL(mControl, overrideMotorSpeed(_, _)).Times(0);
    mDistanceCar.enableCruiseControl();
    mDistanceCar.overrideMotorSpeed(leftSpeed, rightSpeed);

    EXPECT_CALL(mControl, overrideMotorSpeed(leftSpeed, rightSpeed));
    mDistanceCar.disableCruiseControl();
    mDistanceCar.overrideMotorSpeed(leftSpeed, rightSpeed);
}

TEST_F(DistanceCarTest, update_WhenOdometersNotAttached_WillReturnImmediately)
{
    EXPECT_CALL(mRuntime, currentTimeMillis()).Times(0);

    mDistanceCar.update();
}

TEST_F(DistanceCarOdometersAttachedTest, update_WhenCruiseControlNotEnabled_WillReturnImmediately)
{
    EXPECT_CALL(mRuntime, currentTimeMillis()).Times(0);

    mDistanceCar.update();
}

TEST_F(DistanceCarOdometersAttachedTest, update_WhenCalledTooFast_WillReturn)
{
    EXPECT_CALL(mRuntime, currentTimeMillis()).WillOnce(Return(kDefaultPidFrequency - 1));
    EXPECT_CALL(mOdometerLeft, providesDirection()).Times(0);
    EXPECT_CALL(mOdometerRight, providesDirection()).Times(0);

    mDistanceCar.enableCruiseControl();
    mDistanceCar.update();
}

TEST_F(DistanceCarOdometersAttachedTest,
       update_WhenOdometersNotDirectionalAndIdleSpeed_WillNotUpdateSpeed)
{
    mDistanceCar.enableCruiseControl();
    mDistanceCar.setSpeed(kIdleControlSpeed);
    EXPECT_CALL(mRuntime, currentTimeMillis()).WillOnce(Return(kDefaultPidFrequency));
    EXPECT_CALL(mOdometerLeft, providesDirection()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerRight, providesDirection()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerLeft, getSpeed()).Times(0);
    EXPECT_CALL(mOdometerRight, getSpeed()).Times(0);

    mDistanceCar.update();
}

TEST_F(DistanceCarCruiseControlTest, update_WhenGroundSpeedBelowTarget_WillIncreaseSpeedToMotors)
{
    float targetSpeed = 1.5;
    float groundSpeed = targetSpeed / 2;

    ON_CALL(mOdometerLeft, getSpeed()).WillByDefault(Return(groundSpeed));
    ON_CALL(mOdometerRight, getSpeed()).WillByDefault(Return(groundSpeed));
    mDistanceCar.setSpeed(targetSpeed);

    int previousSpeedToMotors = 0;
    for (auto i = 0; i < 10; i++)
    {
        int speedToMotors = 0;
        EXPECT_CALL(mControl, setSpeed(_)).WillOnce(SaveArg<0>(&speedToMotors));
        mDistanceCar.update();
        ASSERT_GT(speedToMotors, previousSpeedToMotors);
        previousSpeedToMotors = speedToMotors;
    }
}

TEST_F(DistanceCarCruiseControlTest,
       update_WhenGroundSpeedAboveTargetAndOdometersAreDirectionless_WillSetIdleSpeed)
{
    float targetSpeed = 10;
    float groundSpeed = targetSpeed * 1.1;

    ON_CALL(mOdometerLeft, getSpeed()).WillByDefault(Return(groundSpeed));
    ON_CALL(mOdometerRight, getSpeed()).WillByDefault(Return(groundSpeed));
    mDistanceCar.setSpeed(targetSpeed);

    for (auto i = 0; i < 10; i++)
    {
        int speedToMotors = 0;
        EXPECT_CALL(mControl, setSpeed(_)).WillOnce(SaveArg<0>(&speedToMotors));
        mDistanceCar.update();
        // Since the odometers are not directional, we should just stop the motors
        // so to avoid moving accidentally towards the opposite direction.
        // This test case is so to avoid #5 regressions.
        ASSERT_EQ(speedToMotors, kIdleControlSpeed);
    }
}

TEST_F(DistanceCarCruiseControlTest,
       update_WhenGroundSpeedAboveTargetAndOdometersAreDirectional_WillDecreaseSpeedToMotors)
{
    float targetSpeed = 6.5;
    float groundSpeed = targetSpeed * 1.1;

    ON_CALL(mOdometerLeft, providesDirection()).WillByDefault(Return(true));
    ON_CALL(mOdometerRight, providesDirection()).WillByDefault(Return(true));
    ON_CALL(mOdometerLeft, getSpeed()).WillByDefault(Return(groundSpeed));
    ON_CALL(mOdometerRight, getSpeed()).WillByDefault(Return(groundSpeed));
    mDistanceCar.setSpeed(targetSpeed);

    int previousSpeedToMotors = 0;
    for (auto i = 0; i < 10; i++)
    {
        int speedToMotors = 0;
        EXPECT_CALL(mControl, setSpeed(_)).WillOnce(SaveArg<0>(&speedToMotors));
        mDistanceCar.update();
        ASSERT_GT(previousSpeedToMotors, speedToMotors);
        previousSpeedToMotors = speedToMotors;
    }
}

TEST_F(DistanceCarCruiseControlTest,
       update_WhenBackwardSpeedBelowTarget_WillIncreaseMotorSpeedBackward)
{
    float targetSpeed = -3.5;
    float groundSpeed = abs(targetSpeed * 0.9); // Directionless odometers return unsigned speed

    ON_CALL(mOdometerLeft, getSpeed()).WillByDefault(Return(groundSpeed));
    ON_CALL(mOdometerRight, getSpeed()).WillByDefault(Return(groundSpeed));
    mDistanceCar.setSpeed(targetSpeed);

    int previousSpeedToMotors = 0;
    for (auto i = 0; i < 10; i++)
    {
        int speedToMotors = 0;
        EXPECT_CALL(mControl, setSpeed(_)).WillOnce(SaveArg<0>(&speedToMotors));
        mDistanceCar.update();
        // We compare the absolute values of the speeds since we are moving backward
        ASSERT_GT(abs(speedToMotors), abs(previousSpeedToMotors));
        previousSpeedToMotors = speedToMotors;
    }
}

TEST_F(DistanceCarSingleOdometerTest, constructor_WhenOneOdometerSupplied_WillTreatItAsTwo)
{
    float speed = 4.5;
    EXPECT_CALL(mOdometer, getSpeed()).Times(2).WillRepeatedly(Return(speed));

    EXPECT_EQ(mDistanceCar.getSpeed(), speed);
}
<commit_msg>Expect attach calls<commit_after>#include <cmath>

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

#include "DistanceCar.hpp"
#include "MockControl.hpp"
#include "MockOdometer.hpp"
#include "MockRuntime.hpp"

using namespace ::testing;
using namespace smartcarlib::constants::control;
using namespace smartcarlib::constants::car;

class DistanceCarTest : public Test
{
public:
    DistanceCarTest()
        : mDistanceCar{ mControl, mOdometerLeft, mOdometerRight, mRuntime }
    {
    }

    NiceMock<MockControl> mControl;
    NiceMock<MockOdometer> mOdometerLeft;
    NiceMock<MockOdometer> mOdometerRight;
    NiceMock<MockRuntime> mRuntime;
    DistanceCar mDistanceCar;
};

class DistanceCarSingleOdometerTest : public Test
{
public:
    DistanceCarSingleOdometerTest()
        : mDistanceCar{ mControl, mOdometer, mRuntime }
    {
    }

    virtual void SetUp()
    {
        ON_CALL(mOdometer, isAttached()).WillByDefault(Return(true));
    }

    NiceMock<MockControl> mControl;
    NiceMock<MockOdometer> mOdometer;
    NiceMock<MockRuntime> mRuntime;
    DistanceCar mDistanceCar;
};

class DistanceCarOdometersAttachedTest : public DistanceCarTest
{
public:
    virtual void SetUp()
    {
        ON_CALL(mOdometerLeft, isAttached()).WillByDefault(Return(true));
        ON_CALL(mOdometerRight, isAttached()).WillByDefault(Return(true));
    }
};

class DistanceCarCruiseControlTest : public DistanceCarTest
{
public:
    DistanceCarCruiseControlTest()
        : mNumberOfCurrentTimeMillisCalls{ 0 }
    {
    }

    virtual void SetUp()
    {
        auto validCallTimer
            = [this]() { return ++mNumberOfCurrentTimeMillisCalls * kDefaultPidFrequency; };
        ON_CALL(mRuntime, currentTimeMillis()).WillByDefault(InvokeWithoutArgs(validCallTimer));
        ON_CALL(mOdometerLeft, isAttached()).WillByDefault(Return(true));
        ON_CALL(mOdometerRight, isAttached()).WillByDefault(Return(true));

        mDistanceCar.enableCruiseControl();
    }

    int mNumberOfCurrentTimeMillisCalls;
};

TEST_F(DistanceCarTest, getDistance_WhenOdometersNotAttached_WillReturnError)
{
    EXPECT_CALL(mOdometerLeft, isAttached()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerRight, isAttached()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerLeft, attach(_, _)).Times(AtMost(2));
    EXPECT_CALL(mOdometerRight, attach(_, _)).Times(AtMost(2));
    EXPECT_CALL(mOdometerLeft, getDistance()).Times(0);
    EXPECT_CALL(mOdometerRight, getDistance()).Times(0);

    ASSERT_EQ(mDistanceCar.getDistance(), static_cast<long>(kOdometersNotAttachedError));
}

TEST_F(DistanceCarTest, getDistance_WhenOdometersAttached_WillReturnAverageDistance)
{
    unsigned long leftOdometerDistance  = 205;
    unsigned long rightOdometerDistance = 180;
    unsigned long expectedDistance      = (leftOdometerDistance + rightOdometerDistance) / 2;
    EXPECT_CALL(mOdometerLeft, isAttached()).WillOnce(Return(true));
    EXPECT_CALL(mOdometerRight, isAttached()).WillOnce(Return(true));
    EXPECT_CALL(mOdometerLeft, getDistance()).WillOnce(Return(leftOdometerDistance));
    EXPECT_CALL(mOdometerRight, getDistance()).WillOnce(Return(rightOdometerDistance));

    ASSERT_EQ(mDistanceCar.getDistance(), expectedDistance);
}

TEST_F(DistanceCarTest, getDistance_WhenOneOdometerAttached_WillReturnItsDistance)
{
    unsigned long leftOdometerDistance = 400;
    EXPECT_CALL(mOdometerLeft, isAttached()).Times(2).WillRepeatedly(Return(true));
    EXPECT_CALL(mOdometerLeft, getDistance()).Times(2).WillRepeatedly(Return(leftOdometerDistance));

    DistanceCar distanceCar(mControl, mOdometerLeft, mOdometerLeft, mRuntime);
    EXPECT_EQ(distanceCar.getDistance(), leftOdometerDistance);
}

TEST_F(DistanceCarTest, setSpeed_WhenNotAttached_WillNotConsiderCruiseControlAndSetOnlySpeed)
{
    float speed = 50.0;

    EXPECT_CALL(mOdometerLeft, isAttached()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerRight, isAttached()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerLeft, providesDirection()).Times(0);
    EXPECT_CALL(mOdometerRight, providesDirection()).Times(0);
    EXPECT_CALL(mControl, setSpeed(speed));

    mDistanceCar.setSpeed(speed);
}

TEST_F(
    DistanceCarOdometersAttachedTest,
    setSpeed_WhenOdometersAreDirectionalAndCruiseControlIsEnabled_WillNotBrakeWhenChangingSpeedDirection)
{
    float speed = 50.0;
    ON_CALL(mOdometerLeft, providesDirection()).WillByDefault(Return(true));
    ON_CALL(mOdometerRight, providesDirection()).WillByDefault(Return(true));
    // The speed should be taken care only by the PID controller
    EXPECT_CALL(mControl, setSpeed(_)).Times(0);

    mDistanceCar.enableCruiseControl();
    mDistanceCar.setSpeed(speed);
    mDistanceCar.setSpeed(-speed);
}

TEST_F(DistanceCarOdometersAttachedTest, setSpeed_WhenCarShouldStop_WillBrake)
{
    auto initialSpeed = 50.0;
    mDistanceCar.setSpeed(initialSpeed);

    EXPECT_CALL(mControl, setSpeed(-initialSpeed));
    EXPECT_CALL(mControl, setSpeed(static_cast<float>(kIdleControlSpeed)));

    mDistanceCar.setSpeed(static_cast<float>(kIdleControlSpeed));
}

TEST_F(DistanceCarOdometersAttachedTest, setSpeed_WhenDirectionChangesInCruiseControl_WillBrake)
{
    auto initialSpeed = 50.0;
    mDistanceCar.enableCruiseControl();
    mDistanceCar.setSpeed(initialSpeed);
    // When braking we will sample the distance at least two times (to determine a dX)
    // and will eventually set the speed to idle
    EXPECT_CALL(mOdometerLeft, getDistance()).Times(AtLeast(2));
    EXPECT_CALL(mOdometerRight, getDistance()).Times(AtLeast(2));
    EXPECT_CALL(mControl, setSpeed(static_cast<float>(kIdleControlSpeed))).Times(AtLeast(1));

    mDistanceCar.setSpeed(-initialSpeed / 2);
}

TEST_F(DistanceCarOdometersAttachedTest, setSpeed_WhenNotMoving_WillNotBrake)
{
    // Speed might be set to idle but without sampling the dX or other attempts to stop the car
    EXPECT_CALL(mOdometerLeft, getDistance()).Times(0);
    EXPECT_CALL(mOdometerRight, getDistance()).Times(0);
    EXPECT_CALL(mControl, setSpeed(static_cast<float>(kIdleControlSpeed))).Times(AtMost(1));

    mDistanceCar.setSpeed(static_cast<float>(kIdleControlSpeed));
}

TEST_F(DistanceCarOdometersAttachedTest,
       setSpeed_WhenCruiseControlAndNoBrake_WillSetSpeedInPidController)
{
    auto speed = -30.0;
    // Speed should be set via the PID controller algorithm and not directly here
    EXPECT_CALL(mControl, setSpeed(_)).Times(0);

    mDistanceCar.enableCruiseControl();
    mDistanceCar.setSpeed(speed);
}

TEST_F(DistanceCarOdometersAttachedTest, setSpeed_WhenNoCruiseControlAndNoBrake_WillSetSpeed)
{
    auto speed = 10.0;
    EXPECT_CALL(mControl, setSpeed(speed));

    mDistanceCar.setSpeed(speed);
}

TEST_F(DistanceCarTest, getSpeed_WhenOdometersNotAttaached_WillReturnError)
{
    EXPECT_CALL(mOdometerLeft, isAttached()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerRight, isAttached()).Times(AtMost(1)).WillOnce(Return(false));

    EXPECT_EQ(mDistanceCar.getSpeed(), static_cast<float>(kOdometersNotAttachedError));
}

TEST_F(DistanceCarOdometersAttachedTest, getSpeed_WhenOdometersAttached_WillReturnAverageSpeed)
{
    float leftSpeed    = 2.1;
    float rightSpeed   = 1.8;
    auto expectedSpeed = (leftSpeed + rightSpeed) / 2;
    EXPECT_CALL(mOdometerLeft, getSpeed()).WillOnce(Return(leftSpeed));
    EXPECT_CALL(mOdometerRight, getSpeed()).WillOnce(Return(rightSpeed));

    EXPECT_EQ(mDistanceCar.getSpeed(), expectedSpeed);
}

TEST_F(DistanceCarTest, overrideMotorSpeed_WhenCruiseControlEnabled_WillNotSetSpeed)
{
    auto leftSpeed  = 0;
    auto rightSpeed = 90;
    EXPECT_CALL(mControl, overrideMotorSpeed(_, _)).Times(0);

    mDistanceCar.enableCruiseControl();
    mDistanceCar.overrideMotorSpeed(leftSpeed, rightSpeed);
}

TEST_F(DistanceCarTest, overrideMotorSpeed_WhenCruiseControlNotEnabled_WillSetSpeed)
{
    auto leftSpeed  = -20;
    auto rightSpeed = -100;

    EXPECT_CALL(mControl, overrideMotorSpeed(leftSpeed, rightSpeed));
    mDistanceCar.overrideMotorSpeed(leftSpeed, rightSpeed);
}

TEST_F(DistanceCarTest, enableCruiseControl_WhenCalled_WillEnableCruiseControl)
{
    auto leftSpeed  = 0;
    auto rightSpeed = 10;

    EXPECT_CALL(mControl, overrideMotorSpeed(_, _)).Times(0);
    mDistanceCar.enableCruiseControl();
    mDistanceCar.overrideMotorSpeed(leftSpeed, rightSpeed);
}

TEST_F(DistanceCarTest, disableCruiseControl_WhenCalled_WillDisableCruiseControl)
{
    auto leftSpeed  = 20;
    auto rightSpeed = -30;

    EXPECT_CALL(mControl, overrideMotorSpeed(_, _)).Times(0);
    mDistanceCar.enableCruiseControl();
    mDistanceCar.overrideMotorSpeed(leftSpeed, rightSpeed);

    EXPECT_CALL(mControl, overrideMotorSpeed(leftSpeed, rightSpeed));
    mDistanceCar.disableCruiseControl();
    mDistanceCar.overrideMotorSpeed(leftSpeed, rightSpeed);
}

TEST_F(DistanceCarTest, update_WhenOdometersNotAttached_WillReturnImmediately)
{
    EXPECT_CALL(mRuntime, currentTimeMillis()).Times(0);

    mDistanceCar.update();
}

TEST_F(DistanceCarOdometersAttachedTest, update_WhenCruiseControlNotEnabled_WillReturnImmediately)
{
    EXPECT_CALL(mRuntime, currentTimeMillis()).Times(0);

    mDistanceCar.update();
}

TEST_F(DistanceCarOdometersAttachedTest, update_WhenCalledTooFast_WillReturn)
{
    EXPECT_CALL(mRuntime, currentTimeMillis()).WillOnce(Return(kDefaultPidFrequency - 1));
    EXPECT_CALL(mOdometerLeft, providesDirection()).Times(0);
    EXPECT_CALL(mOdometerRight, providesDirection()).Times(0);

    mDistanceCar.enableCruiseControl();
    mDistanceCar.update();
}

TEST_F(DistanceCarOdometersAttachedTest,
       update_WhenOdometersNotDirectionalAndIdleSpeed_WillNotUpdateSpeed)
{
    mDistanceCar.enableCruiseControl();
    mDistanceCar.setSpeed(kIdleControlSpeed);
    EXPECT_CALL(mRuntime, currentTimeMillis()).WillOnce(Return(kDefaultPidFrequency));
    EXPECT_CALL(mOdometerLeft, providesDirection()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerRight, providesDirection()).Times(AtMost(1)).WillOnce(Return(false));
    EXPECT_CALL(mOdometerLeft, getSpeed()).Times(0);
    EXPECT_CALL(mOdometerRight, getSpeed()).Times(0);

    mDistanceCar.update();
}

TEST_F(DistanceCarCruiseControlTest, update_WhenGroundSpeedBelowTarget_WillIncreaseSpeedToMotors)
{
    float targetSpeed = 1.5;
    float groundSpeed = targetSpeed / 2;

    ON_CALL(mOdometerLeft, getSpeed()).WillByDefault(Return(groundSpeed));
    ON_CALL(mOdometerRight, getSpeed()).WillByDefault(Return(groundSpeed));
    mDistanceCar.setSpeed(targetSpeed);

    int previousSpeedToMotors = 0;
    for (auto i = 0; i < 10; i++)
    {
        int speedToMotors = 0;
        EXPECT_CALL(mControl, setSpeed(_)).WillOnce(SaveArg<0>(&speedToMotors));
        mDistanceCar.update();
        ASSERT_GT(speedToMotors, previousSpeedToMotors);
        previousSpeedToMotors = speedToMotors;
    }
}

TEST_F(DistanceCarCruiseControlTest,
       update_WhenGroundSpeedAboveTargetAndOdometersAreDirectionless_WillSetIdleSpeed)
{
    float targetSpeed = 10;
    float groundSpeed = targetSpeed * 1.1;

    ON_CALL(mOdometerLeft, getSpeed()).WillByDefault(Return(groundSpeed));
    ON_CALL(mOdometerRight, getSpeed()).WillByDefault(Return(groundSpeed));
    mDistanceCar.setSpeed(targetSpeed);

    for (auto i = 0; i < 10; i++)
    {
        int speedToMotors = 0;
        EXPECT_CALL(mControl, setSpeed(_)).WillOnce(SaveArg<0>(&speedToMotors));
        mDistanceCar.update();
        // Since the odometers are not directional, we should just stop the motors
        // so to avoid moving accidentally towards the opposite direction.
        // This test case is so to avoid #5 regressions.
        ASSERT_EQ(speedToMotors, kIdleControlSpeed);
    }
}

TEST_F(DistanceCarCruiseControlTest,
       update_WhenGroundSpeedAboveTargetAndOdometersAreDirectional_WillDecreaseSpeedToMotors)
{
    float targetSpeed = 6.5;
    float groundSpeed = targetSpeed * 1.1;

    ON_CALL(mOdometerLeft, providesDirection()).WillByDefault(Return(true));
    ON_CALL(mOdometerRight, providesDirection()).WillByDefault(Return(true));
    ON_CALL(mOdometerLeft, getSpeed()).WillByDefault(Return(groundSpeed));
    ON_CALL(mOdometerRight, getSpeed()).WillByDefault(Return(groundSpeed));
    mDistanceCar.setSpeed(targetSpeed);

    int previousSpeedToMotors = 0;
    for (auto i = 0; i < 10; i++)
    {
        int speedToMotors = 0;
        EXPECT_CALL(mControl, setSpeed(_)).WillOnce(SaveArg<0>(&speedToMotors));
        mDistanceCar.update();
        ASSERT_GT(previousSpeedToMotors, speedToMotors);
        previousSpeedToMotors = speedToMotors;
    }
}

TEST_F(DistanceCarCruiseControlTest,
       update_WhenBackwardSpeedBelowTarget_WillIncreaseMotorSpeedBackward)
{
    float targetSpeed = -3.5;
    float groundSpeed = abs(targetSpeed * 0.9); // Directionless odometers return unsigned speed

    ON_CALL(mOdometerLeft, getSpeed()).WillByDefault(Return(groundSpeed));
    ON_CALL(mOdometerRight, getSpeed()).WillByDefault(Return(groundSpeed));
    mDistanceCar.setSpeed(targetSpeed);

    int previousSpeedToMotors = 0;
    for (auto i = 0; i < 10; i++)
    {
        int speedToMotors = 0;
        EXPECT_CALL(mControl, setSpeed(_)).WillOnce(SaveArg<0>(&speedToMotors));
        mDistanceCar.update();
        // We compare the absolute values of the speeds since we are moving backward
        ASSERT_GT(abs(speedToMotors), abs(previousSpeedToMotors));
        previousSpeedToMotors = speedToMotors;
    }
}

TEST_F(DistanceCarSingleOdometerTest, constructor_WhenOneOdometerSupplied_WillTreatItAsTwo)
{
    float speed = 4.5;
    EXPECT_CALL(mOdometer, getSpeed()).Times(2).WillRepeatedly(Return(speed));

    EXPECT_EQ(mDistanceCar.getSpeed(), speed);
}
<|endoftext|>


<commit_before>/**********************************************************************/
/* Copyright 2014 RCF                                                 */
/*                                                                    */
/* 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.                                 */
/**********************************************************************/

/**
 * @file  Main.cpp
 * @brief Main function, which start the program
 */

// Default libraries
#include <iostream>
#include <stdexcept>
using namespace std;

// Libraries
#include "RVM.hpp"
#include "Quark.hpp"
#include "Command.hpp"
#include "Options.hpp"
#include "Stackable.hpp"

#include "Syntax_C.hpp"
#include "Compiler.hpp"
#include "SyntaxC2Asm.hpp"

/**
 * @fn Main function.
 * @param  argc Number of arguments in the command line
 * @param  argv Array of string with the arguments
 * @return 0 if success; non-zero otherwise
 */
int main(int argc, char **argv)
{
    using namespace parser;

    // Process options
    Options::parse_args(argc, argv);

    // // Usage
    // if(optind <= argc && argc-optind != 1)
    // {
    //     cout << "USAGE: Main Program_name" << endl;
    //     return 0;
    // }
    //
    // try {
    //     parser::quark::Func_ptr upload
    //         = parser::quark::functions.at(argv[optind]);
    //
    //     vm::RVM Bender { upload() };
    //     Bender.run();
    //
    // } catch (const std::out_of_range& exc) {
    //     cerr << "ERROR: Program \"" << argv[1] << "\" unknown." << endl;
    //     return -1;
    // }

    // vm::Prog minus { Compiler{}.compile(bminusC{numC{2},numC{1}}) };
    // cout << minus << endl;
    // vm::RVM{ minus }.run();

    vm::Prog ifelse { Compiler{}.compile(ifC{numC{1},numC{2},numC{3}}) };
    cout << ifelse << endl;
    vm::RVM{ ifelse }.run();

    // vm::Prog test { Compiler{}.compile(plusC{numC{2},numC{2}}) };
    // cout << test << endl;
    // vm::RVM{ test }.run();

    return 0;
}
<commit_msg>Fixing old Main<commit_after>/**********************************************************************/
/* Copyright 2014 RCF                                                 */
/*                                                                    */
/* 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.                                 */
/**********************************************************************/

/**
 * @file  Main.cpp
 * @brief Main function, which start the program
 */

// Default libraries
#include <iostream>
#include <stdexcept>
using namespace std;

// Libraries
#include "RVM.hpp"
#include "Quark.hpp"
#include "Command.hpp"
#include "Options.hpp"
#include "Stackable.hpp"

/**
 * @fn Main function.
 * @param  argc Number of arguments in the command line
 * @param  argv Array of string with the arguments
 * @return 0 if success; non-zero otherwise
 */
int main(int argc, char **argv)
{
    using namespace parser;

    // Process options
    Options::parse_args(argc, argv);

    // Usage
    if(optind <= argc && argc-optind != 1)
    {
        cout << "USAGE: Main Program_name" << endl;
        return 0;
    }

    try {
        parser::quark::Func_ptr upload
            = parser::quark::functions.at(argv[optind]);

        vm::RVM Bender { upload() };
        Bender.run();

    } catch (const std::out_of_range& exc) {
        cerr << "ERROR: Program \"" << argv[1] << "\" unknown." << endl;
        return -1;
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "Version.h"
#include "System/Config.h"
#include "System/Events/EventLoop.h"
#include "System/IO/IOProcessor.h"
#include "Framework/Storage/StorageDataCache.h"
#include "Application/Common/ContextTransport.h"
#include "Application/Controller/ControllerApp.h"
#include "Application/ShardServer/ShardServerApp.h"

#ifdef DEBUG
#define VERSION_FMT_STRING "ScalienDB v" VERSION_STRING " (DEBUG build date " __DATE__ " " __TIME__ ")"
#else
#define VERSION_FMT_STRING "ScalienDB v" VERSION_STRING
#endif

void InitLog();
bool IsController();
void InitContextTransport();

int main(int argc, char** argv)
{
    Application*        app;
    bool                isController;

    if (argc < 2)
        ASSERT_FAIL();

    configFile.Init(argv[1]);
    InitLog();
    StartClock();
    IOProcessor::Init(1024);
    InitContextTransport();

    isController = IsController();
    Log_Message(VERSION_FMT_STRING " started as %s", isController ? "CONTROLLER" : "SHARD SERVER");
    if (isController)
        app = new ControllerApp;
    else
        app = new ShardServerApp;

    app->Init();

    EventLoop::Init();
    EventLoop::Run();
    EventLoop::Shutdown();

    app->Shutdown();
    delete app;

    IOProcessor::Shutdown();
    StopClock();
    configFile.Shutdown();
}

void InitLog()
{
    int logTargets;

    logTargets = 0;
    if (configFile.GetListNum("log.targets") == 0)
        logTargets = LOG_TARGET_STDOUT;

    for (int i = 0; i < configFile.GetListNum("log.targets"); i++)
    {
        if (strcmp(configFile.GetListValue("log.targets", i, ""), "file") == 0)
        {
            logTargets |= LOG_TARGET_FILE;
            Log_SetOutputFile(configFile.GetValue("log.file", NULL),
            configFile.GetBoolValue("log.truncate", false));
        }
        if (strcmp(configFile.GetListValue("log.targets", i, NULL), "stdout") == 0)
            logTargets |= LOG_TARGET_STDOUT;
        if (strcmp(configFile.GetListValue("log.targets", i, NULL), "stderr") == 0)
            logTargets |= LOG_TARGET_STDERR;
    }
    Log_SetTarget(logTargets);

    Log_SetTrace(configFile.GetBoolValue("log.trace", false));
    Log_SetTimestamping(configFile.GetBoolValue("log.timestamping", false));
}

bool IsController()
{
    const char* role;

    role = configFile.GetValue("role", "");
    if (strcmp(role, "controller") == 0)
        return true;
    else
        return false;
}

void InitContextTransport()
{
    const char*     str;
    Endpoint        endpoint;

    // set my endpoint
    str = configFile.GetValue("endpoint", "");
    if (str == 0)
        ASSERT_FAIL();
    endpoint.Set(str);
    CONTEXT_TRANSPORT->Init(endpoint);
}
<commit_msg>Fixed initialization warnings and return values.<commit_after>#include "Version.h"
#include "System/Config.h"
#include "System/Events/EventLoop.h"
#include "System/IO/IOProcessor.h"
#include "Framework/Storage/StorageDataCache.h"
#include "Application/Common/ContextTransport.h"
#include "Application/Controller/ControllerApp.h"
#include "Application/ShardServer/ShardServerApp.h"

#ifdef DEBUG
#define VERSION_FMT_STRING "ScalienDB v" VERSION_STRING " (DEBUG build date " __DATE__ " " __TIME__ ")"
#else
#define VERSION_FMT_STRING "ScalienDB v" VERSION_STRING
#endif

void InitLog();
bool IsController();
void InitContextTransport();

int main(int argc, char** argv)
{
    Application*        app;
    bool                isController;

    if (argc < 2)
        STOP_FAIL(1, "Config file argument not given, exiting");

    if (!configFile.Init(argv[1]))
        STOP_FAIL(1, "Invalid config file (%s)", argv[1]);

    InitLog();
    StartClock();
    IOProcessor::Init(1024);
    InitContextTransport();

    isController = IsController();
    Log_Message(VERSION_FMT_STRING " started as %s", isController ? "CONTROLLER" : "SHARD SERVER");
    if (isController)
        app = new ControllerApp;
    else
        app = new ShardServerApp;

    app->Init();

    EventLoop::Init();
    EventLoop::Run();
    EventLoop::Shutdown();

    app->Shutdown();
    delete app;

    IOProcessor::Shutdown();
    StopClock();
    configFile.Shutdown();
}

void InitLog()
{
    int logTargets;

    logTargets = 0;
    if (configFile.GetListNum("log.targets") == 0)
        logTargets = LOG_TARGET_STDOUT;

    for (int i = 0; i < configFile.GetListNum("log.targets"); i++)
    {
        if (strcmp(configFile.GetListValue("log.targets", i, ""), "file") == 0)
        {
            logTargets |= LOG_TARGET_FILE;
            Log_SetOutputFile(configFile.GetValue("log.file", NULL),
            configFile.GetBoolValue("log.truncate", false));
        }
        if (strcmp(configFile.GetListValue("log.targets", i, NULL), "stdout") == 0)
            logTargets |= LOG_TARGET_STDOUT;
        if (strcmp(configFile.GetListValue("log.targets", i, NULL), "stderr") == 0)
            logTargets |= LOG_TARGET_STDERR;
    }
    Log_SetTarget(logTargets);

    Log_SetTrace(configFile.GetBoolValue("log.trace", false));
    Log_SetTimestamping(configFile.GetBoolValue("log.timestamping", false));
}

bool IsController()
{
    const char* role;

    role = configFile.GetValue("role", "");
    if (strcmp(role, "controller") == 0)
        return true;
    else
        return false;
}

void InitContextTransport()
{
    const char*     str;
    Endpoint        endpoint;

    // set my endpoint
    str = configFile.GetValue("endpoint", "");
    if (str == 0)
        ASSERT_FAIL();
    endpoint.Set(str);
    CONTEXT_TRANSPORT->Init(endpoint);
}
<|endoftext|>


<commit_before>#include "Version.h"
#include "System/Config.h"
#include "System/Events/EventLoop.h"
#include "System/IO/IOProcessor.h"
#include "Framework/Storage/BloomFilter.h"
#include "Application/Common/ContextTransport.h"
#include "Application/ConfigServer/ConfigServerApp.h"
#include "Application/ShardServer/ShardServerApp.h"

#define PRODUCT_STRING      "ScalienDB v" VERSION_STRING " " PLATFORM_STRING

void InitLog();
void ParseArgs(int argc, char** argv);
void RunServer(int argc, char** argv);
void ConfigureSystemSettings();
bool IsController();
void InitContextTransport();
void LogPrintVersion(bool isController);

int main(int argc, char** argv)
{
    try
    {
        RunServer(argc, argv);
    }
    catch (std::bad_alloc&)
    {
        STOP_FAIL(1, "Out of memory error");
    }
    catch (std::exception& e)
    {
        STOP_FAIL(1, "Unexpected exception happened (%s)", e.what());
    }
    catch (...)
    {
        STOP_FAIL(1, "Unexpected exception happened");
    }

    return 0;
}

void RunServer(int argc, char** argv)
{
    Application* app;
    bool isController;

    if (argc < 2)
        STOP_FAIL(1, "Config file argument not given");

    if (!configFile.Init(argv[1]))
        STOP_FAIL(1, "Invalid config file (%s)", argv[1]);

    InitLog();
    ParseArgs(argc, argv);
    StartClock();
    ConfigureSystemSettings();

    IOProcessor::Init(configFile.GetIntValue("io.maxfd", 32768));
    InitContextTransport();
    BloomFilter::StaticInit();

    isController = IsController();
    LogPrintVersion(isController);
    if (isController)
        app = new ConfigServerApp;
    else
        app = new ShardServerApp;

    app->Init();

    IOProcessor::BlockSignals(IOPROCESSOR_BLOCK_ALL);
    EventLoop::Init();
    EventLoop::Run();

    Log_Message("Shutting down...");

    EventLoop::Shutdown();
    app->Shutdown();
    delete app;

    IOProcessor::Shutdown();
    StopClock();
    configFile.Shutdown();
    Log_Shutdown();
}

void InitLog()
{
    int logTargets;

    logTargets = 0;
    if (configFile.GetListNum("log.targets") == 0)
        logTargets = LOG_TARGET_STDOUT;

    for (int i = 0; i < configFile.GetListNum("log.targets"); i++)
    {
        if (strcmp(configFile.GetListValue("log.targets", i, ""), "file") == 0)
        {
            logTargets |= LOG_TARGET_FILE;
            Log_SetOutputFile(configFile.GetValue("log.file", NULL),
            configFile.GetBoolValue("log.truncate", false));
        }
        if (strcmp(configFile.GetListValue("log.targets", i, NULL), "stdout") == 0)
            logTargets |= LOG_TARGET_STDOUT;
        if (strcmp(configFile.GetListValue("log.targets", i, NULL), "stderr") == 0)
            logTargets |= LOG_TARGET_STDERR;
    }
    Log_SetTarget(logTargets);

    Log_SetTrace(configFile.GetBoolValue("log.trace", false));
    Log_SetTimestamping(configFile.GetBoolValue("log.timestamping", false));
}

void ParseArgs(int argc, char** argv)
{
    for (int i = 1; i < argc; i++)
    {
        if (argv[i][0] == '-')
        {
            switch (argv[i][1])
            {
            case 't':
                Log_SetTrace(true);
                break;
            case 'h':
                STOP_FAIL(0, "Usage: %s [-t] config-file\n\n", argv[0]);
                break;
            }
        }
    }
}

void ConfigureSystemSettings()
{
    int         memLimitPerc;
    uint64_t    memLimit;

    // percentage of physical memory can be used by the program
    memLimitPerc = configFile.GetIntValue("system.memoryLimitPercentage", 90);
    if (memLimitPerc < 0)
        memLimitPerc = 90;

    // memoryLimit overrides memoryLimitPercentage
    memLimit = configFile.GetInt64Value("system.memoryLimit", 0);
    if (memLimit == 0)
        memLimit = (uint64_t) (GetTotalPhysicalMemory() * memLimit / 100.0 + 0.5);

    if (memLimit != 0)
        SetMemoryLimit(memLimit);
}

bool IsController()
{
    const char* role;

    role = configFile.GetValue("role", "");
    if (role == NULL)
        STOP_FAIL(1, "Missing \"role\" in config file!");

    if (strcmp(role, "controller") == 0)
        return true;
    else
        return false;
}

void InitContextTransport()
{
    const char* str;
    Endpoint    endpoint;

    // set my endpoint
    str = configFile.GetValue("endpoint", "");
    if (str == NULL)
        STOP_FAIL(1, "Missing \"endpoint\" in config file!");

    if (!endpoint.Set(str, true))
        STOP_FAIL(1, "Bad endpoint format in config file!");

    CONTEXT_TRANSPORT->Init(endpoint);
}

void LogPrintVersion(bool isController)
{
    const char*     debugInfo = "";
    const char*     productString = PRODUCT_STRING;

#ifdef DEBUG
    const char*     buildDate = "Build date: " __DATE__ " " __TIME__;
    Buffer          debugBuffer;

    debugBuffer.Appendf(" -- DEBUG %s, Pid: %U", buildDate, GetProcessID());
    debugBuffer.NullTerminate();
    debugInfo = debugBuffer.GetBuffer();
#endif

    Log_Message("%s started as %s%s", productString,
     isController ? "CONTROLLER" : "SHARD SERVER", debugInfo);
}
<commit_msg>Added build date to binary even in release build.<commit_after>#include "Version.h"
#include "System/Config.h"
#include "System/Events/EventLoop.h"
#include "System/IO/IOProcessor.h"
#include "Framework/Storage/BloomFilter.h"
#include "Application/Common/ContextTransport.h"
#include "Application/ConfigServer/ConfigServerApp.h"
#include "Application/ShardServer/ShardServerApp.h"

const char PRODUCT_STRING[] = "ScalienDB v" VERSION_STRING " " PLATFORM_STRING;
const char BUILD_DATE[]     = "Build date: " __DATE__ " " __TIME__;

void InitLog();
void ParseArgs(int argc, char** argv);
void RunServer(int argc, char** argv);
void ConfigureSystemSettings();
bool IsController();
void InitContextTransport();
void LogPrintVersion(bool isController);

int main(int argc, char** argv)
{
    try
    {
        RunServer(argc, argv);
    }
    catch (std::bad_alloc&)
    {
        STOP_FAIL(1, "Out of memory error");
    }
    catch (std::exception& e)
    {
        STOP_FAIL(1, "Unexpected exception happened (%s)", e.what());
    }
    catch (...)
    {
        STOP_FAIL(1, "Unexpected exception happened");
    }

    return 0;
}

void RunServer(int argc, char** argv)
{
    Application* app;
    bool isController;

    if (argc < 2)
        STOP_FAIL(1, "Config file argument not given");

    if (!configFile.Init(argv[1]))
        STOP_FAIL(1, "Invalid config file (%s)", argv[1]);

    InitLog();
    ParseArgs(argc, argv);
    StartClock();
    ConfigureSystemSettings();

    IOProcessor::Init(configFile.GetIntValue("io.maxfd", 32768));
    InitContextTransport();
    BloomFilter::StaticInit();

    isController = IsController();
    LogPrintVersion(isController);
    if (isController)
        app = new ConfigServerApp;
    else
        app = new ShardServerApp;

    app->Init();

    IOProcessor::BlockSignals(IOPROCESSOR_BLOCK_ALL);
    EventLoop::Init();
    EventLoop::Run();

    Log_Message("Shutting down...");

    EventLoop::Shutdown();
    app->Shutdown();
    delete app;

    IOProcessor::Shutdown();
    StopClock();
    configFile.Shutdown();
    Log_Shutdown();
}

void InitLog()
{
    int logTargets;

    logTargets = 0;
    if (configFile.GetListNum("log.targets") == 0)
        logTargets = LOG_TARGET_STDOUT;

    for (int i = 0; i < configFile.GetListNum("log.targets"); i++)
    {
        if (strcmp(configFile.GetListValue("log.targets", i, ""), "file") == 0)
        {
            logTargets |= LOG_TARGET_FILE;
            Log_SetOutputFile(configFile.GetValue("log.file", NULL),
            configFile.GetBoolValue("log.truncate", false));
        }
        if (strcmp(configFile.GetListValue("log.targets", i, NULL), "stdout") == 0)
            logTargets |= LOG_TARGET_STDOUT;
        if (strcmp(configFile.GetListValue("log.targets", i, NULL), "stderr") == 0)
            logTargets |= LOG_TARGET_STDERR;
    }
    Log_SetTarget(logTargets);

    Log_SetTrace(configFile.GetBoolValue("log.trace", false));
    Log_SetTimestamping(configFile.GetBoolValue("log.timestamping", false));
}

void ParseArgs(int argc, char** argv)
{
    for (int i = 1; i < argc; i++)
    {
        if (argv[i][0] == '-')
        {
            switch (argv[i][1])
            {
            case 't':
                Log_SetTrace(true);
                break;
            case 'h':
                STOP_FAIL(0, "Usage: %s [-t] config-file\n\n", argv[0]);
                break;
            }
        }
    }
}

void ConfigureSystemSettings()
{
    int         memLimitPerc;
    uint64_t    memLimit;

    // percentage of physical memory can be used by the program
    memLimitPerc = configFile.GetIntValue("system.memoryLimitPercentage", 90);
    if (memLimitPerc < 0)
        memLimitPerc = 90;

    // memoryLimit overrides memoryLimitPercentage
    memLimit = configFile.GetInt64Value("system.memoryLimit", 0);
    if (memLimit == 0)
        memLimit = (uint64_t) (GetTotalPhysicalMemory() * memLimit / 100.0 + 0.5);

    if (memLimit != 0)
        SetMemoryLimit(memLimit);
}

bool IsController()
{
    const char* role;

    role = configFile.GetValue("role", "");
    if (role == NULL)
        STOP_FAIL(1, "Missing \"role\" in config file!");

    if (strcmp(role, "controller") == 0)
        return true;
    else
        return false;
}

void InitContextTransport()
{
    const char* str;
    Endpoint    endpoint;

    // set my endpoint
    str = configFile.GetValue("endpoint", "");
    if (str == NULL)
        STOP_FAIL(1, "Missing \"endpoint\" in config file!");

    if (!endpoint.Set(str, true))
        STOP_FAIL(1, "Bad endpoint format in config file!");

    CONTEXT_TRANSPORT->Init(endpoint);
}

void LogPrintVersion(bool isController)
{
    const char*     debugInfo = "";
    const char*     buildDate = BUILD_DATE;

#ifdef DEBUG
    Buffer          debugBuffer;

    debugBuffer.Appendf(" -- DEBUG %s, Pid: %U", buildDate, GetProcessID());
    debugBuffer.NullTerminate();
    debugInfo = debugBuffer.GetBuffer();
#endif

    Log_Message("%s started as %s%s", PRODUCT_STRING,
     isController ? "CONTROLLER" : "SHARD SERVER", debugInfo);
}
<|endoftext|>