validate_add_to_cart()')); self::assertNotFalse(has_filter('woocommerce_add_cart_item_data', 'Magdev\WcComposableProduct\CartHandler->add_cart_item_data()')); self::assertNotFalse(has_filter('woocommerce_get_cart_item_from_session', 'Magdev\WcComposableProduct\CartHandler->get_cart_item_from_session()')); self::assertNotFalse(has_filter('woocommerce_get_item_data', 'Magdev\WcComposableProduct\CartHandler->display_cart_item_data()')); self::assertNotFalse(has_action('woocommerce_before_calculate_totals', 'Magdev\WcComposableProduct\CartHandler->calculate_cart_item_price()')); self::assertNotFalse(has_action('woocommerce_single_product_summary', 'Magdev\WcComposableProduct\CartHandler->render_product_selector()')); self::assertNotFalse(has_filter('woocommerce_is_purchasable', 'Magdev\WcComposableProduct\CartHandler->hide_default_add_to_cart()')); } public function testHideDefaultAddToCart_ReturnsFalseForComposable(): void { $handler = new CartHandler(); $product = $this->createProductMock(['get_type' => 'composable']); $result = $handler->hide_default_add_to_cart(true, $product); $this->assertFalse($result); } public function testHideDefaultAddToCart_PassesThroughForSimple(): void { $handler = new CartHandler(); $product = $this->createProductMock(['get_type' => 'simple']); $result = $handler->hide_default_add_to_cart(true, $product); $this->assertTrue($result); } public function testValidateAddToCart_PassesThroughForNonComposable(): void { $product = $this->createProductMock(['get_type' => 'simple']); Functions\expect('wc_get_product')->with(1)->andReturn($product); $handler = new CartHandler(); $result = $handler->validate_add_to_cart(true, 1, 1); $this->assertTrue($result); } public function testValidateAddToCart_ReturnsFalseWhenNoProductsSelected(): void { $product = $this->createProductMock(['get_type' => 'composable']); Functions\expect('wc_get_product')->with(1)->andReturn($product); Functions\expect('wc_add_notice')->once(); $_POST['composable_products'] = []; $handler = new CartHandler(); $result = $handler->validate_add_to_cart(true, 1, 1); $this->assertFalse($result); } public function testValidateAddToCart_ReturnsFalseWhenNoPostData(): void { $product = $this->createProductMock(['get_type' => 'composable']); Functions\expect('wc_get_product')->with(1)->andReturn($product); Functions\expect('wc_add_notice')->once(); // No $_POST['composable_products'] at all $handler = new CartHandler(); $result = $handler->validate_add_to_cart(true, 1, 1); $this->assertFalse($result); } public function testAddCartItemData_AddsSelectionsForComposable(): void { $product = $this->createProductMock(['get_type' => 'composable']); Functions\expect('wc_get_product')->with(1)->andReturn($product); Functions\expect('absint')->andReturnUsing(function ($val) { return abs((int) $val); }); $_POST['composable_products'] = ['101', '102']; $handler = new CartHandler(); $result = $handler->add_cart_item_data([], 1); $this->assertArrayHasKey('composable_products', $result); $this->assertSame([101, 102], $result['composable_products']); $this->assertArrayHasKey('unique_key', $result); } public function testAddCartItemData_PassesThroughForNonComposable(): void { $product = $this->createProductMock(['get_type' => 'simple']); Functions\expect('wc_get_product')->with(1)->andReturn($product); $handler = new CartHandler(); $result = $handler->add_cart_item_data(['existing' => 'data'], 1); $this->assertSame(['existing' => 'data'], $result); } public function testGetCartItemFromSession_RestoresComposableProducts(): void { $handler = new CartHandler(); $result = $handler->get_cart_item_from_session( ['data' => 'test'], ['composable_products' => [101, 102]] ); $this->assertSame([101, 102], $result['composable_products']); } public function testGetCartItemFromSession_PassesThroughWithoutComposableData(): void { $handler = new CartHandler(); $result = $handler->get_cart_item_from_session( ['data' => 'test'], [] ); $this->assertArrayNotHasKey('composable_products', $result); } public function testDisplayCartItemData_FormatsProductNames(): void { $mock1 = $this->createProductMock(['get_name' => 'Product A']); $mock2 = $this->createProductMock(['get_name' => 'Product B']); Functions\expect('wc_get_product') ->andReturnUsing(function ($id) use ($mock1, $mock2) { return match ($id) { 101 => $mock1, 102 => $mock2, default => false, }; }); $handler = new CartHandler(); $result = $handler->display_cart_item_data( [], ['composable_products' => [101, 102]] ); $this->assertCount(1, $result); $this->assertStringContainsString('Product A', $result[0]['value']); $this->assertStringContainsString('Product B', $result[0]['value']); } public function testDisplayCartItemData_ReturnsEmptyForNonComposable(): void { $handler = new CartHandler(); $result = $handler->display_cart_item_data([], []); $this->assertSame([], $result); } }