<commit_before>// Copyright (c) 2016-2018 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <test/test_syscoin_services.h>
#include <util/time.h>
#include <rpc/server.h>
#include <services/asset.h>
#include <base58.h>
#include <chainparams.h>
#include <boost/test/unit_test.hpp>
#include <iterator>
#include <key.h>
using namespace std;
BOOST_GLOBAL_FIXTURE( SyscoinTestingSetup );
BOOST_FIXTURE_TEST_SUITE(syscoin_asset_allocation_tests, BasicSyscoinTestingSetup)

BOOST_AUTO_TEST_CASE(generate_asset_allocation_address_sync)
{
	UniValue r;
	printf("Running generate_asset_allocation_address_sync...\n");
	GenerateBlocks(5);
	string newaddress = GetNewFundedAddress("node1");
    BOOST_CHECK_NO_THROW(r = CallExtRPC("node1", "getnewaddress"));
    string newaddressreceiver = r.get_str();
	string guid = AssetNew("node1", newaddress, "data", "''", "8", "10000", "1000000");

	AssetSend("node1", guid, "\"[{\\\"address\\\":\\\"" + newaddressreceiver + "\\\",\\\"amount\\\":5000}]\"");
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddressreceiver ));
	UniValue balance = find_value(r.get_obj(), "balance");
	BOOST_CHECK_NO_THROW(r = CallRPC("node2", "assetallocationinfo " + guid + " " + newaddressreceiver ));
	balance = find_value(r.get_obj(), "balance");
	StopNode("node2");
	StartNode("node2");
	GenerateBlocks(5, "node2");
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddressreceiver ));
	balance = find_value(r.get_obj(), "balance");
	BOOST_CHECK_NO_THROW(r = CallRPC("node2", "assetallocationinfo " + guid + " " + newaddressreceiver ));
	balance = find_value(r.get_obj(), "balance");

}
BOOST_AUTO_TEST_CASE(generate_asset_allocation_lock)
{
    UniValue r;
    printf("Running generate_asset_allocation_lock...\n");
    GenerateBlocks(5);
    string txid;
    string newaddress1 = GetNewFundedAddress("node2");
    string newaddress = GetNewFundedAddress("node1", txid);

    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "getrawtransaction " + txid + " true" ));
    UniValue voutArray = find_value(r.get_obj(), "vout");
    int vout = 0;
    for(unsigned int i = 0;i<voutArray.size();i++){
        UniValue scriptObj = find_value(voutArray[i].get_obj(), "scriptPubKey").get_obj();
        UniValue addressesArray = find_value(scriptObj, "addresses");
        for(unsigned int j = 0;j<addressesArray.size();j++){
            if(addressesArray[j].get_str() == newaddress)
                vout = i;
        }
    }
    string voutstr = itostr(vout);
    // lock outpoint so other txs can't spend through wallet auto-selection
    BOOST_CHECK_NO_THROW(CallRPC("node1", "lockunspent false \"[{\\\"txid\\\":\\\"" + txid + "\\\",\\\"vout\\\":" + voutstr + "}]\"" ));

    string guid = AssetNew("node1", newaddress, "data","''", "8", "1", "100000");

    AssetSend("node1", guid, "\"[{\\\"address\\\":\\\"" + newaddress + "\\\",\\\"amount\\\":1}]\"");
    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddress ));
    UniValue balance = find_value(r.get_obj(), "balance");
    BOOST_CHECK_EQUAL(AssetAmountFromValue(balance, 8), 1 * COIN);

    LockAssetAllocation("node1", guid, newaddress, txid, voutstr);

    // unlock now to test spending
    BOOST_CHECK_NO_THROW(CallRPC("node1", "lockunspent true \"[{\\\"txid\\\":\\\"" + txid + "\\\",\\\"vout\\\":" + voutstr + "}]\""));
    // cannot spend as normal through sendrawtransaction
    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "createrawtransaction \"[{\\\"txid\\\":\\\"" + txid + "\\\",\\\"vout\\\":" + voutstr + "}]\" \"[{\\\"" + newaddress1 + "\\\":0.01}]\"", true, false));
	printf("createraw %s\n", r.write().c_str());
    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "signrawtransactionwithwallet " + r.get_str()));
    string hex_str = find_value(r.get_obj(), "hex").get_str();
    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "testmempoolaccept \"[\\\"" + hex_str + "\\\"]\""));
    BOOST_CHECK(find_value(r.get_array()[0].get_obj(), "allowed").get_bool());
    BOOST_CHECK_THROW(r = CallRPC("node1", "sendrawtransaction " + hex_str, true, false), runtime_error);

    string txid0 = AssetAllocationTransfer(false, "node1", guid, newaddress, "\"[{\\\"address\\\":\\\"" + newaddress1 + "\\\",\\\"amount\\\":0.11}]\"");
    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddress1 ));
    balance = find_value(r.get_obj(), "balance");
    BOOST_CHECK_EQUAL(AssetAmountFromValue(balance, 8), 0.11 * COIN);
    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "getrawtransaction " + txid0 + " true" ));
    UniValue vinArray = find_value(r.get_obj(), "vin");
    bool found = false;
    for(unsigned int i = 0;i<vinArray.size();i++){
        if(find_value(vinArray[i].get_obj(), "txid").get_str() == txid && find_value(vinArray[i].get_obj(), "vout").get_int() == vout){
            found = true;
            break;
        }
    }
    BOOST_CHECK(found);

}
BOOST_AUTO_TEST_CASE(generate_asset_allocation_send_address)
{
	UniValue r;
	printf("Running generate_asset_allocation_send_address...\n");
	GenerateBlocks(5);
    GenerateBlocks(101, "node2");
	string newaddress1 = GetNewFundedAddress("node1");
    CallRPC("node2", "sendtoaddress " + newaddress1 + " 1", true, false);
    CallRPC("node2", "sendtoaddress " + newaddress1 + " 1", true, false);
	GenerateBlocks(5);
	GenerateBlocks(5, "node2");
    BOOST_CHECK_NO_THROW(r = CallExtRPC("node1", "getnewaddress"));
    string newaddress2 = r.get_str();

	string guid = AssetNew("node1", newaddress1, "data","''", "8", "1", "100000");

	AssetSend("node1", guid, "\"[{\\\"address\\\":\\\"" + newaddress1 + "\\\",\\\"amount\\\":1}]\"");
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddress1 ));
	UniValue balance = find_value(r.get_obj(), "balance");
	BOOST_CHECK_EQUAL(AssetAmountFromValue(balance, 8), 1 * COIN);

	string txid0 = AssetAllocationTransfer(false, "node1", guid, newaddress1, "\"[{\\\"address\\\":\\\"" + newaddress2 + "\\\",\\\"amount\\\":0.11}]\"");
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddress2 ));
	balance = find_value(r.get_obj(), "balance");
	BOOST_CHECK_EQUAL(AssetAmountFromValue(balance, 8), 0.11 * COIN);

	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid0));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_NOT_FOUND);

	// send using zdag
	string txid1 = AssetAllocationTransfer(true, "node1", guid, newaddress1, "\"[{\\\"address\\\":\\\"" + newaddress2 + "\\\",\\\"amount\\\":0.12}]\"");
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddress2));
	balance = find_value(r.get_obj(), "balance_zdag");
	BOOST_CHECK_EQUAL(AssetAmountFromValue(balance, 8), 0.23 * COIN);

	// non zdag cannot be found since it was already mined, but ends up briefly in conflict state because sender is conflicted
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid0));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_MINOR_CONFLICT);

	// first tx should have to wait 1 sec for good status
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid1));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_MINOR_CONFLICT);

	// check just sender
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " ''"));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_MINOR_CONFLICT);

	// wait for 1 second as required by unit test
	MilliSleep(1000);
	// second send
	string txid2 = AssetAllocationTransfer(true, "node1", guid, newaddress1, "\"[{\\\"address\\\":\\\"" + newaddress2 + "\\\",\\\"amount\\\":0.13}]\"");
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddress2 ));
	balance = find_value(r.get_obj(), "balance_zdag");
	BOOST_CHECK_EQUAL(AssetAmountFromValue(balance, 8), 0.36 * COIN);

	// sender is conflicted so txid0 is conflicted by extension even if its not found
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid0));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_MINOR_CONFLICT);

	// first ones now OK because it was found explicitly
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid1));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_STATUS_OK);

	// second one hasn't waited enough time yet
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid2));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_MINOR_CONFLICT);

	// check just sender
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " ''"));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_MINOR_CONFLICT);

	// wait for 1.5 second to clear minor warning status
	MilliSleep(1500);
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid0));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_NOT_FOUND);

	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid1));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_STATUS_OK);

	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid2));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_STATUS_OK);

	// check just sender as well
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " ''"));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_STATUS_OK);

	// after pow, should get not found on all of them
	GenerateBlocks(1);

	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid0));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_NOT_FOUND);

	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid1));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_NOT_FOUND);

	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid2));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_NOT_FOUND);

	// check just sender as well
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " ''"));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_NOT_FOUND);
    ECC_Stop();
}
BOOST_AUTO_TEST_SUITE_END ()
<commit_msg>getstr<commit_after>// Copyright (c) 2016-2018 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <test/test_syscoin_services.h>
#include <util/time.h>
#include <rpc/server.h>
#include <services/asset.h>
#include <base58.h>
#include <chainparams.h>
#include <boost/test/unit_test.hpp>
#include <iterator>
#include <key.h>
using namespace std;
BOOST_GLOBAL_FIXTURE( SyscoinTestingSetup );
BOOST_FIXTURE_TEST_SUITE(syscoin_asset_allocation_tests, BasicSyscoinTestingSetup)

