<commit_before>#!/usr/bin/php
<?
/**
 * generate test data
 *
 * @author <NAME> <<EMAIL>>
 * @package Basisentscheid
 */


if ( $dir = dirname($_SERVER['argv'][0]) ) chdir($dir);
define('DOCROOT', "../");
require DOCROOT."inc/common_cli.php";


// delete everything
//DB::query("TRUNCATE periods CASCADE");
//DB::query("TRUNCATE members CASCADE");
//DB::query("TRUNCATE areas CASCADE");

// to aviod conflicts with existing usernames
$date = dechex(time());

// create main member
$password = crypt("<PASSWORD>");
create_member("t".$date."login");
$login = Login::$member;

$ngroup = 1;

$bcase = array(1=>0, 2=>0, 3=>0, 4=>0);
// read start branches from command line
foreach ( $_SERVER['argv'] as $key => $value ) {
	if ($key==0) continue;
	$bcase[$key] = $value;
}

// go through all cases
$case = 0;
do {
	$stopcase = 0;
	do {
		$case++;
		$stopcase++;
	} while ( ! $return = create_case_wrapper($case, $stopcase) );
} while ( $return !== "end" );


/**
 * handle case titles
 *
 * @param integer $case
 * @param integer $stopcase
 * @return mixed null after one stopcase, false after one branchcase, true after last case
 */
function create_case_wrapper($case, $stopcase) {
	global $proposal, $proposal2, $casetitle;

	$return = create_case($case, $stopcase);

	if ($casetitle) {
		echo " - ".$casetitle."\n";
		if ($proposal) {
			$proposal->title .= " - ".$casetitle;
			$proposal->update(array('title'));
		}
		if ($proposal2) {
			$proposal2->title .= " - ".$casetitle;
			$proposal2->update(array('title'));
		}
	}

	return $return;
}


/**
 * create one test case
 *
 * @param integer $case
 * @param integer $stopcase
 * @return mixed null after one stopcase, false after one branchcase, true after last case
 */
