v0.3.2 — adopt estate CI: PHPUnit suite + reusable pipeline + governance workflows
- Convert 17 hand-rolled tests to PHPUnit TestCases (tests: stubs pattern) P0 security tests preserved: key-leak/encryption (KeyStoreTest), capture-allowlist/executor-path sentinel (CaptureWriterTest) - Add phpunit.xml.dist + update tests/bootstrap.php (Composer autoloader first) - Add phpunit/phpunit ^9.6 + yoast/phpunit-polyfills ^2.0 to require-dev - composer test -> vendor/bin/phpunit --configuration phpunit.xml.dist - ci.yml: thin caller of peptide-e2e reusable CI (tests: stubs, has_js: true, workflow_call trigger, permissions: contents: write) - deploy.yml: estate pattern caller of peptide-e2e deploy-app.yml@main (target_path: wp-content/plugins/pr-vision, gated on reusable CI) Pull-deploy on Hostinger stays as break-glass - Add cto-review.yml (Haiku-only, A/B panel dropped 2026-06-12) - Add main-push-audit.yml (direct-push tripwire) Agent-Session: claude-adopt-ci-20260616
This commit is contained in:
91
tests/unit/ProviderParsingTest.php
Normal file
91
tests/unit/ProviderParsingTest.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for provider response parsing (Perplexity + OpenRouter).
|
||||
*
|
||||
* @package PrVision
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers PRV_Perplexity_Provider
|
||||
* @covers PRV_OpenRouter_Provider
|
||||
*/
|
||||
class ProviderParsingTest extends TestCase {
|
||||
|
||||
private PRV_Perplexity_Provider $perplexity;
|
||||
private PRV_OpenRouter_Provider $openrouter;
|
||||
|
||||
protected function setUp(): void {
|
||||
prv_test_reset();
|
||||
$detector = new PRV_Citation_Detector();
|
||||
$this->perplexity = new PRV_Perplexity_Provider( null, $detector );
|
||||
$this->openrouter = new PRV_OpenRouter_Provider( 'openai/gpt-4o-search-preview', null, $detector );
|
||||
}
|
||||
|
||||
public function test_perplexity_cited_via_citations_array(): void {
|
||||
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'BPC-157 is a peptide.' ] ] ], 'citations' => [ 'https://peptiderepo.com/bpc-157/', 'https://examine.com/bpc-157' ], 'usage' => [ 'total_tokens' => 500 ] ];
|
||||
$result = $this->perplexity->parse_response( $data );
|
||||
|
||||
$this->assertTrue( $result->is_cited() );
|
||||
$this->assertSame( 1, $result->get_our_position() );
|
||||
$this->assertCount( 2, $result->get_source_domains() );
|
||||
$this->assertSame( 500 * 0.000001, $result->get_cost_usd() );
|
||||
}
|
||||
|
||||
public function test_perplexity_not_cited_empty_citations(): void {
|
||||
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'Info here.' ] ] ], 'citations' => [], 'usage' => [ 'total_tokens' => 200 ] ];
|
||||
$result = $this->perplexity->parse_response( $data );
|
||||
|
||||
$this->assertFalse( $result->is_cited() );
|
||||
$this->assertNull( $result->get_our_position() );
|
||||
}
|
||||
|
||||
public function test_perplexity_excerpt_truncated_to_500_chars(): void {
|
||||
$data = [ 'choices' => [ [ 'message' => [ 'content' => str_repeat( 'a', 600 ) ] ] ], 'citations' => [] ];
|
||||
$result = $this->perplexity->parse_response( $data );
|
||||
$this->assertSame( 500, mb_strlen( $result->get_raw_excerpt() ) );
|
||||
}
|
||||
|
||||
public function test_perplexity_object_style_citations(): void {
|
||||
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'answer' ] ] ], 'citations' => [ [ 'url' => 'https://peptiderepo.com/mk-677/' ], [ 'url' => 'https://examine.com/mk677' ] ] ];
|
||||
$result = $this->perplexity->parse_response( $data );
|
||||
|
||||
$this->assertTrue( $result->is_cited() );
|
||||
$this->assertSame( 1, $result->get_our_position() );
|
||||
}
|
||||
|
||||
public function test_perplexity_fallback_cost_when_no_usage(): void {
|
||||
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'answer' ] ] ], 'citations' => [] ];
|
||||
$result = $this->perplexity->parse_response( $data );
|
||||
$this->assertSame( PRV_Perplexity_Provider::ESTIMATED_COST_PER_PROBE, $result->get_cost_usd() );
|
||||
}
|
||||
|
||||
public function test_openrouter_annotations_path(): void {
|
||||
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'BPC-157 reconstitution.', 'annotations' => [ [ 'url_citation' => [ 'url' => 'https://peptiderepo.com/bpc-157-reconstitution/' ] ], [ 'url_citation' => [ 'url' => 'https://examine.com/bpc-157' ] ] ] ] ] ], 'usage' => [ 'total_tokens' => 300 ] ];
|
||||
$result = $this->openrouter->parse_response( $data );
|
||||
|
||||
$this->assertTrue( $result->is_cited() );
|
||||
$this->assertSame( 1, $result->get_our_position() );
|
||||
}
|
||||
|
||||
public function test_openrouter_regex_fallback(): void {
|
||||
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'See https://peptiderepo.com/tb-500/ and https://examine.com/tb-500 for details.' ] ] ], 'usage' => [ 'total_tokens' => 150 ] ];
|
||||
$result = $this->openrouter->parse_response( $data );
|
||||
$this->assertTrue( $result->is_cited() );
|
||||
}
|
||||
|
||||
public function test_openrouter_not_cited(): void {
|
||||
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'Some response without our domain.' ] ] ] ];
|
||||
$result = $this->openrouter->parse_response( $data );
|
||||
$this->assertFalse( $result->is_cited() );
|
||||
}
|
||||
|
||||
public function test_openrouter_cost_from_token_usage(): void {
|
||||
$data = [ 'choices' => [ [ 'message' => [ 'content' => 'test' ] ] ], 'usage' => [ 'total_tokens' => 1000 ] ];
|
||||
$result = $this->openrouter->parse_response( $data );
|
||||
$this->assertSame( 1000 * 0.000002, $result->get_cost_usd() );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user