BOOST_AUTO_TEST_CASE(generate_asset_allocation_address_sync)
{
	UniValue r;
	printf("Running generate_asset_allocation_address_sync...\n");
	GenerateBlocks(5);
	string newaddress = GetNewFundedAddress("node1");
    BOOST_CHECK_NO_THROW(r = CallExtRPC("node1", "getnewaddress"));
    string newaddressreceiver = r.get_str();
	string guid = AssetNew("node1", newaddress, "data", "''", "8", "10000", "1000000");

	AssetSend("node1", guid, "\"[{\\\"address\\\":\\\"" + newaddressreceiver + "\\\",\\\"amount\\\":5000}]\"");
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddressreceiver ));
	UniValue balance = find_value(r.get_obj(), "balance");
	BOOST_CHECK_NO_THROW(r = CallRPC("node2", "assetallocationinfo " + guid + " " + newaddressreceiver ));
	balance = find_value(r.get_obj(), "balance");
	StopNode("node2");
	StartNode("node2");
	GenerateBlocks(5, "node2");
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddressreceiver ));
	balance = find_value(r.get_obj(), "balance");
	BOOST_CHECK_NO_THROW(r = CallRPC("node2", "assetallocationinfo " + guid + " " + newaddressreceiver ));
	balance = find_value(r.get_obj(), "balance");

}
BOOST_AUTO_TEST_CASE(generate_asset_allocation_lock)
{
    UniValue r;
    printf("Running generate_asset_allocation_lock...\n");
    GenerateBlocks(5);
    string txid;
    string newaddress1 = GetNewFundedAddress("node2");
    string newaddress = GetNewFundedAddress("node1", txid);

    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "getrawtransaction " + txid + " true" ));
    UniValue voutArray = find_value(r.get_obj(), "vout");
    int vout = 0;
    for(unsigned int i = 0;i<voutArray.size();i++){
        UniValue scriptObj = find_value(voutArray[i].get_obj(), "scriptPubKey").get_obj();
        UniValue addressesArray = find_value(scriptObj, "addresses");
        for(unsigned int j = 0;j<addressesArray.size();j++){
            if(addressesArray[j].get_str() == newaddress)
                vout = i;
        }
    }
    string voutstr = itostr(vout);
    // lock outpoint so other txs can't spend through wallet auto-selection
    BOOST_CHECK_NO_THROW(CallRPC("node1", "lockunspent false \"[{\\\"txid\\\":\\\"" + txid + "\\\",\\\"vout\\\":" + voutstr + "}]\"" ));

    string guid = AssetNew("node1", newaddress, "data","''", "8", "1", "100000");

    AssetSend("node1", guid, "\"[{\\\"address\\\":\\\"" + newaddress + "\\\",\\\"amount\\\":1}]\"");
    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddress ));
    UniValue balance = find_value(r.get_obj(), "balance");
    BOOST_CHECK_EQUAL(AssetAmountFromValue(balance, 8), 1 * COIN);

    LockAssetAllocation("node1", guid, newaddress, txid, voutstr);

    // unlock now to test spending
    BOOST_CHECK_NO_THROW(CallRPC("node1", "lockunspent true \"[{\\\"txid\\\":\\\"" + txid + "\\\",\\\"vout\\\":" + voutstr + "}]\""));
    // cannot spend as normal through sendrawtransaction
    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "createrawtransaction \"[{\\\"txid\\\":\\\"" + txid + "\\\",\\\"vout\\\":" + voutstr + "}]\" \"[{\\\"" + newaddress1 + "\\\":0.01}]\"", true, false));
	printf("createraw %s\n", r.get_str());
    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "signrawtransactionwithwallet " + r.get_str()));
    string hex_str = find_value(r.get_obj(), "hex").get_str();
    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "testmempoolaccept \"[\\\"" + hex_str + "\\\"]\""));
    BOOST_CHECK(find_value(r.get_array()[0].get_obj(), "allowed").get_bool());
    BOOST_CHECK_THROW(r = CallRPC("node1", "sendrawtransaction " + hex_str, true, false), runtime_error);

    string txid0 = AssetAllocationTransfer(false, "node1", guid, newaddress, "\"[{\\\"address\\\":\\\"" + newaddress1 + "\\\",\\\"amount\\\":0.11}]\"");
    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddress1 ));
    balance = find_value(r.get_obj(), "balance");
    BOOST_CHECK_EQUAL(AssetAmountFromValue(balance, 8), 0.11 * COIN);
    BOOST_CHECK_NO_THROW(r = CallRPC("node1", "getrawtransaction " + txid0 + " true" ));
    UniValue vinArray = find_value(r.get_obj(), "vin");
    bool found = false;
    for(unsigned int i = 0;i<vinArray.size();i++){
        if(find_value(vinArray[i].get_obj(), "txid").get_str() == txid && find_value(vinArray[i].get_obj(), "vout").get_int() == vout){
            found = true;
            break;
        }
    }
    BOOST_CHECK(found);

}
BOOST_AUTO_TEST_CASE(generate_asset_allocation_send_address)
{
	UniValue r;
	printf("Running generate_asset_allocation_send_address...\n");
	GenerateBlocks(5);
    GenerateBlocks(101, "node2");
	string newaddress1 = GetNewFundedAddress("node1");
    CallRPC("node2", "sendtoaddress " + newaddress1 + " 1", true, false);
    CallRPC("node2", "sendtoaddress " + newaddress1 + " 1", true, false);
	GenerateBlocks(5);
	GenerateBlocks(5, "node2");
    BOOST_CHECK_NO_THROW(r = CallExtRPC("node1", "getnewaddress"));
    string newaddress2 = r.get_str();

	string guid = AssetNew("node1", newaddress1, "data","''", "8", "1", "100000");

	AssetSend("node1", guid, "\"[{\\\"address\\\":\\\"" + newaddress1 + "\\\",\\\"amount\\\":1}]\"");
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddress1 ));
	UniValue balance = find_value(r.get_obj(), "balance");
	BOOST_CHECK_EQUAL(AssetAmountFromValue(balance, 8), 1 * COIN);

	string txid0 = AssetAllocationTransfer(false, "node1", guid, newaddress1, "\"[{\\\"address\\\":\\\"" + newaddress2 + "\\\",\\\"amount\\\":0.11}]\"");
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddress2 ));
	balance = find_value(r.get_obj(), "balance");
	BOOST_CHECK_EQUAL(AssetAmountFromValue(balance, 8), 0.11 * COIN);

	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid0));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_NOT_FOUND);

	// send using zdag
	string txid1 = AssetAllocationTransfer(true, "node1", guid, newaddress1, "\"[{\\\"address\\\":\\\"" + newaddress2 + "\\\",\\\"amount\\\":0.12}]\"");
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddress2));
	balance = find_value(r.get_obj(), "balance_zdag");
	BOOST_CHECK_EQUAL(AssetAmountFromValue(balance, 8), 0.23 * COIN);

	// non zdag cannot be found since it was already mined, but ends up briefly in conflict state because sender is conflicted
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid0));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_MINOR_CONFLICT);

	// first tx should have to wait 1 sec for good status
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid1));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_MINOR_CONFLICT);

	// check just sender
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " ''"));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_MINOR_CONFLICT);

	// wait for 1 second as required by unit test
	MilliSleep(1000);
	// second send
	string txid2 = AssetAllocationTransfer(true, "node1", guid, newaddress1, "\"[{\\\"address\\\":\\\"" + newaddress2 + "\\\",\\\"amount\\\":0.13}]\"");
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationinfo " + guid + " " + newaddress2 ));
	balance = find_value(r.get_obj(), "balance_zdag");
	BOOST_CHECK_EQUAL(AssetAmountFromValue(balance, 8), 0.36 * COIN);

	// sender is conflicted so txid0 is conflicted by extension even if its not found
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid0));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_MINOR_CONFLICT);

	// first ones now OK because it was found explicitly
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid1));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_STATUS_OK);

	// second one hasn't waited enough time yet
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid2));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_MINOR_CONFLICT);

	// check just sender
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " ''"));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_MINOR_CONFLICT);

	// wait for 1.5 second to clear minor warning status
	MilliSleep(1500);
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid0));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_NOT_FOUND);

	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid1));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_STATUS_OK);

	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid2));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_STATUS_OK);

	// check just sender as well
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " ''"));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_STATUS_OK);

	// after pow, should get not found on all of them
	GenerateBlocks(1);

	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid0));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_NOT_FOUND);

	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid1));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_NOT_FOUND);

	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " " + txid2));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_NOT_FOUND);

	// check just sender as well
	BOOST_CHECK_NO_THROW(r = CallRPC("node1", "assetallocationsenderstatus " + guid + " " + newaddress1 + " ''"));
	BOOST_CHECK_EQUAL(find_value(r.get_obj(), "status").get_int(), ZDAG_NOT_FOUND);
    ECC_Stop();
}
BOOST_AUTO_TEST_SUITE_END ()
<|endoftext|>


<commit_before>#include "stan/math/functions/logit.hpp"
#include <gtest/gtest.h>

TEST(MathFunctions, logit) {
  using stan::math::logit;
  EXPECT_FLOAT_EQ(0.0, logit(0.5));
  EXPECT_FLOAT_EQ(5.0, logit(1.0/(1.0 + exp(-5.0))));
}
<commit_msg>added NaN test for logit<commit_after>#include <stan/math/functions/logit.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <gtest/gtest.h>

TEST(MathFunctions, logit) {
  using stan::math::logit;
  EXPECT_FLOAT_EQ(0.0, logit(0.5));
  EXPECT_FLOAT_EQ(5.0, logit(1.0/(1.0 + exp(-5.0))));
}

TEST(MathFunctions, logit_nan) {
  double nan = std::numeric_limits<double>::quiet_NaN();

  EXPECT_PRED1(boost::math::isnan<double>,
               stan::math::logit(nan));
}
<|endoftext|>


<commit_before>//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// EGLMakeCurrentPerfTest:
//   Performance test for eglMakeCurrent.
//

#include "ANGLEPerfTest.h"
#include "common/platform.h"
#include "common/system_utils.h"
#include "platform/PlatformMethods.h"
#include "test_utils/angle_test_configs.h"
#include "test_utils/angle_test_instantiate.h"

#define ITERATIONS 20

using namespace testing;

namespace
{
class EGLMakeCurrentPerfTest : public ANGLEPerfTest,
                               public WithParamInterface<angle::PlatformParameters>
{
  public:
    EGLMakeCurrentPerfTest();

    void step() override;
    void SetUp() override;
    void TearDown() override;

  private:
    OSWindow *mOSWindow;
    EGLDisplay mDisplay;
    EGLSurface mSurface;
    EGLConfig mConfig;
    std::array<EGLContext, 2> mContexts;
    std::unique_ptr<angle::Library> mEGLLibrary;
};

EGLMakeCurrentPerfTest::EGLMakeCurrentPerfTest()
    : ANGLEPerfTest("EGLMakeCurrent", "", "_run", ITERATIONS),
      mOSWindow(nullptr),
      mDisplay(EGL_NO_DISPLAY),
      mSurface(EGL_NO_SURFACE),
      mConfig(nullptr),
      mContexts({})
{
    auto platform = GetParam().eglParameters;

    std::vector<EGLint> displayAttributes;
    displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
    displayAttributes.push_back(platform.renderer);
    displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
    displayAttributes.push_back(platform.majorVersion);
    displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
    displayAttributes.push_back(platform.minorVersion);
    displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
    displayAttributes.push_back(platform.deviceType);
    displayAttributes.push_back(EGL_NONE);

    mOSWindow = OSWindow::New();
    mOSWindow->initialize("EGLMakeCurrent Test", 64, 64);

    mEGLLibrary.reset(
        angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ApplicationDir));

    angle::LoadProc getProc =
        reinterpret_cast<angle::LoadProc>(mEGLLibrary->getSymbol("eglGetProcAddress"));

    if (!getProc)
    {
        abortTest();
    }
    else
    {
        angle::LoadEGL(getProc);

        if (!eglGetPlatformDisplayEXT)
        {
            abortTest();
        }
        else
        {
            mDisplay = eglGetPlatformDisplayEXT(
                EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(mOSWindow->getNativeDisplay()),
                &displayAttributes[0]);
        }
    }
}

void EGLMakeCurrentPerfTest::SetUp()
{
    ASSERT_NE(EGL_NO_DISPLAY, mDisplay);
    EGLint majorVersion, minorVersion;
    ASSERT_TRUE(eglInitialize(mDisplay, &majorVersion, &minorVersion));

    EGLint numConfigs;
    EGLint configAttrs[] = {EGL_RED_SIZE,
                            8,
                            EGL_GREEN_SIZE,
                            8,
                            EGL_BLUE_SIZE,
                            8,
                            EGL_RENDERABLE_TYPE,
                            GetParam().majorVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT,
                            EGL_SURFACE_TYPE,
                            EGL_WINDOW_BIT,
                            EGL_NONE};

    ASSERT_TRUE(eglChooseConfig(mDisplay, configAttrs, &mConfig, 1, &numConfigs));

    mContexts[0] = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, nullptr);
    ASSERT_NE(EGL_NO_CONTEXT, mContexts[0]);
    mContexts[1] = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, nullptr);
    ASSERT_NE(EGL_NO_CONTEXT, mContexts[1]);

    mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr);
    ASSERT_NE(EGL_NO_SURFACE, mSurface);
    ASSERT_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[0]));
}

void EGLMakeCurrentPerfTest::TearDown()
{
    ANGLEPerfTest::TearDown();
    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroySurface(mDisplay, mSurface);
    eglDestroyContext(mDisplay, mContexts[0]);
    eglDestroyContext(mDisplay, mContexts[1]);
}

void EGLMakeCurrentPerfTest::step()
{
    int mCurrContext = 0;
    for (int x = 0; x < ITERATIONS; x++)
    {
        mCurrContext = (mCurrContext + 1) % mContexts.size();
        eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[mCurrContext]);
    }
}

