<commit_before>#include "Entity.hpp"
#include "EntityScheme.hpp"
#include "EntityManager.hpp"
#include "EntitySchemeManager.hpp"
#include "EntityCallback.hpp"
#include "EntityFieldType.hpp"
#include "Action.hpp"
#include "ClientRepo.hpp"
#include "../inanity/script/np/Any.hpp"
#include "../inanity/script/np/State.hpp"
#include "../inanity/MemoryFile.hpp"
#include "../inanity/Exception.hpp"

BEGIN_INANITY_OIL

Entity::Entity(ptr<EntityManager> manager, const EntityId& id)
: manager(manager), id(id)
{
	manager->OnNewEntity(id, this);
}

Entity::~Entity()
{
	manager->OnFreeEntity(id);
}

ptr<EntityManager> Entity::GetManager() const
{
	return manager;
}

EntityId Entity::GetId() const
{
	return id;
}

ptr<EntityScheme> Entity::GetScheme() const
{
	return scheme;
}

void Entity::SetScheme(ptr<EntityScheme> scheme)
{
	this->scheme = scheme;
}

void Entity::OnNewCallback(EntityCallback* callback)
{
	callbacks.push_back(callback);
}

void Entity::OnFreeCallback(EntityCallback* callback)
{
	for(size_t i = 0; i < callbacks.size(); ++i)
		if(callbacks[i] == callback)
		{
			callbacks.erase(callbacks.begin() + i);
			return;
		}

	THROW("Entity callback already freed");
}

ptr<File> Entity::GetFullTagKey(const EntityTagId& tagId) const
{
	ptr<MemoryFile> key = NEW(MemoryFile(EntityId::size + 1 + EntityTagId::size));
	char* keyData = (char*)key->GetData();
	memcpy(keyData, id.data, EntityId::size);
	keyData[EntityId::size] = 't';
	memcpy(keyData + EntityId::size + 1, tagId.data, EntityTagId::size);
	return key;
}

ptr<File> Entity::GetFullFieldKey(int fieldIndex) const
{
	if(fieldIndex >= (1 << 16))
		THROW("Too big field index");

	ptr<MemoryFile> key = NEW(MemoryFile(EntityId::size + 1 + 2));
	char* keyData = (char*)key->GetData();
	memcpy(keyData, id.data, EntityId::size);
	keyData[EntityId::size] = 'f';
	keyData[EntityId::size + 1] = fieldIndex & 0xff;
	keyData[EntityId::size + 2] = (fieldIndex >> 8) & 0xff;

	return key;
}

ptr<File> Entity::GetFullDataKey(const void* nameData, size_t nameSize) const
{
	ptr<MemoryFile> key = NEW(MemoryFile(EntityId::size + 1 + nameSize));
	char* keyData = (char*)key->GetData();
	memcpy(keyData, id.data, EntityId::size);
	keyData[EntityId::size] = 'd';
	memcpy(keyData + EntityId::size + 1, nameData, nameSize);

	return key;
}

int Entity::TryParseFieldKey(const void* data, size_t size)
{
	if(size != 2)
		return -1;

	const unsigned char* d = (const unsigned char*)data;
	return d[0] | (d[1] << 8);
}

void Entity::OnChange(const void* keyData, size_t keySize, ptr<File> value)
{
	if(!scheme)
		return;

	// if this is a main entity key (scheme key)
	if(!keySize)
	{
		// value should be entity scheme id and has appropriate size
		// if it not, think like there is no scheme
		ptr<EntityScheme> newScheme;
		if(value->GetSize() == EntitySchemeId::size)
			newScheme = manager->GetSchemeManager()->TryGet(EntitySchemeId::FromData(value->GetData()));

		// if scheme doesn't match
		if(scheme != newScheme)
		{
			// remember it
			scheme = newScheme;
			// fire callbacks
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireScheme(scheme);
		}

		return;
	}

	// the rest is entity's tags, fields or data
	switch(*(const char*)keyData)
	{
	case 't':
		{
			if(keySize != EntityTagId::size + 1)
				break;
			EntityTagId tagId = EntityTagId::FromData((const char*)keyData + 1);
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireTag(tagId, value);
		}
		break;
	case 'f':
		{
			int fieldIndex = TryParseFieldKey((const char*)keyData + 1, keySize - 1);
			if(fieldIndex < 0)
				break;
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireField(fieldIndex, value);
		}
		break;
	case 'd':
		{
			ptr<File> key = MemoryFile::CreateViaCopy((const char*)keyData + 1, keySize - 1);
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireData(key, value);
		}
		break;
	}
}

ptr<File> Entity::ReadTag(const EntityTagId& tagId) const
{
	if(!scheme)
		return nullptr;

	return manager->GetRepo()->GetValue(GetFullTagKey(tagId));
}

void Entity::WriteTag(ptr<Action> action, const EntityTagId& tagId, ptr<File> tagData)
{
	if(!scheme)
		return;

	action->AddChange(GetFullTagKey(tagId), tagData);
}

ptr<File> Entity::RawReadField(int fieldIndex) const
{
	if(!scheme)
		return nullptr;

	return manager->GetRepo()->GetValue(GetFullFieldKey(fieldIndex));
}

void Entity::RawWriteField(ptr<Action> action, int fieldIndex, ptr<File> value)
{
	if(!scheme)
		return;

	action->AddChange(GetFullFieldKey(fieldIndex), value);
}

void Entity::EnumerateFields(FieldEnumerator* enumerator)
{
	if(!scheme)
		return;

	class Enumerator : public ClientRepo::KeyValueEnumerator
	{
	private:
		FieldEnumerator* enumerator;

	public:
		Enumerator(FieldEnumerator* enumerator)
		: enumerator(enumerator) {}

		bool OnKeyValue(ptr<File> key, ptr<File> value)
		{
			int fieldIndex = TryParseFieldKey(
				(char*)key->GetData() + EntityId::size + 1,
				key->GetSize() - EntityId::size - 1);

			if(fieldIndex < 0)
				return true;

			enumerator->OnField(fieldIndex, value);
			return true;
		}
	};

	ptr<MemoryFile> prefix = NEW(MemoryFile(EntityId::size + 1));
	char* prefixData = (char*)prefix->GetData();
	memcpy(prefixData, id.data, EntityId::size);
	prefixData[EntityId::size] = 'f';

	manager->GetRepo()->EnumerateKeyValues(prefix, &Enumerator(enumerator));
}

ptr<Script::Any> Entity::ReadField(int fieldIndex) const
{
	if(!scheme)
		return nullptr;

	const EntityScheme::Fields& fields = scheme->GetFields();
	if(fieldIndex >= (int)fields.size())
		return nullptr;

	return fields[fieldIndex].type->TryConvertToScript(
		Script::Np::State::GetCurrent(),
		RawReadField(fieldIndex));
}

void Entity::WriteField(ptr<Action> action, int fieldIndex, ptr<Script::Any> value)
{
	if(!scheme)
		return;

	const EntityScheme::Fields& fields = scheme->GetFields();
	if(fieldIndex >= (int)fields.size())
		return;

	ptr<File> fileValue = fields[fieldIndex].type->TryConvertFromScript(value.FastCast<Script::Np::Any>());
	if(!fileValue)
		return;

	RawWriteField(action, fieldIndex, fileValue);
}

ptr<File> Entity::ReadData(const void* nameData, size_t nameSize) const
{
	if(!scheme)
		return nullptr;

	return manager->GetRepo()->GetValue(GetFullDataKey(nameData, nameSize));
}

void Entity::WriteData(ptr<Action> action, const void* nameData, size_t nameSize, ptr<File> value)
{
	if(!scheme)
		return;

	action->AddChange(GetFullDataKey(nameData, nameSize), value);
}

void Entity::EnumerateData(DataEnumerator* enumerator)
{
	if(!scheme)
		return;

	class Enumerator : public ClientRepo::KeyValueEnumerator
	{
	private:
		DataEnumerator* enumerator;

	public:
		Enumerator(DataEnumerator* enumerator)
		: enumerator(enumerator) {}

		bool OnKeyValue(ptr<File> key, ptr<File> value)
		{
			enumerator->OnData(key->SliceFrom(EntityId::size + 1), value);
			return true;
		}
	};

	ptr<MemoryFile> prefix = NEW(MemoryFile(EntityId::size + 1));
	char* prefixData = (char*)prefix->GetData();
	memcpy(prefixData, id.data, EntityId::size);
	prefixData[EntityId::size] = 'd';

	manager->GetRepo()->EnumerateKeyValues(prefix, &Enumerator(enumerator));
}

ptr<EntityCallback> Entity::AddCallback(ptr<Script::Any> callback)
{
	return NEW(EntityCallback(this, callback.FastCast<Script::Np::Any>()));
}

END_INANITY_OIL
<commit_msg>fixed crash with change to null value for entity<commit_after>#include "Entity.hpp"
#include "EntityScheme.hpp"
#include "EntityManager.hpp"
#include "EntitySchemeManager.hpp"
#include "EntityCallback.hpp"
#include "EntityFieldType.hpp"
#include "Action.hpp"
#include "ClientRepo.hpp"
#include "../inanity/script/np/Any.hpp"
#include "../inanity/script/np/State.hpp"
#include "../inanity/MemoryFile.hpp"
#include "../inanity/Exception.hpp"

BEGIN_INANITY_OIL

Entity::Entity(ptr<EntityManager> manager, const EntityId& id)
: manager(manager), id(id)
{
	manager->OnNewEntity(id, this);
}

Entity::~Entity()
{
	manager->OnFreeEntity(id);
}

ptr<EntityManager> Entity::GetManager() const
{
	return manager;
}

EntityId Entity::GetId() const
{
	return id;
}

ptr<EntityScheme> Entity::GetScheme() const
{
	return scheme;
}

void Entity::SetScheme(ptr<EntityScheme> scheme)
{
	this->scheme = scheme;
}

void Entity::OnNewCallback(EntityCallback* callback)
{
	callbacks.push_back(callback);
}

void Entity::OnFreeCallback(EntityCallback* callback)
{
	for(size_t i = 0; i < callbacks.size(); ++i)
		if(callbacks[i] == callback)
		{
			callbacks.erase(callbacks.begin() + i);
			return;
		}

	THROW("Entity callback already freed");
}

ptr<File> Entity::GetFullTagKey(const EntityTagId& tagId) const
{
	ptr<MemoryFile> key = NEW(MemoryFile(EntityId::size + 1 + EntityTagId::size));
	char* keyData = (char*)key->GetData();
	memcpy(keyData, id.data, EntityId::size);
	keyData[EntityId::size] = 't';
	memcpy(keyData + EntityId::size + 1, tagId.data, EntityTagId::size);
	return key;
}

ptr<File> Entity::GetFullFieldKey(int fieldIndex) const
{
	if(fieldIndex >= (1 << 16))
		THROW("Too big field index");

	ptr<MemoryFile> key = NEW(MemoryFile(EntityId::size + 1 + 2));
	char* keyData = (char*)key->GetData();
	memcpy(keyData, id.data, EntityId::size);
	keyData[EntityId::size] = 'f';
	keyData[EntityId::size + 1] = fieldIndex & 0xff;
	keyData[EntityId::size + 2] = (fieldIndex >> 8) & 0xff;

	return key;
}

ptr<File> Entity::GetFullDataKey(const void* nameData, size_t nameSize) const
{
	ptr<MemoryFile> key = NEW(MemoryFile(EntityId::size + 1 + nameSize));
	char* keyData = (char*)key->GetData();
	memcpy(keyData, id.data, EntityId::size);
	keyData[EntityId::size] = 'd';
	memcpy(keyData + EntityId::size + 1, nameData, nameSize);

	return key;
}

int Entity::TryParseFieldKey(const void* data, size_t size)
{
	if(size != 2)
		return -1;

	const unsigned char* d = (const unsigned char*)data;
	return d[0] | (d[1] << 8);
}

void Entity::OnChange(const void* keyData, size_t keySize, ptr<File> value)
{
	if(!scheme)
		return;

	// if this is a main entity key (scheme key)
	if(!keySize)
	{
		// value should be entity scheme id and has appropriate size
		// if it not, think like there is no scheme
		ptr<EntityScheme> newScheme;
		if(value && value->GetSize() == EntitySchemeId::size)
			newScheme = manager->GetSchemeManager()->TryGet(EntitySchemeId::FromData(value->GetData()));

		// if scheme doesn't match
		if(scheme != newScheme)
		{
			// remember it
			scheme = newScheme;
			// fire callbacks
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireScheme(scheme);
		}

		return;
	}

	// the rest is entity's tags, fields or data
	switch(*(const char*)keyData)
	{
	case 't':
		{
			if(keySize != EntityTagId::size + 1)
				break;
			EntityTagId tagId = EntityTagId::FromData((const char*)keyData + 1);
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireTag(tagId, value);
		}
		break;
	case 'f':
		{
			int fieldIndex = TryParseFieldKey((const char*)keyData + 1, keySize - 1);
			if(fieldIndex < 0)
				break;
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireField(fieldIndex, value);
		}
		break;
	case 'd':
		{
			ptr<File> key = MemoryFile::CreateViaCopy((const char*)keyData + 1, keySize - 1);
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireData(key, value);
		}
		break;
	}
}

