admin_id = $this->factory->user->create(['role' => 'administrator']); $this->subscriber_id = $this->factory->user->create(['role' => 'subscriber']); // Initialize the handler new MLF_Ajax_Handler(); } /** * Clean up after tests. */ public function tear_down() { // Clean up test fonts $fonts = get_posts([ 'post_type' => 'wp_font_family', 'posts_per_page' => -1, 'meta_key' => '_mlf_imported', 'meta_value' => '1', 'fields' => 'ids', ]); foreach ($fonts as $font_id) { wp_delete_post($font_id, true); } wp_set_current_user(0); delete_transient('mlf_imported_fonts_list'); parent::tear_down(); } /** * Test download without nonce. */ public function test_download_without_nonce() { wp_set_current_user($this->admin_id); $_POST['font_name'] = 'Open Sans'; $_POST['weights'] = [400]; $_POST['styles'] = ['normal']; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_download_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('Security', $response['data']['message']); throw $e; } } /** * Test download with invalid nonce. */ public function test_download_with_invalid_nonce() { wp_set_current_user($this->admin_id); $_POST['nonce'] = 'invalid_nonce'; $_POST['font_name'] = 'Open Sans'; $_POST['weights'] = [400]; $_POST['styles'] = ['normal']; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_download_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); throw $e; } } /** * Test download without proper capability. */ public function test_download_without_capability() { wp_set_current_user($this->subscriber_id); $_POST['nonce'] = wp_create_nonce('mlf_download_font'); $_POST['font_name'] = 'Open Sans'; $_POST['weights'] = [400]; $_POST['styles'] = ['normal']; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_download_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('Unauthorized', $response['data']['message']); throw $e; } } /** * Test download with empty font name. */ public function test_download_empty_font_name() { wp_set_current_user($this->admin_id); $_POST['nonce'] = wp_create_nonce('mlf_download_font'); $_POST['font_name'] = ''; $_POST['weights'] = [400]; $_POST['styles'] = ['normal']; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_download_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('required', $response['data']['message']); throw $e; } } /** * Test download with invalid font name (XSS attempt). */ public function test_download_invalid_font_name_xss() { wp_set_current_user($this->admin_id); $_POST['nonce'] = wp_create_nonce('mlf_download_font'); $_POST['font_name'] = ''; $_POST['weights'] = [400]; $_POST['styles'] = ['normal']; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_download_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('Invalid font name', $response['data']['message']); throw $e; } } /** * Test download with path traversal in font name. */ public function test_download_path_traversal() { wp_set_current_user($this->admin_id); $_POST['nonce'] = wp_create_nonce('mlf_download_font'); $_POST['font_name'] = '../../../etc/passwd'; $_POST['weights'] = [400]; $_POST['styles'] = ['normal']; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_download_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('Invalid font name', $response['data']['message']); throw $e; } } /** * Test download with font name too long. */ public function test_download_font_name_too_long() { wp_set_current_user($this->admin_id); $_POST['nonce'] = wp_create_nonce('mlf_download_font'); $_POST['font_name'] = str_repeat('a', 101); $_POST['weights'] = [400]; $_POST['styles'] = ['normal']; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_download_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('too long', $response['data']['message']); throw $e; } } /** * Test download with no weights. */ public function test_download_no_weights() { wp_set_current_user($this->admin_id); $_POST['nonce'] = wp_create_nonce('mlf_download_font'); $_POST['font_name'] = 'Open Sans'; $_POST['weights'] = []; $_POST['styles'] = ['normal']; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_download_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('weight', $response['data']['message']); throw $e; } } /** * Test download with invalid weights. */ public function test_download_invalid_weights() { wp_set_current_user($this->admin_id); $_POST['nonce'] = wp_create_nonce('mlf_download_font'); $_POST['font_name'] = 'Open Sans'; $_POST['weights'] = [999, 1000]; // Invalid weights $_POST['styles'] = ['normal']; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_download_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('weight', $response['data']['message']); throw $e; } } /** * Test download with no styles. */ public function test_download_no_styles() { wp_set_current_user($this->admin_id); $_POST['nonce'] = wp_create_nonce('mlf_download_font'); $_POST['font_name'] = 'Open Sans'; $_POST['weights'] = [400]; $_POST['styles'] = []; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_download_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('style', $response['data']['message']); throw $e; } } /** * Test delete without nonce. */ public function test_delete_without_nonce() { wp_set_current_user($this->admin_id); $font_id = $this->create_test_font(); $_POST['font_id'] = $font_id; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_delete_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); throw $e; } } /** * Test delete without capability. */ public function test_delete_without_capability() { wp_set_current_user($this->subscriber_id); $font_id = $this->create_test_font(); $_POST['nonce'] = wp_create_nonce('mlf_delete_font'); $_POST['font_id'] = $font_id; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_delete_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('Unauthorized', $response['data']['message']); throw $e; } } /** * Test delete with invalid font ID. */ public function test_delete_invalid_font_id() { wp_set_current_user($this->admin_id); $_POST['nonce'] = wp_create_nonce('mlf_delete_font'); $_POST['font_id'] = 0; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_delete_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('Invalid', $response['data']['message']); throw $e; } } /** * Test delete font not found. */ public function test_delete_font_not_found() { wp_set_current_user($this->admin_id); $_POST['nonce'] = wp_create_nonce('mlf_delete_font'); $_POST['font_id'] = 99999; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_delete_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('not found', $response['data']['message']); throw $e; } } /** * Test delete font not imported by plugin. */ public function test_delete_font_not_ours() { wp_set_current_user($this->admin_id); // Create font without our meta $font_id = wp_insert_post([ 'post_type' => 'wp_font_family', 'post_title' => 'Theme Font', 'post_status' => 'publish', ]); $_POST['nonce'] = wp_create_nonce('mlf_delete_font'); $_POST['font_id'] = $font_id; $this->expectException('WPAjaxDieStopException'); try { $this->_handleAjax('mlf_delete_font'); } catch (WPAjaxDieStopException $e) { $response = json_decode($this->_last_response, true); $this->assertFalse($response['success']); $this->assertStringContainsString('not imported', $response['data']['message']); throw $e; } // Clean up wp_delete_post($font_id, true); } /** * Helper to create a test font. * * @return int Font ID. */ private function create_test_font() { $font_id = wp_insert_post([ 'post_type' => 'wp_font_family', 'post_title' => 'Test Font', 'post_name' => 'test-font', 'post_status' => 'publish', ]); update_post_meta($font_id, '_mlf_imported', '1'); return $font_id; } }