/s'; expect(preg_match($pattern, $source, $match))->toBe(1); $parser = (new \PhpParser\ParserFactory())->createForNewestSupportedVersion(); $statements = $parser->parse('expr; expect($expression)->toBeInstanceOf(\PhpParser\Node\Expr\Print_::class); $encodedCall = $expression->expr; expect($encodedCall)->toBeInstanceOf(\PhpParser\Node\Expr\FuncCall::class); expect($encodedCall->name->toString())->toBe('cacti_js_encode'); $translatedCall = $encodedCall->args[0]->value; expect($translatedCall)->toBeInstanceOf(\PhpParser\Node\Expr\FuncCall::class); expect($translatedCall->name->toString())->toBe('__esc'); // Supply adversarial catalog text to the actual production expression; // neither the translation helper nor the JSON encoder is replaced. $translatedCall->args[0]->value = new \PhpParser\Node\Expr\Variable('catalogMessage'); $printer = new \PhpParser\PrettyPrinter\Standard(); $encoded = eval('return ' . $printer->prettyPrintExpr($encodedCall) . ';'); expect(json_decode($encoded, true, 512, JSON_THROW_ON_ERROR))->toBe(__esc($catalogMessage)); expect($encoded)->not->toContain(''); expect($encoded)->not->toContain("\u{2028}"); expect($encoded)->not->toContain("\u{2029}"); })->with([ ['settings.php', 'permsHeader'], ['settings.php', 'permsMessage'], ['lib/html.php', 'tableConstraints'], ['lib/html.php', 'zoom_outOfRangeMessage'], ])->with([ 'quotes and backslashes' => ["single' double\" backslash\\"], 'script closing text' => [''], 'line terminators' => ["first\nsecond\u{2028}third\u{2029}fourth"], 'HTML entities' => ['" ' caption'], ]);