<commit_before>/*
 * Copyright (C) 2016,2017 deipi.com LLC and contributors. All rights reserved.
 *
 * 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.
 */

#include "test_guid.h"

#include "../src/guid/guid.h"
#include "utils.h"

constexpr int NUM_TESTS = 1000;

constexpr size_t MIN_COMPACTED_LENGTH =  2;
constexpr size_t MAX_COMPACTED_LENGTH = 11;
constexpr size_t MIN_CONDENSED_LENGTH =  2;
constexpr size_t MAX_CONDENSED_LENGTH = 16;
constexpr size_t MIN_EXPANDED_LENGTH  =  3;
constexpr size_t MAX_EXPANDED_LENGTH  = 17;

int test_guid() {
	INIT_LOG
	GuidGenerator generator;

	auto g1 = generator.newGuid();
	auto g2 = generator.newGuid();
	auto g3 = generator.newGuid();

	L_DEBUG(nullptr, "Guids generated: %s  %s  %s", repr(g1.to_string()).c_str(), repr(g2.to_string()).c_str(), repr(g3.to_string()).c_str());
	if (g1 == g2 || g1 == g3 || g2 == g3) {
		L_ERR(nullptr, "ERROR: Not all random guids are different");
		RETURN(1);
	}

	std::string u1("3c0f2be3-ff4f-40ab-b157-c51a81eff176");
	std::string u2("e47fcfdf-8db6-4469-a97f-57146dc41ced");
	std::string u3("b2ce58e8-d049-4705-b0cb-fe7435843781");

	Guid s1(u1);
	Guid s2(u2);
	Guid s3(u3);
	Guid s4(u1);

	if (s1 == s2) {
		L_ERR(nullptr, "ERROR: s1 and s2 must be different");
		RETURN(1);
	}

	if (s1 != s4) {
		L_ERR(nullptr, "ERROR: s1 and s4 must be equal");
		RETURN(1);
	}

	if (s1.to_string() != u1) {
		L_ERR(nullptr, "ERROR: string generated from s1 is wrong");
		RETURN(1);
	}

	if (s2.to_string() != u2) {
		L_ERR(nullptr, "ERROR: string generated from s2 is wrong");
		RETURN(1);
	}

	if (s3.to_string() != u3) {
		L_ERR(nullptr, "ERROR: string generated from s3 is wrong");
		RETURN(1);
	}

	RETURN(0);
}

int test_special_guids() {
	std::vector<std::string> special_uuids({
		"00000000-0000-0000-0000-000000000000",
		"00000000-0000-1000-a000-000000000000",
		"00000000-0000-4000-b000-000000000000",
		"00000000-2000-1000-c000-000000000000",
		"00000000-2000-4000-c000-000000000000",
		"00000000-2000-2000-0000-000000000000",
	});

	int cont = 0;
	for (const auto& uuid_orig : special_uuids) {
		Guid guid(uuid_orig);
		Guid guid2 = Guid::unserialise(guid.serialise());
		const auto uuid_rec = guid2.to_string();
		if (uuid_orig != uuid_rec) {
			++cont;
			L_ERR(nullptr, "ERROR: Expected: %s Result: %s", uuid_orig.c_str(), uuid_rec.c_str());
		}
	}

	RETURN(cont);
}

int test_compacted_guids() {
	int cont = 0;
	size_t min_length = 20, max_length = 0;
	for (int i = 0; i < NUM_TESTS; ++i) {
		Guid guid = GuidGenerator().newGuid(true);
		const auto uuid_orig = guid.to_string();
		const auto serialised = guid.serialise();
		Guid guid2 = Guid::unserialise(serialised);
		const auto uuid_rec = guid2.to_string();
		if (uuid_orig != uuid_rec) {
			++cont;
			L_ERR(stderr, "ERROR: Expected: %s Result: %s", uuid_orig.c_str(), uuid_rec.c_str());
		}
		if (max_length < serialised.length()) {
			max_length = serialised.length();
		}
		if (min_length > serialised.length()) {
			min_length = serialised.length();
		}
	}

	if (max_length > MAX_COMPACTED_LENGTH) {
		L_ERR(nullptr, "ERROR: Max length for compacted uuid is %zu", MAX_COMPACTED_LENGTH);
		++cont;
	}

	if (min_length < MIN_COMPACTED_LENGTH) {
		L_ERR(nullptr, "ERROR: Min length for compacted uuid is %zu", MIN_COMPACTED_LENGTH);
		++cont;
	}

	RETURN(cont);
}

int test_condensed_guids() {
	int cont = 0;
	size_t min_length = 20, max_length = 0;
	for (int i = 0; i < NUM_TESTS; ++i) {
		Guid guid = GuidGenerator().newGuid(false);
		const auto uuid_orig = guid.to_string();
		const auto serialised = guid.serialise();
		Guid guid2 = Guid::unserialise(serialised);
		const auto uuid_rec = guid2.to_string();
		if (uuid_orig != uuid_rec) {
			++cont;
			L_ERR(stderr, "ERROR: Expected: %s Result: %s", uuid_orig.c_str(), uuid_rec.c_str());
		}
		if (max_length < serialised.length()) {
			max_length = serialised.length();
		}
		if (min_length > serialised.length()) {
			min_length = serialised.length();
		}
	}

	if (max_length > MAX_CONDENSED_LENGTH) {
		L_ERR(nullptr, "ERROR: Max length for condensed uuid is %zu", MAX_CONDENSED_LENGTH);
		++cont;
	}

	if (min_length < MIN_CONDENSED_LENGTH) {
		L_ERR(nullptr, "ERROR: Min length for condensed uuid is %zu", MIN_CONDENSED_LENGTH);
		++cont;
	}

	RETURN(cont);
}

int test_expanded_guids() {
	int cont = 0;
	size_t min_length = 20, max_length = 0;
	for (auto i = 0; i < NUM_TESTS; ++i) {
		std::string uuid_orig;
		uuid_orig.reserve(36);
		const char x[] = {
			'0', '1', '2',  '3',  '4',  '5',  '6',  '7',
			'8', '9', 'a',  'b',  'c',  'd',  'e',  'f',
		};
		for (int i = 0; i < 8; ++i) {
			uuid_orig.push_back(x[random_int(0, 15)]);
		}
		uuid_orig.push_back('-');
		for (int i = 0; i < 4; ++i) {
			uuid_orig.push_back(x[random_int(0, 15)]);
		}
		uuid_orig.push_back('-');
		for (int i = 0; i < 4; ++i) {
			uuid_orig.push_back(x[random_int(0, 15)]);
		}
		uuid_orig.push_back('-');
		for (int i = 0; i < 4; ++i) {
			uuid_orig.push_back(x[random_int(0, 15)]);
		}
		uuid_orig.push_back('-');
		for (int i = 0; i < 12; ++i) {
			uuid_orig.push_back(x[random_int(0, 15)]);
		}
		// If random uuid is rfc 4122, change the variant.
		const auto& version = uuid_orig[14];
		auto& variant = uuid_orig[19];
		if ((version == 1 || version == 4) && (variant == '8' || variant == '9' || variant == 'a' || variant == 'b')) {
			variant = '7';
		}
		Guid guid(uuid_orig);
		const auto serialised = guid.serialise();
		Guid guid2 = Guid::unserialise(serialised);
		const auto uuid_rec = guid2.to_string();
		if (uuid_orig != uuid_rec) {
			++cont;
			L_ERR(nullptr, "ERROR: Expected: %s Result: %s\n", uuid_orig.c_str(), uuid_rec.c_str());
		}
		if (max_length < serialised.length()) {
			max_length = serialised.length();
		}
		if (min_length > serialised.length()) {
			min_length = serialised.length();
		}
	}

	if (max_length > MAX_EXPANDED_LENGTH) {
		L_ERR(nullptr, "ERROR: Max length for expanded uuid is %zu", MAX_EXPANDED_LENGTH);
		++cont;
	}

	if (min_length < MIN_EXPANDED_LENGTH) {
		L_ERR(nullptr, "ERROR: Min length for expanded uuid is %zu", MIN_EXPANDED_LENGTH);
		++cont;
	}

	RETURN(cont);
}

int test_several_guids() {
	size_t cont = 0;
	for (auto i = 0; i < NUM_TESTS; ++i) {
		std::vector<std::string> str_uuids;
		std::vector<std::string> norm_uuids;
		switch (i % 3) {
			case 0: {
				Guid guid = GuidGenerator().newGuid(true);
				str_uuids.push_back(guid.to_string());
				norm_uuids.push_back(guid.to_string());
				guid = GuidGenerator().newGuid(false);
				str_uuids.push_back(guid.to_string());
				norm_uuids.push_back(guid.to_string());
				guid = GuidGenerator().newGuid(true);
				str_uuids.push_back(guid.to_string());
				norm_uuids.push_back(guid.to_string());
				break;
			}
			case 1: {
				Guid guid = GuidGenerator().newGuid(true);
				str_uuids.push_back(guid.to_string());
				norm_uuids.push_back(base64::encode(guid.serialise()));
				guid = GuidGenerator().newGuid(false);
				str_uuids.push_back(guid.to_string());
				norm_uuids.push_back(base64::encode(guid.serialise()));
				guid = GuidGenerator().newGuid(true);
				str_uuids.push_back(guid.to_string());
				norm_uuids.push_back(base64::encode(guid.serialise()));
				break;
			}
			default: {
				Guid guid = GuidGenerator().newGuid(true);
				str_uuids.push_back(guid.to_string());
				auto serialised = guid.serialise();
				guid = GuidGenerator().newGuid(false);
				str_uuids.push_back(guid.to_string());
				serialised.append(guid.serialise());
				guid = GuidGenerator().newGuid(true);
				str_uuids.push_back(guid.to_string());
				serialised.append(guid.serialise());
				norm_uuids.push_back(base64::encode(serialised));
				break;
			}
		}
		std::vector<Guid> guids;
		const auto serialised = Guid::serialise(norm_uuids.begin(), norm_uuids.end());
		Guid::unserialise(serialised, std::back_inserter(guids));
		if (guids.size() != str_uuids.size()) {
			++cont;
			L_ERR(nullptr, "ERROR: Different sizes. Expected: %zu  Result: %zu", str_uuids.size(), guids.size());
		} else {
			auto it = str_uuids.begin();
			for (const auto& guid : guids) {
				const auto str_guid = guid.to_string();
				if (str_guid != *it) {
					++cont;
					L_ERR(nullptr, "ERROR: Expected: %s  Result: %s", it->c_str(), str_guid.c_str());
				}
				++it;
			}
		}
	}

	RETURN(cont);
}
<commit_msg>Add special uuid test<commit_after>/*
 * Copyright (C) 2016,2017 deipi.com LLC and contributors. All rights reserved.
 *
 * 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.
 */

#include "test_guid.h"

#include "../src/guid/guid.h"
#include "utils.h"

constexpr int NUM_TESTS = 1000;

constexpr size_t MIN_COMPACTED_LENGTH =  2;
constexpr size_t MAX_COMPACTED_LENGTH = 11;
constexpr size_t MIN_CONDENSED_LENGTH =  2;
constexpr size_t MAX_CONDENSED_LENGTH = 16;
constexpr size_t MIN_EXPANDED_LENGTH  =  3;
constexpr size_t MAX_EXPANDED_LENGTH  = 17;