TEST_P(EGLMakeCurrentPerfTest, Run)
{
    run();
}

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLMakeCurrentPerfTest);
#if !defined(ANGLE_PLATFORM_ANDROID)
ANGLE_INSTANTIATE_TEST(EGLMakeCurrentPerfTest,
                       angle::ES2_D3D11(),
                       angle::ES2_METAL(),
                       angle::ES2_OPENGL(),
                       angle::ES2_OPENGLES(),
                       angle::ES2_VULKAN());
#else
ANGLE_INSTANTIATE_TEST(EGLMakeCurrentPerfTest, angle::ES2_D3D11());
#endif

}  // namespace
<commit_msg>Cleanup EGLMakeCurrentPerfTest instantiation<commit_after>//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// EGLMakeCurrentPerfTest:
//   Performance test for eglMakeCurrent.
//

#include "ANGLEPerfTest.h"
#include "common/platform.h"
#include "common/system_utils.h"
#include "platform/PlatformMethods.h"
#include "test_utils/angle_test_configs.h"
#include "test_utils/angle_test_instantiate.h"

#define ITERATIONS 20

using namespace testing;

namespace
{
class EGLMakeCurrentPerfTest : public ANGLEPerfTest,
                               public WithParamInterface<angle::PlatformParameters>
{
  public:
    EGLMakeCurrentPerfTest();

    void step() override;
    void SetUp() override;
    void TearDown() override;

  private:
    OSWindow *mOSWindow;
    EGLDisplay mDisplay;
    EGLSurface mSurface;
    EGLConfig mConfig;
    std::array<EGLContext, 2> mContexts;
    std::unique_ptr<angle::Library> mEGLLibrary;
};

EGLMakeCurrentPerfTest::EGLMakeCurrentPerfTest()
    : ANGLEPerfTest("EGLMakeCurrent", "", "_run", ITERATIONS),
      mOSWindow(nullptr),
      mDisplay(EGL_NO_DISPLAY),
      mSurface(EGL_NO_SURFACE),
      mConfig(nullptr),
      mContexts({})
{
    auto platform = GetParam().eglParameters;

    std::vector<EGLint> displayAttributes;
    displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
    displayAttributes.push_back(platform.renderer);
    displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
    displayAttributes.push_back(platform.majorVersion);
    displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
    displayAttributes.push_back(platform.minorVersion);
    displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
    displayAttributes.push_back(platform.deviceType);
    displayAttributes.push_back(EGL_NONE);

    mOSWindow = OSWindow::New();
    mOSWindow->initialize("EGLMakeCurrent Test", 64, 64);

    mEGLLibrary.reset(
        angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ApplicationDir));

    angle::LoadProc getProc =
        reinterpret_cast<angle::LoadProc>(mEGLLibrary->getSymbol("eglGetProcAddress"));

    if (!getProc)
    {
        abortTest();
    }
    else
    {
        angle::LoadEGL(getProc);

        if (!eglGetPlatformDisplayEXT)
        {
            abortTest();
        }
        else
        {
            mDisplay = eglGetPlatformDisplayEXT(
                EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(mOSWindow->getNativeDisplay()),
                &displayAttributes[0]);
        }
    }
}

void EGLMakeCurrentPerfTest::SetUp()
{
    ASSERT_NE(EGL_NO_DISPLAY, mDisplay);
    EGLint majorVersion, minorVersion;
    ASSERT_TRUE(eglInitialize(mDisplay, &majorVersion, &minorVersion));

    EGLint numConfigs;
    EGLint configAttrs[] = {EGL_RED_SIZE,
                            8,
                            EGL_GREEN_SIZE,
                            8,
                            EGL_BLUE_SIZE,
                            8,
                            EGL_RENDERABLE_TYPE,
                            GetParam().majorVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT,
                            EGL_SURFACE_TYPE,
                            EGL_WINDOW_BIT,
                            EGL_NONE};

    ASSERT_TRUE(eglChooseConfig(mDisplay, configAttrs, &mConfig, 1, &numConfigs));

    mContexts[0] = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, nullptr);
    ASSERT_NE(EGL_NO_CONTEXT, mContexts[0]);
    mContexts[1] = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, nullptr);
    ASSERT_NE(EGL_NO_CONTEXT, mContexts[1]);

    mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr);
    ASSERT_NE(EGL_NO_SURFACE, mSurface);
    ASSERT_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[0]));
}

void EGLMakeCurrentPerfTest::TearDown()
{
    ANGLEPerfTest::TearDown();
    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroySurface(mDisplay, mSurface);
    eglDestroyContext(mDisplay, mContexts[0]);
    eglDestroyContext(mDisplay, mContexts[1]);
}

void EGLMakeCurrentPerfTest::step()
{
    int mCurrContext = 0;
    for (int x = 0; x < ITERATIONS; x++)
    {
        mCurrContext = (mCurrContext + 1) % mContexts.size();
        eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[mCurrContext]);
    }
}

TEST_P(EGLMakeCurrentPerfTest, Run)
{
    run();
}

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLMakeCurrentPerfTest);
// We want to run this test on GL(ES) and Vulkan everywhere except Android
#if !defined(ANGLE_PLATFORM_ANDROID)
ANGLE_INSTANTIATE_TEST(EGLMakeCurrentPerfTest,
                       angle::ES2_D3D11(),
                       angle::ES2_METAL(),
                       angle::ES2_OPENGL(),
                       angle::ES2_OPENGLES(),
                       angle::ES2_VULKAN());
#endif

}  // namespace
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS sb82 (1.6.148); FILE MERGED 2007/11/07 13:00:17 sb 1.6.148.1: #i83412# Use double instead of long double literal.<commit_after><|endoftext|>


<commit_before>#include "Mocks.hpp"
// test json is valid
// test parse formatter config into formatter_config_t
// test parse sink config -//-
// test parse entire config including log name.
// test parse multiple frontends
// opt: test throw exception when frontend type not registered
// opt: test -//-                 sink -//-

class parser_t {
public:
    static std::vector<log_config_t> parse(const rapidjson::Value& root) {
//        if (root.Size() != 1) {
//            throw blackhole::error_t("");
//        }

        std::vector<log_config_t> configs;
        for (auto it = root.MemberBegin(); it != root.MemberEnd(); ++it) {
            log_config_t config;
            config.name = it->name.GetString();

            configs.push_back(config);
        }

        return configs;
    }
};

template<typename T>
T to(const boost::any& source) {
    T value;
    try {
        aux::any_to(source, value);
    } catch (boost::bad_any_cast&) {
        throw blackhole::error_t("conversion error");
    }
    return value;
}

std::string valid_cfg = R"(
{
    "root": [
        {
            "formatter": {
                "type": "string",
                "pattern": "[%(level)s]: %(message)s"
            },
            "sink": {
                "type": "files",
                "path": "test.log",
                "rotation": {
                    "pattern": "test.log.%N",
                    "backups": 5,
                    "size": 1000000
                }
            }
        }
    ]
}
)";

TEST(parser_t, NameParsing) {
    rapidjson::Document doc;
    doc.Parse<0>(valid_cfg.c_str());
    std::vector<log_config_t> configs = parser_t::parse(doc);

    ASSERT_EQ(1, configs.size());
    EXPECT_EQ("root", configs.at(0).name);
}
<commit_msg>Compatibility with GCC 4.4.<commit_after>#include "Mocks.hpp"
// test json is valid
// test parse formatter config into formatter_config_t
// test parse sink config -//-
// test parse entire config including log name.
// test parse multiple frontends
// opt: test throw exception when frontend type not registered
// opt: test -//-                 sink -//-

class parser_t {
public:
    static std::vector<log_config_t> parse(const rapidjson::Value& root) {
//        if (root.Size() != 1) {
//            throw blackhole::error_t("");
//        }

        std::vector<log_config_t> configs;
        for (auto it = root.MemberBegin(); it != root.MemberEnd(); ++it) {
            log_config_t config;
            config.name = it->name.GetString();

            configs.push_back(config);
        }

        return configs;
    }
};

template<typename T>
T to(const boost::any& source) {
    T value;
    try {
        aux::any_to(source, value);
    } catch (boost::bad_any_cast&) {
        throw blackhole::error_t("conversion error");
    }
    return value;
}

std::string valid_cfg = ""
"{"
"   \"root\": ["
"       {"
"           \"formatter\": {"
"               \"type\": \"string\","
"               \"pattern\": \"[%(level)s]: %(message)s\""
"            },"
"           \"sink\": {"
"               \"type\": \"files\","
"               \"path\": \"test.log\","
"               \"rotation\": {"
"                   \"pattern\": \"test.log.%N\","
"                   \"backups\": 5,"
"                   \"size\": 1000000"
"               }"
"           }"
"       }"
"   ]"
"}";

TEST(parser_t, NameParsing) {
    rapidjson::Document doc;
    doc.Parse<0>(valid_cfg.c_str());
    std::vector<log_config_t> configs = parser_t::parse(doc);

    ASSERT_EQ(1, configs.size());
    EXPECT_EQ("root", configs.at(0).name);
}
<|endoftext|>


<commit_before>/*
  This is a tool shipped by 'Aleph - A Library for Exploring Persistent
  Homology'.

  Given a set of persistence diagrams, it calculates their persistence
  indicator functions and---optionally---their mean indicator function
  if specified by the client.

  All files will be written to '/tmp', prefixed with 'PIF_'.
*/

#include <iostream>
#include <string>
#include <vector>

#include <getopt.h>

#include <aleph/persistenceDiagrams/PersistenceDiagram.hh>
#include <aleph/persistenceDiagrams/PersistenceIndicatorFunction.hh>

#include <aleph/persistenceDiagrams/io/Raw.hh>

#include <aleph/utilities/Filesystem.hh>

using DataType           = double;
using PersistenceDiagram = aleph::PersistenceDiagram<DataType>;

int main( int argc, char** argv )
{
  static option commandLineOptions[] =
  {
    { "mean" , no_argument, nullptr, 'm' },
    { nullptr, 0          , nullptr,  0  }
  };

  if( ( argc - optind ) < 1 )
  {
    // TODO: Show usage
    return -1;
  }

  bool calculateMean = false;

  {
    int option = 0;
    while( ( option = getopt_long( argc, argv, "m", commandLineOptions, nullptr ) ) != -1 )
    {
      switch( option )
      {
      case 'm':
        calculateMean = true;
        break;
      default:
        break;
      }
    }
  }

  // Get filenames -----------------------------------------------------

  std::vector<std::string> filenames;
  filenames.reserve( argc - optind );

  for( int i = optind; i < argc; i++ )
    filenames.push_back( argv[i] );

  // Load persistence diagrams -----------------------------------------

  std::vector<PersistenceDiagram> persistenceDiagrams;
  persistenceDiagrams.reserve( filenames.size() );

  for( auto&& filename : filenames )
  {
    std::cerr << "* Processing '" << filename << "'...";

    PersistenceDiagram persistenceDiagram = aleph::io::load<DataType>( filename );

    // FIXME: This is only required in order to ensure that the
    // persistence indicator function has a finite integral; it
    // can be solved more elegantly by using a special value to
    // indicate infinite intervals.
    persistenceDiagram.removeUnpaired();

    persistenceDiagrams.push_back( persistenceDiagram );

    std::cerr << "finished\n";
  }

  // Calculate persistence indicator functions -------------------------

  decltype( aleph::persistenceIndicatorFunction( PersistenceDiagram() ) ) mean;

  unsigned i = 0;
  for( auto&& D : persistenceDiagrams )
  {
    auto f        = aleph::persistenceIndicatorFunction( D );
    auto filename = filenames.at(i);

    if( calculateMean )
      mean += f;

    using namespace aleph::utilities;

    auto outputFilename = "/tmp/PIF_" + stem( basename( filename ) ) + ".txt";

    std::cerr << "* Writing persistence indicator function to '" << outputFilename << "'...\n";

    std::ofstream out( outputFilename );
    out << f << "\n";

    ++i;
  }

  if( calculateMean )
  {
    mean                /= static_cast<DataType>( persistenceDiagrams.size() );
    auto outputFilename  = "/tmp/PIF_mean.txt";

    std::cerr << "* Writing mean persistence indicator function to '" << outputFilename << "'...\n";

    std::ofstream out( outputFilename );
    out << mean << "\n";
  }
}
<commit_msg>Implemented sample variance calculation for persistence indicator functions<commit_after>/*
  This is a tool shipped by 'Aleph - A Library for Exploring Persistent
  Homology'.

  Given a set of persistence diagrams, it calculates their persistence
  indicator functions and---optionally---their mean indicator function
  if specified by the client.

  All files will be written to '/tmp', prefixed with 'PIF_'.
*/

