From 18f7def6c61eb07e1a4346f808d9f2f65437b383 Mon Sep 17 00:00:00 2001 From: Nabeel Molham Date: Thu, 10 Oct 2024 16:47:29 +1100 Subject: [PATCH 1/5] Add helper method to get WooCommerce object meta value based on its data type --- woocommerce/class-sv-wc-helper.php | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/woocommerce/class-sv-wc-helper.php b/woocommerce/class-sv-wc-helper.php index 5cbfaa3b8..38ce5a9ae 100644 --- a/woocommerce/class-sv-wc-helper.php +++ b/woocommerce/class-sv-wc-helper.php @@ -24,7 +24,10 @@ namespace SkyVerge\WooCommerce\PluginFramework\v5_15_1; +use Automattic\WooCommerce\Utilities\OrderUtil; use SkyVerge\WooCommerce\PluginFramework\v5_15_1\Helpers\NumberHelper; +use WC_Data; +use WP_Post; defined( 'ABSPATH' ) or exit; @@ -1197,6 +1200,34 @@ 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) + { + $orderUtilExists = class_exists(OrderUtil::class); + + if ($object instanceof WP_Post) { + return $orderUtilExists ? + OrderUtil::get_post_or_object_meta($object, null, $field, $single) : + get_post_meta($object->ID, $field, $single); + } + + if ($object instanceof WC_Data) { + return $orderUtilExists ? + OrderUtil::get_post_or_object_meta(null, $object, $field, $single) : + $object->get_meta($field, $single); + } + + return null; + } + } From 3a6fc7adde27c0556c6d85a3e1625e38860c2aba Mon Sep 17 00:00:00 2001 From: Nabeel Molham Date: Thu, 10 Oct 2024 16:47:47 +1100 Subject: [PATCH 2/5] Unit test SV_WC_Helper::getWooCommerceObjectMetaValue method --- tests/Mocks/OrderUtil.php | 11 +++++ tests/unit/HelperTest.php | 86 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 tests/Mocks/OrderUtil.php diff --git a/tests/Mocks/OrderUtil.php b/tests/Mocks/OrderUtil.php new file mode 100644 index 000000000..3075bd546 --- /dev/null +++ b/tests/Mocks/OrderUtil.php @@ -0,0 +1,11 @@ +assertFalse(SV_WC_Helper::is_wc_navigation_enabled()); } + + /** + * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_1\SV_WC_Helper::getWooCommerceObjectMetaValue() + * + * @runInSeparateProcess + * + * @throws ReflectionException + */ + public function testCanGetWooCommerceDataObjectMetaValueUsingOrderUtil() : void + { + require_once PLUGIN_ROOT_DIR.'/tests/Mocks/OrderUtil.php'; + + $object = Mockery::mock('WC_Data'); + + $object->expects('get_meta')->never(); + + $this->mockStaticMethod(OrderUtil::class, 'get_post_or_object_meta') + ->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_1\SV_WC_Helper::getWooCommerceObjectMetaValue() + * + * @runInSeparateProcess + */ + public function testCanGetWooCommerceDataObjectMetaValueWithoutUsingOrderUtil() : void + { + $object = Mockery::mock('WC_Data'); + + $object->expects('get_meta') + ->once() + ->with($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_1\SV_WC_Helper::getWooCommerceObjectMetaValue() + * + * @runInSeparateProcess + * + * @throws ReflectionException + */ + public function testCanGetWordPressPostMetaValueUsingOrderUtil() : void + { + require_once PLUGIN_ROOT_DIR.'/tests/Mocks/OrderUtil.php'; + + $object = Mockery::mock('WP_Post'); + + WP_Mock::userFunction('get_post_meta')->never(); + + $this->mockStaticMethod(OrderUtil::class, 'get_post_or_object_meta') + ->once() + ->with($object, null, $field = 'TEST_FIELD', true) + ->andReturn($value = 'WP_POST_META_VALUE'); + + $this->assertSame($value, SV_WC_Helper::getWooCommerceObjectMetaValue($object, $field)); + } + + /** + * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_1\SV_WC_Helper::getWooCommerceObjectMetaValue() + * + * @runInSeparateProcess + */ + public function testCanGetWordPressPostMetaValueWithoutUsingOrderUtil() : void + { + $object = Mockery::mock('WP_Post'); + $object->ID = 123; + + WP_Mock::userFunction('get_post_meta') + ->once() + ->with($object->ID, $field = 'TEST_FIELD', true) + ->andReturn($value = 'WP_POST_META_VALUE'); + + $this->assertSame($value, SV_WC_Helper::getWooCommerceObjectMetaValue($object, $field)); + } } From 5249fea5bab3d81b328a620590dcfc7cf1330453 Mon Sep 17 00:00:00 2001 From: Nabeel Molham Date: Thu, 10 Oct 2024 16:53:00 +1100 Subject: [PATCH 3/5] Add preserveGlobalState annotation --- tests/unit/HelperTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/HelperTest.php b/tests/unit/HelperTest.php index 055ae2c52..f50cd71ef 100644 --- a/tests/unit/HelperTest.php +++ b/tests/unit/HelperTest.php @@ -59,6 +59,7 @@ public function testAlwaysDetermineNavigationFeaturedDisabled() : void * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_1\SV_WC_Helper::getWooCommerceObjectMetaValue() * * @runInSeparateProcess + * @preserveGlobalState * * @throws ReflectionException */ @@ -82,6 +83,7 @@ public function testCanGetWooCommerceDataObjectMetaValueUsingOrderUtil() : void * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_1\SV_WC_Helper::getWooCommerceObjectMetaValue() * * @runInSeparateProcess + * @preserveGlobalState */ public function testCanGetWooCommerceDataObjectMetaValueWithoutUsingOrderUtil() : void { @@ -99,6 +101,7 @@ public function testCanGetWooCommerceDataObjectMetaValueWithoutUsingOrderUtil() * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_1\SV_WC_Helper::getWooCommerceObjectMetaValue() * * @runInSeparateProcess + * @preserveGlobalState * * @throws ReflectionException */ @@ -122,6 +125,7 @@ public function testCanGetWordPressPostMetaValueUsingOrderUtil() : void * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_1\SV_WC_Helper::getWooCommerceObjectMetaValue() * * @runInSeparateProcess + * @preserveGlobalState */ public function testCanGetWordPressPostMetaValueWithoutUsingOrderUtil() : void { From 9f45812e46dbe561a6f2db73fec9e5f45b3a1036 Mon Sep 17 00:00:00 2001 From: Andrew Jaynes Date: Tue, 22 Oct 2024 00:51:29 -0600 Subject: [PATCH 4/5] Drop the dependency on OrderUtil, add a compat method with tests instead. Update tests and remove the OrderUtil mock. --- tests/Mocks/OrderUtil.php | 11 --- tests/unit/HelperTest.php | 107 +++++++++++++++++------------ woocommerce/class-sv-wc-helper.php | 33 ++++++--- 3 files changed, 87 insertions(+), 64 deletions(-) delete mode 100644 tests/Mocks/OrderUtil.php diff --git a/tests/Mocks/OrderUtil.php b/tests/Mocks/OrderUtil.php deleted file mode 100644 index 3075bd546..000000000 --- a/tests/Mocks/OrderUtil.php +++ /dev/null @@ -1,11 +0,0 @@ -expects('get_meta')->never(); - - $this->mockStaticMethod(OrderUtil::class, 'get_post_or_object_meta') + $this->mockStaticMethod(SV_WC_Helper::class, 'getPostOrObjectMetaCompat') ->once() ->with(null, $object, $field = 'TEST_FIELD', true) ->andReturn($value = 'WC_DATA_META_VALUE'); @@ -82,61 +76,86 @@ public function testCanGetWooCommerceDataObjectMetaValueUsingOrderUtil() : void /** * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_1\SV_WC_Helper::getWooCommerceObjectMetaValue() * - * @runInSeparateProcess - * @preserveGlobalState + * @throws ReflectionException */ - public function testCanGetWooCommerceDataObjectMetaValueWithoutUsingOrderUtil() : void + public function testCanGetWordPressPostMetaValueUsingOrderUtil() : void { - $object = Mockery::mock('WC_Data'); + $object = Mockery::mock('WP_Post'); - $object->expects('get_meta') + $this->mockStaticMethod(SV_WC_Helper::class, 'getPostOrObjectMetaCompat') ->once() - ->with($field = 'TEST_FIELD', true) - ->andReturn($value = 'WC_DATA_META_VALUE'); + ->with($object, null, $field = 'TEST_FIELD', true) + ->andReturn($value = 'WP_POST_META_VALUE'); $this->assertSame($value, SV_WC_Helper::getWooCommerceObjectMetaValue($object, $field)); } /** - * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_1\SV_WC_Helper::getWooCommerceObjectMetaValue() + * @dataProvider providerCanGetPostOrObjectMetaCompat() + * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_1\SV_WC_Helper::getPostOrObjectMetaCompat() * - * @runInSeparateProcess - * @preserveGlobalState + * @param bool $hasData + * @param bool $hasPostId + * @param mixed $expected * * @throws ReflectionException */ - public function testCanGetWordPressPostMetaValueUsingOrderUtil() : void + public function testCanGetPostOrObjectMetaCompat( + bool $hasData, + bool $hasPostId, + $expected + ) : void { - require_once PLUGIN_ROOT_DIR.'/tests/Mocks/OrderUtil.php'; + $key = 'test'; + $object = null; - $object = Mockery::mock('WP_Post'); + $post = Mockery::mock('WP_Post'); - WP_Mock::userFunction('get_post_meta')->never(); + if ($hasPostId) { + $post->ID = 123; + } - $this->mockStaticMethod(OrderUtil::class, 'get_post_or_object_meta') - ->once() - ->with($object, null, $field = 'TEST_FIELD', true) - ->andReturn($value = 'WP_POST_META_VALUE'); + if ($hasData) { + $object = Mockery::mock('WC_Data'); - $this->assertSame($value, SV_WC_Helper::getWooCommerceObjectMetaValue($object, $field)); - } - - /** - * @covers \SkyVerge\WooCommerce\PluginFramework\v5_15_1\SV_WC_Helper::getWooCommerceObjectMetaValue() - * - * @runInSeparateProcess - * @preserveGlobalState - */ - public function testCanGetWordPressPostMetaValueWithoutUsingOrderUtil() : void - { - $object = Mockery::mock('WP_Post'); - $object->ID = 123; + $object->expects('get_meta') + ->times((int) ($hasData)) + ->with($key, true) + ->andReturn('WC_DATA_META_VALUE'); + } WP_Mock::userFunction('get_post_meta') - ->once() - ->with($object->ID, $field = 'TEST_FIELD', true) - ->andReturn($value = 'WP_POST_META_VALUE'); + ->times((int) (! $hasData && $hasPostId)) + ->with(123, $key, true) + ->andReturn('WP_POST_META_VALUE'); - $this->assertSame($value, SV_WC_Helper::getWooCommerceObjectMetaValue($object, $field)); + $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 38ce5a9ae..c4dc20cec 100644 --- a/woocommerce/class-sv-wc-helper.php +++ b/woocommerce/class-sv-wc-helper.php @@ -24,7 +24,6 @@ namespace SkyVerge\WooCommerce\PluginFramework\v5_15_1; -use Automattic\WooCommerce\Utilities\OrderUtil; use SkyVerge\WooCommerce\PluginFramework\v5_15_1\Helpers\NumberHelper; use WC_Data; use WP_Post; @@ -1211,23 +1210,39 @@ public static function get_escaped_id_list( array $ids ) { */ public static function getWooCommerceObjectMetaValue($object, string $field, bool $single = true) { - $orderUtilExists = class_exists(OrderUtil::class); - if ($object instanceof WP_Post) { - return $orderUtilExists ? - OrderUtil::get_post_or_object_meta($object, null, $field, $single) : - get_post_meta($object->ID, $field, $single); + return static::getPostOrObjectMetaCompat($object, null, $field, $single); } if ($object instanceof WC_Data) { - return $orderUtilExists ? - OrderUtil::get_post_or_object_meta(null, $object, $field, $single) : - $object->get_meta($field, $single); + 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; + } + } + } From 287c7beffae252d05e97fe9a75ed6a0a4e67a4b9 Mon Sep 17 00:00:00 2001 From: Andrew Jaynes Date: Tue, 22 Oct 2024 00:55:51 -0600 Subject: [PATCH 5/5] Rename test methods to remove OrderUtil references. --- tests/unit/HelperTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/HelperTest.php b/tests/unit/HelperTest.php index a5aa08c3d..e7841cf37 100644 --- a/tests/unit/HelperTest.php +++ b/tests/unit/HelperTest.php @@ -61,7 +61,7 @@ public function testAlwaysDetermineNavigationFeaturedDisabled() : void * * @throws ReflectionException */ - public function testCanGetWooCommerceDataObjectMetaValueUsingOrderUtil() : void + public function testCanGetWooCommerceDataObjectMetaValue() : void { $object = Mockery::mock('WC_Data'); @@ -78,7 +78,7 @@ public function testCanGetWooCommerceDataObjectMetaValueUsingOrderUtil() : void * * @throws ReflectionException */ - public function testCanGetWordPressPostMetaValueUsingOrderUtil() : void + public function testCanGetWordPressPostMetaValue() : void { $object = Mockery::mock('WP_Post');