function create_case($case, $stopcase) {
	global $bcase, $date, $login, $proposal, $proposal2, $casetitle, $ngroup;

	$stop = 0;
	$branch = 0;
	$casedesc = $case." (stop: ".$stopcase.", branches:";
	foreach ($bcase as $value) $casedesc .= " ".$value;
	$casedesc .= ")";
	echo "Test case ".$casedesc."\n";

	Login::$member = $login;
	$proposal = null;
	$proposal2 = null;
	$casetitle = "";

	// create area
	$area = new Area;
	$area->ngroup = $ngroup;
	$area->name = "Test area case ".$casedesc;
	$area->create();

	// create new proposal
	$proposal = new Proposal;
	$proposal->title = "Test ".$date." case ".$casedesc;
	$proposal->content = "Test content";
	$proposal->reason = "Test reason";
	$proposal->create("Test proponent ".$date." proposal case ".$casedesc, $area->id);
	$proponents = array(Login::$member);

	if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
		$casetitle = "draft";
		return;
	}

	$issue = $proposal->issue();

	if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
		$proposal->remove_proponent(Login::$member);
		cron();
		$casetitle = "remove proponent from draft";
		return;
	}

	if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
		$proposal->remove_proponent(Login::$member);
		time_warp($issue, "1 week");
		cron();
		$casetitle = "remove proponent from draft and finally revoke proposal";
		return;
	}

	if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
		$proposal->remove_proponent(Login::$member);
		add_proponent($proposal, "px");
		time_warp($issue, "1 week");
		cron();
		$casetitle = "remove proponent from draft, add new proponent";
		return;
	}

	// add proponents
	for ( $i=2; $i<=REQUIRED_PROPONENTS; $i++ ) {
		add_proponent($proposal, "pi".$i);
		$proponents[] = Login::$member;
	}

	if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
		$casetitle = "draft with proponents";
		return;
	}

	$proposal->submit();

	if ($proposal->state=="submitted") {

		if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
			foreach ($proponents as $proponent) {
				$proposal->remove_proponent($proponent);
			}
			cron();
			$casetitle = "remove all proponents from submitted proposal";
			return;
		}

		if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
			foreach ($proponents as $proponent) {
				$proposal->remove_proponent($proponent);
			}
			for ( $i=1; $i<=REQUIRED_PROPONENTS-1; $i++ ) {
				add_proponent($proposal, "pr".$i);
			}
			time_warp($issue, "1 week");
			cron();
			$casetitle = "remove all proponents from submitted proposal, add less than required new proponents and finally revoke proposal";
			return;
		}

		if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
			foreach ($proponents as $proponent) {
				$proposal->remove_proponent($proponent);
			}
			for ( $i=1; $i<=REQUIRED_PROPONENTS; $i++ ) {
				add_proponent($proposal, "pr".$i);
			}
			time_warp($issue, "1 week");
			cron();
			$casetitle = "remove all proponents from submitted proposal, add sufficient new proponents";
			return;
		}

		$required_supporters = $proposal->quorum_required();

		${'branch'.++$branch.'_array'} = array(0, $required_supporters-1, $required_supporters);
		$supporter_count = ${'branch'.$branch.'_array'}[$bcase[$branch]];

		for ( $i=1; $i<=$supporter_count-REQUIRED_PROPONENTS; $i++ ) {
			add_supporter($proposal, "a".$i);
		}

		if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
			$casetitle = "alternative proposal with $supporter_count supporters";
			return;
		}

		if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
			time_warp($issue, CANCEL_NOT_ADMITTED_INTERVAL);
			cron();
			$casetitle = "cancel long time not admitted proposal";
			return;
		}

		// create alternative proposal
		$proposal2 = new Proposal;
		$proposal2->title = "Test ".$date." alternative proposal case ".$casedesc;
		$proposal2->content = "Test content";
		$proposal2->reason = "Test reason";
		$proposal2->issue = $proposal->issue;
		$proposal2->create("Test proponent ".$date." alternative proposal case ".$casedesc, $area->id);
		$proponents = array(Login::$member);

		if ($stopcase == ++$stop) {
			$casetitle = "alternative draft";
			return;
		}

		// add proponents
		for ( $i=1; $i<=4; $i++ ) {
			add_proponent($proposal2, "qi".$i);
			$proponents[] = Login::$member;
		}

		if ($stopcase == ++$stop) {
			$casetitle = "alternative draft with proponents";
			return;
		}

		$proposal2->submit();

		if ($proposal2->state=="submitted" and $stopcase == ++$stop) {
			foreach ($proponents as $proponent) {
				$proposal2->remove_proponent($proponent);
			}
			cron();
			$casetitle = "remove all proponents from submitted alternative proposal";
			return;
		}

		$required_supporters = $proposal2->quorum_required();

		${'branch'.++$branch.'_array'} = array(0, $required_supporters-1, $required_supporters);
		$supporter_count2 = ${'branch'.$branch.'_array'}[$bcase[$branch]];

		for ( $i=1; $i<=$supporter_count2; $i++ ) {
			add_supporter($proposal2, "a".$i);
		}

		if ($stopcase == ++$stop) {
			$casetitle = "alternative proposal with $supporter_count2 supporters";
			return;
		}

		if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
			time_warp($issue, CANCEL_NOT_ADMITTED_INTERVAL);
			cron();
			$casetitle = "cancel long time not admitted alternative proposal";
			return;
		}

		if ($proposal->state=="admitted" or $proposal2->state=="admitted") {

			// create period
			$sql = "INSERT INTO periods (debate, preparation, voting, counting, online_voting, ballot_voting, ngroup)
			VALUES (
				now() + interval '1 week',
				now() + interval '2 weeks',
				now() + interval '3 weeks',
				now() + interval '4 weeks',
				true,
				true,
				".$ngroup."
			) RETURNING id";
			$result = DB::query($sql);
			$row = DB::fetch_row($result);
			$period = $row[0];

			// assign issue to period
			$issue->period = $period;
			$issue->update(array("period"));

			// assigned, but not yet started
			cron();

			if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
				$casetitle = "assigned issue";
				return;
			}

			// move on to state "debate"
			time_warp($issue, "1 week");
			cron();

			$ballot_voting_required = $issue->quorum_ballot_voting_required();

			${'branch'.++$branch.'_array'} = array(0, $ballot_voting_required-1, $ballot_voting_required);
			$ballot_voting_demanders_count = ${'branch'.$branch.'_array'}[$bcase[$branch]];

			for ( $i=1; $i<=$ballot_voting_demanders_count; $i++ ) {
				add_ballot_voting_demander($proposal2, "a".$i);
			}

			if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
				$casetitle = "issue with $ballot_voting_demanders_count ballot voting demanders";
				return;
			}

			$proposal2->read();

			${'branch'.++$branch.'_array'} = array(false, true);
			if ( ${'branch'.$branch.'_array'}[$bcase[$branch]] and $proposal2->state!="cancelled" ) {
				// remove all proponents from alternative proposal during debate
				foreach ($proponents as $proponent) {
					$proposal2->remove_proponent($proponent);
				}
			}

			// move on to state "preparation"
			time_warp($issue, "1 week");
			cron();

			if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
				$casetitle = "issue in voting preparation state";
				return;
			}

			// move on to state "voting"
			time_warp($issue, "1 week");
			cron();

			if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
				$casetitle = "issue in voting state";
				return;
			}

			// random votes
			$proposals = $issue->proposals(true);
			$acceptance_array = array();
			$score_array = array();
			foreach ( $proposals as $proposal ) {
				$part = rand(1, 10);
				$acceptance_array[$proposal->id] = array_merge(
					array_fill(1, rand(1, 10),     -1),
					array_fill(1, pow($part,    2), 0),
					array_fill(1, pow(11-$part, 2), 1)
				);
				if (count($proposals) > 1) {
					$score_array[$proposal->id] = array_merge(
						array_fill(1, pow(rand(1, 12), 2), 0),
						array_fill(1, pow(rand(1,  3), 2), 1),
						array_fill(1, pow(rand(1,  3), 2), 2),
						array_fill(1, pow(rand(1, 12), 2), 3)
					);
				}
			}
			$sql = "SELECT * FROM members
 				JOIN members_ngroups ON members.id = members_ngroups.member
				WHERE members_ngroups.ngroup = 1 AND members.entitled = TRUE
				LIMIT ".rand(0, 100);
			$result = DB::query($sql);
			while ( Login::$member = DB::fetch_object($result, "Member") ) {
				$vote = array();
				foreach ( $proposals as $proposal ) {
					$vote[$proposal->id]['acceptance'] = $acceptance_array[$proposal->id][ array_rand($acceptance_array[$proposal->id]) ];
					if (count($proposals) > 1) {
						$vote[$proposal->id]['score'] = $score_array[$proposal->id][ array_rand($score_array[$proposal->id]) ];
					}
				}
				$token = $issue->vote_token();
				$issue->vote($token, $vote);
			}

			// move on to state "counting" and then "finished"
			time_warp($issue, "1 week");
			cron();

			if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
				$casetitle = "issue in finished state";
				return;
			}

			// move on to state "cleared"
			time_warp($issue, CLEAR_INTERVAL);
			cron();

			$casetitle = "issue in cleared state";

		} else {
			$casetitle = "no admitted proposal";
		}

	} else {
		$casetitle = "proposal not submitted";
	}

	// continue with next case if branches are still available
	for ($i=1; $i<=$branch; $i++) {
		if (isset(${'branch'.$i.'_array'}[++$bcase[$i]])) {
			for ($j=1; $j<$i; $j++) $bcase[$j]=0;
			return true;
		}
	}

	// end of last case
	return "end";
}


