1#!perl
2
3use warnings;
4use strict;
5
6use Test::More tests => 19;
7
8use lib 't';
9use Util;
10
11prep_environment();
12
13# Checks also beginning of file.
14BEFORE: {
15    my @expected = line_split( <<'HERE' );
16I met a traveller from an antique land
17--
18Stand in the desert... Near them, on the sand,
19Half sunk, a shattered visage lies, whose frown,
20HERE
21
22    my $regex = 'a';
23    my @files = qw( t/text/ozymandias.txt );
24    my @args = ( '-w', '-B1', $regex );
25
26    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex - before" );
27}
28
29BEFORE_WITH_LINE_NO: {
30    my $target_file = reslash( 't/text/ozymandias.txt' );
31    my @expected = line_split( <<"HERE" );
32$target_file-1-I met a traveller from an antique land
33$target_file-2-Who said: Two vast and trunkless legs of stone
34$target_file:3:Stand in the desert... Near them, on the sand,
35--
36$target_file-12-Nothing beside remains. Round the decay
37$target_file-13-Of that colossal wreck, boundless and bare
38$target_file:14:The lone and level sands stretch far away.
39HERE
40
41    my $regex = 'sand';
42    my @files = qw( t/text/ozymandias.txt t/text/bill-of-rights.txt );  # So we don't pick up constitution.txt
43    my @args = ( '--sort-files', '-B2', $regex );
44
45    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex - before with line numbers" );
46}
47
48# Checks also end of file.
49AFTER: {
50    my @expected = line_split( <<'HERE' );
51The lone and level sands stretch far away.
52HERE
53
54    my $regex = 'sands';
55    my @files = qw( t/text/ozymandias.txt );
56    my @args = ( '-A2', $regex );
57
58    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex - after" );
59}
60
61# Context defaults to 2.
62CONTEXT_DEFAULT: {
63    my @expected = line_split( <<'HERE' );
64"Yes,"I said, "let us be gone."
65
66"For the love of God, Montresor!"
67
68"Yes," I said, "for the love of God!"
69HERE
70
71    my $regex = 'Montresor';
72    my @files = qw( t/text/amontillado.txt );
73    my @args = ( '-w', '-C', $regex );
74
75    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex - context defaults to 2" );
76}
77
78# Try context 1.
79CONTEXT_ONE: {
80    my @expected = line_split( <<'HERE' );
81
82"For the love of God, Montresor!"
83HERE
84
85    push( @expected, '' );  # Since split eats the last line.
86
87    my $regex = 'Montresor';
88    my @files = qw( t/text/amontillado.txt );
89    my @args = ( '-w', '-C', 1, $regex );
90
91    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex - context=1" );
92}
93
94# --context=0 means no context.
95CONTEXT_ONE: {
96    my @expected = line_split( <<'HERE' );
97"For the love of God, Montresor!"
98HERE
99
100    my $regex = 'Montresor';
101    my @files = qw( t/text/amontillado.txt );
102    my @args = ( '-w', '-C', 0, $regex );
103
104    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex - context=0" );
105}
106
107# -1 must not stop the ending context from displaying.
108CONTEXT_DEFAULT: {
109    my @expected = line_split( <<'HERE' );
110or prohibiting the free exercise thereof; or abridging the freedom of
111speech, or of the press; or the right of the people peaceably to assemble,
112and to petition the Government for a redress of grievances.
113HERE
114
115    my $regex = 'right';
116    my @files = qw( t/text/bill-of-rights.txt );
117    my @args = ( '-1', '-C1', $regex );
118
119    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex with -1" );
120}
121
122# -C with overlapping contexts (adjacent lines)
123CONTEXT_OVERLAPPING: {
124    my @expected = line_split( <<'HERE' );
125This is line 03
126This is line 04
127This is line 05
128This is line 06
129This is line 07
130This is line 08
131HERE
132
133    my $regex = '05|06';
134    my @files = qw( t/text/numbered-text.txt );
135    my @args = ( '-C', $regex );
136
137    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex with overlapping contexts" );
138}
139
140# -C with contexts that touch.
141CONTEXT_ADJACENT: {
142    my @expected = line_split( <<'HERE' );
143This is line 01
144This is line 02
145This is line 03
146This is line 04
147This is line 05
148This is line 06
149This is line 07
150This is line 08
151This is line 09
152This is line 10
153HERE
154
155    my $regex = '03|08';
156    my @files = qw( t/text/numbered-text.txt );
157    my @args = ( '-C', $regex );
158
159    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex with contexts that touch" );
160}
161
162# -C with contexts that just don't touch.
163CONTEXT_NONADJACENT: {
164    my @expected = line_split( <<'HERE' );
165This is line 01
166This is line 02
167This is line 03
168This is line 04
169This is line 05
170--
171This is line 07
172This is line 08
173This is line 09
174This is line 10
175This is line 11
176HERE
177
178    my $regex = '03|09';
179    my @files = qw( t/text/numbered-text.txt );
180    my @args = ( '-C', $regex );
181
182    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex with contexts that just don't touch" );
183}
184
185CONTEXT_OVERLAPPING_COLOR: {
186    my $match_start = "\e[30;43m";
187    my $match_end   = "\e[0m";
188    my $line_end    = "\e[0m\e[K";
189
190    my @expected = line_split( <<"HERE" );
191This is line 03
192This is line 04
193This is line ${match_start}05${match_end}${line_end}
194This is line ${match_start}06${match_end}${line_end}
195This is line 07
196This is line 08
197HERE
198
199    my $regex = '05|06';
200    my @files = qw( t/text/numbered-text.txt );
201    my @args = ( '--color', '-C', $regex );
202
203    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex with overlapping contexts" );
204}
205
206CONTEXT_OVERLAPPING_COLOR_BEFORE: {
207    my $match_start = "\e[30;43m";
208    my $match_end   = "\e[0m";
209    my $line_end    = "\e[0m\e[K";
210
211    my @expected = line_split( <<"HERE" );
212This is line 03
213This is line 04
214This is line ${match_start}05${match_end}${line_end}
215This is line ${match_start}06${match_end}${line_end}
216HERE
217
218    my $regex = '05|06';
219    my @files = qw( t/text/numbered-text.txt );
220    my @args = ( '--color', '-B2', $regex );
221
222    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex with overlapping contexts" );
223}
224
225CONTEXT_OVERLAPPING_COLOR_AFTER: {
226    my $match_start = "\e[30;43m";
227    my $match_end   = "\e[0m";
228    my $line_end    = "\e[0m\e[K";
229
230    my @expected = line_split( <<"HERE" );
231This is line ${match_start}05${match_end}${line_end}
232This is line ${match_start}06${match_end}${line_end}
233This is line 07
234This is line 08
235HERE
236
237    my $regex = '05|06';
238    my @files = qw( t/text/numbered-text.txt );
239    my @args = ( '--color', '-A2', $regex );
240
241    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex with overlapping contexts" );
242}
243
244# -m3 should work properly and show only 3 matches with correct context
245#    even though there is a 4th match in the after context of the third match
246#    ("ratifying" in the last line)
247CONTEXT_MAX_COUNT: {
248    my @expected = line_split( <<'HERE' );
249ratified by the Legislatures of three fourths of the several States, or
250by Conventions in three fourths thereof, as the one or the other Mode of
251Ratification may be proposed by the Congress; Provided that no Amendment
252which may be made prior to the Year One thousand eight hundred and eight
253--
254The Ratification of the Conventions of nine States, shall be sufficient
255for the Establishment of this Constitution between the States so ratifying
256HERE
257
258    my $regex = 'ratif';
259
260    my @files = qw( t/text/constitution.txt );
261    my @args = ( '-i', '-m3', '-A1', $regex );
262
263    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex with -m3" );
264}
265
266# Highlighting works with context.
267HIGHLIGHTING: {
268    my @ack_args = qw( wretch -i -C5 --color );
269    my @results = pipe_into_ack( 't/text/raven.txt', @ack_args );
270    my @escaped_lines = grep { /\e/ } @results;
271    is( scalar @escaped_lines, 1, 'Only one line highlighted' );
272    is( scalar @results, 11, 'Expecting altogether 11 lines back' );
273}
274
275# Grouping works with context (single file).
276GROUPING_SINGLE_FILE: {
277    my $target_file = reslash( 't/etc/shebang.py.xxx' );
278    my @expected = line_split( <<"HERE" );
279$target_file
2801:#!/usr/bin/python
281HERE
282
283    my $regex = 'python';
284    my @args = ( '-t', 'python', '--group', '-C', $regex );
285
286    ack_lists_match( [ @args ], \@expected, "Looking for $regex in Python files with grouping" );
287}
288
289
290# Grouping works with context and multiple files.
291# i.e. a separator line between different matches in the same file and no separator between files
292GROUPING_MULTIPLE_FILES: {
293    my @expected = line_split( <<"HERE" );
294t/text/amontillado.txt
295258-As I said these words I busied myself among the pile of bones of
296259:which I have before spoken. Throwing them aside, I soon uncovered
297
298t/text/raven.txt
29931-But the silence was unbroken, and the stillness gave no token,
30032:And the only word there spoken was the whispered word, "Lenore?"
301--
30270-
30371:Startled at the stillness broken by reply so aptly spoken,
304--
305114-"Get thee back into the tempest and the Night's Plutonian shore!
306115:Leave no black plume as a token of that lie thy soul hath spoken!
307HERE
308
309    my $regex = 'spoken';
310    my @files = qw( t/text/ );
311    my @args = ( '--group', '-B1', '--sort-files', $regex );
312
313    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex in multiple files with grouping" );
314}
315
316# See https://github.com/beyondgrep/ack2/issues/326 and links there for details.
317WITH_COLUMNS_AND_CONTEXT: {
318    my @files = qw( t/text/ );
319    my @expected = line_split( <<'HERE' );
320t/text/bill-of-rights.txt-1-# Amendment I
321t/text/bill-of-rights.txt-2-
322t/text/bill-of-rights.txt-3-Congress shall make no law respecting an establishment of religion,
323t/text/bill-of-rights.txt:4:60:or prohibiting the free exercise thereof; or abridging the freedom of
324t/text/bill-of-rights.txt-5-speech, or of the press; or the right of the people peaceably to assemble,
325t/text/bill-of-rights.txt-6-and to petition the Government for a redress of grievances.
326t/text/bill-of-rights.txt-7-
327t/text/bill-of-rights.txt-8-# Amendment II
328t/text/bill-of-rights.txt-9-
329--
330t/text/gettysburg.txt-18-fought here have thus far so nobly advanced. It is rather for us to be
331t/text/gettysburg.txt-19-here dedicated to the great task remaining before us -- that from these
332t/text/gettysburg.txt-20-honored dead we take increased devotion to that cause for which they gave
333t/text/gettysburg.txt-21-the last full measure of devotion -- that we here highly resolve that
334t/text/gettysburg.txt-22-these dead shall not have died in vain -- that this nation, under God,
335t/text/gettysburg.txt:23:27:shall have a new birth of freedom -- and that government of the people,
336t/text/gettysburg.txt-24-by the people, for the people, shall not perish from the earth.
337HERE
338
339    my $regex = 'freedom';
340    my @args = ( '--column', '-C5', '-H', '--sort-files', $regex );
341
342    ack_lists_match( [ @args, @files ], \@expected, "Looking for $regex" );
343}
344
345done_testing();
346
347exit 0;
348