int test_guid() {
	INIT_LOG
	GuidGenerator generator;

	auto g1 = generator.newGuid();
	auto g2 = generator.newGuid();
	auto g3 = generator.newGuid();

	L_DEBUG(nullptr, "Guids generated: %s  %s  %s", repr(g1.to_string()).c_str(), repr(g2.to_string()).c_str(), repr(g3.to_string()).c_str());
	if (g1 == g2 || g1 == g3 || g2 == g3) {
		L_ERR(nullptr, "ERROR: Not all random guids are different");
		RETURN(1);
	}

	std::string u1("3c0f2be3-ff4f-40ab-b157-c51a81eff176");
	std::string u2("e47fcfdf-8db6-4469-a97f-57146dc41ced");
	std::string u3("b2ce58e8-d049-4705-b0cb-fe7435843781");

	Guid s1(u1);
	Guid s2(u2);
	Guid s3(u3);
	Guid s4(u1);

	if (s1 == s2) {
		L_ERR(nullptr, "ERROR: s1 and s2 must be different");
		RETURN(1);
	}

	if (s1 != s4) {
		L_ERR(nullptr, "ERROR: s1 and s4 must be equal");
		RETURN(1);
	}

	if (s1.to_string() != u1) {
		L_ERR(nullptr, "ERROR: string generated from s1 is wrong");
		RETURN(1);
	}

	if (s2.to_string() != u2) {
		L_ERR(nullptr, "ERROR: string generated from s2 is wrong");
		RETURN(1);
	}

	if (s3.to_string() != u3) {
		L_ERR(nullptr, "ERROR: string generated from s3 is wrong");
		RETURN(1);
	}

	RETURN(0);
}

int test_special_guids() {
	std::vector<std::string> special_uuids({
		"00000000-0000-0000-0000-000000000000",
		"00000000-0000-1000-8000-000000000000",
		"00000000-0000-1000-a000-000000000000",
		"00000000-0000-4000-b000-000000000000",
		"00000000-2000-1000-c000-000000000000",
		"00000000-2000-4000-c000-000000000000",
		"00000000-2000-2000-0000-000000000000",
	});

	int cont = 0;
	for (const auto& uuid_orig : special_uuids) {
		Guid guid(uuid_orig);
		Guid guid2 = Guid::unserialise(guid.serialise());
		const auto uuid_rec = guid2.to_string();
		if (uuid_orig != uuid_rec) {
			++cont;
			L_ERR(nullptr, "ERROR: Expected: %s Result: %s", uuid_orig.c_str(), uuid_rec.c_str());
		}
	}

	RETURN(cont);
}

int test_compacted_guids() {
	int cont = 0;
	size_t min_length = 20, max_length = 0;
	for (int i = 0; i < NUM_TESTS; ++i) {
		Guid guid = GuidGenerator().newGuid(true);
		const auto uuid_orig = guid.to_string();
		const auto serialised = guid.serialise();
		Guid guid2 = Guid::unserialise(serialised);
		const auto uuid_rec = guid2.to_string();
		if (uuid_orig != uuid_rec) {
			++cont;
			L_ERR(stderr, "ERROR: Expected: %s Result: %s", uuid_orig.c_str(), uuid_rec.c_str());
		}
		if (max_length < serialised.length()) {
			max_length = serialised.length();
		}
		if (min_length > serialised.length()) {
			min_length = serialised.length();
		}
	}

	if (max_length > MAX_COMPACTED_LENGTH) {
		L_ERR(nullptr, "ERROR: Max length for compacted uuid is %zu", MAX_COMPACTED_LENGTH);
		++cont;
	}

	if (min_length < MIN_COMPACTED_LENGTH) {
		L_ERR(nullptr, "ERROR: Min length for compacted uuid is %zu", MIN_COMPACTED_LENGTH);
		++cont;
	}

	RETURN(cont);
}

int test_condensed_guids() {
	int cont = 0;
	size_t min_length = 20, max_length = 0;
	for (int i = 0; i < NUM_TESTS; ++i) {
		Guid guid = GuidGenerator().newGuid(false);
		const auto uuid_orig = guid.to_string();
		const auto serialised = guid.serialise();
		Guid guid2 = Guid::unserialise(serialised);
		const auto uuid_rec = guid2.to_string();
		if (uuid_orig != uuid_rec) {
			++cont;
			L_ERR(stderr, "ERROR: Expected: %s Result: %s", uuid_orig.c_str(), uuid_rec.c_str());
		}
		if (max_length < serialised.length()) {
			max_length = serialised.length();
		}
		if (min_length > serialised.length()) {
			min_length = serialised.length();
		}
	}

	if (max_length > MAX_CONDENSED_LENGTH) {
		L_ERR(nullptr, "ERROR: Max length for condensed uuid is %zu", MAX_CONDENSED_LENGTH);
		++cont;
	}

	if (min_length < MIN_CONDENSED_LENGTH) {
		L_ERR(nullptr, "ERROR: Min length for condensed uuid is %zu", MIN_CONDENSED_LENGTH);
		++cont;
	}

	RETURN(cont);
}

int test_expanded_guids() {
	int cont = 0;
	size_t min_length = 20, max_length = 0;
	for (auto i = 0; i < NUM_TESTS; ++i) {
		std::string uuid_orig;
		uuid_orig.reserve(36);
		const char x[] = {
			'0', '1', '2',  '3',  '4',  '5',  '6',  '7',
			'8', '9', 'a',  'b',  'c',  'd',  'e',  'f',
		};
		for (int i = 0; i < 8; ++i) {
			uuid_orig.push_back(x[random_int(0, 15)]);
		}
		uuid_orig.push_back('-');
		for (int i = 0; i < 4; ++i) {
			uuid_orig.push_back(x[random_int(0, 15)]);
		}
		uuid_orig.push_back('-');
		for (int i = 0; i < 4; ++i) {
			uuid_orig.push_back(x[random_int(0, 15)]);
		}
		uuid_orig.push_back('-');
		for (int i = 0; i < 4; ++i) {
			uuid_orig.push_back(x[random_int(0, 15)]);
		}
		uuid_orig.push_back('-');
		for (int i = 0; i < 12; ++i) {
			uuid_orig.push_back(x[random_int(0, 15)]);
		}
		// If random uuid is rfc 4122, change the variant.
		const auto& version = uuid_orig[14];
		auto& variant = uuid_orig[19];
		if ((version == 1 || version == 4) && (variant == '8' || variant == '9' || variant == 'a' || variant == 'b')) {
			variant = '7';
		}
		Guid guid(uuid_orig);
		const auto serialised = guid.serialise();
		Guid guid2 = Guid::unserialise(serialised);
		const auto uuid_rec = guid2.to_string();
		if (uuid_orig != uuid_rec) {
			++cont;
			L_ERR(nullptr, "ERROR: Expected: %s Result: %s\n", uuid_orig.c_str(), uuid_rec.c_str());
		}
		if (max_length < serialised.length()) {
			max_length = serialised.length();
		}
		if (min_length > serialised.length()) {
			min_length = serialised.length();
		}
	}

	if (max_length > MAX_EXPANDED_LENGTH) {
		L_ERR(nullptr, "ERROR: Max length for expanded uuid is %zu", MAX_EXPANDED_LENGTH);
		++cont;
	}

	if (min_length < MIN_EXPANDED_LENGTH) {
		L_ERR(nullptr, "ERROR: Min length for expanded uuid is %zu", MIN_EXPANDED_LENGTH);
		++cont;
	}

	RETURN(cont);
}

int test_several_guids() {
	size_t cont = 0;
	for (auto i = 0; i < NUM_TESTS; ++i) {
		std::vector<std::string> str_uuids;
		std::vector<std::string> norm_uuids;
		switch (i % 3) {
			case 0: {
				Guid guid = GuidGenerator().newGuid(true);
				str_uuids.push_back(guid.to_string());
				norm_uuids.push_back(guid.to_string());
				guid = GuidGenerator().newGuid(false);
				str_uuids.push_back(guid.to_string());
				norm_uuids.push_back(guid.to_string());
				guid = GuidGenerator().newGuid(true);
				str_uuids.push_back(guid.to_string());
				norm_uuids.push_back(guid.to_string());
				break;
			}
			case 1: {
				Guid guid = GuidGenerator().newGuid(true);
				str_uuids.push_back(guid.to_string());
				norm_uuids.push_back(base64::encode(guid.serialise()));
				guid = GuidGenerator().newGuid(false);
				str_uuids.push_back(guid.to_string());
				norm_uuids.push_back(base64::encode(guid.serialise()));
				guid = GuidGenerator().newGuid(true);
				str_uuids.push_back(guid.to_string());
				norm_uuids.push_back(base64::encode(guid.serialise()));
				break;
			}
			default: {
				Guid guid = GuidGenerator().newGuid(true);
				str_uuids.push_back(guid.to_string());
				auto serialised = guid.serialise();
				guid = GuidGenerator().newGuid(false);
				str_uuids.push_back(guid.to_string());
				serialised.append(guid.serialise());
				guid = GuidGenerator().newGuid(true);
				str_uuids.push_back(guid.to_string());
				serialised.append(guid.serialise());
				norm_uuids.push_back(base64::encode(serialised));
				break;
			}
		}
		std::vector<Guid> guids;
		const auto serialised = Guid::serialise(norm_uuids.begin(), norm_uuids.end());
		Guid::unserialise(serialised, std::back_inserter(guids));
		if (guids.size() != str_uuids.size()) {
			++cont;
			L_ERR(nullptr, "ERROR: Different sizes. Expected: %zu  Result: %zu", str_uuids.size(), guids.size());
		} else {
			auto it = str_uuids.begin();
			for (const auto& guid : guids) {
				const auto str_guid = guid.to_string();
				if (str_guid != *it) {
					++cont;
					L_ERR(nullptr, "ERROR: Expected: %s  Result: %s", it->c_str(), str_guid.c_str());
				}
				++it;
			}
		}
	}

	RETURN(cont);
}
<|endoftext|>


<commit_before>#define BOOST_TEST_MODULE json test
#include <boost/test/unit_test.hpp>
#include <ten/json.hh>
#ifdef TEN_JSON_CXX11
#include <ten/jserial.hh>
#include <ten/jserial_maybe.hh>
#include <ten/jserial_seq.hh>
#include <ten/jserial_assoc.hh>
#include <ten/jserial_enum.hh>
#endif
#include <array>

using namespace std;
using namespace ten;

const char json_text[] =
"{ \"store\": {"
"    \"book\": ["
"      { \"category\": \"reference\","
"        \"author\": \"Nigel Rees\","
"        \"title\": \"Sayings of the Century\","
"        \"price\": 8.95"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"Evelyn Waugh\","
"        \"title\": \"Sword of Honour\","
"        \"price\": 12.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"Herman Melville\","
"        \"title\": \"Moby Dick\","
"        \"isbn\": \"0-553-21311-3\","
"        \"price\": 8.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"J. R. R. Tolkien\","
"        \"title\": \"The Lord of the Rings\","
"        \"isbn\": \"0-395-19395-8\","
"        \"price\": 22.99"
"      }"
"    ],"
"    \"bicycle\": {"
"      \"color\": \"red\","
"      \"price\": 19.95"
"    }"
"  }"
"}";

BOOST_AUTO_TEST_CASE(json_test_path1) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    static const char a1[] = "[\"Nigel Rees\", \"Evelyn Waugh\", \"Herman Melville\", \"J. R. R. Tolkien\"]";
    json r1(o.path("/store/book/author"));
    BOOST_CHECK_EQUAL(json::load(a1), r1);

    json r2(o.path("//author"));
    BOOST_CHECK_EQUAL(json::load(a1), r2);

    // jansson hashtable uses size_t for hash
    // we think this is causing the buckets to change on 32bit vs. 64bit
#if (__SIZEOF_SIZE_T__ == 4)
    static const char a3[] = "[{\"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95}, {\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}, {\"color\": \"red\", \"price\": 19.95}]";
