#include <catch2/catch.hpp>
#include <alib/map>
#include <alib/algorithm>

namespace {
	class Moveable {
		int& m_moves;
		int& m_copies;

		public:
		Moveable(int& moves, int& copies) : m_moves(moves), m_copies(copies) {
			m_moves = 0;
			m_copies = 0;
		}

		Moveable(const Moveable& src) : m_moves(src.m_moves), m_copies(src.m_copies) {
			m_copies++;
		}

		Moveable(Moveable&& src) : m_moves(src.m_moves), m_copies(src.m_copies) {
			m_moves++;
		}

		Moveable & operator = ( const Moveable & ) {
			m_copies ++;
			return * this;
		}

		Moveable & operator = ( Moveable && ) {
			m_moves ++;
			return * this;
		}

		bool operator<(const Moveable&) const {
			return false;
		}
	};
}
TEST_CASE ( "Map", "[unit][std][container]" ) {
	SECTION ( "Basic" ) {
		int moves;
		int copies;

		ext::map<Moveable, Moveable> map;
		map.insert ( Moveable(moves, copies ), Moveable(moves, copies) );
		ext::map<Moveable, Moveable> map2;

		for( std::pair < Moveable, Moveable > moveablePair : ext::make_mover (  map ) ) {
			map2.insert(std::move(moveablePair));
		}

		bool res = map2.insert_or_assign ( Moveable ( moves, copies ), Moveable ( moves, copies ) ).second;

		CHECK ( res == false );

		CHECK ( copies == 0 );
	}

	SECTION ( "At" ) {
		ext::map < int, std::string > map;
		map.insert ( 1, "one" );

		{
			std::string defaultValue = "default";
			std::string & value = map.at ( 0, defaultValue );

			CHECK ( value == "default" );
		}

		{
			const std::string defaultValue = "default";
			const std::string & value = map.at ( 0, defaultValue );

			CHECK ( value == "default" );
		}
	}

	CHECK ( ( std::tuple_size < const std::pair < int, int > >::value == 2 ) );
}
