Passed
Push — 4.x ( db19f6...38fd84 )
by Fabian
04:30
created

Hunk::isSame()   B

Complexity

Conditions 8
Paths 6

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 8

Importance

Changes 0
Metric Value
cc 8
eloc 10
nc 6
nop 1
dl 0
loc 18
ccs 11
cts 11
cp 1
crap 8
rs 8.4444
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the php-merge package.
4
 *
5
 * (c) Fabian Bircher <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
declare(strict_types=1);
12
13
namespace PhpMerge\internal;
14
15
/**
16
 * Class Hunk
17
 *
18
 * This represents a collection of changed lines.
19
 *
20
 * @internal This class is not part of the public api.
21
 */
22
final class Hunk
23
{
24
25
    const ADDED = 1;
26
    const REMOVED = 2;
27
    const REPLACED = 3;
28
29
    /**
30
     * @var int
31
     */
32
    protected $start;
33
    /**
34
     * @var int
35
     */
36
    protected $end;
37
    /**
38
     * @var Line[]
39
     */
40
    protected $lines;
41
    /**
42
     * @var int
43
     */
44
    protected $type;
45
46
    /**
47
     * The Hunk constructor.
48
     *
49
     * @param Line|Line[] $lines
50
     *   The lines belonging to the hunk.
51
     * @param int $type
52
     *   The type of the hunk: Hunk::ADDED Hunk::REMOVED Hunk::REPLACED
53
     * @param int $start
54
     *   The line index where the hunk starts.
55
     * @param int $end
56
     *   The line index where the hunk stops.
57
     */
58 13
    public function __construct($lines, $type, $start, $end = null)
59
    {
60 13
        $this->start = $start;
61 13
        if (is_null($end)) {
62 13
            $end = $start;
63
        }
64 13
        $this->end = $end;
65 13
        if (!is_array($lines)) {
66 13
            $lines = [$lines];
67
        }
68 13
        $this->lines = $lines;
69 13
        $this->type = $type;
70 13
    }
71
72
    /**
73
     * Add a new line to the hunk.
74
     *
75
     * @param \PhpMerge\internal\Line $line
76
     *   The line to add.
77
     */
78 11
    public function addLine(Line $line)
79
    {
80 11
        $this->lines[] = $line;
81 11
        $this->end = $line->getIndex();
82 11
    }
83
84
    /**
85
     * Create an array of hunks out of an array of lines.
86
     *
87
     * @param Line[] $lines
88
     *   The lines of the diff.
89
     * @return Hunk[]
90
     *   The hunks in the lines.
91
     */
92 13
    public static function createArray($lines)
93
    {
94 13
        $op = Line::UNCHANGED;
95 13
        $hunks = [];
96
        /** @var Hunk $current */
97 13
        $current = null;
98 13
        foreach ($lines as $line) {
99 13
            switch ($line->getType()) {
100
                case Line::REMOVED:
101 13
                    if (Line::REMOVED !== $op) {
102
                        // The last line was not removed so we start a new hunk.
103 13
                        $current = new Hunk($line, Hunk::REMOVED, $line->getIndex());
104
                    } else {
105
                        // continue adding the line to the hunk.
106 2
                        $current->addLine($line);
107
                    }
108 13
                    break;
109
                case Line::ADDED:
110 13
                    switch ($op) {
111
                        case Line::REMOVED:
112
                            // The hunk is a replacement.
113 11
                            $current->setType(Hunk::REPLACED);
114 11
                            $current->addLine($line);
115 11
                            break;
116
                        case Line::ADDED:
117 5
                            $current->addLine($line);
118 5
                            break;
119
                        case Line::UNCHANGED:
120
                            // Add a new hunk with the added type.
121 12
                            $current = new Hunk($line, Hunk::ADDED, $line->getIndex());
122 12
                            break;
123
                    }
124 13
                    break;
125
                case Line::UNCHANGED:
126 13
                    if ($current) {
127
                        // The hunk exists so add it to the array.
128 11
                        $hunks[] = $current;
129 11
                        $current = null;
130
                    }
131 13
                    break;
132
            }
133 13
            $op = $line->getType();
134
        }
135 13
        if ($current) {
136
            // The last line was part of a hunk, so add it.
137 9
            $hunks[] = $current;
138
        }
139
140 13
        return $hunks;
141
    }
142
143
    /**
144
     * Get the line index where the hunk starts.
145
     *
146
     * @return int
147
     */
148 12
    public function getStart()
149
    {
150 12
        return $this->start;
151
    }
152
153
    /**
154
     * Get the line index where the hunk ends.
155
     *
156
     * @return int
157
     */
158 7
    public function getEnd()
159
    {
160 7
        return $this->end;
161
    }
162
163
    /**
164
     * Get the type of the hunk.
165
     *
166
     * @return int
167
     */
168 9
    public function getType()
169
    {
170 9
        return $this->type;
171
    }
172
173
    /**
174
     * Get the lines of the hunk.
175
     *
176
     * @return Line[]
177
     */
178 1
    public function getLines()
179
    {
180 1
        return $this->lines;
181
    }
182
183
    /**
184
     * Get the removed lines.
185
     *
186
     * @return Line[]
187
     */
188 2
    public function getRemovedLines()
189
    {
190 2
        return array_values(array_filter(
191 2
            $this->lines,
192 2
            function (Line $line) {
193 2
                return $line->getType() === Line::REMOVED;
194 2
            }
195
        ));
196
    }
197
198
    /**
199
     * Get the added lines.
200
     *
201
     * @return Line[]
202
     */
203 9
    public function getAddedLines()
204
    {
205 9
        return array_values(array_filter(
206 9
            $this->lines,
207 9
            function (Line $line) {
208 9
                return $line->getType() === Line::ADDED;
209 9
            }
210
        ));
211
    }
212
213
    /**
214
     * Get the lines content.
215
     *
216
     * @return string[]
217
     */
218 6
    public function getLinesContent()
219
    {
220 6
        return array_map(
221 6
            function (Line $line) {
222 6
                return $line->getContent();
223 6
            },
224 6
            $this->getAddedLines()
225
        );
226
    }
227
228
    /**
229
     * Test whether the hunk is to be considered for a conflict resolution.
230
     *
231
     * @param int $line
232
     *   The line number in the original text to test.
233
     *
234
     * @return bool
235
     *   Whether the line is affected by the hunk.
236
     */
237 7
    public function isLineNumberAffected($line)
238
    {
239
        // Added lines also affect the ones afterwards in conflict resolution,
240
        // because they are added in between.
241 7
        $bleed = ($this->type === self::ADDED ? 1 : 0);
242
243 7
        return ($line >= $this->start && $line <= $this->end + $bleed);
244
    }
245
246
    /**
247
     * @param \PhpMerge\internal\Hunk|null $hunk
248
     *
249
     * @return bool
250
     */
251 7
    public function hasIntersection(Hunk $hunk = null)
252
    {
253 7
        if (!$hunk) {
254 5
            return false;
255
        }
256 7
        if ($this->type === self::ADDED && $hunk->type === self::ADDED) {
257 1
            return $this->start === $hunk->start;
258
        }
259
260 7
        return $this->isLineNumberAffected($hunk->start) || $this->isLineNumberAffected($hunk->end)
261 7
          || $hunk->isLineNumberAffected($this->start) || $hunk->isLineNumberAffected($this->end);
262
    }
263
264
    /**
265
     * @param \PhpMerge\internal\Hunk|null $other
266
     *
267
     * @return bool
268
     */
269 11
    public function isSame(Hunk $other = null): bool
270
    {
271 11
        if (is_null($other)) {
272 2
            return false;
273
        }
274 11
        if ($this->type !== $other->type || $this->start !== $other->start || $this->end !== $other->end) {
275 7
            return false;
276
        }
277 8
        if (count($this->lines) !== count($other->lines)) {
278 2
            return false;
279
        }
280 8
        foreach ($this->lines as $key => $line) {
281 8
            if (!$line->isSame($other->lines[$key])) {
282 7
                return false;
283
            }
284
        }
285
286 5
        return true;
287
    }
288
289
    /**
290
     * Set the type of the hunk.
291
     *
292
     * @param int $type
293
     */
294 11
    protected function setType($type)
295
    {
296 11
        $this->type = $type;
297 11
    }
298
}
299