#elif (__SIZEOF_SIZE_T__ == 8)
    static const char a3[] = "[{\"color\": \"red\", \"price\": 19.95}, {\"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95}, {\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}]";
#endif
    json r3(o.path("/store/*"));
    json t3(json::load(a3));
    BOOST_CHECK_EQUAL(t3, r3);

#if (__SIZEOF_SIZE_T__ == 4)
    static const char a4[] = "[8.95, 12.99, 8.99, 22.99, 19.95]";
#elif (__SIZEOF_SIZE_T__ == 8)
    static const char a4[] = "[19.95, 8.95, 12.99, 8.99, 22.99]";
#endif
    json r4(o.path("/store//price"));
    BOOST_CHECK_EQUAL(json::load(a4), r4);

    static const char a5[] = "{\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}";
    json r5(o.path("//book[3]"));
    BOOST_CHECK_EQUAL(json::load(a5), r5);

    static const char a6[] = "\"J. R. R. Tolkien\"";
    json r6(o.path("/store/book[3]/author"));
    BOOST_CHECK_EQUAL(json::load(a6), r6);
    BOOST_CHECK(json::load(a6) == r6);

    static const char a7[] = "[{\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}]";
    json r7(o.path("/store/book[category=\"fiction\"]"));
    BOOST_CHECK_EQUAL(json::load(a7), r7);
}

BOOST_AUTO_TEST_CASE(json_test_path2) {
    json o(json::load("[{\"type\": 0}, {\"type\": 1}]"));
    BOOST_CHECK_EQUAL(json::load("[{\"type\":1}]"), o.path("/[type=1]"));
}

BOOST_AUTO_TEST_CASE(json_test_filter_key_exists) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    static const char a[] = "["
"      { \"category\": \"fiction\","
"        \"author\": \"Herman Melville\","
"        \"title\": \"Moby Dick\","
"        \"isbn\": \"0-553-21311-3\","
"        \"price\": 8.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"J. R. R. Tolkien\","
"        \"title\": \"The Lord of the Rings\","
"        \"isbn\": \"0-395-19395-8\","
"        \"price\": 22.99"
"      }]";
    json r(o.path("//book[isbn]"));
    BOOST_CHECK_EQUAL(json::load(a), r);

    json r1(o.path("//book[doesnotexist]"));
    BOOST_REQUIRE(r1.is_array());
    BOOST_CHECK_EQUAL(0, r1.asize());
}

BOOST_AUTO_TEST_CASE(json_test_truth) {
    json o(json::object());
    BOOST_CHECK(o.get("nothing").is_true() == false);
    BOOST_CHECK(o.get("nothing").is_false() == false);
    BOOST_CHECK(o.get("nothing").is_null() == false);
    BOOST_CHECK(!o.get("nothing"));
}

BOOST_AUTO_TEST_CASE(json_test_path3) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    BOOST_CHECK_EQUAL(o, o.path("/"));
    BOOST_CHECK_EQUAL("Sayings of the Century",
        o.path("/store/book[category=\"reference\"]/title"));

    static const char text[] = "["
    "{\"type\":\"a\", \"value\":0},"
    "{\"type\":\"b\", \"value\":1},"
    "{\"type\":\"c\", \"value\":2},"
    "{\"type\":\"c\", \"value\":3}"
    "]";

    BOOST_CHECK_EQUAL(json(1), json::load(text).path("/[type=\"b\"]/value"));
}

BOOST_AUTO_TEST_CASE(json_init_list) {
    json meta{
        { "foo", 17 },
        { "bar", 23 },
        { "baz", true },
        { "corge", json::array({ 1, 3.14159 }) },
        { "grault", json::array({ "hello", string("world") }) },
    };
    BOOST_REQUIRE(meta);
    BOOST_REQUIRE(meta.is_object());
    BOOST_CHECK_EQUAL(meta.osize(), 5);
    BOOST_CHECK_EQUAL(meta["foo"].integer(), 17);
    BOOST_CHECK_EQUAL(meta["corge"][0].integer(), 1);
    BOOST_CHECK_EQUAL(meta["grault"][1].str(), "world");
}

template <class T>
inline void test_conv(T val, json j, json_type t) {
    json j2 = to_json(val);
    BOOST_CHECK_EQUAL(j2.type(), t);
    BOOST_CHECK_EQUAL(j, j2);
    T val2 = json_cast<T>(j2);
    BOOST_CHECK_EQUAL(val, val2);
}

template <class T, json_type TYPE = JSON_INTEGER>
inline void test_conv_num() {
    typedef numeric_limits<T> lim;
    T range[5] = { lim::min(), T(-1), 0, T(1), lim::max() };
    for (unsigned i = 0; i < 5; ++i)
        test_conv<T>(range[i], json(range[i]), TYPE);
}

BOOST_AUTO_TEST_CASE(json_conversions) {
    test_conv<string>(string("hello"), json::str("hello"), JSON_STRING);
    BOOST_CHECK_EQUAL(to_json("world"), json::str("world"));

    test_conv_num<short>();
    test_conv_num<int>();
    test_conv_num<long>();
    test_conv_num<long long>();
    test_conv_num<unsigned short>();
    test_conv_num<unsigned>();
#if ULONG_MAX < LLONG_MAX
    test_conv_num<unsigned long>();
#endif

    test_conv_num<double, JSON_REAL>();
    test_conv_num<float,  JSON_REAL>();

    test_conv<bool>(true,  json::jtrue(),  JSON_TRUE);
    test_conv<bool>(false, json::jfalse(), JSON_FALSE);
}

BOOST_AUTO_TEST_CASE(json_create) {
    json obj1;
    obj1.set("test", "set");
    BOOST_CHECK(obj1);
    BOOST_CHECK(obj1.get("test"));
    json root{
        {"obj1", obj1}
    };
    BOOST_CHECK_EQUAL(root.get("obj1"), obj1);
    obj1.set("this", "that");
    BOOST_CHECK_EQUAL(root.get("obj1").get("this").str(), "that");
    json obj2{ {"answer", 42} };
    obj1.set("obj2", obj2);
    BOOST_CHECK_EQUAL(root.get("obj1").get("obj2"), obj2);
}

#ifdef TEN_JSON_CXX11

struct corge {
    int foo, bar;

    corge() : foo(), bar() {}
    corge(int foo_, int bar_) : foo(foo_), bar(bar_) {}
};
template <class AR>
inline void serialize(AR &ar, corge &c) {
    ar & kv("foo", c.foo) & kv("bar", c.bar);
}
inline bool operator == (const corge &a, const corge &b) {
    return a.foo == b.foo && a.bar == b.bar;
}

enum captain { kirk, picard, janeway, sisko };
const array<string, 4> captain_names = {{ "kirk", "picard", "janeway", "sisko" }};
template <class AR>
inline void serialize(AR &ar, captain &c) {
    serialize_enum(ar, c, captain_names);
}

BOOST_AUTO_TEST_CASE(json_serial) {
    corge c1(42, 17);
    auto j = jsave_all(c1);
    corge c2;
    json_loader(j) >> c2;
    BOOST_CHECK(c1 == c2);

    map<string, int> m;
    json_loader(j) >> m;
    BOOST_CHECK_EQUAL(m.size(), 2);
    BOOST_CHECK(m.find("foo") != m.end());
    BOOST_CHECK(m.find("bar") != m.end());
    BOOST_CHECK_EQUAL(m["foo"], 42);
    BOOST_CHECK_EQUAL(m["bar"], 17);

#if BOOST_VERSION >= 104800
    flat_map<string, int> f;
    json_loader(j) >> f;
    BOOST_CHECK_EQUAL(f.size(), 2);
    BOOST_CHECK(f.find("foo") != f.end());
    BOOST_CHECK(f.find("bar") != f.end());
    BOOST_CHECK_EQUAL(f["foo"], 42);
    BOOST_CHECK_EQUAL(f["bar"], 17);
#endif

    maybe<int> a;
    j = jsave_all(a);
    BOOST_CHECK(!j);
    a = 42;
    j = jsave_all(a);
    BOOST_CHECK_EQUAL(j, 42);

    a.reset();
    BOOST_CHECK(!a.ok());
    j = 17;
    json_loader(j) >> a;
    BOOST_CHECK(a.ok());
    BOOST_CHECK_EQUAL(a.get(), 17);

    captain c = janeway;
    j = jsave_all(c);
    BOOST_CHECK_EQUAL(j, "janeway");
    j = "kirk";
    json_loader(j) >> c;
    BOOST_CHECK_EQUAL(c, kirk);
}

#endif // TEN_JSON_CXX11
<commit_msg>cosmetic<commit_after>#define BOOST_TEST_MODULE json test
#include <boost/test/unit_test.hpp>
#include <ten/json.hh>
#ifdef TEN_JSON_CXX11
#include <ten/jserial.hh>
#include <ten/jserial_maybe.hh>
#include <ten/jserial_seq.hh>
#include <ten/jserial_assoc.hh>
#include <ten/jserial_enum.hh>
#endif
#include <array>

using namespace std;
using namespace ten;

const char json_text[] =
"{ \"store\": {"
"    \"book\": ["
"      { \"category\": \"reference\","
"        \"author\": \"Nigel Rees\","
"        \"title\": \"Sayings of the Century\","
"        \"price\": 8.95"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"Evelyn Waugh\","
"        \"title\": \"Sword of Honour\","
"        \"price\": 12.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"Herman Melville\","
"        \"title\": \"Moby Dick\","
"        \"isbn\": \"0-553-21311-3\","
"        \"price\": 8.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"J. R. R. Tolkien\","
"        \"title\": \"The Lord of the Rings\","
"        \"isbn\": \"0-395-19395-8\","
"        \"price\": 22.99"
"      }"
"    ],"
"    \"bicycle\": {"
"      \"color\": \"red\","
"      \"price\": 19.95"
"    }"
"  }"
"}";

BOOST_AUTO_TEST_CASE(json_test_path1) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    static const char a1[] = "[\"Nigel Rees\", \"Evelyn Waugh\", \"Herman Melville\", \"J. R. R. Tolkien\"]";
    json r1(o.path("/store/book/author"));
    BOOST_CHECK_EQUAL(json::load(a1), r1);

    json r2(o.path("//author"));
    BOOST_CHECK_EQUAL(json::load(a1), r2);

    // jansson hashtable uses size_t for hash
    // we think this is causing the buckets to change on 32bit vs. 64bit
#if (__SIZEOF_SIZE_T__ == 4)
    static const char a3[] = "[{\"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95}, {\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}, {\"color\": \"red\", \"price\": 19.95}]";
#elif (__SIZEOF_SIZE_T__ == 8)
    static const char a3[] = "[{\"color\": \"red\", \"price\": 19.95}, {\"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95}, {\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}]";
#endif
    json r3(o.path("/store/*"));
    json t3(json::load(a3));
    BOOST_CHECK_EQUAL(t3, r3);

#if (__SIZEOF_SIZE_T__ == 4)
    static const char a4[] = "[8.95, 12.99, 8.99, 22.99, 19.95]";
#elif (__SIZEOF_SIZE_T__ == 8)
    static const char a4[] = "[19.95, 8.95, 12.99, 8.99, 22.99]";
#endif
    json r4(o.path("/store//price"));
    BOOST_CHECK_EQUAL(json::load(a4), r4);

    static const char a5[] = "{\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}";
    json r5(o.path("//book[3]"));
    BOOST_CHECK_EQUAL(json::load(a5), r5);

    static const char a6[] = "\"J. R. R. Tolkien\"";
    json r6(o.path("/store/book[3]/author"));
    BOOST_CHECK_EQUAL(json::load(a6), r6);
    BOOST_CHECK(json::load(a6) == r6);

    static const char a7[] = "[{\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}]";
    json r7(o.path("/store/book[category=\"fiction\"]"));
    BOOST_CHECK_EQUAL(json::load(a7), r7);
}