/**
 * return true if the case should be provided in the current branches
 *
 * @param integer $branch
 * @param array   $bcase
 * @param array   $exclude_branches (optional)
 * @return boolean
 */
function no_branch_skip($branch, array $bcase, array $exclude_branches=array()) {
	for ($b=$branch+1; $b<=count($bcase); $b++) {
		if (!in_array($b, $exclude_branches) and $bcase[$b]) return false;
	}
	return true;
}


/**
 * create a new member and let it support the supplied proposal
 *
 * @param object  $proposal
 * @param string  $i
 */
function add_supporter(Proposal $proposal, $i) {
	create_member("user".$i);
	$proposal->add_support();
}


/**
 * create a new member and let it support the supplied proposal
 *
 * @param object  $proposal
 * @param string  $i
 */
function add_proponent(Proposal $proposal, $i) {
	create_member("user".$i);
	$proposal->add_proponent(Login::$member->username, true);
}


/**
 * create a new member and let it support ballot voting for the supplied proposal
 *
 * @param object  $proposal
 * @param string  $i
 */
function add_ballot_voting_demander(Proposal $proposal, $i) {
	create_member("user".$i);
	$proposal->issue()->demand_ballot_voting();
}


/**
 * create a member once
 *
 * @param string  $username
 */
function create_member($username) {
	global $password;

	static $members = array();

	if (isset($members[$username])) {
		Login::$member = $members[$username];
		return;
	}

	Login::$member = new Member;
	Login::$member->invite = Login::generate_token(24);
	Login::$member->entitled = true;
	Login::$member->create();
	Login::$member->username = $username;
	Login::$member->password = $password;

	// Enable this only in local development environment, because it will lead to extremely many notification mails!
	//Login::$member->mail = ERROR_MAIL;

	Login::$member->update(array('username', 'password', 'entitled', 'mail'), 'activated=now()');
	DB::insert("members_ngroups", array('member'=>Login::$member->id, 'ngroup'=>1));

	// activate all notifications
	foreach ( Notification::$default_settings as $interest => $types ) {
		$fields_values = array('member'=>Login::$member->id, 'interest'=>$interest);
		foreach ( $types as $type => $value ) {
			$fields_values[$type] = true;
		}
		DB::insert_or_update("notify", $fields_values, array('member', 'interest'));
	}

	$members[$username] = Login::$member;

}