ptr<File> Entity::ReadTag(const EntityTagId& tagId) const
{
	if(!scheme)
		return nullptr;

	return manager->GetRepo()->GetValue(GetFullTagKey(tagId));
}

void Entity::WriteTag(ptr<Action> action, const EntityTagId& tagId, ptr<File> tagData)
{
	if(!scheme)
		return;

	action->AddChange(GetFullTagKey(tagId), tagData);
}

ptr<File> Entity::RawReadField(int fieldIndex) const
{
	if(!scheme)
		return nullptr;

	return manager->GetRepo()->GetValue(GetFullFieldKey(fieldIndex));
}

void Entity::RawWriteField(ptr<Action> action, int fieldIndex, ptr<File> value)
{
	if(!scheme)
		return;

	action->AddChange(GetFullFieldKey(fieldIndex), value);
}

void Entity::EnumerateFields(FieldEnumerator* enumerator)
{
	if(!scheme)
		return;

	class Enumerator : public ClientRepo::KeyValueEnumerator
	{
	private:
		FieldEnumerator* enumerator;

	public:
		Enumerator(FieldEnumerator* enumerator)
		: enumerator(enumerator) {}

		bool OnKeyValue(ptr<File> key, ptr<File> value)
		{
			int fieldIndex = TryParseFieldKey(
				(char*)key->GetData() + EntityId::size + 1,
				key->GetSize() - EntityId::size - 1);

			if(fieldIndex < 0)
				return true;

			enumerator->OnField(fieldIndex, value);
			return true;
		}
	};

	ptr<MemoryFile> prefix = NEW(MemoryFile(EntityId::size + 1));
	char* prefixData = (char*)prefix->GetData();
	memcpy(prefixData, id.data, EntityId::size);
	prefixData[EntityId::size] = 'f';

	manager->GetRepo()->EnumerateKeyValues(prefix, &Enumerator(enumerator));
}

ptr<Script::Any> Entity::ReadField(int fieldIndex) const
{
	if(!scheme)
		return nullptr;

	const EntityScheme::Fields& fields = scheme->GetFields();
	if(fieldIndex >= (int)fields.size())
		return nullptr;

	return fields[fieldIndex].type->TryConvertToScript(
		Script::Np::State::GetCurrent(),
		RawReadField(fieldIndex));
}

void Entity::WriteField(ptr<Action> action, int fieldIndex, ptr<Script::Any> value)
{
	if(!scheme)
		return;

	const EntityScheme::Fields& fields = scheme->GetFields();
	if(fieldIndex >= (int)fields.size())
		return;

	ptr<File> fileValue = fields[fieldIndex].type->TryConvertFromScript(value.FastCast<Script::Np::Any>());
	if(!fileValue)
		return;

	RawWriteField(action, fieldIndex, fileValue);
}

ptr<File> Entity::ReadData(const void* nameData, size_t nameSize) const
{
	if(!scheme)
		return nullptr;

	return manager->GetRepo()->GetValue(GetFullDataKey(nameData, nameSize));
}

void Entity::WriteData(ptr<Action> action, const void* nameData, size_t nameSize, ptr<File> value)
{
	if(!scheme)
		return;

	action->AddChange(GetFullDataKey(nameData, nameSize), value);
}

void Entity::EnumerateData(DataEnumerator* enumerator)
{
	if(!scheme)
		return;

	class Enumerator : public ClientRepo::KeyValueEnumerator
	{
	private:
		DataEnumerator* enumerator;

	public:
		Enumerator(DataEnumerator* enumerator)
		: enumerator(enumerator) {}

		bool OnKeyValue(ptr<File> key, ptr<File> value)
		{
			enumerator->OnData(key->SliceFrom(EntityId::size + 1), value);
			return true;
		}
	};

	ptr<MemoryFile> prefix = NEW(MemoryFile(EntityId::size + 1));
	char* prefixData = (char*)prefix->GetData();
	memcpy(prefixData, id.data, EntityId::size);
	prefixData[EntityId::size] = 'd';

	manager->GetRepo()->EnumerateKeyValues(prefix, &Enumerator(enumerator));
}

ptr<EntityCallback> Entity::AddCallback(ptr<Script::Any> callback)
{
	return NEW(EntityCallback(this, callback.FastCast<Script::Np::Any>()));
}

END_INANITY_OIL
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2015 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * Suite of performance tests for ep-engine.
 *
 * Uses the same engine_testapp infrastructure as ep_testsuite.
 *
 * Tests print their performance metrics to stdout; to see this output when
 * run via do:
 *
 *     make test ARGS="--verbose"
 *
**/

#include "config.h"

#include <memcached/engine.h>
#include <memcached/engine_testapp.h>

#include "ep_testsuite_common.h"
#include "ep_test_apis.h"

struct Stats {
    std::string name;
    double mean;
    double median;
    double stddev;
    double pct5;
    double pct95;
    double pct99;
    std::vector<hrtime_t>* vec;
};

// Given a vector of timings (each a vector<hrtime_t>) calcuate metrics on them
// and print to stdout.
void print_timings(std::vector<std::pair<std::string, std::vector<hrtime_t>*> > timings)
{
    // First, calculate mean, median, standard deviation and percentiles of
    // each set of timings, both for printing and to derive what the range of
    // the graphs should be.
    std::vector<Stats> timing_stats;
    for (const auto& t : timings) {
        Stats stats;
        stats.name = t.first;
        stats.vec = t.second;
        std::vector<hrtime_t>& vec = *t.second;

        // Calculate latency percentiles
        std::sort(vec.begin(), vec.end());
        stats.median = vec[(vec.size() * 50) / 100];
        stats.pct5 = vec[(vec.size() * 5) / 100];
        stats.pct95 = vec[(vec.size() * 95) / 100];
        stats.pct99 = vec[(vec.size() * 99) / 100];

        const double sum = std::accumulate(vec.begin(), vec.end(), 0.0);
        stats.mean = sum / vec.size();
        double accum = 0.0;
        std::for_each (vec.begin(), vec.end(), [&](const double d) {
            accum += (d - stats.mean) * (d - stats.mean);
        });
        stats.stddev = sqrt(accum / (vec.size() - 1));

        timing_stats.push_back(stats);
    }

    // From these find the start and end for the spark graphs which covers the
    // a "reasonable sample" of each timing set. We define that as from the 9th
    // to the 95th percentile, so we ensure *all* sets have that range covered.
    hrtime_t spark_start = std::numeric_limits<hrtime_t>::max();
    hrtime_t spark_end = 0;
    for (const auto& stats : timing_stats) {
        spark_start = (stats.pct5 < spark_start) ? stats.pct5 : spark_start;
        spark_end = (stats.pct95 > spark_end) ? stats.pct95 : spark_end;
    }

    printf("\n\n                         Percentile           \n");
    printf("  %-8s Median     95th     99th  Std Dev  Histogram of samples\n\n", "");
    // Finally, print out each set.
    for (const auto& stats : timing_stats) {
        printf("%-8s %8.03f %8.03f %8.03f %8.03f  ",
               stats.name.c_str(), stats.median/1e3, stats.pct95/1e3,
               stats.pct99/1e3, stats.stddev/1e3);

        // Calculate and render Sparkline (requires UTF-8 terminal).
        const int nbins = 32;
        int prev_distance = 0;
        std::vector<size_t> histogram;
        for (unsigned int bin = 0; bin < nbins; bin++) {
            const hrtime_t max_for_bin = (spark_end / nbins) * bin;
            auto it = std::lower_bound(stats.vec->begin(), stats.vec->end(), max_for_bin);
            const int distance = std::distance(stats.vec->begin(), it);
            histogram.push_back(distance - prev_distance);
            prev_distance = distance;
        }

        const auto minmax = std::minmax_element(histogram.begin(), histogram.end());
        const size_t range = *minmax.second - *minmax.first + 1;
        const int levels = 8;
        for (const auto& h : histogram) {
            int bar_size = ((h - *minmax.first + 1) * (levels - 1)) / range;
            putchar('\xe2');
            putchar('\x96');
            putchar('\x81' + bar_size);
        }
        putchar('\n');
    }
    printf("%44s  %-14d µs %14d\n\n", "",
           int(spark_start/1e3), int(spark_end/1e3));
}

/*****************************************************************************
 ** Testcases
 *****************************************************************************/

static enum test_result perf_latency(ENGINE_HANDLE *h,
                                     ENGINE_HANDLE_V1 *h1,
                                     const char* title) {
    // Only timing front-end performance, not considering persistence.
    stop_persistence(h, h1);

    const void *cookie = testHarness.create_cookie();

    const unsigned int num_docs = 500000;
    const std::string data(100, 'x');

    std::vector<hrtime_t> add_timings, get_timings, replace_timings, delete_timings;
    add_timings.reserve(num_docs);
    get_timings.reserve(num_docs);
    replace_timings.reserve(num_docs);
    delete_timings.reserve(num_docs);

    int printed = 0;
    printf("\n\n=== Latency [%s] - %u items (µs) %n", title, num_docs, &printed);
    for (int i = 0; i < 81-printed; i++) {
        putchar('=');
    }

    // Build vector of keys
    std::vector<std::string> keys;
    for (unsigned int i = 0; i < num_docs; i++) {
        keys.push_back(std::to_string(i));
    }

    // Create (add)
    for (auto& key : keys) {
        item* item = NULL;
        const hrtime_t start = gethrtime();
        check(storeCasVb11(h, h1, cookie, OPERATION_ADD, key.c_str(),
                           data.c_str(), data.length(), 0, &item, 0,
                           /*vBucket*/0, 0, 0) == ENGINE_SUCCESS,
              "Failed to add a value");
        const hrtime_t end = gethrtime();
        add_timings.push_back(end - start);
        h1->release(h, cookie, item);
    }

    // Get
    for (auto& key : keys) {
        item* item = NULL;
        const hrtime_t start = gethrtime();
        check(h1->get(h, cookie, &item, key.c_str(), key.size(), 0) == ENGINE_SUCCESS,
              "Failed to get a value");
        const hrtime_t end = gethrtime();
        get_timings.push_back(end - start);
        h1->release(h, cookie, item);
    }

    // Update (Replace)
    for (auto& key : keys) {
        item* item = NULL;
        const hrtime_t start = gethrtime();
        check(storeCasVb11(h, h1, cookie, OPERATION_REPLACE, key.c_str(),
                           data.c_str(), data.length(), 0, &item, 0,
                           /*vBucket*/0, 0, 0) == ENGINE_SUCCESS,
              "Failed to replace a value");
        const hrtime_t end = gethrtime();
        replace_timings.push_back(end - start);
        h1->release(h, cookie, item);
    }

    // Delete
    for (auto& key : keys) {
        const hrtime_t start = gethrtime();
        check(del(h, h1, key.c_str(), 0, 0, cookie) == ENGINE_SUCCESS,
              "Failed to delete a value");
        const hrtime_t end = gethrtime();
        delete_timings.push_back(end - start);
    }

    std::vector<std::pair<std::string, std::vector<hrtime_t>*> > all_timings;
    all_timings.push_back(std::make_pair("Add", &add_timings));
    all_timings.push_back(std::make_pair("Get", &get_timings));
    all_timings.push_back(std::make_pair("Replace", &replace_timings));
    all_timings.push_back(std::make_pair("Delete", &delete_timings));
    print_timings(all_timings);

    return SUCCESS;
}

/* Benchmark the baseline latency (without any tasks running) of ep-engine.
 */
static enum test_result perf_latency_baseline(ENGINE_HANDLE *h,
                                              ENGINE_HANDLE_V1 *h1) {
    return perf_latency(h, h1, "Baseline");
}

/* Benchmark the baseline latency with the defragmenter enabled.
 */
static enum test_result perf_latency_defragmenter(ENGINE_HANDLE *h,
                                                  ENGINE_HANDLE_V1 *h1) {
    return perf_latency(h, h1, "With constant defragmention");
}

/*****************************************************************************
 * List of testcases
 *****************************************************************************/

TestCase testsuite_testcases[] = {
        TestCase("Baseline latency", perf_latency_baseline,
                 test_setup, teardown,
                 "ht_size=393209", prepare, cleanup),
        TestCase("Defragmenter latency", perf_latency_defragmenter,
                 test_setup, teardown,
                 "ht_size=393209"
                 // Run defragmenter constantly.
                 ";defragmenter_interval=0",
                 prepare, cleanup),

        TestCase(NULL, NULL, NULL, NULL, NULL, prepare, cleanup)
};
<commit_msg>Add Expiry Pager latency test to ep_perfsuite<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2015 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * Suite of performance tests for ep-engine.
 *
 * Uses the same engine_testapp infrastructure as ep_testsuite.
 *
 * Tests print their performance metrics to stdout; to see this output when
 * run via do:
 *
 *     make test ARGS="--verbose"
 *
