<commit_before>//#include "../shutdown/shutdown.h"
#include "../windlg/windlg.h"
#include "../fswork/fswork.h"
#include "../apps_starter/apps_starter.h"

#include "./header/menu_apps.h"

#include <unistd.h>
#include <stdlib.h>
#include <curses.h>

using namespace std;

void open_menu(vector <string>& app_list) {
	DLGSTR menu_panel = {};
	menu_panel.xpos = 1;
	menu_panel.ypos = 1;
	// menu_panel.style = 3;
	menu_panel.border_menu = true;
	bool cycle = true;
	int key;
	while (cycle) {
		menu_win(menu_panel, app_list);
		key = getch();
		switch (key) {
			case 27: cycle = false; break;
			case KEY_UP: if (menu_panel.selected != 1) menu_panel.selected--; break;
			case KEY_DOWN: if (menu_panel.selected != menu_panel.second_border) menu_panel.selected++; break;
			case '\n': app_start(menu_panel.selected, ""); return; break;
		}
	}
	return;
}

int draw_desktop(int selected, bool open_label, bool new_draw, unsigned int maxX, unsigned int maxY) {
	unsigned x, y;
	printw("                                                           \n");
	// if (new_draw) {
		if (selected == 0) attron(COLOR_PAIR(1) | A_BOLD); // Белый цвет
		for (x = 0; x < maxX; x++) {
			mvprintw(maxY - 1, x, "-");
			mvprintw(0, x, "-");
		}
		for (y = 0; y < maxY; y++) {mvprintw(y, 0, "|"); mvprintw(y, maxX - 1, "|");}
		if (selected == 0) attroff(COLOR_PAIR(1) | A_BOLD);
	// }
		if (selected == 0) attron(COLOR_PAIR(1) | A_BOLD); // Белый цвет
		mvprintw(0, 1, "Menu");
		if (selected == 0) attroff(COLOR_PAIR(1) | A_BOLD);
		if (selected == 1) attron(COLOR_PAIR(1) | A_BOLD); // Белый цвет
		mvprintw(0, 6, "Edit");
		if (selected == 1) attroff(COLOR_PAIR(1) | A_BOLD);
		if (selected == 2) attron(COLOR_PAIR(1) | A_BOLD); // Белый цвет
		mvprintw(0, 11, "Exit");
		if (selected == 2) attroff(COLOR_PAIR(1) | A_BOLD);
		refresh();
	return 0;
}

int work_desktop(vector <string> app_list, string user_name) {
	string test_output;
	DLGSTR teststr = {}; // Только так!!!
	teststr.title = "Pre pre pre ... Alpha";
	teststr.style = 1;
	teststr.line = "Dear user, it's not full version of OS!/nThis is just an example of how might look this OS.";
	unsigned int maxY, maxYb = 0, maxX, maxXb = 0;
	bool cycle = true, open_label = false, new_draw = false;
	int key_pressed, selected = 2;
	while (cycle) {
		getmaxyx(stdscr, maxY, maxX); // Получение размера терминала
		if ((maxX != maxXb) || (maxY != maxYb)) {
			new_draw = true;
			erase();
		}
		timeout(0);
		draw_desktop(selected, open_label, true, maxX, maxY);
		// draw_desktop(selected, open_label, new_draw, maxX, maxY);
		new_draw = false;
		key_pressed = getch();
		switch (key_pressed) {
			case KEY_RIGHT: if (selected != 2) selected++; break;
			case KEY_LEFT: if (selected != 0) selected--; break;
			case '\n': switch (selected) {
							case 0: open_menu(app_list); new_draw = true; break;
							case 1: msg_win(teststr); break;
							case 2: cycle = false; break;
						}
			case 27: if (open_label) open_label = false;
					/*else shutdown_process();*/
					break;
		}
	}
	return 0;
}

int main_desktop(string user_name/*...*/) {
	vector <string> app_list;
	get_apps_list(app_list);
	work_desktop(app_list, user_name);
	return 0;
}<commit_msg>Minor fixes<commit_after>//#include "../shutdown/shutdown.h"
#include "../windlg/windlg.h"
#include "../fswork/fswork.h"
#include "../apps_starter/apps_starter.h"

#include "./header/menu_apps.h"

#include <unistd.h>
#include <stdlib.h>
#include <curses.h>

using namespace std;

void open_menu(vector <string>& app_list) {
	DLGSTR menu_panel = {};
	menu_panel.xpos = 1;
	menu_panel.ypos = 1;
	menu_panel.style = 3;
	menu_panel.border_menu = true;
	bool cycle = true;
	int key;
	while (cycle) {
		menu_win(menu_panel, app_list);
		key = getch();
		switch (key) {
			case 27: cycle = false; break;
			case KEY_UP: if (menu_panel.selected != 1) menu_panel.selected--; break;
			case KEY_DOWN: if (menu_panel.selected != menu_panel.second_border) menu_panel.selected++; break;
			case '\n': app_start(menu_panel.selected, ""); return; break;
		}
	}
	return;
}

int draw_desktop(int selected, bool open_label, bool new_draw, unsigned int maxX, unsigned int maxY) {
	if (new_draw) {
		for (unsigned int x = 0; x < maxX; x++) {
			mvprintw(maxY - 1, x, "-");
			mvprintw(0, x, "-");
		}
		for (unsigned int y = 0; y < maxY; y++) {mvprintw(y, 0, "|"); mvprintw(y, maxX - 1, "|");}
	}
		if (selected == 0) attron(COLOR_PAIR(1) | A_BOLD); // Белый цвет
		mvprintw(0, 1, "Menu");
		if (selected == 0) attroff(COLOR_PAIR(1) | A_BOLD);
		if (selected == 1) attron(COLOR_PAIR(1) | A_BOLD); // Белый цвет
		mvprintw(0, 6, "Edit");
		if (selected == 1) attroff(COLOR_PAIR(1) | A_BOLD);
		if (selected == 2) attron(COLOR_PAIR(1) | A_BOLD); // Белый цвет
		mvprintw(0, 11, "Exit");
		if (selected == 2) attroff(COLOR_PAIR(1) | A_BOLD);
	return 0;
}

int work_desktop(vector <string> app_list, string user_name) {
	unsigned int maxY, maxYb = 0, maxX, maxXb = 0;
	bool cycle = true, open_label = false, new_draw = false;
	int key_pressed, selected = 2;
	while (cycle) {
		getmaxyx(stdscr, maxY, maxX); // Получение размера терминала
		if ((maxX != maxXb) || (maxY != maxYb)) {
			new_draw = true;
			erase();
		}
		timeout(0);
		// if (new_draw) update_screen();
		draw_desktop(selected, open_label, new_draw, maxX, maxY);
		new_draw = false;
		key_pressed = getch();
		switch (key_pressed) {
			case KEY_RIGHT: if (selected != 2) selected++; break;
			case KEY_LEFT: if (selected != 0) selected--; break;
			case '\n': switch (selected) {
							case 0: open_menu(app_list); new_draw = true; break;
							case 1: break;
							case 2: cycle = false; break;
						}
			case 27: if (open_label) open_label = false;
					/*else shutdown_process();*/
					break;
		}
	}
	return 0;
}

int main_desktop(string user_name/*...*/) {
	vector <string> app_list;
	get_apps_list(app_list);
	work_desktop(app_list, user_name);
	return 0;
}<|endoftext|>