/**
 * move all times in the past to pretend we moved into the future
 *
 * @param object  $issue
 * @param string  $interval (optional)
 */
function time_warp(Issue $issue, $interval="1 hour") {
	$interval = "interval '".$interval."'";

	foreach ( array('submitted', 'admitted', 'cancelled', 'revoke') as $column ) {
		$sql = "UPDATE proposals SET
				$column = $column - $interval
			WHERE issue=".intval($issue->id)."<commit_msg>fix: disable notification mails for test users<commit_after>#!/usr/bin/php
<?
/**
 * generate test data
 *
 * @author <NAME> <<EMAIL>>
 * @package Basisentscheid
 */


if ( $dir = dirname($_SERVER['argv'][0]) ) chdir($dir);
define('DOCROOT', "../");
require DOCROOT."inc/common_cli.php";


// delete everything
//DB::query("TRUNCATE periods CASCADE");
//DB::query("TRUNCATE members CASCADE");
//DB::query("TRUNCATE areas CASCADE");

// to aviod conflicts with existing usernames
$date = dechex(time());

// create main member
$password = crypt("<PASSWORD>");
create_member("t".$date."login");
$login = Login::$member;

$ngroup = 1;

$bcase = array(1=>0, 2=>0, 3=>0, 4=>0);
// read start branches from command line
foreach ( $_SERVER['argv'] as $key => $value ) {
	if ($key==0) continue;
	$bcase[$key] = $value;
}

// go through all cases
$case = 0;
do {
	$stopcase = 0;
	do {
		$case++;
		$stopcase++;
	} while ( ! $return = create_case_wrapper($case, $stopcase) );
} while ( $return !== "end" );


/**
 * handle case titles
 *
 * @param integer $case
 * @param integer $stopcase
 * @return mixed null after one stopcase, false after one branchcase, true after last case
 */
function create_case_wrapper($case, $stopcase) {
	global $proposal, $proposal2, $casetitle;

	$return = create_case($case, $stopcase);

	if ($casetitle) {
		echo " - ".$casetitle."\n";
		if ($proposal) {
			$proposal->title .= " - ".$casetitle;
			$proposal->update(array('title'));
		}
		if ($proposal2) {
			$proposal2->title .= " - ".$casetitle;
			$proposal2->update(array('title'));
		}
	}

	return $return;
}


/**
 * create one test case
 *
 * @param integer $case
 * @param integer $stopcase
 * @return mixed null after one stopcase, false after one branchcase, true after last case
 */
function create_case($case, $stopcase) {
	global $bcase, $date, $login, $proposal, $proposal2, $casetitle, $ngroup;

	$stop = 0;
	$branch = 0;
	$casedesc = $case." (stop: ".$stopcase.", branches:";
	foreach ($bcase as $value) $casedesc .= " ".$value;
	$casedesc .= ")";
	echo "Test case ".$casedesc."\n";

	Login::$member = $login;
	$proposal = null;
	$proposal2 = null;
	$casetitle = "";

	// create area
	$area = new Area;
	$area->ngroup = $ngroup;
	$area->name = "Test area case ".$casedesc;
	$area->create();

	// create new proposal
	$proposal = new Proposal;
	$proposal->title = "Test ".$date." case ".$casedesc;
	$proposal->content = "Test content";
	$proposal->reason = "Test reason";
	$proposal->create("Test proponent ".$date." proposal case ".$casedesc, $area->id);
	$proponents = array(Login::$member);

	if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
		$casetitle = "draft";
		return;
	}

	$issue = $proposal->issue();

	if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
		$proposal->remove_proponent(Login::$member);
		cron();
		$casetitle = "remove proponent from draft";
		return;
	}

	if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
		$proposal->remove_proponent(Login::$member);
		time_warp($issue, "1 week");
		cron();
		$casetitle = "remove proponent from draft and finally revoke proposal";
		return;
	}

	if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
		$proposal->remove_proponent(Login::$member);
		add_proponent($proposal, "px");
		time_warp($issue, "1 week");
		cron();
		$casetitle = "remove proponent from draft, add new proponent";
		return;
	}

	// add proponents
	for ( $i=2; $i<=REQUIRED_PROPONENTS; $i++ ) {
		add_proponent($proposal, "pi".$i);
		$proponents[] = Login::$member;
	}

	if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
		$casetitle = "draft with proponents";
		return;
	}

	$proposal->submit();

	if ($proposal->state=="submitted") {

		if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
			foreach ($proponents as $proponent) {
				$proposal->remove_proponent($proponent);
			}
			cron();
			$casetitle = "remove all proponents from submitted proposal";
			return;
		}

		if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
			foreach ($proponents as $proponent) {
				$proposal->remove_proponent($proponent);
			}
			for ( $i=1; $i<=REQUIRED_PROPONENTS-1; $i++ ) {
				add_proponent($proposal, "pr".$i);
			}
			time_warp($issue, "1 week");
			cron();
			$casetitle = "remove all proponents from submitted proposal, add less than required new proponents and finally revoke proposal";
			return;
		}

		if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
			foreach ($proponents as $proponent) {
				$proposal->remove_proponent($proponent);
			}
			for ( $i=1; $i<=REQUIRED_PROPONENTS; $i++ ) {
				add_proponent($proposal, "pr".$i);
			}
			time_warp($issue, "1 week");
			cron();
			$casetitle = "remove all proponents from submitted proposal, add sufficient new proponents";
			return;
		}

		$required_supporters = $proposal->quorum_required();

		${'branch'.++$branch.'_array'} = array(0, $required_supporters-1, $required_supporters);
		$supporter_count = ${'branch'.$branch.'_array'}[$bcase[$branch]];

		for ( $i=1; $i<=$supporter_count-REQUIRED_PROPONENTS; $i++ ) {
			add_supporter($proposal, "a".$i);
		}

		if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
			$casetitle = "alternative proposal with $supporter_count supporters";
			return;
		}

		if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
			time_warp($issue, CANCEL_NOT_ADMITTED_INTERVAL);
			cron();
			$casetitle = "cancel long time not admitted proposal";
			return;
		}

		// create alternative proposal
		$proposal2 = new Proposal;
		$proposal2->title = "Test ".$date." alternative proposal case ".$casedesc;
		$proposal2->content = "Test content";
		$proposal2->reason = "Test reason";
		$proposal2->issue = $proposal->issue;
		$proposal2->create("Test proponent ".$date." alternative proposal case ".$casedesc, $area->id);
		$proponents = array(Login::$member);

		if ($stopcase == ++$stop) {
			$casetitle = "alternative draft";
			return;
		}

		// add proponents
		for ( $i=1; $i<=4; $i++ ) {
			add_proponent($proposal2, "qi".$i);
			$proponents[] = Login::$member;
		}

		if ($stopcase == ++$stop) {
			$casetitle = "alternative draft with proponents";
			return;
		}

		$proposal2->submit();

		if ($proposal2->state=="submitted" and $stopcase == ++$stop) {
			foreach ($proponents as $proponent) {
				$proposal2->remove_proponent($proponent);
			}
			cron();
			$casetitle = "remove all proponents from submitted alternative proposal";
			return;
		}

		$required_supporters = $proposal2->quorum_required();

		${'branch'.++$branch.'_array'} = array(0, $required_supporters-1, $required_supporters);
		$supporter_count2 = ${'branch'.$branch.'_array'}[$bcase[$branch]];

		for ( $i=1; $i<=$supporter_count2; $i++ ) {
			add_supporter($proposal2, "a".$i);
		}

		if ($stopcase == ++$stop) {
			$casetitle = "alternative proposal with $supporter_count2 supporters";
			return;
		}

		if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
			time_warp($issue, CANCEL_NOT_ADMITTED_INTERVAL);
			cron();
			$casetitle = "cancel long time not admitted alternative proposal";
			return;
		}

		if ($proposal->state=="admitted" or $proposal2->state=="admitted") {

			// create period
			$sql = "INSERT INTO periods (debate, preparation, voting, counting, online_voting, ballot_voting, ngroup)
			VALUES (
				now() + interval '1 week',
				now() + interval '2 weeks',
				now() + interval '3 weeks',
				now() + interval '4 weeks',
				true,
				true,
				".$ngroup."
			) RETURNING id";
			$result = DB::query($sql);
			$row = DB::fetch_row($result);
			$period = $row[0];

			// assign issue to period
			$issue->period = $period;
			$issue->update(array("period"));

			// assigned, but not yet started
			cron();

			if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
				$casetitle = "assigned issue";
				return;
			}

			// move on to state "debate"
			time_warp($issue, "1 week");
			cron();

			$ballot_voting_required = $issue->quorum_ballot_voting_required();

			${'branch'.++$branch.'_array'} = array(0, $ballot_voting_required-1, $ballot_voting_required);
			$ballot_voting_demanders_count = ${'branch'.$branch.'_array'}[$bcase[$branch]];

			for ( $i=1; $i<=$ballot_voting_demanders_count; $i++ ) {
				add_ballot_voting_demander($proposal2, "a".$i);
			}

			if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
				$casetitle = "issue with $ballot_voting_demanders_count ballot voting demanders";
				return;
			}

			$proposal2->read();

			${'branch'.++$branch.'_array'} = array(false, true);
			if ( ${'branch'.$branch.'_array'}[$bcase[$branch]] and $proposal2->state!="cancelled" ) {
				// remove all proponents from alternative proposal during debate
				foreach ($proponents as $proponent) {
					$proposal2->remove_proponent($proponent);
				}
			}

			// move on to state "preparation"
			time_warp($issue, "1 week");
			cron();

			if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
				$casetitle = "issue in voting preparation state";
				return;
			}

			// move on to state "voting"
			time_warp($issue, "1 week");
			cron();

			if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
				$casetitle = "issue in voting state";
				return;
			}

			// random votes
			$proposals = $issue->proposals(true);
			$acceptance_array = array();
			$score_array = array();
			foreach ( $proposals as $proposal ) {
				$part = rand(1, 10);
				$acceptance_array[$proposal->id] = array_merge(
					array_fill(1, rand(1, 10),     -1),
					array_fill(1, pow($part,    2), 0),
					array_fill(1, pow(11-$part, 2), 1)
				);
				if (count($proposals) > 1) {
					$score_array[$proposal->id] = array_merge(
						array_fill(1, pow(rand(1, 12), 2), 0),
						array_fill(1, pow(rand(1,  3), 2), 1),
						array_fill(1, pow(rand(1,  3), 2), 2),
						array_fill(1, pow(rand(1, 12), 2), 3)
					);
				}
			}
			$sql = "SELECT * FROM members
 				JOIN members_ngroups ON members.id = members_ngroups.member
				WHERE members_ngroups.ngroup = 1 AND members.entitled = TRUE
				LIMIT ".rand(0, 100);
			$result = DB::query($sql);
			while ( Login::$member = DB::fetch_object($result, "Member") ) {
				$vote = array();
				foreach ( $proposals as $proposal ) {
					$vote[$proposal->id]['acceptance'] = $acceptance_array[$proposal->id][ array_rand($acceptance_array[$proposal->id]) ];
					if (count($proposals) > 1) {
						$vote[$proposal->id]['score'] = $score_array[$proposal->id][ array_rand($score_array[$proposal->id]) ];
					}
				}
				$token = $issue->vote_token();
				$issue->vote($token, $vote);
			}

			// move on to state "counting" and then "finished"
			time_warp($issue, "1 week");
			cron();

			if (no_branch_skip($branch, $bcase) and $stopcase == ++$stop) {
				$casetitle = "issue in finished state";
				return;
			}

			// move on to state "cleared"
			time_warp($issue, CLEAR_INTERVAL);
			cron();

			$casetitle = "issue in cleared state";

		} else {
			$casetitle = "no admitted proposal";
		}

	} else {
		$casetitle = "proposal not submitted";
	}

	// continue with next case if branches are still available
	for ($i=1; $i<=$branch; $i++) {
		if (isset(${'branch'.$i.'_array'}[++$bcase[$i]])) {
			for ($j=1; $j<$i; $j++) $bcase[$j]=0;
			return true;
		}
	}

	// end of last case
	return "end";
}