**/

#include "config.h"

#include <memcached/engine.h>
#include <memcached/engine_testapp.h>

#include "ep_testsuite_common.h"
#include "ep_test_apis.h"

struct Stats {
    std::string name;
    double mean;
    double median;
    double stddev;
    double pct5;
    double pct95;
    double pct99;
    std::vector<hrtime_t>* vec;
};

// Given a vector of timings (each a vector<hrtime_t>) calcuate metrics on them
// and print to stdout.
void print_timings(std::vector<std::pair<std::string, std::vector<hrtime_t>*> > timings)
{
    // First, calculate mean, median, standard deviation and percentiles of
    // each set of timings, both for printing and to derive what the range of
    // the graphs should be.
    std::vector<Stats> timing_stats;
    for (const auto& t : timings) {
        Stats stats;
        stats.name = t.first;
        stats.vec = t.second;
        std::vector<hrtime_t>& vec = *t.second;

        // Calculate latency percentiles
        std::sort(vec.begin(), vec.end());
        stats.median = vec[(vec.size() * 50) / 100];
        stats.pct5 = vec[(vec.size() * 5) / 100];
        stats.pct95 = vec[(vec.size() * 95) / 100];
        stats.pct99 = vec[(vec.size() * 99) / 100];

        const double sum = std::accumulate(vec.begin(), vec.end(), 0.0);
        stats.mean = sum / vec.size();
        double accum = 0.0;
        std::for_each (vec.begin(), vec.end(), [&](const double d) {
            accum += (d - stats.mean) * (d - stats.mean);
        });
        stats.stddev = sqrt(accum / (vec.size() - 1));

        timing_stats.push_back(stats);
    }

    // From these find the start and end for the spark graphs which covers the
    // a "reasonable sample" of each timing set. We define that as from the 9th
    // to the 95th percentile, so we ensure *all* sets have that range covered.
    hrtime_t spark_start = std::numeric_limits<hrtime_t>::max();
    hrtime_t spark_end = 0;
    for (const auto& stats : timing_stats) {
        spark_start = (stats.pct5 < spark_start) ? stats.pct5 : spark_start;
        spark_end = (stats.pct95 > spark_end) ? stats.pct95 : spark_end;
    }

    printf("\n\n                         Percentile           \n");
    printf("  %-8s Median     95th     99th  Std Dev  Histogram of samples\n\n", "");
    // Finally, print out each set.
    for (const auto& stats : timing_stats) {
        printf("%-8s %8.03f %8.03f %8.03f %8.03f  ",
               stats.name.c_str(), stats.median/1e3, stats.pct95/1e3,
               stats.pct99/1e3, stats.stddev/1e3);

        // Calculate and render Sparkline (requires UTF-8 terminal).
        const int nbins = 32;
        int prev_distance = 0;
        std::vector<size_t> histogram;
        for (unsigned int bin = 0; bin < nbins; bin++) {
            const hrtime_t max_for_bin = (spark_end / nbins) * bin;
            auto it = std::lower_bound(stats.vec->begin(), stats.vec->end(), max_for_bin);
            const int distance = std::distance(stats.vec->begin(), it);
            histogram.push_back(distance - prev_distance);
            prev_distance = distance;
        }

        const auto minmax = std::minmax_element(histogram.begin(), histogram.end());
        const size_t range = *minmax.second - *minmax.first + 1;
        const int levels = 8;
        for (const auto& h : histogram) {
            int bar_size = ((h - *minmax.first + 1) * (levels - 1)) / range;
            putchar('\xe2');
            putchar('\x96');
            putchar('\x81' + bar_size);
        }
        putchar('\n');
    }
    printf("%44s  %-14d µs %14d\n\n", "",
           int(spark_start/1e3), int(spark_end/1e3));
}

/*****************************************************************************
 ** Testcases
 *****************************************************************************/

static enum test_result perf_latency(ENGINE_HANDLE *h,
                                     ENGINE_HANDLE_V1 *h1,
                                     const char* title) {
    // Only timing front-end performance, not considering persistence.
    stop_persistence(h, h1);

    const void *cookie = testHarness.create_cookie();

    const unsigned int num_docs = 500000;
    const std::string data(100, 'x');

    std::vector<hrtime_t> add_timings, get_timings, replace_timings, delete_timings;
    add_timings.reserve(num_docs);
    get_timings.reserve(num_docs);
    replace_timings.reserve(num_docs);
    delete_timings.reserve(num_docs);

    int printed = 0;
    printf("\n\n=== Latency [%s] - %u items (µs) %n", title, num_docs, &printed);
    for (int i = 0; i < 81-printed; i++) {
        putchar('=');
    }

    // Build vector of keys
    std::vector<std::string> keys;
    for (unsigned int i = 0; i < num_docs; i++) {
        keys.push_back(std::to_string(i));
    }

    // Create (add)
    for (auto& key : keys) {
        item* item = NULL;
        const hrtime_t start = gethrtime();
        check(storeCasVb11(h, h1, cookie, OPERATION_ADD, key.c_str(),
                           data.c_str(), data.length(), 0, &item, 0,
                           /*vBucket*/0, 0, 0) == ENGINE_SUCCESS,
              "Failed to add a value");
        const hrtime_t end = gethrtime();
        add_timings.push_back(end - start);
        h1->release(h, cookie, item);
    }

    // Get
    for (auto& key : keys) {
        item* item = NULL;
        const hrtime_t start = gethrtime();
        check(h1->get(h, cookie, &item, key.c_str(), key.size(), 0) == ENGINE_SUCCESS,
              "Failed to get a value");
        const hrtime_t end = gethrtime();
        get_timings.push_back(end - start);
        h1->release(h, cookie, item);
    }

    // Update (Replace)
    for (auto& key : keys) {
        item* item = NULL;
        const hrtime_t start = gethrtime();
        check(storeCasVb11(h, h1, cookie, OPERATION_REPLACE, key.c_str(),
                           data.c_str(), data.length(), 0, &item, 0,
                           /*vBucket*/0, 0, 0) == ENGINE_SUCCESS,
              "Failed to replace a value");
        const hrtime_t end = gethrtime();
        replace_timings.push_back(end - start);
        h1->release(h, cookie, item);
    }

    // Delete
    for (auto& key : keys) {
        const hrtime_t start = gethrtime();
        check(del(h, h1, key.c_str(), 0, 0, cookie) == ENGINE_SUCCESS,
              "Failed to delete a value");
        const hrtime_t end = gethrtime();
        delete_timings.push_back(end - start);
    }

    std::vector<std::pair<std::string, std::vector<hrtime_t>*> > all_timings;
    all_timings.push_back(std::make_pair("Add", &add_timings));
    all_timings.push_back(std::make_pair("Get", &get_timings));
    all_timings.push_back(std::make_pair("Replace", &replace_timings));
    all_timings.push_back(std::make_pair("Delete", &delete_timings));
    print_timings(all_timings);

    return SUCCESS;
}

/* Benchmark the baseline latency (without any tasks running) of ep-engine.
 */
static enum test_result perf_latency_baseline(ENGINE_HANDLE *h,
                                              ENGINE_HANDLE_V1 *h1) {
    return perf_latency(h, h1, "Baseline");
}

/* Benchmark the baseline latency with the defragmenter enabled.
 */
static enum test_result perf_latency_defragmenter(ENGINE_HANDLE *h,
                                                  ENGINE_HANDLE_V1 *h1) {
    return perf_latency(h, h1, "With constant defragmention");
}

/* Benchmark the baseline latency with the defragmenter enabled.
 */
static enum test_result perf_latency_expiry_pager(ENGINE_HANDLE *h,
                                                  ENGINE_HANDLE_V1 *h1) {
    return perf_latency(h, h1, "With constant Expiry pager");
}

/*****************************************************************************
 * List of testcases
 *****************************************************************************/

TestCase testsuite_testcases[] = {
        TestCase("Baseline latency", perf_latency_baseline,
                 test_setup, teardown,
                 "ht_size=393209", prepare, cleanup),
        TestCase("Defragmenter latency", perf_latency_defragmenter,
                 test_setup, teardown,
                 "ht_size=393209"
                 // Run defragmenter constantly.
                 ";defragmenter_interval=0",
                 prepare, cleanup),
        TestCase("Expiry pager latency", perf_latency_expiry_pager,
                 test_setup, teardown,
                 "ht_size=393209"
                 // Run expiry pager constantly.
                 ";exp_pager_stime=0",
                 prepare, cleanup),

        TestCase(NULL, NULL, NULL, NULL, NULL, prepare, cleanup)
};
<|endoftext|>


<commit_before>// Petter Strandmark 2013.

#include <queue>

#define CATCH_CONFIG_MAIN
#include <catch.hpp>

#include <spii/interval_term.h>
#include <spii/global.h>
#include <spii/solver.h>
using namespace spii;

struct SimpleFunction1
{
	template<typename R>
	R operator()(const R* const x) const
	{
		return pow(x[0], 2) + 3.0*cos(5.0*x[0]);
	}
};

struct SimpleFunction2
{
	template<typename R>
	R operator()(const R* const x) const
	{
		return x[0]*x[0] + x[1]*x[1] + 1.0;
	}
};

struct SimpleFunction1_1
{
	template<typename R>
	R operator()(const R* const x, const R* const y) const
	{
		return x[0]*x[0] + y[0]*y[0] + 1.0;
	}
};

TEST_CASE("global_optimization/simple_function1", "Petter")
{
	double x = 2.0;
	Function f;
	f.add_variable(&x, 1);
	f.add_term(
		new IntervalTerm<SimpleFunction1, 1>(
			new SimpleFunction1),
		&x);

	Solver solver;
	solver.maximum_iterations = 1015;
	std::stringstream info_buffer;
	solver.log_function = [&info_buffer](const std::string& str) { info_buffer << str << std::endl; };
	SolverResults results;
	std::vector<Interval<double>> x_interval;
	x_interval.push_back(Interval<double>(-10.0, 9.0));
	solver.solve_global(f, x_interval, &results);

	INFO(info_buffer.str());
	INFO(results);

	auto opt = results.optimum;
	CHECK((opt.get_upper() - opt.get_lower()) <= 1e-3);
	auto val = f.evaluate();
	CHECK(opt.get_lower() <= val); CHECK(val <= opt.get_upper());
}

TEST_CASE("global_optimization/simple_function2", "Petter")
{
	double x[] = {2.0, 2.0};
	Function f;
	f.add_variable(x, 2);
	f.add_term(
		new IntervalTerm<SimpleFunction2, 2>(
			new SimpleFunction2),
		x);

	Solver solver;
	solver.maximum_iterations = 1000;
	solver.argument_improvement_tolerance = 0;
	solver.function_improvement_tolerance = 1e-12;
	std::stringstream info_buffer;
	solver.log_function = [&info_buffer](const std::string& str) { info_buffer << str << std::endl; };
	SolverResults results;
	std::vector<Interval<double>> x_interval;
	x_interval.push_back(Interval<double>(-10.0, 9.0));
	x_interval.push_back(Interval<double>(-8.0, 8.0));
	solver.solve_global(f, x_interval, &results);

	INFO(info_buffer.str());
	INFO(results);

	auto opt = results.optimum;
	CHECK((opt.get_upper() - opt.get_lower()) <= 1e-10);
	CHECK(results.exit_condition == SolverResults::FUNCTION_TOLERANCE);
	CHECK(opt.get_lower() <= 1.0); CHECK(1.0 <= opt.get_upper());
}

TEST_CASE("global_optimization/simple_function1-1", "Petter")
{
	double x = 2.0, y = 2.0;
	Function f;
	f.add_variable(&x, 1);
	f.add_variable(&y, 1);
	f.add_term(
		new IntervalTerm<SimpleFunction1_1, 1, 1>(
			new SimpleFunction1_1),
		&x, &y);

	Solver solver;
	solver.maximum_iterations = 1000;
	solver.argument_improvement_tolerance = 0;
	solver.function_improvement_tolerance = 1e-12;
	std::stringstream info_buffer;
	solver.log_function = [&info_buffer](const std::string& str) { info_buffer << str << std::endl; };
	SolverResults results;
	std::vector<Interval<double>> x_interval;
	x_interval.push_back(Interval<double>(-10.0, 9.0));
	x_interval.push_back(Interval<double>(-8.0, 8.0));
	solver.solve_global(f, x_interval, &results);

	INFO(info_buffer.str());
	INFO(results);

	auto opt = results.optimum;
	CHECK((opt.get_upper() - opt.get_lower()) <= 1e-10);
	CHECK(results.exit_condition == SolverResults::FUNCTION_TOLERANCE);
	CHECK(opt.get_lower() <= 1.0); CHECK(1.0 <= opt.get_upper());
}

