summaryrefslogtreecommitdiff
path: root/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparison.php
blob: a3f511bfcffcfcf051f3db4060455cabaf3ece3e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
<?php

namespace Guzzle\Tests\Http\Message;

use Guzzle\Common\Collection;
use Guzzle\Http\Message\Header\HeaderCollection;

/**
 * Class used to compare HTTP headers using a custom DSL
 */
class HeaderComparison
{
    /**
     * Compare HTTP headers and use special markup to filter values
     * A header prefixed with '!' means it must not exist
     * A header prefixed with '_' means it must be ignored
     * A header value of '*' means anything after the * will be ignored
     *
     * @param array $filteredHeaders Array of special headers
     * @param array $actualHeaders   Array of headers to check against
     *
     * @return array|bool Returns an array of the differences or FALSE if none
     */
    public function compare($filteredHeaders, $actualHeaders)
    {
        $expected = array();
        $ignore = array();
        $absent = array();

        if ($actualHeaders instanceof HeaderCollection) {
            $actualHeaders = $actualHeaders->toArray();
        }

        foreach ($filteredHeaders as $k => $v) {
            if ($k[0] == '_') {
                // This header should be ignored
                $ignore[] = str_replace('_', '', $k);
            } elseif ($k[0] == '!') {
                // This header must not be present
                $absent[] = str_replace('!', '', $k);
            } else {
                $expected[$k] = $v;
            }
        }

        return $this->compareArray($expected, $actualHeaders, $ignore, $absent);
    }

    /**
     * Check if an array of HTTP headers matches another array of HTTP headers while taking * into account as a wildcard
     *
     * @param array            $expected Expected HTTP headers (allows wildcard values)
     * @param array|Collection $actual   Actual HTTP header array
     * @param array            $ignore   Headers to ignore from the comparison
     * @param array            $absent   Array of headers that must not be present
     *
     * @return array|bool Returns an array of the differences or FALSE if none
     */
    public function compareArray(array $expected, $actual, array $ignore = array(), array $absent = array())
    {
        $differences = array();

        // Add information about headers that were present but weren't supposed to be
        foreach ($absent as $header) {
            if ($this->hasKey($header, $actual)) {
                $differences["++ {$header}"] = $actual[$header];
                unset($actual[$header]);
            }
        }

        // Check if expected headers are missing
        foreach ($expected as $header => $value) {
            if (!$this->hasKey($header, $actual)) {
                $differences["- {$header}"] = $value;
            }
        }

        // Flip the ignore array so it works with the case insensitive helper
        $ignore = array_flip($ignore);
        // Allow case-insensitive comparisons in wildcards
        $expected = array_change_key_case($expected);

        // Compare the expected and actual HTTP headers in no particular order
        foreach ($actual as $key => $value) {

            // If this is to be ignored, the skip it
            if ($this->hasKey($key, $ignore)) {
                continue;
            }

            // If the header was not expected
            if (!$this->hasKey($key, $expected)) {
                $differences["+ {$key}"] = $value;
                continue;
            }

            // Check values and take wildcards into account
            $lkey = strtolower($key);
            $pos = is_string($expected[$lkey]) ? strpos($expected[$lkey], '*') : false;

            foreach ((array) $actual[$key] as $v) {
                if (($pos === false && $v != $expected[$lkey]) || $pos > 0 && substr($v, 0, $pos) != substr($expected[$lkey], 0, $pos)) {
                    $differences[$key] = "{$value} != {$expected[$lkey]}";
                }
            }
        }

        return empty($differences) ? false : $differences;
    }

    /**
     * Case insensitive check if an array have a key
     *
     * @param string $key   Key to check
     * @param array  $array Array to check
     *
     * @return bool
     */
    protected function hasKey($key, $array)
    {
        if ($array instanceof Collection) {
            $keys = $array->getKeys();
        } else {
            $keys = array_keys($array);
        }

        foreach ($keys as $k) {
            if (!strcasecmp($k, $key)) {
                return true;
            }
        }

        return false;
    }
}