<commit_before>/*
Copyright 2015 Shoestring Research, LLC.  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 <algorithm>
#include <cassert>
#include <condition_variable>
#include <map>
#include <thread>
#include <vector>

#include "Delay.hpp"

using poolqueue::Delay;
using poolqueue::Promise;

namespace {

   struct Pimpl {
      std::multimap<std::chrono::time_point<std::chrono::steady_clock>, Promise> queue_;

      // A dedicated thread waits for the next timer expiration and
      // configuration change conditions.
      bool running_;
      std::mutex mutex_;
      std::condition_variable condition_;
      std::thread thread_;

      Pimpl()
         : running_(true)
         , thread_([this]() { run(); }) {
      }

      Pimpl(const Pimpl&) {
         assert(false);
      }

      ~Pimpl() {
         {
            std::lock_guard<std::mutex> lock(mutex_);
            running_ = false;
            condition_.notify_all();
         }

         thread_.join();
      }

      void insert(const std::chrono::steady_clock::duration& duration, const Promise& p) {
         // Add the entry to the queue.
         std::lock_guard<std::mutex> lock(mutex_);
         queue_.insert(std::make_pair(std::chrono::steady_clock::now() + duration, p));

         // Notify the thread if the new entry is next.
         if (queue_.begin()->second == p)
            condition_.notify_one();
      }

      bool cancel(const Promise& p, const std::exception_ptr& e) {
         // If a match is found, it will be swapped with target and
         // the subsequent reject will be propagated to dependencies.
         // If a match is not found, the result is reset to false.
         bool result = true;
         Promise target;
         target.except([&](const std::exception_ptr&) {
               result = false;
            });

         {
            // Linear search over queue entries.
            std::lock_guard<std::mutex> lock(mutex_);
            auto i = std::find_if(
               queue_.begin(), queue_.end(),
               [&](const decltype(queue_)::value_type& value) {
                  return value.second == p;
               });
            if (i != queue_.end()) {
               target.swap(i->second);
               queue_.erase(i);
            }
         }

         target.reject(e);
         return result;
      }

      void run() {
         while (running_) {
            // Wait until signaled or the next timer expiration.
            std::unique_lock<std::mutex> lock(mutex_);
            if (queue_.empty())
               condition_.wait(lock);
            else
               condition_.wait_until(lock, queue_.begin()->first);

            // Remove expired entries, saving the callbacks.
            std::vector<Promise> ready;
            const auto now = std::chrono::steady_clock::now();
            const auto upper = queue_.upper_bound(now);
            for (auto i = queue_.begin(); i != upper; ++i)
               ready.push_back(std::move(i->second));
            queue_.erase(queue_.begin(), upper);

            // Execute the callbacks outside the lock.
            lock.unlock();
            for (auto& p : ready)
               p.resolve();
         }

         // Notify outstanding entries of cancellation.
         for (auto& value : queue_)
            value.second.reject(std::make_exception_ptr(Delay::cancelled()));
      }

      static Pimpl& singleton() {
         static Pimpl pimpl;
         return pimpl;
      }
   };

}

bool
poolqueue::Delay::cancel(const Promise& p, const std::exception_ptr& e) {
   Pimpl& pimpl = Pimpl::singleton();
   return pimpl.cancel(p, e);
}

void
poolqueue::Delay::schedule(
   const Promise& p,
   const std::chrono::steady_clock::duration& duration) {
   Pimpl& pimpl = Pimpl::singleton();
   pimpl.insert(duration, p);
}
<commit_msg>Minor Delay queue handling optimization.<commit_after>/*
Copyright 2015 Shoestring Research, LLC.  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 <algorithm>
#include <cassert>
#include <condition_variable>
#include <map>
#include <thread>
#include <vector>

#include "Delay.hpp"

using poolqueue::Delay;
using poolqueue::Promise;

namespace {

   struct Pimpl {
      std::multimap<std::chrono::time_point<std::chrono::steady_clock>, Promise> queue_;

      // A dedicated thread waits for the next timer expiration and
      // configuration change conditions.
      bool running_;
      std::mutex mutex_;
      std::condition_variable condition_;
      std::thread thread_;

      Pimpl()
         : running_(true)
         , thread_([this]() { run(); }) {
      }

      Pimpl(const Pimpl&) {
         assert(false);
      }

      ~Pimpl() {
         {
            std::lock_guard<std::mutex> lock(mutex_);
            running_ = false;
            condition_.notify_all();
         }

         thread_.join();
      }

      void insert(const std::chrono::steady_clock::duration& duration, const Promise& p) {
         // Add the entry to the queue.
         std::lock_guard<std::mutex> lock(mutex_);
         queue_.insert(std::make_pair(std::chrono::steady_clock::now() + duration, p));

         // Notify the thread if the new entry is next.
         if (queue_.begin()->second == p)
            condition_.notify_one();
      }

      bool cancel(const Promise& p, const std::exception_ptr& e) {
         // If a match is found, it will be swapped with target and
         // the subsequent reject will be propagated to dependencies.
         // If a match is not found, the result is reset to false.
         bool result = true;
         Promise target;
         target.except([&](const std::exception_ptr&) {
               result = false;
            });

         {
            // Linear search over queue entries.
            std::lock_guard<std::mutex> lock(mutex_);
            auto i = std::find_if(
               queue_.begin(), queue_.end(),
               [&](const decltype(queue_)::value_type& value) {
                  return value.second == p;
               });
            if (i != queue_.end()) {
               target.swap(i->second);
               queue_.erase(i);
            }
         }

         target.reject(e);
         return result;
      }

      void run() {
         while (running_) {
            // Wait until signaled or the next timer expiration.
            std::unique_lock<std::mutex> lock(mutex_);
            if (queue_.empty())
               condition_.wait(lock);
            else
               condition_.wait_until(lock, queue_.begin()->first);

            // Remove expired entries, saving the callbacks.
            std::vector<Promise> ready;
            const auto now = std::chrono::steady_clock::now();
            const auto upper = queue_.upper_bound(now);
            ready.reserve(std::distance(queue_.begin(), upper));
            for (auto i = queue_.begin(); i != upper; ++i)
               ready.push_back(std::move(i->second));
            queue_.erase(queue_.begin(), upper);

            // Execute the callbacks outside the lock.
            lock.unlock();
            for (auto& p : ready)
               p.resolve();
         }

         // Notify outstanding entries of cancellation.
         for (auto& value : queue_)
            value.second.reject(std::make_exception_ptr(Delay::cancelled()));
      }

      static Pimpl& singleton() {
         static Pimpl pimpl;
         return pimpl;
      }
   };

}

bool
poolqueue::Delay::cancel(const Promise& p, const std::exception_ptr& e) {
   Pimpl& pimpl = Pimpl::singleton();
   return pimpl.cancel(p, e);
}

void
poolqueue::Delay::schedule(
   const Promise& p,
   const std::chrono::steady_clock::duration& duration) {
   Pimpl& pimpl = Pimpl::singleton();
   pimpl.insert(duration, p);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: appdef.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: vs $ $Date: 2001-01-30 15:45:03 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <appdef.hxx>

const char* GetDefStandList()
{
    char* pRet;
    char* pEnv = getenv("STAR_STANDLST");
    if ( pEnv )
    {
        int nLen = strlen( pEnv );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, pEnv );
    }
    else
    {
        int nLen = strlen( _DEF_STAND_LIST );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, _DEF_STAND_LIST );
    }
    return pRet;
}

const char* GetIniRoot()
{
    char* pRet;
    char* pEnv = getenv("STAR_INIROOT");
    if ( pEnv )
    {
        int nLen = strlen( pEnv );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, pEnv );
    }
    else
    {
        int nLen = strlen( _INIROOT );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, _INIROOT );
    }
    return pRet;
}

const char* GetIniRootOld()
{
    char* pRet;
    char* pEnv = getenv("STAR_INIROOTOLD");
    if ( pEnv )
    {
        int nLen = strlen( pEnv );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, pEnv );
    }
    else
    {
        int nLen = strlen( _INIROOT_OLD );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, _INIROOT_OLD );
    }
    return pRet;
}

const char* GetSSolarIni()
{
    char* pRet;
    char* pEnv = getenv("STAR_SSOLARINI");
    if ( pEnv )
    {
        int nLen = strlen( pEnv );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, pEnv );
    }
    else
    {
        int nLen = strlen( _DEF_SSOLARINI );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, _DEF_SSOLARINI );
    }
    return pRet;
}

const char* GetSSCommon()
{
    char* pRet;
    char* pEnv = getenv("STAR_SSCOMMON");
    if ( pEnv )
    {
        int nLen = strlen( pEnv );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, pEnv );
    }
    else
    {
        int nLen = strlen( _DEF_SSCOMMON );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, _DEF_SSCOMMON );
    }
    return pRet;
}

const char* GetBServerRoot()
{
    char* pRet;
    char* pEnv = getenv("STAR_BSERVERROOT");
    if ( pEnv )
    {
        int nLen = strlen( pEnv );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, pEnv );
    }
    else
    {
        int nLen = strlen( B_SERVER_ROOT );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, B_SERVER_ROOT );
    }
    return pRet;
}

const char* GetEnv( const char *pVar )
{
    char *pRet = getenv( pVar );
    if ( !pRet )
        pRet = "";
    return pRet;
}

const char* GetEnv( const char *pVar, const char *pDefault )
{
    char *pRet = getenv( pVar );
    if ( !pRet )
        return pDefault;
    return pRet;
}
<commit_msg>INTEGRATION: CWS ooo19126 (1.2.420); FILE MERGED 2005/09/05 13:58:11 rt 1.2.420.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: appdef.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 13:27:19 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <appdef.hxx>

const char* GetDefStandList()
{
    char* pRet;
    char* pEnv = getenv("STAR_STANDLST");
    if ( pEnv )
    {
        int nLen = strlen( pEnv );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, pEnv );
    }
    else
    {
        int nLen = strlen( _DEF_STAND_LIST );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, _DEF_STAND_LIST );
    }
    return pRet;
}

const char* GetIniRoot()
{
    char* pRet;
    char* pEnv = getenv("STAR_INIROOT");
    if ( pEnv )
    {
        int nLen = strlen( pEnv );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, pEnv );
    }
    else
    {
        int nLen = strlen( _INIROOT );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, _INIROOT );
    }
    return pRet;
}

const char* GetIniRootOld()
{
    char* pRet;
    char* pEnv = getenv("STAR_INIROOTOLD");
    if ( pEnv )
    {
        int nLen = strlen( pEnv );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, pEnv );
    }
    else
    {
        int nLen = strlen( _INIROOT_OLD );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, _INIROOT_OLD );
    }
    return pRet;
}

const char* GetSSolarIni()
{
    char* pRet;
    char* pEnv = getenv("STAR_SSOLARINI");
    if ( pEnv )
    {
        int nLen = strlen( pEnv );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, pEnv );
    }
    else
    {
        int nLen = strlen( _DEF_SSOLARINI );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, _DEF_SSOLARINI );
    }
    return pRet;
}

const char* GetSSCommon()
{
    char* pRet;
    char* pEnv = getenv("STAR_SSCOMMON");
    if ( pEnv )
    {
        int nLen = strlen( pEnv );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, pEnv );
    }
    else
    {
        int nLen = strlen( _DEF_SSCOMMON );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, _DEF_SSCOMMON );
    }
    return pRet;
}

const char* GetBServerRoot()
{
    char* pRet;
    char* pEnv = getenv("STAR_BSERVERROOT");
    if ( pEnv )
    {
        int nLen = strlen( pEnv );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, pEnv );
    }
    else
    {
        int nLen = strlen( B_SERVER_ROOT );
        pRet = ( char *) malloc( nLen + 1 );
        (void) strcpy( pRet, B_SERVER_ROOT );
    }
    return pRet;
}

const char* GetEnv( const char *pVar )
{
    char *pRet = getenv( pVar );
    if ( !pRet )
        pRet = "";
    return pRet;
}

const char* GetEnv( const char *pVar, const char *pDefault )
{
    char *pRet = getenv( pVar );
    if ( !pRet )
        return pDefault;
    return pRet;
}
<|endoftext|>


<commit_before>/**
 * Copyright 2008 Matthew Graham
 * 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 "testpp.h"

/**
 * Define tests
 */
testpp_suite_c parent_suite( "parent" );
testpp_suite_c simple_suite( "simple", parent_suite );
testpp_suite_c special_suite( "special", parent_suite );
testpp_suite_c assertion_suite( "assertion" );

class test_custom
: public testpp_c
{
public:
	void test()
	{
		assertpp( m_x ).t();
		assertpp( m_x ) == 5;
	}

	void setup()
	{
		m_x = 5;
	}

	void teardown()
	{
		m_x = 0;
	}

private:
	int m_x;
};
REGISTER_TESTPP( test_custom );
// REGISTER_SUITE_TESTPP( test_custom, parent_suite );

// expansion of what the TESTPP macro does
class simple_test : public testpp_c { void test(); };
/*
static testpp_runner_i simple_test_runner( new simple_test(), "simple_test"
		, __FILE__, __LINE__ );
		*/
void simple_test::test()
{
}

SUITE_TESTPP( test_equality_assertion, assertion_suite )
{
	int value( 5 );
	assertpp( value ) == 5;
}

TESTPP( test_equality_assertion_failure )
{
	int value( 5 );
	assertpp( value ) == 4;
}

TESTPP( test_inequality_assertion )
{
	int value( 5 );
	assertpp( value ) != 4;
}

TESTPP( test_inequality_assertion_failure )
{
	int value( 5 );
	assertpp( value ) != 5;
}

TESTPP( test_string_equality_assertion )
{
	std::string value( "hello" );
	assertpp( value ) == "hello";
}

TESTPP( test_suite_match )
{
	testpp_suite_c suite( "special" );
	assertpp( suite.match( "special" ) ).t();
}

TESTPP( test_parent_suite_match )
{
	testpp_suite_c parent( "parent" );
	testpp_suite_c suite( "special", parent );
	assertpp( suite.match( "parent" ) ).t();
}

TESTPP( test_duplicate_runner )
{
	/*
	testpp_runner_c< test_duplicate_runner > runner( "tst_runner_in_suite"
			, __FILE__, __LINE__ );
	assertpp( runner.in_suite( "simple" ) ).f();
	*/
}

TESTPP( test_runner_in_suite )
{
	/*
	testpp_runner_c< test_runner_in_suite > runner( "tst_runner_in_suite"
			, simple_suite, __FILE__, __LINE__ );
	assertpp( runner.in_suite( "simple" ) ).t();
	*/
}

<commit_msg>added some sample usage for adding output types to the tests<commit_after>/**
 * Copyright 2008 Matthew Graham
 * 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 "testpp.h"

/**
 * Define tests
 */
testpp_suite_c parent_suite( "parent" );
testpp_suite_c simple_suite( "simple", parent_suite );
testpp_suite_c special_suite( "special", parent_suite );
testpp_suite_c assertion_suite( "assertion" );

class test_custom
: public testpp_c
{
public:
	void test()
	{
		assertpp( m_x ).t();
		assertpp( m_x ) == 5;
	}

	void setup()
	{
		m_x = 5;
	}

	void teardown()
	{
		m_x = 0;
	}

private:
	int m_x;
};
REGISTER_TESTPP( test_custom );
// REGISTER_SUITE_TESTPP( test_custom, parent_suite );

// expansion of what the TESTPP macro does
class simple_test : public testpp_c { void test(); };
/*
static testpp_runner_i simple_test_runner( new simple_test(), "simple_test"
		, __FILE__, __LINE__ );
		*/
void simple_test::test()
{
}

SUITE_TESTPP( test_equality_assertion, assertion_suite )
{
	int value( 5 );
	assertpp( value ) == 5;
}

TESTPP( test_equality_assertion_failure )
{
	int value( 5 );
	assertpp( value ) == 4;
}

TESTPP( test_inequality_assertion )
{
	int value( 5 );
	assertpp( value ) != 4;
}

TESTPP( test_inequality_assertion_failure )
{
	int value( 5 );
	assertpp( value ) != 5;
}

TESTPP( test_string_equality_assertion )
{
	std::string value( "hello" );
	assertpp( value ) == "hello";
}

TESTPP( test_suite_match )
{
	testpp_suite_c suite( "special" );
	assertpp( suite.match( "special" ) ).t();
}

TESTPP( test_parent_suite_match )
{
	testpp_suite_c parent( "parent" );
	testpp_suite_c suite( "special", parent );
	assertpp( suite.match( "parent" ) ).t();
}

