<?php
// Standalone check for the first-item time ceiling: php -d zend.assertions=1 tests/first-item-budget.php
// No WordPress, no framework. It fails if one slow page can fail a run on a server that allows it.

function __( $s, $d = null ) { return $s; }
function apply_filters( $tag, $value ) { return $value; }
class Meow_WPMC_Transient_Exception extends Exception {}
require __DIR__ . '/../classes/core.php';

class Probe extends Meow_WPMC_Core {
	public $is_cli = false;
	function log( $data = null, $force = false ) {}
}

// A core whose request started $elapsed seconds ago, on a server allowing $max_execution seconds.
function probe( $max_execution, $elapsed, $items_checked, $request_items = null ) {
	ini_set( 'max_execution_time', (string) $max_execution );
	ini_set( 'memory_limit', '-1' );
	$p = ( new ReflectionClass( 'Probe' ) )->newInstanceWithoutConstructor();
	foreach ( array( 'request_start_time' => microtime( true ) - $elapsed, 'start_time' => microtime( true ) - $elapsed, 'items_checked' => $items_checked, 'request_items' => $request_items ?? $items_checked ) as $name => $value ) {
		$property = new ReflectionProperty( 'Meow_WPMC_Core', $name );
		$property->setAccessible( true );
		$property->setValue( $p, $value );
	}
	return $p;
}

function stops( $p ) {
	try { $p->timeout_check(); return false; }
	catch ( Meow_WPMC_Transient_Exception $e ) { return true; }
}

// The case from the field: a generous server, the first page of the batch took 52s.
assert( !stops( probe( 43300, 52, 0 ) ), 'first item keeps going while the server allows it' );

// The same 52s on a later item still hands back, so batches stay short.
assert( stops( probe( 43300, 52, 1 ) ), 'later items still yield on the work budget' );

// The ceiling stays under the client's 120s patience, or the browser hangs up first.
assert( stops( probe( 43300, 115, 0 ) ), 'first item stops before the client gives up' );

// A 30s server gets no extension: its first item stops where it always did.
assert( stops( probe( 30, 25, 0 ) ), 'no ceiling beyond what the server allows' );

// The check between items always uses the work budget, so the run still yields there.
assert( probe( 43300, 30, 0 )->timeout_should_yield(), 'yield between items is unchanged' );

// A request can run several batches: the first item of a later one is not the first of the request.
assert( stops( probe( 43300, 52, 0, 5 ) ), 'a later batch in the same request gets no extended ceiling' );

echo "ok\n";