BOOST_AUTO_TEST_CASE(json_test_path2) {
    json o(json::load("[{\"type\": 0}, {\"type\": 1}]"));
    BOOST_CHECK_EQUAL(json::load("[{\"type\":1}]"), o.path("/[type=1]"));
}

BOOST_AUTO_TEST_CASE(json_test_filter_key_exists) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    static const char a[] = "["
"      { \"category\": \"fiction\","
"        \"author\": \"Herman Melville\","
"        \"title\": \"Moby Dick\","
"        \"isbn\": \"0-553-21311-3\","
"        \"price\": 8.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"J. R. R. Tolkien\","
"        \"title\": \"The Lord of the Rings\","
"        \"isbn\": \"0-395-19395-8\","
"        \"price\": 22.99"
"      }]";
    json r(o.path("//book[isbn]"));
    BOOST_CHECK_EQUAL(json::load(a), r);

    json r1(o.path("//book[doesnotexist]"));
    BOOST_REQUIRE(r1.is_array());
    BOOST_CHECK_EQUAL(0, r1.asize());
}

BOOST_AUTO_TEST_CASE(json_test_truth) {
    json o(json::object());
    BOOST_CHECK(o.get("nothing").is_true() == false);
    BOOST_CHECK(o.get("nothing").is_false() == false);
    BOOST_CHECK(o.get("nothing").is_null() == false);
    BOOST_CHECK(!o.get("nothing"));
}

BOOST_AUTO_TEST_CASE(json_test_path3) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    BOOST_CHECK_EQUAL(o, o.path("/"));
    BOOST_CHECK_EQUAL("Sayings of the Century",
        o.path("/store/book[category=\"reference\"]/title"));

    static const char text[] = "["
    "{\"type\":\"a\", \"value\":0},"
    "{\"type\":\"b\", \"value\":1},"
    "{\"type\":\"c\", \"value\":2},"
    "{\"type\":\"c\", \"value\":3}"
    "]";

    BOOST_CHECK_EQUAL(json(1), json::load(text).path("/[type=\"b\"]/value"));
}

BOOST_AUTO_TEST_CASE(json_init_list) {
    json meta{
        { "foo", 17 },
        { "bar", 23 },
        { "baz", true },
        { "corge", json::array({ 1, 3.14159 }) },
        { "grault", json::array({ "hello", string("world") }) },
    };
    BOOST_REQUIRE(meta);
    BOOST_REQUIRE(meta.is_object());
    BOOST_CHECK_EQUAL(meta.osize(), 5);
    BOOST_CHECK_EQUAL(meta["foo"].integer(), 17);
    BOOST_CHECK_EQUAL(meta["corge"][0].integer(), 1);
    BOOST_CHECK_EQUAL(meta["grault"][1].str(), "world");
}

template <class T>
inline void test_conv(T val, json j, json_type t) {
    json j2 = to_json(val);
    BOOST_CHECK_EQUAL(j2.type(), t);
    BOOST_CHECK_EQUAL(j, j2);
    T val2 = json_cast<T>(j2);
    BOOST_CHECK_EQUAL(val, val2);
}

template <class T, json_type TYPE = JSON_INTEGER>
inline void test_conv_num() {
    typedef numeric_limits<T> lim;
    T range[5] = { lim::min(), T(-1), 0, T(1), lim::max() };
    for (unsigned i = 0; i < 5; ++i)
        test_conv<T>(range[i], json(range[i]), TYPE);
}

BOOST_AUTO_TEST_CASE(json_conversions) {
    test_conv<string>(string("hello"), json::str("hello"), JSON_STRING);
    BOOST_CHECK_EQUAL(to_json("world"), json::str("world"));

    test_conv_num<short>();
    test_conv_num<int>();
    test_conv_num<long>();
    test_conv_num<long long>();
    test_conv_num<unsigned short>();
    test_conv_num<unsigned>();
#if ULONG_MAX < LLONG_MAX
    test_conv_num<unsigned long>();
#endif

    test_conv_num<double, JSON_REAL>();
    test_conv_num<float,  JSON_REAL>();

    test_conv<bool>(true,  json::jtrue(),  JSON_TRUE);
    test_conv<bool>(false, json::jfalse(), JSON_FALSE);
}

BOOST_AUTO_TEST_CASE(json_create) {
    json obj1;
    obj1.set("test", "set");
    BOOST_CHECK(obj1);
    BOOST_CHECK(obj1.get("test"));
    json root{
        {"obj1", obj1}
    };
    BOOST_CHECK_EQUAL(root.get("obj1"), obj1);
    obj1.set("this", "that");
    BOOST_CHECK_EQUAL(root.get("obj1").get("this").str(), "that");
    json obj2{ {"answer", 42} };
    obj1.set("obj2", obj2);
    BOOST_CHECK_EQUAL(root.get("obj1").get("obj2"), obj2);
}

#ifdef TEN_JSON_CXX11

struct corge {
    int foo, bar;

    corge() : foo(), bar() {}
    corge(int foo_, int bar_) : foo(foo_), bar(bar_) {}
};
template <class AR>
inline void serialize(AR &ar, corge &c) {
    ar & kv("foo", c.foo) & kv("bar", c.bar);
}
inline bool operator == (const corge &a, const corge &b) {
    return a.foo == b.foo && a.bar == b.bar;
}

enum captain { kirk, picard, janeway, sisko };
const array<string, 4> captain_names = {{ "kirk", "picard", "janeway", "sisko" }};
template <class AR>
inline void serialize(AR &ar, captain &c) {
    serialize_enum(ar, c, captain_names);
}

BOOST_AUTO_TEST_CASE(json_serial) {
    corge c1(42, 17);
    auto j = jsave_all(c1);
    corge c2;
    json_loader(j) >> c2;
    BOOST_CHECK(c1 == c2);

    map<string, int> m;
    json_loader(j) >> m;
    BOOST_CHECK_EQUAL(m.size(), 2);
    BOOST_CHECK(m.find("foo") != m.end());
    BOOST_CHECK(m.find("bar") != m.end());
    BOOST_CHECK_EQUAL(m["foo"], 42);
    BOOST_CHECK_EQUAL(m["bar"], 17);

#if BOOST_VERSION >= 104800
    flat_map<string, int> f;
    json_loader(j) >> f;
    BOOST_CHECK_EQUAL(f.size(), 2);
    BOOST_CHECK(f.find("foo") != f.end());
    BOOST_CHECK(f.find("bar") != f.end());
    BOOST_CHECK_EQUAL(f["foo"], 42);
    BOOST_CHECK_EQUAL(f["bar"], 17);
#endif

    maybe<int> a;
    j = jsave_all(a);
    BOOST_CHECK(!j);
    a = 42;
    j = jsave_all(a);
    BOOST_CHECK_EQUAL(j, 42);

    a.reset();
    BOOST_CHECK(!a.ok());
    j = 17;
    json_loader(j) >> a;
    BOOST_CHECK(a.ok());
    BOOST_CHECK_EQUAL(a.get(), 17);

    captain c = janeway;
    j = jsave_all(c);
    BOOST_CHECK_EQUAL(j, "janeway");
    j = "kirk";
    json_loader(j) >> c;
    BOOST_CHECK_EQUAL(c, kirk);
}

#endif // TEN_JSON_CXX11
<|endoftext|>


<commit_before>#define BOOST_TEST_MODULE json test
#include <boost/test/unit_test.hpp>
#include <ten/json.hh>
#ifdef TEN_JSON_CXX11
#include <ten/jserial.hh>
#include <ten/jserial_maybe.hh>
#include <ten/jserial_seq.hh>
#include <ten/jserial_assoc.hh>
#include <ten/jserial_enum.hh>
#endif
#include <array>

using namespace std;
using namespace ten;

const char json_text[] =
"{ \"store\": {"
"    \"book\": ["
"      { \"category\": \"reference\","
"        \"author\": \"Nigel Rees\","
"        \"title\": \"Sayings of the Century\","
"        \"price\": 8.95"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"Evelyn Waugh\","
"        \"title\": \"Sword of Honour\","
"        \"price\": 12.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"Herman Melville\","
"        \"title\": \"Moby Dick\","
"        \"isbn\": \"0-553-21311-3\","
"        \"price\": 8.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"J. R. R. Tolkien\","
"        \"title\": \"The Lord of the Rings\","
"        \"isbn\": \"0-395-19395-8\","
"        \"price\": 22.99"
"      }"
"    ],"
"    \"bicycle\": {"
"      \"color\": \"red\","
"      \"price\": 19.95"
"    }"
"  }"
"}";

BOOST_AUTO_TEST_CASE(json_test_path1) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    static const char a1[] = "[\"Nigel Rees\", \"Evelyn Waugh\", \"Herman Melville\", \"J. R. R. Tolkien\"]";
    json r1(o.path("/store/book/author"));
    BOOST_CHECK_EQUAL(json::load(a1), r1);

    json r2(o.path("//author"));
    BOOST_CHECK_EQUAL(json::load(a1), r2);

    // jansson hashtable uses size_t for hash
    // we think this is causing the buckets to change on 32bit vs. 64bit
#if (__SIZEOF_SIZE_T__ == 4)
    static const char a3[] = "[{\"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95}, {\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}, {\"color\": \"red\", \"price\": 19.95}]";
#elif (__SIZEOF_SIZE_T__ == 8)
    static const char a3[] = "[{\"color\": \"red\", \"price\": 19.95}, {\"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95}, {\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}]";
#endif
    json r3(o.path("/store/*"));
    json t3(json::load(a3));
    BOOST_CHECK_EQUAL(t3, r3);

#if (__SIZEOF_SIZE_T__ == 4)
    static const char a4[] = "[8.95, 12.99, 8.99, 22.99, 19.95]";
#elif (__SIZEOF_SIZE_T__ == 8)
    static const char a4[] = "[19.95, 8.95, 12.99, 8.99, 22.99]";
#endif
    json r4(o.path("/store//price"));
    BOOST_CHECK_EQUAL(json::load(a4), r4);

    static const char a5[] = "{\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}";
    json r5(o.path("//book[3]"));
    BOOST_CHECK_EQUAL(json::load(a5), r5);

    static const char a6[] = "\"J. R. R. Tolkien\"";
    json r6(o.path("/store/book[3]/author"));
    BOOST_CHECK_EQUAL(json::load(a6), r6);
    BOOST_CHECK(json::load(a6) == r6);

    static const char a7[] = "[{\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}]";
    json r7(o.path("/store/book[category=\"fiction\"]"));
    BOOST_CHECK_EQUAL(json::load(a7), r7);
}

BOOST_AUTO_TEST_CASE(json_test_path2) {
    json o(json::load("[{\"type\": 0}, {\"type\": 1}]"));
    BOOST_CHECK_EQUAL(json::load("[{\"type\":1}]"), o.path("/[type=1]"));
}

BOOST_AUTO_TEST_CASE(json_test_filter_key_exists) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    static const char a[] = "["
"      { \"category\": \"fiction\","
"        \"author\": \"Herman Melville\","
"        \"title\": \"Moby Dick\","
"        \"isbn\": \"0-553-21311-3\","
"        \"price\": 8.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"J. R. R. Tolkien\","
"        \"title\": \"The Lord of the Rings\","
"        \"isbn\": \"0-395-19395-8\","
"        \"price\": 22.99"
"      }]";
    json r(o.path("//book[isbn]"));
    BOOST_CHECK_EQUAL(json::load(a), r);

    json r1(o.path("//book[doesnotexist]"));
    BOOST_REQUIRE(r1.is_array());
    BOOST_CHECK_EQUAL(0, r1.asize());
}

