cucumber_analytics 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/History.rdoc ADDED
@@ -0,0 +1,16 @@
1
+ === Version 0.0.3 / 2012-11-10
2
+
3
+ * 'But' has been added to the list of recognized step keywords (formerly Given,
4
+ When,Then, And, and *)
5
+ * Bug fix: the number of test cases a feature is considered to contain now
6
+ properly takes into account an outline's example rows.
7
+
8
+
9
+ === Version 0.0.2 / 2012-11-1
10
+
11
+ * Bug fix: descriptions are no longer cut short due to the presence of keywords
12
+
13
+
14
+ === Version 0.0.1 / 2012-10-28
15
+
16
+ * Initial release
@@ -19,4 +19,5 @@ Gem::Specification.new do |gem|
19
19
  gem.add_development_dependency("cucumber")
20
20
  gem.add_development_dependency("wrong")
21
21
  gem.add_development_dependency("simplecov")
22
+ gem.add_development_dependency("log4r")
22
23
  end
@@ -26,13 +26,14 @@ Feature: Background elements can be modeled.
26
26
  # Basically, if it's not a step keyword or tag then I will accept
27
27
  # it as description here. Cucumber might not but but that's between
28
28
  # you and its lexxer/parser. ;)
29
- * this *parameterized* step takes a table:
29
+ Given this *parameterized* step takes a table:
30
30
  | data |
31
31
  | more data |
32
- * some setup step
32
+ When some setup step
33
+ But some setup step
33
34
  #
34
- * a step with a *parameter*
35
- * some big setup step:
35
+ Then a step with a *parameter*
36
+ And some big setup step:
36
37
  #random comment
37
38
  \"\"\"
38
39
  some text
@@ -47,6 +48,8 @@ Feature: Background elements can be modeled.
47
48
  Given
48
49
  When
49
50
  Then
51
+ And
52
+ But
50
53
  *
51
54
  some more text
52
55
  \"\"\"
@@ -78,40 +81,45 @@ Feature: Background elements can be modeled.
78
81
 
79
82
  Scenario: The background steps are modeled.
80
83
  Then the background's steps are as follows:
81
- | * this *parameterized* step takes a table: |
82
- | \| data \| |
83
- | \| more data \| |
84
- | * some setup step |
85
- | * a step with a *parameter* |
86
- | * some big setup step: |
87
- | """ |
88
- | 'some text' |
89
- | '' |
90
- | '#some comments' |
91
- | 'Scenario:' |
92
- | 'Scenario Outline:' |
93
- | 'Examples:' |
94
- | '@' |
95
- | 'Feature:' |
96
- | '\|' |
97
- | 'Given' |
98
- | 'When' |
99
- | 'Then' |
100
- | '*' |
101
- | ' some more text' |
102
- | """ |
103
- | * *lots* *of* *parameters* |
84
+ | Given this *parameterized* step takes a table: |
85
+ | \| data \| |
86
+ | \| more data \| |
87
+ | When some setup step |
88
+ | But some setup step |
89
+ | Then a step with a *parameter* |
90
+ | And some big setup step: |
91
+ | """ |
92
+ | 'some text' |
93
+ | '' |
94
+ | '#some comments' |
95
+ | 'Scenario:' |
96
+ | 'Scenario Outline:' |
97
+ | 'Examples:' |
98
+ | '@' |
99
+ | 'Feature:' |
100
+ | '\|' |
101
+ | 'Given' |
102
+ | 'When' |
103
+ | 'Then' |
104
+ | 'And' |
105
+ | 'But' |
106
+ | '*' |
107
+ | ' some more text' |
108
+ | """ |
109
+ | * *lots* *of* *parameters* |
104
110
  And the background's steps "without" arguments are as follows:
105
- | * this ** step takes a table: |
106
- | * some setup step |
107
- | * a step with a ** |
108
- | * some big setup step: |
109
- | * ** ** ** |
111
+ | Given this ** step takes a table: |
112
+ | When some setup step |
113
+ | But some setup step |
114
+ | Then a step with a ** |
115
+ | And some big setup step: |
116
+ | * ** ** ** |
110
117
  And the background's steps "without" keywords are as follows:
111
118
  | this *parameterized* step takes a table: |
112
119
  | \| data \| |
113
120
  | \| more data \| |
114
121
  | some setup step |
122
+ | some setup step |
115
123
  | a step with a *parameter* |
116
124
  | some big setup step: |
117
125
  | """ |
@@ -127,6 +135,8 @@ Feature: Background elements can be modeled.
127
135
  | 'Given' |
128
136
  | 'When' |
129
137
  | 'Then' |
138
+ | 'And' |
139
+ | 'But' |
130
140
  | '*' |
131
141
  | ' some more text' |
132
142
  | """ |
@@ -134,13 +144,14 @@ Feature: Background elements can be modeled.
134
144
  And the background's steps "without" arguments "without" keywords are as follows:
135
145
  | this ** step takes a table: |
136
146
  | some setup step |
147
+ | some setup step |
137
148
  | a step with a ** |
138
149
  | some big setup step: |
139
150
  | ** ** ** |
140
151
  And step "1" of the background has the following block:
141
152
  | \| data \| |
142
153
  | \| more data \| |