<commit_msg>Removing unused header file.<commit_after>// Petter Strandmark 2013.

#include <queue>

#define CATCH_CONFIG_MAIN
#include <catch.hpp>

#include <spii/interval_term.h>
#include <spii/solver.h>
using namespace spii;

struct SimpleFunction1
{
	template<typename R>
	R operator()(const R* const x) const
	{
		return pow(x[0], 2) + 3.0*cos(5.0*x[0]);
	}
};

struct SimpleFunction2
{
	template<typename R>
	R operator()(const R* const x) const
	{
		return x[0]*x[0] + x[1]*x[1] + 1.0;
	}
};

struct SimpleFunction1_1
{
	template<typename R>
	R operator()(const R* const x, const R* const y) const
	{
		return x[0]*x[0] + y[0]*y[0] + 1.0;
	}
};

TEST_CASE("global_optimization/simple_function1", "Petter")
{
	double x = 2.0;
	Function f;
	f.add_variable(&x, 1);
	f.add_term(
		new IntervalTerm<SimpleFunction1, 1>(
			new SimpleFunction1),
		&x);

	Solver solver;
	solver.maximum_iterations = 1015;
	std::stringstream info_buffer;
	solver.log_function = [&info_buffer](const std::string& str) { info_buffer << str << std::endl; };
	SolverResults results;
	std::vector<Interval<double>> x_interval;
	x_interval.push_back(Interval<double>(-10.0, 9.0));
	solver.solve_global(f, x_interval, &results);

	INFO(info_buffer.str());
	INFO(results);

	auto opt = results.optimum;
	CHECK((opt.get_upper() - opt.get_lower()) <= 1e-3);
	auto val = f.evaluate();
	CHECK(opt.get_lower() <= val); CHECK(val <= opt.get_upper());
}

TEST_CASE("global_optimization/simple_function2", "Petter")
{
	double x[] = {2.0, 2.0};
	Function f;
	f.add_variable(x, 2);
	f.add_term(
		new IntervalTerm<SimpleFunction2, 2>(
			new SimpleFunction2),
		x);

	Solver solver;
	solver.maximum_iterations = 1000;
	solver.argument_improvement_tolerance = 0;
	solver.function_improvement_tolerance = 1e-12;
	std::stringstream info_buffer;
	solver.log_function = [&info_buffer](const std::string& str) { info_buffer << str << std::endl; };
	SolverResults results;
	std::vector<Interval<double>> x_interval;
	x_interval.push_back(Interval<double>(-10.0, 9.0));
	x_interval.push_back(Interval<double>(-8.0, 8.0));
	solver.solve_global(f, x_interval, &results);

	INFO(info_buffer.str());
	INFO(results);

	auto opt = results.optimum;
	CHECK((opt.get_upper() - opt.get_lower()) <= 1e-10);
	CHECK(results.exit_condition == SolverResults::FUNCTION_TOLERANCE);
	CHECK(opt.get_lower() <= 1.0); CHECK(1.0 <= opt.get_upper());
}

TEST_CASE("global_optimization/simple_function1-1", "Petter")
{
	double x = 2.0, y = 2.0;
	Function f;
	f.add_variable(&x, 1);
	f.add_variable(&y, 1);
	f.add_term(
		new IntervalTerm<SimpleFunction1_1, 1, 1>(
			new SimpleFunction1_1),
		&x, &y);

	Solver solver;
	solver.maximum_iterations = 1000;
	solver.argument_improvement_tolerance = 0;
	solver.function_improvement_tolerance = 1e-12;
	std::stringstream info_buffer;
	solver.log_function = [&info_buffer](const std::string& str) { info_buffer << str << std::endl; };
	SolverResults results;
	std::vector<Interval<double>> x_interval;
	x_interval.push_back(Interval<double>(-10.0, 9.0));
	x_interval.push_back(Interval<double>(-8.0, 8.0));
	solver.solve_global(f, x_interval, &results);

	INFO(info_buffer.str());
	INFO(results);

	auto opt = results.optimum;
	CHECK((opt.get_upper() - opt.get_lower()) <= 1e-10);
	CHECK(results.exit_condition == SolverResults::FUNCTION_TOLERANCE);
	CHECK(opt.get_lower() <= 1.0); CHECK(1.0 <= opt.get_upper());
}

<|endoftext|>


<commit_before><commit_msg>Replace AttributeSet with AttributeList in CallInst<commit_after><|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	ディスパッチ・クラス @n
			グループ割り込みの分類を行うサポート用
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/device.hpp"

namespace utils {

	typedef void (*TASK)();		///< 関数呼び出し型

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  dispatch class
		@param[in]	VEC	グループ・ベクター
		@param[in]	NUM	分岐数（最大３２）
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template<device::icu_t::VECTOR VEC, uint32_t NUM>
	class dispatch {

		TASK		task_[NUM];
		uint32_t	mask_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		*/
		//-----------------------------------------------------------------//
		dispatch() noexcept : task_{ nullptr }, mask_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	サイズを返す
			@return サイズ
		*/
		//-----------------------------------------------------------------//
		uint32_t size() const noexcept { return NUM; }