BOOST_AUTO_TEST_CASE(json_test_truth) {
    json o(json::object());
    BOOST_CHECK(o.get("nothing").is_true() == false);
    BOOST_CHECK(o.get("nothing").is_false() == false);
    BOOST_CHECK(o.get("nothing").is_null() == false);
    BOOST_CHECK(!o.get("nothing"));
}

BOOST_AUTO_TEST_CASE(json_test_path3) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    BOOST_CHECK_EQUAL(o, o.path("/"));
    BOOST_CHECK_EQUAL("Sayings of the Century",
        o.path("/store/book[category=\"reference\"]/title"));

    static const char text[] = "["
    "{\"type\":\"a\", \"value\":0},"
    "{\"type\":\"b\", \"value\":1},"
    "{\"type\":\"c\", \"value\":2},"
    "{\"type\":\"c\", \"value\":3}"
    "]";

    BOOST_CHECK_EQUAL(json(1), json::load(text).path("/[type=\"b\"]/value"));
}

BOOST_AUTO_TEST_CASE(json_init_list) {
    json meta{
        { "foo", 17 },
        { "bar", 23 },
        { "baz", true },
        { "corge", json::array({ 1, 3.14159 }) },
        { "grault", json::array({ "hello", string("world") }) },
    };
    BOOST_REQUIRE(meta);
    BOOST_REQUIRE(meta.is_object());
    BOOST_CHECK_EQUAL(meta.osize(), 5);
    BOOST_CHECK_EQUAL(meta["foo"].integer(), 17);
    BOOST_CHECK_EQUAL(meta["corge"][0].integer(), 1);
    BOOST_CHECK_EQUAL(meta["grault"][1].str(), "world");
}

template <class T>
inline void test_conv(T val, json j, json_type t) {
    json j2 = to_json(val);
    BOOST_CHECK_EQUAL(j2.type(), t);
    BOOST_CHECK_EQUAL(j, j2);
    T val2 = json_cast<T>(j2);
    BOOST_CHECK_EQUAL(val, val2);
}

template <class T, json_type TYPE = JSON_INTEGER>
inline void test_conv_num() {
    typedef numeric_limits<T> lim;
    T range[5] = { lim::min(), T(-1), 0, T(1), lim::max() };
    for (unsigned i = 0; i < 5; ++i)
        test_conv<T>(range[i], json(range[i]), TYPE);
}

BOOST_AUTO_TEST_CASE(json_conversions) {
    test_conv<string>(string("hello"), json::str("hello"), JSON_STRING);
    BOOST_CHECK_EQUAL(to_json("world"), json::str("world"));

    test_conv_num<short>();
    test_conv_num<int>();
    test_conv_num<long>();
    test_conv_num<long long>();
    test_conv_num<unsigned short>();
    test_conv_num<unsigned>();
#if ULONG_MAX < LLONG_MAX
    test_conv_num<unsigned long>();
#endif

    test_conv_num<double, JSON_REAL>();
    test_conv_num<float,  JSON_REAL>();

    test_conv<bool>(true,  json::jtrue(),  JSON_TRUE);
    test_conv<bool>(false, json::jfalse(), JSON_FALSE);
}

BOOST_AUTO_TEST_CASE(json_create) {
    json obj1{};
    BOOST_CHECK(obj1);
    obj1.set("test", "set");
    BOOST_CHECK(obj1.get("test"));
    json root{
        {"obj1", obj1}
    };
    BOOST_CHECK_EQUAL(root.get("obj1"), obj1);
    obj1.set("this", "that");
    json obj2{};
    BOOST_CHECK_EQUAL(root.get("obj1").get("this").str(), "that");
    obj1.set("obj2", obj2);
    BOOST_CHECK_EQUAL(root.get("obj1").get("obj2"), obj2);
}

#ifdef TEN_JSON_CXX11
struct corge {
    int foo, bar;

    corge() : foo(), bar() {}
    corge(int foo_, int bar_) : foo(foo_), bar(bar_) {}
};
template <class AR>
inline AR & operator & (AR &ar, corge &c) {
    return ar & kv("foo", c.foo) & kv("bar", c.bar);
}
inline bool operator == (const corge &a, const corge &b) {
    return a.foo == b.foo && a.bar == b.bar;
}

enum captain { kirk, picard, janeway, sisko };
const array<string, 4> captain_names = {{ "kirk", "picard", "janeway", "sisko" }};
template <class AR>
inline AR & operator & (AR &ar, captain &c) {
    return serialize_enum(ar, c, captain_names);
}

BOOST_AUTO_TEST_CASE(json_serial) {
    corge c1(42, 17);
    auto j = jsave_all(c1);
    corge c2;
    JLoad(j) >> c2;
    BOOST_CHECK(c1 == c2);

    map<string, int> m;
    JLoad(j) >> m;
    BOOST_CHECK_EQUAL(m.size(), 2);
    BOOST_CHECK(m.find("foo") != m.end());
    BOOST_CHECK(m.find("bar") != m.end());
    BOOST_CHECK_EQUAL(m["foo"], 42);
    BOOST_CHECK_EQUAL(m["bar"], 17);

#if BOOST_VERSION >= 104800
    flat_map<string, int> f;
    JLoad(j) >> f;
    BOOST_CHECK_EQUAL(f.size(), 2);
    BOOST_CHECK(f.find("foo") != f.end());
    BOOST_CHECK(f.find("bar") != f.end());
    BOOST_CHECK_EQUAL(f["foo"], 42);
    BOOST_CHECK_EQUAL(f["bar"], 17);
#endif

    maybe<int> a;
    j = jsave_all(a);
    BOOST_CHECK(!j);
    a = 42;
    j = jsave_all(a);
    BOOST_CHECK_EQUAL(j, 42);

    a.reset();
    BOOST_CHECK(!a.ok());
    j = 17;
    JLoad(j) >> a;
    BOOST_CHECK(a.ok());
    BOOST_CHECK_EQUAL(a.get(), 17);

    captain c = janeway;
    j = jsave_all(c);
    BOOST_CHECK_EQUAL(j, "janeway");
    j = "kirk";
    JLoad(j) >> c;
    BOOST_CHECK_EQUAL(c, kirk);
}

#endif // TEN_JSON_CXX11
<commit_msg>update json_create to work even though {} is not init list<commit_after>#define BOOST_TEST_MODULE json test
#include <boost/test/unit_test.hpp>
#include <ten/json.hh>
#ifdef TEN_JSON_CXX11
#include <ten/jserial.hh>
#include <ten/jserial_maybe.hh>
#include <ten/jserial_seq.hh>
#include <ten/jserial_assoc.hh>
#include <ten/jserial_enum.hh>
#endif
#include <array>

using namespace std;
using namespace ten;

const char json_text[] =
"{ \"store\": {"
"    \"book\": ["
"      { \"category\": \"reference\","
"        \"author\": \"Nigel Rees\","
"        \"title\": \"Sayings of the Century\","
"        \"price\": 8.95"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"Evelyn Waugh\","
"        \"title\": \"Sword of Honour\","
"        \"price\": 12.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"Herman Melville\","
"        \"title\": \"Moby Dick\","
"        \"isbn\": \"0-553-21311-3\","
"        \"price\": 8.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"J. R. R. Tolkien\","
"        \"title\": \"The Lord of the Rings\","
"        \"isbn\": \"0-395-19395-8\","
"        \"price\": 22.99"
"      }"
"    ],"
"    \"bicycle\": {"
"      \"color\": \"red\","
"      \"price\": 19.95"
"    }"
"  }"
"}";

BOOST_AUTO_TEST_CASE(json_test_path1) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    static const char a1[] = "[\"Nigel Rees\", \"Evelyn Waugh\", \"Herman Melville\", \"J. R. R. Tolkien\"]";
    json r1(o.path("/store/book/author"));
    BOOST_CHECK_EQUAL(json::load(a1), r1);

    json r2(o.path("//author"));
    BOOST_CHECK_EQUAL(json::load(a1), r2);

    // jansson hashtable uses size_t for hash
    // we think this is causing the buckets to change on 32bit vs. 64bit
#if (__SIZEOF_SIZE_T__ == 4)
    static const char a3[] = "[{\"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95}, {\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}, {\"color\": \"red\", \"price\": 19.95}]";
#elif (__SIZEOF_SIZE_T__ == 8)
    static const char a3[] = "[{\"color\": \"red\", \"price\": 19.95}, {\"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95}, {\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}]";
#endif
    json r3(o.path("/store/*"));
    json t3(json::load(a3));
    BOOST_CHECK_EQUAL(t3, r3);

#if (__SIZEOF_SIZE_T__ == 4)
    static const char a4[] = "[8.95, 12.99, 8.99, 22.99, 19.95]";
#elif (__SIZEOF_SIZE_T__ == 8)
    static const char a4[] = "[19.95, 8.95, 12.99, 8.99, 22.99]";
#endif
    json r4(o.path("/store//price"));
    BOOST_CHECK_EQUAL(json::load(a4), r4);

    static const char a5[] = "{\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}";
    json r5(o.path("//book[3]"));
    BOOST_CHECK_EQUAL(json::load(a5), r5);

    static const char a6[] = "\"J. R. R. Tolkien\"";
    json r6(o.path("/store/book[3]/author"));
    BOOST_CHECK_EQUAL(json::load(a6), r6);
    BOOST_CHECK(json::load(a6) == r6);

    static const char a7[] = "[{\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}]";
    json r7(o.path("/store/book[category=\"fiction\"]"));
    BOOST_CHECK_EQUAL(json::load(a7), r7);
}

BOOST_AUTO_TEST_CASE(json_test_path2) {
    json o(json::load("[{\"type\": 0}, {\"type\": 1}]"));
    BOOST_CHECK_EQUAL(json::load("[{\"type\":1}]"), o.path("/[type=1]"));
}

BOOST_AUTO_TEST_CASE(json_test_filter_key_exists) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    static const char a[] = "["
"      { \"category\": \"fiction\","
"        \"author\": \"Herman Melville\","
"        \"title\": \"Moby Dick\","
"        \"isbn\": \"0-553-21311-3\","
"        \"price\": 8.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"J. R. R. Tolkien\","
"        \"title\": \"The Lord of the Rings\","
"        \"isbn\": \"0-395-19395-8\","
"        \"price\": 22.99"
"      }]";
    json r(o.path("//book[isbn]"));
    BOOST_CHECK_EQUAL(json::load(a), r);

    json r1(o.path("//book[doesnotexist]"));
    BOOST_REQUIRE(r1.is_array());
    BOOST_CHECK_EQUAL(0, r1.asize());
}

BOOST_AUTO_TEST_CASE(json_test_truth) {
    json o(json::object());
    BOOST_CHECK(o.get("nothing").is_true() == false);
    BOOST_CHECK(o.get("nothing").is_false() == false);
    BOOST_CHECK(o.get("nothing").is_null() == false);
    BOOST_CHECK(!o.get("nothing"));
}

BOOST_AUTO_TEST_CASE(json_test_path3) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    BOOST_CHECK_EQUAL(o, o.path("/"));
    BOOST_CHECK_EQUAL("Sayings of the Century",
        o.path("/store/book[category=\"reference\"]/title"));

    static const char text[] = "["
    "{\"type\":\"a\", \"value\":0},"
    "{\"type\":\"b\", \"value\":1},"
    "{\"type\":\"c\", \"value\":2},"
    "{\"type\":\"c\", \"value\":3}"
    "]";

    BOOST_CHECK_EQUAL(json(1), json::load(text).path("/[type=\"b\"]/value"));
}