143
- And step "4" of the background has the following block:
154
+ And step "5" of the background has the following block:
144
155
  | """ |
145
156
  | 'some text' |
146
157
  | '' |
@@ -154,6 +165,8 @@ Feature: Background elements can be modeled.
154
165
  | 'Given' |
155
166
  | 'When' |
156
167
  | 'Then' |
168
+ | 'And' |
169
+ | 'But' |
157
170
  | '*' |
158
171
  | ' some more text' |
159
172
  | """ |
@@ -30,6 +30,7 @@ Feature: Features can be modeled.
30
30
  Given some description that uses keywords
31
31
  And more of it
32
32
  When I chuck the kitchen sink at it:
33
+ But
33
34
  *
34
35
  |
35
36
 
@@ -79,6 +80,7 @@ Feature: Features can be modeled.
79
80
  Examples: some examples with different significance and a tag
80
81
  | param1 | param2 |
81
82
  | a | b |
83
+ | c | d |
82
84
 
83
85
 
84
86
  Scenario: The second scenario's name.
@@ -113,7 +115,7 @@ Feature: Features can be modeled.
113
115
  Then feature "1" is found to have the following properties:
114
116
  | name | The test feature name. |
115
117
  | test_count | 3 |
116
- | test_case_count | 4 |
118
+ | test_case_count | 5 |
117
119
  And feature "2" is found to have the following properties:
118
120
  | name | |
119
121
  | test_count | 2 |
@@ -132,6 +134,7 @@ Feature: Features can be modeled.
132
134
  | Given some description that uses keywords |
133
135
  | And more of it |
134
136
  | When I chuck the kitchen sink at it: |
137
+ | But |
135
138
  | * |
136
139
  | \| |
137
140
  | Scenario Outline |
@@ -36,9 +36,10 @@ Feature: Scenario Outline elements can be modeled.
36
36
  | <param1> |
37
37
  | <param2> |
38
38
  And some setup step
39
+ * some setup step
39
40
  #
40
41
  When a step with a *parameter*
41
- And a big step:
42
+ But a big step:
42
43
  #random comment
43
44
  \"\"\"
44
45
  some text
@@ -53,6 +54,8 @@ Feature: Scenario Outline elements can be modeled.
53
54
  Given
54
55
  When
55
56
  Then
57
+ And
58
+ But
56
59
  *
57
60
  some more text
58
61
  \"\"\"
@@ -103,8 +106,9 @@ Feature: Scenario Outline elements can be modeled.
103
106
  | \| <param1> \| |
104
107
  | \| <param2> \| |
105
108
  | And some setup step |
109
+ | * some setup step |
106
110
  | When a step with a *parameter* |
107
- | And a big step: |
111
+ | But a big step: |
108
112
  | """ |
109
113
  | 'some text' |
110
114
  | '' |
@@ -118,6 +122,8 @@ Feature: Scenario Outline elements can be modeled.
118
122
  | 'Given' |
119
123
  | 'When' |
120
124
  | 'Then' |
125
+ | 'And' |
126
+ | 'But' |
121
127
  | '*' |
122
128
  | ' some more text' |
123
129
  | """ |
@@ -125,14 +131,16 @@ Feature: Scenario Outline elements can be modeled.
125
131
  And the test steps "without" arguments are as follows:
126
132
  | Given this ** step takes a table: |
127
133
  | And some setup step |
134
+ | * some setup step |
128
135
  | When a step with a ** |
129
- | And a big step: |
136
+ | But a big step: |
130
137
  | Then ** ** ** |
131
138
  And the test steps "without" keywords are as follows:
132
139
  | this *parameterized* step takes a table: |
133
140
  | \| <param1> \| |
134
141
  | \| <param2> \| |
135
142
  | some setup step |
143
+ | some setup step |
136
144
  | a step with a *parameter* |
137
145
  | a big step: |
138
146
  | """ |
@@ -148,6 +156,8 @@ Feature: Scenario Outline elements can be modeled.
148
156
  | 'Given' |
149
157
  | 'When' |
150
158
  | 'Then' |
159
+ | 'And' |
160
+ | 'But' |
151
161
  | '*' |
152
162
  | ' some more text' |
153
163
  | """ |
@@ -155,13 +165,14 @@ Feature: Scenario Outline elements can be modeled.
155
165
  And the test steps "without" arguments "without" keywords are as follows:
156
166
  | this ** step takes a table: |
157
167
  | some setup step |
168
+ | some setup step |
158
169
  | a step with a ** |
159
170
  | a big step: |
160
171
  | ** ** ** |
161
172
  And the test step "1" has the following block:
162
173
  | \| <param1> \| |
163
174
  | \| <param2> \| |
164
- And the test step "4" has the following block:
175
+ And the test step "5" has the following block:
165
176
  | """ |
166
177
  | 'some text' |
167
178
  | '' |
@@ -175,6 +186,8 @@ Feature: Scenario Outline elements can be modeled.
175
186
  | 'Given' |
176
187
  | 'When' |
177
188
  | 'Then' |
189
+ | 'And' |
190
+ | 'But' |
178
191
  | '*' |
179
192
  | ' some more text' |
180
193
  | """ |
@@ -36,9 +36,10 @@ Feature: Scenario elements can be modeled.
36
36
  | data |
37
37
  | more data |
38
38
  And some setup step
39
+ * some setup step
39
40
  #
40
41
  When a step with a *parameter*
41
- And a big step:
42
+ But a big step:
42
43
  #random comment
43
44
  \"\"\"
