<?php

namespace ActivityPhpTest\Type;

use ActivityPhpTest\MyCustomType;
use ActivityPhpTest\MyCustomValidator;
use ActivityPhp\Type;
use Exception;
use PHPUnit\Framework\TestCase;

class FactoryTest extends TestCase
{
	/**
	 * Valid scenarios provider
	 */
	public function getShortTypes()
	{
		return [
		    ['Activity'],
		    ['Collection'],
		    ['CollectionPage'],
		    ['IntransitiveActivity'],
		    ['Link'],
		    ['ObjectType'],
		    ['Object'],
		    ['OrderedCollection'],
		    ['OrderedCollectionPage'],
		    ['Application'],
		    ['Group'],
		    ['Organization'],
		    ['Person'],
		    ['Service'],
		    ['Accept'],
		    ['Add'],
		    ['Announce'],
		    ['Arrive'],
		    ['Block'],
		    ['Create'],
		    ['Delete'],
		    ['Dislike'],
		    ['Flag'],
		    ['Follow'],
		    ['Ignore'],
		    ['Invite'],
		    ['Join'],
		    ['Leave'],
		    ['Like'],
		    ['Listen'],
		    ['Move'],
		    ['Offer'],
		    ['Question'],
		    ['Read'],
		    ['Reject'],
		    ['Remove'],
		    ['TentativeAccept'],
		    ['TentativeReject'],
		    ['Travel'],
		    ['Undo'],
		    ['Update'],
		    ['View'],
		    ['Article'],
		    ['Audio'],
		    ['Document'],
		    ['Event'],
		    ['Image'],
		    ['Mention'],
		    ['Note'],
		    ['Page'],
		    ['Place'],
		    ['Profile'],
		    ['Relationship'],
		    ['Tombstone'],
		    ['Video'],
		];
	}


	/**
	 * Check that all core objects have a correct type property.
	 *
	 * @dataProvider getShortTypes
	 */
	public function testShortTypesInstanciation($type)
	{
		$class = Type::create($type, ['name' => strtolower($type)]);

		// Assert affectation
		$this->assertEquals(
		    strtolower($type),
		    $class->name
		);

		// Object has two names: Object and ObjectType
		if ($type == 'ObjectType') {
		    $type = 'Object';
		}

		// Assert type property
		$this->assertEquals(
		    $type,
		    $class->type
		);
	}


	/**
	 * Scenario for an undefined type
	 */
	public function testUndefinedType()
	{
		$this->expectException(Exception::class);

		$class = Type::create('UndefinedType');
	}


	/**
	 * Scenario for a custom validator
	 *
	 * - Add a validator in the pool for 'customProperty' attribute
	 * - Create a type with this property and affect a correct value
	 */
	public function testCustomValidatorSuccess()
	{
		Type::add('MyCustomType', MyCustomType::class);
		Type::addValidator('customProperty', MyCustomValidator::class);
		$type = Type::create(
		    'MyCustomType',
		    ['customProperty' => 'My value']
		);

		// Assert type property
		$this->assertEquals(
		    'My value',
		    $type->customProperty
		);
	}


	/**
	 * Scenario for instanciating a Type with a single array parameter
	 */
	public function testShortCallSuccess()
	{
		$type = Type::create([
		    'type' => 'Note',
		    'id' => 'http://example.org/missing-type'
		]);

		// Assert type property
		$this->assertEquals(
		    'Note',
		    $type->type
		);

		// Assert another property
		$this->assertEquals(
		    'http://example.org/missing-type',
		    $type->id
		);
	}


	/**
	 * Scenario for instanciating a Type with a single array parameter
	 * for a failing value (missing type property)
	 */
	public function testShortCallFailing()
	{
		$this->expectException(Exception::class);

		$type = Type::create(
		    ['id' => 'http://example.org/missing-type']
		);
	}


	/**
	 * Scenario for instanciating a Type with a single parameter that
	 * is not an array.
	 */
	public function testShortCallFailingIntGiven()
	{
		$this->expectException(Exception::class);

		$type = Type::create(
		    42
		);
	}


	/**
	 * Scenario for a custom classes and custom validator with an
	 * failing value
	 */
	public function testCustomValidatorFailing()
	{
		$this->expectException(Exception::class);

		Type::addValidator('customProperty', MyCustomValidator::class);
		$type = Type::create(
		    'MyCustomType',
		    ['customProperty' => 'Bad value']
		);
	}


