manager = new StockManager(); } // --- validate_stock_availability --- public function testValidateStock_ReturnsTrueWhenAllInStock(): void { $mock = $this->createProductMock([ 'managing_stock' => false, 'is_in_stock' => true, ]); Functions\expect('wc_get_product')->with(1)->andReturn($mock); Functions\expect('wc_get_product')->with(2)->andReturn($mock); $result = $this->manager->validate_stock_availability([1, 2]); $this->assertTrue($result); } public function testValidateStock_ReturnsTrueWhenNotManagingStock(): void { $mock = $this->createProductMock(['managing_stock' => false]); Functions\expect('wc_get_product')->with(1)->andReturn($mock); $result = $this->manager->validate_stock_availability([1]); $this->assertTrue($result); } public function testValidateStock_ReturnsErrorForOutOfStock(): void { $mock = $this->createProductMock([ 'managing_stock' => true, 'is_in_stock' => false, 'get_name' => 'Widget', ]); Functions\expect('wc_get_product')->with(1)->andReturn($mock); $result = $this->manager->validate_stock_availability([1]); $this->assertIsString($result); $this->assertStringContainsString('Widget', $result); } public function testValidateStock_ReturnsErrorForInsufficientQuantity(): void { $mock = $this->createProductMock([ 'managing_stock' => true, 'is_in_stock' => true, 'get_stock_quantity' => 1, 'get_name' => 'Widget', 'backorders_allowed' => false, ]); Functions\expect('wc_get_product')->with(1)->andReturn($mock); $result = $this->manager->validate_stock_availability([1], 5); $this->assertIsString($result); $this->assertStringContainsString('Widget', $result); } public function testValidateStock_PassesWhenBackordersAllowed(): void { // When stock_quantity is null the insufficient-stock check is skipped, // and the backorders_allowed() branch is reached. $mock = $this->createProductMock([ 'managing_stock' => true, 'is_in_stock' => true, 'get_stock_quantity' => null, 'backorders_allowed' => true, ]); Functions\expect('wc_get_product')->with(1)->andReturn($mock); $result = $this->manager->validate_stock_availability([1], 5); $this->assertTrue($result); } public function testValidateStock_SkipsNullProducts(): void { Functions\expect('wc_get_product')->with(999)->andReturn(false); $result = $this->manager->validate_stock_availability([999]); $this->assertTrue($result); } // --- get_product_stock_info --- public function testGetProductStockInfo_ReturnsCorrectStructure(): void { $mock = $this->createProductMock([ 'is_in_stock' => true, 'get_stock_quantity' => 10, 'backorders_allowed' => false, 'get_stock_status' => 'instock', 'managing_stock' => true, ]); Functions\expect('wc_get_product')->with(1)->andReturn($mock); $info = $this->manager->get_product_stock_info(1); $this->assertTrue($info['in_stock']); $this->assertSame(10, $info['stock_quantity']); $this->assertFalse($info['backorders_allowed']); $this->assertSame('instock', $info['stock_status']); $this->assertTrue($info['managing_stock']); $this->assertTrue($info['has_enough_stock']); } public function testGetProductStockInfo_ReturnsFallbackForInvalidProduct(): void { Functions\expect('wc_get_product')->with(999)->andReturn(false); $info = $this->manager->get_product_stock_info(999); $this->assertFalse($info['in_stock']); $this->assertSame(0, $info['stock_quantity']); $this->assertFalse($info['backorders_allowed']); $this->assertSame('outofstock', $info['stock_status']); } public function testGetProductStockInfo_HasEnoughStockTrueWhenNotManaging(): void { $mock = $this->createProductMock([ 'managing_stock' => false, 'get_stock_quantity' => null, ]); Functions\expect('wc_get_product')->with(1)->andReturn($mock); $info = $this->manager->get_product_stock_info(1, 100); $this->assertTrue($info['has_enough_stock']); } public function testGetProductStockInfo_HasEnoughStockFalseWhenInsufficient(): void { $mock = $this->createProductMock([ 'managing_stock' => true, 'get_stock_quantity' => 2, ]); Functions\expect('wc_get_product')->with(1)->andReturn($mock); $info = $this->manager->get_product_stock_info(1, 5); $this->assertFalse($info['has_enough_stock']); } // --- prevent_composable_stock_reduction --- public function testPreventStockReduction_ReturnsFalseForComposableItem(): void { $productMock = $this->createProductMock(['get_type' => 'composable']); $itemMock = \Mockery::mock('WC_Order_Item_Product'); $itemMock->shouldReceive('get_product')->andReturn($productMock); $orderMock = \Mockery::mock('WC_Order'); $orderMock->shouldReceive('get_items')->andReturn([$itemMock]); $result = $this->manager->prevent_composable_stock_reduction(true, $orderMock); $this->assertFalse($result); } public function testPreventStockReduction_PassesThroughForNonComposable(): void { $productMock = $this->createProductMock(['get_type' => 'simple']); $itemMock = \Mockery::mock('WC_Order_Item_Product'); $itemMock->shouldReceive('get_product')->andReturn($productMock); $orderMock = \Mockery::mock('WC_Order'); $orderMock->shouldReceive('get_items')->andReturn([$itemMock]); $result = $this->manager->prevent_composable_stock_reduction(true, $orderMock); $this->assertTrue($result); } // --- store_selected_products_in_order --- public function testStoreSelectedProducts_AddsMetaWhenPresent(): void { $itemMock = \Mockery::mock('WC_Order_Item_Product'); $itemMock->shouldReceive('add_meta_data') ->once() ->with('_composable_products', [1, 2], true); $this->manager->store_selected_products_in_order( $itemMock, 'cart_key', ['composable_products' => [1, 2]] ); } public function testStoreSelectedProducts_DoesNothingWithoutData(): void { $itemMock = \Mockery::mock('WC_Order_Item_Product'); $itemMock->shouldNotReceive('add_meta_data'); $this->manager->store_selected_products_in_order( $itemMock, 'cart_key', [] ); } }