44
45
  some text
@@ -53,6 +54,8 @@ Feature: Scenario elements can be modeled.
53
54
  Given
54
55
  When
55
56
  Then
57
+ And
58
+ But
56
59
  *
57
60
  some more text
58
61
  \"\"\"
@@ -69,13 +72,13 @@ Feature: Scenario elements can be modeled.
69
72
 
70
73
  Scenario: The scenario description is modeled.
71
74
  Then the test descriptive lines are as follows:
72
- | My big hunk of perfectly valid description: |
73
- | \| |
74
- | Scenario Outline |
75
- | Examples |
76
- | """ |
77
- | Background |
78
- | this is still one big valid description |
75
+ | My big hunk of perfectly valid description: |
76
+ | \| |
77
+ | Scenario Outline |
78
+ | Examples |
79
+ | """ |
80
+ | Background |
81
+ | this is still one big valid description |
79
82
 
80
83
  Scenario: The scenario steps are modeled.
81
84
  Then the test steps are as follows:
@@ -83,8 +86,9 @@ Feature: Scenario elements can be modeled.
83
86
  | \| data \| |
84
87
  | \| more data \| |
85
88
  | And some setup step |
89
+ | * some setup step |
86
90
  | When a step with a *parameter* |
87
- | And a big step: |
91
+ | But a big step: |
88
92
  | """ |
89
93
  | 'some text' |
90
94
  | '' |
@@ -98,6 +102,8 @@ Feature: Scenario elements can be modeled.
98
102
  | 'Given' |
99
103
  | 'When' |
100
104
  | 'Then' |
105
+ | 'And' |
106
+ | 'But' |
101
107
  | '*' |
102
108
  | ' some more text' |
103
109
  | """ |
@@ -105,14 +111,16 @@ Feature: Scenario elements can be modeled.
105
111
  And the test steps "without" arguments are as follows:
106
112
  | Given this ** step takes a table: |
107
113
  | And some setup step |
114
+ | * some setup step |
108
115
  | When a step with a ** |
109
- | And a big step: |
116
+ | But a big step: |
110
117
  | Then ** ** ** |
111
118
  And the test steps "without" keywords are as follows:
112
119
  | this *parameterized* step takes a table: |
113
120
  | \| data \| |
114
121
  | \| more data \| |
115
122
  | some setup step |
123
+ | some setup step |
116
124
  | a step with a *parameter* |
117
125
  | a big step: |
118
126
  | """ |
@@ -128,6 +136,8 @@ Feature: Scenario elements can be modeled.
128
136
  | 'Given' |
129
137
  | 'When' |
130
138
  | 'Then' |
139
+ | 'And' |
140
+ | 'But' |
131
141
  | '*' |
132
142
  | ' some more text' |
133
143
  | """ |
@@ -135,13 +145,14 @@ Feature: Scenario elements can be modeled.
135
145
  And the test steps "without" arguments "without" keywords are as follows:
136
146
  | this ** step takes a table: |
137
147
  | some setup step |
148
+ | some setup step |
138
149
  | a step with a ** |
139
150
  | a big step: |
140
151
  | ** ** ** |
141
152
  And the test step "1" has the following block:
142
153
  | \| data \| |
143
154
  | \| more data \| |
144
- And the test step "4" has the following block:
155
+ And the test step "5" has the following block:
145
156
  | """ |
146
157
  | 'some text' |
147
158
  | '' |
@@ -155,6 +166,8 @@ Feature: Scenario elements can be modeled.
155
166
  | 'Given' |
156
167
  | 'When' |
157
168
  | 'Then' |
169
+ | 'And' |
170
+ | 'But' |
158
171
  | '*' |
159
172
  | ' some more text' |
160
173
  | """ |
@@ -6,6 +6,15 @@ include Wrong
6
6
 
7
7
  require File.dirname(__FILE__) + '/../../lib/cucumber_analytics'
8
8
 
9
+ Log4r::Logger.root.level = Log4r::OFF
10
+
11
+ Log4r::FileOutputter.new('logfile',
12
+ :filename=>'test_log.txt',
13
+ :trunc=>true,
14
+ :level=>Log4r::DEBUG)
15
+
16
+ CucumberAnalytics::Logging.logger.add('logfile')
17
+
9
18
 
10
19
  DEFAULT_FEATURE_FILE_NAME = 'test_feature.feature'
11
20
  DEFAULT_STEP_FILE_NAME = 'test_steps.rb'
@@ -1,4 +1,7 @@
1
+ require "log4r"
2
+
1
3
  require 'cucumber_analytics/version'
4
+ require 'cucumber_analytics/logging'
2
5
  require 'cucumber_analytics/parsed_file'
3
6
  require 'cucumber_analytics/parsed_directory'
4
7
  require 'cucumber_analytics/feature_element.rb'
@@ -8,6 +8,8 @@ module CucumberAnalytics
8
8
 
9
9
  # Creates a new FeatureElement object.
10
10
  def initialize(source_lines = nil)
11
+ CucumberAnalytics::Logging.logger.info('FeatureElement#initialize')
12
+
11
13
  @name = ''
12
14
  @description =[]
13
15
  end
@@ -17,25 +19,41 @@ module CucumberAnalytics
17
19
 
18
20
 
19
21
  def parse_feature_element(source_lines)
