diff --git a/tests/unit/HelperTest.php b/tests/unit/HelperTest.php index 620801295..29f9b2ede 100644 --- a/tests/unit/HelperTest.php +++ b/tests/unit/HelperTest.php @@ -2,10 +2,14 @@ namespace SkyVerge\WooCommerce\PluginFramework\v5_15_4\Tests\Unit; +use Generator; +use Mockery; use ReflectionException; use SkyVerge\WooCommerce\PluginFramework\v5_15_4\SV_WC_Helper; use SkyVerge\WooCommerce\PluginFramework\v5_15_4\SV_WC_Plugin_Compatibility; use SkyVerge\WooCommerce\PluginFramework\v5_15_4\Tests\TestCase; +use WC_Data; +use WP_Mock; class HelperTest extends TestCase { @@ -51,4 +55,107 @@ public function testAlwaysDetermineNavigationFeaturedDisabled() : void $this->assertFalse(SV_WC_Helper::is_wc_navigation_enabled()); } + + /** + * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_4\SV_WC_Helper::getWooCommerceObjectMetaValue() + * + * @throws ReflectionException + */ + public function testCanGetWooCommerceDataObjectMetaValue() : void + { + $object = Mockery::mock('WC_Data'); + + $this->mockStaticMethod(SV_WC_Helper::class, 'getPostOrObjectMetaCompat') + ->once() + ->with(null, $object, $field = 'TEST_FIELD', true) + ->andReturn($value = 'WC_DATA_META_VALUE'); + + $this->assertSame($value, SV_WC_Helper::getWooCommerceObjectMetaValue($object, $field)); + } + + /** + * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_4\SV_WC_Helper::getWooCommerceObjectMetaValue() + * + * @throws ReflectionException + */ + public function testCanGetWordPressPostMetaValue() : void + { + $object = Mockery::mock('WP_Post'); + + $this->mockStaticMethod(SV_WC_Helper::class, 'getPostOrObjectMetaCompat') + ->once() + ->with($object, null, $field = 'TEST_FIELD', true) + ->andReturn($value = 'WP_POST_META_VALUE'); + + $this->assertSame($value, SV_WC_Helper::getWooCommerceObjectMetaValue($object, $field)); + } + + /** + * @dataProvider providerCanGetPostOrObjectMetaCompat() + * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_4\SV_WC_Helper::getPostOrObjectMetaCompat() + * + * @param bool $hasData + * @param bool $hasPostId + * @param mixed $expected + * + * @throws ReflectionException + */ + public function testCanGetPostOrObjectMetaCompat( + bool $hasData, + bool $hasPostId, + $expected + ) : void + { + $key = 'test'; + $object = null; + + $post = Mockery::mock('WP_Post'); + + if ($hasPostId) { + $post->ID = 123; + } + + if ($hasData) { + $object = Mockery::mock('WC_Data'); + + $object->expects('get_meta') + ->times((int) ($hasData)) + ->with($key, true) + ->andReturn('WC_DATA_META_VALUE'); + } + + WP_Mock::userFunction('get_post_meta') + ->times((int) (! $hasData && $hasPostId)) + ->with(123, $key, true) + ->andReturn('WP_POST_META_VALUE'); + + $this->assertSame($expected, SV_WC_Helper::getPostOrObjectMetaCompat($post, $object, $key, true)); + } + + /** @see testCanGetPostOrObjectMetaCompat() */ + public function providerCanGetPostOrObjectMetaCompat() : Generator + { + yield 'data is set, method does not exist' => [ + 'hasData' => true, + 'hasPostId' => false, + 'expected' => 'WC_DATA_META_VALUE', + ]; + + /* + * Note: It seems there's no sane way to test the get$key() method + * on a WC_Data mock, thus no test case for 'data is set, method exists'. + */ + + yield 'data not set, no post ID' => [ + 'hasData' => false, + 'hasPostId' => false, + 'expected' => false, + ]; + + yield 'data not set, has post ID' => [ + 'hasData' => false, + 'hasPostId' => true, + 'expected' => 'WP_POST_META_VALUE', + ]; + } } diff --git a/woocommerce/class-sv-wc-helper.php b/woocommerce/class-sv-wc-helper.php index 60439233f..e4c7c5101 100644 --- a/woocommerce/class-sv-wc-helper.php +++ b/woocommerce/class-sv-wc-helper.php @@ -25,6 +25,8 @@ namespace SkyVerge\WooCommerce\PluginFramework\v5_15_4; use SkyVerge\WooCommerce\PluginFramework\v5_15_4\Helpers\NumberHelper; +use WC_Data; +use WP_Post; defined( 'ABSPATH' ) or exit; @@ -1197,6 +1199,50 @@ public static function get_escaped_id_list( array $ids ) { } + /** + * Gets value of a meta key from WooCommerce object based on its data type. + * + * @param WP_Post|WC_Data $object + * @param string $field + * @param bool $single + * + * @return array|mixed|string|null + */ + public static function getWooCommerceObjectMetaValue($object, string $field, bool $single = true) + { + if ($object instanceof WP_Post) { + return static::getPostOrObjectMetaCompat($object, null, $field, $single); + } + + if ($object instanceof WC_Data) { + return static::getPostOrObjectMetaCompat(null, $object, $field, $single); + } + + return null; + } + + /** + * Adds local compatibility for Woo's internal OrderUtil::get_post_or_object_meta() method. + * + * @param WP_Post|null $post + * @param WC_Data|null $data + * @param string $key + * @param bool $single + * + * @return array|false|mixed|string + */ + public static function getPostOrObjectMetaCompat(?\WP_Post $post, ?\WC_Data $data, string $key, bool $single) + { + if (isset($data)) { + if (method_exists($data, "get$key")) { + return $data->{"get$key"}(); + } + return $data->get_meta($key, $single); + } else { + return isset($post->ID) ? get_post_meta($post->ID, $key, $single) : false; + } + } + }