		//-----------------------------------------------------------------//
		/*!
			@brief	マスクを返す
			@return マスク
		*/
		//-----------------------------------------------------------------//
		uint32_t get_mask() const noexcept { return mask_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	分岐タスクを登録
			@param[in]	index	インデックス
			@param[in]	task	タスク
			@return 不正なインデックスの場合「false」
		*/
		//-----------------------------------------------------------------//
		bool set_task(uint32_t index, TASK task) noexcept
		{
			if(index < NUM) {
				task_[index] = task;
				if(task != nullptr) {
					mask_ |= 1 << index;
				} else {
					mask_ &= ~(1 << index);
				}
				return true;
			} else {
				return false;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	分岐タスクを取得
			@param[in]	index	インデックス
			@return 分岐タスク
		*/
		//-----------------------------------------------------------------//
		TASK get_task(uint32_t index) noexcept
		{
			if(index < NUM) {
				return task_[index];
			} else {
				return nullptr;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	分岐タスクを実行
			@param[in]	index	インデックス
		*/
		//-----------------------------------------------------------------//
		void run_task(uint32_t index) noexcept
		{
			if(index < NUM) {
				if(task_[index] != nullptr) {
					(*task_[index])();
				}
			}
		}
	};
}
<commit_msg>Update: typo ICU type<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	ディスパッチ・クラス @n
			グループ割り込みの分類を行うサポート用
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/device.hpp"

namespace utils {

	typedef void (*TASK)();		///< 関数呼び出し型

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  dispatch class
		@param[in]	VEC	グループ・ベクター
		@param[in]	NUM	分岐数（最大３２）
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template<device::ICU::VECTOR VEC, uint32_t NUM>
	class dispatch {

		TASK		task_[NUM];
		uint32_t	mask_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		*/
		//-----------------------------------------------------------------//
		dispatch() noexcept : task_{ nullptr }, mask_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	サイズを返す
			@return サイズ
		*/
		//-----------------------------------------------------------------//
		uint32_t size() const noexcept { return NUM; }

		//-----------------------------------------------------------------//
		/*!
			@brief	マスクを返す
			@return マスク
		*/
		//-----------------------------------------------------------------//
		uint32_t get_mask() const noexcept { return mask_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	分岐タスクを登録
			@param[in]	index	インデックス
			@param[in]	task	タスク
			@return 不正なインデックスの場合「false」
		*/
		//-----------------------------------------------------------------//
		bool set_task(uint32_t index, TASK task) noexcept
		{
			if(index < NUM) {
				task_[index] = task;
				if(task != nullptr) {
					mask_ |= 1 << index;
				} else {
					mask_ &= ~(1 << index);
				}
				return true;
			} else {
				return false;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	分岐タスクを取得
			@param[in]	index	インデックス
			@return 分岐タスク
		*/
		//-----------------------------------------------------------------//
		TASK get_task(uint32_t index) noexcept
		{
			if(index < NUM) {
				return task_[index];
			} else {
				return nullptr;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	分岐タスクを実行
			@param[in]	index	インデックス
		*/
		//-----------------------------------------------------------------//
		void run_task(uint32_t index) noexcept
		{
			if(index < NUM) {
				if(task_[index] != nullptr) {
					(*task_[index])();
				}
			}
		}
	};
}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2014 - 2015 Martin Buck
    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation the rights to
    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
    and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
    OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/**
 * \file    test_lib_2d.cpp
 * \author  Martin Buck
 * \date    November 2014
 * \version 1.0
 * \brief   contains several tests for the library
 */

#include <iostream>
#include <stdexcept>

#include "../lib_2d.h"

#define CATCH_CONFIG_MAIN
#include "../dependencies/Catch.h" //https://github.com/philsquared/Catch

#define OUTPUT_TEST_FILES

using namespace std;
using namespace lib_2d;

const double
    X(0.3),
    Y(4.5),
    MOVE_X(0.5),
    MOVE_Y(-10.0),
    MAX_DELTA(0.00001),
    PI (3.14159265358979323846);

TEST_CASE("testing Point") {

    Point <double> p(X, Y);
    auto p2 = p;

    SECTION ("testing initialisation") {
        REQUIRE(p.get_x() == X);
        REQUIRE(p.get_y() == Y);
    }

    SECTION("testing moving") {
        p.move_by(MOVE_X, MOVE_Y);

        REQUIRE(p.get_x() == X+MOVE_X);
        REQUIRE(p.get_y() == Y+MOVE_Y);
    }

    SECTION("testing parsing from and to strings") {
        std::string tmp = p.to_string();
        p.set_x(17);
        p.set_y(32);
        p.from_string(tmp);

        REQUIRE(p.to_string() == tmp);
    }

    SECTION("testing distances and abs") {
        REQUIRE(p.abs() == sqrt(  pow(p.get_x(),2) + pow(p.get_y(),2)  ));
        REQUIRE(p.distance_to(0.0, 0.0) == p.abs());
        REQUIRE(p.distance_to(p) == 0.0);
    }

    SECTION("testing rotation") {
        p2 = p;

        p.rotate(PI);
        REQUIRE(p.get_x() !=  p2.get_x());
        REQUIRE(p.get_y() !=  p2.get_y());

        p.rotate(PI);
        REQUIRE(abs(p.get_x() - p2.get_x()) < MAX_DELTA);
        REQUIRE(abs(p.get_y() - p2.get_y()) < MAX_DELTA);
    }

    SECTION("testing mirroring") {
        p2 = p;
        p.mirror_vertically();
        REQUIRE(p.get_y() == p2.get_y());
        REQUIRE(p.get_x() == -p2.get_x());

        p2 = p;
        p.mirror_horizontally();
        REQUIRE(p.get_x() == p2.get_x());
        REQUIRE(p.get_y() == -p2.get_y());

        p2 = p;
        p.mirror_point();
        REQUIRE(p.get_x() == -p2.get_x());
        REQUIRE(p.get_y() == -p2.get_y());
    }

    SECTION("testing equality tests") {
        p2 = p;
        REQUIRE(p2 == p);

        p.move_by(0.00000000001, 0.0);

        REQUIRE(p2 != p);
    }

    SECTION("testing conversion with pair") {
        p2 = p;
        pair <double, double> tmp = p;
        p = Point <double> (tmp);

        REQUIRE(p2 == p);

        tmp = pair <double,double> (0.3, 17.7);
        p = Point <double> (tmp);

        REQUIRE(p != p2);
    }

    SECTION("testing stringstream overload") {
        std::stringstream tmp;
        p2 = p;
        tmp << p;
        p.move_by(0.3, 7.9);
        p.from_string(tmp.str());

        REQUIRE(p == p2);
    }

    SECTION("testing similarity") {
        p2 = p;
        REQUIRE(p.similar_to(p2, MAX_DELTA));

        p.move_by(0.999 * MAX_DELTA,0);
        REQUIRE(p.similar_to(p2, MAX_DELTA));

        p2 = p;
        p.move_by(1.0001 * MAX_DELTA,0);
        REQUIRE(!p.similar_to(p2, MAX_DELTA));
    }

    SECTION("testing phi calculation") {
        p.set_x(0);
        p.set_y(1);
        REQUIRE(abs( p.phi() - PI/2.0) <= MAX_DELTA);

        p.set_x(-1);
        p.set_y(0);
        REQUIRE(abs( p.phi() - PI) <= MAX_DELTA);
    }

    SECTION("testing slope calculation") {
        p.set_x(0);
        p.set_y(0);

        p2.set_x(1);
        p2.set_y(2);

        REQUIRE(abs( p.slope_to(p2) - 2.0) <= MAX_DELTA);
    }

    SECTION("testing radians calculation") {
        p.set_x(1);
        p.set_y(1);

        p2.set_x(1);
        p2.set_y(2);

        REQUIRE(abs( p.rad_to(p2) - PI/2.0) <= MAX_DELTA);
    }

    SECTION("testing center calculation") {
        Point <double> center, centerShould;

        p = Point<double> (1,1);
        p2 = Point<double> (1,2);
        centerShould = Point <double> (1, 1.5);
        center = p.center_between(p2);

        REQUIRE(center.similar_to(centerShould, MAX_DELTA));
    }
}

TEST_CASE("testing Path") {
    Path<double> path = Path<double>();
    path.push_back(0.0, 0.0);
    path.push_back(1.0, 0.0);
    path.push_back(-1.0, 0.0);

    SECTION("testing center of path") {
        auto pathCenter = path.center();

        REQUIRE(pathCenter.abs() == 0.0);
    }

    SECTION("testing moving of path") {
        path.move_by(1.0, 0.0);
        auto pathCenter = path.center();

        REQUIRE( pathCenter.abs() == 1.0);
    }

    SECTION("testing rotation of path") {
        path.move_by(1.0, 0.0);
        path.rotate(PI);
        auto pathCenter = path.center();

        REQUIRE(pathCenter.abs() == 1.0);
        REQUIRE(pathCenter.get_x() == -1.0);
    }

    SECTION("testing parsing from and to string") {
        auto path2 = path;
        std::string path2String = path2.to_string();

        path.move_by(100, 1000);
        path.from_string(path2String);

        REQUIRE(path.similar_to(path2, MAX_DELTA));
    }

    SECTION("testing reversing of path") {
        path.push_back(13.0 ,137.3);
        auto path2 = path;

        path.reverse();
        REQUIRE(!path.similar_to(path2,MAX_DELTA));

        path.reverse();
        REQUIRE(path.similar_to(path2,MAX_DELTA));
    }

    SECTION("testing mirroring") {
        path.push_back(13.0 ,137.3);
        auto path2 = path;

        path.mirror_horizontally();
        REQUIRE(!path.similar_to(path2,MAX_DELTA));

        path.mirror_horizontally();
        REQUIRE(path.similar_to(path2,MAX_DELTA));
    }

    SECTION("testing intersections between paths") {
        Path<double> tmp = Path<double> ();
        tmp.push_back(-100,0);
        tmp.push_back(100,0);

        Path<double> tmp2 = Path<double> ();
        tmp2.push_back(0,-100);
        tmp2.push_back(0,100);

        auto intersections = tmp.intersections_with(tmp2);
        auto shouldIntersection = Point<double>(0,0);
        REQUIRE(intersections[0].similar_to(shouldIntersection,MAX_DELTA));

        tmp.move_by(0,-1);
        intersections = tmp.intersections_with(tmp2);
        shouldIntersection = Point<double>(0,-1);
        REQUIRE(intersections[0].similar_to(shouldIntersection,MAX_DELTA));

        tmp = Path<double> ();
        tmp.push_back(-100,100);
        tmp.push_back(100,-100);

        tmp2 = Path<double> ();
        tmp2.push_back(100,100);
        tmp2.push_back(-100,-100);

        intersections = tmp.intersections_with(tmp2);
        shouldIntersection = Point<double>(0,0);
        REQUIRE(intersections[0].similar_to(shouldIntersection,MAX_DELTA));
    }

    SECTION("testing sorting") {
        Path<double> tmp = Path<double> ();
        tmp.push_back(1,100);
        tmp.push_back(2,99);
        tmp.push_back(3,98);
        tmp.push_back(4,97);
        tmp.push_back(5,96);
        tmp.push_back(6,95);
        tmp.push_back(7,94);
        tmp.push_back(8,93);
        tmp.push_back(9,92);
        tmp.push_back(10,91);

        tmp.sort_y();
        for(unsigned int y=91; y <= 100; ++y)
            REQUIRE(tmp[y-91].get_y() == y);

        tmp.sort_x();
        for(unsigned int x=1; x <= 10; ++x)
            REQUIRE(tmp[x-1].get_x() == x);
    }

    SECTION("testing closest and furthest") {
        Path<double> tmp = Path<double> ();
        tmp.push_back(1,100);
        tmp.push_back(9,92);
        tmp.push_back(10,91);

        REQUIRE(tmp[tmp.furthest_apart(Point<double>())] == Point<double>(1,100));

        REQUIRE(tmp[tmp.closest(Point<double>())] == Point<double>(10,91));

        Path<double> tmp2 = Path<double> ();
        tmp2.push_back(Point<double>());

        REQUIRE(tmp[tmp.furthest_apart(tmp2)] == Point<double>(1,100));

        REQUIRE(tmp[tmp.closest(tmp2)] == Point<double>(10,91));
    }

    SECTION("testing average distance") {
        Path<double> tmp = Path<double> ();
        tmp.push_back(Point<double>());
        tmp.push_back(1,0);
        tmp.push_back(2,0);

        REQUIRE(tmp.average_distance() == 1);
    }

    SECTION("testing finding of points") {
        Path<double> tmp = Path<double> ();
        tmp.push_back(Point<double>());
        tmp.push_back(1,0);
        tmp.push_back(2,0);

        REQUIRE(tmp.index_of(Point<double>(2,0)) == 2);

        REQUIRE(tmp.index_of(Point<double>(222,0)) == -1);
    }

    SECTION("testing removal of points") {
        Path<double> tmp = Path<double> ();
        tmp.push_back(Point<double>());
        tmp.push_back(1,0);
        tmp.push_back(2,0);

        tmp.remove_from(5);
        tmp.remove_until(0);
        tmp.remove_left_of(0);
        tmp.remove_right_of(2);
        tmp.remove_above_of(0);
        tmp.remove_below_of(0);
        REQUIRE(tmp.size() == 3);

        tmp.push_back(0,17);
        tmp.remove_above_of(16);
        REQUIRE(tmp.size() == 3);

        tmp.push_back(0,-17);
        tmp.remove_below_of(-16);
        REQUIRE(tmp.size() == 3);

        tmp.push_back(17,17);
        tmp.remove_right_of(16);
        REQUIRE(tmp.size() == 3);

        tmp.push_back(-17,17);
        tmp.remove_left_of(-16);
        REQUIRE(tmp.size() == 3);

        tmp.remove_from(2);
        REQUIRE(tmp.size() == 2);

        tmp.remove_until(1);
        REQUIRE(tmp.size() == 1);
    }
}

TEST_CASE("testing Arc") {

    lib_2d::Arc<double> arc = lib_2d::Arc<double>(300.0, 100);
    SECTION("creation") {
        REQUIRE(arc.size() == 100);

#ifdef OUTPUT_TEST_FILES
        arc.to_file("arc_full.test");
#endif // OUTPUT_TEST_FILES

        arc = lib_2d::Arc<double>(300.0, 100, false, PI);

        REQUIRE(arc.size() == 100);
#ifdef OUTPUT_TEST_FILES
        arc.to_file("arc_semi.test");
#endif // OUTPUT_TEST_FILES
    }

    SECTION("moving") {
        arc.move_by(10,0);
        REQUIRE(arc.center() == Point<double>(10,0));
    }

    SECTION("rotation") {
        arc.move_by(10,0);
        arc.rotate(PI);
        auto center = arc.center();
        REQUIRE(center.get_x() == -10);
    }

}

TEST_CASE("testing InvolutCircle") {
    InvolutCircle<double> inv = InvolutCircle<double>(1.0, 100);

    REQUIRE(inv.size() == 100);
#ifdef OUTPUT_TEST_FILES
    inv.to_file("inv.test");
#endif // OUTPUT_TEST_FILES
}

TEST_CASE("testing bezier interpolation") {
    Path<double> tmp = Path<double> ();
    tmp.push_back(Point<double>());
    tmp.push_back(1,1);
    tmp.push_back(2,-5);
    InterpolationBezier<double> bezier = InterpolationBezier<double>(100, tmp);

    REQUIRE(bezier.size() == 100);
#ifdef OUTPUT_TEST_FILES
    bezier.to_file("bezier.test");
#endif // OUTPUT_TEST_FILES
}

TEST_CASE("testing linear interpolation") {
    Path<double> tmp = Path<double> ();
    tmp.push_back(Point<double>());
    tmp.push_back(1,1);
    tmp.push_back(2,-5);
    InterpolationLinear<double> linear = InterpolationLinear<double>(100, tmp);

    REQUIRE(linear.size() == 100);
#ifdef OUTPUT_TEST_FILES
    linear.to_file("linear.test");
#endif // OUTPUT_TEST_FILES

}
<commit_msg>added tests for arc mirroring<commit_after>/*
    Copyright (c) 2014 - 2015 Martin Buck
    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation the rights to
    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
    and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
    OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/**
 * \file    test_lib_2d.cpp
 * \author  Martin Buck
 * \date    November 2014
 * \version 1.0
 * \brief   contains several tests for the library
 */

#include <iostream>
#include <stdexcept>

#include "../lib_2d.h"

#define CATCH_CONFIG_MAIN
#include "../dependencies/Catch.h" //https://github.com/philsquared/Catch

#define OUTPUT_TEST_FILES

using namespace std;
using namespace lib_2d;

const double
    X(0.3),
    Y(4.5),
    MOVE_X(0.5),
    MOVE_Y(-10.0),
    MAX_DELTA(0.00001),
    PI (3.14159265358979323846);

TEST_CASE("testing Point") {

    Point <double> p(X, Y);
    auto p2 = p;

    SECTION ("testing initialisation") {
        REQUIRE(p.get_x() == X);
        REQUIRE(p.get_y() == Y);
    }

    SECTION("testing moving") {
        p.move_by(MOVE_X, MOVE_Y);

        REQUIRE(p.get_x() == X+MOVE_X);
        REQUIRE(p.get_y() == Y+MOVE_Y);
    }

    SECTION("testing parsing from and to strings") {
        std::string tmp = p.to_string();
        p.set_x(17);
        p.set_y(32);
        p.from_string(tmp);

        REQUIRE(p.to_string() == tmp);
    }

    SECTION("testing distances and abs") {
        REQUIRE(p.abs() == sqrt(  pow(p.get_x(),2) + pow(p.get_y(),2)  ));
        REQUIRE(p.distance_to(0.0, 0.0) == p.abs());
        REQUIRE(p.distance_to(p) == 0.0);
    }

    SECTION("testing rotation") {
        p2 = p;

        p.rotate(PI);
        REQUIRE(p.get_x() !=  p2.get_x());
        REQUIRE(p.get_y() !=  p2.get_y());

        p.rotate(PI);
        REQUIRE(abs(p.get_x() - p2.get_x()) < MAX_DELTA);
        REQUIRE(abs(p.get_y() - p2.get_y()) < MAX_DELTA);
    }

    SECTION("testing mirroring") {
        p2 = p;
        p.mirror_vertically();
        REQUIRE(p.get_y() == p2.get_y());
        REQUIRE(p.get_x() == -p2.get_x());

        p2 = p;
        p.mirror_horizontally();
        REQUIRE(p.get_x() == p2.get_x());
        REQUIRE(p.get_y() == -p2.get_y());

        p2 = p;
        p.mirror_point();
        REQUIRE(p.get_x() == -p2.get_x());
        REQUIRE(p.get_y() == -p2.get_y());
    }

    SECTION("testing equality tests") {
        p2 = p;
        REQUIRE(p2 == p);

        p.move_by(0.00000000001, 0.0);

        REQUIRE(p2 != p);
    }

    SECTION("testing conversion with pair") {
        p2 = p;
        pair <double, double> tmp = p;
        p = Point <double> (tmp);

        REQUIRE(p2 == p);

        tmp = pair <double,double> (0.3, 17.7);
        p = Point <double> (tmp);

        REQUIRE(p != p2);
    }

    SECTION("testing stringstream overload") {
        std::stringstream tmp;
        p2 = p;
        tmp << p;
        p.move_by(0.3, 7.9);
        p.from_string(tmp.str());

        REQUIRE(p == p2);
    }

    SECTION("testing similarity") {
        p2 = p;
        REQUIRE(p.similar_to(p2, MAX_DELTA));

        p.move_by(0.999 * MAX_DELTA,0);
        REQUIRE(p.similar_to(p2, MAX_DELTA));

        p2 = p;
        p.move_by(1.0001 * MAX_DELTA,0);
        REQUIRE(!p.similar_to(p2, MAX_DELTA));
    }

    SECTION("testing phi calculation") {
        p.set_x(0);
        p.set_y(1);
        REQUIRE(abs( p.phi() - PI/2.0) <= MAX_DELTA);

        p.set_x(-1);
        p.set_y(0);
        REQUIRE(abs( p.phi() - PI) <= MAX_DELTA);
    }

    SECTION("testing slope calculation") {
        p.set_x(0);
        p.set_y(0);

        p2.set_x(1);
        p2.set_y(2);

        REQUIRE(abs( p.slope_to(p2) - 2.0) <= MAX_DELTA);
    }

    SECTION("testing radians calculation") {
        p.set_x(1);
        p.set_y(1);

        p2.set_x(1);
        p2.set_y(2);

        REQUIRE(abs( p.rad_to(p2) - PI/2.0) <= MAX_DELTA);
    }

    SECTION("testing center calculation") {
        Point <double> center, centerShould;

        p = Point<double> (1,1);
        p2 = Point<double> (1,2);
        centerShould = Point <double> (1, 1.5);
        center = p.center_between(p2);

        REQUIRE(center.similar_to(centerShould, MAX_DELTA));
    }
}

TEST_CASE("testing Path") {
    Path<double> path = Path<double>();
    path.push_back(0.0, 0.0);
    path.push_back(1.0, 0.0);
    path.push_back(-1.0, 0.0);

    SECTION("testing center of path") {
        auto pathCenter = path.center();

        REQUIRE(pathCenter.abs() == 0.0);
    }

    SECTION("testing moving of path") {
        path.move_by(1.0, 0.0);
        auto pathCenter = path.center();

        REQUIRE( pathCenter.abs() == 1.0);
    }

    SECTION("testing rotation of path") {
        path.move_by(1.0, 0.0);
        path.rotate(PI);
        auto pathCenter = path.center();

        REQUIRE(pathCenter.abs() == 1.0);
        REQUIRE(pathCenter.get_x() == -1.0);
    }

    SECTION("testing parsing from and to string") {
        auto path2 = path;
        std::string path2String = path2.to_string();

        path.move_by(100, 1000);
        path.from_string(path2String);

        REQUIRE(path.similar_to(path2, MAX_DELTA));
    }

    SECTION("testing reversing of path") {
        path.push_back(13.0 ,137.3);
        auto path2 = path;

        path.reverse();
        REQUIRE(!path.similar_to(path2,MAX_DELTA));

        path.reverse();
        REQUIRE(path.similar_to(path2,MAX_DELTA));
    }

    SECTION("testing mirroring") {
        path.push_back(13.0 ,137.3);
        auto path2 = path;

        path.mirror_horizontally();
        REQUIRE(!path.similar_to(path2,MAX_DELTA));

        path.mirror_horizontally();
        REQUIRE(path.similar_to(path2,MAX_DELTA));
    }

    SECTION("testing intersections between paths") {
        Path<double> tmp = Path<double> ();
        tmp.push_back(-100,0);
        tmp.push_back(100,0);

        Path<double> tmp2 = Path<double> ();
        tmp2.push_back(0,-100);
        tmp2.push_back(0,100);

        auto intersections = tmp.intersections_with(tmp2);
        auto shouldIntersection = Point<double>(0,0);
        REQUIRE(intersections[0].similar_to(shouldIntersection,MAX_DELTA));

        tmp.move_by(0,-1);
        intersections = tmp.intersections_with(tmp2);
        shouldIntersection = Point<double>(0,-1);
        REQUIRE(intersections[0].similar_to(shouldIntersection,MAX_DELTA));

        tmp = Path<double> ();
        tmp.push_back(-100,100);
        tmp.push_back(100,-100);

        tmp2 = Path<double> ();
        tmp2.push_back(100,100);
        tmp2.push_back(-100,-100);

        intersections = tmp.intersections_with(tmp2);
        shouldIntersection = Point<double>(0,0);
        REQUIRE(intersections[0].similar_to(shouldIntersection,MAX_DELTA));
    }

    SECTION("testing sorting") {
        Path<double> tmp = Path<double> ();
        tmp.push_back(1,100);
        tmp.push_back(2,99);
        tmp.push_back(3,98);
        tmp.push_back(4,97);
        tmp.push_back(5,96);
        tmp.push_back(6,95);
        tmp.push_back(7,94);
        tmp.push_back(8,93);
        tmp.push_back(9,92);
        tmp.push_back(10,91);

        tmp.sort_y();
        for(unsigned int y=91; y <= 100; ++y)
            REQUIRE(tmp[y-91].get_y() == y);

        tmp.sort_x();
        for(unsigned int x=1; x <= 10; ++x)
            REQUIRE(tmp[x-1].get_x() == x);
    }

    SECTION("testing closest and furthest") {
        Path<double> tmp = Path<double> ();
        tmp.push_back(1,100);
        tmp.push_back(9,92);
        tmp.push_back(10,91);

        REQUIRE(tmp[tmp.furthest_apart(Point<double>())] == Point<double>(1,100));

        REQUIRE(tmp[tmp.closest(Point<double>())] == Point<double>(10,91));

        Path<double> tmp2 = Path<double> ();
        tmp2.push_back(Point<double>());

        REQUIRE(tmp[tmp.furthest_apart(tmp2)] == Point<double>(1,100));

        REQUIRE(tmp[tmp.closest(tmp2)] == Point<double>(10,91));
    }

    SECTION("testing average distance") {
        Path<double> tmp = Path<double> ();
        tmp.push_back(Point<double>());
        tmp.push_back(1,0);
        tmp.push_back(2,0);

        REQUIRE(tmp.average_distance() == 1);
    }

    SECTION("testing finding of points") {
        Path<double> tmp = Path<double> ();
        tmp.push_back(Point<double>());
        tmp.push_back(1,0);
        tmp.push_back(2,0);

        REQUIRE(tmp.index_of(Point<double>(2,0)) == 2);

        REQUIRE(tmp.index_of(Point<double>(222,0)) == -1);
    }

    SECTION("testing removal of points") {
        Path<double> tmp = Path<double> ();
        tmp.push_back(Point<double>());
        tmp.push_back(1,0);
        tmp.push_back(2,0);

        tmp.remove_from(5);
        tmp.remove_until(0);
        tmp.remove_left_of(0);
        tmp.remove_right_of(2);
        tmp.remove_above_of(0);
        tmp.remove_below_of(0);
        REQUIRE(tmp.size() == 3);

        tmp.push_back(0,17);
        tmp.remove_above_of(16);
        REQUIRE(tmp.size() == 3);

        tmp.push_back(0,-17);
        tmp.remove_below_of(-16);
        REQUIRE(tmp.size() == 3);

        tmp.push_back(17,17);
        tmp.remove_right_of(16);
        REQUIRE(tmp.size() == 3);

        tmp.push_back(-17,17);
        tmp.remove_left_of(-16);
        REQUIRE(tmp.size() == 3);

        tmp.remove_from(2);
        REQUIRE(tmp.size() == 2);

        tmp.remove_until(1);
        REQUIRE(tmp.size() == 1);
    }
}

TEST_CASE("testing Arc") {

    lib_2d::Arc<double> arc = lib_2d::Arc<double>(300.0, 100);
    SECTION("creation") {
        REQUIRE(arc.size() == 100);

#ifdef OUTPUT_TEST_FILES
        arc.to_file("arc_full.test");
#endif // OUTPUT_TEST_FILES

        arc = lib_2d::Arc<double>(300.0, 100, false, PI);

        REQUIRE(arc.size() == 100);
#ifdef OUTPUT_TEST_FILES
        arc.to_file("arc_semi.test");
#endif // OUTPUT_TEST_FILES
    }

    SECTION("moving") {
        arc.move_by(10,0);
        REQUIRE(arc.center() == Point<double>(10,0));
    }

    SECTION("rotation") {
        arc.move_by(10,0);
        arc.rotate(PI);
        auto center = arc.center();
        REQUIRE(center.get_x() == -10);
    }

    SECTION("mirroring") {
        arc.move_by(10,5);

        arc.mirror_vertically();
        auto center = arc.center();
        REQUIRE(center.get_x() == -10);
        REQUIRE(center.get_y() == 5);

        arc.mirror_horizontally();
        center = arc.center();
        REQUIRE(center.get_x() == -10);
        REQUIRE(center.get_y() == -5);
    }

}

TEST_CASE("testing InvolutCircle") {
    InvolutCircle<double> inv = InvolutCircle<double>(1.0, 100);

    REQUIRE(inv.size() == 100);
#ifdef OUTPUT_TEST_FILES
    inv.to_file("inv.test");
#endif // OUTPUT_TEST_FILES
}

TEST_CASE("testing bezier interpolation") {
    Path<double> tmp = Path<double> ();
    tmp.push_back(Point<double>());
    tmp.push_back(1,1);
    tmp.push_back(2,-5);
    InterpolationBezier<double> bezier = InterpolationBezier<double>(100, tmp);

    REQUIRE(bezier.size() == 100);
#ifdef OUTPUT_TEST_FILES
    bezier.to_file("bezier.test");
#endif // OUTPUT_TEST_FILES
}

TEST_CASE("testing linear interpolation") {
    Path<double> tmp = Path<double> ();
    tmp.push_back(Point<double>());
    tmp.push_back(1,1);
    tmp.push_back(2,-5);
    InterpolationLinear<double> linear = InterpolationLinear<double>(100, tmp);

    REQUIRE(linear.size() == 100);
#ifdef OUTPUT_TEST_FILES
    linear.to_file("linear.test");
#endif // OUTPUT_TEST_FILES

}
<|endoftext|>


<commit_before>#include "config.hpp"
#include "mapcss/StyleSheet.hpp"
#include "mapcss/MapCssParser.cpp"
#include "utils/CoreUtils.hpp"

#include <boost/test/unit_test.hpp>

using namespace utymap::mapcss;
using namespace utymap::meshing;

namespace {
    typedef std::string::const_iterator StringIterator;

    struct MapCss_MapCssParserFixture {
        MapCss_MapCssParserFixture() :
            stylesheet(),
            styleSheetGrammar("", stylesheet)
        {
        }

        // parsed data
        StyleSheet stylesheet;
        Condition condition;
        Zoom zoom;
        Selector selector;
        Declaration declaration;
        Rule rule;
        // grammars
        CommentSkipper<StringIterator> skipper;
        StyleSheetGrammar<StringIterator> styleSheetGrammar;
        ConditionGrammar<StringIterator> conditionGrammar;
        ZoomGrammar<StringIterator> zoomGrammar;
        SelectorGrammar<StringIterator> selectorGrammar;
        DeclarationGrammar<StringIterator> declarationGrammar;
        RuleGrammar<StringIterator> ruleGrammar;
    };
}

BOOST_FIXTURE_TEST_SUITE(MapCss_MapCssParser, MapCss_MapCssParserFixture)

/* Comment */
BOOST_AUTO_TEST_CASE(GivenCppComment_WhenParse_ThenDoesNotBreak)
{
    std::string str = "/* Some \nncomment */\n way|z1-15[highway] {key:value;}";

    bool success = phrase_parse(str.cbegin(), str.cend(), styleSheetGrammar, skipper, stylesheet);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 1);
}

BOOST_AUTO_TEST_CASE(GivenHtmlComment_WhenParse_ThenDoesNotBreak)
{
    std::string str = "<!--Some \ncomment-->\n way|z1-15[highway] {key:value;}";

    bool success = phrase_parse(str.cbegin(), str.cend(), styleSheetGrammar, skipper, stylesheet);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 1);
}

/* Condition */
BOOST_AUTO_TEST_CASE(GivenExistenceCondition_WhenParse_ThenOnlyKeyIsSet)
{
    std::string str = "[highway]";

    bool success = phrase_parse(str.cbegin(), str.cend(), conditionGrammar, skipper, condition);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(condition.key, "highway");
    BOOST_CHECK(condition.operation.empty());
    BOOST_CHECK(condition.value.empty());
}

BOOST_AUTO_TEST_CASE(GivenEqualCondition_WhenParse_ThenKeyOpValueAreSet)
{
    std::string str = "[highway=primary]";

    bool success = phrase_parse(str.cbegin(), str.cend(), conditionGrammar, skipper, condition);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(condition.key, "highway");
    BOOST_CHECK_EQUAL(condition.operation, "=");
    BOOST_CHECK_EQUAL(condition.value, "primary");
}

BOOST_AUTO_TEST_CASE(GivenNegativeCondition_WhenParse_ThenKeyOpValueAreSet)
{
    std::string str = "[highway!=primary]";

    bool success = phrase_parse(str.cbegin(), str.cend(), conditionGrammar, skipper, condition);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(condition.key, "highway");
    BOOST_CHECK_EQUAL(condition.operation, "!=");
    BOOST_CHECK_EQUAL(condition.value, "primary");
}

/* Zoom */
BOOST_AUTO_TEST_CASE(GivenOneZoom_WhenParse_ThenStartAndEndAreSet)
{
    std::string str = "|z1";

    bool success = phrase_parse(str.cbegin(), str.cend(), zoomGrammar, skipper, zoom);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(zoom.start, 1);
    BOOST_CHECK_EQUAL(zoom.end, 1);
}

BOOST_AUTO_TEST_CASE(GivenZoomRange_WhenParse_ThenStartAndEndAreSet)
{
    std::string str = "|z12-21";

    bool success = phrase_parse(str.cbegin(), str.cend(), zoomGrammar, skipper, zoom);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(zoom.start, 12);
    BOOST_CHECK_EQUAL(zoom.end, 21);
}

/* Selector */
BOOST_AUTO_TEST_CASE(GivenSingleSelector_WhenParse_ThenNameAndConditionsAreSet)
{
    std::string str = "way|z1[highway]";

    bool success = phrase_parse(str.cbegin(), str.cend(), selectorGrammar, skipper, selector);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(selector.names.size(), 1);
    BOOST_CHECK_EQUAL(selector.names[0], "way");
    BOOST_CHECK_EQUAL(selector.conditions.size(), 1);
    BOOST_CHECK_EQUAL(selector.conditions[0].key, "highway");
}

BOOST_AUTO_TEST_CASE(GivenTwoSelectors_WhenParse_ThenNameAndConditionsAreSet)
{
    std::string str = "way|z1[highway][landuse]";

    bool success = phrase_parse(str.cbegin(), str.cend(), selectorGrammar, skipper, selector);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(selector.names.size(), 1);
    BOOST_CHECK_EQUAL(selector.names[0], "way");
    BOOST_CHECK_EQUAL(selector.conditions.size(), 2);
    BOOST_CHECK_EQUAL(selector.conditions[0].key, "highway");
    BOOST_CHECK_EQUAL(selector.conditions[1].key, "landuse");
}

BOOST_AUTO_TEST_CASE(GivenTwoSelectorNames_WhenParse_ThenNamesAndConditionsAreSet)
{
    std::string str = "area,relation|z1[building][part]";

    bool success = phrase_parse(str.cbegin(), str.cend(), selectorGrammar, skipper, selector);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(selector.names.size(), 2);
    BOOST_CHECK_EQUAL(selector.names[0], "area");
    BOOST_CHECK_EQUAL(selector.names[1], "relation");
    BOOST_CHECK_EQUAL(selector.conditions.size(), 2);
    BOOST_CHECK_EQUAL(selector.conditions[0].key, "building");
    BOOST_CHECK_EQUAL(selector.conditions[1].key, "part");
}

/* Declaration */
BOOST_AUTO_TEST_CASE(GivenSingleDeclaraion_WhenParse_ThenKeyValueAreSet)
{
    std::string str = "key1:value1;";

    bool success = phrase_parse(str.cbegin(), str.cend(), declarationGrammar, skipper, declaration);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(declaration.key, "key1");
    BOOST_CHECK_EQUAL(declaration.value, "value1");
}

BOOST_AUTO_TEST_CASE(GivenGradientDeclaraion_WhenParse_ThenGradientValueIsCorrect)
{
    std::string str = "color:gradient(#dcdcdc 0%, #c0c0c0 10%, #a9a9a9 50%, #808080);";

    bool success = phrase_parse(str.cbegin(), str.cend(), declarationGrammar, skipper, declaration);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(declaration.key, "color");
    BOOST_CHECK_EQUAL(declaration.value, "gradient(#dcdcdc 0%, #c0c0c0 10%, #a9a9a9 50%, #808080)");
}

/* Rule */
BOOST_AUTO_TEST_CASE(GivenSimpleRule_WhenParse_ThenSelectorAndDeclarationAreSet)
{
    std::string str = "way|z1[highway] {key1:value1;}";

    bool success = phrase_parse(str.cbegin(), str.cend(), ruleGrammar, skipper, rule);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(rule.selectors.size(), 1);
    BOOST_CHECK_EQUAL(rule.declarations.size(), 1);
    BOOST_CHECK_EQUAL(rule.selectors[0].conditions[0].key , "highway");
    BOOST_CHECK_EQUAL(rule.declarations[0].key, "key1");
    BOOST_CHECK_EQUAL(rule.declarations[0].value,"value1");
}

BOOST_AUTO_TEST_CASE(GivenComplexRule_WhenParse_ThenSelectorAndDeclarationAreSet)
{
    std::string str = "way|z1[highway],area|z2[landuse] { key1:value1; key2:value2; }";

    bool success = phrase_parse(str.cbegin(), str.cend(), ruleGrammar, skipper, rule);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(rule.selectors.size(), 2);
    BOOST_CHECK_EQUAL(rule.declarations.size(), 2);
    BOOST_CHECK_EQUAL(rule.selectors[0].names.size(), 1);
    BOOST_CHECK_EQUAL(rule.selectors[0].names[0], "way");
    BOOST_CHECK_EQUAL(rule.selectors[1].names.size(), 1);
    BOOST_CHECK_EQUAL(rule.selectors[1].names[0], "area");
    BOOST_CHECK_EQUAL(rule.selectors[0].conditions[0].key, "highway");
    BOOST_CHECK_EQUAL(rule.selectors[1].conditions[0].key, "landuse");
    BOOST_CHECK_EQUAL(rule.declarations[0].key,"key1");
    BOOST_CHECK_EQUAL(rule.declarations[0].value, "value1");
    BOOST_CHECK_EQUAL(rule.declarations[1].key, "key2");
    BOOST_CHECK_EQUAL(rule.declarations[1].value, "value2");
}

/* StyleSheet */
BOOST_AUTO_TEST_CASE(GivenFourRulesOnDifferentLines_WhenParse_ThenHasFourRules)
{
    std::string str =
        "way|z1[highway]  { key1:value1; }\n"
        "area|z2[landuse] { key2:value2; }\n"
        "node|z3[amenity] { key3:value3; }\n"
        "canvas|z3        { key4:value4; }";

    phrase_parse(str.cbegin(), str.cend(), styleSheetGrammar, skipper, stylesheet);

    BOOST_CHECK_EQUAL( stylesheet.rules.size(), 4) ;
}

BOOST_AUTO_TEST_CASE(GivenImport_WhenParse_ThenStyleSheetIsImported)
{
    std::string str = "@import url(\"import.mapcss\");";
    ImportGrammar<StringIterator> importGrammar(TEST_MAPCSS_PATH, stylesheet);

    bool success = phrase_parse(str.cbegin(), str.cend(), importGrammar, skipper);

    BOOST_CHECK(success);
}

BOOST_AUTO_TEST_CASE(GivenSimpleStyleSheet_WhenParserParse_ThenNoErrorsAndHasValidStyleSheet)
{
    std::string str = "way|z1[highway]  { key1:value1; }\n";
    MapCssParser parser;

    StyleSheet stylesheet = parser.parse(str);

    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 1);
}

BOOST_AUTO_TEST_CASE(GivenCanvasRule_WhenParse_ThenProcessValidStyleSheet)
{
    std::string str = "canvas|z1 { key1:value1; }\n";
    MapCssParser parser;

    StyleSheet stylesheet = parser.parse(str);

    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 1);
}

BOOST_AUTO_TEST_CASE(GivenSimpleRuleWithZoomRange_WhenParse_ThenReturnCorrectZoomStartAndEnd)
{
    std::string str = "way|z1-12[highway]{key1:value1;}";
    MapCssParser parser;

    StyleSheet stylesheet = parser.parse(str);

    Selector selector = stylesheet.rules[0].selectors[0];
    BOOST_CHECK_EQUAL(selector.zoom.start, 1);
    BOOST_CHECK_EQUAL(selector.zoom.end, 12);
}

BOOST_AUTO_TEST_CASE(GivenRuleWithGradient_WhenParse_ThenReturnCorrectGradientValue)
{
    std::string str = "way|z1-12[highway]{color:gradient(#dcdcdc 0%, #c0c0c0 10%, #a9a9a9 50%, #808080);}";
    MapCssParser parser;

    StyleSheet stylesheet = parser.parse(str);

    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 1);
    BOOST_CHECK_EQUAL(stylesheet.rules[0].declarations[0].value, "gradient(#dcdcdc 0%, #c0c0c0 10%, #a9a9a9 50%, #808080)");
}

BOOST_AUTO_TEST_CASE(GivenSimpleRule_WhenToString_ThenReturnCorrectRepresentation)
{
    std::string str = "way|z1-12[highway]{key1:value1;}";
    MapCssParser parser;

    StyleSheet stylesheet = parser.parse(str);

    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 1);
    BOOST_CHECK_EQUAL(utymap::utils::toString(stylesheet.rules[0]), str);
}

BOOST_AUTO_TEST_CASE(GivenImportFile_WhenParse_ThenAllRulesAreMerged)
{
    std::ifstream styleFile(TEST_MAPCSS_PATH "import.mapcss");
    MapCssParser parser(TEST_MAPCSS_PATH);

    StyleSheet stylesheet = parser.parse(styleFile);

    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 5);
}

BOOST_AUTO_TEST_CASE(GivenTwoTextureRegions_WhenParse_ThenHasTwoRegions)
{
    std::ifstream styleFile(TEST_MAPCSS_PATH "import.mapcss");
    MapCssParser parser(TEST_MAPCSS_PATH);

    StyleSheet stylesheet = parser.parse(styleFile);

    BOOST_CHECK_EQUAL(stylesheet.textures.size(), 2);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>core: fix broken unit test<commit_after>#include "config.hpp"
#include "mapcss/StyleSheet.hpp"
#include "mapcss/MapCssParser.cpp"
#include "utils/CoreUtils.hpp"

#include <boost/test/unit_test.hpp>

using namespace utymap::mapcss;
using namespace utymap::meshing;

namespace {
    typedef std::string::const_iterator StringIterator;

    struct MapCss_MapCssParserFixture {
        MapCss_MapCssParserFixture() :
            stylesheet(),
            styleSheetGrammar("", stylesheet)
        {
        }

        // parsed data
        StyleSheet stylesheet;
        Condition condition;
        Zoom zoom;
        Selector selector;
        Declaration declaration;
        Rule rule;
        // grammars
        CommentSkipper<StringIterator> skipper;
        StyleSheetGrammar<StringIterator> styleSheetGrammar;
        ConditionGrammar<StringIterator> conditionGrammar;
        ZoomGrammar<StringIterator> zoomGrammar;
        SelectorGrammar<StringIterator> selectorGrammar;
        DeclarationGrammar<StringIterator> declarationGrammar;
        RuleGrammar<StringIterator> ruleGrammar;
    };
}

BOOST_FIXTURE_TEST_SUITE(MapCss_MapCssParser, MapCss_MapCssParserFixture)

/* Comment */
BOOST_AUTO_TEST_CASE(GivenCppComment_WhenParse_ThenDoesNotBreak)
{
    std::string str = "/* Some \nncomment */\n way|z1-15[highway] {key:value;}";

    bool success = phrase_parse(str.cbegin(), str.cend(), styleSheetGrammar, skipper, stylesheet);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 1);
}

BOOST_AUTO_TEST_CASE(GivenHtmlComment_WhenParse_ThenDoesNotBreak)
{
    std::string str = "<!--Some \ncomment-->\n way|z1-15[highway] {key:value;}";

    bool success = phrase_parse(str.cbegin(), str.cend(), styleSheetGrammar, skipper, stylesheet);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 1);
}

/* Condition */
BOOST_AUTO_TEST_CASE(GivenExistenceCondition_WhenParse_ThenOnlyKeyIsSet)
{
    std::string str = "[highway]";

    bool success = phrase_parse(str.cbegin(), str.cend(), conditionGrammar, skipper, condition);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(condition.key, "highway");
    BOOST_CHECK(condition.operation.empty());
    BOOST_CHECK(condition.value.empty());
}

BOOST_AUTO_TEST_CASE(GivenEqualCondition_WhenParse_ThenKeyOpValueAreSet)
{
    std::string str = "[highway=primary]";

    bool success = phrase_parse(str.cbegin(), str.cend(), conditionGrammar, skipper, condition);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(condition.key, "highway");
    BOOST_CHECK_EQUAL(condition.operation, "=");
    BOOST_CHECK_EQUAL(condition.value, "primary");
}

BOOST_AUTO_TEST_CASE(GivenNegativeCondition_WhenParse_ThenKeyOpValueAreSet)
{
    std::string str = "[highway!=primary]";

    bool success = phrase_parse(str.cbegin(), str.cend(), conditionGrammar, skipper, condition);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(condition.key, "highway");
    BOOST_CHECK_EQUAL(condition.operation, "!=");
    BOOST_CHECK_EQUAL(condition.value, "primary");
}

/* Zoom */
BOOST_AUTO_TEST_CASE(GivenOneZoom_WhenParse_ThenStartAndEndAreSet)
{
    std::string str = "|z1";

    bool success = phrase_parse(str.cbegin(), str.cend(), zoomGrammar, skipper, zoom);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(zoom.start, 1);
    BOOST_CHECK_EQUAL(zoom.end, 1);
}

BOOST_AUTO_TEST_CASE(GivenZoomRange_WhenParse_ThenStartAndEndAreSet)
{
    std::string str = "|z12-21";

    bool success = phrase_parse(str.cbegin(), str.cend(), zoomGrammar, skipper, zoom);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(zoom.start, 12);
    BOOST_CHECK_EQUAL(zoom.end, 21);
}

/* Selector */
BOOST_AUTO_TEST_CASE(GivenSingleSelector_WhenParse_ThenNameAndConditionsAreSet)
{
    std::string str = "way|z1[highway]";

    bool success = phrase_parse(str.cbegin(), str.cend(), selectorGrammar, skipper, selector);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(selector.names.size(), 1);
    BOOST_CHECK_EQUAL(selector.names[0], "way");
    BOOST_CHECK_EQUAL(selector.conditions.size(), 1);
    BOOST_CHECK_EQUAL(selector.conditions[0].key, "highway");
}

BOOST_AUTO_TEST_CASE(GivenTwoSelectors_WhenParse_ThenNameAndConditionsAreSet)
{
    std::string str = "way|z1[highway][landuse]";

    bool success = phrase_parse(str.cbegin(), str.cend(), selectorGrammar, skipper, selector);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(selector.names.size(), 1);
    BOOST_CHECK_EQUAL(selector.names[0], "way");
    BOOST_CHECK_EQUAL(selector.conditions.size(), 2);
    BOOST_CHECK_EQUAL(selector.conditions[0].key, "highway");
    BOOST_CHECK_EQUAL(selector.conditions[1].key, "landuse");
}

BOOST_AUTO_TEST_CASE(GivenTwoSelectorNames_WhenParse_ThenNamesAndConditionsAreSet)
{
    std::string str = "area,relation|z1[building][part]";

    bool success = phrase_parse(str.cbegin(), str.cend(), selectorGrammar, skipper, selector);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(selector.names.size(), 2);
    BOOST_CHECK_EQUAL(selector.names[0], "area");
    BOOST_CHECK_EQUAL(selector.names[1], "relation");
    BOOST_CHECK_EQUAL(selector.conditions.size(), 2);
    BOOST_CHECK_EQUAL(selector.conditions[0].key, "building");
    BOOST_CHECK_EQUAL(selector.conditions[1].key, "part");
}

/* Declaration */
BOOST_AUTO_TEST_CASE(GivenSingleDeclaraion_WhenParse_ThenKeyValueAreSet)
{
    std::string str = "key1:value1;";

    bool success = phrase_parse(str.cbegin(), str.cend(), declarationGrammar, skipper, declaration);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(declaration.key, "key1");
    BOOST_CHECK_EQUAL(declaration.value, "value1");
}

BOOST_AUTO_TEST_CASE(GivenGradientDeclaraion_WhenParse_ThenGradientValueIsCorrect)
{
    std::string str = "color:gradient(#dcdcdc 0%, #c0c0c0 10%, #a9a9a9 50%, #808080);";

    bool success = phrase_parse(str.cbegin(), str.cend(), declarationGrammar, skipper, declaration);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(declaration.key, "color");
    BOOST_CHECK_EQUAL(declaration.value, "gradient(#dcdcdc 0%, #c0c0c0 10%, #a9a9a9 50%, #808080)");
}

/* Rule */
BOOST_AUTO_TEST_CASE(GivenSimpleRule_WhenParse_ThenSelectorAndDeclarationAreSet)
{
    std::string str = "way|z1[highway] {key1:value1;}";

    bool success = phrase_parse(str.cbegin(), str.cend(), ruleGrammar, skipper, rule);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(rule.selectors.size(), 1);
    BOOST_CHECK_EQUAL(rule.declarations.size(), 1);
    BOOST_CHECK_EQUAL(rule.selectors[0].conditions[0].key , "highway");
    BOOST_CHECK_EQUAL(rule.declarations[0].key, "key1");
    BOOST_CHECK_EQUAL(rule.declarations[0].value,"value1");
}

BOOST_AUTO_TEST_CASE(GivenComplexRule_WhenParse_ThenSelectorAndDeclarationAreSet)
{
    std::string str = "way|z1[highway],area|z2[landuse] { key1:value1; key2:value2; }";

    bool success = phrase_parse(str.cbegin(), str.cend(), ruleGrammar, skipper, rule);

    BOOST_CHECK(success);
    BOOST_CHECK_EQUAL(rule.selectors.size(), 2);
    BOOST_CHECK_EQUAL(rule.declarations.size(), 2);
    BOOST_CHECK_EQUAL(rule.selectors[0].names.size(), 1);
    BOOST_CHECK_EQUAL(rule.selectors[0].names[0], "way");
    BOOST_CHECK_EQUAL(rule.selectors[1].names.size(), 1);
    BOOST_CHECK_EQUAL(rule.selectors[1].names[0], "area");
    BOOST_CHECK_EQUAL(rule.selectors[0].conditions[0].key, "highway");
    BOOST_CHECK_EQUAL(rule.selectors[1].conditions[0].key, "landuse");
    BOOST_CHECK_EQUAL(rule.declarations[0].key,"key1");
    BOOST_CHECK_EQUAL(rule.declarations[0].value, "value1");
    BOOST_CHECK_EQUAL(rule.declarations[1].key, "key2");
    BOOST_CHECK_EQUAL(rule.declarations[1].value, "value2");
}

/* StyleSheet */
BOOST_AUTO_TEST_CASE(GivenFourRulesOnDifferentLines_WhenParse_ThenHasFourRules)
{
    std::string str =
        "way|z1[highway]  { key1:value1; }\n"
        "area|z2[landuse] { key2:value2; }\n"
        "node|z3[amenity] { key3:value3; }\n"
        "canvas|z3        { key4:value4; }";

    phrase_parse(str.cbegin(), str.cend(), styleSheetGrammar, skipper, stylesheet);

    BOOST_CHECK_EQUAL( stylesheet.rules.size(), 4) ;
}

BOOST_AUTO_TEST_CASE(GivenImport_WhenParse_ThenStyleSheetIsImported)
{
    std::string str = "@import url(\"import.mapcss\");";
    ImportGrammar<StringIterator> importGrammar(TEST_MAPCSS_PATH, stylesheet);

    bool success = phrase_parse(str.cbegin(), str.cend(), importGrammar, skipper);

    BOOST_CHECK(success);
}

BOOST_AUTO_TEST_CASE(GivenSimpleStyleSheet_WhenParserParse_ThenNoErrorsAndHasValidStyleSheet)
{
    std::string str = "way|z1[highway]  { key1:value1; }\n";
    MapCssParser parser;

    StyleSheet stylesheet = parser.parse(str);

    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 1);
}

BOOST_AUTO_TEST_CASE(GivenCanvasRule_WhenParse_ThenProcessValidStyleSheet)
{
    std::string str = "canvas|z1 { key1:value1; }\n";
    MapCssParser parser;

    StyleSheet stylesheet = parser.parse(str);

    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 1);
}

