From 19fea30932176b649b7b167f5603a4cc1ac0d2b5 Mon Sep 17 00:00:00 2001 From: peptiderepo <273788462+peptiderepo@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:01:34 +0700 Subject: [PATCH] fix(admin): load delegate classes + add WP test stubs (#8) * fix(admin): load delegate classes from orchestrator + add WP stubs for tests The admin refactor split introduced delegate classes that the orchestrator instantiates in its constructor. CI failed because tests require the orchestrator directly without going through the plugin loader. Fix: add require_once for all delegate files at the top of the orchestrator, and add missing WP function stubs to the test bootstrap. Co-Authored-By: Claude Opus 4.6 * fix(admin): add missing sanitize_model_id and sanitize_api_key delegators The refactored orchestrator was missing public method delegations for sanitize_model_id() and sanitize_api_key(), which tests call directly on the Peptide_News_Admin instance and WordPress uses as register_setting callbacks. Co-Authored-By: Claude Opus 4.6 * fix(phpcs): remove strict_types declaration that breaks file header order PSR12.Files.FileHeader.IncorrectOrder requires the docblock immediately after the opening PHP tag. The declare(strict_types=1) was inserted between them. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: peptiderepo Co-authored-by: Claude Opus 4.6 --- admin/class-peptide-news-admin.php | 38 ++++++++++++++++++++++- tests/bootstrap.php | 49 ++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/admin/class-peptide-news-admin.php b/admin/class-peptide-news-admin.php index 20ad3e0..4fc7083 100755 --- a/admin/class-peptide-news-admin.php +++ b/admin/class-peptide-news-admin.php @@ -1,5 +1,4 @@ dashboard_pages->render_cost_dashboard_page(); } + + /** + * Sanitize and validate an OpenRouter model ID. + * + * Delegates to the settings class. Kept on the orchestrator because + * WordPress register_setting() callbacks may reference $this. + * + * @param string $value Raw model ID from form input. + * @return string Sanitized model ID or empty string on failure. + */ + public function sanitize_model_id( string $value ): string { + return $this->settings->sanitize_model_id( $value ); + } + + /** + * Sanitize an API key value — encrypt if new, preserve if masked. + * + * Delegates to the settings class. Kept on the orchestrator because + * WordPress register_setting() callbacks may reference $this. + * + * @param string $value Raw API key from form input. + * @param string $option_name The WP option being saved. + * @return string Encrypted key or previous value if input was masked. + */ + public function sanitize_api_key( string $value, string $option_name = '' ): string { + return $this->settings->sanitize_api_key( $value, $option_name ); + } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 17bcda3..aab0338 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -300,6 +300,55 @@ if ( ! function_exists( 'selected' ) ) { return $result; } } +if ( ! function_exists( 'checked' ) ) { + function checked( $checked, $current = true, $echo = true ) { + $result = (string) $checked === (string) $current ? ' checked="checked"' : ''; + if ( $echo ) { + echo $result; + } + return $result; + } +} +if ( ! function_exists( 'wp_enqueue_style' ) ) { + function wp_enqueue_style( $handle, $src = '', $deps = array(), $ver = false, $media = 'all' ) { + return true; + } +} +if ( ! function_exists( 'wp_enqueue_script' ) ) { + function wp_enqueue_script( $handle, $src = '', $deps = array(), $ver = false, $args = array() ) { + return true; + } +} +if ( ! function_exists( 'wp_localize_script' ) ) { + function wp_localize_script( $handle, $object_name, $l10n ) { + return true; + } +} +if ( ! function_exists( 'add_menu_page' ) ) { + function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $callback = '', $icon_url = '', $position = null ) { + return $menu_slug; + } +} +if ( ! function_exists( 'add_submenu_page' ) ) { + function add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $callback = '', $position = null ) { + return $menu_slug; + } +} +if ( ! function_exists( 'register_setting' ) ) { + function register_setting( $option_group, $option_name, $args = array() ) { + return true; + } +} +if ( ! function_exists( 'add_settings_section' ) ) { + function add_settings_section( $id, $title, $callback, $page, $args = array() ) { + return true; + } +} +if ( ! function_exists( 'add_settings_field' ) ) { + function add_settings_field( $id, $title, $callback, $page, $section = 'default', $args = array() ) { + return true; + } +} // Cost tracker provides calculate_cost(), budget checks used by tests. require_once PEPTIDE_NEWS_PLUGIN_DIR . 'includes/class-peptide-news-cost-tracker.php';