#include <algorithm>
#include <iostream>
#include <limits>
#include <string>
#include <vector>

#include <getopt.h>

#include <aleph/math/KahanSummation.hh>

#include <aleph/persistenceDiagrams/PersistenceDiagram.hh>
#include <aleph/persistenceDiagrams/PersistenceIndicatorFunction.hh>

#include <aleph/persistenceDiagrams/io/Raw.hh>

#include <aleph/utilities/Filesystem.hh>

using DataType           = double;
using PersistenceDiagram = aleph::PersistenceDiagram<DataType>;

int main( int argc, char** argv )
{
  static option commandLineOptions[] =
  {
    { "mean" , no_argument, nullptr, 'm' },
    { nullptr, 0          , nullptr,  0  }
  };

  if( ( argc - optind ) < 1 )
  {
    // TODO: Show usage
    return -1;
  }

  bool calculateMean = false;

  {
    int option = 0;
    while( ( option = getopt_long( argc, argv, "m", commandLineOptions, nullptr ) ) != -1 )
    {
      switch( option )
      {
      case 'm':
        calculateMean = true;
        break;
      default:
        break;
      }
    }
  }

  // Get filenames -----------------------------------------------------

  std::vector<std::string> filenames;
  filenames.reserve( argc - optind );

  for( int i = optind; i < argc; i++ )
    filenames.push_back( argv[i] );

  // Load persistence diagrams -----------------------------------------

  std::vector<PersistenceDiagram> persistenceDiagrams;
  persistenceDiagrams.reserve( filenames.size() );

  for( auto&& filename : filenames )
  {
    std::cerr << "* Processing '" << filename << "'...";

    PersistenceDiagram persistenceDiagram = aleph::io::load<DataType>( filename );

    // FIXME: This is only required in order to ensure that the
    // persistence indicator function has a finite integral; it
    // can be solved more elegantly by using a special value to
    // indicate infinite intervals.
    persistenceDiagram.removeUnpaired();

    persistenceDiagrams.push_back( persistenceDiagram );

    std::cerr << "finished\n";
  }

  // Calculate persistence indicator functions -------------------------

  using PersistenceIndicatorFunction = decltype( aleph::persistenceIndicatorFunction( PersistenceDiagram() ) );

  std::vector<PersistenceIndicatorFunction> persistenceIndicatorFunctions;
  persistenceIndicatorFunctions.reserve( persistenceDiagrams.size() );

  PersistenceIndicatorFunction mean;

  unsigned i = 0;
  for( auto&& D : persistenceDiagrams )
  {
    auto f        = aleph::persistenceIndicatorFunction( D );
    auto filename = filenames.at(i);

    if( calculateMean )
      mean += f;

    using namespace aleph::utilities;

    auto outputFilename = "/tmp/PIF_" + stem( basename( filename ) ) + ".txt";

    std::cerr << "* Writing persistence indicator function to '" << outputFilename << "'...\n";

    std::ofstream out( outputFilename );
    out << f << "\n";

    persistenceIndicatorFunctions.emplace_back( f );

    ++i;
  }

  if( calculateMean )
  {
    mean                /= static_cast<DataType>( persistenceDiagrams.size() );
    auto outputFilename  = "/tmp/PIF_mean.txt";

    std::cerr << "* Writing mean persistence indicator function to '" << outputFilename << "'...\n";

    std::ofstream out( outputFilename );
    out << mean << "\n";

    // Since Y is supposed to be a random variable at this point, this
    // nomenclature makes sense.
    auto Y = mean.integral();

    std::cerr << "* Norm of the mean persistence indicator function: " << Y << "\n";

    std::vector<double> squaredDifferences( persistenceDiagrams.size() );

    std::transform( persistenceIndicatorFunctions.begin(), persistenceIndicatorFunctions.end(),
                    squaredDifferences.begin(),
                      [&Y] ( const PersistenceIndicatorFunction& f )
                      {
                        auto Z = f.integral();
                        return (Z-Y) * (Z-Y);
                      }
                    );

    auto s
      = aleph::math::accumulate_kahan_sorted( squaredDifferences.begin(),
                                              squaredDifferences.end(),
                                              0.0 );

    if( persistenceDiagrams.size() > 1 )
      s /= static_cast<double>( persistenceDiagrams.size() - 1 );
    else
      s = std::numeric_limits<double>::infinity();

    std::cerr << "* Sample variance: " << s << "\n";
  }
}
<|endoftext|>


<commit_before>#include "transforms/utils/CallPromotionUtils.hh"
#include "transforms/utils/BasicBlockUtils.hh"

#include "llvm/IR/CallSite.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/CallPromotionUtils.h"

using namespace llvm;

namespace previrt {
namespace transforms {
///
/// Create a sequence of if-then-else statements at the location of
/// the callsite.  The "if" condition compares the callsite's called
/// value with a function f from Callees.  The direct call to f is
/// moved to the "then" block. The "else" block contains the next
/// "if". For the last callsite's called value we don't create an
/// "else" block.
///
/// For example, the call instruction below:
///
///   orig_bb:
///     %t0 = call i32 %ptr()  with callees = {foo, bar}
///     ...
///
/// Is replaced by the following:
///
///   orig_bb:
///     %cond = icmp eq i32 ()* %ptr, @foo
///     br i1 %cond, %then_bb, %else_bb
///
///   then_bb:
///     %t1 = call i32 @foo()
///     br merge_bb
///
///   else_bb:
///     %t0 = call i32 %bar()
///     br merge_bb
///
///   merge_bb:
///     ; Uses of the original call instruction are replaced by uses of the phi
///     ; node.
///     %t2 = phi i32 [ %t0, %else_bb ], [ %t1, %then_bb ]
///     ...
///
void promoteIndirectCall(CallSite &CS, const std::vector<Function *> &Callees) {
  for (unsigned i = 0, numCallees = Callees.size(); i < numCallees; ++i) {
    // The last callee does not create an "else" block
    // If there is only one callee we don't create an "else" block either.
    if (i == numCallees - 1) {
      llvm::promoteCall(CS, Callees[i]);
    } else {
      llvm::promoteCallWithIfThenElse(CS, Callees[i]);
    }
  }
}

// Copied from llvm CallPromotionUtils
static void fixupPHINodeForNormalDest(InvokeInst *Invoke, BasicBlock *OrigBlock,
                                      BasicBlock *MergeBlock) {
  for (PHINode &Phi : Invoke->getNormalDest()->phis()) {
    int Idx = Phi.getBasicBlockIndex(OrigBlock);
    if (Idx == -1)
      continue;
    Phi.setIncomingBlock(Idx, MergeBlock);
  }
}

// Copied from llvm CallPromotionUtils
static void fixupPHINodeForUnwindDest(InvokeInst *Invoke, BasicBlock *OrigBlock,
                                      BasicBlock *ThenBlock,
                                      BasicBlock *ElseBlock) {
  for (PHINode &Phi : Invoke->getUnwindDest()->phis()) {
    int Idx = Phi.getBasicBlockIndex(OrigBlock);
    if (Idx == -1)
      continue;
    auto *V = Phi.getIncomingValue(Idx);
    Phi.setIncomingBlock(Idx, ThenBlock);
    Phi.addIncoming(V, ElseBlock);
  }
}

// Copied from llvm CallPromotionUtils
static void createRetPHINode(Instruction *OrigInst, Instruction *NewInst,
                             BasicBlock *MergeBlock, IRBuilder<> &Builder) {

  if (OrigInst->getType()->isVoidTy() || OrigInst->use_empty())
    return;

  Builder.SetInsertPoint(&MergeBlock->front());
  PHINode *Phi = Builder.CreatePHI(OrigInst->getType(), 0);
  SmallVector<User *, 16> UsersToUpdate;
  for (User *U : OrigInst->users())
    UsersToUpdate.push_back(U);
  for (User *U : UsersToUpdate)
    U->replaceUsesOfWith(OrigInst, Phi);
  Phi->addIncoming(OrigInst, OrigInst->getParent());
  Phi->addIncoming(NewInst, NewInst->getParent());
}

static void specializeCallFunctionPtrArg(CallSite &CS, unsigned ArgNo,
                                         Value *Callee) {
  auto *Arg = CS.getArgument(ArgNo);
  if (Arg->getType() != Callee->getType()) {
    Callee = CastInst::CreateBitOrPointerCast(Arg, Callee->getType(), "",
                                              CS.getInstruction());
  }
  CS.setArgument(ArgNo, Callee);
}

// Code very similar to CallPromotionUtils::versionCallSite. The
// difference is that we don't split on CS.getCalledCallue() but
// instead on CS.getArgument(ArgNo).
static Instruction *versionCallSite(CallSite CS, unsigned ArgNo, Value *Callee,
                                    MDNode *BranchWeights) {
  IRBuilder<> Builder(CS.getInstruction());
  Instruction *OrigInst = CS.getInstruction();
  BasicBlock *OrigBlock = OrigInst->getParent();

  // Create the compare. The CS.getArgument(ArgNo) value and callee must
  // have the same type to be compared.
  if (CS.getArgument(ArgNo)->getType() != Callee->getType())
    Callee = Builder.CreateBitCast(Callee, CS.getArgument(ArgNo)->getType());
  auto *Cond = Builder.CreateICmpEQ(CS.getArgument(ArgNo), Callee);

  // Create an if-then-else structure. The original instruction is moved into
  // the "else" block, and a clone of the original instruction is placed in the
  // "then" block.
  Instruction *ThenTerm = nullptr;
  Instruction *ElseTerm = nullptr;
  SplitBlockAndInsertIfThenElse(Cond, CS.getInstruction(), &ThenTerm, &ElseTerm,
                                BranchWeights);
  BasicBlock *ThenBlock = ThenTerm->getParent();
  BasicBlock *ElseBlock = ElseTerm->getParent();
  BasicBlock *MergeBlock = OrigInst->getParent();

  ThenBlock->setName("if.true.specialize_funcptr");
  ElseBlock->setName("if.false.specialize_funcptr");
  MergeBlock->setName("if.end.specialize_funcptr");

  Instruction *NewInst = OrigInst->clone();
  OrigInst->moveBefore(ElseTerm);
  NewInst->insertBefore(ThenTerm);

  // If the original call site is an invoke instruction, we have extra work to
  // do since invoke instructions are terminating. We have to fix-up phi nodes
  // in the invoke's normal and unwind destinations.
  if (auto *OrigInvoke = dyn_cast<InvokeInst>(OrigInst)) {
    auto *NewInvoke = cast<InvokeInst>(NewInst);

    // Invoke instructions are terminating, so we don't need the terminator
    // instructions that were just created.
    ThenTerm->eraseFromParent();
    ElseTerm->eraseFromParent();

    // Branch from the "merge" block to the original normal destination.
    Builder.SetInsertPoint(MergeBlock);
    Builder.CreateBr(OrigInvoke->getNormalDest());

    // Fix-up phi nodes in the original invoke's normal and unwind destinations.
    fixupPHINodeForNormalDest(OrigInvoke, OrigBlock, MergeBlock);
    fixupPHINodeForUnwindDest(OrigInvoke, MergeBlock, ThenBlock, ElseBlock);

    // Now set the normal destinations of the invoke instructions to be the
    // "merge" block.
    OrigInvoke->setNormalDest(MergeBlock);
    NewInvoke->setNormalDest(MergeBlock);
  }

  // Create a phi node for the returned value of the call site.
  createRetPHINode(OrigInst, NewInst, MergeBlock, Builder);

  return NewInst;
}

void specializeCallFunctionPtrArg(CallSite &CS, unsigned ArgNo,
                                  const std::vector<Function *> &Callees) {
  for (unsigned i = 0, numCallees = Callees.size(); i < numCallees; ++i) {
    // The last callee does not create an "else" block
    // If there is only one callee we don't create an "else" block either.
    if (i == numCallees - 1) {
      specializeCallFunctionPtrArg(CS, ArgNo, Callees[i]);
    } else {
      Function *ArgV = Callees[i];
      versionCallSite(CS, ArgNo, ArgV, nullptr);
      specializeCallFunctionPtrArg(CS, ArgNo, ArgV);
    }
  }
}

} // end namespace transforms
} // end namespace previrt
<commit_msg>fix: bitcast in the wrong direction<commit_after>#include "transforms/utils/CallPromotionUtils.hh"
#include "transforms/utils/BasicBlockUtils.hh"

