xref: /PHP-8.4/ext/dom/tests/DOMXPath_quote.phpt (revision 2f9320c0)
1--TEST--
2Test DOMXPath::quote with various inputs
3--EXTENSIONS--
4dom
5--SKIPIF--
6<?php if (!class_exists('DOMXPath')) die('skip DOMXPath not available.'); ?>
7--FILE--
8<?php
9$dom = new DOMDocument();
10$xpath = new DOMXPath($dom);
11
12
13/**
14 * Quote a string for use in an XPath expression.
15 *
16 * Example: $xp->query("//span[contains(text()," . $xp->quote($string) . ")]")
17 *
18 * @param string $string string to quote.
19 * @return string quoted string.
20 */
21function UserlandDOMXPathQuote(string $string): string
22{
23    if (false === \strpos($string, '\'')) {
24        return '\'' . $string . '\'';
25    }
26    if (false === \strpos($string, '"')) {
27        return '"' . $string . '"';
28    }
29    // if the string contains both single and double quotes, construct an
30    // expression that concatenates all non-double-quote substrings with
31    // the quotes, e.g.:
32    //  'foo'"bar => concat("'foo'", '"bar")
33    $sb = [];
34    while ($string !== '') {
35        $bytesUntilSingleQuote = \strcspn($string, '\'');
36        $bytesUntilDoubleQuote = \strcspn($string, '"');
37        $quoteMethod = ($bytesUntilSingleQuote > $bytesUntilDoubleQuote) ? "'" : '"';
38        $bytesUntilQuote = \max($bytesUntilSingleQuote, $bytesUntilDoubleQuote);
39        $sb[] = $quoteMethod . \substr($string, 0, $bytesUntilQuote) . $quoteMethod;
40        $string = \substr($string, $bytesUntilQuote);
41    }
42    $sb = \implode(',', $sb);
43    return 'concat(' . $sb . ')';
44}
45
46
47
48$tests = [
49    '' => "''", // empty string
50    'foo' => "'foo'", // no quotes
51    '"foo' => '\'"foo\'', // double quotes only
52    '\'foo' => '"\'foo"', // single quotes only
53    '\'foo"bar' => 'concat("\'foo",\'"bar\')', // both; double quotes in mid-string
54    '\'foo"bar"baz' => 'concat("\'foo",\'"bar"baz\')', // multiple double quotes in mid-string
55    '\'foo"' => 'concat("\'foo",\'"\')', // string ends with double quotes
56    '\'foo""' => 'concat("\'foo",\'""\')', // string ends with run of double quotes
57    '"\'foo' => 'concat(\'"\',"\'foo")', // string begins with double quotes
58    '""\'foo' => 'concat(\'""\',"\'foo")', // string begins with run of double quotes
59    '\'foo""bar' => 'concat("\'foo",\'""bar\')', // run of double quotes in mid-string
60];
61
62foreach ($tests as $input => $expected) {
63    $result = $xpath->quote($input);
64    if ($result === $expected) {
65        echo "Pass: {$input} => {$result}\n";
66    } else {
67        echo 'Fail: ';
68        var_dump([
69            'input' => $input,
70            'expected' => $expected,
71            'result' => $result,
72            'userland_implementation_result' => UserlandDOMXPathQuote($input),
73        ]);
74    }
75}
76?>
77--EXPECT--
78Pass:  => ''
79Pass: foo => 'foo'
80Pass: "foo => '"foo'
81Pass: 'foo => "'foo"
82Pass: 'foo"bar => concat("'foo",'"bar')
83Pass: 'foo"bar"baz => concat("'foo",'"bar"baz')
84Pass: 'foo" => concat("'foo",'"')
85Pass: 'foo"" => concat("'foo",'""')
86Pass: "'foo => concat('"',"'foo")
87Pass: ""'foo => concat('""',"'foo")
88Pass: 'foo""bar => concat("'foo",'""bar')
89