Files
peptide-search-ai/tests/bootstrap.php
peptiderepo d69f637b06 refactor: extract upgrade logic to PSA_Upgrade class (fixes CI)
CI on 61cf00c failed PHPUnit with "Call to undefined function
plugin_dir_path()" — the test required peptide-search-ai.php, which calls
plugin_dir_path() at top level (line 19) before any hook. Stubbing every
top-level WP function the plugin file touches was the wrong shape of fix.

Proper fix: move the upgrade logic into includes/class-psa-upgrade.php so
the test can require just the helper class, matching the pattern every
other includes/ module follows.

- New: includes/class-psa-upgrade.php with PSA_Upgrade::is_needed()
  (pure) and PSA_Upgrade::maybe_run() (driver). OPTION_NAME and
  DEFAULT_STORED_VERSION exposed as constants.
- peptide-search-ai.php: psa_admin_init() now calls PSA_Upgrade::maybe_run();
  the inline helper functions and docblocks are removed.
- tests/bootstrap.php: loads class-psa-upgrade.php alongside the other
  tested classes.
- tests/unit/UpgradeTest.php: rewritten against PSA_Upgrade; adds two
  extra assertions on the constants for stability.
- ARCHITECTURE.md: refreshed to reference the class and its constants.

No behavioral change. The cost-tracker schema upgrade still runs once per
admin_init when PSA_VERSION advances past psa_db_version.

Agent-Session: cowork-qa-p1-fixes-20260414
2026-04-14 19:54:23 +07:00

134 lines
3.3 KiB
PHP
Executable File

<?php
/**
* PHPUnit bootstrap file for Peptide Search AI tests.
*
* Initializes the test environment with minimal WordPress stubs.
*
* @package PeptideSearchAI
*/
// Define WordPress constants.
define( 'ABSPATH', __DIR__ . '/../' );
define( 'PSA_PLUGIN_DIR', ABSPATH );
define( 'PSA_PLUGIN_FILE', ABSPATH . 'peptide-search-ai.php' );
define( 'PSA_VERSION', '1.0.0' );
// Stub WordPress functions.
if ( ! function_exists( 'sanitize_text_field' ) ) {
function sanitize_text_field( $str ) {
return $str;
}
}
if ( ! function_exists( 'wp_json_encode' ) ) {
function wp_json_encode( $data, $options = 0, $depth = 512 ) {
return json_encode( $data, $options, $depth );
}
}
if ( ! function_exists( 'get_option' ) ) {
function get_option( $option, $default = false ) {
return array();
}
}
if ( ! function_exists( 'get_transient' ) ) {
function get_transient( $transient ) {
return false;
}
}
if ( ! function_exists( 'set_transient' ) ) {
function set_transient( $transient, $value, $expiration = 0 ) {
return true;
}
}
if ( ! function_exists( 'wp_unslash' ) ) {
function wp_unslash( $value ) {
return $value;
}
}
if ( ! function_exists( 'apply_filters' ) ) {
function apply_filters( $hook, $value ) {
// Return the first non-hook argument (typically the second arg onwards)
$args = func_get_args();
return isset( $args[1] ) ? $args[1] : $value;
}
}
if ( ! function_exists( 'is_wp_error' ) ) {
function is_wp_error( $thing ) {
return class_exists( 'WP_Error' ) && $thing instanceof WP_Error;
}
}
if ( ! function_exists( 'wp_kses_post' ) ) {
function wp_kses_post( $data ) {
return $data;
}
}
if ( ! function_exists( 'wp_parse_args' ) ) {
function wp_parse_args( $args, $defaults = array() ) {
if ( is_array( $args ) ) {
return array_merge( $defaults, $args );
}
return $defaults;
}
}
if ( ! function_exists( 'esc_html' ) ) {
function esc_html( $text ) {
return htmlspecialchars( $text, ENT_QUOTES, 'UTF-8' );
}
}
// Define WP_Error class if it doesn't exist.
if ( ! class_exists( 'WP_Error' ) ) {
class WP_Error {
public $errors = array();
public $error_data = array();
public function __construct( $code = '', $message = '', $data = '' ) {
if ( ! empty( $code ) ) {
$this->add( $code, $message, $data );
}
}
public function add( $code, $message = '', $data = '' ) {
if ( empty( $code ) ) {
return;
}
if ( ! isset( $this->errors[ $code ] ) ) {
$this->errors[ $code ] = array();
}
$this->errors[ $code ][] = $message;
if ( ! empty( $data ) ) {
$this->error_data[ $code ] = $data;
}
}
public function get_error_code() {
$codes = array_keys( $this->errors );
return ! empty( $codes ) ? $codes[0] : '';
}
public function get_error_message( $code = '' ) {
if ( empty( $code ) ) {
$code = $this->get_error_code();
}
return isset( $this->errors[ $code ][0] ) ? $this->errors[ $code ][0] : '';
}
}
}
// Require the class files under test.
require_once ABSPATH . 'includes/class-psa-config.php';
require_once ABSPATH . 'includes/class-psa-cost-tracker.php';
require_once ABSPATH . 'includes/class-psa-openrouter.php';
require_once ABSPATH . 'includes/class-psa-kb-builder.php';
require_once ABSPATH . 'includes/class-psa-ai-generator.php';
require_once ABSPATH . 'includes/class-psa-upgrade.php';