#include "llvm/IR/CallSite.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/CallPromotionUtils.h"

using namespace llvm;

namespace previrt {
namespace transforms {
///
/// Create a sequence of if-then-else statements at the location of
/// the callsite.  The "if" condition compares the callsite's called
/// value with a function f from Callees.  The direct call to f is
/// moved to the "then" block. The "else" block contains the next
/// "if". For the last callsite's called value we don't create an
/// "else" block.
///
/// For example, the call instruction below:
///
///   orig_bb:
///     %t0 = call i32 %ptr()  with callees = {foo, bar}
///     ...
///
/// Is replaced by the following:
///
///   orig_bb:
///     %cond = icmp eq i32 ()* %ptr, @foo
///     br i1 %cond, %then_bb, %else_bb
///
///   then_bb:
///     %t1 = call i32 @foo()
///     br merge_bb
///
///   else_bb:
///     %t0 = call i32 %bar()
///     br merge_bb
///
///   merge_bb:
///     ; Uses of the original call instruction are replaced by uses of the phi
///     ; node.
///     %t2 = phi i32 [ %t0, %else_bb ], [ %t1, %then_bb ]
///     ...
///
void promoteIndirectCall(CallSite &CS, const std::vector<Function *> &Callees) {
  for (unsigned i = 0, numCallees = Callees.size(); i < numCallees; ++i) {
    // The last callee does not create an "else" block
    // If there is only one callee we don't create an "else" block either.
    if (i == numCallees - 1) {
      llvm::promoteCall(CS, Callees[i]);
    } else {
      llvm::promoteCallWithIfThenElse(CS, Callees[i]);
    }
  }
}

// Copied from llvm CallPromotionUtils
static void fixupPHINodeForNormalDest(InvokeInst *Invoke, BasicBlock *OrigBlock,
                                      BasicBlock *MergeBlock) {
  for (PHINode &Phi : Invoke->getNormalDest()->phis()) {
    int Idx = Phi.getBasicBlockIndex(OrigBlock);
    if (Idx == -1)
      continue;
    Phi.setIncomingBlock(Idx, MergeBlock);
  }
}

// Copied from llvm CallPromotionUtils
static void fixupPHINodeForUnwindDest(InvokeInst *Invoke, BasicBlock *OrigBlock,
                                      BasicBlock *ThenBlock,
                                      BasicBlock *ElseBlock) {
  for (PHINode &Phi : Invoke->getUnwindDest()->phis()) {
    int Idx = Phi.getBasicBlockIndex(OrigBlock);
    if (Idx == -1)
      continue;
    auto *V = Phi.getIncomingValue(Idx);
    Phi.setIncomingBlock(Idx, ThenBlock);
    Phi.addIncoming(V, ElseBlock);
  }
}

// Copied from llvm CallPromotionUtils
static void createRetPHINode(Instruction *OrigInst, Instruction *NewInst,
                             BasicBlock *MergeBlock, IRBuilder<> &Builder) {

  if (OrigInst->getType()->isVoidTy() || OrigInst->use_empty())
    return;

  Builder.SetInsertPoint(&MergeBlock->front());
  PHINode *Phi = Builder.CreatePHI(OrigInst->getType(), 0);
  SmallVector<User *, 16> UsersToUpdate;
  for (User *U : OrigInst->users())
    UsersToUpdate.push_back(U);
  for (User *U : UsersToUpdate)
    U->replaceUsesOfWith(OrigInst, Phi);
  Phi->addIncoming(OrigInst, OrigInst->getParent());
  Phi->addIncoming(NewInst, NewInst->getParent());
}

static void specializeCallFunctionPtrArg(CallSite &CS, unsigned ArgNo,
                                         Value *Callee) {
  auto *Arg = CS.getArgument(ArgNo);
  if (Arg->getType() != Callee->getType()) {
    Callee = CastInst::CreateBitOrPointerCast(Callee, Arg->getType(), "",
                                              CS.getInstruction());
  }
  CS.setArgument(ArgNo, Callee);
}

// Code very similar to CallPromotionUtils::versionCallSite. The
// difference is that we don't split on CS.getCalledCallue() but
// instead on CS.getArgument(ArgNo).
static Instruction *versionCallSite(CallSite CS, unsigned ArgNo, Value *Callee,
                                    MDNode *BranchWeights) {
  IRBuilder<> Builder(CS.getInstruction());
  Instruction *OrigInst = CS.getInstruction();
  BasicBlock *OrigBlock = OrigInst->getParent();

  // Create the compare. The CS.getArgument(ArgNo) value and callee must
  // have the same type to be compared.
  if (CS.getArgument(ArgNo)->getType() != Callee->getType())
    Callee = Builder.CreateBitCast(Callee, CS.getArgument(ArgNo)->getType());
  auto *Cond = Builder.CreateICmpEQ(CS.getArgument(ArgNo), Callee);

  // Create an if-then-else structure. The original instruction is moved into
  // the "else" block, and a clone of the original instruction is placed in the
  // "then" block.
  Instruction *ThenTerm = nullptr;
  Instruction *ElseTerm = nullptr;
  SplitBlockAndInsertIfThenElse(Cond, CS.getInstruction(), &ThenTerm, &ElseTerm,
                                BranchWeights);
  BasicBlock *ThenBlock = ThenTerm->getParent();
  BasicBlock *ElseBlock = ElseTerm->getParent();
  BasicBlock *MergeBlock = OrigInst->getParent();

  ThenBlock->setName("if.true.specialize_funcptr");
  ElseBlock->setName("if.false.specialize_funcptr");
  MergeBlock->setName("if.end.specialize_funcptr");

  Instruction *NewInst = OrigInst->clone();
  OrigInst->moveBefore(ElseTerm);
  NewInst->insertBefore(ThenTerm);

  // If the original call site is an invoke instruction, we have extra work to
  // do since invoke instructions are terminating. We have to fix-up phi nodes
  // in the invoke's normal and unwind destinations.
  if (auto *OrigInvoke = dyn_cast<InvokeInst>(OrigInst)) {
    auto *NewInvoke = cast<InvokeInst>(NewInst);

    // Invoke instructions are terminating, so we don't need the terminator
    // instructions that were just created.
    ThenTerm->eraseFromParent();
    ElseTerm->eraseFromParent();

    // Branch from the "merge" block to the original normal destination.
    Builder.SetInsertPoint(MergeBlock);
    Builder.CreateBr(OrigInvoke->getNormalDest());

    // Fix-up phi nodes in the original invoke's normal and unwind destinations.
    fixupPHINodeForNormalDest(OrigInvoke, OrigBlock, MergeBlock);
    fixupPHINodeForUnwindDest(OrigInvoke, MergeBlock, ThenBlock, ElseBlock);

    // Now set the normal destinations of the invoke instructions to be the
    // "merge" block.
    OrigInvoke->setNormalDest(MergeBlock);
    NewInvoke->setNormalDest(MergeBlock);
  }

  // Create a phi node for the returned value of the call site.
  createRetPHINode(OrigInst, NewInst, MergeBlock, Builder);

  return NewInst;
}

void specializeCallFunctionPtrArg(CallSite &CS, unsigned ArgNo,
                                  const std::vector<Function *> &Callees) {
  for (unsigned i = 0, numCallees = Callees.size(); i < numCallees; ++i) {
    // The last callee does not create an "else" block
    // If there is only one callee we don't create an "else" block either.
    if (i == numCallees - 1) {
      specializeCallFunctionPtrArg(CS, ArgNo, Callees[i]);
    } else {
      Function *ArgV = Callees[i];
      versionCallSite(CS, ArgNo, ArgV, nullptr);
      specializeCallFunctionPtrArg(CS, ArgNo, ArgV);
    }
  }
}

} // end namespace transforms
} // end namespace previrt
<|endoftext|>


<commit_before>#include "convergence/flux/multi_checker_sequential.h"

#include <memory>
#include <optional>

#include <deal.II/lac/petsc_parallel_vector.h>

#include "test_helpers/test_helper_functions.h"
#include "test_helpers/gmock_wrapper.h"
#include "convergence/flux/tests/single_checker_mock.h"

using ::testing::_;

class MultiCheckerSequentialTest : public ::testing::Test {
 protected:

  bart::convergence::flux::MultiCheckerSequential sequential_checker;

  std::unique_ptr<bart::convergence::flux::SingleCheckerI> checker_ptr;
  std::unique_ptr<bart::convergence::flux::SingleCheckerMock> checker_mock;

  bart::data::MultiFluxPtrs current;
  bart::data::MultiFluxPtrs previous;

  void SetUp() override;
  void FillGroupFluxes(bart::data::MultiFluxPtrs &to_fill, int n_ptrs);

  // Move the mock flux checker into the pointer
  void MocksToPointers() {
    checker_ptr = std::move(checker_mock);
  };
};
/* Fills a MultiFluxPtrs object with n_ptrs random flux pointers */
void MultiCheckerSequentialTest::FillGroupFluxes(
    bart::data::MultiFluxPtrs &to_fill, int n_ptrs) {

  for (int i = 0; i < n_ptrs; ++i) {
    auto flux = std::make_unique<bart::data::Flux>();
    flux->reinit(MPI_COMM_WORLD, 5, 5);

    auto random_vector = btest::RandomVector(5, 0, 2);

    for (unsigned int j = 0; j < flux->size(); ++j)
      (*flux)(j) = random_vector[j];

    flux->compress(dealii::VectorOperation::values::insert);
    to_fill[i] = std::move(flux);
  }
}

void MultiCheckerSequentialTest::SetUp() {
  // Make mock flux convergence checker
  checker_mock = std::make_unique<bart::convergence::flux::SingleCheckerMock>();
}

// Tests where there are no mock calls
class MultiCheckerSeqTestEmptyMock : public MultiCheckerSequentialTest {
 protected:
  bart::convergence::flux::MultiCheckerSequential sequential_checker;
  void SetUp() override {
    MocksToPointers();
    sequential_checker.ProvideChecker(checker_ptr);
  }
};

TEST_F(MultiCheckerSeqTestEmptyMock, Constructor) {
  // Verify constructor took ownership of the checker pointer
  EXPECT_EQ(checker_ptr, nullptr);
}

TEST_F(MultiCheckerSeqTestEmptyMock, EmptyGroups) {
  // Verify error thrown if empty fluxes provided
  EXPECT_ANY_THROW(sequential_checker.CheckIfConverged(current, previous));
}

