Skip to content

Commit

Permalink
Add test coverage for Meta namespace and fix bugs around multi-value …
Browse files Browse the repository at this point in the history
…meta keys.
  • Loading branch information
felixarntz committed Jul 24, 2024
1 parent c36f1f3 commit 6942a45
Show file tree
Hide file tree
Showing 7 changed files with 913 additions and 0 deletions.
22 changes: 22 additions & 0 deletions src/Meta/Meta_Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ public function exists( int $entity_id, string $key ): bool {
*/
public function get( int $entity_id, string $key, $default = null ) {
if ( ! metadata_exists( $this->object_type, $entity_id, $key ) ) {
// If not single, ensure the default is within an array.
if ( ! $this->get_single( $key ) ) {
if ( null !== $default ) {
return array( $default );
}
return array();
}
return $default;
}

Expand All @@ -89,6 +96,21 @@ public function get( int $entity_id, string $key, $default = null ) {
* @return bool True on success, false on failure.
*/
public function update( int $entity_id, string $key, $value ): bool {
/*
* If multiple values, delete the original ones first and then add the new ones individually, but only if the
* passed value is an indexed (not associative) array.
* There is only one caveat with this, but that is an edge-case: If the individual values of a multi-value meta
* key are themselves indexed arrays, this can lead to unexpected behavior with this implementation. A
* workaround would be to wrap them in another array before passing them to this method.
*/
if ( ! $this->get_single( $key ) && wp_is_numeric_array( $value ) ) {
delete_metadata( $this->object_type, $entity_id, $key );
foreach ( $value as $single_value ) {
add_metadata( $this->object_type, $entity_id, $key, $single_value );
}
return true;
}

return (bool) update_metadata( $this->object_type, $entity_id, $key, $value );
}

Expand Down
92 changes: 92 additions & 0 deletions tests/phpunit/tests/Meta/Entity_Aware_Meta_Container_Tests.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php
/**
* Tests for Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Entity_Aware_Meta_Container
*
* @since n.e.x.t
* @package wp-oop-plugin-lib
*/

namespace Felix_Arntz\WP_OOP_Plugin_Lib\PHPUnit\Tests\Meta;

use Felix_Arntz\WP_OOP_Plugin_Lib\General\Exception\Not_Found_Exception;
use Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Entity_Aware_Meta_Container;
use Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Entity_Aware_Meta_Key;
use Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Meta_Container;
use Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Meta_Key;
use Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Meta_Repository;
use Felix_Arntz\WP_OOP_Plugin_Lib\PHPUnit\Includes\Test_Case;
use WP_UnitTest_Factory;

/**
* @group meta
*/
class Entity_Aware_Meta_Container_Tests extends Test_Case {

private static $post_id;

private $repository;
private $container;

public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
self::$post_id = $factory->post->create();
}

public static function wpTearDownAfterClass() {
wp_delete_post( self::$post_id, true );
}

public function set_up() {
parent::set_up();
$this->repository = new Meta_Repository( 'post' );

$meta_container = new Meta_Container();
$meta_container->set(
'test_meta',
function () {
return new Meta_Key(
$this->repository,
'test_meta',
array( 'type' => 'string' )
);
}
);

$this->container = new Entity_Aware_Meta_Container( $meta_container, self::$post_id );
}

public function test_has() {
$this->assertTrue( $this->container->has( 'test_meta' ) );
$this->assertFalse( $this->container->has( 'missing_meta' ) );
}

public function test_get_simple() {
$meta_key = $this->container->get( 'test_meta' );
$this->assertInstanceOf( Entity_Aware_Meta_Key::class, $meta_key );
$this->assertSame( 'test_meta', $meta_key->get_key() );
$this->assertSame( self::$post_id, $meta_key->get_entity_id() );
}

public function test_get_with_missing() {
$this->expectException( Not_Found_Exception::class );
$this->container->get( 'missing_meta' );
}

public function test_get_keys() {
$this->assertSame(
array( 'test_meta' ),
$this->container->get_keys()
);
}

public function test_offsetExists() {
$this->assertSame( $this->container->has( 'test_meta' ), isset( $this->container['test_meta'] ) );
}

public function test_offsetGet() {
$this->assertSame( $this->container->get( 'test_meta' ), $this->container['test_meta'] );
}

public function test_get_entity_id() {
$this->assertSame( self::$post_id, $this->container->get_entity_id() );
}
}
84 changes: 84 additions & 0 deletions tests/phpunit/tests/Meta/Entity_Aware_Meta_Key_Tests.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php
/**
* Tests for Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Entity_Aware_Meta_Key
*
* @since n.e.x.t
* @package wp-oop-plugin-lib
*/

namespace Felix_Arntz\WP_OOP_Plugin_Lib\PHPUnit\Tests\Meta;

use Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Entity_Aware_Meta_Key;
use Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Meta_Key;
use Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Meta_Repository;
use Felix_Arntz\WP_OOP_Plugin_Lib\PHPUnit\Includes\Test_Case;
use WP_UnitTest_Factory;

/**
* @group meta
*/
class Entity_Aware_Meta_Key_Tests extends Test_Case {

private static $post_id;

private $repository;
private $meta_key;

public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
self::$post_id = $factory->post->create();
}

public static function wpTearDownAfterClass() {
wp_delete_post( self::$post_id, true );
}

public function set_up() {
parent::set_up();
$this->repository = new Meta_Repository( 'post' );

$this->meta_key = new Entity_Aware_Meta_Key(
new Meta_Key(
$this->repository,
'test_meta',
array( 'type' => 'string' )
),
self::$post_id
);
}

public function test_has_value() {
$this->assertFalse( $this->meta_key->has_value() );

update_post_meta( self::$post_id, 'test_meta', 'some-value' );
$this->assertTrue( $this->meta_key->has_value() );
}

public function test_get_value() {
$this->assertSame( '', $this->meta_key->get_value() );

update_post_meta( self::$post_id, 'test_meta', 'some-value' );
$this->assertSame( 'some-value', $this->meta_key->get_value() );
}

public function test_update_value() {
$this->assertSame( '', get_post_meta( self::$post_id, 'test_meta', true ) );

$this->meta_key->update_value( 'new-value' );
$this->assertSame( 'new-value', get_post_meta( self::$post_id, 'test_meta', true ) );
}

public function test_delete_value() {
update_post_meta( self::$post_id, 'test_meta', 'some-value' );

$this->meta_key->delete_value();
$this->assertSame( '', get_post_meta( self::$post_id, 'test_meta', true ) );
}

public function test_get_key() {
$this->assertSame( 'test_meta', $this->meta_key->get_key() );
}

public function test_get_entity_id() {
$this->assertSame( self::$post_id, $this->meta_key->get_entity_id() );
}
}
180 changes: 180 additions & 0 deletions tests/phpunit/tests/Meta/Meta_Container_Tests.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
<?php
/**
* Tests for Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Meta_Container
*
* @since n.e.x.t
* @package wp-oop-plugin-lib
*/

namespace Felix_Arntz\WP_OOP_Plugin_Lib\PHPUnit\Tests\Meta;

use Felix_Arntz\WP_OOP_Plugin_Lib\General\Exception\Invalid_Type_Exception;
use Felix_Arntz\WP_OOP_Plugin_Lib\General\Exception\Not_Found_Exception;
use Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Meta_Container;
use Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Meta_Key;
use Felix_Arntz\WP_OOP_Plugin_Lib\Meta\Meta_Repository;
use Felix_Arntz\WP_OOP_Plugin_Lib\PHPUnit\Includes\Test_Case;

/**
* @group meta
*/
class Meta_Container_Tests extends Test_Case {

private $repository;
private $container;

public function set_up() {
parent::set_up();
$this->repository = new Meta_Repository( 'post' );
$this->container = new Meta_Container();

$this->container->set(
'test_meta',
function () {
return new Meta_Key(
$this->repository,
'test_meta',
array(
'type' => 'string',
'description' => 'Test meta key',
'default' => 'test-value',
)
);
}
);
}

public function test_has() {
$this->assertTrue( $this->container->has( 'test_meta' ) );
$this->assertFalse( $this->container->has( 'missing_meta' ) );
}

public function test_get_simple() {
$meta_key = $this->container->get( 'test_meta' );
$this->assertInstanceOf( Meta_Key::class, $meta_key );
$this->assertSame( 'test_meta', $meta_key->get_key() );
}

public function test_get_with_missing() {
$this->expectException( Not_Found_Exception::class );
$this->container->get( 'missing_meta' );
}

public function test_get_with_invalid_type() {
$this->container->set(
'invalid_type_meta',
static function () {
return new \stdClass();
}
);

$this->expectException( Invalid_Type_Exception::class );
$this->container->get( 'invalid_type_meta' );
}

public function test_set_simple() {
$this->assertFalse( $this->container->has( 'integer_meta' ) );
$this->container->set(
'integer_meta',
function () {
return new Meta_Key(
$this->repository,
'integer_meta',
array(
'type' => 'integer',
'default' => 23,
)
);
}
);
$this->assertTrue( $this->container->has( 'integer_meta' ) );
$this->assertInstanceOf( Meta_Key::class, $this->container->get( 'integer_meta' ) );
}

public function test_set_with_override() {
$this->assertTrue( $this->container->has( 'test_meta' ) );
$this->assertSame( 'test-value', $this->container->get( 'test_meta' )->get_value( 1 ) );
$this->container->set(
'test_meta',
function () {
return new Meta_Key(
$this->repository,
'test_meta',
array(
'type' => 'integer',
'default' => 23,
)
);
}
);
$this->assertSame( 23, $this->container->get( 'test_meta' )->get_value( 1 ) );
}

public function test_set_by_args() {
$this->assertFalse( $this->container->has( 'integer_meta' ) );
$this->container->set_by_args(
'integer_meta',
$this->repository,
array(
'type' => 'integer',
'default' => 23,
)
);
$this->assertTrue( $this->container->has( 'integer_meta' ) );
$this->assertInstanceOf( Meta_Key::class, $this->container->get( 'integer_meta' ) );
}

public function test_unset() {
// Resolve the meta key prior to its removal.
$this->container->get( 'test_meta' );

// Remove it.
$this->container->unset( 'test_meta' );
$this->assertFalse( $this->container->has( 'test_meta' ) );

// Ensure the already resolved instance was wiped as intended.
$this->expectException( Not_Found_Exception::class );
$this->container->get( 'test_meta' );
}

public function test_get_keys() {
$this->assertSame(
array( 'test_meta' ),
$this->container->get_keys()
);
}

public function test_offsetExists() {
$this->assertSame( $this->container->has( 'test_meta' ), isset( $this->container['test_meta'] ) );
}

public function test_offsetGet() {
$this->assertSame( $this->container->get( 'test_meta' ), $this->container['test_meta'] );
}

public function test_offsetSet() {
$this->assertFalse( $this->container->has( 'integer_meta' ) );
$this->container['integer_meta'] = function () {
return new Meta_Key(
$this->repository,
'integer_meta',
array(
'type' => 'integer',
'default' => 23,
)
);
};
$this->assertTrue( $this->container->has( 'integer_meta' ) );
}

public function test_offsetUnset() {
unset( $this->container['test_meta'] );
$this->assertFalse( $this->container->has( 'test_meta' ) );
}

public function test_create_entity_aware() {
$entity_aware_container = $this->container->create_entity_aware( 1 );
$this->assertSame( 1, $entity_aware_container->get_entity_id() );
$this->assertSame( $this->container, $this->get_hidden_property_value( $entity_aware_container, 'wrapped_container' ) );
}
}
Loading

0 comments on commit 6942a45

Please sign in to comment.