TESTPP( test_duplicate_runner )
{
	/*
	testpp_runner_c< test_duplicate_runner > runner( "tst_runner_in_suite"
			, __FILE__, __LINE__ );
	assertpp( runner.in_suite( "simple" ) ).f();
	*/
}

TESTPP( test_runner_in_suite )
{
	/*
	testpp_runner_c< test_runner_in_suite > runner( "tst_runner_in_suite"
			, simple_suite, __FILE__, __LINE__ );
	assertpp( runner.in_suite( "simple" ) ).t();
	*/
}

/*
testpp_output_register< human_testpp_output_c > human_output( "human" );
testpp_output_register< yaml_testpp_output_c > yaml_output( "yaml" );
testpp_output_register< json_testpp_output_c > json_output( "json" );

TESTPP_OUTPUT()
{
	add_output< human_testpp_output_c >();
	add_output< yaml_testpp_output_c >();
	add_output< json_testpp_output_c >();
}
*/

<|endoftext|>


<commit_before>#include <QtCore/QUuid>
#include <QtGui/QMouseEvent>
#include "../../qrkernel/definitions.h"
#include "paletteTree.h"
#include <QtCore/QtAlgorithms>
#include <QtGui/QLabel>
#include <QtGui/QVBoxLayout>

using namespace qReal;
using namespace gui;

EditorManager * PaletteTree::mEditorManager = NULL;

PaletteTree::DraggableElement::DraggableElement(const Id &id, const QString &name
		, const QString &description, const QIcon &icon, bool iconsOnly, QWidget *parent)
	: QWidget(parent)
	, mId(id)
	, mIcon(icon)
	, mText(name)
{
	QHBoxLayout *layout = new QHBoxLayout(this);
	layout->setContentsMargins(4, 4, 4, 4);

	int size = iconsOnly ? 50 : 30;
	QLabel *pic = new QLabel(this);
	pic->setFixedSize(size, size);  // the frame
	pic->setPixmap(mIcon.pixmap(size - 2, size - 2));
	layout->addWidget(pic);

	if (!iconsOnly) {
		QLabel *text = new QLabel(this);
		text->setText(mText);
		layout->addWidget(text);
	}

	setLayout(layout);

	QString modifiedDescription = description;
	if (!modifiedDescription.isEmpty()) {
		modifiedDescription.insert(0, "<body>");  //turns alignment on
		setToolTip(modifiedDescription);
	}
}

PaletteTree::PaletteTree(QWidget *parent)
	:QWidget(parent), mCurrentEditor(0)
{
	createPaletteTree();
}

void PaletteTree::addItemType(const Id &id, const QString &name, const QString &description
		, const QIcon &icon, QTreeWidget *tree, QTreeWidgetItem *parent)
{
	QTreeWidgetItem *leaf = new QTreeWidgetItem;
	DraggableElement *element = new DraggableElement(id, name, description, icon, mIconsView);
	parent->addChild(leaf);
	tree->setItemWidget(leaf, 0, element);
}

void PaletteTree::addTopItemType(const Id &id, const QString &name
		, const QString &description, const QIcon &icon, QTreeWidget *tree)
{
	QTreeWidgetItem *item = new QTreeWidgetItem;
	DraggableElement *element = new DraggableElement(id, name, description, icon, mIconsView);
	tree->addTopLevelItem(item);
	tree->setItemWidget(item,0,element);
}

void PaletteTree::DraggableElement::dragEnterEvent(QDragEnterEvent * /*event*/)
{
}

void PaletteTree::DraggableElement::dropEvent(QDropEvent * /*event*/)
{
}

void PaletteTree::DraggableElement::mousePressEvent(QMouseEvent *event)
{
	QWidget *atMouse = childAt(event->pos());
	if (!atMouse || atMouse == this) {
		return;
	}

	DraggableElement *child = dynamic_cast<DraggableElement *>(atMouse->parent());
	if (!child) {
		child = dynamic_cast<DraggableElement *>(atMouse);
	}
	if (!child) {
		return;
	}

	Q_ASSERT(child->id().idSize() == 3);  // it should be element type

	// new element's ID is being generated here
	// may this epic event should take place in some more appropriate place

	Id elementId(child->id(), QUuid::createUuid().toString());

	QByteArray itemData;
	bool isFromLogicalModel = false;

	QDataStream stream(&itemData, QIODevice::WriteOnly);
	stream << elementId.toString();  // uuid
	stream << Id::rootId().toString();  // pathToItem
	stream << QString("(" + child->text() + ")");
	stream << QPointF(0, 0);
	stream << isFromLogicalModel;

	QMimeData *mimeData = new QMimeData;
	mimeData->setData("application/x-real-uml-data", itemData);

	QDrag *drag = new QDrag(this);
	drag->setMimeData(mimeData);

	QPixmap p = child->icon().pixmap(96, 96);

	if (!p.isNull()) {
		drag->setPixmap(child->icon().pixmap(96, 96));
	}

	if (drag->start(Qt::CopyAction | Qt::MoveAction) == Qt::MoveAction) {
		child->close();
	} else {
		child->show();
	}
}

bool PaletteTree::idLessThan(const Id &s1, const Id &s2)
{
	return mEditorManager->friendlyName(s1).toLower() <
			mEditorManager->friendlyName(s2).toLower();
}

void PaletteTree::collapseChildren(QTreeWidgetItem *item)
{
	for (int i = 0; i < item->childCount(); i++) {
		if (item->child(i)) {
			collapseChildren(item->child(i));
		}
	}
	mTree->collapseItem(item);
}

void PaletteTree::collapse()
{
	for (int i = 0; i < mTree->topLevelItemCount(); i++) {
		if (mTree->topLevelItem(i)) {
			collapseChildren(mTree->topLevelItem(i));
		}
	}
}

void PaletteTree::setActiveEditor(int index)
{
	mCurrentEditor = index;
	mTree->hide();
	mTree = mEditorsTrees[index];
	mTree->show();
}

void PaletteTree::setActiveEditor(Id id)
{
	setActiveEditor(mCategories.value(id, 0));
}

void PaletteTree::expandChildren(QTreeWidgetItem *item)
{
	for (int i = 0; i < item->childCount(); i++) {
		if (item->child(i)) {
			expandChildren(item->child(i));
		}
	}
	mTree->expandItem(item);
}

void PaletteTree::expand()
{
	for (int i = 0; i < mTree->topLevelItemCount(); i++) {
		if (mTree->topLevelItem(i)) {
			expandChildren(mTree->topLevelItem(i));
		}
	}
}

void PaletteTree::addItemsRow(IdList &tmpIdList, QTreeWidget *editorTree, QTreeWidgetItem *item)
{
	if (mItemsCountInARow == 1 || !mIconsView) {
		foreach (const Id &element, tmpIdList) {
			addItemType(element, mEditorManager->friendlyName(element)
					, mEditorManager->description(element)
					, mEditorManager->icon(element), editorTree, item);
		}
		return;
	}
	for (IdList::ConstIterator it = tmpIdList.begin(); it != tmpIdList.end();) {
		QWidget *field = new QWidget;
		QHBoxLayout *layout = new QHBoxLayout;
		int count = mItemsCountInARow;
		for (; it != tmpIdList.end() && count-- > 0; ++it) {
			DraggableElement *element = new DraggableElement(*it
					, mEditorManager->friendlyName(*it)
					, mEditorManager->description(*it)
					, mEditorManager->icon(*it)
					, true);
			element->setToolTip(mEditorManager->friendlyName(*it));
			layout->addWidget(element);
			if (count > 0) {
				layout->addStretch(50);
			}
		}
		field->setLayout(layout);
		QTreeWidgetItem *leaf = new QTreeWidgetItem;
		item->addChild(leaf);
		editorTree->setItemWidget(leaf, 0, field);
	}
}

void PaletteTree::addEditorElements(EditorManager &editorManager, const Id &editor, const Id &diagram)
{
	mEditorManager = &editorManager;
	mEditorsNames.push_back(mEditorManager->friendlyName(diagram));

	mComboBox->addItem(mEditorManager->friendlyName(diagram));

	QTreeWidget *EditorTree = new QTreeWidget(this);
	EditorTree->setHeaderHidden(true);

	IdList list = mEditorManager->elements(diagram);
	qSort(list.begin(), list.end(), idLessThan);

	mCategories[diagram] = mEditorsTrees.size() - 1;

	if (!mEditorManager->paletteGroups(editor, diagram).empty()) {
		foreach (const QString &group, mEditorManager->paletteGroups(editor, diagram)) {
			QTreeWidgetItem *item = new QTreeWidgetItem;
			item->setText(0, group);

			IdList tmpIdList;

			foreach (const QString &elementName, mEditorManager->paletteGroupList(editor, diagram, group)) {
				foreach (const Id &element, list) {
					if (mEditorManager->friendlyName(element) == elementName) {
						tmpIdList.append (element);
						break;
					}
				}
			}
			qSort(tmpIdList.begin(), tmpIdList.end(), idLessThan);

			addItemsRow(tmpIdList, EditorTree, item);

			EditorTree->addTopLevelItem(item);

			if (mSettings->value("Diagram" + mEditorsTrees.count() + group, 0).toBool()) {
				EditorTree->expandItem(item);
				mSettings->remove("Diagram" + mEditorsTrees.count() + group);
			}
		}
	} else {
		foreach (const Id &element, list) {
			addTopItemType(element, mEditorManager->friendlyName(element)
					, mEditorManager->description(element)
					, mEditorManager->icon(element), EditorTree);
		}
	}
	EditorTree->hide();

	mEditorsTrees.push_back(EditorTree);

	mLayout->addWidget(EditorTree);
}

void PaletteTree::initDone()
{
	connect(mComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setActiveEditor(int)));
	setActiveEditor(mSettings->value("CurrentIndex", 0).toInt());
}

void PaletteTree::setComboBox(Id const &id)
{
	mComboBox->setCurrentIndex(mCategories.value(id, -1));
}

QComboBox* PaletteTree::comboBox() const
{
	return mComboBox;
}

QVector<QString> PaletteTree::editorsNames() const
{
	return mEditorsNames;
}

void PaletteTree::deleteEditor(const Id &id)
{
	if (mCategories.contains(id)) {
		QTreeWidget * tree = mEditorsTrees[mCategories[id]];
		QObject *w = mComboBox->children().value(mCategories[id]);
		mComboBox->removeItem(mCategories[id]);
		delete w;
		mEditorsNames.remove(mCategories[id]);
		mEditorsTrees.remove(mCategories[id]);
		delete tree;
		mCategories.remove(id);
	}
}

Id PaletteTree::currentEditor() const
{
	return mCategories.key(mCurrentEditor);
}

void PaletteTree::recreateTrees()
{
	deletePaletteTree();
	createPaletteTree();
}

void PaletteTree::createPaletteTree()
{
	mLayout = new QVBoxLayout(this);
	mLayout->setSpacing(0);

	QLabel *header = new QLabel("Palette");
	header->setAlignment(Qt::AlignHCenter);
	mLayout->addWidget(header);

	mComboBox = new QComboBox;
	mComboBox->setGeometry(0,0,300,50);
	mLayout->addWidget(mComboBox);

	QHBoxLayout *hLayout = new QHBoxLayout;
	hLayout->setSpacing(0);

	mExpandAll  = new QPushButton(this);
	mExpandAll->setGeometry(0,0,140,50);
	mExpandAll->setText("Expand All");
	connect(mExpandAll,SIGNAL(clicked()),this,SLOT(expand()));
	hLayout->addWidget(mExpandAll);

	mCollapseAll  = new QPushButton(this);
	mCollapseAll->setGeometry(0,0,140,50);
	mCollapseAll->setText("Collapse All");
	connect(mCollapseAll,SIGNAL(clicked()),this,SLOT(collapse()));
	hLayout->addWidget(mCollapseAll);
	mLayout->addLayout(hLayout,0);

	mTree = new QTreeWidget(this);
	mTree->setHeaderHidden(true);
	mLayout->addWidget(mTree);
	mSettings = new QSettings("Qreal", "PaletteItems");
}