TEST_F(MultiCheckerSeqTestEmptyMock, DifferentGroupSizes) {
  // Verify error thrown if fluxes have different numbers of flux pointers
  FillGroupFluxes(current, 5);
  FillGroupFluxes(previous, 4);
  EXPECT_ANY_THROW(sequential_checker.CheckIfConverged(current, previous));
  EXPECT_FALSE(sequential_checker.is_converged());
  EXPECT_FALSE(sequential_checker.failed_index().has_value());
  EXPECT_FALSE(sequential_checker.failed_delta().has_value());
}

TEST_F(MultiCheckerSequentialTest, GoodMatch) {
  // Verify good match
  EXPECT_CALL(*checker_mock, CheckIfConverged(_,_)).
      WillRepeatedly(::testing::Return(true));

  MocksToPointers();
  sequential_checker.ProvideChecker(checker_ptr);

  FillGroupFluxes(current, 3);
  FillGroupFluxes(previous, 3);

  EXPECT_TRUE(sequential_checker.CheckIfConverged(current, previous));
  EXPECT_TRUE(sequential_checker.is_converged());
  EXPECT_FALSE(sequential_checker.failed_index().has_value());
  EXPECT_FALSE(sequential_checker.failed_delta().has_value());
}

TEST_F(MultiCheckerSequentialTest, BadGroupMatch) {
  // Verify error if group values are not the same
  EXPECT_CALL(*checker_mock, CheckIfConverged(_,_)).
      WillRepeatedly(::testing::Return(true));

  MocksToPointers();
  sequential_checker.ProvideChecker(checker_ptr);

  FillGroupFluxes(current, 3);
  FillGroupFluxes(previous, 3);

  auto flux = current.extract(0);
  flux.key() = 6;
  current.insert(std::move(flux));

  EXPECT_ANY_THROW(sequential_checker.CheckIfConverged(current, previous));
  EXPECT_FALSE(sequential_checker.is_converged());
  EXPECT_FALSE(sequential_checker.failed_index().has_value());
  EXPECT_FALSE(sequential_checker.failed_delta().has_value());
}

TEST_F(MultiCheckerSequentialTest, BadMatch) {
  // Check if correct action on failed convergence
  EXPECT_CALL(*checker_mock, CheckIfConverged(_,_)).
      WillOnce(::testing::Return(true)).
      WillOnce(::testing::Return(false));

  EXPECT_CALL(*checker_mock, delta()).
      WillOnce(::testing::Return(std::make_optional(0.123)));

  MocksToPointers();
  sequential_checker.ProvideChecker(checker_ptr);

  FillGroupFluxes(current, 3);
  FillGroupFluxes(previous, 3);

  EXPECT_FALSE(sequential_checker.CheckIfConverged(current, previous));
  EXPECT_FALSE(sequential_checker.is_converged());
  EXPECT_TRUE(sequential_checker.failed_index().has_value());
  EXPECT_EQ(sequential_checker.failed_index().value(), 1);
  EXPECT_TRUE(sequential_checker.failed_delta().has_value());
  EXPECT_EQ(sequential_checker.failed_delta().value(), 0.123);
}
<commit_msg>updated tests for MultiCheckerSequential to indicate that delta should be reported even if converged<commit_after>#include "convergence/flux/multi_checker_sequential.h"

#include <memory>
#include <optional>

#include <deal.II/lac/petsc_parallel_vector.h>

#include "test_helpers/test_helper_functions.h"
#include "test_helpers/gmock_wrapper.h"
#include "convergence/flux/tests/single_checker_mock.h"

using ::testing::_;

class MultiCheckerSequentialTest : public ::testing::Test {
 protected:

  bart::convergence::flux::MultiCheckerSequential sequential_checker;

  std::unique_ptr<bart::convergence::flux::SingleCheckerI> checker_ptr;
  std::unique_ptr<bart::convergence::flux::SingleCheckerMock> checker_mock;

  bart::data::MultiFluxPtrs current;
  bart::data::MultiFluxPtrs previous;

  void SetUp() override;
  void FillGroupFluxes(bart::data::MultiFluxPtrs &to_fill, int n_ptrs);

  // Move the mock flux checker into the pointer
  void MocksToPointers() {
    checker_ptr = std::move(checker_mock);
  };
};
/* Fills a MultiFluxPtrs object with n_ptrs random flux pointers */
void MultiCheckerSequentialTest::FillGroupFluxes(
    bart::data::MultiFluxPtrs &to_fill, int n_ptrs) {

  for (int i = 0; i < n_ptrs; ++i) {
    auto flux = std::make_unique<bart::data::Flux>();
    flux->reinit(MPI_COMM_WORLD, 5, 5);

    auto random_vector = btest::RandomVector(5, 0, 2);

    for (unsigned int j = 0; j < flux->size(); ++j)
      (*flux)(j) = random_vector[j];

    flux->compress(dealii::VectorOperation::values::insert);
    to_fill[i] = std::move(flux);
  }
}

void MultiCheckerSequentialTest::SetUp() {
  // Make mock flux convergence checker
  checker_mock = std::make_unique<bart::convergence::flux::SingleCheckerMock>();
}

// Tests where there are no mock calls
class MultiCheckerSeqTestEmptyMock : public MultiCheckerSequentialTest {
 protected:
  bart::convergence::flux::MultiCheckerSequential sequential_checker;
  void SetUp() override {
    MocksToPointers();
    sequential_checker.ProvideChecker(checker_ptr);
  }
};

TEST_F(MultiCheckerSeqTestEmptyMock, Constructor) {
  // Verify constructor took ownership of the checker pointer
  EXPECT_EQ(checker_ptr, nullptr);
}

TEST_F(MultiCheckerSeqTestEmptyMock, EmptyGroups) {
  // Verify error thrown if empty fluxes provided
  EXPECT_ANY_THROW(sequential_checker.CheckIfConverged(current, previous));
}

TEST_F(MultiCheckerSeqTestEmptyMock, DifferentGroupSizes) {
  // Verify error thrown if fluxes have different numbers of flux pointers
  FillGroupFluxes(current, 5);
  FillGroupFluxes(previous, 4);
  EXPECT_ANY_THROW(sequential_checker.CheckIfConverged(current, previous));
  EXPECT_FALSE(sequential_checker.is_converged());
  EXPECT_FALSE(sequential_checker.failed_index().has_value());
  EXPECT_FALSE(sequential_checker.failed_delta().has_value());
}

TEST_F(MultiCheckerSequentialTest, GoodMatch) {
  // Verify good match
  EXPECT_CALL(*checker_mock, CheckIfConverged(_,_)).
      WillRepeatedly(::testing::Return(true));
  EXPECT_CALL(*checker_mock, delta()).
      WillOnce(::testing::Return(std::make_optional(0.123)));

  MocksToPointers();
  sequential_checker.ProvideChecker(checker_ptr);

  FillGroupFluxes(current, 3);
  FillGroupFluxes(previous, 3);

  EXPECT_TRUE(sequential_checker.CheckIfConverged(current, previous));
  EXPECT_TRUE(sequential_checker.is_converged());
  EXPECT_TRUE(sequential_checker.failed_delta().has_value());
  EXPECT_FALSE(sequential_checker.failed_index().has_value());
  EXPECT_DOUBLE_EQ(sequential_checker.failed_delta().value(), 0.123);
}

TEST_F(MultiCheckerSequentialTest, BadGroupMatch) {
  // Verify error if group values are not the same
  EXPECT_CALL(*checker_mock, CheckIfConverged(_,_)).
      WillRepeatedly(::testing::Return(true));

  MocksToPointers();
  sequential_checker.ProvideChecker(checker_ptr);

  FillGroupFluxes(current, 3);
  FillGroupFluxes(previous, 3);

  auto flux = current.extract(0);
  flux.key() = 6;
  current.insert(std::move(flux));

  EXPECT_ANY_THROW(sequential_checker.CheckIfConverged(current, previous));
  EXPECT_FALSE(sequential_checker.is_converged());
  EXPECT_FALSE(sequential_checker.failed_index().has_value());
  EXPECT_FALSE(sequential_checker.failed_delta().has_value());
}

TEST_F(MultiCheckerSequentialTest, BadMatch) {
  // Check if correct action on failed convergence
  EXPECT_CALL(*checker_mock, CheckIfConverged(_,_)).
      WillOnce(::testing::Return(true)).
      WillOnce(::testing::Return(false));

  EXPECT_CALL(*checker_mock, delta()).
      WillOnce(::testing::Return(std::make_optional(0.123)));

  MocksToPointers();
  sequential_checker.ProvideChecker(checker_ptr);

  FillGroupFluxes(current, 3);
  FillGroupFluxes(previous, 3);

  EXPECT_FALSE(sequential_checker.CheckIfConverged(current, previous));
  EXPECT_FALSE(sequential_checker.is_converged());
  EXPECT_TRUE(sequential_checker.failed_index().has_value());
  EXPECT_EQ(sequential_checker.failed_index().value(), 1);
  EXPECT_TRUE(sequential_checker.failed_delta().has_value());
  EXPECT_EQ(sequential_checker.failed_delta().value(), 0.123);
}
<|endoftext|>


<commit_before>/*
 *  Phusion Passenger - http://www.modrails.com/
 *  Copyright (C) 2008  Phusion
 *
 *  Phusion Passenger is a trademark of Hongli Lai & Ninh Bui.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include "Bucket.h"

static apr_status_t bucket_read(apr_bucket *a, const char **str, apr_size_t *len, apr_read_type_e block);

static const apr_bucket_type_t apr_bucket_type_passenger_pipe = {
	"PASSENGER_PIPE",
	5,
	apr_bucket_type_t::APR_BUCKET_DATA,
	apr_bucket_destroy_noop,
	bucket_read,
	apr_bucket_setaside_notimpl,
	apr_bucket_split_notimpl,
	apr_bucket_copy_notimpl
};

static apr_status_t
bucket_read(apr_bucket *bucket, const char **str, apr_size_t *len, apr_read_type_e block) {
	apr_file_t *pipe;
	char *buf;
	apr_status_t ret;
	apr_interval_time_t timeout;

	pipe = (apr_file_t *) bucket->data;
	if (block == APR_NONBLOCK_READ) {
		apr_file_pipe_timeout_get(pipe, &timeout);
		apr_file_pipe_timeout_set(pipe, 0);
	}

	*str = NULL;
	*len = APR_BUCKET_BUFF_SIZE;
	buf = (char *) apr_bucket_alloc(*len, bucket->list); // TODO: check for failure?

	ret = apr_file_read(pipe, buf, len);
	if (block == APR_NONBLOCK_READ) {
		apr_file_pipe_timeout_set(pipe, timeout);
	}

	if (ret != APR_SUCCESS && ret != APR_EOF) {
		// ... we might want to set an error flag here ...
		apr_bucket_free(buf);
		return ret;
	}
	/*
	 * If there's more to read we have to keep the rest of the pipe
	 * for later.
	 */
	if (*len > 0) {
		apr_bucket_heap *h;
		/* Change the current bucket to refer to what we read */
		bucket = apr_bucket_heap_make(bucket, buf, *len, apr_bucket_free);
		h = (apr_bucket_heap *) bucket->data;
		h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */
		*str = buf;
		APR_BUCKET_INSERT_AFTER(bucket, passenger_bucket_create(pipe, bucket->list));
	} else {
		apr_bucket_free(buf);
		bucket = apr_bucket_immortal_make(bucket, "", 0);
		*str = (const char *) bucket->data;
		// if (rv != APR_EOF) {
		//     ... we might want to set an error flag here ...
		// }
	}
	return APR_SUCCESS;
}

apr_bucket *
passenger_bucket_make(apr_bucket *bucket, apr_file_t *pipe) {
	bucket->type   = &apr_bucket_type_passenger_pipe;
	bucket->length = (apr_size_t)(-1);
	bucket->start  = -1;
	bucket->data   = pipe;
	return bucket;
}