BOOST_AUTO_TEST_CASE(GivenSimpleRuleWithZoomRange_WhenParse_ThenReturnCorrectZoomStartAndEnd)
{
    std::string str = "way|z1-12[highway]{key1:value1;}";
    MapCssParser parser;

    StyleSheet stylesheet = parser.parse(str);

    Selector selector = stylesheet.rules[0].selectors[0];
    BOOST_CHECK_EQUAL(selector.zoom.start, 1);
    BOOST_CHECK_EQUAL(selector.zoom.end, 12);
}

BOOST_AUTO_TEST_CASE(GivenRuleWithGradient_WhenParse_ThenReturnCorrectGradientValue)
{
    std::string str = "way|z1-12[highway]{color:gradient(#dcdcdc 0%, #c0c0c0 10%, #a9a9a9 50%, #808080);}";
    MapCssParser parser;

    StyleSheet stylesheet = parser.parse(str);

    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 1);
    BOOST_CHECK_EQUAL(stylesheet.rules[0].declarations[0].value, "gradient(#dcdcdc 0%, #c0c0c0 10%, #a9a9a9 50%, #808080)");
}

BOOST_AUTO_TEST_CASE(GivenSimpleRule_WhenToString_ThenReturnCorrectRepresentation)
{
    std::string str = "way|z1-12[highway]{key1:value1;}";
    MapCssParser parser;

    StyleSheet stylesheet = parser.parse(str);

    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 1);
    BOOST_CHECK_EQUAL(utymap::utils::toString(stylesheet.rules[0]), str);
}