void PaletteTree::deletePaletteTree()
{
	for (int i = 0; i < mEditorsTrees.count(); i++) {
		const QTreeWidget *editorTree = mEditorsTrees[i];
		for (int j = 0; j < editorTree->topLevelItemCount(); j++) {
			const QTreeWidgetItem *topItem = editorTree->topLevelItem(j);
			if (topItem && topItem->isExpanded()) {
				mSettings->setValue("Diagram" + i + topItem->text(0), 1);
			}
		}
	}
	mSettings->setValue("CurrentIndex", mComboBox->currentIndex());
	mSettings->sync();
	delete mCollapseAll;
	delete mExpandAll;
	delete mComboBox;
	delete mLayout;
	qDeleteAll(mEditorsTrees);
	mEditorsTrees.clear();
	mEditorsNames.clear();
	mCategories.clear();
}

PaletteTree::~PaletteTree()
{
	deletePaletteTree();
}

void PaletteTree::setComboBoxIndex(int index)
{
	mComboBox->setCurrentIndex(index);
}

void PaletteTree::setComboBoxIndex()
{
	mComboBox->setCurrentIndex(mSettings->value("CurrentIndex", 0).toInt());
}

bool PaletteTree::IconsView() const
{
	return mIconsView;
}

void PaletteTree::setIconsView(bool iconsView)
{
	mIconsView = iconsView;
}

void PaletteTree::loadEditors(EditorManager &editorManager)
{
	foreach (Id const editor, editorManager.editors()) {
		foreach (Id const diagram, editorManager.diagrams(editor)) {
			addEditorElements(editorManager, editor, diagram);
		}
	}
}

void PaletteTree::setItemsCountInARow(int count)
{
	mItemsCountInARow = count;
}

int PaletteTree::ItemsCountInARow() const
{
	return mItemsCountInARow;
}
<commit_msg>item cursor changed<commit_after>#include <QtCore/QUuid>
#include <QtGui/QMouseEvent>
#include "../../qrkernel/definitions.h"
#include "paletteTree.h"
#include <QtCore/QtAlgorithms>
#include <QtGui/QLabel>
#include <QtGui/QVBoxLayout>

using namespace qReal;
using namespace gui;

EditorManager * PaletteTree::mEditorManager = NULL;

PaletteTree::DraggableElement::DraggableElement(const Id &id, const QString &name
		, const QString &description, const QIcon &icon, bool iconsOnly, QWidget *parent)
	: QWidget(parent)
	, mId(id)
	, mIcon(icon)
	, mText(name)
{
	QHBoxLayout *layout = new QHBoxLayout(this);
	layout->setContentsMargins(4, 4, 4, 4);

	int size = iconsOnly ? 50 : 30;
	QLabel *pic = new QLabel(this);
	pic->setFixedSize(size, size);  // the frame
	pic->setPixmap(mIcon.pixmap(size - 2, size - 2));
	layout->addWidget(pic);

	if (!iconsOnly) {
		QLabel *text = new QLabel(this);
		text->setText(mText);
		layout->addWidget(text);
	}

	setLayout(layout);

	QString modifiedDescription = description;
	if (!modifiedDescription.isEmpty()) {
		modifiedDescription.insert(0, "<body>");  //turns alignment on
		setToolTip(modifiedDescription);
	}
	setCursor(Qt::OpenHandCursor);

}

PaletteTree::PaletteTree(QWidget *parent)
	:QWidget(parent), mCurrentEditor(0)
{
	createPaletteTree();
}

void PaletteTree::addItemType(const Id &id, const QString &name, const QString &description
		, const QIcon &icon, QTreeWidget *tree, QTreeWidgetItem *parent)
{
	QTreeWidgetItem *leaf = new QTreeWidgetItem;
	DraggableElement *element = new DraggableElement(id, name, description, icon, mIconsView);
	parent->addChild(leaf);
	tree->setItemWidget(leaf, 0, element);
}

void PaletteTree::addTopItemType(const Id &id, const QString &name
		, const QString &description, const QIcon &icon, QTreeWidget *tree)
{
	QTreeWidgetItem *item = new QTreeWidgetItem;
	DraggableElement *element = new DraggableElement(id, name, description, icon, mIconsView);
	tree->addTopLevelItem(item);
	tree->setItemWidget(item,0,element);
}

void PaletteTree::DraggableElement::dragEnterEvent(QDragEnterEvent * /*event*/)
{
}

void PaletteTree::DraggableElement::dropEvent(QDropEvent * /*event*/)
{
}

void PaletteTree::DraggableElement::mousePressEvent(QMouseEvent *event)
{

	QWidget *atMouse = childAt(event->pos());
	if (!atMouse || atMouse == this) {
		return;
	}

	DraggableElement *child = dynamic_cast<DraggableElement *>(atMouse->parent());
	if (!child) {
		child = dynamic_cast<DraggableElement *>(atMouse);
	}
	if (!child) {
		return;
	}

	Q_ASSERT(child->id().idSize() == 3);  // it should be element type

	// new element's ID is being generated here
	// may this epic event should take place in some more appropriate place

	Id elementId(child->id(), QUuid::createUuid().toString());

	QByteArray itemData;
	bool isFromLogicalModel = false;

	QDataStream stream(&itemData, QIODevice::WriteOnly);
	stream << elementId.toString();  // uuid
	stream << Id::rootId().toString();  // pathToItem
	stream << QString("(" + child->text() + ")");
	stream << QPointF(0, 0);
	stream << isFromLogicalModel;

	QMimeData *mimeData = new QMimeData;
	mimeData->setData("application/x-real-uml-data", itemData);

	QDrag *drag = new QDrag(this);
	drag->setMimeData(mimeData);

	QPixmap p = child->icon().pixmap(96, 96);

	if (!p.isNull()) {
		drag->setPixmap(child->icon().pixmap(96, 96));
	}

	if (drag->start(Qt::CopyAction | Qt::MoveAction) == Qt::MoveAction) {
		child->close();
	} else {
		child->show();
	}
}

bool PaletteTree::idLessThan(const Id &s1, const Id &s2)
{
	return mEditorManager->friendlyName(s1).toLower() <
			mEditorManager->friendlyName(s2).toLower();
}

void PaletteTree::collapseChildren(QTreeWidgetItem *item)
{
	for (int i = 0; i < item->childCount(); i++) {
		if (item->child(i)) {
			collapseChildren(item->child(i));
		}
	}
	mTree->collapseItem(item);
}

void PaletteTree::collapse()
{
	for (int i = 0; i < mTree->topLevelItemCount(); i++) {
		if (mTree->topLevelItem(i)) {
			collapseChildren(mTree->topLevelItem(i));
		}
	}
}

void PaletteTree::setActiveEditor(int index)
{
	mCurrentEditor = index;
	mTree->hide();
	mTree = mEditorsTrees[index];
	mTree->show();
}

void PaletteTree::setActiveEditor(Id id)
{
	setActiveEditor(mCategories.value(id, 0));
}

void PaletteTree::expandChildren(QTreeWidgetItem *item)
{
	for (int i = 0; i < item->childCount(); i++) {
		if (item->child(i)) {
			expandChildren(item->child(i));
		}
	}
	mTree->expandItem(item);
}

void PaletteTree::expand()
{
	for (int i = 0; i < mTree->topLevelItemCount(); i++) {
		if (mTree->topLevelItem(i)) {
			expandChildren(mTree->topLevelItem(i));
		}
	}
}

void PaletteTree::addItemsRow(IdList &tmpIdList, QTreeWidget *editorTree, QTreeWidgetItem *item)
{
	if (mItemsCountInARow == 1 || !mIconsView) {
		foreach (const Id &element, tmpIdList) {
			addItemType(element, mEditorManager->friendlyName(element)
					, mEditorManager->description(element)
					, mEditorManager->icon(element), editorTree, item);
		}
		return;
	}
	for (IdList::ConstIterator it = tmpIdList.begin(); it != tmpIdList.end();) {
		QWidget *field = new QWidget;
		QHBoxLayout *layout = new QHBoxLayout;
		int count = mItemsCountInARow;
		for (; it != tmpIdList.end() && count-- > 0; ++it) {
			DraggableElement *element = new DraggableElement(*it
					, mEditorManager->friendlyName(*it)
					, mEditorManager->description(*it)
					, mEditorManager->icon(*it)
					, true);
			element->setToolTip(mEditorManager->friendlyName(*it));
			layout->addWidget(element);
			if (count > 0) {
				layout->addStretch(50);
			}
		}
		field->setLayout(layout);
		QTreeWidgetItem *leaf = new QTreeWidgetItem;
		item->addChild(leaf);
		editorTree->setItemWidget(leaf, 0, field);
	}
}

void PaletteTree::addEditorElements(EditorManager &editorManager, const Id &editor, const Id &diagram)
{
	mEditorManager = &editorManager;
	mEditorsNames.push_back(mEditorManager->friendlyName(diagram));

	mComboBox->addItem(mEditorManager->friendlyName(diagram));

	QTreeWidget *EditorTree = new QTreeWidget(this);
	EditorTree->setHeaderHidden(true);
	EditorTree->setSelectionMode(QAbstractItemView::NoSelection);

	IdList list = mEditorManager->elements(diagram);
	qSort(list.begin(), list.end(), idLessThan);

	mCategories[diagram] = mEditorsTrees.size() - 1;

	if (!mEditorManager->paletteGroups(editor, diagram).empty()) {
		foreach (const QString &group, mEditorManager->paletteGroups(editor, diagram)) {
			QTreeWidgetItem *item = new QTreeWidgetItem;
			item->setText(0, group);

			IdList tmpIdList;

			foreach (const QString &elementName, mEditorManager->paletteGroupList(editor, diagram, group)) {
				foreach (const Id &element, list) {
					if (mEditorManager->friendlyName(element) == elementName) {
						tmpIdList.append (element);
						break;
					}
				}
			}
			qSort(tmpIdList.begin(), tmpIdList.end(), idLessThan);

			addItemsRow(tmpIdList, EditorTree, item);

			EditorTree->addTopLevelItem(item);

			if (mSettings->value("Diagram" + mEditorsTrees.count() + group, 0).toBool()) {
				EditorTree->expandItem(item);
				mSettings->remove("Diagram" + mEditorsTrees.count() + group);
			}
		}
	} else {
		foreach (const Id &element, list) {
			addTopItemType(element, mEditorManager->friendlyName(element)
					, mEditorManager->description(element)
					, mEditorManager->icon(element), EditorTree);
		}
	}
	EditorTree->hide();

	mEditorsTrees.push_back(EditorTree);

	mLayout->addWidget(EditorTree);
}

void PaletteTree::initDone()
{
	connect(mComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setActiveEditor(int)));
	setActiveEditor(mSettings->value("CurrentIndex", 0).toInt());
}

void PaletteTree::setComboBox(Id const &id)
{
	mComboBox->setCurrentIndex(mCategories.value(id, -1));
}

QComboBox* PaletteTree::comboBox() const
{
	return mComboBox;
}

QVector<QString> PaletteTree::editorsNames() const
{
	return mEditorsNames;
}

void PaletteTree::deleteEditor(const Id &id)
{
	if (mCategories.contains(id)) {
		QTreeWidget * tree = mEditorsTrees[mCategories[id]];
		QObject *w = mComboBox->children().value(mCategories[id]);
		mComboBox->removeItem(mCategories[id]);
		delete w;
		mEditorsNames.remove(mCategories[id]);
		mEditorsTrees.remove(mCategories[id]);
		delete tree;
		mCategories.remove(id);
	}
}

Id PaletteTree::currentEditor() const
{
	return mCategories.key(mCurrentEditor);
}

void PaletteTree::recreateTrees()
{
	deletePaletteTree();
	createPaletteTree();
}