apr_bucket *
passenger_bucket_create(apr_file_t *pipe, apr_bucket_alloc_t *list) {
	apr_bucket *bucket;

	bucket = (apr_bucket *) apr_bucket_alloc(sizeof(*bucket), list);
	APR_BUCKET_INIT(bucket);
	bucket->free = apr_bucket_free;
	bucket->list = list;
	return passenger_bucket_make(bucket, pipe);
}

<commit_msg>Properly treat EAGAIN errors when reading data from the backend application. This fixes some mysterious freeze bugs.<commit_after>/*
 *  Phusion Passenger - http://www.modrails.com/
 *  Copyright (C) 2008  Phusion
 *
 *  Phusion Passenger is a trademark of Hongli Lai & Ninh Bui.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include "Bucket.h"

static apr_status_t bucket_read(apr_bucket *a, const char **str, apr_size_t *len, apr_read_type_e block);

static const apr_bucket_type_t apr_bucket_type_passenger_pipe = {
	"PASSENGER_PIPE",
	5,
	apr_bucket_type_t::APR_BUCKET_DATA,
	apr_bucket_destroy_noop,
	bucket_read,
	apr_bucket_setaside_notimpl,
	apr_bucket_split_notimpl,
	apr_bucket_copy_notimpl
};

static apr_status_t
bucket_read(apr_bucket *bucket, const char **str, apr_size_t *len, apr_read_type_e block) {
	apr_file_t *pipe;
	char *buf;
	apr_status_t ret;
	apr_interval_time_t timeout;

	pipe = (apr_file_t *) bucket->data;
	if (block == APR_NONBLOCK_READ) {
		apr_file_pipe_timeout_get(pipe, &timeout);
		apr_file_pipe_timeout_set(pipe, 0);
	}

	*str = NULL;
	*len = APR_BUCKET_BUFF_SIZE;
	buf = (char *) apr_bucket_alloc(*len, bucket->list); // TODO: check for failure?

	do {
		ret = apr_file_read(pipe, buf, len);
	} while (APR_STATUS_IS_EAGAIN(ret));

	if (block == APR_NONBLOCK_READ) {
		apr_file_pipe_timeout_set(pipe, timeout);
	}

	if (ret != APR_SUCCESS && ret != APR_EOF) {
		// ... we might want to set an error flag here ...
		apr_bucket_free(buf);
		return ret;
	}
	/*
	 * If there's more to read we have to keep the rest of the pipe
	 * for later.
	 */
	if (*len > 0) {
		apr_bucket_heap *h;
		/* Change the current bucket to refer to what we read */
		bucket = apr_bucket_heap_make(bucket, buf, *len, apr_bucket_free);
		h = (apr_bucket_heap *) bucket->data;
		h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */
		*str = buf;
		APR_BUCKET_INSERT_AFTER(bucket, passenger_bucket_create(pipe, bucket->list));
	} else {
		apr_bucket_free(buf);
		bucket = apr_bucket_immortal_make(bucket, "", 0);
		*str = (const char *) bucket->data;
		// if (rv != APR_EOF) {
		//     ... we might want to set an error flag here ...
		// }
	}
	return APR_SUCCESS;
}

apr_bucket *
passenger_bucket_make(apr_bucket *bucket, apr_file_t *pipe) {
	bucket->type   = &apr_bucket_type_passenger_pipe;
	bucket->length = (apr_size_t)(-1);
	bucket->start  = -1;
	bucket->data   = pipe;
	return bucket;
}

apr_bucket *
passenger_bucket_create(apr_file_t *pipe, apr_bucket_alloc_t *list) {
	apr_bucket *bucket;

	bucket = (apr_bucket *) apr_bucket_alloc(sizeof(*bucket), list);
	APR_BUCKET_INIT(bucket);
	bucket->free = apr_bucket_free;
	bucket->list = list;
	return passenger_bucket_make(bucket, pipe);
}

<|endoftext|>


<commit_before><commit_msg>Fixed major bug EXT-6900(Temporary bans do not show minute countdown in Parcel Ban List) - fixed the passing of suffix argument to LLNameListCtrl::addNameItemRow(). Reviewed by Vadim Savchuk at https://codereview.productengine.com/secondlife/r/296/<commit_after><|endoftext|>


<commit_before>#pragma once

#include "numerics/polynomial.hpp"

#include "base/macros.hpp"

namespace principia {
namespace numerics {
namespace internal_polynomial {

namespace {

// The structs below are only needed because the language won't let us have (1)
// a partial specialization of a function (2) an explicit specialization of a
// member function template in an unspecialized class template.  Sigh.
// We use FORCE_INLINE because we have to write this recursively, but we really
// want linear code.

template<typename Value, typename Argument, int degree, int k>
struct HornerEvaluator {
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree>::Coefficients;

  static FORCE_INLINE NthDerivative<Value, Argument, k>
  Evaluate(Coefficients const& coefficients,
           Argument const& argument);
  static FORCE_INLINE NthDerivative<Value, Argument, k>
  EvaluateDerivative(Coefficients const& coefficients,
                     Argument const& argument);
};

template<typename Value, typename Argument, int degree>
struct HornerEvaluator<Value, Argument, degree, degree> {
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree>::Coefficients;

  static FORCE_INLINE NthDerivative<Value, Argument, degree>
  Evaluate(Coefficients const& coefficients,
           Argument const& argument);
  static FORCE_INLINE NthDerivative<Value, Argument, degree>
  EvaluateDerivative(Coefficients const& coefficients,
                     Argument const& argument);
};

template<typename Value, typename Argument, int degree, int k>
NthDerivative<Value, Argument, k>
HornerEvaluator<Value, Argument, degree, k>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<k>(coefficients) +
         argument *
         HornerEvaluator<Value, Argument, degree, k + 1>::Evaluate(
             coefficients, argument);
}

template<typename Value, typename Argument, int degree, int k>
NthDerivative<Value, Argument, k>
HornerEvaluator<Value, Argument, degree, k>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<k>(coefficients) * k +
         argument *
         HornerEvaluator<Value, Argument, degree, k + 1>::EvaluateDerivative(
             coefficients, argument);
}

template<typename Value, typename Argument, int degree>
NthDerivative<Value, Argument, degree>
HornerEvaluator<Value, Argument, degree, degree>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<degree>(coefficients);
}

template<typename Value, typename Argument, int degree>
NthDerivative<Value, Argument, degree>
HornerEvaluator<Value, Argument, degree, degree>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<degree>(coefficients) * degree;
}

}  // namespace

template<typename Value, typename Argument, int degree>
PolynomialInMonomialBasis<Value, Argument, degree>::PolynomialInMonomialBasis(
    Coefficients const& coefficients)
    : coefficients_(coefficients) {}

template<typename Value, typename Argument, int degree>
Value PolynomialInMonomialBasis<Value, Argument, degree>::Evaluate(
    Argument const& argument) const {
  return HornerEvaluator<Value, Argument, degree, 0>::Evaluate(
      coefficients_, argument);
}

template<typename Value, typename Argument, int degree>
Derivative<Value, Argument>
PolynomialInMonomialBasis<Value, Argument, degree>::EvaluateDerivative(
    Argument const& argument) const {
  return HornerEvaluator<Value, Argument, degree, 1>::EvaluateDerivative(
      coefficients_, argument);
}

}  // namespace internal_polynomial
}  // namespace numerics
}  // namespace principia
<commit_msg>Estrin is hard, the language doesn't help.<commit_after>#pragma once

#include "numerics/polynomial.hpp"

#include "base/macros.hpp"

namespace principia {
namespace numerics {
namespace internal_polynomial {

using quantities::Exponentiation;
using quantities::Square;

namespace {

// Greatest power of 2 less than or equal to n.  8 -> 8, 7 -> 4.
constexpr int flp2(int const n) {
  return n == 0 ? 0 : n == 1 ? 1 : flp2(n >> 1) << 1;
}

// Ceiling log2 of n.  8 -> 3, 7 -> 2.
constexpr int log2(int const n) {
  return n == 1 ? 0 : flp2(n >> 1) + 1;
}

// Generator for repeated squaring:
//   SquareGenerator<Length, 0>::Type is Length
//   SquareGenerator<Length, 1>::Type is Exponentiation<Length, 2>
//   SquareGenerator<Length, 2>::Type is Exponentiation<Length, 4>
//   SquareGenerator<Length, n>::Type is Exponentiation<Length, 2^n>
// etc.
template<typename Argument, int n>
struct SquareGenerator {
  using Type = Square<typename SquareGenerator<Argument, n - 1>::Type>;
};

template<typename Argument>
struct SquareGenerator<Argument, 0> {
  using Type = Argument;
};

template<typename Argument, typename>
struct SquaresGenerator;
template<typename Argument, int... orders>
struct SquaresGenerator<Argument, std::integer_sequence<int, orders...>> {
  using Type = std::tuple<typename SquareGenerator<Argument, orders>::Type...>;
};

template<typename Value, typename Argument, int degree>
struct EstrinEvaluator {
  using ArgumentSquares = typename SquaresGenerator<
      Argument,
      std::make_integer_sequence<int, log2(degree)>>::Type;
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree>::Coefficients;

  ArgumentSquares ComputeArgumentSquares(Argument const& argument);

  template<int low, int high>
  struct Subevaluator {
    static NthDerivative<Value, Argument, low>
    Evaluate(Coefficients const& coefficients,
             Argument const& argument,
             ArgumentSquares& argument_squares);
  };
};

template<typename Value, typename Argument, int degree>
template<int low, int high>
NthDerivative<Value, Argument, low>
EstrinEvaluator<Value, Argument, degree>::Subevaluator<low, high>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument,
    ArgumentSquares& argument_squares) {
  constexpr int n = flp2(high - low);
  return EstrinEvaluator::Subevaluator<low, low + n - 1>::Evaluate(
             coefficients, argument, argument_squares) +
         std::get<n>(argument_squares) *
             EstrinEvaluator::Subevaluator<low + n, high>::Evaluate(
                 coefficients, argument, argument_squares);
}

// OMG This is a specialization of a non-specialization, Cthulu comes!
template<typename Value, typename Argument, int degree>
template<int low>
NthDerivative<Value, Argument, low>
EstrinEvaluator<Value, Argument, degree>::Subevaluator<low, low>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument,
    ArgumentSquares& argument_squares) {
  return std::get<low>(coefficients);
}

// The structs below are only needed because the language won't let us have (1)
// a partial specialization of a function (2) an explicit specialization of a
// member function template in an unspecialized class template.  Sigh.
// We use FORCE_INLINE because we have to write this recursively, but we really
// want linear code.

template<typename Value, typename Argument, int degree, int k>
struct HornerEvaluator {
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree>::Coefficients;

  static FORCE_INLINE NthDerivative<Value, Argument, k>
  Evaluate(Coefficients const& coefficients,
           Argument const& argument);
  static FORCE_INLINE NthDerivative<Value, Argument, k>
  EvaluateDerivative(Coefficients const& coefficients,
                     Argument const& argument);
};

template<typename Value, typename Argument, int degree>
struct HornerEvaluator<Value, Argument, degree, degree> {
  using Coefficients =
      typename PolynomialInMonomialBasis<Value, Argument, degree>::Coefficients;

  static FORCE_INLINE NthDerivative<Value, Argument, degree>
  Evaluate(Coefficients const& coefficients,
           Argument const& argument);
  static FORCE_INLINE NthDerivative<Value, Argument, degree>
  EvaluateDerivative(Coefficients const& coefficients,
                     Argument const& argument);
};

template<typename Value, typename Argument, int degree, int k>
NthDerivative<Value, Argument, k>
HornerEvaluator<Value, Argument, degree, k>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<k>(coefficients) +
         argument *
         HornerEvaluator<Value, Argument, degree, k + 1>::Evaluate(
             coefficients, argument);
}

template<typename Value, typename Argument, int degree, int k>
NthDerivative<Value, Argument, k>
HornerEvaluator<Value, Argument, degree, k>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<k>(coefficients) * k +
         argument *
         HornerEvaluator<Value, Argument, degree, k + 1>::EvaluateDerivative(
             coefficients, argument);
}