	/**
	 * Scenario for a custom type
	 *
	 * - Add a Type in the pool with 'Person' name
	 * - Instanciate and sets customType value
	 */
	public function testCustomTypeSuccess()
	{
		Type::add('Person', MyCustomType::class);
		$type = Type::create(
		    'Person',
		    ['customProperty' => 'My value']
		);

		// Assert type property
		$this->assertEquals(
		    'My value',
		    $type->customProperty
		);
	}


	/**
	 * Scenario for a custom classes with a failing value
	 */
	public function testCustomTypeFailing()
	{
		$this->expectException(Exception::class);

		Type::add('Person', 'MyUndefinedType');
	}


	/**
	 * Test a copy of an AS object
	 */
	public function testCopy()
	{
		$original = Type::create([
		    'type' => 'Note',
		    'id' => 'http://example.org/original-id'
		]);

		$copy = $original->copy();

		// Assert type are equals
		$this->assertEquals(
		    $original->type,
		    $copy->type
		);

		// Assert all properties are equals
		$this->assertEquals(
		    $original->toArray(),
		    $copy->toArray()
		);

		// Change a value
		$copy->id = 'http://example.org/copy-id';

		// Change is ok for the copy
		$this->assertEquals(
		    'http://example.org/copy-id',
		    $copy->id
		);

		// Assert original is not affected
		$this->assertEquals(
		    'http://example.org/original-id',
		    $original->id
		);
	}


	/**
	 * Test copy chaining
	 */
	public function testCopyChaining()
	{
		$original = Type::create([
		    'type' => 'Note',
		    'id' => 'http://example.org/original-id'
		]);

		$copy = $original->copy()->setId(
		    'http://example.org/copy-id'
		);

		// Change is ok for the copy
		$this->assertEquals(
		    'http://example.org/copy-id',
		    $copy->id
		);

		// Assert original is not affected
		$this->assertEquals(
		    'http://example.org/original-id',
		    $original->id
		);
	}


	/**
	 * Test creating a type from a JSON string
	 */
	public function testFromJson()
	{
		$json = '{"type":"Note","content":"A content for my note"}';

		$note = Type::fromJson($json);

		$this->assertEquals(
		    $json,
		    $note->toJson()
		);
	}


	/**
	 * Test creating a type from a malformed JSON string
	 */
	public function testFromJsonMalformedJsonString()
	{
		$this->expectException(Exception::class);

		$json = '{';
		$note = Type::fromJson($json);
	}


	/**
	 * Test creating a type from a JSON string which does not contains
	 * an array.
	 */
	public function testFromJsonNotAnArray()
	{
		$this->expectException(Exception::class);

		$json = '"OK"';
		$note = Type::fromJson($json);
	}
}
__halt_compiler();----SIGNATURE:----sRoaK1jODq2gi6Tt+1idan+ajek3d3YsWQkeV8YaagQCbOEp003aPEX/RSI1ohPOUjEtm6f7KrjH2UOWjMh6Di2H5eWmgxgb8+4zRqFCyG2fFElqaX3/sAtDcJjmoEgFoxrjpek0nvxdOYH+jt/UjCLWMhSdzF2xEhMvQ8cl7uXnadRsqbfbhaLFb3o1hTY440FbEdDal6SHFin/D3Y0y5wXCHMzEPT4u0tt3bP8MO59Dix580R99VzsmexpbS+a/p/egA5+FRnaRHMn7Teb9YGOzhntRcd5LPtfNyrD8zVWnsUcpLcW046/1t83vt8HTRm7LWfI8I4D/ly+0qOhzfJ/ep7nGf9HU4G+JZH9l5SsXgV97bRoPwFlKYVKWtxASSdqpygKG9Xe2NPOn140oO9Qr+iBuRB9sTvEnPd54XGSLuL2XFnj+4JKYJc8yFzGn97OW0GnwBTR34w9idTAdp3MCkqaCnwmVrmbzjcX91HSSXMKEiLzI0+0d6bKJfbNJUpDEbyrXFBsOF6tS3m0/Ghg5XNTuFPMlubIPuzj0NBq73w93C/fIn+azTeGaksJtwW91tbVSLyF3h63Rdw0dOeHZMXSYlhG6mvS/JBQsOeyY+M8+KEBjgGztNca4GcTcxxDoMog0MkSfn80WTbBZOy8zPcIuj4/Cxl7zgXhRzo=----ATTACHMENT:----NjExMjE4MTc2NzEwNjY4OCA0MjIzMjAwNjY2NTY3MTcyIDYyMTk3ODQ1NjczOTM3MTI=