22
+ CucumberAnalytics::Logging.logger.info('FeatureElement#parse_feature_element')
23
+
20
24
  parse_feature_element_name(source_lines)
21
25
  parse_feature_element_description(source_lines)
22
26
  end
23
27
 
24
28
  #todo - move this elsewhere
25
29
  def parse_feature_element_tags(source_lines)
26
- source_lines.take_while { |line| !(line =~/^\s*(?:[A-Z a-z])+:/) }.tap do |tag_lines|
30
+ CucumberAnalytics::Logging.logger.info('FeatureElement#parse_feature_element_tags')
31
+ CucumberAnalytics::Logging.logger.debug('source lines')
32
+ source_lines.each do |line|
33
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
34
+ end
35
+
36
+ source_lines.take_while { |line| line !~ /^\s*(?:[A-Z a-z])+:/ }.tap do |tag_lines|
37
+ tag_lines.delete_if { |line| World.ignored_line?(line)}
38
+
27
39
  tag_lines.join(' ').delete(' ').split('@').each do |tag|
28
40
  @tags << "@#{tag.strip}"
29
41
  end
30
42
  end
31
43
  @tags.shift
32
44
 
33
- while source_lines.first =~ /^\s*@/
45
+ while source_lines.first !~ /^\s*(?:[A-Z a-z])+:/
34
46
  source_lines.shift
35
47
  end
36
48
  end
37
49
 
38
50
  def parse_feature_element_name(source_lines)
51
+ CucumberAnalytics::Logging.logger.info('FeatureElement#parse_feature_element_name')
52
+ CucumberAnalytics::Logging.logger.debug('source lines')
53
+ source_lines.each do |line|
54
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
55
+ end
56
+
39
57
  @name.replace source_lines.first.match(/^\s*(?:[A-Z a-z])+:(.*)/)[1].strip
40
58
  source_lines.shift
41
59
  end
@@ -0,0 +1,9 @@
1
+ module CucumberAnalytics
2
+ module Logging
3
+
4
+ def self.logger
5
+ @logger ||= Log4r::Logger.new('ca_logger')
6
+ end
7
+
8
+ end
9
+ end
@@ -9,6 +9,12 @@ module CucumberAnalytics
9
9
  # Creates a new OutlineExample object and, if *source_lines* is provided,
10
10
  # populates the object.
11
11
  def initialize(source_lines = nil)
12
+ CucumberAnalytics::Logging.logger.info('OutlineExample#initialize')
13
+ CucumberAnalytics::Logging.logger.debug('source lines')
14
+ source_lines.each do |line|
15
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
16
+ end
17
+
12
18
  super
13
19
 
14
20
  @tags = []
@@ -22,16 +28,29 @@ module CucumberAnalytics
22
28
 
23
29
 
24
30
  def parse_example(source_lines)
31
+ CucumberAnalytics::Logging.logger.info('OutlineExample#parse_example')
32
+
25
33
  parse_feature_element_tags(source_lines)
26
34
  parse_feature_element(source_lines)
35
+
36
+ source_lines.delete_if { |line| World.ignored_line?(line)}
27
37
  rows.concat source_lines.collect { |line| line.strip }
28
38
  end
29
39
 
30
40
  def parse_feature_element_description(source_lines)
41
+ CucumberAnalytics::Logging.logger.info('OutlineExample#parse_feature_element_description')
42
+ CucumberAnalytics::Logging.logger.debug('source lines')
43
+ source_lines.each do |line|
44
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
45
+ end
46
+
31
47
  until source_lines.first =~ /^\s*\|/ or
32
48
  source_lines.empty?
33
49
 
34
- @description << source_lines.first.strip
50
+ unless World.ignored_line?(source_lines.first)
51
+ @description << source_lines.first.strip
52
+ end
53
+
35
54
  source_lines.shift
36
55
  end
37
56
  end
@@ -5,6 +5,8 @@ module CucumberAnalytics
5
5
  # Creates a new ParsedBackground object and, if *source_lines* is provided,
6
6
  # populates the object.
7
7
  def initialize(source_lines = nil)
8
+ CucumberAnalytics::Logging.logger.info('ParsedBackground#initialize')
9
+
8
10
  super
9
11
 
10
12
  parse_background(source_lines) if source_lines
@@ -15,15 +17,26 @@ module CucumberAnalytics
15
17
 
16
18
 
17
19
  def parse_background(source_lines)
20
+ CucumberAnalytics::Logging.logger.info('ParsedBackground#parse_background')
21
+
18
22
  parse_feature_element(source_lines)
19
23
  parse_test_element_steps(source_lines)
20
24
  end
21
25
 
22
26
  def parse_feature_element_description(source_lines)
27
+ CucumberAnalytics::Logging.logger.info('ParsedBackground#parse_feature_element_description')
28
+ CucumberAnalytics::Logging.logger.debug('source lines')
29
+ source_lines.each do |line|
30
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
31
+ end
32
+
23
33
  until source_lines.first =~ /^\s*(?:(?:Given )|(?:When )|(?:Then )|(?:And )|(?:\* ))/ or
24
34
  source_lines.empty?
25
35
 
26
- @description << source_lines.first.strip
36
+ unless World.ignored_line?(source_lines.first)
37
+ @description << source_lines.first.strip
38
+ end
39
+
27
40
  source_lines.shift
28
41
  end
29
42
  end