template<typename Value, typename Argument, int degree>
NthDerivative<Value, Argument, degree>
HornerEvaluator<Value, Argument, degree, degree>::Evaluate(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<degree>(coefficients);
}

template<typename Value, typename Argument, int degree>
NthDerivative<Value, Argument, degree>
HornerEvaluator<Value, Argument, degree, degree>::EvaluateDerivative(
    Coefficients const& coefficients,
    Argument const& argument) {
  return std::get<degree>(coefficients) * degree;
}

}  // namespace

template<typename Value, typename Argument, int degree>
PolynomialInMonomialBasis<Value, Argument, degree>::PolynomialInMonomialBasis(
    Coefficients const& coefficients)
    : coefficients_(coefficients) {}

template<typename Value, typename Argument, int degree>
Value PolynomialInMonomialBasis<Value, Argument, degree>::Evaluate(
    Argument const& argument) const {
  return HornerEvaluator<Value, Argument, degree, 0>::Evaluate(
      coefficients_, argument);
}

template<typename Value, typename Argument, int degree>
Derivative<Value, Argument>
PolynomialInMonomialBasis<Value, Argument, degree>::EvaluateDerivative(
    Argument const& argument) const {
  return HornerEvaluator<Value, Argument, degree, 1>::EvaluateDerivative(
      coefficients_, argument);
}

}  // namespace internal_polynomial
}  // namespace numerics
}  // namespace principia
<|endoftext|>


<commit_before>#pragma once

#ifndef _QI_SIGNALHELPER_HPP_
#define _QI_SIGNALHELPER_HPP_

#include <qi/actor.hpp>
#include <qi/anyobject.hpp>
#include <qi/clock.hpp>
#include <qi/signal.hpp>

namespace qi
{
/**
 * @brief A tool to track signal emissions, specialized for testing.
 * A signal spy can acknowledge every signal emission of a given signal, type-erased or not.
 * Every emission is recorded, so that they can be compared to expectations, or to produce a
 * history.
 *
 * It could also be used in production code for the timeout mechanism implemented in waitUntil.
 */
class SignalSpy: public qi::Actor
{
public:
  /// Constructor taking a signal instance.
  template<typename... Args>
  SignalSpy(SignalF<void(Args...)>& signal)
    : _records()
  {
    signal.connect(strand()->schedulerFor([this](const Args&... args)
    {
      this->recordCallback(args...);
    }));
  }

  /// Constructor taking a type-erased signal.
  SignalSpy(qi::AnyObject& object, const std::string& signalOrPropertyName)
    : _records()
  {
    object.connect(
          signalOrPropertyName,
          qi::AnyFunction::fromDynamicFunction(
            strand()->schedulerFor([this](qi::AnyReferenceVector anything)
    {
      return this->recordAnyCallback(anything);
    })));
  }

  // Non-copyable
  SignalSpy(const SignalSpy&) = delete;
  SignalSpy& operator=(const SignalSpy&) = delete;

  ~SignalSpy()
  {
    strand()->join();
  }

  /// A record data, corresponding to one signal emission.
  struct Record
  {
    /// Signal arguments are stored here, in a type-erased way for compatibility.
    std::vector<qi::AnyValue> args;

    /// Use this to access an argument in the type you expect it.
    template<typename T>
    const T& arg(int index) const
    {
      return args[index].asReference().as<T>();
    }
  };

  /// Retrieve all the records in one shot.
  std::vector<Record> allRecords()
  {
    return strand()->async([this]
    { return _records;
    }).value();
  }

  /// Direct access to a record, by order of arrival.
  Record record(size_t index)
  {
    qiLogDebug("qi.signalspy") << "Getting record #" << index << " "
                               << (strand()->isInThisContext() ? "from strand" : "from outside");

    return strand()->async([this, index]
    {
      qiLogDebug("qi.signalspy") << "Getting record #" << index;
      return _records[index];
    }).value();
  }

  /// Direct access to last record.
  Record lastRecord()
  {
    return strand()->async([this]
    {
      assert(!_records.empty()); return _records.back();
    }).value();
  }

  /// The number of records.
  size_t recordCount() const
  {
    qiLogDebug("qi.signalspy") << "Getting record count "
                               << (strand()->isInThisContext() ? "from strand" : "from outside");
    return strand()->async([this]
    {
      qiLogDebug("qi.signalspy") << "Getting record count";
      return _records.size();
    }).value();
  }

  QI_API_DEPRECATED_MSG(Use 'recordCount' instead)
  unsigned int getCounter() const
  {
    return strand()->async([&]{ return static_cast<unsigned int>(_records.size()); }).value();
  }

  /// Waits for the given number of records to be reached, before the given timeout.
  qi::FutureSync<bool> waitUntil(unsigned int nofRecords, const qi::Duration& timeout) const
  {
    qi::Promise<bool> waiting;
    strand()->async([this, waiting, nofRecords, timeout]() mutable
    {
      if(nofRecords <= _records.size())
      {
        waiting.setValue(true);
        return;
      }

      qi::SignalLink recordedSubscription;

      // track timeout
      auto timingOut = strand()->asyncDelay([this, waiting, &recordedSubscription]() mutable
      {
        waiting.setValue(false);
        recorded.disconnect(recordedSubscription);
      }, timeout);

      // be called after signal emissions are recorded
      recordedSubscription = recorded.connect(strand()->schedulerFor(
      [this, waiting, &recordedSubscription, timingOut, nofRecords]() mutable
      {
        assert(nofRecords <= _records.size());
        if (nofRecords == _records.size())
        {
          waiting.setValue(true);
          timingOut.cancel();
          recorded.disconnect(recordedSubscription);
        } // no need for scheduling in the strand because it is a direct connection
      })).setCallType(qi::MetaCallType_Direct);
    });
    return waiting.future();
  }

private:
  /// The signal records.
  std::vector<Record> _records;

  /// Emitted for internal synchronziation.
  mutable qi::Signal<void> recorded;

  /// Internal generic typed callback for signals.
  template <typename... Args>
  void recordCallback(const Args&... args)
  {
    assert(strand()->isInThisContext());
    _records.emplace_back(Record{{qi::AnyValue::from<Args>(args)...}});
    recorded();
  }

  /// Internal type-erased callback for type-erased signals.
  AnyReference recordAnyCallback(const qi::AnyReferenceVector& args)
  {
    assert(strand()->isInThisContext());
    Record record;
    for (const auto& arg: args)
      record.args.emplace_back(arg.to<qi::AnyValue>());
    _records.emplace_back(std::move(record));
    recorded();
    return AnyReference();
  }
};
}

#endif
<commit_msg>SignalSpy: Fix an assert and add some const<commit_after>#pragma once

#ifndef _QI_SIGNALHELPER_HPP_
#define _QI_SIGNALHELPER_HPP_

#include <qi/actor.hpp>
#include <qi/anyobject.hpp>
#include <qi/clock.hpp>
#include <qi/signal.hpp>

namespace qi
{
/**
 * @brief A tool to track signal emissions, specialized for testing.
 * A signal spy can acknowledge every signal emission of a given signal, type-erased or not.
 * Every emission is recorded, so that they can be compared to expectations, or to produce a
 * history.
 *
 * It could also be used in production code for the timeout mechanism implemented in waitUntil.
 */
class SignalSpy: public qi::Actor
{
public:
  /// Constructor taking a signal instance.
  template<typename... Args>
  SignalSpy(SignalF<void(Args...)>& signal)
    : _records()
  {
    signal.connect(strand()->schedulerFor([this](const Args&... args)
    {
      this->recordCallback(args...);
    }));
  }

  /// Constructor taking a type-erased signal.
  SignalSpy(qi::AnyObject& object, const std::string& signalOrPropertyName)
    : _records()
  {
    object.connect(
          signalOrPropertyName,
          qi::AnyFunction::fromDynamicFunction(
            strand()->schedulerFor([this](qi::AnyReferenceVector anything)
    {
      return this->recordAnyCallback(anything);
    })));
  }

  // Non-copyable
  SignalSpy(const SignalSpy&) = delete;
  SignalSpy& operator=(const SignalSpy&) = delete;

  ~SignalSpy()
  {
    strand()->join();
  }

  /// A record data, corresponding to one signal emission.
  struct Record
  {
    /// Signal arguments are stored here, in a type-erased way for compatibility.
    std::vector<qi::AnyValue> args;

    /// Use this to access an argument in the type you expect it.
    template<typename T>
    const T& arg(int index) const
    {
      return args[index].asReference().as<T>();
    }
  };

  /// Retrieve all the records in one shot.
  std::vector<Record> allRecords() const
  {
    return strand()->async([this]
    { return _records;
    }).value();
  }

  /// Direct access to a record, by order of arrival.
  Record record(size_t index) const
  {
    qiLogDebug("qi.signalspy") << "Getting record #" << index << " "
                               << (strand()->isInThisContext() ? "from strand" : "from outside");

    return strand()->async([this, index]
    {
      qiLogDebug("qi.signalspy") << "Getting record #" << index;
      return _records[index];
    }).value();
  }

  /// Direct access to last record.
  Record lastRecord() const
  {
    return strand()->async([this]
    {
      assert(!_records.empty()); return _records.back();
    }).value();
  }

  /// The number of records.
  size_t recordCount() const
  {
    qiLogDebug("qi.signalspy") << "Getting record count "
                               << (strand()->isInThisContext() ? "from strand" : "from outside");
    return strand()->async([this]
    {
      qiLogDebug("qi.signalspy") << "Getting record count";
      return _records.size();
    }).value();
  }

  QI_API_DEPRECATED_MSG(Use 'recordCount' instead)
  unsigned int getCounter() const
  {
    return strand()->async([&]{ return static_cast<unsigned int>(_records.size()); }).value();
  }

  /// Waits for the given number of records to be reached, before the given timeout.
  qi::FutureSync<bool> waitUntil(unsigned int nofRecords, const qi::Duration& timeout) const
  {
    qi::Promise<bool> waiting;
    strand()->async([this, waiting, nofRecords, timeout]() mutable
    {
      if(nofRecords <= _records.size())
      {
        waiting.setValue(true);
        return;
      }

      qi::SignalLink recordedSubscription;

      // track timeout
      auto timingOut = strand()->asyncDelay([this, waiting, &recordedSubscription]() mutable
      {
        waiting.setValue(false);
        recorded.disconnect(recordedSubscription);
      }, timeout);

      // be called after signal emissions are recorded
      recordedSubscription = recorded.connect(strand()->schedulerFor(
      [this, waiting, &recordedSubscription, timingOut, nofRecords]() mutable
      {
        assert(nofRecords >= _records.size());
        if (nofRecords == _records.size())
        {
          waiting.setValue(true);
          timingOut.cancel();
          recorded.disconnect(recordedSubscription);
        } // no need for scheduling in the strand because it is a direct connection
      })).setCallType(qi::MetaCallType_Direct);
    });
    return waiting.future();
  }

private:
  /// The signal records.
  std::vector<Record> _records;

  /// Emitted for internal synchronziation.
  mutable qi::Signal<void> recorded;

  /// Internal generic typed callback for signals.
  template <typename... Args>
  void recordCallback(const Args&... args)
  {
    assert(strand()->isInThisContext());
    _records.emplace_back(Record{{qi::AnyValue::from<Args>(args)...}});
    recorded();
  }

  /// Internal type-erased callback for type-erased signals.
  AnyReference recordAnyCallback(const qi::AnyReferenceVector& args)
  {
    assert(strand()->isInThisContext());
    Record record;
    for (const auto& arg: args)
      record.args.emplace_back(arg.to<qi::AnyValue>());
    _records.emplace_back(std::move(record));
    recorded();
    return AnyReference();
  }
};
}

#endif
<|endoftext|>