BOOST_AUTO_TEST_CASE(json_init_list) {
    json meta{
        { "foo", 17 },
        { "bar", 23 },
        { "baz", true },
        { "corge", json::array({ 1, 3.14159 }) },
        { "grault", json::array({ "hello", string("world") }) },
    };
    BOOST_REQUIRE(meta);
    BOOST_REQUIRE(meta.is_object());
    BOOST_CHECK_EQUAL(meta.osize(), 5);
    BOOST_CHECK_EQUAL(meta["foo"].integer(), 17);
    BOOST_CHECK_EQUAL(meta["corge"][0].integer(), 1);
    BOOST_CHECK_EQUAL(meta["grault"][1].str(), "world");
}

template <class T>
inline void test_conv(T val, json j, json_type t) {
    json j2 = to_json(val);
    BOOST_CHECK_EQUAL(j2.type(), t);
    BOOST_CHECK_EQUAL(j, j2);
    T val2 = json_cast<T>(j2);
    BOOST_CHECK_EQUAL(val, val2);
}

template <class T, json_type TYPE = JSON_INTEGER>
inline void test_conv_num() {
    typedef numeric_limits<T> lim;
    T range[5] = { lim::min(), T(-1), 0, T(1), lim::max() };
    for (unsigned i = 0; i < 5; ++i)
        test_conv<T>(range[i], json(range[i]), TYPE);
}

BOOST_AUTO_TEST_CASE(json_conversions) {
    test_conv<string>(string("hello"), json::str("hello"), JSON_STRING);
    BOOST_CHECK_EQUAL(to_json("world"), json::str("world"));

    test_conv_num<short>();
    test_conv_num<int>();
    test_conv_num<long>();
    test_conv_num<long long>();
    test_conv_num<unsigned short>();
    test_conv_num<unsigned>();
#if ULONG_MAX < LLONG_MAX
    test_conv_num<unsigned long>();
#endif

    test_conv_num<double, JSON_REAL>();
    test_conv_num<float,  JSON_REAL>();

    test_conv<bool>(true,  json::jtrue(),  JSON_TRUE);
    test_conv<bool>(false, json::jfalse(), JSON_FALSE);
}

BOOST_AUTO_TEST_CASE(json_create) {
    json obj1;
    obj1.set("test", "set");
    BOOST_CHECK(obj1);
    BOOST_CHECK(obj1.get("test"));
    json root{
        {"obj1", obj1}
    };
    BOOST_CHECK_EQUAL(root.get("obj1"), obj1);
    obj1.set("this", "that");
    BOOST_CHECK_EQUAL(root.get("obj1").get("this").str(), "that");
    json obj2{ {"answer", 42} };
    obj1.set("obj2", obj2);
    BOOST_CHECK_EQUAL(root.get("obj1").get("obj2"), obj2);
}

#ifdef TEN_JSON_CXX11
struct corge {
    int foo, bar;

    corge() : foo(), bar() {}
    corge(int foo_, int bar_) : foo(foo_), bar(bar_) {}
};
template <class AR>
inline AR & operator & (AR &ar, corge &c) {
    return ar & kv("foo", c.foo) & kv("bar", c.bar);
}
inline bool operator == (const corge &a, const corge &b) {
    return a.foo == b.foo && a.bar == b.bar;
}

enum captain { kirk, picard, janeway, sisko };
const array<string, 4> captain_names = {{ "kirk", "picard", "janeway", "sisko" }};
template <class AR>
inline AR & operator & (AR &ar, captain &c) {
    return serialize_enum(ar, c, captain_names);
}

BOOST_AUTO_TEST_CASE(json_serial) {
    corge c1(42, 17);
    auto j = jsave_all(c1);
    corge c2;
    JLoad(j) >> c2;
    BOOST_CHECK(c1 == c2);

    map<string, int> m;
    JLoad(j) >> m;
    BOOST_CHECK_EQUAL(m.size(), 2);
    BOOST_CHECK(m.find("foo") != m.end());
    BOOST_CHECK(m.find("bar") != m.end());
    BOOST_CHECK_EQUAL(m["foo"], 42);
    BOOST_CHECK_EQUAL(m["bar"], 17);

#if BOOST_VERSION >= 104800
    flat_map<string, int> f;
    JLoad(j) >> f;
    BOOST_CHECK_EQUAL(f.size(), 2);
    BOOST_CHECK(f.find("foo") != f.end());
    BOOST_CHECK(f.find("bar") != f.end());
    BOOST_CHECK_EQUAL(f["foo"], 42);
    BOOST_CHECK_EQUAL(f["bar"], 17);
#endif

    maybe<int> a;
    j = jsave_all(a);
    BOOST_CHECK(!j);
    a = 42;
    j = jsave_all(a);
    BOOST_CHECK_EQUAL(j, 42);

    a.reset();
    BOOST_CHECK(!a.ok());
    j = 17;
    JLoad(j) >> a;
    BOOST_CHECK(a.ok());
    BOOST_CHECK_EQUAL(a.get(), 17);

    captain c = janeway;
    j = jsave_all(c);
    BOOST_CHECK_EQUAL(j, "janeway");
    j = "kirk";
    JLoad(j) >> c;
    BOOST_CHECK_EQUAL(c, kirk);
}

#endif // TEN_JSON_CXX11
<|endoftext|>


<commit_before>//
//  KinematicsSimulator.cpp
//  GPcode01_01_xcode
//
//  Created by young-min kang on 3/27/15.
//  Copyright (c) 2015 young-min kang. All rights reserved.
//

#include "DynamicSimulator.h"

CDynamicSimulator::CDynamicSimulator() : CSimulator() {}

void CDynamicSimulator::init() {

    for(int i=0;i<NUMPARTS;i++)particle[i].randomInit();
}

void CDynamicSimulator::clean() {

}

void CDynamicSimulator::doBeforeSimulation(double dt, double currentTime) {
	// buoyancy here
}

void CDynamicSimulator::doSimulation(double dt, double currentTime) {
    for(int i=0;i<NUMPARTS;i++)
        particle[i].simulate(dt, currentTime);
}

void CDynamicSimulator::doAfterSimulation(double dt, double currentTime) {
    for(int i=0;i<NUMPARTS;i++) {
		particle[i].resetForce();
	}
}

void CDynamicSimulator::visualize(void) {
    for(int i=0;i<NUMPARTS;i++) {
        particle[i].drawWithGL(SPHERE_DRAW);
    }
}<commit_msg>Update DynamicSimulator.cpp<commit_after>//
//  DynamicSimulator.cpp
//  GPcode01_01_xcode
//
//  Created by young-min kang on 3/27/15.
//  Copyright (c) 2015 young-min kang. All rights reserved.
//

#include "DynamicSimulator.h"

CDynamicSimulator::CDynamicSimulator() : CSimulator() {}

void CDynamicSimulator::init() {

    for(int i=0;i<NUMPARTS;i++)particle[i].randomInit();
}

void CDynamicSimulator::clean() {

}

void CDynamicSimulator::doBeforeSimulation(double dt, double currentTime) {
	// buoyancy here
}

void CDynamicSimulator::doSimulation(double dt, double currentTime) {
    for(int i=0;i<NUMPARTS;i++)
        particle[i].simulate(dt, currentTime);
}

void CDynamicSimulator::doAfterSimulation(double dt, double currentTime) {
    for(int i=0;i<NUMPARTS;i++) {
		particle[i].resetForce();
	}
}