@@ -9,6 +9,8 @@ module CucumberAnalytics
9
9
  # Creates a new ParsedDirectory object and, if *directory_parsed* is
10
10
  # provided, populates the object.
11
11
  def initialize(directory_parsed = nil)
12
+ CucumberAnalytics::Logging.logger.info('ParsedDirectory#initialize')
13
+
12
14
  @directory = directory_parsed
13
15
 
14
16
  @feature_files = []
@@ -10,6 +10,8 @@ module CucumberAnalytics
10
10
  # Creates a new ParsedFeature object and, if *source_lines* is provided,
11
11
  # populates the object.
12
12
  def initialize(source_lines = nil)
13
+ CucumberAnalytics::Logging.logger.info('ParsedFeature#initialize')
14
+
13
15
  super
14
16
 
15
17
  @tags = []
@@ -50,7 +52,11 @@ module CucumberAnalytics
50
52
 
51
53
  # Returns the number of test cases contained in the feature.
52
54
  def test_case_count
53
- scenario_count + outlines.reduce(0) { |sum, outline| sum += outline.examples.count }
55
+ scenario_count + outlines.reduce(0) { |outline_sum, outline|
56
+ outline_sum += outline.examples.reduce(0) { |example_sum, example|
57
+ example_sum += example.rows.count - 1
58
+ }
59
+ }
54
60
  end
55
61
 
56
62
  def contains
@@ -62,11 +68,21 @@ module CucumberAnalytics
62
68
 
63
69
 
64
70
  def parse_feature(source_lines)
71
+ CucumberAnalytics::Logging.logger.info('ParsedFeature#parse_feature')
72
+
65
73
  parse_feature_element_tags(source_lines)
66
74
  parse_feature_element(source_lines)
67
75
  end
68
76
 
69
77
  def parse_feature_element_description(source_lines)
78
+ CucumberAnalytics::Logging.logger.info('ParsedFeature#parse_feature_element_description')
79
+ CucumberAnalytics::Logging.logger.debug('source lines')
80
+ source_lines.each do |line|
81
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
82
+ end
83
+
84
+ source_lines.delete_if { |line| World.ignored_line?(line)}
85
+
70
86
  until source_lines.first =~ /^\s*(?:(?:Scenario: )|(?:Scenario Outline: )|(?:Background: )|(?:@ ))/ or
71
87
  source_lines.empty?
72
88
 
@@ -8,6 +8,8 @@ module CucumberAnalytics
8
8
  # Creates a new ParsedFile object and, if *file_parsed* is provided,
9
9
  # populates the object.
10
10
  def initialize(file_parsed = nil)
11
+ CucumberAnalytics::Logging.logger.info('ParsedFile#initialize')
12
+
11
13
  parse_file(file_parsed) if file_parsed
12
14
  end
13
15
 
@@ -30,6 +32,8 @@ module CucumberAnalytics
30
32
 
31
33
 
32
34
  def parse_file(file_parsed)
35
+ CucumberAnalytics::Logging.logger.info('ParsedFile#parse_file')
36
+
33
37
  @file = file_parsed
34
38
 
35
39
  file_lines = []
@@ -40,47 +44,44 @@ module CucumberAnalytics
40
44
 
41
45
  # collect feature tag lines
42
46
  until file_lines.first =~ /^s*Feature:/
43
- unless ignored_line?(file_lines.first)
44
- feature_lines << file_lines.first
45
- end
47
+ feature_lines << file_lines.first
46
48
  file_lines.shift
47
49
  end
48
50
 
49
51
  # collect everything else until the end of the feature section
50
- until file_lines.first =~ /^\s*(?:@|Background:|Scenario:|(?:Scenario Outline:))/ or file_lines.empty?
51
- unless ignored_line?(file_lines.first)
52
- feature_lines << file_lines.first
53
- end
52
+ until file_lines.first =~ /^\s*(?:@|Background:|Scenario:|(?:Scenario Outline:))/ or
53
+ file_lines.empty?
54
+
55
+ feature_lines << file_lines.first
54
56
  file_lines.shift
55
57
  end
56
58
 
59
+ # create a new feature bases on the collected lines
60
+ @feature = ParsedFeature.new(feature_lines)
61
+
57
62
  if file_lines.first =~ /^\s*Background:/
58
63
 
59
64
  # collect the background description lines
60
- until (file_lines.first =~ /^\s*(?:(?:Given )|(?:When )|(?:Then )|(?:And )|(?:\* )|@|Scenario:|(?:Scenario Outline:))/) or file_lines.empty?
61
- unless ignored_line?(file_lines.first)
62
- background_lines << file_lines.first
63
- end
65
+ until (file_lines.first =~ /^\s*(?:(?:Given )|(?:When )|(?:Then )|(?:And )|(?:\* )|@|Scenario:|(?:Scenario Outline:))/) or
66
+ file_lines.empty?
67
+
68
+ background_lines << file_lines.first
64
69
  file_lines.shift
65
70
  end
66
71
 
67
72
  # collect everything else up to the first test