BOOST_AUTO_TEST_CASE(GivenImportFile_WhenParse_ThenAllRulesAreMerged)
{
    std::ifstream styleFile(TEST_MAPCSS_PATH "import.mapcss");
    MapCssParser parser(TEST_MAPCSS_PATH);

    StyleSheet stylesheet = parser.parse(styleFile);

    BOOST_CHECK_EQUAL(stylesheet.rules.size(), 5);
}

BOOST_AUTO_TEST_CASE(GivenImportFile_WhenParse_ThenHasOneTexture)
{
    std::ifstream styleFile(TEST_MAPCSS_PATH "import.mapcss");
    MapCssParser parser(TEST_MAPCSS_PATH);

    StyleSheet stylesheet = parser.parse(styleFile);

    BOOST_CHECK_EQUAL(stylesheet.textures.size(), 1);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008, British Broadcasting Corporation
 * All Rights Reserved.
 *
 * Author: Philip de Nier
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the British Broadcasting Corporation nor the names
 *       of its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <libMXF++/MXF.h>

using namespace std;
using namespace mxfpp;

Preface::Preface(HeaderMetadata *headerMetadata)
: PrefaceBase(headerMetadata)
{}

Preface::Preface(HeaderMetadata *headerMetadata, ::MXFMetadataSet *cMetadataSet)
: PrefaceBase(headerMetadata, cMetadataSet)
{}

Preface::~Preface()
{}

GenericPackage* Preface::findPackage(mxfUMID package_uid) const
{
    vector<GenericPackage*> packages = getContentStorage()->getPackages();
    mxfUMID uid;
    size_t i;
    for (i = 0; i < packages.size(); i++) {
        uid = packages[i]->getPackageUID();
        if (mxf_equals_umid(&package_uid, &uid))
            return packages[i];
    }

    return 0;
}

MaterialPackage* Preface::findMaterialPackage() const
{
    vector<GenericPackage*> packages = getContentStorage()->getPackages();
    MaterialPackage *material_package;
    size_t i;
    for (i = 0; i < packages.size(); i++) {
        material_package = dynamic_cast<MaterialPackage*>(packages[i]);
        if (material_package)
            return material_package;
    }

    return 0;
}

vector<SourcePackage*> Preface::findFileSourcePackages() const
{
    vector<GenericPackage*> packages = getContentStorage()->getPackages();
    vector<SourcePackage*> file_packages;
    SourcePackage *file_package;
    size_t i;
    for (i = 0; i < packages.size(); i++) {
        file_package = dynamic_cast<SourcePackage*>(packages[i]);
        if (!file_package ||
            !file_package->haveDescriptor() || !dynamic_cast<FileDescriptor*>(file_package->getDescriptor()))
        {
            continue;
        }

        file_packages.push_back(file_package);
    }

    return file_packages;
}

<commit_msg>avoid exception in Preface::findFileSourcePackages when descriptor is dark<commit_after>/*
 * Copyright (C) 2008, British Broadcasting Corporation
 * All Rights Reserved.
 *
 * Author: Philip de Nier
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the British Broadcasting Corporation nor the names
 *       of its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <libMXF++/MXF.h>

using namespace std;
using namespace mxfpp;

Preface::Preface(HeaderMetadata *headerMetadata)
: PrefaceBase(headerMetadata)
{}

Preface::Preface(HeaderMetadata *headerMetadata, ::MXFMetadataSet *cMetadataSet)
: PrefaceBase(headerMetadata, cMetadataSet)
{}

Preface::~Preface()
{}

GenericPackage* Preface::findPackage(mxfUMID package_uid) const
{
    vector<GenericPackage*> packages = getContentStorage()->getPackages();
    mxfUMID uid;
    size_t i;
    for (i = 0; i < packages.size(); i++) {
        uid = packages[i]->getPackageUID();
        if (mxf_equals_umid(&package_uid, &uid))
            return packages[i];
    }

    return 0;
}

MaterialPackage* Preface::findMaterialPackage() const
{
    vector<GenericPackage*> packages = getContentStorage()->getPackages();
    MaterialPackage *material_package;
    size_t i;
    for (i = 0; i < packages.size(); i++) {
        material_package = dynamic_cast<MaterialPackage*>(packages[i]);
        if (material_package)
            return material_package;
    }

    return 0;
}

vector<SourcePackage*> Preface::findFileSourcePackages() const
{
    vector<GenericPackage*> packages = getContentStorage()->getPackages();
    vector<SourcePackage*> file_packages;
    SourcePackage *file_package;
    size_t i;
    for (i = 0; i < packages.size(); i++) {
        file_package = dynamic_cast<SourcePackage*>(packages[i]);
        if (!file_package ||
            !file_package->haveDescriptor() ||
            !dynamic_cast<FileDescriptor*>(file_package->getDescriptorLight()))
        {
            continue;
        }

        file_packages.push_back(file_package);
    }

    return file_packages;
}

<|endoftext|>