array( 'code' => 200 ), 'body' => '{}' ); $GLOBALS['privacy_posts'] = array(); class WP_User { public $ID; public function __construct( $id ) { $this->ID = $id; } } class WP_Error { private $message; public function __construct( $code, $message = '', $data = array() ) { $this->message = $message; } public function get_error_message() { return $this->message; } } function add_filter( $hook, $callback ) { $GLOBALS['privacy_filters'][ $hook ] = $callback; } function __( $text ) { return $text; } function get_option( $name, $default = false ) { return $GLOBALS['privacy_options'][ $name ] ?? $default; } function apply_filters( $hook, $value ) { return $value; } function untrailingslashit( $url ) { return rtrim( $url, '/' ); } function esc_url_raw( $url ) { return $url; } function is_email( $email ) { return false !== filter_var( $email, FILTER_VALIDATE_EMAIL ); } function get_user_by( $field, $email ) { return $GLOBALS['privacy_user']; } function wc_get_orders( $args ) { return $GLOBALS['privacy_orders']; } function wp_remote_post( $url, $args ) { $GLOBALS['privacy_posts'][] = array( $url, $args ); return $GLOBALS['privacy_response']; } function is_wp_error( $value ) { return $value instanceof WP_Error; } function wp_remote_retrieve_response_code( $response ) { return $response['response']['code'] ?? 0; } function wp_remote_retrieve_body( $response ) { return $response['body'] ?? ''; } function wp_json_encode( $value ) { return json_encode( $value ); } require_once __DIR__ . '/../includes/class-plugin.php'; require_once __DIR__ . '/../includes/class-privacy.php'; use Aisthetix\TryOn\Plugin; use Aisthetix\TryOn\Privacy; $passed = 0; $failed = 0; function privacy_check( $name, $condition ) { global $passed, $failed; if ( $condition ) { echo " ✓ {$name}\n"; ++$passed; return; } echo " ✗ {$name}\n"; ++$failed; } function privacy_connect( $connected = true ) { $GLOBALS['privacy_options'][ Plugin::OPTION_PUBLISHABLE_KEY ] = $connected ? 'pk_test' : ''; $GLOBALS['privacy_options'][ Plugin::OPTION_SECRET_KEY ] = $connected ? 'sk_test' : ''; } function privacy_result( $body, $code = 200 ) { $GLOBALS['privacy_response'] = array( 'response' => array( 'code' => $code ), 'body' => is_string( $body ) ? $body : json_encode( $body ) ); } echo "Privacy\n"; $privacy = new Privacy(); $privacy->init(); privacy_check( 'registers both core privacy filters', 2 === count( $GLOBALS['privacy_filters'] ) ); $exporters = $privacy->register_exporter( array( 'existing' => array() ) ); $erasers = $privacy->register_eraser( array() ); privacy_check( 'registers named callable exporter and eraser', is_callable( $exporters['aisthetix-tryon']['callback'] ) && is_callable( $erasers['aisthetix-tryon']['callback'] ) ); privacy_connect( false ); privacy_check( 'disconnected export is a clean empty page', array( 'data' => array(), 'done' => true ) === $privacy->export( 'shopper@example.com' ) ); $erased = $privacy->erase( 'shopper@example.com' ); privacy_check( 'disconnected erase is a clean no-op', false === $erased['items_removed'] && false === $erased['items_retained'] ); privacy_connect(); $GLOBALS['privacy_user'] = null; $GLOBALS['privacy_orders'] = array(); privacy_check( 'invalid or unknown subjects never call the brain', array() === $privacy->export( 'invalid' )['data'] && array() === $privacy->export( 'nobody@example.com' )['data'] ); $GLOBALS['privacy_user'] = new WP_User( 42 ); $GLOBALS['privacy_orders'] = array( 7, '7', 8, 0, -3 ); privacy_result( array( 'events' => array( array( 'eventName' => 'checkout_completed', 'productId' => '', 'orderId' => '7', 'value' => 59.9, 'currency' => 'EUR', 'productIds' => array( '10', 11 ), ), 'bad-event', ), ) ); $export = $privacy->export( ' shopper@example.com ' ); privacy_check( 'exports one shaped item and skips malformed events', 1 === count( $export['data'] ) && 'aisthetix-event-0' === $export['data'][0]['item_id'] ); $rows = $export['data'][0]['data']; privacy_check( 'flattens scalar and product-id fields but omits empty values', false !== strpos( json_encode( $rows ), 'checkout_completed' ) && false !== strpos( json_encode( $rows ), '10, 11' ) && false === strpos( json_encode( $rows ), 'Product ID\"' ) ); privacy_check( 'sends deduplicated subject keys with the server secret', false !== strpos( $GLOBALS['privacy_posts'][0][1]['body'], '"orderIds":["7","8"]' ) && 'sk_test' === $GLOBALS['privacy_posts'][0][1]['headers']['X-Aisthetix-Secret'] ); $GLOBALS['privacy_response'] = new WP_Error( 'offline', 'offline' ); privacy_check( 'export transport failures soft-fail empty', array() === $privacy->export( 'shopper@example.com' )['data'] ); $retained = $privacy->erase( 'shopper@example.com' ); privacy_check( 'erase transport failures retain data with retry guidance', true === $retained['items_retained'] && 1 === count( $retained['messages'] ) ); privacy_result( array( 'skipped' => true ) ); $skipped = $privacy->erase( 'shopper@example.com' ); privacy_check( 'unmatched erase explains the no-op without claiming retention', false === $skipped['items_removed'] && false === $skipped['items_retained'] && 1 === count( $skipped['messages'] ) ); privacy_result( array( 'deleted' => 3 ) ); privacy_check( 'positive brain deletion is reported to WordPress', true === $privacy->erase( 'shopper@example.com' )['items_removed'] ); privacy_result( array( 'deleted' => 0 ) ); privacy_check( 'zero deletion does not claim data removal', false === $privacy->erase( 'shopper@example.com' )['items_removed'] ); privacy_result( 'not-json', 200 ); privacy_check( 'invalid JSON is a retained soft failure', true === $privacy->erase( 'shopper@example.com' )['items_retained'] ); privacy_result( array( 'deleted' => 1 ), 503 ); privacy_check( 'non-200 responses are retained soft failures', true === $privacy->erase( 'shopper@example.com' )['items_retained'] ); $GLOBALS['privacy_orders'] = 'not-an-array'; $GLOBALS['privacy_user'] = new WP_User( 9 ); privacy_result( array( 'events' => array() ) ); privacy_check( 'registered users remain resolvable when Woo returns malformed orders', array() === $privacy->export( 'member@example.com' )['data'] ); echo "\n{$passed} passed, {$failed} failed\n"; exit( $failed > 0 ? 1 : 0 );