/**
 * return true if the case should be provided in the current branches
 *
 * @param integer $branch
 * @param array   $bcase
 * @param array   $exclude_branches (optional)
 * @return boolean
 */
function no_branch_skip($branch, array $bcase, array $exclude_branches=array()) {
	for ($b=$branch+1; $b<=count($bcase); $b++) {
		if (!in_array($b, $exclude_branches) and $bcase[$b]) return false;
	}
	return true;
}


/**
 * create a new member and let it support the supplied proposal
 *
 * @param object  $proposal
 * @param string  $i
 */
function add_supporter(Proposal $proposal, $i) {
	create_member("user".$i);
	$proposal->add_support();
}


/**
 * create a new member and let it support the supplied proposal
 *
 * @param object  $proposal
 * @param string  $i
 */
function add_proponent(Proposal $proposal, $i) {
	create_member("user".$i);
	$proposal->add_proponent(Login::$member->username, true);
}


/**
 * create a new member and let it support ballot voting for the supplied proposal
 *
 * @param object  $proposal
 * @param string  $i
 */
function add_ballot_voting_demander(Proposal $proposal, $i) {
	create_member("user".$i);
	$proposal->issue()->demand_ballot_voting();
}


/**
 * create a member once
 *
 * @param string  $username
 */
function create_member($username) {
	global $password;

	static $members = array();

	if (isset($members[$username])) {
		Login::$member = $members[$username];
		return;
	}

	Login::$member = new Member;
	Login::$member->invite = Login::generate_token(24);
	Login::$member->entitled = true;
	Login::$member->create();
	Login::$member->username = $username;
	Login::$member->password = $password;
	$update_fields = array('username', 'password', '<PASSWORD>');

	// Enable this only in local development environment, because it will lead to extremely many notification mails!
	//Login::$member->mail = ERROR_MAIL;
	//$update_fields[] = "mail";

	Login::$member->update($update_fields, 'activated=now()');
	DB::insert("members_ngroups", array('member'=>Login::$member->id, 'ngroup'=>1));

	// activate all notifications
	foreach ( Notification::$default_settings as $interest => $types ) {
		$fields_values = array('member'=>Login::$member->id, 'interest'=>$interest);
		foreach ( $types as $type => $value ) {
			$fields_values[$type] = true;
		}
		DB::insert_or_update("notify", $fields_values, array('member', 'interest'));
	}

	$members[$username] = Login::$member;

}


/**
 * move all times in the past to pretend we moved into the future
 *
 * @param object  $issue
 * @param string  $interval (optional)
 */
function time_warp(Issue $issue, $interval="1 hour") {
	$interval = "interval '".$interval."'";

	foreach ( array('submitted', 'admitted', 'cancelled', 'revoke') as $column ) {
		$sql = "UPDATE proposals SET
				$column = $column - $interval
			WHERE issue=".intval($issue->id)."
{'fraction_non_alphanumeric': 0.1822200219243962, 'fraction_numerical': 0.0086283107606351, 'mean_word_length': 4.06084466714388, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 172, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4685598', 'n_tokens_mistral': 11192, 'n_tokens_neox': 9977, 'n_words': 2338}