File Coverage

blib/lib/Test/BDD/Cucumber/Errors.pm
Criterion Covered Total %
statement 42 42 100.0
branch 2 2 100.0
condition 1 2 50.0
subroutine 4 4 100.0
pod 1 1 100.0
total 50 51 98.0


line stmt bran cond sub pod time code
1             package Test::BDD::Cucumber::Errors;
2             $Test::BDD::Cucumber::Errors::VERSION = '0.84';
3 18     18   144 use strict;
  18         67  
  18         584  
4 18     18   172 use warnings;
  18         60  
  18         8681  
5              
6             require Exporter;
7             our @ISA = qw(Exporter);
8             our @EXPORT_OK = qw(parse_error_from_line);
9              
10             =head1 NAME
11              
12             Test::BDD::Cucumber::Errors - Consistently formatted errors
13              
14             =head1 VERSION
15              
16             version 0.84
17              
18             =head1 DESCRIPTION
19              
20             Consistently formatted errors
21              
22             =head1 NOTE
23              
24             This module is not intended to help throw error classes, simply to provide
25             helpers for consistently formatting certain errors. Most of the errors thrown in
26             practice are errors with the input test scenarios, and it's helpful to have the
27             location of the error and context when debugging those. Perhaps in the future
28             these can return error objects.
29              
30             All current uses (2016-02-09) just pass the results straight to die, so I
31             have decided to UTF8 encode the error message on the basis that this probably
32             constitutes an application boundary.
33              
34             =head1 SYNOPSIS
35              
36             use Test::BDD::Cucumber::Errors qw/parse_error_from_line/;
37              
38             parse_error_from_line(
39             "Your input was bad",
40             $line
41             );
42              
43             =head1 PARSER ERRORS
44              
45             =head2 parse_error_from_line
46              
47             Generates a parser error from a L object, and
48             error reason:
49              
50             parse_error_from_line(
51             "Your input was bad",
52             $line
53             );
54              
55             =cut
56              
57             sub parse_error_from_line {
58 2     2 1 726 my ( $message, $line ) = @_;
59              
60 2         10 my $error = "-- Parse Error --\n\n $message\n";
61 2         6 $error .= " at [%s] line %d\n";
62 2         20 $error .= " thrown by: [%s] line %d\n\n";
63 2         5 $error .= "-- [%s] --\n\n";
64 2         5 $error .= "%s";
65 2         7 $error .= "\n%s\n";
66              
67             # Get the caller data
68 2         12 my ( $caller_filename, $caller_line ) = ( caller() )[ 1, 2 ];
69              
70             # Get the simplistic filename and line number it occurred on
71 2   50     47 my $feature_filename = $line->document->filename || "(no filename)";
72 2         88 my $feature_line = $line->number;
73              
74             # Get the context lines
75 2         48 my ( $start_line, @lines ) =
76             _get_context_range( $line->document, $feature_line );
77              
78 2         56 my $formatted_lines;
79 2         10 for ( 0 .. $#lines ) {
80 10         18 my $actual_line = $start_line + $_;
81 10 100       24 my $mark = ( $feature_line == $actual_line ) ? '*' : '|';
82 10         42 $formatted_lines .=
83             sprintf( "% 3d%s %s\n", $actual_line, $mark, $lines[$_] );
84             }
85              
86 2         30 my $to_return = sprintf( $error,
87             $feature_filename, $feature_line,
88             $caller_filename, $caller_line,
89             $feature_filename, $formatted_lines,
90             ( '-' x ( ( length $feature_filename ) + 8 ) ) );
91              
92 2         43 utf8::encode($to_return);
93 2         32 return $to_return;
94             }
95              
96             sub _get_context_range {
97 10     10   5004 my ( $document, $number ) = @_;
98              
99             # Context range
100 10         19 my $min_range = 1;
101 10         17 my $max_range = ( scalar @{ $document->lines } );
  10         162  
102              
103 10         88 my @range = ( $number - 2, $number - 1, $number, $number + 1, $number + 2 );
104              
105             # Push the range higher if needed
106 10         33 while ( $range[0] < $min_range ) {
107 7         11 @range = map { $_ + 1 } @range;
  35         63  
108             }
109              
110             # Push the range lower if needed
111 10         24 while ( $range[4] > $max_range ) {
112 6         12 @range = map { $_ - 1 } @range;
  30         54  
113             }
114              
115             # Then cut it off
116 10         22 @range = grep { $_ >= $min_range } @range;
  50         95  
117 10         18 @range = grep { $_ <= $max_range } @range;
  50         85  
118              
119             return ( $range[0],
120 10         17 map { $document->lines->[ $_ - 1 ]->raw_content } @range );
  50         1542  
121             }
122              
123             =head1 AUTHOR
124              
125             Peter Sergeant C
126              
127             =head1 LICENSE
128              
129             Copyright 2019-2023, Erik Huelsmann
130             Copyright 2014-2019, Peter Sergeant; Licensed under the same terms as Perl
131              
132             =cut
133              
134             1;