void PaletteTree::createPaletteTree()
{
	mLayout = new QVBoxLayout(this);
	mLayout->setSpacing(0);

	//QLabel *header = new QLabel("Palette");
	//header->setAlignment(Qt::AlignHCenter);
	//mLayout->addWidget(header);

	mComboBox = new QComboBox;
	mComboBox->setGeometry(0,0,300,50);
	mLayout->addWidget(mComboBox);

	QHBoxLayout *hLayout = new QHBoxLayout;
	hLayout->setSpacing(0);

	mExpandAll  = new QPushButton(this);
	mExpandAll->setGeometry(0,0,140,50);
	mExpandAll->setText("Expand All");
	connect(mExpandAll,SIGNAL(clicked()),this,SLOT(expand()));
	hLayout->addWidget(mExpandAll);

	mCollapseAll  = new QPushButton(this);
	mCollapseAll->setGeometry(0,0,140,50);
	mCollapseAll->setText("Collapse All");
	connect(mCollapseAll,SIGNAL(clicked()),this,SLOT(collapse()));
	hLayout->addWidget(mCollapseAll);
	mLayout->addLayout(hLayout,0);

	mTree = new QTreeWidget(this);
	mTree->setHeaderHidden(true);
	mLayout->addWidget(mTree);
	mSettings = new QSettings("Qreal", "PaletteItems");
}

void PaletteTree::deletePaletteTree()
{
	for (int i = 0; i < mEditorsTrees.count(); i++) {
		const QTreeWidget *editorTree = mEditorsTrees[i];
		for (int j = 0; j < editorTree->topLevelItemCount(); j++) {
			const QTreeWidgetItem *topItem = editorTree->topLevelItem(j);
			if (topItem && topItem->isExpanded()) {
				mSettings->setValue("Diagram" + i + topItem->text(0), 1);
			}
		}
	}
	mSettings->setValue("CurrentIndex", mComboBox->currentIndex());
	mSettings->sync();
	delete mCollapseAll;
	delete mExpandAll;
	delete mComboBox;
	delete mLayout;
	qDeleteAll(mEditorsTrees);
	mEditorsTrees.clear();
	mEditorsNames.clear();
	mCategories.clear();
}

PaletteTree::~PaletteTree()
{
	deletePaletteTree();
}

void PaletteTree::setComboBoxIndex(int index)
{
	mComboBox->setCurrentIndex(index);
}

void PaletteTree::setComboBoxIndex()
{
	mComboBox->setCurrentIndex(mSettings->value("CurrentIndex", 0).toInt());
}

bool PaletteTree::IconsView() const
{
	return mIconsView;
}

void PaletteTree::setIconsView(bool iconsView)
{
	mIconsView = iconsView;
}

void PaletteTree::loadEditors(EditorManager &editorManager)
{
	if (editorManager.editors().empty())
		return;
	foreach (Id const editor, editorManager.editors()) {
		foreach (Id const diagram, editorManager.diagrams(editor)) {
			addEditorElements(editorManager, editor, diagram);
		}
	}
}

void PaletteTree::setItemsCountInARow(int count)
{
	mItemsCountInARow = count;
}