68
- until file_lines.first =~ /^\s*(?:@|Scenario:|(?:Scenario Outline:))/ or file_lines.empty?
73
+ until file_lines.first =~ /^\s*(?:@|Scenario:|(?:Scenario Outline:))/ or
74
+ file_lines.empty?
75
+
69
76
  if file_lines.first =~ /^\s*"""/
70
77
  background_lines.concat(extract_doc_string!(file_lines))
71
78
  else
72
- unless ignored_line?(file_lines.first)
73
- background_lines << file_lines.first
74
- end
79
+ background_lines << file_lines.first
75
80
  file_lines.shift
76
81
  end
77
82
  end
78
83
 
79
- end
80
-
81
- @feature = ParsedFeature.new(feature_lines)
82
-
83
- unless background_lines.empty?
84
+ # create a new background based on the collected lines
84
85
  @feature.background = ParsedBackground.new(background_lines)
85
86
  end
86
87
 
@@ -88,18 +89,22 @@ module CucumberAnalytics
88
89
  end
89
90
 
90
91
  def parse_tests(lines)
91
- test_lines = []
92
+ CucumberAnalytics::Logging.logger.info('ParsedFile#parse_tests')
93
+ CucumberAnalytics::Logging.logger.debug('lines')
94
+ lines.each do |line|
95
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
96
+ end
92
97
 
93
98
  until lines.empty?
94
99
  # we'll need this in order to figure out whether we are dealing with a
95
100
  # scenario or an outline
96
101
  current_test_line = lines.index { |line| line =~ /^\s*(?:Scenario:|(?:Scenario Outline:))/ }
97
102
 
103
+ test_lines = []
104
+
98
105
  # collect the tag lines
99
106
  until lines.first =~ /^\s*(?:Scenario:|(?:Scenario Outline:))/
100
- unless ignored_line?(lines.first)
101
- test_lines << lines.first
102
- end
107
+ test_lines << lines.first
103
108
  lines.shift
104
109
  end
105
110
 
@@ -107,28 +112,28 @@ module CucumberAnalytics
107
112
  lines.shift
108
113
 
109
114
  # collect the description lines
110
- until (lines.first =~ /^\s*(?:(?:Given )|(?:When )|(?:Then )|(?:And )|(?:\* )|Scenario:|(?:Scenario Outline:))/) or lines.empty?
111
- unless ignored_line?(lines.first)
112
- test_lines << lines.first
113
- end
115
+ until (lines.first =~ /^\s*(?:(?:Given )|(?:When )|(?:Then )|(?:And )|(?:\* )|Scenario:|(?:Scenario Outline:))/) or
116
+ lines.empty?
117
+
118
+ test_lines << lines.first
114
119
  lines.shift
115
120
  end
116
121
 
117
122
  # collect everything else up to the next test
118
- until (lines.first =~ /^\s*(?:Scenario:|(?:Scenario Outline:))/) or lines.empty?
123
+ until (lines.first =~ /^\s*(?:Scenario:|(?:Scenario Outline:))/) or
124
+ lines.empty?
125
+
119
126
  if (lines.first =~ /^\s*"""/)
120
127
  test_lines.concat(extract_doc_string!(lines))
121
128
  else
122
- unless ignored_line?(lines.first)
123
- test_lines << lines.first
124
- end
129
+ test_lines << lines.first
125
130
  lines.shift
126
131
  end
127
132
  end
128
133
 
129
134
  # backtrack in order to not end up stealing the next test's tag lines
130
135
  unless lines.empty?
131
- while (test_lines.last =~ /^\s*@/)
136
+ while (test_lines.last =~ /^\s*@/) or World.ignored_line?(test_lines.last)
132
137
  lines = [test_lines.pop].concat(lines)
133
138
  end
134
139
  end
@@ -145,6 +150,12 @@ module CucumberAnalytics
145
150
  end
146
151
 
147
152
  def extract_doc_string!(lines)
153
+ CucumberAnalytics::Logging.logger.info('ParsedFile#extract_doc_string!')
154
+ CucumberAnalytics::Logging.logger.debug('lines')
155
+ lines.each do |line|
156
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
157
+ end
158
+
148
159
  doc_block = []
149
160
 
150
161
  doc_block << lines.first
@@ -161,9 +172,5 @@ module CucumberAnalytics
161
172
  doc_block
162
173
  end
163
174
 
164
- def ignored_line?(line)
165
- line =~ /^\s*#/ or !(line =~ /\S/)
166
- end
167
-
168
175
  end
169
176
  end
@@ -8,6 +8,12 @@ module CucumberAnalytics
8
8
  # Creates a new ParsedScenario object and, if *source_lines* is provided,
9
9
  # populates the object.
10
10
  def initialize(source_lines = nil)
11
+ CucumberAnalytics::Logging.logger.info('ParsedScenario#initialize')
12
+ CucumberAnalytics::Logging.logger.debug('source lines')
13
+ source_lines.each do |line|
14
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
15
+ end
16
+
11
17
  super
12
18
 
13
19
  @tags = []
@@ -20,16 +26,27 @@ module CucumberAnalytics
20
26
 
21
27
 
22
28
  def parse_scenario(source_lines)
29
+ CucumberAnalytics::Logging.logger.info('ParsedScenario#parse_scenario')
30
+
23
31
  parse_feature_element_tags(source_lines)
24
32
  parse_feature_element(source_lines)
25
33
  parse_test_element_steps(source_lines)
26
34
  end
27
35
 
28
36
  def parse_feature_element_description(source_lines)
37
+ CucumberAnalytics::Logging.logger.info('ParsedScenario#parse_feature_element_description')
38
+ CucumberAnalytics::Logging.logger.debug('source lines')
39
+ source_lines.each do |line|
40
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
41
+ end
42
+
29
43
  until source_lines.first =~ /^\s*(?:(?:Given )|(?:When )|(?:Then )|(?:And )|(?:\* ))/ or