void CDynamicSimulator::visualize(void) {
    for(int i=0;i<NUMPARTS;i++) {
        particle[i].drawWithGL(SPHERE_DRAW);
    }
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// test unsigned long to_ulong() const;

#include <bitset>
#include <algorithm>
#include <climits>
#include <cassert>

template <std::size_t N>
void test_to_ulong()
{
    const std::size_t M = sizeof(unsigned long) * CHAR_BIT < N ? sizeof(unsigned long) * CHAR_BIT : N;
    const std::size_t X = M == 0 ? sizeof(unsigned long) * CHAR_BIT - 1 : sizeof(unsigned long) * CHAR_BIT - M;
    const std::size_t max = M == 0 ? 0 : std::size_t(-1) >> X;
    std::size_t tests[] = {0,
                           std::min<std::size_t>(1, max),
                           std::min<std::size_t>(2, max),
                           std::min<std::size_t>(3, max),
                           std::min(max, max-3),
                           std::min(max, max-2),
                           std::min(max, max-1),
                           max};
    for (std::size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i)
    {
        std::size_t j = tests[i];
        std::bitset<N> v(j);
        assert(j == v.to_ulong());
    }
}

int main()
{
    test_to_ulong<0>();
    test_to_ulong<1>();
    test_to_ulong<31>();
    test_to_ulong<32>();
    test_to_ulong<33>();
    test_to_ulong<63>();
    test_to_ulong<64>();
    test_to_ulong<65>();
    test_to_ulong<1000>();
}
<commit_msg>Test case was forming the wrong limits when size_t != unsigned long.<commit_after>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// test unsigned long to_ulong() const;

#include <bitset>
#include <algorithm>
#include <limits>
#include <climits>
#include <cassert>

template <std::size_t N>
void test_to_ulong()
{
    const std::size_t M = sizeof(unsigned long) * CHAR_BIT < N ? sizeof(unsigned long) * CHAR_BIT : N;
    const std::size_t X = M == 0 ? sizeof(unsigned long) * CHAR_BIT - 1 : sizeof(unsigned long) * CHAR_BIT - M;
    const std::size_t max = M == 0 ? 0 : std::size_t(std::numeric_limits<unsigned long>::max()) >> X;
    std::size_t tests[] = {0,
                           std::min<std::size_t>(1, max),
                           std::min<std::size_t>(2, max),
                           std::min<std::size_t>(3, max),
                           std::min(max, max-3),
                           std::min(max, max-2),
                           std::min(max, max-1),
                           max};
    for (std::size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i)
    {
        std::size_t j = tests[i];
        std::bitset<N> v(j);
        assert(j == v.to_ulong());
    }
}

int main()
{
    test_to_ulong<0>();
    test_to_ulong<1>();
    test_to_ulong<31>();
    test_to_ulong<32>();
    test_to_ulong<33>();
    test_to_ulong<63>();
    test_to_ulong<64>();
    test_to_ulong<65>();
    test_to_ulong<1000>();
}
<|endoftext|>


<commit_before><commit_msg>Setting pending override mesh<commit_after><|endoftext|>


<commit_before>#ifndef BENCHMARK_HPP_
#define BENCHMARK_HPP_

#define BOOST_TEST_NO_MAIN
#define BOOST_TEST_ALTERNATIVE_INIT_API

#include "application.hpp"
#include "options.hpp"
#include "benchmark_suite.hpp"

#include <boost/test/included/unit_test.hpp>
#include <boost/mpl/list.hpp>

namespace gearshifft {

  /// List alias
  template<typename... Types>
  using List = boost::mpl::list<Types...>;

  /**
   * Benchmark API class for clients.
   *
   */
  template<typename Context>
  class Benchmark {
    using AppT = Application<Context>;

  public:
    Benchmark() = default;

    ~Benchmark() {
      if(AppT::getInstance().isContextCreated()) {
        AppT::getInstance().destroyContext();
      }
    }

    void configure(int argc, char* argv[]) {
      configured_ = false;
      std::vector<char*> vargv(argv, argv+argc);
      boost_vargv_.clear();
      boost_vargv_.emplace_back(argv[0]); // [0] = name of application

      if( Options::getInstance().parse(vargv, boost_vargv_) ) {
        if( gearshifft::Options::getInstance().getListDevices() ) {
          std::cout << Context::getListDevices() << std::endl;
        }
      }
      else
        configured_ = true;
    }

    template<typename T_FFT_Is_Normalized,
             typename T_FFTs,
             typename T_Precisions>
    void run() {
      if(configured_==false)
        return;

      AppT::getInstance().createContext();

      auto init_function = []() {
        Run<Context, T_FFT_Is_Normalized, T_FFTs, T_Precisions> instance;
        ::boost::unit_test::framework::master_test_suite().add( instance() );
        return true;
      };

      ::boost::unit_test::unit_test_main( init_function,
                                          boost_vargv_.size(),
                                          boost_vargv_.data() );

      AppT::getInstance().destroyContext();
      AppT::getInstance().dumpResults();
    }

  private:
    bool configured_ = false;
    std::vector<char*> boost_vargv_;
  };

} // gearshifft

#endif // BENCHMARK_HPP_
<commit_msg>disabled using the boost test alternative stack to fix segfault at the end of fftw benchmarks<commit_after>#ifndef BENCHMARK_HPP_
#define BENCHMARK_HPP_
#define BOOST_TEST_DISABLE_ALT_STACK
#define BOOST_TEST_NO_MAIN
#define BOOST_TEST_ALTERNATIVE_INIT_API

#include "application.hpp"
#include "options.hpp"
#include "benchmark_suite.hpp"

#include <boost/test/included/unit_test.hpp>
#include <boost/mpl/list.hpp>

namespace gearshifft {

  /// List alias
  template<typename... Types>
  using List = boost::mpl::list<Types...>;

  /**
   * Benchmark API class for clients.
   *
   */
  template<typename Context>
  class Benchmark {
    using AppT = Application<Context>;

  public:
    Benchmark() = default;

    ~Benchmark() {
      if(AppT::getInstance().isContextCreated()) {
        AppT::getInstance().destroyContext();
      }
    }

    void configure(int argc, char* argv[]) {
      configured_ = false;
      std::vector<char*> vargv(argv, argv+argc);
      boost_vargv_.clear();
      boost_vargv_.emplace_back(argv[0]); // [0] = name of application

      if( Options::getInstance().parse(vargv, boost_vargv_) ) {
        if( gearshifft::Options::getInstance().getListDevices() ) {
          std::cout << Context::getListDevices() << std::endl;
        }
      }
      else
        configured_ = true;
    }

    template<typename T_FFT_Is_Normalized,
             typename T_FFTs,
             typename T_Precisions>
    void run() {
      if(configured_==false)
        return;

      AppT::getInstance().createContext();

      auto init_function = []() {
        Run<Context, T_FFT_Is_Normalized, T_FFTs, T_Precisions> instance;
        ::boost::unit_test::framework::master_test_suite().add( instance() );
        return true;
      };

      ::boost::unit_test::unit_test_main( init_function,
                                          boost_vargv_.size(),
                                          boost_vargv_.data() );

      AppT::getInstance().destroyContext();
      AppT::getInstance().dumpResults();
    }

  private:
    bool configured_ = false;
    std::vector<char*> boost_vargv_;
  };

} // gearshifft

#endif // BENCHMARK_HPP_
<|endoftext|>


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

#include "wamp_message_type.hpp"

#include <boost/lexical_cast.hpp>
#include <stdexcept>
#include <tuple>

namespace autobahn {

inline wamp_invocation_impl::wamp_invocation_impl()
    : m_zone()
    , m_details(EMPTY_DETAILS)
    , m_arguments(EMPTY_ARGUMENTS)
    , m_kw_arguments(EMPTY_KW_ARGUMENTS)
    , m_send_result_fn()
    , m_request_id(0)
{
}

template <typename T>
T wamp_invocation_impl::details(const std::string& key) const
{
    if (m_details.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    for (std::size_t i = 0; i < m_details.via.map.size; ++i) {
        const msgpack::object_kv& kv = m_details.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key.size() == kv.key.via.str.size
            && key.compare(0, key.size(), kv.key.via.str.ptr, kv.key.via.str.size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw std::out_of_range(key + " detail argument doesn't exist");
}

template <typename T>
T wamp_invocation_impl::detail(const char *key) const
{
    if (m_details.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    std::size_t key_size = strlen(key);
    for (std::size_t i = 0; i < m_details.via.map.size; ++i) {
        const msgpack::object_kv& kv = m_details.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key_size == kv.key.via.str.size
            && memcmp(key, kv.key.via.str.ptr, key_size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw std::out_of_range(std::string(key) + " keyword argument doesn't exist");
}

template<typename Map>
Map wamp_invocation_impl::details() const
{
    return m_details.as<Map>();
}

inline std::size_t wamp_invocation_impl::number_of_arguments() const
{
    return m_arguments.type == msgpack::type::ARRAY ? m_arguments.via.array.size : 0;
}

inline std::size_t wamp_invocation_impl::number_of_kw_arguments() const
{
    return m_kw_arguments.type == msgpack::type::MAP ? m_kw_arguments.via.map.size : 0;
}

template <typename T>
inline T wamp_invocation_impl::argument(std::size_t index) const
{
    if (m_arguments.type != msgpack::type::ARRAY || m_arguments.via.array.size <= index) {
        throw std::out_of_range("no argument at index " + boost::lexical_cast<std::string>(index));
    }
    return m_arguments.via.array.ptr[index].as<T>();
}

template <typename List>
inline List wamp_invocation_impl::arguments() const
{
    return m_arguments.as<List>();
}

template <typename List>
inline void wamp_invocation_impl::get_arguments(List& args) const
{
    m_arguments.convert(args);
}

template <typename... T>
inline void wamp_invocation_impl::get_each_argument(T&... args) const
{
    auto args_tuple = std::make_tuple(std::ref(args)...);
    m_arguments.convert(args_tuple);
}

template <typename T>
inline T wamp_invocation_impl::kw_argument(const std::string& key) const
{
    if (m_kw_arguments.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    for (std::size_t i = 0; i < m_kw_arguments.via.map.size; ++i) {
        const msgpack::object_kv& kv = m_kw_arguments.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key.size() == kv.key.via.str.size
                && key.compare(0, key.size(), kv.key.via.str.ptr, kv.key.via.str.size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw std::out_of_range(key + " keyword argument doesn't exist");
}

template <typename T>
inline T wamp_invocation_impl::kw_argument(const char* key) const
{
    if (m_kw_arguments.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    std::size_t key_size = strlen(key);
    for (std::size_t i = 0; i < m_kw_arguments.via.map.size; ++i) {
        const msgpack::object_kv& kv = m_kw_arguments.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key_size == kv.key.via.str.size
                && memcmp(key, kv.key.via.str.ptr, key_size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw std::out_of_range(std::string(key) + " keyword argument doesn't exist");
}

template <typename T>
inline T wamp_invocation_impl::kw_argument_or(const std::string& key, const T& fallback) const
{
    if (m_kw_arguments.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    for (std::size_t i = 0; i < m_kw_arguments.via.map.size; ++i) {
        const msgpack::object_kv& kv = m_kw_arguments.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key.size() == kv.key.via.str.size
                && key.compare(0, key.size(), kv.key.via.str.ptr, kv.key.via.str.size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    return fallback;
}

template <typename T>
inline T wamp_invocation_impl::kw_argument_or(const char* key, const T& fallback) const
{
    if (m_kw_arguments.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    std::size_t key_size = strlen(key);
    for (std::size_t i = 0; i < m_kw_arguments.via.map.size; ++i) {
        const msgpack::object_kv& kv = m_kw_arguments.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key_size == kv.key.via.str.size
                && memcmp(key, kv.key.via.str.ptr, key_size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw fallback;
}

template <typename Map>
inline Map wamp_invocation_impl::kw_arguments() const
{
    return m_kw_arguments.as<Map>();
}

template <typename Map>
inline void wamp_invocation_impl::get_kw_arguments(Map& kw_args) const
{
    m_kw_arguments.convert(kw_args);
}

inline void wamp_invocation_impl::empty_result()
{
    throw_if_not_sendable();

    auto buffer = std::make_shared<msgpack::sbuffer>();
    msgpack::packer<msgpack::sbuffer> packer(*buffer);

    // [YIELD, INVOCATION.Request|id, Options|dict]
    packer.pack_array(3);
    packer.pack(static_cast<int>(message_type::YIELD));
    packer.pack(m_request_id);
    packer.pack_map(0);

    m_send_result_fn(buffer);
    m_send_result_fn = send_result_fn();
}

template<typename List>
inline void wamp_invocation_impl::result(const List& arguments)
{
    throw_if_not_sendable();

    auto buffer = std::make_shared<msgpack::sbuffer>();
    msgpack::packer<msgpack::sbuffer> packer(*buffer);

    // [YIELD, INVOCATION.Request|id, Options|dict, Arguments|list]
    packer.pack_array(4);
    packer.pack(static_cast<int>(message_type::YIELD));
    packer.pack(m_request_id);
    packer.pack_map(0);
    packer.pack(arguments);

    m_send_result_fn(buffer);
    m_send_result_fn = send_result_fn();
}

template<typename List, typename Map>
inline void wamp_invocation_impl::result(
        const List& arguments, const Map& kw_arguments)
{
    throw_if_not_sendable();

    auto buffer = std::make_shared<msgpack::sbuffer>();
    msgpack::packer<msgpack::sbuffer> packer(*buffer);

    // [YIELD, INVOCATION.Request|id, Options|dict, Arguments|list, ArgumentsKw|dict]
    packer.pack_array(5);
    packer.pack(static_cast<int>(message_type::YIELD));
    packer.pack(m_request_id);
    packer.pack_map(0);
    packer.pack(arguments);
    packer.pack(kw_arguments);

    m_send_result_fn(buffer);
    m_send_result_fn = send_result_fn();
}

inline void wamp_invocation_impl::error(const std::string& error_uri)
{
    throw_if_not_sendable();

    auto buffer = std::make_shared<msgpack::sbuffer>();
    msgpack::packer<msgpack::sbuffer> packer(*buffer);

    // [ERROR, INVOCATION, INVOCATION.Request|id, Details|dict, Error|uri]
    packer.pack_array(5);
    packer.pack(static_cast<int>(message_type::ERROR));
    packer.pack(static_cast<int>(message_type::INVOCATION));
    packer.pack(m_request_id);
    packer.pack_map(0);
    packer.pack(error_uri);

    m_send_result_fn(buffer);
    m_send_result_fn = send_result_fn();
}

template <typename List>
inline void wamp_invocation_impl::error(const std::string& error_uri, const List& arguments)
{
    throw_if_not_sendable();

    auto buffer = std::make_shared<msgpack::sbuffer>();
    msgpack::packer<msgpack::sbuffer> packer(*buffer);

    // [ERROR, INVOCATION, INVOCATION.Request|id, Details|dict, Error|uri, Arguments|list]
    packer.pack_array(6);
    packer.pack(static_cast<int>(message_type::ERROR));
    packer.pack(static_cast<int>(message_type::INVOCATION));
    packer.pack(m_request_id);
    packer.pack_map(0);
    packer.pack(error_uri);
    packer.pack(arguments);

    m_send_result_fn(buffer);
    m_send_result_fn = send_result_fn();
}

template <typename List, typename Map>
inline void wamp_invocation_impl::error(
        const std::string& error_uri,
        const List& arguments, const Map& kw_arguments)
{
    throw_if_not_sendable();

    auto buffer = std::make_shared<msgpack::sbuffer>();
    msgpack::packer<msgpack::sbuffer> packer(*buffer);

    // [ERROR, INVOCATION, INVOCATION.Request|id, Details|dict, Error|uri, Arguments|list, ArgumentsKw|dict]
    packer.pack_array(7);
    packer.pack(static_cast<int>(message_type::ERROR));
    packer.pack(static_cast<int>(message_type::INVOCATION));
    packer.pack(m_request_id);
    packer.pack_map(0);
    packer.pack(error_uri);
    packer.pack(arguments);
    packer.pack(kw_arguments);

    m_send_result_fn(buffer);
    m_send_result_fn = send_result_fn();
}

inline void wamp_invocation_impl::set_send_result_fn(send_result_fn&& send_result)
{
    m_send_result_fn = std::move(send_result);
}

inline void wamp_invocation_impl::set_request_id(std::uint64_t request_id)
{
    m_request_id = request_id;
}

inline void wamp_invocation_impl::set_details(const msgpack::object& details)
{
    m_details = details;
}

inline void wamp_invocation_impl::set_zone(msgpack::zone&& zone)
{
    m_zone = std::move(zone);
}

inline void wamp_invocation_impl::set_arguments(const msgpack::object& arguments)
{
    m_arguments = arguments;
}

inline void wamp_invocation_impl::set_kw_arguments(const msgpack::object& kw_arguments)
{
    m_kw_arguments = kw_arguments;
}

inline bool wamp_invocation_impl::sendable() const
{
    return static_cast<bool>(m_send_result_fn);
}

inline void wamp_invocation_impl::throw_if_not_sendable()
{
    if (!sendable()) {
        throw std::runtime_error("tried to call result() or error() but wamp_invocation "
                "is not sendable (double call?)");
    }
}

} // namespace autobahn
<commit_msg>Clean up exception wording<commit_after>///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2014 Tavendo GmbH
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////

#include "wamp_message_type.hpp"

#include <boost/lexical_cast.hpp>
#include <stdexcept>
#include <tuple>

namespace autobahn {

inline wamp_invocation_impl::wamp_invocation_impl()
    : m_zone()
    , m_details(EMPTY_DETAILS)
    , m_arguments(EMPTY_ARGUMENTS)
    , m_kw_arguments(EMPTY_KW_ARGUMENTS)
    , m_send_result_fn()
    , m_request_id(0)
{
}

template <typename T>
T wamp_invocation_impl::details(const std::string& key) const
{
    if (m_details.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    for (std::size_t i = 0; i < m_details.via.map.size; ++i) {
        const msgpack::object_kv& kv = m_details.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key.size() == kv.key.via.str.size
            && key.compare(0, key.size(), kv.key.via.str.ptr, kv.key.via.str.size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw std::out_of_range(key + " detail doesn't exist");
}

template <typename T>
T wamp_invocation_impl::detail(const char *key) const
{
    if (m_details.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    std::size_t key_size = strlen(key);
    for (std::size_t i = 0; i < m_details.via.map.size; ++i) {
        const msgpack::object_kv& kv = m_details.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key_size == kv.key.via.str.size
            && memcmp(key, kv.key.via.str.ptr, key_size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw std::out_of_range(std::string(key) + " detail doesn't exist");
}

template<typename Map>
Map wamp_invocation_impl::details() const
{
    return m_details.as<Map>();
}

inline std::size_t wamp_invocation_impl::number_of_arguments() const
{
    return m_arguments.type == msgpack::type::ARRAY ? m_arguments.via.array.size : 0;
}

inline std::size_t wamp_invocation_impl::number_of_kw_arguments() const
{
    return m_kw_arguments.type == msgpack::type::MAP ? m_kw_arguments.via.map.size : 0;
}

template <typename T>
inline T wamp_invocation_impl::argument(std::size_t index) const
{
    if (m_arguments.type != msgpack::type::ARRAY || m_arguments.via.array.size <= index) {
        throw std::out_of_range("no argument at index " + boost::lexical_cast<std::string>(index));
    }
    return m_arguments.via.array.ptr[index].as<T>();
}

template <typename List>
inline List wamp_invocation_impl::arguments() const
{
    return m_arguments.as<List>();
}

template <typename List>
inline void wamp_invocation_impl::get_arguments(List& args) const
{
    m_arguments.convert(args);
}

template <typename... T>
inline void wamp_invocation_impl::get_each_argument(T&... args) const
{
    auto args_tuple = std::make_tuple(std::ref(args)...);
    m_arguments.convert(args_tuple);
}

template <typename T>
inline T wamp_invocation_impl::kw_argument(const std::string& key) const
{
    if (m_kw_arguments.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    for (std::size_t i = 0; i < m_kw_arguments.via.map.size; ++i) {
        const msgpack::object_kv& kv = m_kw_arguments.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key.size() == kv.key.via.str.size
                && key.compare(0, key.size(), kv.key.via.str.ptr, kv.key.via.str.size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw std::out_of_range(key + " keyword argument doesn't exist");
}

template <typename T>
inline T wamp_invocation_impl::kw_argument(const char* key) const
{
    if (m_kw_arguments.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    std::size_t key_size = strlen(key);
    for (std::size_t i = 0; i < m_kw_arguments.via.map.size; ++i) {
        const msgpack::object_kv& kv = m_kw_arguments.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key_size == kv.key.via.str.size
                && memcmp(key, kv.key.via.str.ptr, key_size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw std::out_of_range(std::string(key) + " keyword argument doesn't exist");
}

template <typename T>
inline T wamp_invocation_impl::kw_argument_or(const std::string& key, const T& fallback) const
{
    if (m_kw_arguments.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    for (std::size_t i = 0; i < m_kw_arguments.via.map.size; ++i) {
        const msgpack::object_kv& kv = m_kw_arguments.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key.size() == kv.key.via.str.size
                && key.compare(0, key.size(), kv.key.via.str.ptr, kv.key.via.str.size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    return fallback;
}

template <typename T>
inline T wamp_invocation_impl::kw_argument_or(const char* key, const T& fallback) const
{
    if (m_kw_arguments.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    std::size_t key_size = strlen(key);
    for (std::size_t i = 0; i < m_kw_arguments.via.map.size; ++i) {
        const msgpack::object_kv& kv = m_kw_arguments.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key_size == kv.key.via.str.size
                && memcmp(key, kv.key.via.str.ptr, key_size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw fallback;
}

template <typename Map>
inline Map wamp_invocation_impl::kw_arguments() const
{
    return m_kw_arguments.as<Map>();
}

template <typename Map>
inline void wamp_invocation_impl::get_kw_arguments(Map& kw_args) const
{
    m_kw_arguments.convert(kw_args);
}

inline void wamp_invocation_impl::empty_result()
{
    throw_if_not_sendable();

    auto buffer = std::make_shared<msgpack::sbuffer>();
    msgpack::packer<msgpack::sbuffer> packer(*buffer);

    // [YIELD, INVOCATION.Request|id, Options|dict]
    packer.pack_array(3);
    packer.pack(static_cast<int>(message_type::YIELD));
    packer.pack(m_request_id);
    packer.pack_map(0);

    m_send_result_fn(buffer);
    m_send_result_fn = send_result_fn();
}

template<typename List>
inline void wamp_invocation_impl::result(const List& arguments)
{
    throw_if_not_sendable();

    auto buffer = std::make_shared<msgpack::sbuffer>();
    msgpack::packer<msgpack::sbuffer> packer(*buffer);

    // [YIELD, INVOCATION.Request|id, Options|dict, Arguments|list]
    packer.pack_array(4);
    packer.pack(static_cast<int>(message_type::YIELD));
    packer.pack(m_request_id);
    packer.pack_map(0);
    packer.pack(arguments);

    m_send_result_fn(buffer);
    m_send_result_fn = send_result_fn();
}

template<typename List, typename Map>
inline void wamp_invocation_impl::result(
        const List& arguments, const Map& kw_arguments)
{
    throw_if_not_sendable();

    auto buffer = std::make_shared<msgpack::sbuffer>();
    msgpack::packer<msgpack::sbuffer> packer(*buffer);

    // [YIELD, INVOCATION.Request|id, Options|dict, Arguments|list, ArgumentsKw|dict]
    packer.pack_array(5);
    packer.pack(static_cast<int>(message_type::YIELD));
    packer.pack(m_request_id);
    packer.pack_map(0);
    packer.pack(arguments);
    packer.pack(kw_arguments);

    m_send_result_fn(buffer);
    m_send_result_fn = send_result_fn();
}

inline void wamp_invocation_impl::error(const std::string& error_uri)
{
    throw_if_not_sendable();

    auto buffer = std::make_shared<msgpack::sbuffer>();
    msgpack::packer<msgpack::sbuffer> packer(*buffer);

    // [ERROR, INVOCATION, INVOCATION.Request|id, Details|dict, Error|uri]
    packer.pack_array(5);
    packer.pack(static_cast<int>(message_type::ERROR));
    packer.pack(static_cast<int>(message_type::INVOCATION));
    packer.pack(m_request_id);
    packer.pack_map(0);
    packer.pack(error_uri);

    m_send_result_fn(buffer);
    m_send_result_fn = send_result_fn();
}

template <typename List>
inline void wamp_invocation_impl::error(const std::string& error_uri, const List& arguments)
{
    throw_if_not_sendable();

    auto buffer = std::make_shared<msgpack::sbuffer>();
    msgpack::packer<msgpack::sbuffer> packer(*buffer);

    // [ERROR, INVOCATION, INVOCATION.Request|id, Details|dict, Error|uri, Arguments|list]
    packer.pack_array(6);
    packer.pack(static_cast<int>(message_type::ERROR));
    packer.pack(static_cast<int>(message_type::INVOCATION));
    packer.pack(m_request_id);
    packer.pack_map(0);
    packer.pack(error_uri);
    packer.pack(arguments);

    m_send_result_fn(buffer);
    m_send_result_fn = send_result_fn();
}

template <typename List, typename Map>
inline void wamp_invocation_impl::error(
        const std::string& error_uri,
        const List& arguments, const Map& kw_arguments)
{
    throw_if_not_sendable();

    auto buffer = std::make_shared<msgpack::sbuffer>();
    msgpack::packer<msgpack::sbuffer> packer(*buffer);

    // [ERROR, INVOCATION, INVOCATION.Request|id, Details|dict, Error|uri, Arguments|list, ArgumentsKw|dict]
    packer.pack_array(7);
    packer.pack(static_cast<int>(message_type::ERROR));
    packer.pack(static_cast<int>(message_type::INVOCATION));
    packer.pack(m_request_id);
    packer.pack_map(0);
    packer.pack(error_uri);
    packer.pack(arguments);
    packer.pack(kw_arguments);

    m_send_result_fn(buffer);
    m_send_result_fn = send_result_fn();
}

inline void wamp_invocation_impl::set_send_result_fn(send_result_fn&& send_result)
{
    m_send_result_fn = std::move(send_result);
}

inline void wamp_invocation_impl::set_request_id(std::uint64_t request_id)
{
    m_request_id = request_id;
}

inline void wamp_invocation_impl::set_details(const msgpack::object& details)
{
    m_details = details;
}

inline void wamp_invocation_impl::set_zone(msgpack::zone&& zone)
{
    m_zone = std::move(zone);
}

inline void wamp_invocation_impl::set_arguments(const msgpack::object& arguments)
{
    m_arguments = arguments;
}

inline void wamp_invocation_impl::set_kw_arguments(const msgpack::object& kw_arguments)
{
    m_kw_arguments = kw_arguments;
}

inline bool wamp_invocation_impl::sendable() const
{
    return static_cast<bool>(m_send_result_fn);
}

inline void wamp_invocation_impl::throw_if_not_sendable()
{
    if (!sendable()) {
        throw std::runtime_error("tried to call result() or error() but wamp_invocation "
                "is not sendable (double call?)");
    }
}

} // namespace autobahn
<|endoftext|>