int PaletteTree::ItemsCountInARow() const
{
	return mItemsCountInARow;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

#include <quic/congestion_control/Copa.h>
#include <quic/common/TimeUtil.h>
#include <quic/congestion_control/CongestionControlFunctions.h>
#include <quic/logging/QLoggerConstants.h>

namespace quic {

using namespace std::chrono;

Copa::Copa(QuicConnectionStateBase& conn)
    : conn_(conn),
      cwndBytes_(conn.transportSettings.initCwndInMss * conn.udpSendPacketLen),
      isSlowStart_(true),
      minRTTFilter_(kMinRTTWindowLength.count(), 0us, 0),
      standingRTTFilter_(
          100000, /*100ms*/
          0us,
          0) {
  VLOG(10) << __func__ << " writable=" << getWritableBytes()
           << " cwnd=" << cwndBytes_ << " inflight=" << bytesInFlight_ << " "
           << conn_;
  if (conn_.transportSettings.latencyFactor.hasValue()) {
    latencyFactor_ = conn_.transportSettings.latencyFactor.value();
  }
}

void Copa::onRemoveBytesFromInflight(uint64_t bytes) {
  subtractAndCheckUnderflow(bytesInFlight_, bytes);
  VLOG(10) << __func__ << " writable=" << getWritableBytes()
           << " cwnd=" << cwndBytes_ << " inflight=" << bytesInFlight_ << " "
           << conn_;
  if (conn_.qLogger) {
    conn_.qLogger->addCongestionMetricUpdate(
        bytesInFlight_, getCongestionWindow(), kRemoveInflight.str());
  }
}

void Copa::onPacketSent(const OutstandingPacket& packet) {
  addAndCheckOverflow(bytesInFlight_, packet.encodedSize);

  VLOG(10) << __func__ << " writable=" << getWritableBytes()
           << " cwnd=" << cwndBytes_ << " inflight=" << bytesInFlight_
           << " bytesBufferred=" << conn_.flowControlState.sumCurStreamBufferLen
           << " packetNum="
           << folly::variant_match(
                  packet.packet.header,
                  [](auto& h) { return h.getPacketSequenceNum(); })
           << " " << conn_;
  if (conn_.qLogger) {
    conn_.qLogger->addCongestionMetricUpdate(
        bytesInFlight_, getCongestionWindow(), kCongestionPacketSent.str());
  }
}

/**
 * Once per window, the sender
 * compares the current cwnd to the cwnd value at
 *  the time that the latest acknowledged packet was
 *  sent (i.e., cwnd at the start of the current window).
 *  If the current cwnd is larger, then set direction to
 *  'up'; if it is smaller, then set direction to 'down'.
 *  Now, if direction is the same as in the previous
 *  window, then double v. If not, then reset v to 1.
 *  However, start doubling v only after the direction
 *  has remained the same for three RTTs
 */
void Copa::checkAndUpdateDirection(const TimePoint ackTime) {
  if (!velocityState_.lastCwndRecordTime.hasValue()) {
    velocityState_.lastCwndRecordTime = ackTime;
    velocityState_.lastRecordedCwndBytes = cwndBytes_;
    return;
  }
  auto elapsed_time = ackTime - velocityState_.lastCwndRecordTime.value();

  VLOG(10) << __func__ << " elapsed time for direction update "
           << elapsed_time.count() << ", srtt " << conn_.lossState.srtt.count()
           << " " << conn_;

  if (elapsed_time >= conn_.lossState.srtt) {
    auto newDirection = cwndBytes_ > velocityState_.lastRecordedCwndBytes
        ? VelocityState::Direction::Up
        : VelocityState::Direction::Down;
    if (newDirection != velocityState_.direction) {
      // if direction changes, change velocity to 1
      velocityState_.velocity = 1;
      velocityState_.numTimesDirectionSame = 0;
    } else {
      velocityState_.numTimesDirectionSame++;
      if (velocityState_.numTimesDirectionSame >= 3) {
        velocityState_.velocity = 2 * velocityState_.velocity;
      }
    }
    VLOG(10) << __func__ << " updated direction from "
             << velocityState_.direction << " to " << newDirection
             << " velocityState_.numTimesDirectionSame "
             << velocityState_.numTimesDirectionSame << " velocity "
             << velocityState_.velocity << " " << conn_;
    velocityState_.direction = newDirection;
    velocityState_.lastCwndRecordTime = ackTime;
    velocityState_.lastRecordedCwndBytes = cwndBytes_;
  }
}

void Copa::changeDirection(
    VelocityState::Direction newDirection,
    const TimePoint ackTime) {
  if (velocityState_.direction == newDirection) {
    return;
  }
  VLOG(10) << __func__ << " Suddenly direction change to " << newDirection
           << " " << conn_;
  velocityState_.direction = newDirection;
  velocityState_.velocity = 1;
  velocityState_.numTimesDirectionSame = 0;
  velocityState_.lastCwndRecordTime = ackTime;
  velocityState_.lastRecordedCwndBytes = cwndBytes_;
}

void Copa::onPacketAckOrLoss(
    folly::Optional<AckEvent> ack,
    folly::Optional<LossEvent> loss) {
  if (loss) {
    onPacketLoss(*loss);
  }
  if (ack && ack->largestAckedPacket.hasValue()) {
    onPacketAcked(*ack);
  }
}

void Copa::onPacketAcked(const AckEvent& ack) {
  DCHECK(ack.largestAckedPacket.hasValue());
  subtractAndCheckUnderflow(bytesInFlight_, ack.ackedBytes);
  minRTTFilter_.Update(
      conn_.lossState.lrtt,
      std::chrono::duration_cast<microseconds>(ack.ackTime.time_since_epoch())
          .count());
  auto rttMin = minRTTFilter_.GetBest();
  standingRTTFilter_.SetWindowLength(conn_.lossState.srtt.count() / 2);
  standingRTTFilter_.Update(
      conn_.lossState.lrtt,
      std::chrono::duration_cast<microseconds>(ack.ackTime.time_since_epoch())
          .count());
  auto rttStandingMicroSec = standingRTTFilter_.GetBest().count();

  VLOG(10) << __func__ << "ack size=" << ack.ackedBytes
           << " num packets acked=" << ack.ackedBytes / conn_.udpSendPacketLen
           << " writable=" << getWritableBytes() << " cwnd=" << cwndBytes_
           << " inflight=" << bytesInFlight_ << " rttMin=" << rttMin.count()
           << " sRTT=" << conn_.lossState.srtt.count()
           << " lRTT=" << conn_.lossState.lrtt.count()
           << " mRTT=" << conn_.lossState.mrtt.count()
           << " rttvar=" << conn_.lossState.rttvar.count()
           << " packetsBufferred="
           << conn_.flowControlState.sumCurStreamBufferLen
           << " packetsRetransmitted=" << conn_.lossState.rtxCount << " "
           << conn_;

  if (conn_.qLogger) {
    conn_.qLogger->addCongestionMetricUpdate(
        bytesInFlight_, getCongestionWindow(), kCongestionPacketAck.str());
  }

  auto delayInMicroSec =
      duration_cast<microseconds>(conn_.lossState.lrtt - rttMin).count();
  if (delayInMicroSec < 0) {
    LOG(ERROR) << __func__
               << "delay negative, lrtt=" << conn_.lossState.lrtt.count()
               << " rttMin=" << rttMin.count() << " " << conn_;
    return;
  }
  if (rttStandingMicroSec == 0) {
    LOG(ERROR) << __func__ << "rttStandingMicroSec zero, lrtt = "
               << conn_.lossState.lrtt.count() << " rttMin=" << rttMin.count()
               << " " << conn_;
    return;
  }

  VLOG(10) << __func__
           << " estimated queuing delay microsec =" << delayInMicroSec << " "
           << conn_;

  bool increaseCwnd = false;
  if (delayInMicroSec == 0) {
    // taking care of inf targetRate case here, this happens in beginning where
    // we do want to increase cwnd
    increaseCwnd = true;
  } else {
    auto targetRate = (1.0 * conn_.udpSendPacketLen * 1000000) /
        (latencyFactor_ * delayInMicroSec);
    auto currentRate = (1.0 * cwndBytes_ * 1000000) / rttStandingMicroSec;

    VLOG(10) << __func__ << " estimated target rate=" << targetRate
             << " current rate=" << currentRate << " " << conn_;
    increaseCwnd = targetRate >= currentRate;
  }

  if (!(increaseCwnd && isSlowStart_)) {
    // Update direction except for the case where we are in slow start mode,
    checkAndUpdateDirection(ack.ackTime);
  }

  if (increaseCwnd) {
    if (isSlowStart_) {
      // When a flow starts, Copa performs slow-start where
      // cwnd doubles once per RTT until current rate exceeds target rate".
      if (!lastCwndDoubleTime_.hasValue()) {
        lastCwndDoubleTime_ = ack.ackTime;
      } else if (
          ack.ackTime - lastCwndDoubleTime_.value() > conn_.lossState.srtt) {
        VLOG(10) << __func__ << " doubling cwnd per RTT from=" << cwndBytes_
                 << " due to slow start"
                 << " " << conn_;
        addAndCheckOverflow(cwndBytes_, cwndBytes_);
        lastCwndDoubleTime_ = ack.ackTime;
      }
    } else {
      if (velocityState_.direction != VelocityState::Direction::Up &&
          velocityState_.velocity > 1.0) {
        // if our current rate is much different than target, we double v every
        // RTT. That could result in a high v at some point in time. If we
        // detect a sudden direction change here, while v is still very high but
        // meant for opposite direction, we should reset it to 1.
        changeDirection(VelocityState::Direction::Up, ack.ackTime);
      }
      uint64_t addition = (ack.ackedPackets.size() * conn_.udpSendPacketLen *
                           conn_.udpSendPacketLen * velocityState_.velocity) /
          (latencyFactor_ * cwndBytes_);
      VLOG(10) << __func__ << " increasing cwnd from=" << cwndBytes_ << " by "
               << addition << " " << conn_;
      addAndCheckOverflow(cwndBytes_, addition);
    }
  } else {
    if (velocityState_.direction != VelocityState::Direction::Down &&
        velocityState_.velocity > 1.0) {
      // if our current rate is much different than target, we double v every
      // RTT. That could result in a high v at some point in time. If we detect
      // a sudden direction change here, while v is still very high but meant
      // for opposite direction, we should reset it to 1.
      changeDirection(VelocityState::Direction::Down, ack.ackTime);
    }
    uint64_t reduction = (ack.ackedPackets.size() * conn_.udpSendPacketLen *
                          conn_.udpSendPacketLen * velocityState_.velocity) /
        (latencyFactor_ * cwndBytes_);
    VLOG(10) << __func__ << " decreasing cwnd from=" << cwndBytes_ << " by "
             << reduction << " " << conn_;
    isSlowStart_ = false;
    subtractAndCheckUnderflow(
        cwndBytes_,
        std::min<uint64_t>(
            reduction,
            cwndBytes_ -
                conn_.transportSettings.minCwndInMss * conn_.udpSendPacketLen));
  }
  updatePacing();
}

void Copa::onPacketLoss(const LossEvent& loss) {
  VLOG(10) << __func__ << " lostBytes=" << loss.lostBytes
           << " lostPackets=" << loss.lostPackets << " cwnd=" << cwndBytes_
           << " inflight=" << bytesInFlight_ << " " << conn_;
  if (conn_.qLogger) {
    conn_.qLogger->addCongestionMetricUpdate(
        bytesInFlight_, getCongestionWindow(), kCongestionPacketLoss.str());
  }
  DCHECK(loss.largestLostPacketNum.hasValue());
  subtractAndCheckUnderflow(bytesInFlight_, loss.lostBytes);
  if (loss.persistentCongestion) {
    // TODO See if we should go to slowStart here
    VLOG(10) << __func__ << " writable=" << getWritableBytes()
             << " cwnd=" << cwndBytes_ << " inflight=" << bytesInFlight_ << " "
             << conn_;
    if (conn_.qLogger) {
      conn_.qLogger->addCongestionMetricUpdate(
          bytesInFlight_, getCongestionWindow(), kPersistentCongestion.str());
    }
    cwndBytes_ = conn_.transportSettings.minCwndInMss * conn_.udpSendPacketLen;
    updatePacing();
  }
}

uint64_t Copa::getWritableBytes() const noexcept {
  if (bytesInFlight_ > cwndBytes_) {
    return 0;
  } else {
    return cwndBytes_ - bytesInFlight_;
  }
}

uint64_t Copa::getCongestionWindow() const noexcept {
  return cwndBytes_;
}

bool Copa::inSlowStart() {
  return isSlowStart_;
}

CongestionControlType Copa::type() const noexcept {
  return CongestionControlType::Copa;
}

void Copa::setConnectionEmulation(uint8_t) noexcept {}

void Copa::updatePacing() noexcept {
  std::tie(pacingInterval_, pacingBurstSize_) = calculatePacingRate(
      conn_,
      cwndBytes_ * 2,
      conn_.transportSettings.minCwndInMss,
      minimalPacingInterval_,
      conn_.lossState.srtt);
  if (pacingInterval_ == std::chrono::milliseconds::zero()) {
    return;
  }
  if (conn_.transportSettings.pacingEnabled) {
    VLOG(10) << "updatePacing pacingInterval_ = " << pacingInterval_.count()
             << ", pacingBurstSize_ " << pacingBurstSize_ << " " << conn_;
    if (conn_.qLogger) {
      conn_.qLogger->addPacingMetricUpdate(pacingBurstSize_, pacingInterval_);
    }
  }
}

bool Copa::canBePaced() const noexcept {
  if (conn_.lossState.srtt < minimalPacingInterval_) {
    return false;
  }
  return true;
}

uint64_t Copa::getBytesInFlight() const noexcept {
  return bytesInFlight_;
}

uint64_t Copa::getPacingRate(TimePoint /* currentTime */) noexcept {
  return pacingBurstSize_;
}

void Copa::markPacerTimeoutScheduled(TimePoint /* currentTime*/) noexcept {}

std::chrono::microseconds Copa::getPacingInterval() const noexcept {
  return pacingInterval_;
}

void Copa::setMinimalPacingInterval(
    std::chrono::microseconds interval) noexcept {
  minimalPacingInterval_ = interval;
}

void Copa::setAppIdle(bool, TimePoint) noexcept { /* unsupported */
}

void Copa::setAppLimited() { /* unsupported */
}

bool Copa::isAppLimited() const noexcept {
  return false; // not supported
}

} // namespace quic
<commit_msg>Add ack and loss trace for Quic Copa<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

#include <quic/congestion_control/Copa.h>
#include <quic/common/TimeUtil.h>
#include <quic/congestion_control/CongestionControlFunctions.h>
#include <quic/logging/QLoggerConstants.h>
#include <quic/logging/QuicLogger.h>

namespace quic {

using namespace std::chrono;

Copa::Copa(QuicConnectionStateBase& conn)
    : conn_(conn),
      cwndBytes_(conn.transportSettings.initCwndInMss * conn.udpSendPacketLen),
      isSlowStart_(true),
      minRTTFilter_(kMinRTTWindowLength.count(), 0us, 0),
      standingRTTFilter_(
          100000, /*100ms*/
          0us,
          0) {
  VLOG(10) << __func__ << " writable=" << getWritableBytes()
           << " cwnd=" << cwndBytes_ << " inflight=" << bytesInFlight_ << " "
           << conn_;
  if (conn_.transportSettings.latencyFactor.hasValue()) {
    latencyFactor_ = conn_.transportSettings.latencyFactor.value();
  }
}

void Copa::onRemoveBytesFromInflight(uint64_t bytes) {
  subtractAndCheckUnderflow(bytesInFlight_, bytes);
  VLOG(10) << __func__ << " writable=" << getWritableBytes()
           << " cwnd=" << cwndBytes_ << " inflight=" << bytesInFlight_ << " "
           << conn_;
  if (conn_.qLogger) {
    conn_.qLogger->addCongestionMetricUpdate(
        bytesInFlight_, getCongestionWindow(), kRemoveInflight.str());
  }
}

void Copa::onPacketSent(const OutstandingPacket& packet) {
  addAndCheckOverflow(bytesInFlight_, packet.encodedSize);

  VLOG(10) << __func__ << " writable=" << getWritableBytes()
           << " cwnd=" << cwndBytes_ << " inflight=" << bytesInFlight_
           << " bytesBufferred=" << conn_.flowControlState.sumCurStreamBufferLen
           << " packetNum="
           << folly::variant_match(
                  packet.packet.header,
                  [](auto& h) { return h.getPacketSequenceNum(); })
           << " " << conn_;
  if (conn_.qLogger) {
    conn_.qLogger->addCongestionMetricUpdate(
        bytesInFlight_, getCongestionWindow(), kCongestionPacketSent.str());
  }
}

/**
 * Once per window, the sender
 * compares the current cwnd to the cwnd value at
 *  the time that the latest acknowledged packet was
 *  sent (i.e., cwnd at the start of the current window).
 *  If the current cwnd is larger, then set direction to
 *  'up'; if it is smaller, then set direction to 'down'.
 *  Now, if direction is the same as in the previous
 *  window, then double v. If not, then reset v to 1.
 *  However, start doubling v only after the direction
 *  has remained the same for three RTTs
 */
void Copa::checkAndUpdateDirection(const TimePoint ackTime) {
  if (!velocityState_.lastCwndRecordTime.hasValue()) {
    velocityState_.lastCwndRecordTime = ackTime;
    velocityState_.lastRecordedCwndBytes = cwndBytes_;
    return;
  }
  auto elapsed_time = ackTime - velocityState_.lastCwndRecordTime.value();

  VLOG(10) << __func__ << " elapsed time for direction update "
           << elapsed_time.count() << ", srtt " << conn_.lossState.srtt.count()
           << " " << conn_;

  if (elapsed_time >= conn_.lossState.srtt) {
    auto newDirection = cwndBytes_ > velocityState_.lastRecordedCwndBytes
        ? VelocityState::Direction::Up
        : VelocityState::Direction::Down;
    if (newDirection != velocityState_.direction) {
      // if direction changes, change velocity to 1
      velocityState_.velocity = 1;
      velocityState_.numTimesDirectionSame = 0;
    } else {
      velocityState_.numTimesDirectionSame++;
      if (velocityState_.numTimesDirectionSame >= 3) {
        velocityState_.velocity = 2 * velocityState_.velocity;
      }
    }
    VLOG(10) << __func__ << " updated direction from "
             << velocityState_.direction << " to " << newDirection
             << " velocityState_.numTimesDirectionSame "
             << velocityState_.numTimesDirectionSame << " velocity "
             << velocityState_.velocity << " " << conn_;
    velocityState_.direction = newDirection;
    velocityState_.lastCwndRecordTime = ackTime;
    velocityState_.lastRecordedCwndBytes = cwndBytes_;
  }
}

void Copa::changeDirection(
    VelocityState::Direction newDirection,
    const TimePoint ackTime) {
  if (velocityState_.direction == newDirection) {
    return;
  }
  VLOG(10) << __func__ << " Suddenly direction change to " << newDirection
           << " " << conn_;
  velocityState_.direction = newDirection;
  velocityState_.velocity = 1;
  velocityState_.numTimesDirectionSame = 0;
  velocityState_.lastCwndRecordTime = ackTime;
  velocityState_.lastRecordedCwndBytes = cwndBytes_;
}

void Copa::onPacketAckOrLoss(
    folly::Optional<AckEvent> ack,
    folly::Optional<LossEvent> loss) {
  if (loss) {
    onPacketLoss(*loss);
    QUIC_TRACE(copa_loss, conn_, cwndBytes_, bytesInFlight_);
  }
  if (ack && ack->largestAckedPacket.hasValue()) {
    onPacketAcked(*ack);
    QUIC_TRACE(copa_ack, conn_, cwndBytes_, bytesInFlight_);
  }
}

void Copa::onPacketAcked(const AckEvent& ack) {
  DCHECK(ack.largestAckedPacket.hasValue());
  subtractAndCheckUnderflow(bytesInFlight_, ack.ackedBytes);
  minRTTFilter_.Update(
      conn_.lossState.lrtt,
      std::chrono::duration_cast<microseconds>(ack.ackTime.time_since_epoch())
          .count());
  auto rttMin = minRTTFilter_.GetBest();
  standingRTTFilter_.SetWindowLength(conn_.lossState.srtt.count() / 2);
  standingRTTFilter_.Update(
      conn_.lossState.lrtt,
      std::chrono::duration_cast<microseconds>(ack.ackTime.time_since_epoch())
          .count());
  auto rttStandingMicroSec = standingRTTFilter_.GetBest().count();

  VLOG(10) << __func__ << "ack size=" << ack.ackedBytes
           << " num packets acked=" << ack.ackedBytes / conn_.udpSendPacketLen
           << " writable=" << getWritableBytes() << " cwnd=" << cwndBytes_
           << " inflight=" << bytesInFlight_ << " rttMin=" << rttMin.count()
           << " sRTT=" << conn_.lossState.srtt.count()
           << " lRTT=" << conn_.lossState.lrtt.count()
           << " mRTT=" << conn_.lossState.mrtt.count()
           << " rttvar=" << conn_.lossState.rttvar.count()
           << " packetsBufferred="
           << conn_.flowControlState.sumCurStreamBufferLen
           << " packetsRetransmitted=" << conn_.lossState.rtxCount << " "
           << conn_;

  if (conn_.qLogger) {
    conn_.qLogger->addCongestionMetricUpdate(
        bytesInFlight_, getCongestionWindow(), kCongestionPacketAck.str());
  }

  auto delayInMicroSec =
      duration_cast<microseconds>(conn_.lossState.lrtt - rttMin).count();
  if (delayInMicroSec < 0) {
    LOG(ERROR) << __func__
               << "delay negative, lrtt=" << conn_.lossState.lrtt.count()
               << " rttMin=" << rttMin.count() << " " << conn_;
    return;
  }
  if (rttStandingMicroSec == 0) {
    LOG(ERROR) << __func__ << "rttStandingMicroSec zero, lrtt = "
               << conn_.lossState.lrtt.count() << " rttMin=" << rttMin.count()
               << " " << conn_;
    return;
  }

  VLOG(10) << __func__
           << " estimated queuing delay microsec =" << delayInMicroSec << " "
           << conn_;

  bool increaseCwnd = false;
  if (delayInMicroSec == 0) {
    // taking care of inf targetRate case here, this happens in beginning where
    // we do want to increase cwnd
    increaseCwnd = true;
  } else {
    auto targetRate = (1.0 * conn_.udpSendPacketLen * 1000000) /
        (latencyFactor_ * delayInMicroSec);
    auto currentRate = (1.0 * cwndBytes_ * 1000000) / rttStandingMicroSec;

    VLOG(10) << __func__ << " estimated target rate=" << targetRate
             << " current rate=" << currentRate << " " << conn_;
    increaseCwnd = targetRate >= currentRate;
  }

  if (!(increaseCwnd && isSlowStart_)) {
    // Update direction except for the case where we are in slow start mode,
    checkAndUpdateDirection(ack.ackTime);
  }

  if (increaseCwnd) {
    if (isSlowStart_) {
      // When a flow starts, Copa performs slow-start where
      // cwnd doubles once per RTT until current rate exceeds target rate".
      if (!lastCwndDoubleTime_.hasValue()) {
        lastCwndDoubleTime_ = ack.ackTime;
      } else if (
          ack.ackTime - lastCwndDoubleTime_.value() > conn_.lossState.srtt) {
        VLOG(10) << __func__ << " doubling cwnd per RTT from=" << cwndBytes_
                 << " due to slow start"
                 << " " << conn_;
        addAndCheckOverflow(cwndBytes_, cwndBytes_);
        lastCwndDoubleTime_ = ack.ackTime;
      }
    } else {
      if (velocityState_.direction != VelocityState::Direction::Up &&
          velocityState_.velocity > 1.0) {
        // if our current rate is much different than target, we double v every
        // RTT. That could result in a high v at some point in time. If we
        // detect a sudden direction change here, while v is still very high but
        // meant for opposite direction, we should reset it to 1.
        changeDirection(VelocityState::Direction::Up, ack.ackTime);
      }
      uint64_t addition = (ack.ackedPackets.size() * conn_.udpSendPacketLen *
                           conn_.udpSendPacketLen * velocityState_.velocity) /
          (latencyFactor_ * cwndBytes_);
      VLOG(10) << __func__ << " increasing cwnd from=" << cwndBytes_ << " by "
               << addition << " " << conn_;
      addAndCheckOverflow(cwndBytes_, addition);
    }
  } else {
    if (velocityState_.direction != VelocityState::Direction::Down &&
        velocityState_.velocity > 1.0) {
      // if our current rate is much different than target, we double v every
      // RTT. That could result in a high v at some point in time. If we detect
      // a sudden direction change here, while v is still very high but meant
      // for opposite direction, we should reset it to 1.
      changeDirection(VelocityState::Direction::Down, ack.ackTime);
    }
    uint64_t reduction = (ack.ackedPackets.size() * conn_.udpSendPacketLen *
                          conn_.udpSendPacketLen * velocityState_.velocity) /
        (latencyFactor_ * cwndBytes_);
    VLOG(10) << __func__ << " decreasing cwnd from=" << cwndBytes_ << " by "
             << reduction << " " << conn_;
    isSlowStart_ = false;
    subtractAndCheckUnderflow(
        cwndBytes_,
        std::min<uint64_t>(
            reduction,
            cwndBytes_ -
                conn_.transportSettings.minCwndInMss * conn_.udpSendPacketLen));
  }
  updatePacing();
}

void Copa::onPacketLoss(const LossEvent& loss) {
  VLOG(10) << __func__ << " lostBytes=" << loss.lostBytes
           << " lostPackets=" << loss.lostPackets << " cwnd=" << cwndBytes_
           << " inflight=" << bytesInFlight_ << " " << conn_;
  if (conn_.qLogger) {
    conn_.qLogger->addCongestionMetricUpdate(
        bytesInFlight_, getCongestionWindow(), kCongestionPacketLoss.str());
  }
  DCHECK(loss.largestLostPacketNum.hasValue());
  subtractAndCheckUnderflow(bytesInFlight_, loss.lostBytes);
  if (loss.persistentCongestion) {
    // TODO See if we should go to slowStart here
    VLOG(10) << __func__ << " writable=" << getWritableBytes()
             << " cwnd=" << cwndBytes_ << " inflight=" << bytesInFlight_ << " "
             << conn_;
    if (conn_.qLogger) {
      conn_.qLogger->addCongestionMetricUpdate(
          bytesInFlight_, getCongestionWindow(), kPersistentCongestion.str());
    }
    cwndBytes_ = conn_.transportSettings.minCwndInMss * conn_.udpSendPacketLen;
    updatePacing();
  }
}

uint64_t Copa::getWritableBytes() const noexcept {
  if (bytesInFlight_ > cwndBytes_) {
    return 0;
  } else {
    return cwndBytes_ - bytesInFlight_;
  }
}

uint64_t Copa::getCongestionWindow() const noexcept {
  return cwndBytes_;
}

bool Copa::inSlowStart() {
  return isSlowStart_;
}

CongestionControlType Copa::type() const noexcept {
  return CongestionControlType::Copa;
}

void Copa::setConnectionEmulation(uint8_t) noexcept {}

void Copa::updatePacing() noexcept {
  std::tie(pacingInterval_, pacingBurstSize_) = calculatePacingRate(
      conn_,
      cwndBytes_ * 2,
      conn_.transportSettings.minCwndInMss,
      minimalPacingInterval_,
      conn_.lossState.srtt);
  if (pacingInterval_ == std::chrono::milliseconds::zero()) {
    return;
  }
  if (conn_.transportSettings.pacingEnabled) {
    VLOG(10) << "updatePacing pacingInterval_ = " << pacingInterval_.count()
             << ", pacingBurstSize_ " << pacingBurstSize_ << " " << conn_;
    if (conn_.qLogger) {
      conn_.qLogger->addPacingMetricUpdate(pacingBurstSize_, pacingInterval_);
    }
  }
}

bool Copa::canBePaced() const noexcept {
  if (conn_.lossState.srtt < minimalPacingInterval_) {
    return false;
  }
  return true;
}

uint64_t Copa::getBytesInFlight() const noexcept {
  return bytesInFlight_;
}

uint64_t Copa::getPacingRate(TimePoint /* currentTime */) noexcept {
  return pacingBurstSize_;
}

void Copa::markPacerTimeoutScheduled(TimePoint /* currentTime*/) noexcept {}

std::chrono::microseconds Copa::getPacingInterval() const noexcept {
  return pacingInterval_;
}

void Copa::setMinimalPacingInterval(
    std::chrono::microseconds interval) noexcept {
  minimalPacingInterval_ = interval;
}

void Copa::setAppIdle(bool, TimePoint) noexcept { /* unsupported */
}

void Copa::setAppLimited() { /* unsupported */
}

bool Copa::isAppLimited() const noexcept {
  return false; // not supported
}

} // namespace quic
<|endoftext|>


<commit_before>// SPDX-FileCopyrightText: 2014 Félix Robles <felrobelv@gmail.com>
// SPDX-FileCopyrightText: 2021 Eduardo Robles <edulix@nvotes.com>
//
// SPDX-License-Identifier: AGPL-3.0-only

#include <agora-airgap/ElGamal.h>
#include <agora-airgap/encrypt.h>
#include <agora-airgap/sha256.h>
#include <cryptopp/cryptlib.h>
#include <cryptopp/elgamal.h>
#include <cryptopp/files.h>
#include <cryptopp/osrng.h>
#include <cryptopp/secblock.h>
#include <gmock/gmock.h>
#include <gmpxx.h>
#include <gtest/gtest.h>
#include <memory.h>

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>

using namespace AgoraAirgap::sha256;
using namespace CryptoPP;
using std::function;
using std::string;
using std::stringstream;
using ::testing::HasSubstr;
using ::testing::Not;
using ::testing::ThrowsMessage;

// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST(Sha256Test, StringOne)
{
    BYTE text1[] = {"abc"};
    BYTE hash1[SHA256_BLOCK_SIZE] = {
        0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40,
        0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17,
        0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad};
    BYTE buf[SHA256_BLOCK_SIZE];
    SHA256_CTX ctx;
    sha256_init(&ctx);
    sha256_update(&ctx, text1, sizeof(text1) - 1);
    sha256_final(&ctx, buf);
    EXPECT_EQ(0, memcmp(hash1, buf, SHA256_BLOCK_SIZE));
}

// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST(Sha256Test, StringTwo)
{
    BYTE text2[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"};
    BYTE hash2[SHA256_BLOCK_SIZE] = {
        0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26,
        0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff,
        0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1};
    BYTE buf[SHA256_BLOCK_SIZE];
    SHA256_CTX ctx;
    sha256_init(&ctx);
    sha256_update(&ctx, text2, sizeof(text2) - 1);
    sha256_final(&ctx, buf);
    EXPECT_EQ(0, memcmp(hash2, buf, SHA256_BLOCK_SIZE));
}

// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST(Sha256Test, StringLoopTest)
{
    BYTE text3[] = {"aaaaaaaaaa"};
    BYTE hash3[SHA256_BLOCK_SIZE] = {
        0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7,
        0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97,
        0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0};
    BYTE buf[SHA256_BLOCK_SIZE];
    SHA256_CTX ctx;
    sha256_init(&ctx);
    for (int idx = 0; idx < 100000; ++idx)
    {
        sha256_update(&ctx, text3, sizeof(text3) - 1);
    }
    sha256_final(&ctx, buf);
    EXPECT_EQ(0, memcmp(hash3, buf, SHA256_BLOCK_SIZE));
}

// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST(AgoraUnitTest, SmallMessageEncryption)
{
    mpz_t p, q, g, y, x, m, rand;

    mpz_init_set_str(p, "1019", 10);
    mpz_init_set_str(q, "509", 10);  // q = (p-1)/2 = 509
    mpz_init_set_str(g, "3", 10);
    mpz_init_set_str(y, "770", 10);  // y = (g^x) mod p
    mpz_init_set_str(x, "66", 10);
    mpz_init_set_str(m, "133", 10);
    mpz_init_set_str(rand, "4", 10);

    mpz_class p_c(p), q_c(q), g_c(g), x_c(x), y_c(y), rand_c(rand), m_c(m);

    AgoraAirgap::ElGamal::PublicKey pk(p_c, q_c, g_c, y_c);
    AgoraAirgap::ElGamal::Plaintext plaintext(m_c, pk, true);
    AgoraAirgap::ElGamal::Ciphertext ciphertext =
        AgoraAirgap::ElGamal::encrypt(pk, plaintext, rand_c);
    // alpha = (g^random) mod p  = (3^4) mod 1019 = 81
    // U = (y^random) mod p = (770^4) mod 1019 = 508
    // M = m+1 = 134
    // beta = ( U M  ) mod p = ( 508 * 134) mod 1019 = 818

    EXPECT_EQ(0, ciphertext.alpha.get_str().compare("81"));
    EXPECT_EQ(0, ciphertext.beta.get_str().compare("818"));
}

/**
 * Groups examples that should not fail
 */
class ExampleDirsTest : public ::testing::Test
{
    protected:
    void SetUp() override
    {
        this->exampleDirs = std::vector<std::string>({"example_1"});
    }
    std::vector<string> exampleDirs;
};

/**
 * Executes download_audit with correct data
 */
// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST_F(ExampleDirsTest, MockDownloadAudit)
{
    for (string & examplePath: exampleDirs)
    {
        string ballotPath = examplePath + "/ballot.json";
        auto getConfig = [&examplePath](stringstream & out, const string &) {
            return AgoraAirgap::read_file(out, examplePath + "/config");
        };
        stringstream out;
        EXPECT_NO_THROW(
            { AgoraAirgap::download_audit(out, ballotPath, getConfig); });
        EXPECT_EQ(out.str().find("Error"), string::npos)
            << "Error found in output: " << out.str() << std::endl;

        EXPECT_THAT(out.str(), HasSubstr("\n> Audit PASSED\n"))
            << std::endl
            << "Error found in output: " << out.str() << std::endl;
    }
}

/**
 * Executes download_audit with invalid data (/config-bad will yield nothing)
 */
// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST_F(ExampleDirsTest, MockBadDownloadAudit)
{
    for (string & examplePath: exampleDirs)
    {
        string ballotPath = examplePath + "/ballot.json";
        auto getConfig = [&examplePath](stringstream & out, const string &) {
            return AgoraAirgap::read_file(out, examplePath + "/config-bad");
        };
        stringstream out;
        EXPECT_THAT(
            [&]() { AgoraAirgap::download_audit(out, ballotPath, getConfig); },
            ThrowsMessage<std::runtime_error>(
                HasSubstr("!!! Error [read-file]")))
            << std::endl
            << "Error found in output: " << out.str() << std::endl;
    }
}

/**
 * Executes download only and compares downloaded file with original
 */
// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST_F(ExampleDirsTest, MockDownload)
{
    for (string & examplePath: exampleDirs)
    {
        string ballotPath = examplePath + "/ballot.json";
        auto getConfig = [&examplePath](stringstream & out, const string &) {
            return AgoraAirgap::read_file(out, examplePath + "/config");
        };
        stringstream out;
        string election_path = std::tmpnam(nullptr);
        AgoraAirgap::download(out, ballotPath, election_path, getConfig);

        EXPECT_THAT(out.str(), Not(HasSubstr("!!! Error")))
            << std::endl
            << "Error found in output: " << out.str() << std::endl;

        stringstream out2;
        string read_election_str = AgoraAirgap::read_file(out, election_path);
        string orig_election_str =
            AgoraAirgap::read_file(out, examplePath + "/config");

        EXPECT_THAT(out2.str(), Not(HasSubstr("!!! Error")))
            << std::endl
            << "Error found in output: " << out2.str() << std::endl;

        EXPECT_EQ(read_election_str, orig_election_str)
            << "Read election config does not match original" << std::endl;
    }
}

/**
 * Executes audit only
 */
// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST_F(ExampleDirsTest, MockAudit)
{
    for (string & examplePath: exampleDirs)
    {
        string ballotPath = examplePath + "/ballot.json";
        stringstream out;
        string election_path = examplePath + "/config";
        EXPECT_NO_THROW(
            { AgoraAirgap::audit(out, ballotPath, election_path); });
        EXPECT_EQ(out.str().find("Error"), string::npos)
            << "Error found in output: " << out.str() << std::endl;
        AgoraAirgap::audit(out, ballotPath, election_path);

        EXPECT_THAT(out.str(), HasSubstr("\n> Audit PASSED\n"))
            << std::endl
            << "Error found in output: " << out.str() << std::endl;

    }
}<commit_msg>fixing format<commit_after>// SPDX-FileCopyrightText: 2014 Félix Robles <felrobelv@gmail.com>
// SPDX-FileCopyrightText: 2021 Eduardo Robles <edulix@nvotes.com>
//
// SPDX-License-Identifier: AGPL-3.0-only

#include <agora-airgap/ElGamal.h>
#include <agora-airgap/encrypt.h>
#include <agora-airgap/sha256.h>
#include <cryptopp/cryptlib.h>
#include <cryptopp/elgamal.h>
#include <cryptopp/files.h>
#include <cryptopp/osrng.h>
#include <cryptopp/secblock.h>
#include <gmock/gmock.h>
#include <gmpxx.h>
#include <gtest/gtest.h>
#include <memory.h>

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>

using namespace AgoraAirgap::sha256;
using namespace CryptoPP;
using std::function;
using std::string;
using std::stringstream;
using ::testing::HasSubstr;
using ::testing::Not;
using ::testing::ThrowsMessage;

// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST(Sha256Test, StringOne)
{
    BYTE text1[] = {"abc"};
    BYTE hash1[SHA256_BLOCK_SIZE] = {
        0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40,
        0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17,
        0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad};
    BYTE buf[SHA256_BLOCK_SIZE];
    SHA256_CTX ctx;
    sha256_init(&ctx);
    sha256_update(&ctx, text1, sizeof(text1) - 1);
    sha256_final(&ctx, buf);
    EXPECT_EQ(0, memcmp(hash1, buf, SHA256_BLOCK_SIZE));
}

// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST(Sha256Test, StringTwo)
{
    BYTE text2[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"};
    BYTE hash2[SHA256_BLOCK_SIZE] = {
        0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26,
        0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff,
        0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1};
    BYTE buf[SHA256_BLOCK_SIZE];
    SHA256_CTX ctx;
    sha256_init(&ctx);
    sha256_update(&ctx, text2, sizeof(text2) - 1);
    sha256_final(&ctx, buf);
    EXPECT_EQ(0, memcmp(hash2, buf, SHA256_BLOCK_SIZE));
}

// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST(Sha256Test, StringLoopTest)
{
    BYTE text3[] = {"aaaaaaaaaa"};
    BYTE hash3[SHA256_BLOCK_SIZE] = {
        0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7,
        0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97,
        0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0};
    BYTE buf[SHA256_BLOCK_SIZE];
    SHA256_CTX ctx;
    sha256_init(&ctx);
    for (int idx = 0; idx < 100000; ++idx)
    {
        sha256_update(&ctx, text3, sizeof(text3) - 1);
    }
    sha256_final(&ctx, buf);
    EXPECT_EQ(0, memcmp(hash3, buf, SHA256_BLOCK_SIZE));
}

// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST(AgoraUnitTest, SmallMessageEncryption)
{
    mpz_t p, q, g, y, x, m, rand;

    mpz_init_set_str(p, "1019", 10);
    mpz_init_set_str(q, "509", 10);  // q = (p-1)/2 = 509
    mpz_init_set_str(g, "3", 10);
    mpz_init_set_str(y, "770", 10);  // y = (g^x) mod p
    mpz_init_set_str(x, "66", 10);
    mpz_init_set_str(m, "133", 10);
    mpz_init_set_str(rand, "4", 10);

    mpz_class p_c(p), q_c(q), g_c(g), x_c(x), y_c(y), rand_c(rand), m_c(m);

    AgoraAirgap::ElGamal::PublicKey pk(p_c, q_c, g_c, y_c);
    AgoraAirgap::ElGamal::Plaintext plaintext(m_c, pk, true);
    AgoraAirgap::ElGamal::Ciphertext ciphertext =
        AgoraAirgap::ElGamal::encrypt(pk, plaintext, rand_c);
    // alpha = (g^random) mod p  = (3^4) mod 1019 = 81
    // U = (y^random) mod p = (770^4) mod 1019 = 508
    // M = m+1 = 134
    // beta = ( U M  ) mod p = ( 508 * 134) mod 1019 = 818

    EXPECT_EQ(0, ciphertext.alpha.get_str().compare("81"));
    EXPECT_EQ(0, ciphertext.beta.get_str().compare("818"));
}

/**
 * Groups examples that should not fail
 */
class ExampleDirsTest : public ::testing::Test
{
    protected:
    void SetUp() override
    {
        this->exampleDirs = std::vector<std::string>({"example_1"});
    }
    std::vector<string> exampleDirs;
};

/**
 * Executes download_audit with correct data
 */
// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST_F(ExampleDirsTest, MockDownloadAudit)
{
    for (string & examplePath: exampleDirs)
    {
        string ballotPath = examplePath + "/ballot.json";
        auto getConfig = [&examplePath](stringstream & out, const string &) {
            return AgoraAirgap::read_file(out, examplePath + "/config");
        };
        stringstream out;
        EXPECT_NO_THROW(
            { AgoraAirgap::download_audit(out, ballotPath, getConfig); });
        EXPECT_EQ(out.str().find("Error"), string::npos)
            << "Error found in output: " << out.str() << std::endl;

        EXPECT_THAT(out.str(), HasSubstr("\n> Audit PASSED\n"))
            << std::endl
            << "Error found in output: " << out.str() << std::endl;
    }
}

/**
 * Executes download_audit with invalid data (/config-bad will yield nothing)
 */
// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST_F(ExampleDirsTest, MockBadDownloadAudit)
{
    for (string & examplePath: exampleDirs)
    {
        string ballotPath = examplePath + "/ballot.json";
        auto getConfig = [&examplePath](stringstream & out, const string &) {
            return AgoraAirgap::read_file(out, examplePath + "/config-bad");
        };
        stringstream out;
        EXPECT_THAT(
            [&]() { AgoraAirgap::download_audit(out, ballotPath, getConfig); },
            ThrowsMessage<std::runtime_error>(
                HasSubstr("!!! Error [read-file]")))
            << std::endl
            << "Error found in output: " << out.str() << std::endl;
    }
}

/**
 * Executes download only and compares downloaded file with original
 */
// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST_F(ExampleDirsTest, MockDownload)
{
    for (string & examplePath: exampleDirs)
    {
        string ballotPath = examplePath + "/ballot.json";
        auto getConfig = [&examplePath](stringstream & out, const string &) {
            return AgoraAirgap::read_file(out, examplePath + "/config");
        };
        stringstream out;
        string election_path = std::tmpnam(nullptr);
        AgoraAirgap::download(out, ballotPath, election_path, getConfig);

        EXPECT_THAT(out.str(), Not(HasSubstr("!!! Error")))
            << std::endl
            << "Error found in output: " << out.str() << std::endl;

        stringstream out2;
        string read_election_str = AgoraAirgap::read_file(out, election_path);
        string orig_election_str =
            AgoraAirgap::read_file(out, examplePath + "/config");

        EXPECT_THAT(out2.str(), Not(HasSubstr("!!! Error")))
            << std::endl
            << "Error found in output: " << out2.str() << std::endl;

        EXPECT_EQ(read_election_str, orig_election_str)
            << "Read election config does not match original" << std::endl;
    }
}

/**
 * Executes audit only
 */
// Supress warnings related to using the google test macro
// NOLINTNEXTLINE(misc-unused-parameters, readability-named-parameter)
TEST_F(ExampleDirsTest, MockAudit)
{
    for (string & examplePath: exampleDirs)
    {
        string ballotPath = examplePath + "/ballot.json";
        stringstream out;
        string election_path = examplePath + "/config";
        EXPECT_NO_THROW(
            { AgoraAirgap::audit(out, ballotPath, election_path); });
        EXPECT_EQ(out.str().find("Error"), string::npos)
            << "Error found in output: " << out.str() << std::endl;
        AgoraAirgap::audit(out, ballotPath, election_path);

        EXPECT_THAT(out.str(), HasSubstr("\n> Audit PASSED\n"))
            << std::endl
            << "Error found in output: " << out.str() << std::endl;
    }
}<|endoftext|>