File Coverage

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


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