/*

oess_1: Object Entity Serialization & Stability
Yauheni A. Akhotnikau (C) 2002-2006
eao197@yahoo.com
-------------------------------------------------

Permission is granted to anyone to use this software for any purpose on any
computer system, and to redistribute it freely, subject to the following
restrictions:

1. This software is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

2. The origin of this software must not be misrepresented, either by
   explicit claim or by omission.

3. Altered versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

-------------------------------------------------

*/

/*
 * Проверка корректности сохранения oess_1::defs::quantity_t в
 * двоичном потоке.
 */

#undef NDEBUG

#include <string>
#include <cassert>

#include <oess_1/defs/h/quantity.hpp>
#include <oess_1/defs/h/ex.hpp>

#include <oess_1/io/h/errno.hpp>
#include <oess_1/io/h/bstring_buf.hpp>
#include <oess_1/io/h/fixed_mem_buf.hpp>

void
test_pack()
	{
		{
			// Ноль должен сохраняться как ноль.
			char etalon[] = { 0 };
			std::string result;
			oess_1::io::obstring_t result_stream( result );
			result_stream << oess_1::defs::quantity_t( 0 );

			assert( 1 == result.length() );
			assert( result == std::string( etalon, sizeof( etalon ) ) );
		}
		{
			// 127 должно быть сохранено в одном байте.
			char etalon[] = { 127 };
			std::string result;
			oess_1::io::obstring_t result_stream( result );
			result_stream << oess_1::defs::quantity_t( 127 );

			assert( 1 == result.length() );
			assert( result == std::string( etalon, sizeof( etalon ) ) );
		}
		{
			// 128 должно быть сохранено в одном байте + один байт длины.
			char etalon[] = { 0x81, 128 };
			std::string result;
			oess_1::io::obstring_t result_stream( result );
			result_stream << oess_1::defs::quantity_t( 128 );

			assert( 2 == result.length() );
			assert( result == std::string( etalon, sizeof( etalon ) ) );
		}
		{
			// 255 должно быть сохранено в одном байте + один байт длины.
			char etalon[] = { 0x81, 255 };
			std::string result;
			oess_1::io::obstring_t result_stream( result );
			result_stream << oess_1::defs::quantity_t( 255 );

			assert( 2 == result.length() );
			assert( result == std::string( etalon, sizeof( etalon ) ) );
		}
		{
			// 256 должно быть сохранено в двух байтах + один байт длины.
			char etalon[] = { 0x82, 1, 0 };
			std::string result;
			oess_1::io::obstring_t result_stream( result );
			result_stream << oess_1::defs::quantity_t( 256 );

			assert( 3 == result.length() );
			assert( result == std::string( etalon, sizeof( etalon ) ) );
		}
		{
			// 0xFFFFFFFFu должно быть сохранено в четырех байтах + байт длины.
			char etalon[] = { 0x84, 255, 255, 255, 255 };
			std::string result;
			oess_1::io::obstring_t result_stream( result );
			result_stream << oess_1::defs::quantity_t( 0xFFFFFFFFu );

			assert( 5 == result.length() );
			assert( result == std::string( etalon, sizeof( etalon ) ) );
		}
	}

void
test_unpack()
	{
		{
			// Ноль должен читаться как ноль.
			char etalon[] = { 0 };
			oess_1::io::ifixed_mem_buf_t in_stream( etalon, sizeof( etalon ) );
			oess_1::defs::quantity_t result;
			in_stream >> result;

			assert( 0 == result.value() );
		}
		{
			// Единичка должа остаться единичкой.
			char etalon[] = { 1 };
			oess_1::io::ifixed_mem_buf_t in_stream( etalon, sizeof( etalon ) );
			oess_1::defs::quantity_t result;
			in_stream >> result;

			assert( 1 == result.value() );
		}
		{
			// 127
			char etalon[] = { 127 };
			oess_1::io::ifixed_mem_buf_t in_stream( etalon, sizeof( etalon ) );
			oess_1::defs::quantity_t result;
			in_stream >> result;

			assert( 127 == result.value() );
		}
		{
			// 128
			char etalon[] = { 0x81, 128 };
			oess_1::io::ifixed_mem_buf_t in_stream( etalon, sizeof( etalon ) );
			oess_1::defs::quantity_t result;
			in_stream >> result;

			assert( 128 == result.value() );
		}
		{
			// 256
			char etalon[] = { 0x82, 1, 0 };
			oess_1::io::ifixed_mem_buf_t in_stream( etalon, sizeof( etalon ) );
			oess_1::defs::quantity_t result;
			in_stream >> result;

			assert( 256 == result.value() );
		}
		{
			// 0xFFFFFFFF
			char etalon[] = { 0x84, 0xFF, 0xFF, 0xFF, 0xFF };
			oess_1::io::ifixed_mem_buf_t in_stream( etalon, sizeof( etalon ) );
			oess_1::defs::quantity_t result;
			in_stream >> result;

			assert( 0xFFFFFFFFu == result.value() );
		}
		{
			// Порождение исключения, если длина образа слишком большая.
			char etalon[] = { 0x85, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
			oess_1::io::ifixed_mem_buf_t in_stream( etalon, sizeof( etalon ) );
			oess_1::defs::quantity_t result;
			int exception_code = 0;

			try
				{
					in_stream >> result;
				}
			catch( const oess_1::physic_ex_t & x )
				{
					std::cout << x.what() << std::endl;
					exception_code = x.query_err_code().m_code;
				}
			catch( const std::exception & x )
				{
					std::cout << x.what() << std::endl;
					exception_code = -1;
				}

			assert( oess_1::io::err::c_quantity_image_too_long == exception_code );
		}
	}

int
main()
	{
		test_pack();
		test_unpack();
	}

