Files
prautoblogger/tests/unit/Core/CostTrackerTest.php
peptiderepo 49d094b4f8 Refactor: Split cost reporting into separate class
Extract read-only reporting methods from PRAutoBlogger_Cost_Tracker into a new
PRAutoBlogger_Cost_Reporter class. This reduces Cost_Tracker from 313 to 206
lines and Reporter to 141 lines, both under the 300-line cap.

Changed files:
- Create includes/core/class-cost-reporter.php with reporting methods:
  * get_monthly_spend(): float
  * get_daily_spend(int $days = 30): array
  * get_spend_by_stage(string $start_date, string $end_date): array
  * get_budget_utilization(): float

- Update includes/core/class-cost-tracker.php:
  * Remove reporting methods
  * Update is_budget_exceeded() and would_exceed_budget() to use Cost_Reporter
  * Keep get_current_run_cost() (tracks current pipeline run only)
  * Add @see cross-reference to Cost_Reporter

- Update templates and admin classes to instantiate Cost_Reporter:
  * templates/admin/metrics-page.php
  * templates/admin/settings-page.php
  * includes/admin/class-admin-notices.php
  * includes/admin/class-dashboard-widget.php

- Split tests/unit/Core/CostTrackerTest.php:
  * Create tests/unit/Core/CostReporterTest.php for reporter methods
  * Keep run ID and budget enforcement tests in CostTrackerTest

Autoloader automatically discovers PRAutoBlogger_Cost_Reporter class.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 20:27:57 +07:00

117 lines
3.4 KiB
PHP

<?php
/**
* Tests for PRAutoBlogger_Cost_Tracker.
*
* Validates run ID management, monthly spend, budget limits,
* current run cost, and cost retrieval methods.
*
* @package PRAutoBlogger\Tests\Core
*/
namespace PRAutoBlogger\Tests\Core;
use PRAutoBlogger\Tests\BaseTestCase;
use Brain\Monkey\Functions;
class CostTrackerTest extends BaseTestCase {
/**
* @var \PHPUnit\Framework\MockObject\MockObject Mock $wpdb instance.
*/
private $wpdb;
protected function setUp(): void {
parent::setUp();
$this->wpdb = $this->create_mock_wpdb();
$GLOBALS['wpdb'] = $this->wpdb;
// CostTracker methods call get_option for budget settings.
$this->stub_get_option( [
'prautoblogger_monthly_budget_usd' => '50.00',
] );
// Stub current_time used in date-based queries.
$this->stub_current_time( '2026-04-12 10:00:00' );
}
protected function tearDown(): void {
unset( $GLOBALS['wpdb'] );
parent::tearDown();
}
/**
* Test set_run_id and get_run_id.
*/
public function test_set_and_get_run_id(): void {
$tracker = new \PRAutoBlogger_Cost_Tracker();
$tracker->set_run_id( 'run_abc123' );
$this->assertSame( 'run_abc123', $tracker->get_run_id() );
}
/**
* Test get_run_id returns null when not set.
*/
public function test_get_run_id_returns_null_when_not_set(): void {
$tracker = new \PRAutoBlogger_Cost_Tracker();
$this->assertNull( $tracker->get_run_id() );
}
/**
* Test is_budget_exceeded returns false by default.
*/
public function test_is_budget_exceeded_returns_false_by_default(): void {
$tracker = new \PRAutoBlogger_Cost_Tracker();
$this->assertFalse( $tracker->is_budget_exceeded() );
}
/**
* Test get_current_run_cost returns float.
*/
public function test_get_current_run_cost_returns_float(): void {
$this->wpdb->method( 'prepare' )->willReturn( 'prepared' );
$this->wpdb->method( 'get_var' )->willReturn( '0.05' );
$tracker = new \PRAutoBlogger_Cost_Tracker();
$tracker->set_run_id( 'run_abc123' );
$cost = $tracker->get_current_run_cost();
$this->assertIsFloat( $cost );
$this->assertGreaterThanOrEqual( 0.0, $cost );
}
/**
* Test log_api_call with mock database.
*/
public function test_log_api_call_interacts_with_database(): void {
$tracker = new \PRAutoBlogger_Cost_Tracker();
$tracker->set_run_id( 'run_test' );
// Allow multiple inserts — log_api_call inserts a generation log row,
// and Logger may also insert an event log row if a warning fires.
$this->wpdb->expects( $this->atLeastOnce() )
->method( 'insert' )
->willReturn( 1 );
// Actual signature: log_api_call(?int $post_id, string $stage,
// string $provider, string $model, int $prompt_tokens,
// int $completion_tokens, string $response_status, string $error_message).
// Use 'openai/gpt-4o' which IS in MODEL_PRICING to avoid unknown-model warnings.
$tracker->log_api_call(
123,
'analysis',
'openrouter',
'openai/gpt-4o',
500,
250
);
// If we get here without exception, the method worked.
$this->assertTrue( true );
}
}