30
44
  source_lines.empty?
31
45
 
32
- @description << source_lines.first.strip
46
+ unless World.ignored_line?(source_lines.first)
47
+ @description << source_lines.first.strip
48
+ end
49
+
33
50
  source_lines.shift
34
51
  end
35
52
  end
@@ -8,6 +8,12 @@ module CucumberAnalytics
8
8
  # Creates a new ParsedScenarioOutline object and, if *source_lines* is
9
9
  # provided, populates the object.
10
10
  def initialize(source_lines = nil)
11
+ CucumberAnalytics::Logging.logger.info('ParsedScenarioOutline#initialize')
12
+ CucumberAnalytics::Logging.logger.debug('source lines')
13
+ source_lines.each do |line|
14
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
15
+ end
16
+
11
17
  super
12
18
 
13
19
  @tags = []
@@ -25,6 +31,8 @@ module CucumberAnalytics
25
31
 
26
32
 
27
33
  def parse_outline(source_lines)
34
+ CucumberAnalytics::Logging.logger.info('ParsedScenarioOutline#parse_outline')
35
+
28
36
  parse_feature_element_tags(source_lines)
29
37
  parse_feature_element(source_lines)
30
38
  parse_test_element_steps(source_lines)
@@ -32,32 +40,63 @@ module CucumberAnalytics
32
40
  end
33
41
 
34
42
  def parse_feature_element_description(source_lines)
43
+ CucumberAnalytics::Logging.logger.info('ParsedScenarioOutline#parse_feature_element_description')
44
+ CucumberAnalytics::Logging.logger.debug('source lines')
45
+ source_lines.each do |line|
46
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
47
+ end
48
+
35
49
  until source_lines.first =~ /^\s*(?:(?:Given )|(?:When )|(?:Then )|(?:And )|(?:\* )| (?:Examples: ))/ or
36
50
  source_lines.empty?
37
51
 
38
- @description << source_lines.first.strip
52
+ unless World.ignored_line?(source_lines.first)
53
+ @description << source_lines.first.strip
54
+ end
55
+
39
56
  source_lines.shift
40
57
  end
41
58
  end
42
59
 
43
60
  def parse_outline_examples(source_lines)
61
+ CucumberAnalytics::Logging.logger.info('ParsedScenarioOutline#parse_outline_examples')
62
+ CucumberAnalytics::Logging.logger.debug('source lines')
63
+ source_lines.each do |line|
64
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
65
+ end
66
+
67
+
44
68
  until source_lines.empty?
45
- current_example_line = source_lines.index { |line| line =~ /^\s*Examples/ }
69
+ example_lines = []
46
70
 
47
- example_lines = source_lines.slice!(0..current_example_line)
71
+ # collect the tag lines
72
+ until source_lines.first =~ /^\s*Examples:/
73
+ example_lines << source_lines.first
74
+ source_lines.shift
75
+ end
48
76
 
49
- next_example_line = source_lines.index { |line| line =~ /^\s*Examples:/ }
77
+ example_lines << source_lines.first
78
+ source_lines.shift
50
79
 
51
- if next_example_line.nil?
52
- example_lines.concat(source_lines.slice!(0..source_lines.count))
53
- else
54
- while source_lines[next_example_line - 1] =~ /^\s*@/
55
- next_example_line -= 1
56
- end
80
+ # collect the description lines
81
+ until (source_lines.first =~ /^\s*\|/) or source_lines.empty?
82
+ example_lines << source_lines.first
83
+ source_lines.shift
84
+ end
85
+
86
+ # collect everything else up to the next example
87
+ until (source_lines.first =~ /^\s*Examples:/) or source_lines.empty?
88
+ example_lines << source_lines.first
89
+ source_lines.shift
90
+ end
57
91
 
58
- example_lines.concat(source_lines.slice!(0...next_example_line))
92
+ # backtrack in order to not end up stealing the next test's tag lines
93
+ unless source_lines.empty?
94
+ while (example_lines.last =~ /^\s*@/) or World.ignored_line?(example_lines.last)
95
+ source_lines = [example_lines.pop].concat(source_lines)
96
+ end
59
97
  end
60
98
 
99
+ # use the collected lines to create an example
61
100
  @examples << OutlineExample.new(example_lines)
62
101
  end
63
102
  end
@@ -10,11 +10,23 @@ module CucumberAnalytics
10
10
  # Creates a new Step object based on the passed string. If the optional
11
11
  # string array is provided, it becomes the block for the step.
12
12
  def initialize(step, block = nil)
