PR Vision v0.1.1: rename from peptide-geo-monitor + P2 fixes
- Exhaustive rename: PGM_ -> PRV_, pgm_ -> prv_, text domain and slug peptide-geo-monitor -> pr-vision, admin menu GEO Monitor -> PR Vision, main file peptide-geo-monitor.php -> pr-vision.php, DB table pgm_ai_visibility -> prv_ai_visibility. - P2-A: replace ltrim($host,'www.') character-mask with str_starts_with/substr prefix strip in PRV_Citation_Detector. Adds test coverage for wikipedia.org, webmd.com survival. - P2-B: drop continue-on-error: true from PHPCS CI step; WordPress Coding Standards now gates the build. - P2-C: remove dead in-run cache from PRV_Probe_Runner::run(); each (peptide, intent, model) triplet is visited once per run, cache hit is structurally impossible. - Version bump 0.1.0 -> 0.1.1 + CHANGELOG [0.1.1] entry. Agent-Session: pr-vision rename v0.1.1
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Pattern mirrors peptide-repo-core's bootstrap (flat PHP, no PHPUnit).
|
||||
*
|
||||
* @package PeptideGeoMonitor
|
||||
* @package PrVision
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
@@ -16,21 +16,21 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
define( 'ABSPATH', __DIR__ . '/' );
|
||||
}
|
||||
|
||||
define( 'PGM_VERSION', '0.1.0' );
|
||||
define( 'PGM_PLUGIN_FILE', __DIR__ . '/../peptide-geo-monitor.php' );
|
||||
define( 'PGM_PLUGIN_DIR', realpath( __DIR__ . '/..' ) . '/' );
|
||||
define( 'PGM_PLUGIN_URL', 'http://example.test/wp-content/plugins/peptide-geo-monitor/' );
|
||||
define( 'PGM_SCHEMA_VERSION', 1 );
|
||||
define( 'PGM_MAX_RETRIES', 3 );
|
||||
define( 'PGM_API_TIMEOUT_SECONDS', 60 );
|
||||
define( 'PGM_RETRY_BASE_DELAY_SECONDS', 2 );
|
||||
define( 'PGM_DEFAULT_MONTHLY_BUDGET_USD', 5.0 );
|
||||
define( 'PGM_CRON_HOOK', 'pgm_weekly_probe' );
|
||||
define( 'PGM_TARGET_DOMAIN', 'peptiderepo.com' );
|
||||
define( 'PRV_VERSION', '0.1.1' );
|
||||
define( 'PRV_PLUGIN_FILE', __DIR__ . '/../pr-vision.php' );
|
||||
define( 'PRV_PLUGIN_DIR', realpath( __DIR__ . '/..' ) . '/' );
|
||||
define( 'PRV_PLUGIN_URL', 'http://example.test/wp-content/plugins/pr-vision/' );
|
||||
define( 'PRV_SCHEMA_VERSION', 1 );
|
||||
define( 'PRV_MAX_RETRIES', 3 );
|
||||
define( 'PRV_API_TIMEOUT_SECONDS', 60 );
|
||||
define( 'PRV_RETRY_BASE_DELAY_SECONDS', 2 );
|
||||
define( 'PRV_DEFAULT_MONTHLY_BUDGET_USD', 5.0 );
|
||||
define( 'PRV_CRON_HOOK', 'prv_weekly_probe' );
|
||||
define( 'PRV_TARGET_DOMAIN', 'peptiderepo.com' );
|
||||
|
||||
/* ── Global test state ─────────────────────────────────────────────────── */
|
||||
|
||||
$GLOBALS['pgm_test_state'] = [
|
||||
$GLOBALS['prv_test_state'] = [
|
||||
'options' => [],
|
||||
'actions' => [],
|
||||
'wpdb_insert_id' => 1,
|
||||
@@ -40,8 +40,8 @@ $GLOBALS['pgm_test_state'] = [
|
||||
'remote_posts' => [],
|
||||
];
|
||||
|
||||
function pgm_test_reset(): void {
|
||||
$GLOBALS['pgm_test_state'] = [
|
||||
function prv_test_reset(): void {
|
||||
$GLOBALS['prv_test_state'] = [
|
||||
'options' => [],
|
||||
'actions' => [],
|
||||
'wpdb_insert_id' => 1,
|
||||
@@ -50,29 +50,29 @@ function pgm_test_reset(): void {
|
||||
'cron_events' => [],
|
||||
'remote_posts' => [],
|
||||
];
|
||||
PGM_Collector_Registry::reset_for_testing();
|
||||
PRV_Collector_Registry::reset_for_testing();
|
||||
}
|
||||
|
||||
/* ── WordPress function stubs ──────────────────────────────────────────── */
|
||||
|
||||
function get_option( string $name, $default = false ) {
|
||||
return $GLOBALS['pgm_test_state']['options'][ $name ] ?? $default;
|
||||
return $GLOBALS['prv_test_state']['options'][ $name ] ?? $default;
|
||||
}
|
||||
|
||||
function update_option( string $name, $value ): bool {
|
||||
$GLOBALS['pgm_test_state']['options'][ $name ] = $value;
|
||||
$GLOBALS['prv_test_state']['options'][ $name ] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
function add_option( string $name, $value = '' ): bool {
|
||||
if ( ! isset( $GLOBALS['pgm_test_state']['options'][ $name ] ) ) {
|
||||
$GLOBALS['pgm_test_state']['options'][ $name ] = $value;
|
||||
if ( ! isset( $GLOBALS['prv_test_state']['options'][ $name ] ) ) {
|
||||
$GLOBALS['prv_test_state']['options'][ $name ] = $value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function add_action( string $hook, $callback, int $priority = 10, int $accepted_args = 1 ): bool {
|
||||
$GLOBALS['pgm_test_state']['actions'][] = compact( 'hook', 'callback', 'priority' );
|
||||
$GLOBALS['prv_test_state']['actions'][] = compact( 'hook', 'callback', 'priority' );
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -83,19 +83,19 @@ function remove_action( string $hook, $callback, int $priority = 10 ): bool {
|
||||
function add_menu_page( ...$args ): void {}
|
||||
|
||||
function wp_schedule_event( int $timestamp, string $recurrence, string $hook ): void {
|
||||
$GLOBALS['pgm_test_state']['cron_events'][ $hook ] = $timestamp;
|
||||
$GLOBALS['prv_test_state']['cron_events'][ $hook ] = $timestamp;
|
||||
}
|
||||
|
||||
function wp_next_scheduled( string $hook ) {
|
||||
return $GLOBALS['pgm_test_state']['cron_events'][ $hook ] ?? false;
|
||||
return $GLOBALS['prv_test_state']['cron_events'][ $hook ] ?? false;
|
||||
}
|
||||
|
||||
function wp_unschedule_event( int $timestamp, string $hook ): void {
|
||||
unset( $GLOBALS['pgm_test_state']['cron_events'][ $hook ] );
|
||||
unset( $GLOBALS['prv_test_state']['cron_events'][ $hook ] );
|
||||
}
|
||||
|
||||
function wp_clear_scheduled_hook( string $hook ): void {
|
||||
unset( $GLOBALS['pgm_test_state']['cron_events'][ $hook ] );
|
||||
unset( $GLOBALS['prv_test_state']['cron_events'][ $hook ] );
|
||||
}
|
||||
|
||||
function wp_rand( int $min = 0, int $max = 0 ): int {
|
||||
@@ -180,7 +180,7 @@ function is_wp_error( $thing ): bool {
|
||||
|
||||
function wp_remote_post( string $url, array $args = array() ) {
|
||||
// Return from test queue if set, else a generic success.
|
||||
$queue = &$GLOBALS['pgm_test_state']['remote_posts'];
|
||||
$queue = &$GLOBALS['prv_test_state']['remote_posts'];
|
||||
if ( ! empty( $queue ) ) {
|
||||
return array_shift( $queue );
|
||||
}
|
||||
@@ -220,17 +220,17 @@ class stdClass_wpdb {
|
||||
}
|
||||
public function query( string $sql ): bool { return true; }
|
||||
public function insert( string $table, array $data, array $format = [] ): int {
|
||||
$this->insert_id = $GLOBALS['pgm_test_state']['wpdb_insert_id']++;
|
||||
$this->insert_id = $GLOBALS['prv_test_state']['wpdb_insert_id']++;
|
||||
return 1;
|
||||
}
|
||||
public function update( string $table, array $data, array $where, array $data_format = [], array $where_format = [] ): int {
|
||||
return 1;
|
||||
}
|
||||
public function get_results( string $query, string $output = 'OBJECT' ): array {
|
||||
return is_array( $GLOBALS['pgm_test_state']['wpdb_results'] ) ? $GLOBALS['pgm_test_state']['wpdb_results'] : [];
|
||||
return is_array( $GLOBALS['prv_test_state']['wpdb_results'] ) ? $GLOBALS['prv_test_state']['wpdb_results'] : [];
|
||||
}
|
||||
public function get_var( string $query ): mixed {
|
||||
return $GLOBALS['pgm_test_state']['wpdb_var'];
|
||||
return $GLOBALS['prv_test_state']['wpdb_var'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,35 +240,35 @@ function dbDelta( string $sql ): array { return []; }
|
||||
|
||||
/* ── Test assertion helpers ────────────────────────────────────────────── */
|
||||
|
||||
$GLOBALS['pgm_test_report'] = [ 'pass' => 0, 'fail' => 0, 'failures' => [] ];
|
||||
$GLOBALS['prv_test_report'] = [ 'pass' => 0, 'fail' => 0, 'failures' => [] ];
|
||||
|
||||
function pgm_assert( bool $condition, string $label ): void {
|
||||
function prv_assert( bool $condition, string $label ): void {
|
||||
if ( $condition ) {
|
||||
$GLOBALS['pgm_test_report']['pass']++;
|
||||
$GLOBALS['prv_test_report']['pass']++;
|
||||
echo " PASS: {$label}\n";
|
||||
} else {
|
||||
$GLOBALS['pgm_test_report']['fail']++;
|
||||
$GLOBALS['pgm_test_report']['failures'][] = $label;
|
||||
$GLOBALS['prv_test_report']['fail']++;
|
||||
$GLOBALS['prv_test_report']['failures'][] = $label;
|
||||
echo " FAIL: {$label}\n";
|
||||
}
|
||||
}
|
||||
|
||||
function pgm_assert_equals( $expected, $actual, string $label ): void {
|
||||
function prv_assert_equals( $expected, $actual, string $label ): void {
|
||||
$pass = ( $expected === $actual );
|
||||
pgm_assert( $pass, $label . ( $pass ? '' : ' — expected ' . var_export( $expected, true ) . ', got ' . var_export( $actual, true ) ) );
|
||||
prv_assert( $pass, $label . ( $pass ? '' : ' — expected ' . var_export( $expected, true ) . ', got ' . var_export( $actual, true ) ) );
|
||||
}
|
||||
|
||||
function pgm_assert_throws( callable $fn, string $exception_class, string $label ): void {
|
||||
function prv_assert_throws( callable $fn, string $exception_class, string $label ): void {
|
||||
try {
|
||||
$fn();
|
||||
pgm_assert( false, $label . ' — expected ' . $exception_class . ' but no exception thrown' );
|
||||
prv_assert( false, $label . ' — expected ' . $exception_class . ' but no exception thrown' );
|
||||
} catch ( \Throwable $e ) {
|
||||
pgm_assert( $e instanceof $exception_class, $label . ' — got ' . get_class( $e ) );
|
||||
prv_assert( $e instanceof $exception_class, $label . ' — got ' . get_class( $e ) );
|
||||
}
|
||||
}
|
||||
|
||||
function pgm_test_summary(): int {
|
||||
$r = $GLOBALS['pgm_test_report'];
|
||||
function prv_test_summary(): int {
|
||||
$r = $GLOBALS['prv_test_report'];
|
||||
echo "\n---\n";
|
||||
echo "Totals: {$r['pass']} passed, {$r['fail']} failed\n";
|
||||
if ( $r['fail'] > 0 ) {
|
||||
@@ -283,8 +283,8 @@ function pgm_test_summary(): int {
|
||||
|
||||
/* ── Load autoloader + all plugin classes ──────────────────────────────── */
|
||||
|
||||
require_once __DIR__ . '/../includes/core/class-pgm-autoloader.php';
|
||||
PGM_Autoloader::register();
|
||||
require_once __DIR__ . '/../includes/providers/interface-pgm-probe-provider.php';
|
||||
require_once __DIR__ . '/../includes/collector/interface-pgm-data-collector.php';
|
||||
require_once __DIR__ . '/../includes/panel/interface-pgm-dashboard-panel.php';
|
||||
require_once __DIR__ . '/../includes/core/class-prv-autoloader.php';
|
||||
PRV_Autoloader::register();
|
||||
require_once __DIR__ . '/../includes/providers/interface-prv-probe-provider.php';
|
||||
require_once __DIR__ . '/../includes/collector/interface-prv-data-collector.php';
|
||||
require_once __DIR__ . '/../includes/panel/interface-prv-dashboard-panel.php';
|
||||
|
||||
@@ -1,74 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for PGM_Citation_Detector: domain extraction and cite detection.
|
||||
* Tests for PRV_Citation_Detector: domain extraction and cite detection.
|
||||
*
|
||||
* @package PeptideGeoMonitor
|
||||
* @package PrVision
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
echo "=== PGM Citation Detector Tests ===\n";
|
||||
echo "=== PRV Citation Detector Tests ===\n";
|
||||
|
||||
// ── Helpers ──────────────────────────────────────────────────────────────
|
||||
|
||||
$detector = new PGM_Citation_Detector();
|
||||
$detector = new PRV_Citation_Detector();
|
||||
|
||||
// ── Test: parse plain URL strings ────────────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$domains = $detector->parse_domains( [
|
||||
'https://peptiderepo.com/bpc-157/',
|
||||
'https://www.examine.com/supplements/bpc-157/',
|
||||
'https://pubmed.ncbi.nlm.nih.gov/12345',
|
||||
] );
|
||||
|
||||
pgm_assert( in_array( 'peptiderepo.com', $domains, true ), 'parse_domains: peptiderepo.com extracted from URL' );
|
||||
pgm_assert( in_array( 'examine.com', $domains, true ), 'parse_domains: www. stripped from examine.com' );
|
||||
pgm_assert( in_array( 'pubmed.ncbi.nlm.nih.gov', $domains, true ), 'parse_domains: full subdomain preserved when not www.' );
|
||||
pgm_assert_equals( 3, count( $domains ), 'parse_domains: exactly 3 unique domains' );
|
||||
prv_assert( in_array( 'peptiderepo.com', $domains, true ), 'parse_domains: peptiderepo.com extracted from URL' );
|
||||
prv_assert( in_array( 'examine.com', $domains, true ), 'parse_domains: www. stripped from examine.com' );
|
||||
prv_assert( in_array( 'pubmed.ncbi.nlm.nih.gov', $domains, true ), 'parse_domains: full subdomain preserved when not www.' );
|
||||
prv_assert_equals( 3, count( $domains ), 'parse_domains: exactly 3 unique domains' );
|
||||
|
||||
// ── Test: parse object-style citations (Perplexity format) ───────────────
|
||||
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$domains = $detector->parse_domains( [
|
||||
[ 'url' => 'https://peptiderepo.com/tb-500/' ],
|
||||
[ 'url' => 'https://examine.com/tb500' ],
|
||||
[ 'url' => 'https://peptiderepo.com/bpc-157/' ], // duplicate domain
|
||||
] );
|
||||
|
||||
pgm_assert_equals( 2, count( $domains ), 'parse_domains: object-style citations, duplicates removed' );
|
||||
pgm_assert( in_array( 'peptiderepo.com', $domains, true ), 'parse_domains: object-style, peptiderepo.com present' );
|
||||
prv_assert_equals( 2, count( $domains ), 'parse_domains: object-style citations, duplicates removed' );
|
||||
prv_assert( in_array( 'peptiderepo.com', $domains, true ), 'parse_domains: object-style, peptiderepo.com present' );
|
||||
|
||||
// ── Test: parse empty input ──────────────────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$domains = $detector->parse_domains( [] );
|
||||
pgm_assert_equals( [], $domains, 'parse_domains: empty input returns empty array' );
|
||||
prv_assert_equals( [], $domains, 'parse_domains: empty input returns empty array' );
|
||||
|
||||
// ── Test: is_cited detection ─────────────────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
pgm_assert( $detector->is_cited( ['peptiderepo.com', 'examine.com'] ), 'is_cited: returns true when target present' );
|
||||
pgm_assert( ! $detector->is_cited( ['examine.com', 'pubmed.ncbi.nlm.nih.gov'] ), 'is_cited: returns false when target absent' );
|
||||
pgm_assert( ! $detector->is_cited( [] ), 'is_cited: returns false for empty list' );
|
||||
prv_test_reset();
|
||||
prv_assert( $detector->is_cited( ['peptiderepo.com', 'examine.com'] ), 'is_cited: returns true when target present' );
|
||||
prv_assert( ! $detector->is_cited( ['examine.com', 'pubmed.ncbi.nlm.nih.gov'] ), 'is_cited: returns false when target absent' );
|
||||
prv_assert( ! $detector->is_cited( [] ), 'is_cited: returns false for empty list' );
|
||||
|
||||
// ── Test: get_our_position ───────────────────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$domains = ['examine.com', 'peptiderepo.com', 'pubmed.ncbi.nlm.nih.gov'];
|
||||
pgm_assert_equals( 2, $detector->get_our_position( $domains ), 'get_our_position: 1-based, position 2' );
|
||||
prv_assert_equals( 2, $detector->get_our_position( $domains ), 'get_our_position: 1-based, position 2' );
|
||||
|
||||
$domains_first = ['peptiderepo.com', 'examine.com'];
|
||||
pgm_assert_equals( 1, $detector->get_our_position( $domains_first ), 'get_our_position: position 1 when first' );
|
||||
prv_assert_equals( 1, $detector->get_our_position( $domains_first ), 'get_our_position: position 1 when first' );
|
||||
|
||||
$domains_absent = ['examine.com', 'pubmed.ncbi.nlm.nih.gov'];
|
||||
pgm_assert_equals( null, $detector->get_our_position( $domains_absent ), 'get_our_position: null when not present' );
|
||||
prv_assert_equals( null, $detector->get_our_position( $domains_absent ), 'get_our_position: null when not present' );
|
||||
|
||||
// ── Test: malformed / unexpected input ───────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$domains = $detector->parse_domains( [
|
||||
'not-a-url',
|
||||
42,
|
||||
@@ -76,6 +76,21 @@ $domains = $detector->parse_domains( [
|
||||
['no_url_key' => 'foo'],
|
||||
['url' => ''],
|
||||
] );
|
||||
pgm_assert_equals( [], $domains, 'parse_domains: gracefully skips malformed items' );
|
||||
prv_assert_equals( [], $domains, 'parse_domains: gracefully skips malformed items' );
|
||||
|
||||
exit( pgm_test_summary() );
|
||||
|
||||
// ── Test: P2-A — www-strip must not corrupt non-www domains starting with 'w' ──
|
||||
|
||||
prv_test_reset();
|
||||
$domains = $detector->parse_domains( [
|
||||
'https://wikipedia.org/wiki/bpc-157',
|
||||
'https://www.examine.com/bpc-157/',
|
||||
'https://webmd.com/drug/bpc-157',
|
||||
] );
|
||||
|
||||
prv_assert( in_array( 'wikipedia.org', $domains, true ), 'P2-A: wikipedia.org survives intact (no char-mask corruption)' );
|
||||
prv_assert( in_array( 'examine.com', $domains, true ), 'P2-A: www.examine.com correctly stripped to examine.com' );
|
||||
prv_assert( in_array( 'webmd.com', $domains, true ), 'P2-A: webmd.com survives intact (no char-mask corruption)' );
|
||||
prv_assert_equals( 3, count( $domains ), 'P2-A: exactly 3 unique domains from 3 distinct URLs' );
|
||||
|
||||
exit( prv_test_summary() );
|
||||
|
||||
@@ -1,85 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for PGM_Cost_Ledger: MTD cost retrieval, budget pre-check, and
|
||||
* Tests for PRV_Cost_Ledger: MTD cost retrieval, budget pre-check, and
|
||||
* the budget-cap abort behaviour.
|
||||
*
|
||||
* @package PeptideGeoMonitor
|
||||
* @package PrVision
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
echo "=== PGM Cost Ledger Tests ===\n";
|
||||
echo "=== PRV Cost Ledger Tests ===\n";
|
||||
|
||||
// ── Test: can_afford when below cap ─────────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_monthly_budget_usd'] = 5.0;
|
||||
$GLOBALS['pgm_test_state']['wpdb_var'] = '2.50'; // MTD spent
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_monthly_budget_usd'] = 5.0;
|
||||
$GLOBALS['prv_test_state']['wpdb_var'] = '2.50'; // MTD spent
|
||||
|
||||
$ledger = new PGM_Cost_Ledger();
|
||||
pgm_assert( $ledger->can_afford( 1.0 ), 'can_afford: 2.50 spent + 1.00 = 3.50 < 5.00 → true' );
|
||||
$ledger = new PRV_Cost_Ledger();
|
||||
prv_assert( $ledger->can_afford( 1.0 ), 'can_afford: 2.50 spent + 1.00 = 3.50 < 5.00 → true' );
|
||||
|
||||
// ── Test: can_afford when at cap ─────────────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_monthly_budget_usd'] = 5.0;
|
||||
$GLOBALS['pgm_test_state']['wpdb_var'] = '5.00';
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_monthly_budget_usd'] = 5.0;
|
||||
$GLOBALS['prv_test_state']['wpdb_var'] = '5.00';
|
||||
|
||||
$ledger = new PGM_Cost_Ledger();
|
||||
pgm_assert( ! $ledger->can_afford( 0.01 ), 'can_afford: 5.00 spent + 0.01 > 5.00 → false' );
|
||||
$ledger = new PRV_Cost_Ledger();
|
||||
prv_assert( ! $ledger->can_afford( 0.01 ), 'can_afford: 5.00 spent + 0.01 > 5.00 → false' );
|
||||
|
||||
// ── Test: can_afford when exactly at cap ─────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_monthly_budget_usd'] = 5.0;
|
||||
$GLOBALS['pgm_test_state']['wpdb_var'] = '4.99';
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_monthly_budget_usd'] = 5.0;
|
||||
$GLOBALS['prv_test_state']['wpdb_var'] = '4.99';
|
||||
|
||||
$ledger = new PGM_Cost_Ledger();
|
||||
pgm_assert( $ledger->can_afford( 0.01 ), 'can_afford: 4.99 + 0.01 = 5.00 exactly → true (at cap is allowed)' );
|
||||
$ledger = new PRV_Cost_Ledger();
|
||||
prv_assert( $ledger->can_afford( 0.01 ), 'can_afford: 4.99 + 0.01 = 5.00 exactly → true (at cap is allowed)' );
|
||||
|
||||
// ── Test: get_remaining_budget_usd ──────────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_monthly_budget_usd'] = 5.0;
|
||||
$GLOBALS['pgm_test_state']['wpdb_var'] = '3.25';
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_monthly_budget_usd'] = 5.0;
|
||||
$GLOBALS['prv_test_state']['wpdb_var'] = '3.25';
|
||||
|
||||
$ledger = new PGM_Cost_Ledger();
|
||||
pgm_assert_equals( 1.75, round( $ledger->get_remaining_budget_usd(), 2 ), 'get_remaining_budget_usd: 5.00 - 3.25 = 1.75' );
|
||||
$ledger = new PRV_Cost_Ledger();
|
||||
prv_assert_equals( 1.75, round( $ledger->get_remaining_budget_usd(), 2 ), 'get_remaining_budget_usd: 5.00 - 3.25 = 1.75' );
|
||||
|
||||
// ── Test: get_remaining_budget_usd never negative ────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_monthly_budget_usd'] = 5.0;
|
||||
$GLOBALS['pgm_test_state']['wpdb_var'] = '10.00'; // over cap
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_monthly_budget_usd'] = 5.0;
|
||||
$GLOBALS['prv_test_state']['wpdb_var'] = '10.00'; // over cap
|
||||
|
||||
$ledger = new PGM_Cost_Ledger();
|
||||
pgm_assert_equals( 0.0, $ledger->get_remaining_budget_usd(), 'get_remaining_budget_usd: clamps to 0.0 when over cap' );
|
||||
$ledger = new PRV_Cost_Ledger();
|
||||
prv_assert_equals( 0.0, $ledger->get_remaining_budget_usd(), 'get_remaining_budget_usd: clamps to 0.0 when over cap' );
|
||||
|
||||
// ── Test: get_month_to_date_usd with null DB result (no rows yet) ────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_monthly_budget_usd'] = 5.0;
|
||||
$GLOBALS['pgm_test_state']['wpdb_var'] = null;
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_monthly_budget_usd'] = 5.0;
|
||||
$GLOBALS['prv_test_state']['wpdb_var'] = null;
|
||||
|
||||
$ledger = new PGM_Cost_Ledger();
|
||||
pgm_assert_equals( 0.0, $ledger->get_month_to_date_usd(), 'get_month_to_date_usd: null DB result → 0.0' );
|
||||
$ledger = new PRV_Cost_Ledger();
|
||||
prv_assert_equals( 0.0, $ledger->get_month_to_date_usd(), 'get_month_to_date_usd: null DB result → 0.0' );
|
||||
|
||||
// ── Test: update_row_cost returns true ──────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$ledger = new PGM_Cost_Ledger();
|
||||
pgm_assert( $ledger->update_row_cost( 42, 0.00123456 ), 'update_row_cost: returns true on success' );
|
||||
prv_test_reset();
|
||||
$ledger = new PRV_Cost_Ledger();
|
||||
prv_assert( $ledger->update_row_cost( 42, 0.00123456 ), 'update_row_cost: returns true on success' );
|
||||
|
||||
// ── Test: budget abort mid-run (runner stops when cap hit) ──────────────
|
||||
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
// Simulate a nearly-exhausted budget.
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_monthly_budget_usd'] = 0.001; // $0.001 cap
|
||||
$GLOBALS['pgm_test_state']['wpdb_var'] = '0.001'; // fully spent
|
||||
$GLOBALS['prv_test_state']['options']['prv_monthly_budget_usd'] = 0.001; // $0.001 cap
|
||||
$GLOBALS['prv_test_state']['wpdb_var'] = '0.001'; // fully spent
|
||||
|
||||
$ledger2 = new PGM_Cost_Ledger();
|
||||
pgm_assert( ! $ledger2->can_afford( 0.000001 ), 'budget abort: can_afford returns false at cap → runner would stop' );
|
||||
$ledger2 = new PRV_Cost_Ledger();
|
||||
prv_assert( ! $ledger2->can_afford( 0.000001 ), 'budget abort: can_afford returns false at cap → runner would stop' );
|
||||
|
||||
exit( pgm_test_summary() );
|
||||
exit( prv_test_summary() );
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for PGM_Cron: scheduling, clearing, and registration.
|
||||
* Tests for PRV_Cron: scheduling, clearing, and registration.
|
||||
*
|
||||
* @package PeptideGeoMonitor
|
||||
* @package PrVision
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
echo "=== PGM Cron Tests ===\n";
|
||||
echo "=== PRV Cron Tests ===\n";
|
||||
|
||||
// ── Test: schedule_weekly adds the event ────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
pgm_assert( ! PGM_Cron::is_scheduled(), 'schedule_weekly: not scheduled before call' );
|
||||
prv_test_reset();
|
||||
prv_assert( ! PRV_Cron::is_scheduled(), 'schedule_weekly: not scheduled before call' );
|
||||
|
||||
PGM_Cron::schedule_weekly();
|
||||
pgm_assert( PGM_Cron::is_scheduled(), 'schedule_weekly: event scheduled after call' );
|
||||
PRV_Cron::schedule_weekly();
|
||||
prv_assert( PRV_Cron::is_scheduled(), 'schedule_weekly: event scheduled after call' );
|
||||
|
||||
// ── Test: schedule_weekly is idempotent ──────────────────────────────────
|
||||
|
||||
PGM_Cron::schedule_weekly(); // Second call should no-op.
|
||||
$events = $GLOBALS['pgm_test_state']['cron_events'];
|
||||
pgm_assert_equals( 1, count( $events ), 'schedule_weekly: idempotent — second call does not add duplicate' );
|
||||
PRV_Cron::schedule_weekly(); // Second call should no-op.
|
||||
$events = $GLOBALS['prv_test_state']['cron_events'];
|
||||
prv_assert_equals( 1, count( $events ), 'schedule_weekly: idempotent — second call does not add duplicate' );
|
||||
|
||||
// ── Test: clear_schedule removes the event ──────────────────────────────
|
||||
|
||||
PGM_Cron::clear_schedule();
|
||||
pgm_assert( ! PGM_Cron::is_scheduled(), 'clear_schedule: event removed after clear' );
|
||||
PRV_Cron::clear_schedule();
|
||||
prv_assert( ! PRV_Cron::is_scheduled(), 'clear_schedule: event removed after clear' );
|
||||
|
||||
// ── Test: clear_schedule is safe when nothing scheduled ─────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
PGM_Cron::clear_schedule(); // Should not throw.
|
||||
pgm_assert( ! PGM_Cron::is_scheduled(), 'clear_schedule: safe when nothing scheduled' );
|
||||
prv_test_reset();
|
||||
PRV_Cron::clear_schedule(); // Should not throw.
|
||||
prv_assert( ! PRV_Cron::is_scheduled(), 'clear_schedule: safe when nothing scheduled' );
|
||||
|
||||
// ── Test: register_hooks registers the cron hook action ─────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$cron = new PGM_Cron();
|
||||
prv_test_reset();
|
||||
$cron = new PRV_Cron();
|
||||
$cron->register_hooks();
|
||||
|
||||
$hooks = array_column( $GLOBALS['pgm_test_state']['actions'], 'hook' );
|
||||
pgm_assert( in_array( PGM_CRON_HOOK, $hooks, true ), 'register_hooks: pgm_weekly_probe action registered' );
|
||||
$hooks = array_column( $GLOBALS['prv_test_state']['actions'], 'hook' );
|
||||
prv_assert( in_array( PRV_CRON_HOOK, $hooks, true ), 'register_hooks: prv_weekly_probe action registered' );
|
||||
|
||||
// ── Test: hook constant is correct string ────────────────────────────────
|
||||
|
||||
pgm_assert_equals( 'pgm_weekly_probe', PGM_CRON_HOOK, 'PGM_CRON_HOOK: constant value correct' );
|
||||
prv_assert_equals( 'prv_weekly_probe', PRV_CRON_HOOK, 'PRV_CRON_HOOK: constant value correct' );
|
||||
|
||||
// ── Test: PGM_Activator calls schedule_weekly ────────────────────────────
|
||||
// ── Test: PRV_Activator calls schedule_weekly ────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
// Seed options so seed_defaults() doesn't fail.
|
||||
PGM_Activator::activate();
|
||||
pgm_assert( PGM_Cron::is_scheduled(), 'PGM_Activator::activate: weekly cron scheduled after activation' );
|
||||
PRV_Activator::activate();
|
||||
prv_assert( PRV_Cron::is_scheduled(), 'PRV_Activator::activate: weekly cron scheduled after activation' );
|
||||
|
||||
// ── Test: PGM_Deactivator calls clear_schedule ───────────────────────────
|
||||
// ── Test: PRV_Deactivator calls clear_schedule ───────────────────────────
|
||||
|
||||
PGM_Deactivator::deactivate();
|
||||
pgm_assert( ! PGM_Cron::is_scheduled(), 'PGM_Deactivator::deactivate: cron cleared after deactivation' );
|
||||
PRV_Deactivator::deactivate();
|
||||
prv_assert( ! PRV_Cron::is_scheduled(), 'PRV_Deactivator::deactivate: cron cleared after deactivation' );
|
||||
|
||||
exit( pgm_test_summary() );
|
||||
exit( prv_test_summary() );
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for PGM_Probe_Runner: budget-cap abort, in-run caching, and run mechanics.
|
||||
* Tests for PRV_Probe_Runner: budget-cap abort and run mechanics.
|
||||
*
|
||||
* Uses queued mock HTTP responses (via $GLOBALS['pgm_test_state']['remote_posts'])
|
||||
* Uses queued mock HTTP responses (via $GLOBALS['prv_test_state']['remote_posts'])
|
||||
* and a mock ledger to verify runner behaviour without real API calls.
|
||||
*
|
||||
* @package PeptideGeoMonitor
|
||||
* @package PrVision
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
echo "=== PGM Probe Runner Tests ===\n";
|
||||
echo "=== PRV Probe Runner Tests ===\n";
|
||||
|
||||
// ── Define API key constants (required by providers) ──────────────────────
|
||||
|
||||
if ( ! defined( 'PGM_OPENROUTER_API_KEY' ) ) {
|
||||
define( 'PGM_OPENROUTER_API_KEY', 'sk-or-test-key' );
|
||||
if ( ! defined( 'PRV_OPENROUTER_API_KEY' ) ) {
|
||||
define( 'PRV_OPENROUTER_API_KEY', 'sk-or-test-key' );
|
||||
}
|
||||
if ( ! defined( 'PGM_CF_ACCOUNT_ID' ) ) {
|
||||
define( 'PGM_CF_ACCOUNT_ID', '' );
|
||||
if ( ! defined( 'PRV_CF_ACCOUNT_ID' ) ) {
|
||||
define( 'PRV_CF_ACCOUNT_ID', '' );
|
||||
}
|
||||
if ( ! defined( 'PGM_CF_GATEWAY_ID' ) ) {
|
||||
define( 'PGM_CF_GATEWAY_ID', '' );
|
||||
if ( ! defined( 'PRV_CF_GATEWAY_ID' ) ) {
|
||||
define( 'PRV_CF_GATEWAY_ID', '' );
|
||||
}
|
||||
|
||||
// ── Mock ledger: tracks afford calls, simulates exhaustion ────────────────
|
||||
|
||||
class PGM_Mock_Ledger extends PGM_Cost_Ledger {
|
||||
class PRV_Mock_Ledger extends PRV_Cost_Ledger {
|
||||
public int $afford_count = 0;
|
||||
public int $no_afford_count = 0;
|
||||
public int $exhaust_after = PHP_INT_MAX;
|
||||
@@ -57,124 +57,124 @@ $cited_body = json_encode([
|
||||
|
||||
// ── Test: basic run completes — 1×1×1 (peptide × intent × model) ─────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_peptides'] = [['slug'=>'bpc-157','label'=>'BPC-157']];
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_prompt_intents'] = ['what is {peptide}'];
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_models'] = ['perplexity/sonar'];
|
||||
$GLOBALS['pgm_test_state']['remote_posts'] = [
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_peptides'] = [['slug'=>'bpc-157','label'=>'BPC-157']];
|
||||
$GLOBALS['prv_test_state']['options']['prv_prompt_intents'] = ['what is {peptide}'];
|
||||
$GLOBALS['prv_test_state']['options']['prv_models'] = ['perplexity/sonar'];
|
||||
$GLOBALS['prv_test_state']['remote_posts'] = [
|
||||
['response' => ['code' => 200], 'body' => $cited_body],
|
||||
];
|
||||
|
||||
$ledger1 = new PGM_Mock_Ledger();
|
||||
$runner1 = new PGM_Probe_Runner( $ledger1 );
|
||||
$ledger1 = new PRV_Mock_Ledger();
|
||||
$runner1 = new PRV_Probe_Runner( $ledger1 );
|
||||
$counts1 = $runner1->run();
|
||||
|
||||
pgm_assert_equals( 1, $counts1['probed'], 'basic run: 1 probed' );
|
||||
pgm_assert_equals( 0, $counts1['skipped_budget'], 'basic run: 0 budget skips' );
|
||||
pgm_assert_equals( 0, $counts1['skipped_error'], 'basic run: 0 error skips' );
|
||||
pgm_assert_equals( 1, $ledger1->afford_count, 'basic run: 1 can_afford check' );
|
||||
prv_assert_equals( 1, $counts1['probed'], 'basic run: 1 probed' );
|
||||
prv_assert_equals( 0, $counts1['skipped_budget'], 'basic run: 0 budget skips' );
|
||||
prv_assert_equals( 0, $counts1['skipped_error'], 'basic run: 0 error skips' );
|
||||
prv_assert_equals( 1, $ledger1->afford_count, 'basic run: 1 can_afford check' );
|
||||
|
||||
// ── Test: 2×1×1 run completes all probes when budget sufficient ───────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_peptides'] = [
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_peptides'] = [
|
||||
['slug'=>'bpc-157','label'=>'BPC-157'],
|
||||
['slug'=>'tb-500','label'=>'TB-500'],
|
||||
];
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_prompt_intents'] = ['what is {peptide}'];
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_models'] = ['perplexity/sonar'];
|
||||
$GLOBALS['pgm_test_state']['remote_posts'] = [
|
||||
$GLOBALS['prv_test_state']['options']['prv_prompt_intents'] = ['what is {peptide}'];
|
||||
$GLOBALS['prv_test_state']['options']['prv_models'] = ['perplexity/sonar'];
|
||||
$GLOBALS['prv_test_state']['remote_posts'] = [
|
||||
['response' => ['code' => 200], 'body' => $cited_body],
|
||||
['response' => ['code' => 200], 'body' => $cited_body],
|
||||
];
|
||||
|
||||
$ledger2 = new PGM_Mock_Ledger();
|
||||
$runner2 = new PGM_Probe_Runner( $ledger2 );
|
||||
$ledger2 = new PRV_Mock_Ledger();
|
||||
$runner2 = new PRV_Probe_Runner( $ledger2 );
|
||||
$counts2 = $runner2->run();
|
||||
|
||||
pgm_assert_equals( 2, $counts2['probed'], '2×1×1 run: 2 probes completed' );
|
||||
pgm_assert_equals( 2, $ledger2->afford_count, '2×1×1 run: 2 can_afford checks' );
|
||||
prv_assert_equals( 2, $counts2['probed'], '2×1×1 run: 2 probes completed' );
|
||||
prv_assert_equals( 2, $ledger2->afford_count, '2×1×1 run: 2 can_afford checks' );
|
||||
|
||||
// ── Test: budget cap abort after N probes ────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_peptides'] = [
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_peptides'] = [
|
||||
['slug'=>'bpc-157','label'=>'BPC-157'],
|
||||
['slug'=>'tb-500','label'=>'TB-500'],
|
||||
['slug'=>'mk-677','label'=>'MK-677'],
|
||||
];
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_prompt_intents'] = ['what is {peptide}'];
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_models'] = ['perplexity/sonar'];
|
||||
$GLOBALS['prv_test_state']['options']['prv_prompt_intents'] = ['what is {peptide}'];
|
||||
$GLOBALS['prv_test_state']['options']['prv_models'] = ['perplexity/sonar'];
|
||||
// Queue 3 responses but cap budget at 1.
|
||||
$GLOBALS['pgm_test_state']['remote_posts'] = [
|
||||
$GLOBALS['prv_test_state']['remote_posts'] = [
|
||||
['response' => ['code' => 200], 'body' => $cited_body],
|
||||
['response' => ['code' => 200], 'body' => $cited_body],
|
||||
['response' => ['code' => 200], 'body' => $cited_body],
|
||||
];
|
||||
|
||||
$exhausting_ledger = new PGM_Mock_Ledger();
|
||||
$exhausting_ledger = new PRV_Mock_Ledger();
|
||||
$exhausting_ledger->exhaust_after = 1; // Budget exhausted after 1st can_afford check.
|
||||
|
||||
$runner3 = new PGM_Probe_Runner( $exhausting_ledger );
|
||||
$runner3 = new PRV_Probe_Runner( $exhausting_ledger );
|
||||
$counts3 = $runner3->run();
|
||||
|
||||
pgm_assert_equals( 1, $counts3['probed'], 'budget abort: 1 probe completed before cap' );
|
||||
pgm_assert( $counts3['skipped_budget'] >= 2, 'budget abort: ≥2 probes skipped (budget)' );
|
||||
pgm_assert_equals( 0, $counts3['skipped_error'], 'budget abort: 0 error skips' );
|
||||
prv_assert_equals( 1, $counts3['probed'], 'budget abort: 1 probe completed before cap' );
|
||||
prv_assert( $counts3['skipped_budget'] >= 2, 'budget abort: ≥2 probes skipped (budget)' );
|
||||
prv_assert_equals( 0, $counts3['skipped_error'], 'budget abort: 0 error skips' );
|
||||
|
||||
// ── Test: HTTP error counts as skipped_error ─────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_peptides'] = [['slug'=>'bpc-157','label'=>'BPC-157']];
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_prompt_intents'] = ['what is {peptide}'];
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_models'] = ['perplexity/sonar'];
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_peptides'] = [['slug'=>'bpc-157','label'=>'BPC-157']];
|
||||
$GLOBALS['prv_test_state']['options']['prv_prompt_intents'] = ['what is {peptide}'];
|
||||
$GLOBALS['prv_test_state']['options']['prv_models'] = ['perplexity/sonar'];
|
||||
// All retries fail with 500.
|
||||
$GLOBALS['pgm_test_state']['remote_posts'] = [
|
||||
$GLOBALS['prv_test_state']['remote_posts'] = [
|
||||
['response' => ['code' => 500], 'body' => 'Error'],
|
||||
['response' => ['code' => 500], 'body' => 'Error'],
|
||||
['response' => ['code' => 500], 'body' => 'Error'],
|
||||
];
|
||||
|
||||
$ledger4 = new PGM_Mock_Ledger();
|
||||
$runner4 = new PGM_Probe_Runner( $ledger4 );
|
||||
$ledger4 = new PRV_Mock_Ledger();
|
||||
$runner4 = new PRV_Probe_Runner( $ledger4 );
|
||||
$counts4 = $runner4->run();
|
||||
|
||||
pgm_assert_equals( 0, $counts4['probed'], 'HTTP 500: 0 probes' );
|
||||
pgm_assert( $counts4['skipped_error'] >= 1, 'HTTP 500: ≥1 error skip recorded' );
|
||||
prv_assert_equals( 0, $counts4['probed'], 'HTTP 500: 0 probes' );
|
||||
prv_assert( $counts4['skipped_error'] >= 1, 'HTTP 500: ≥1 error skip recorded' );
|
||||
|
||||
// ── Test: WP_Error from wp_remote_post counts as skipped_error ──────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_peptides'] = [['slug'=>'bpc-157','label'=>'BPC-157']];
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_prompt_intents'] = ['what is {peptide}'];
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_models'] = ['perplexity/sonar'];
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_peptides'] = [['slug'=>'bpc-157','label'=>'BPC-157']];
|
||||
$GLOBALS['prv_test_state']['options']['prv_prompt_intents'] = ['what is {peptide}'];
|
||||
$GLOBALS['prv_test_state']['options']['prv_models'] = ['perplexity/sonar'];
|
||||
// Return WP_Error for all retries.
|
||||
$wp_error = new WP_Error( 'http_request_failed', 'cURL error 28: Operation timed out' );
|
||||
$GLOBALS['pgm_test_state']['remote_posts'] = [ $wp_error, $wp_error, $wp_error ];
|
||||
$GLOBALS['prv_test_state']['remote_posts'] = [ $wp_error, $wp_error, $wp_error ];
|
||||
|
||||
$ledger5 = new PGM_Mock_Ledger();
|
||||
$runner5 = new PGM_Probe_Runner( $ledger5 );
|
||||
$ledger5 = new PRV_Mock_Ledger();
|
||||
$runner5 = new PRV_Probe_Runner( $ledger5 );
|
||||
$counts5 = $runner5->run();
|
||||
|
||||
pgm_assert_equals( 0, $counts5['probed'], 'WP_Error: 0 probes completed' );
|
||||
pgm_assert( $counts5['skipped_error'] >= 1, 'WP_Error: ≥1 error skip recorded' );
|
||||
prv_assert_equals( 0, $counts5['probed'], 'WP_Error: 0 probes completed' );
|
||||
prv_assert( $counts5['skipped_error'] >= 1, 'WP_Error: ≥1 error skip recorded' );
|
||||
|
||||
// ── Test: run returns correct keys in counts array ───────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_peptides'] = [['slug'=>'bpc-157','label'=>'BPC-157']];
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_prompt_intents'] = ['what is {peptide}'];
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_models'] = ['perplexity/sonar'];
|
||||
$GLOBALS['pgm_test_state']['remote_posts'] = [
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_peptides'] = [['slug'=>'bpc-157','label'=>'BPC-157']];
|
||||
$GLOBALS['prv_test_state']['options']['prv_prompt_intents'] = ['what is {peptide}'];
|
||||
$GLOBALS['prv_test_state']['options']['prv_models'] = ['perplexity/sonar'];
|
||||
$GLOBALS['prv_test_state']['remote_posts'] = [
|
||||
['response' => ['code' => 200], 'body' => $cited_body],
|
||||
];
|
||||
|
||||
$ledger6 = new PGM_Mock_Ledger();
|
||||
$runner6 = new PGM_Probe_Runner( $ledger6 );
|
||||
$ledger6 = new PRV_Mock_Ledger();
|
||||
$runner6 = new PRV_Probe_Runner( $ledger6 );
|
||||
$counts6 = $runner6->run();
|
||||
|
||||
pgm_assert( array_key_exists( 'probed', $counts6 ), 'run: returns probed key' );
|
||||
pgm_assert( array_key_exists( 'skipped_budget', $counts6 ), 'run: returns skipped_budget key' );
|
||||
pgm_assert( array_key_exists( 'skipped_error', $counts6 ), 'run: returns skipped_error key' );
|
||||
prv_assert( array_key_exists( 'probed', $counts6 ), 'run: returns probed key' );
|
||||
prv_assert( array_key_exists( 'skipped_budget', $counts6 ), 'run: returns skipped_budget key' );
|
||||
prv_assert( array_key_exists( 'skipped_error', $counts6 ), 'run: returns skipped_error key' );
|
||||
|
||||
exit( pgm_test_summary() );
|
||||
exit( prv_test_summary() );
|
||||
|
||||
@@ -2,25 +2,25 @@
|
||||
/**
|
||||
* Tests for provider response parsing.
|
||||
*
|
||||
* Exercises PGM_Perplexity_Provider::parse_response() and
|
||||
* PGM_OpenRouter_Provider::parse_response() with mock HTTP responses,
|
||||
* Exercises PRV_Perplexity_Provider::parse_response() and
|
||||
* PRV_OpenRouter_Provider::parse_response() with mock HTTP responses,
|
||||
* verifying domain extraction, citation detection, and cost calculation.
|
||||
*
|
||||
* @package PeptideGeoMonitor
|
||||
* @package PrVision
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
echo "=== PGM Provider Response Parsing Tests ===\n";
|
||||
echo "=== PRV Provider Response Parsing Tests ===\n";
|
||||
|
||||
// ── PGM_Perplexity_Provider parsing ─────────────────────────────────────
|
||||
// ── PRV_Perplexity_Provider parsing ─────────────────────────────────────
|
||||
|
||||
$provider = new PGM_Perplexity_Provider( null, new PGM_Citation_Detector() );
|
||||
$provider = new PRV_Perplexity_Provider( null, new PRV_Citation_Detector() );
|
||||
|
||||
// Test: cited via citations array
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$data = [
|
||||
'choices' => [[ 'message' => [ 'content' => 'BPC-157 is a peptide. See peptiderepo.com' ] ]],
|
||||
'citations' => [
|
||||
@@ -30,34 +30,34 @@ $data = [
|
||||
'usage' => [ 'total_tokens' => 500 ],
|
||||
];
|
||||
$result = $provider->parse_response( $data );
|
||||
pgm_assert( $result->is_cited(), 'Perplexity: cited=true when peptiderepo.com in citations' );
|
||||
pgm_assert_equals( 1, $result->get_our_position(), 'Perplexity: position=1 when first in citations' );
|
||||
pgm_assert( count( $result->get_source_domains() ) === 2, 'Perplexity: 2 source domains extracted' );
|
||||
pgm_assert_equals( 500 * 0.000001, $result->get_cost_usd(), 'Perplexity: cost from token usage' );
|
||||
prv_assert( $result->is_cited(), 'Perplexity: cited=true when peptiderepo.com in citations' );
|
||||
prv_assert_equals( 1, $result->get_our_position(), 'Perplexity: position=1 when first in citations' );
|
||||
prv_assert( count( $result->get_source_domains() ) === 2, 'Perplexity: 2 source domains extracted' );
|
||||
prv_assert_equals( 500 * 0.000001, $result->get_cost_usd(), 'Perplexity: cost from token usage' );
|
||||
|
||||
// Test: not cited, no citations
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$data_empty = [
|
||||
'choices' => [[ 'message' => [ 'content' => 'BPC-157 info here.' ] ]],
|
||||
'citations' => [],
|
||||
'usage' => [ 'total_tokens' => 200 ],
|
||||
];
|
||||
$result_empty = $provider->parse_response( $data_empty );
|
||||
pgm_assert( ! $result_empty->is_cited(), 'Perplexity: cited=false with empty citations' );
|
||||
pgm_assert_equals( null, $result_empty->get_our_position(), 'Perplexity: position=null when not cited' );
|
||||
prv_assert( ! $result_empty->is_cited(), 'Perplexity: cited=false with empty citations' );
|
||||
prv_assert_equals( null, $result_empty->get_our_position(), 'Perplexity: position=null when not cited' );
|
||||
|
||||
// Test: excerpt truncated to 500 chars
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$long_content = str_repeat( 'a', 600 );
|
||||
$data_long = [
|
||||
'choices' => [[ 'message' => [ 'content' => $long_content ] ]],
|
||||
'citations' => [],
|
||||
];
|
||||
$result_long = $provider->parse_response( $data_long );
|
||||
pgm_assert_equals( 500, mb_strlen( $result_long->get_raw_excerpt() ), 'Perplexity: excerpt truncated to 500 chars' );
|
||||
prv_assert_equals( 500, mb_strlen( $result_long->get_raw_excerpt() ), 'Perplexity: excerpt truncated to 500 chars' );
|
||||
|
||||
// Test: object-style citations
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$data_obj = [
|
||||
'choices' => [[ 'message' => [ 'content' => 'answer' ] ]],
|
||||
'citations' => [
|
||||
@@ -66,26 +66,26 @@ $data_obj = [
|
||||
],
|
||||
];
|
||||
$result_obj = $provider->parse_response( $data_obj );
|
||||
pgm_assert( $result_obj->is_cited(), 'Perplexity: object-style citations — cited=true' );
|
||||
pgm_assert_equals( 1, $result_obj->get_our_position(), 'Perplexity: object-style — position=1' );
|
||||
prv_assert( $result_obj->is_cited(), 'Perplexity: object-style citations — cited=true' );
|
||||
prv_assert_equals( 1, $result_obj->get_our_position(), 'Perplexity: object-style — position=1' );
|
||||
|
||||
// Test: fallback cost when no usage data
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$data_no_usage = [
|
||||
'choices' => [[ 'message' => [ 'content' => 'answer' ] ]],
|
||||
'citations' => [],
|
||||
];
|
||||
$result_no_usage = $provider->parse_response( $data_no_usage );
|
||||
pgm_assert_equals( PGM_Perplexity_Provider::ESTIMATED_COST_PER_PROBE, $result_no_usage->get_cost_usd(), 'Perplexity: fallback to ESTIMATED_COST_PER_PROBE when no usage' );
|
||||
prv_assert_equals( PRV_Perplexity_Provider::ESTIMATED_COST_PER_PROBE, $result_no_usage->get_cost_usd(), 'Perplexity: fallback to ESTIMATED_COST_PER_PROBE when no usage' );
|
||||
|
||||
// ── PGM_OpenRouter_Provider parsing ─────────────────────────────────────
|
||||
// ── PRV_OpenRouter_Provider parsing ─────────────────────────────────────
|
||||
|
||||
echo "\n--- OpenRouter provider parsing ---\n";
|
||||
|
||||
$or_provider = new PGM_OpenRouter_Provider( 'openai/gpt-4o-search-preview', null, new PGM_Citation_Detector() );
|
||||
$or_provider = new PRV_OpenRouter_Provider( 'openai/gpt-4o-search-preview', null, new PRV_Citation_Detector() );
|
||||
|
||||
// Test: annotations path (structured citations)
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$data_ann = [
|
||||
'choices' => [[
|
||||
'message' => [
|
||||
@@ -99,11 +99,11 @@ $data_ann = [
|
||||
'usage' => [ 'total_tokens' => 300 ],
|
||||
];
|
||||
$result_ann = $or_provider->parse_response( $data_ann );
|
||||
pgm_assert( $result_ann->is_cited(), 'OpenRouter: annotations path — cited=true' );
|
||||
pgm_assert_equals( 1, $result_ann->get_our_position(), 'OpenRouter: annotations path — position=1' );
|
||||
prv_assert( $result_ann->is_cited(), 'OpenRouter: annotations path — cited=true' );
|
||||
prv_assert_equals( 1, $result_ann->get_our_position(), 'OpenRouter: annotations path — position=1' );
|
||||
|
||||
// Test: regex URL extraction fallback
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$data_regex = [
|
||||
'choices' => [[
|
||||
'message' => [
|
||||
@@ -113,23 +113,23 @@ $data_regex = [
|
||||
'usage' => [ 'total_tokens' => 150 ],
|
||||
];
|
||||
$result_regex = $or_provider->parse_response( $data_regex );
|
||||
pgm_assert( $result_regex->is_cited(), 'OpenRouter: regex fallback — cited=true from inline URL' );
|
||||
prv_assert( $result_regex->is_cited(), 'OpenRouter: regex fallback — cited=true from inline URL' );
|
||||
|
||||
// Test: not cited
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$data_no_cite = [
|
||||
'choices' => [[ 'message' => [ 'content' => 'Some response without our domain.' ] ]],
|
||||
];
|
||||
$result_no_cite = $or_provider->parse_response( $data_no_cite );
|
||||
pgm_assert( ! $result_no_cite->is_cited(), 'OpenRouter: not cited when peptiderepo.com absent from text' );
|
||||
prv_assert( ! $result_no_cite->is_cited(), 'OpenRouter: not cited when peptiderepo.com absent from text' );
|
||||
|
||||
// Test: cost calculation from token usage
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$data_cost = [
|
||||
'choices' => [[ 'message' => [ 'content' => 'test' ] ]],
|
||||
'usage' => [ 'total_tokens' => 1000 ],
|
||||
];
|
||||
$result_cost = $or_provider->parse_response( $data_cost );
|
||||
pgm_assert_equals( 1000 * 0.000002, $result_cost->get_cost_usd(), 'OpenRouter: cost from token usage (2$/1M)' );
|
||||
prv_assert_equals( 1000 * 0.000002, $result_cost->get_cost_usd(), 'OpenRouter: cost from token usage (2$/1M)' );
|
||||
|
||||
exit( pgm_test_summary() );
|
||||
exit( prv_test_summary() );
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for the visibility score formula in PGM_Ai_Visibility_Collector.
|
||||
* Tests for the visibility score formula in PRV_Ai_Visibility_Collector.
|
||||
*
|
||||
* Score formula (CONTEXT.md):
|
||||
* base_score = cited_probes / total_probes
|
||||
* position_bonus = Σ(1/our_position for cited) / total_probes
|
||||
* visibility_score = round((base_score + position_bonus) / 2, 4)
|
||||
*
|
||||
* @package PeptideGeoMonitor
|
||||
* @package PrVision
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
echo "=== PGM Score Calculation Tests ===\n";
|
||||
echo "=== PRV Score Calculation Tests ===\n";
|
||||
|
||||
// Instantiate with a null ledger (no DB calls in these tests).
|
||||
$collector = new PGM_Ai_Visibility_Collector( null );
|
||||
$collector = new PRV_Ai_Visibility_Collector( null );
|
||||
|
||||
// ── Test: zero total → score 0 ──────────────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
pgm_assert_equals( 0.0, $collector->compute_score( 0, 0, 0.0 ), 'score: zero total returns 0.0' );
|
||||
prv_test_reset();
|
||||
prv_assert_equals( 0.0, $collector->compute_score( 0, 0, 0.0 ), 'score: zero total returns 0.0' );
|
||||
|
||||
// ── Test: all cited, position 1 ─────────────────────────────────────────
|
||||
|
||||
@@ -30,15 +30,15 @@ pgm_assert_equals( 0.0, $collector->compute_score( 0, 0, 0.0 ), 'score: zero tot
|
||||
// base_score = 10/10 = 1.0
|
||||
// position_bonus = (1+1+1+…)/10 = 10/10 = 1.0
|
||||
// score = (1.0 + 1.0) / 2 = 1.0
|
||||
pgm_test_reset();
|
||||
pgm_assert_equals( 1.0, $collector->compute_score( 10, 10, 10.0 ), 'score: all cited at position 1 → 1.0' );
|
||||
prv_test_reset();
|
||||
prv_assert_equals( 1.0, $collector->compute_score( 10, 10, 10.0 ), 'score: all cited at position 1 → 1.0' );
|
||||
|
||||
// ── Test: none cited ────────────────────────────────────────────────────
|
||||
|
||||
// 10 probes, 0 cited, position_sum=0
|
||||
// base_score = 0, position_bonus = 0 → score = 0
|
||||
pgm_test_reset();
|
||||
pgm_assert_equals( 0.0, $collector->compute_score( 0, 10, 0.0 ), 'score: none cited → 0.0' );
|
||||
prv_test_reset();
|
||||
prv_assert_equals( 0.0, $collector->compute_score( 0, 10, 0.0 ), 'score: none cited → 0.0' );
|
||||
|
||||
// ── Test: half cited at position 2 ──────────────────────────────────────
|
||||
|
||||
@@ -46,9 +46,9 @@ pgm_assert_equals( 0.0, $collector->compute_score( 0, 10, 0.0 ), 'score: none ci
|
||||
// base_score = 5/10 = 0.5
|
||||
// position_bonus = 2.5/10 = 0.25
|
||||
// score = (0.5 + 0.25) / 2 = 0.375
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$score = $collector->compute_score( 5, 10, 2.5 );
|
||||
pgm_assert_equals( 0.375, $score, 'score: half cited at position 2 → 0.375' );
|
||||
prv_assert_equals( 0.375, $score, 'score: half cited at position 2 → 0.375' );
|
||||
|
||||
// ── Test: single probe, cited at position 3 ─────────────────────────────
|
||||
|
||||
@@ -56,25 +56,25 @@ pgm_assert_equals( 0.375, $score, 'score: half cited at position 2 → 0.375' );
|
||||
// base_score = 1.0
|
||||
// position_bonus = 0.3333
|
||||
// score = (1.0 + 0.3333) / 2 ≈ 0.6667 (rounded to 4 decimals)
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$score = $collector->compute_score( 1, 1, 1.0 / 3.0 );
|
||||
pgm_assert_equals( 0.6667, $score, 'score: single probe cited at position 3 → 0.6667' );
|
||||
prv_assert_equals( 0.6667, $score, 'score: single probe cited at position 3 → 0.6667' );
|
||||
|
||||
// ── Test: score is bounded [0, 1] ───────────────────────────────────────
|
||||
|
||||
// Extreme: position_sum could theoretically exceed total but that's logically
|
||||
// impossible with 1-based positions (position_sum ≤ cited_count ≤ total).
|
||||
// Verify edge case: 1 probe, 1 cited, position 1
|
||||
pgm_test_reset();
|
||||
pgm_assert( $collector->compute_score( 1, 1, 1.0 ) <= 1.0, 'score: never exceeds 1.0' );
|
||||
pgm_assert( $collector->compute_score( 0, 10, 0.0 ) >= 0.0, 'score: never below 0.0' );
|
||||
prv_test_reset();
|
||||
prv_assert( $collector->compute_score( 1, 1, 1.0 ) <= 1.0, 'score: never exceeds 1.0' );
|
||||
prv_assert( $collector->compute_score( 0, 10, 0.0 ) >= 0.0, 'score: never below 0.0' );
|
||||
|
||||
// ── Test: precision — 4 decimal places ──────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
prv_test_reset();
|
||||
$score = $collector->compute_score( 3, 7, 1.5 );
|
||||
// base = 3/7 ≈ 0.4286, bonus = 1.5/7 ≈ 0.2143, avg ≈ 0.3214
|
||||
$expected = round( ( 3.0 / 7.0 + 1.5 / 7.0 ) / 2.0, 4 );
|
||||
pgm_assert_equals( $expected, $score, 'score: 4-decimal precision maintained' );
|
||||
prv_assert_equals( $expected, $score, 'score: 4-decimal precision maintained' );
|
||||
|
||||
exit( pgm_test_summary() );
|
||||
exit( prv_test_summary() );
|
||||
|
||||
@@ -2,31 +2,31 @@
|
||||
/**
|
||||
* Tests for uninstall purge: table drop + options deletion.
|
||||
*
|
||||
* Exercises PGM_Table_Manager::drop_table() and verifies the uninstall
|
||||
* Exercises PRV_Table_Manager::drop_table() and verifies the uninstall
|
||||
* script logic (simulated because it requires WP_UNINSTALL_PLUGIN).
|
||||
*
|
||||
* @package PeptideGeoMonitor
|
||||
* @package PrVision
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
echo "=== PGM Uninstall Purge Tests ===\n";
|
||||
echo "=== PRV Uninstall Purge Tests ===\n";
|
||||
|
||||
// ── Mock $wpdb to track DROP calls ──────────────────────────────────────
|
||||
|
||||
$GLOBALS['pgm_test_state']['drop_calls'] = [];
|
||||
$GLOBALS['prv_test_state']['drop_calls'] = [];
|
||||
|
||||
// Extend the stub to record DROP statements.
|
||||
global $wpdb;
|
||||
$wpdb = new class extends stdClass_wpdb {
|
||||
public function query( string $sql ): bool {
|
||||
if ( str_contains( strtoupper( $sql ), 'DROP TABLE' ) ) {
|
||||
$GLOBALS['pgm_test_state']['drop_calls'][] = $sql;
|
||||
$GLOBALS['prv_test_state']['drop_calls'][] = $sql;
|
||||
}
|
||||
if ( str_contains( strtoupper( $sql ), 'DELETE FROM' ) && str_contains( $sql, "pgm\\_" ) ) {
|
||||
$GLOBALS['pgm_test_state']['options_deleted'] = true;
|
||||
if ( str_contains( strtoupper( $sql ), 'DELETE FROM' ) && str_contains( $sql, "prv\\_" ) ) {
|
||||
$GLOBALS['prv_test_state']['options_deleted'] = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -34,68 +34,68 @@ $wpdb = new class extends stdClass_wpdb {
|
||||
|
||||
// ── Test: drop_table issues DROP TABLE IF EXISTS ─────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['drop_calls'] = [];
|
||||
PGM_Table_Manager::drop_table();
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['drop_calls'] = [];
|
||||
PRV_Table_Manager::drop_table();
|
||||
|
||||
pgm_assert( ! empty( $GLOBALS['pgm_test_state']['drop_calls'] ), 'drop_table: DROP TABLE query executed' );
|
||||
$drop_sql = $GLOBALS['pgm_test_state']['drop_calls'][0] ?? '';
|
||||
pgm_assert( str_contains( strtoupper( $drop_sql ), 'DROP TABLE IF EXISTS' ), 'drop_table: uses DROP TABLE IF EXISTS' );
|
||||
pgm_assert( str_contains( $drop_sql, 'pgm_ai_visibility' ), 'drop_table: targets pgm_ai_visibility table' );
|
||||
prv_assert( ! empty( $GLOBALS['prv_test_state']['drop_calls'] ), 'drop_table: DROP TABLE query executed' );
|
||||
$drop_sql = $GLOBALS['prv_test_state']['drop_calls'][0] ?? '';
|
||||
prv_assert( str_contains( strtoupper( $drop_sql ), 'DROP TABLE IF EXISTS' ), 'drop_table: uses DROP TABLE IF EXISTS' );
|
||||
prv_assert( str_contains( $drop_sql, 'prv_ai_visibility' ), 'drop_table: targets prv_ai_visibility table' );
|
||||
|
||||
// ── Test: create_table sets the schema_version option ────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
PGM_Table_Manager::create_table();
|
||||
$schema_ver = get_option( 'pgm_schema_version' );
|
||||
pgm_assert_equals( PGM_SCHEMA_VERSION, $schema_ver, 'create_table: pgm_schema_version option set after create' );
|
||||
prv_test_reset();
|
||||
PRV_Table_Manager::create_table();
|
||||
$schema_ver = get_option( 'prv_schema_version' );
|
||||
prv_assert_equals( PRV_SCHEMA_VERSION, $schema_ver, 'create_table: prv_schema_version option set after create' );
|
||||
|
||||
// ── Test: get_table_name returns prefixed name ───────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$table = PGM_Table_Manager::get_table_name();
|
||||
pgm_assert_equals( 'wp_pgm_ai_visibility', $table, 'get_table_name: returns wp_ prefixed table name' );
|
||||
prv_test_reset();
|
||||
$table = PRV_Table_Manager::get_table_name();
|
||||
prv_assert_equals( 'wp_prv_ai_visibility', $table, 'get_table_name: returns wp_ prefixed table name' );
|
||||
|
||||
// ── Test: seed_defaults writes expected option keys ──────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
PGM_Config::seed_defaults();
|
||||
prv_test_reset();
|
||||
PRV_Config::seed_defaults();
|
||||
|
||||
pgm_assert( isset( $GLOBALS['pgm_test_state']['options']['pgm_monthly_budget_usd'] ), 'seed_defaults: pgm_monthly_budget_usd set' );
|
||||
pgm_assert( isset( $GLOBALS['pgm_test_state']['options']['pgm_peptides'] ), 'seed_defaults: pgm_peptides set' );
|
||||
pgm_assert( isset( $GLOBALS['pgm_test_state']['options']['pgm_prompt_intents'] ), 'seed_defaults: pgm_prompt_intents set' );
|
||||
pgm_assert( isset( $GLOBALS['pgm_test_state']['options']['pgm_models'] ), 'seed_defaults: pgm_models set' );
|
||||
prv_assert( isset( $GLOBALS['prv_test_state']['options']['prv_monthly_budget_usd'] ), 'seed_defaults: prv_monthly_budget_usd set' );
|
||||
prv_assert( isset( $GLOBALS['prv_test_state']['options']['prv_peptides'] ), 'seed_defaults: prv_peptides set' );
|
||||
prv_assert( isset( $GLOBALS['prv_test_state']['options']['prv_prompt_intents'] ), 'seed_defaults: prv_prompt_intents set' );
|
||||
prv_assert( isset( $GLOBALS['prv_test_state']['options']['prv_models'] ), 'seed_defaults: prv_models set' );
|
||||
|
||||
// ── Test: seed_defaults does not overwrite existing values ───────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$GLOBALS['pgm_test_state']['options']['pgm_monthly_budget_usd'] = 99.0;
|
||||
PGM_Config::seed_defaults();
|
||||
pgm_assert_equals( 99.0, $GLOBALS['pgm_test_state']['options']['pgm_monthly_budget_usd'], 'seed_defaults: does not overwrite existing pgm_monthly_budget_usd' );
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options']['prv_monthly_budget_usd'] = 99.0;
|
||||
PRV_Config::seed_defaults();
|
||||
prv_assert_equals( 99.0, $GLOBALS['prv_test_state']['options']['prv_monthly_budget_usd'], 'seed_defaults: does not overwrite existing prv_monthly_budget_usd' );
|
||||
|
||||
// ── Test: default budget is PGM_DEFAULT_MONTHLY_BUDGET_USD ──────────────
|
||||
// ── Test: default budget is PRV_DEFAULT_MONTHLY_BUDGET_USD ──────────────
|
||||
|
||||
pgm_test_reset();
|
||||
PGM_Config::seed_defaults();
|
||||
pgm_assert_equals( PGM_DEFAULT_MONTHLY_BUDGET_USD, $GLOBALS['pgm_test_state']['options']['pgm_monthly_budget_usd'], 'seed_defaults: default budget = PGM_DEFAULT_MONTHLY_BUDGET_USD (5.0)' );
|
||||
prv_test_reset();
|
||||
PRV_Config::seed_defaults();
|
||||
prv_assert_equals( PRV_DEFAULT_MONTHLY_BUDGET_USD, $GLOBALS['prv_test_state']['options']['prv_monthly_budget_usd'], 'seed_defaults: default budget = PRV_DEFAULT_MONTHLY_BUDGET_USD (5.0)' );
|
||||
|
||||
// ── Test: default peptide count is 12 ───────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$peptides = PGM_Config::get_peptides();
|
||||
pgm_assert_equals( 12, count( $peptides ), 'get_peptides: default seed has 12 peptides' );
|
||||
prv_test_reset();
|
||||
$peptides = PRV_Config::get_peptides();
|
||||
prv_assert_equals( 12, count( $peptides ), 'get_peptides: default seed has 12 peptides' );
|
||||
|
||||
// ── Test: default prompt intent count is 3 ──────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$intents = PGM_Config::get_prompt_intents();
|
||||
pgm_assert_equals( 3, count( $intents ), 'get_prompt_intents: default seed has 3 intents' );
|
||||
prv_test_reset();
|
||||
$intents = PRV_Config::get_prompt_intents();
|
||||
prv_assert_equals( 3, count( $intents ), 'get_prompt_intents: default seed has 3 intents' );
|
||||
|
||||
// ── Test: default model count is 3 ──────────────────────────────────────
|
||||
|
||||
pgm_test_reset();
|
||||
$models = PGM_Config::get_models();
|
||||
pgm_assert_equals( 3, count( $models ), 'get_models: default seed has 3 models' );
|
||||
pgm_assert( in_array( 'perplexity/sonar', $models, true ), 'get_models: perplexity/sonar in default models' );
|
||||
prv_test_reset();
|
||||
$models = PRV_Config::get_models();
|
||||
prv_assert_equals( 3, count( $models ), 'get_models: default seed has 3 models' );
|
||||
prv_assert( in_array( 'perplexity/sonar', $models, true ), 'get_models: perplexity/sonar in default models' );
|
||||
|
||||
exit( pgm_test_summary() );
|
||||
exit( prv_test_summary() );
|
||||
|
||||
Reference in New Issue
Block a user