@@ -10,51 +10,167 @@ defmodule ExCoveralls.Ignore do
10
10
Enum . map ( info , & do_filter / 1 )
11
11
end
12
12
13
+ defmodule State do
14
+ defstruct ignore_mode: :no_ignore ,
15
+ coverage: [ ] ,
16
+ coverage_buffer: [ ] ,
17
+ warnings: [ ] ,
18
+ last_marker_index: nil
19
+ end
20
+
13
21
defp do_filter ( % { name: name , source: source , coverage: coverage } ) do
14
- lines = String . split ( source , "\n " )
15
- list = Enum . zip ( lines , coverage )
16
- |> Enum . map_reduce ( :no_ignore , & check_and_swap / 2 )
17
- |> elem ( 0 )
18
- |> List . zip
19
- |> Enum . map ( & Tuple . to_list ( & 1 ) )
22
+ source_lines = String . split ( source , "\n " )
20
23
21
- [ source , coverage ] = parse_filter_list ( list )
22
- % { name: name , source: source , coverage: coverage }
23
- end
24
+ processing_result =
25
+ Enum . zip ( source_lines , coverage )
26
+ |> Enum . with_index ( )
27
+ |> Enum . reduce ( % State { } , & process_line / 2 )
28
+ |> process_end_of_file ( )
24
29
25
- defp check_and_swap ( { line , coverage } , ignore ) do
26
- {
27
- coverage_for_line ( { line , coverage } , ignore ) ,
28
- ignore_next? ( line , ignore )
29
- }
30
+ updated_coverage = processing_result . coverage |> List . flatten ( ) |> Enum . reverse ( )
31
+ warnings = Enum . sort_by ( processing_result . warnings , & elem ( & 1 , 0 ) )
32
+ % { name: name , source: source , coverage: updated_coverage , warnings: warnings }
30
33
end
31
34
32
- defp parse_filter_list ( [ ] ) , do: [ "" , [ ] ]
33
- defp parse_filter_list ( [ lines , coverage ] ) , do: [ Enum . join ( lines , "\n " ) , coverage ]
34
-
35
- defp coverage_for_line ( { line , coverage } , ignore ) do
36
- if ignore == :no_ignore do
37
- { line , coverage }
38
- else
39
- { line , nil }
35
+ defp process_line ( { { source_line , coverage_line } , index } , state ) do
36
+ case detect_ignore_marker ( source_line ) do
37
+ :none -> process_regular_line ( coverage_line , index , state )
38
+ :start -> process_start_marker ( coverage_line , index , state )
39
+ :stop -> process_stop_marker ( coverage_line , index , state )
40
+ :next_line -> process_next_line_marker ( coverage_line , index , state )
40
41
end
41
42
end
42
43
43
- defp ignore_next? ( line , ignore ) do
44
+ defp detect_ignore_marker ( line ) do
44
45
case Regex . run ( ~r/ coveralls-ignore-(start|stop|next-line)/ , line , capture: :all_but_first ) do
45
- [ "start" ] -> :ignore_block
46
- [ "stop" ] -> :no_ignore
47
- [ "next-line" ] ->
48
- case ignore do
49
- :ignore_block -> ignore
50
- _sth -> :ignore_line
51
- end
52
- _sth ->
53
- case ignore do
54
- :ignore_line -> :no_ignore
55
- _sth -> ignore
56
- end
46
+ [ "start" ] -> :start
47
+ [ "stop" ] -> :stop
48
+ [ "next-line" ] -> :next_line
49
+ _sth -> :none
57
50
end
58
51
end
59
52
53
+ defp process_regular_line (
54
+ coverage_line ,
55
+ _index ,
56
+ state = % { ignore_mode: :no_ignore , coverage_buffer: [ ] }
57
+ ) do
58
+ % { state | coverage: [ coverage_line | state . coverage ] }
59
+ end
60
+
61
+ defp process_regular_line ( _coverage_line , _index , state = % { ignore_mode: :ignore_line } ) do
62
+ % { state | ignore_mode: :no_ignore , coverage: [ nil | state . coverage ] }
63
+ end
64
+
65
+ defp process_regular_line ( _coverage_line , _index , state = % { ignore_mode: :ignore_block } ) do
66
+ % { state | coverage: [ nil | state . coverage ] }
67
+ end
68
+
69
+ defp process_start_marker (
70
+ _coverage_line ,
71
+ index ,
72
+ state = % { ignore_mode: :no_ignore }
73
+ ) do
74
+ % {
75
+ state
76
+ | ignore_mode: :ignore_block ,
77
+ coverage: [ nil | state . coverage ] ,
78
+ last_marker_index: index
79
+ }
80
+ end
81
+
82
+ defp process_start_marker ( _coverage_line , index , state = % { ignore_mode: :ignore_block } ) do
83
+ warning = { index , "unexpected ignore-start or missing previous ignore-stop" }
84
+
85
+ % {
86
+ state
87
+ | coverage: [ nil | state . coverage ] ,
88
+ warnings: [ warning | state . warnings ] ,
89
+ last_marker_index: index
90
+ }
91
+ end
92
+
93
+ defp process_start_marker ( _coverage_line , index , state = % { ignore_mode: :ignore_line } ) do
94
+ warning = { state . last_marker_index , "redundant ignore-next-line right before an ignore-start" }
95
+
96
+ % {
97
+ state
98
+ | ignore_mode: :ignore_block ,
99
+ coverage: [ nil | state . coverage ] ,
100
+ warnings: [ warning | state . warnings ] ,
101
+ last_marker_index: index
102
+ }
103
+ end
104
+
105
+ defp process_stop_marker ( _coverage_line , index , state = % { ignore_mode: :ignore_block } ) do
106
+ % {
107
+ state
108
+ | ignore_mode: :no_ignore ,
109
+ coverage: [ nil | state . coverage ] ,
110
+ last_marker_index: index
111
+ }
112
+ end
113
+
114
+ defp process_stop_marker ( _coverage_line , index , state ) do
115
+ warning = { index , "unexpected ignore-stop or missing previous ignore-start" }
116
+
117
+ % {
118
+ state
119
+ | ignore_mode: :no_ignore ,
120
+ coverage: [ nil | state . coverage ] ,
121
+ warnings: [ warning | state . warnings ] ,
122
+ last_marker_index: index
123
+ }
124
+ end
125
+
126
+ defp process_next_line_marker (
127
+ _coverage_line ,
128
+ index ,
129
+ state = % { ignore_mode: :no_ignore }
130
+ ) do
131
+ % {
132
+ state
133
+ | ignore_mode: :ignore_line ,
134
+ coverage: [ nil | state . coverage ] ,
135
+ last_marker_index: index
136
+ }
137
+ end
138
+
139
+ defp process_next_line_marker (
140
+ _coverage_line ,
141
+ index ,
142
+ state = % { ignore_mode: :ignore_block }
143
+ ) do
144
+ warning = { index , "redundant ignore-next-line inside ignore block" }
145
+
146
+ % {
147
+ state
148
+ | coverage: [ nil | state . coverage ] ,
149
+ warnings: [ warning | state . warnings ]
150
+ }
151
+ end
152
+
153
+ defp process_next_line_marker (
154
+ _coverage_line ,
155
+ index ,
156
+ state = % { ignore_mode: :ignore_line }
157
+ ) do
158
+ warning = { index , "duplicated ignore-next-line" }
159
+
160
+ % {
161
+ state
162
+ | coverage: [ nil | state . coverage ] ,
163
+ warnings: [ warning | state . warnings ] ,
164
+ last_marker_index: index
165
+ }
166
+ end
167
+
168
+ defp process_end_of_file ( state = % { ignore_mode: :ignore_block } ) do
169
+ warning =
170
+ { state . last_marker_index , "ignore-start without a corresponding ignore-stop" }
171
+
172
+ % { state | warnings: [ warning | state . warnings ] }
173
+ end
174
+
175
+ defp process_end_of_file ( state ) , do: state
60
176
end
0 commit comments