13
+ CucumberAnalytics::Logging.logger.info('Step#initialize')
14
+ CucumberAnalytics::Logging.logger.debug("step: #{step}")
15
+
13
16
  @base = step.sub(/#{World::STEP_KEYWORD_PATTERN}/, '')
14
17
  @block = block
15
18
  @keyword = step.slice(/#{World::STEP_KEYWORD_PATTERN}/).strip
16
19
  end
17
20
 
21
+ # Returns true if the two steps have the same text, minus any keywords
22
+ # and arguments, and false otherwise.
23
+ def ==(other_step)
24
+ left_step = step_text(with_keywords: false, with_arguments: false)
25
+ right_step = other_step.step_text(with_keywords: false, with_arguments: false)
26
+
27
+ left_step == right_step
28
+ end
29
+
18
30
  # Returns the text of the step. Options can be set to selectively exclude
19
31
  # certain portions of the text. *left_delimiter* and *right_delimiter* are
20
32
  # used to determine which parts of the step are arguments.
@@ -7,18 +7,17 @@ module CucumberAnalytics
7
7
 
8
8
  # Creates a new TestElement object.
9
9
  def initialize(source_lines = nil)
10
+ CucumberAnalytics::Logging.logger.info('TestElement#initialize')
11
+
10
12
  super
11
13
 
12
14
  @steps = []
13
15
  end
14
16
 
15
- # Return true if the two elements have the same steps, minus any keywords
17
+ # Returns true if the two elements have the same steps, minus any keywords
16
18
  # and arguments, and false otherwise.
17
19
  def ==(other_element)
18
- left_steps = steps.collect { |step| step.step_text(with_keywords: false, with_arguments: false) }.flatten
19
- right_steps = other_element.steps.collect { |step| step.step_text(with_keywords: false, with_arguments: false) }.flatten
20
-
21
- left_steps == right_steps
20
+ steps == other_element.steps
22
21
  end
23
22
 
24
23
 
@@ -26,6 +25,12 @@ module CucumberAnalytics
26
25
 
27
26
 
28
27
  def parse_test_element_steps(source_lines)
28
+ CucumberAnalytics::Logging.logger.info('TestElement#parse_test_element_steps')
29
+ CucumberAnalytics::Logging.logger.debug('source lines')
30
+ source_lines.each do |line|
31
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
32
+ end
33
+
29
34
  until source_lines.empty? or source_lines.first =~ /^\s*(?:@|Examples:)/
30
35
  line = source_lines.first
31
36
  block = nil
@@ -38,13 +43,22 @@ module CucumberAnalytics
38
43
  block = extract_table_block(source_lines)
39
44
  @steps[@steps.size - 1] = Step.new(@steps.last.keyword + ' ' + @steps.last.base, block)
40
45
  else
41
- @steps << Step.new(line.strip)
46
+ unless World.ignored_line?(line)
47
+ @steps << Step.new(line.strip)
48
+ end
49
+
42
50
  source_lines.shift
43
51
  end
44
52
  end
45
53
  end
46
54
 
47
55
  def extract_doc_block(source_lines)
56
+ CucumberAnalytics::Logging.logger.info('TestElement#extract_doc_block')
57
+ CucumberAnalytics::Logging.logger.debug('source lines')
58
+ source_lines.each do |line|
59
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
60
+ end
61
+
48
62
  step_block = []
49
63
 
50
64
  line = source_lines.first
@@ -72,6 +86,12 @@ module CucumberAnalytics
72
86
  end
73
87
 
74
88
  def extract_table_block(source_lines)
89
+ CucumberAnalytics::Logging.logger.info('TestElement#extract_table_block')
90
+ CucumberAnalytics::Logging.logger.debug('source lines')
91
+ source_lines.each do |line|
92
+ CucumberAnalytics::Logging.logger.debug(line.chomp)
93
+ end
94
+
75
95
  step_block = []
76
96
 
77
97
  line = source_lines.first
@@ -1,3 +1,3 @@
1
- module CucumberAnalytics
2
- VERSION = "0.0.2"
3
- end
1
+ module CucumberAnalytics
2
+ VERSION = "0.0.3"
3
+ end
@@ -3,7 +3,7 @@ module CucumberAnalytics
3
3
 
4
4
 
5
5
  SANITARY_STRING = '___!!!___'
6
- STEP_KEYWORD_PATTERN = '\s*(?:Given|When|Then|And|\*)\s*'
6
+ STEP_KEYWORD_PATTERN = '\s*(?:Given|When|Then|And|But|\*)\s*'
7
7
 
8
8
 
9
9
  # Returns the left delimiter, which is used to mark the beginning of a step
@@ -178,5 +178,11 @@ module CucumberAnalytics
178
178
  end
179
179
  end
180
180
 
181
+ # Returns true if the line is ignored when reading source code, false
182
+ # otherwise.
183
+ def self.ignored_line?(line)
184
+ line =~ /^\s*#/ or !(line =~ /\S/)
185
+ end
186
+
181
187
  end
182
188
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cucumber_analytics
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-01 00:00:00.000000000 Z
12
+ date: 2012-11-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -75,6 +75,22 @@ dependencies:
75
75
  - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: log4r
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
78
94
  description: Static analysis of Cucumber tests made easy.
79
95
  email:
80
96
  - morrow748@gmail.com
@@ -84,6 +100,7 @@ extra_rdoc_files: []
84
100
  files:
85
101
  - .gitignore
86
102
  - Gemfile
103
+ - History.rdoc
87
104
  - LICENSE
88
105
  - README.rdoc
89
106
  - Rakefile
@@ -112,6 +129,7 @@ files:
112
129
  - features/support/transforms.rb
113
130
  - lib/cucumber_analytics.rb
114
131
  - lib/cucumber_analytics/feature_element.rb
132
+ - lib/cucumber_analytics/logging.rb
115
133
  - lib/cucumber_analytics/outline_example.rb
116
134
  - lib/cucumber_analytics/parsed_background.rb
117
135
  - lib/cucumber_analytics/parsed_directory.rb