featuremap 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/featuremap +4 -3
- data/features/give_feedback.feature +75 -0
- data/features/show features and subdirs/show-features.feature +42 -0
- data/features/show features and subdirs/show-scenarios.feature +30 -0
- data/features/show features and subdirs/show-subdirs.feature +58 -0
- data/features/step_definitions/common_steps.rb +44 -0
- data/features/step_definitions/give_feedback_steps.rb +69 -0
- data/features/step_definitions/show_features_steps.rb +57 -0
- data/features/step_definitions/show_scenarios_steps.rb +32 -0
- data/features/step_definitions/show_subdirs_steps.rb +61 -0
- data/features/support/includes.rb +6 -0
- data/features/support/testdata_gen.rb +68 -0
- data/features/support/validate_xml.rb +13 -0
- data/lib/featuremap.rb +68 -43
- data/lib/version.rb +3 -0
- metadata +28 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e9b97e4894658a5d3d8f8dea733013c28c2a74e
|
4
|
+
data.tar.gz: 453f5df89b88b09fd3b6e67f50781a6044f12210
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c4b2b50674749818acee3d3f6ad6d3774f9afd6872ca005584a67f2941a030d8631c08c19c4d9a78cfadd53890fb06be525541b72de996cac30c265ca8cc643c
|
7
|
+
data.tar.gz: 14436d3a64bbf81b951c374fb9baf82b88282f6b2c04ad17747f05be34e53b3f4c3a8a2f21bc07724548d2eb4f475f0043f9cebc55a21b4e5e91d5ceb9a4689f
|
data/bin/featuremap
CHANGED
@@ -28,8 +28,9 @@ else
|
|
28
28
|
else
|
29
29
|
output_file = "STDOUT"
|
30
30
|
end
|
31
|
-
featuremap = Featuremap.new(feature_dir,options[:verbose])
|
32
|
-
featuremap.
|
33
|
-
|
31
|
+
featuremap = Featuremap.new(feature_dir, output_file, options[:verbose])
|
32
|
+
if featuremap.exit_status == 0
|
33
|
+
featuremap.create_featuremap()
|
34
|
+
end
|
34
35
|
exit featuremap.exit_status
|
35
36
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
|
2
|
+
Ability: give feedback
|
3
|
+
To run featuremap the user have to provide certain parameters (e.g. the location
|
4
|
+
of the Gherkn feature files). If those parameters are missing or faulty,
|
5
|
+
featuremap will provide helpful feedback.
|
6
|
+
|
7
|
+
# rule: show an error message if the feature dir is not accessible
|
8
|
+
|
9
|
+
Scenario: feature dir does not exist
|
10
|
+
Given "invalid-path" as a non existing location for the feature dir
|
11
|
+
When the user runs featuremap
|
12
|
+
Then featuremap exits with 66
|
13
|
+
And featuremap shows the message "can't find >>invalid-path<< as feature dir"
|
14
|
+
|
15
|
+
Scenario: access rights are not sufficient to read the feature dir
|
16
|
+
Given a feature dir "secret_features"
|
17
|
+
And the user rights for the feature dir don't allow access
|
18
|
+
When the user runs featuremap
|
19
|
+
Then featuremap exits with 66
|
20
|
+
And featuremap shows the message "can't access >>secret_features/<< as feature dir"
|
21
|
+
|
22
|
+
|
23
|
+
# rule: show an error message if the featuremap can't write the mindmap
|
24
|
+
|
25
|
+
Scenario: mindmap name contains an non-existing path
|
26
|
+
Given a feature dir "features"
|
27
|
+
And "invalid-path/featuremap.mm" as a non existing location for the mindmap
|
28
|
+
When the user runs featuremap
|
29
|
+
Then featuremap exits with 74
|
30
|
+
And featuremap shows the message "can't write to invalid-path/featuremap.mm"
|
31
|
+
|
32
|
+
Scenario: access rights are not sufficient for the mindmap
|
33
|
+
Given a feature dir "features"
|
34
|
+
And "readonly-path/" as a read-only location for the mindmap
|
35
|
+
And the user rights for the mindmaps don't have access for writing
|
36
|
+
When the user runs featuremap
|
37
|
+
Then featuremap exits with 74
|
38
|
+
And featuremap shows the message "can't write to readonly-path/featuremap.mm"
|
39
|
+
|
40
|
+
|
41
|
+
# rule: add a number to the mindmaps name if the file already exists
|
42
|
+
|
43
|
+
Scenario: a file with the same name as the mindmap already exists
|
44
|
+
Given a mindmap file "featuremap.mm" already exists
|
45
|
+
And a feature dir "existing_name_features"
|
46
|
+
And it contains a feature
|
47
|
+
And "featuremap.mm" is used as an argument for the featuremap script
|
48
|
+
When the user runs featuremap
|
49
|
+
Then featuremap shows the message "given mindmap name is already in use, created featuremap-1.mm"
|
50
|
+
And a new mindmap with name "featuremap-1.mm" was created
|
51
|
+
|
52
|
+
Scenario: multiple files with the same name as the mindmap already exists
|
53
|
+
Given 6 multiple mindmap file with the name "featuremap" distinguished only by number exist
|
54
|
+
And a feature dir "existing_name_features"
|
55
|
+
And it contains a feature
|
56
|
+
And "featuremap.mm" is used as an argument for the featuremap script
|
57
|
+
When the user runs featuremap
|
58
|
+
Then featuremap shows the message "given mindmap name is already in use, created featuremap-6.mm"
|
59
|
+
And a new mindmap with name "featuremap-6.mm" was created
|
60
|
+
|
61
|
+
|
62
|
+
# rule: if the result is written on stdout messages should appear on stderr
|
63
|
+
|
64
|
+
Scenario: user does omit the name for the feature file
|
65
|
+
Given a feature dir "features"
|
66
|
+
And it contains a feature
|
67
|
+
And the argument for the mindmap file name is missing
|
68
|
+
When the user runs featuremap
|
69
|
+
Then the content of the mindmap file is redirected to stdout
|
70
|
+
|
71
|
+
Scenario: user does omit the name for the feature file and the feature dir does not exists
|
72
|
+
Given "invalid-path" as a non existing location for the feature dir
|
73
|
+
And the argument for the mindmap file name is missing
|
74
|
+
When the user runs featuremap
|
75
|
+
Then featuremap shows the message "can't find >>invalid-path<< as feature dir" on stderr
|
@@ -0,0 +1,42 @@
|
|
1
|
+
Ability: show features
|
2
|
+
Calling the mapper will result in a new freemind mindmap. The mindmap will
|
3
|
+
show all feature files as separate nodes.
|
4
|
+
|
5
|
+
# rule: every feature file is shown as a node in the mindmap^
|
6
|
+
|
7
|
+
Scenario Outline: show features
|
8
|
+
Given a feature dir is <feature_dir_type>
|
9
|
+
And it contains <nr_of_features>
|
10
|
+
When the mapper is called
|
11
|
+
Then a mindmap file without any validation error is created
|
12
|
+
And the mindmap contains a root node named "featuremap"
|
13
|
+
And the mindmap contains <nr_of_features> nodes
|
14
|
+
|
15
|
+
Examples:
|
16
|
+
|nr_of_features|feature_dir_type|
|
17
|
+
|0 |empty |
|
18
|
+
|1 |single |
|
19
|
+
|3 |multiple |
|
20
|
+
|
21
|
+
|
22
|
+
# rule: other files than .feature files are ignored
|
23
|
+
|
24
|
+
Scenario: ignore other file types
|
25
|
+
Given a feature dir "mixed_files"
|
26
|
+
And it contains <nr_of_files> files of <file_type>
|
27
|
+
|nr_of_files|file_type|
|
28
|
+
|3 |feature |
|
29
|
+
|1 |txt |
|
30
|
+
|1 |csv |
|
31
|
+
When the mapper is called
|
32
|
+
Then a mindmap file without any validation error is created
|
33
|
+
And the mindmap contains only 3 feature nodes
|
34
|
+
|
35
|
+
|
36
|
+
# rule: feature names are using a bold font
|
37
|
+
|
38
|
+
Scenario: format feature names in bold
|
39
|
+
Given a feature dir containing a feature file
|
40
|
+
When the mapper is called
|
41
|
+
Then a mindmap file without any validation error is created
|
42
|
+
And the feature node in this mindmap is using a bold font
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Ability: show scenarios
|
2
|
+
Calling the mapper will result in a new freemind mindmap. The mindmap will
|
3
|
+
show all feature files as separate nodes. Every feature node will contain
|
4
|
+
sub-nodes for all scenarios.
|
5
|
+
|
6
|
+
# rule: if a feature has scenario, scenario name will be shown as subnodes to
|
7
|
+
|
8
|
+
Scenario Outline: show plain scenarios
|
9
|
+
Given a feature dir with a feature containing <nr_of_scenarios> scenarios
|
10
|
+
When the mapper is called
|
11
|
+
Then a mindmap file without any validation error is created
|
12
|
+
And the mindmap contains a feature node
|
13
|
+
And the feature node contains <nr_of_scenarios> scenario subnodes
|
14
|
+
|
15
|
+
Examples:
|
16
|
+
|nr_of_scenarios|
|
17
|
+
|0 |
|
18
|
+
|1 |
|
19
|
+
|3 |
|
20
|
+
|
21
|
+
|
22
|
+
# rule: outline scenarios are marked by an list icon
|
23
|
+
|
24
|
+
Scenario: show outline scenario
|
25
|
+
Given a feature dir with a feature containing an outline scenario
|
26
|
+
When the mapper is called
|
27
|
+
Then a mindmap file without any validation error is created
|
28
|
+
And the mindmap contains a feature node
|
29
|
+
And the feature node contains a scenario subnode
|
30
|
+
And the scenario subnode is marked with an list icon
|
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
Ability: show subdirs
|
3
|
+
Calling the mapper will result in a new freemind mindmap. The mindmap will
|
4
|
+
show every subdir from the feature dir as a separate node and attach all
|
5
|
+
features from the subdir as children nodes.
|
6
|
+
|
7
|
+
# rule: turn subdirs into mindmap nodes
|
8
|
+
# - show subdirs as mindmap nodes
|
9
|
+
# - add a folder icon to mark them as subdirs
|
10
|
+
|
11
|
+
|
12
|
+
Scenario: feature dir without subdirs
|
13
|
+
Given a feature dir "subdirs_none"
|
14
|
+
And it contains a feature file
|
15
|
+
When the mapper is called
|
16
|
+
Then a mindmap file without any validation error is created
|
17
|
+
And the mindmap contains a node with the feature name
|
18
|
+
|
19
|
+
|
20
|
+
Scenario: feature dir with one level of subdirs
|
21
|
+
Given a feature dir "subdirs_one_level"
|
22
|
+
And it contains at least one subdir
|
23
|
+
And the subdir contains a feature file
|
24
|
+
When the mapper is called
|
25
|
+
Then a mindmap file without any validation error is created
|
26
|
+
And the mindmap contains a node with the subdir
|
27
|
+
And the subdir node contains a node with the feature
|
28
|
+
And the subdir node is marked by a folder icon
|
29
|
+
|
30
|
+
|
31
|
+
Scenario: feature dir with multiple levels of subdirs
|
32
|
+
Given a feature dir "subdirs_multiple_levels"
|
33
|
+
And the feature dir contains subdirs with a different amount of features
|
34
|
+
|subdirs |nr_of_features|
|
35
|
+
|sub1/sub1_1 |1 |
|
36
|
+
|sub2 |2 |
|
37
|
+
|sub3/sub3_1/sub3_2 |2 |
|
38
|
+
|sub1/sub1_2 |0 |
|
39
|
+
When the mapper is called
|
40
|
+
Then a mindmap file without any validation error is created
|
41
|
+
And the mindmap shows nodes with a folder icon for every subdir
|
42
|
+
And the node of every subdir contains the corresponding number of feature nodes
|
43
|
+
|
44
|
+
|
45
|
+
# rule: don't show subdirs used for code and configuration
|
46
|
+
|
47
|
+
Scenario: ignore step_definitions and support folders
|
48
|
+
Given a feature dir "subdirs_code_config"
|
49
|
+
And the feature dir contains subdirs with a different amount of features
|
50
|
+
|subdirs |nr_of_features|
|
51
|
+
|sub1/sub1_1 |1 |
|
52
|
+
|sub2 |2 |
|
53
|
+
|step_definitions |0 |
|
54
|
+
|support |0 |
|
55
|
+
When the mapper is called
|
56
|
+
Then a mindmap file without any validation error is created
|
57
|
+
And the minmap does not contain a folder node "step_definitions"
|
58
|
+
And the minmap does not contain a folder node "support"
|
@@ -0,0 +1,44 @@
|
|
1
|
+
Before do
|
2
|
+
@log = Logger.new(STDOUT)
|
3
|
+
@log.datetime_format = "%H:%M:%S"
|
4
|
+
if ENV['LOG_LEVEL'] == 'debug'
|
5
|
+
@log.level = Logger::DEBUG
|
6
|
+
elsif ENV['LOG_LEVEL'] == 'info'
|
7
|
+
@log.level = Logger::INFO
|
8
|
+
else
|
9
|
+
# default log level
|
10
|
+
@log.level = Logger::ERROR
|
11
|
+
end
|
12
|
+
@featuremap_file = nil
|
13
|
+
delete_path("test_data")
|
14
|
+
@path_to_results = "test_data/out"
|
15
|
+
@path_to_testdata = "test_data/in"
|
16
|
+
end
|
17
|
+
|
18
|
+
Given("a feature dir {string}") do |feature_dir|
|
19
|
+
@feature_dir = feature_dir
|
20
|
+
create_path("#{@path_to_testdata}/#{@feature_dir}")
|
21
|
+
end
|
22
|
+
|
23
|
+
When("the mapper is called") do
|
24
|
+
create_path(@path_to_results)
|
25
|
+
@featuremap_file = "#{@path_to_results}/featuremap.mm"
|
26
|
+
@mapper = Featuremap.new("#{@path_to_testdata}/#{@feature_dir}", @featuremap_file)
|
27
|
+
@mapper.create_featuremap()
|
28
|
+
end
|
29
|
+
|
30
|
+
When("the user runs featuremap") do
|
31
|
+
@log.debug "run script: bin/featuremap #{@path_to_testdata}/#{@feature_dir} #{@featuremap_file}"
|
32
|
+
if @featuremap_file
|
33
|
+
@stdout, @stderr, @exit_status = Open3.capture3("bin/featuremap", "#{@path_to_testdata}/#{@feature_dir}", @featuremap_file)
|
34
|
+
else
|
35
|
+
@stdout, @stderr, @exit_status = Open3.capture3("bin/featuremap", "#{@path_to_testdata}/#{@feature_dir}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Then("a mindmap file without any validation error is created") do
|
40
|
+
#validate generated mm file with freemind.xsd
|
41
|
+
#validate_mm returns array containing validation errors
|
42
|
+
expect(validate_mm(@featuremap_file).count).to eq(0)
|
43
|
+
@mindmap = Nokogiri::XML(File.read(@featuremap_file))
|
44
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
Given("{string} as a non existing location for the feature dir") do |feature_dir|
|
2
|
+
@feature_dir = feature_dir
|
3
|
+
end
|
4
|
+
|
5
|
+
Given("the user rights for the feature dir don't allow access") do
|
6
|
+
FileUtils.chmod("a=xw", "#{@path_to_testdata}/#{@feature_dir}")
|
7
|
+
end
|
8
|
+
|
9
|
+
Given("{string} as a non existing location for the mindmap") do |mindmap_file|
|
10
|
+
@featuremap_file = mindmap_file
|
11
|
+
end
|
12
|
+
|
13
|
+
Given("{string} as a read-only location for the mindmap") do |path_to_mindmap|
|
14
|
+
@featuremap_file = "#{path_to_mindmap}featuremap.mm"
|
15
|
+
@path_to_mindmap = path_to_mindmap
|
16
|
+
create_path("#{@path_to_results}/#{@path_to_mindmap}")
|
17
|
+
end
|
18
|
+
|
19
|
+
Given("the user rights for the mindmaps don't have access for writing") do
|
20
|
+
FileUtils.chmod("a=r", "#{@path_to_results}/#{@path_to_mindmap}")
|
21
|
+
end
|
22
|
+
|
23
|
+
Given("a mindmap file {string} already exists") do |mindmap_file_name|
|
24
|
+
create_file(@path_to_results, mindmap_file_name, "")
|
25
|
+
end
|
26
|
+
|
27
|
+
Given("it contains a feature") do
|
28
|
+
create_feature("#{@path_to_testdata}/#{@feature_dir}", "dummy feature.feature")
|
29
|
+
end
|
30
|
+
|
31
|
+
Given("{string} is used as an argument for the featuremap script") do |mindmap_file_name|
|
32
|
+
@featuremap_file = "#{@path_to_results}/#{mindmap_file_name}"
|
33
|
+
end
|
34
|
+
|
35
|
+
Given("{int} multiple mindmap file with the name {string} distinguished only by number exist") do |duplicate_count, mindmap_file_name|
|
36
|
+
create_file(@path_to_results, "#{mindmap_file_name}.mm", "")
|
37
|
+
(1..duplicate_count-1).each do |file_nr|
|
38
|
+
create_file(@path_to_results, "#{mindmap_file_name}-#{file_nr}.mm", "")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Given("the argument for the mindmap file name is missing") do
|
43
|
+
@featuremap_file = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
Then("featuremap exits with {int}") do |exit_status|
|
47
|
+
expect(@exit_status.exitstatus).to eq(exit_status)
|
48
|
+
end
|
49
|
+
|
50
|
+
Then("featuremap shows the message {string}") do |err_msg|
|
51
|
+
script_output = @stdout + @stderr
|
52
|
+
script_output = script_output.sub("#{@path_to_testdata}/", "")
|
53
|
+
script_output = script_output.sub("#{@path_to_results}/", "")
|
54
|
+
expect(script_output).to include(err_msg)
|
55
|
+
end
|
56
|
+
|
57
|
+
Then("a new mindmap with name {string} was created") do |mindmap_file_name|
|
58
|
+
expect(File.exists?("#{@path_to_results}/#{mindmap_file_name}")).to be_truthy
|
59
|
+
expect(validate_mm("#{@path_to_results}/#{mindmap_file_name}").count).to eq(0)
|
60
|
+
end
|
61
|
+
|
62
|
+
Then("the content of the mindmap file is redirected to stdout") do
|
63
|
+
expect(validate_content(@stdout).count).to eq(0)
|
64
|
+
end
|
65
|
+
|
66
|
+
Then("featuremap shows the message {string} on stderr") do |warning_msg|
|
67
|
+
@stderr = @stderr.sub("#{@path_to_testdata}/", "")
|
68
|
+
expect(@stderr).to include(warning_msg)
|
69
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
Given("a feature dir is empty") do
|
2
|
+
@path_to_testdata = "#{@path_to_testdata}/feature_dir_empty"
|
3
|
+
create_path(@path_to_testdata)
|
4
|
+
end
|
5
|
+
|
6
|
+
Given("a feature dir is single") do
|
7
|
+
@path_to_testdata = "#{@path_to_testdata}/feature_dir_single"
|
8
|
+
end
|
9
|
+
|
10
|
+
Given("a feature dir is multiple") do
|
11
|
+
@path_to_testdata = "#{@path_to_testdata}/feature_dir_multiple"
|
12
|
+
end
|
13
|
+
|
14
|
+
Given("a feature dir containing a feature file") do
|
15
|
+
@path_to_testdata = "#{@path_to_testdata}/feature_dir_simple"
|
16
|
+
create_feature(@path_to_testdata, "dummy feature.feature")
|
17
|
+
end
|
18
|
+
|
19
|
+
Given("it contains {int}") do |int|
|
20
|
+
for file_nr in 1..int
|
21
|
+
create_feature(@path_to_testdata, "dummy feature #{file_nr}.feature")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Given("it contains <nr_of_files> files of <file_type>") do |table|
|
26
|
+
@featuredir_setup = table.hashes
|
27
|
+
table.hashes.each do |table_row|
|
28
|
+
if table_row["file_type"] == "feature"
|
29
|
+
for file_nr in 1..table_row["nr_of_files"].to_i
|
30
|
+
create_feature("#{@path_to_testdata}/#{@feature_dir}", "dummy feature #{file_nr}.feature")
|
31
|
+
end
|
32
|
+
else
|
33
|
+
for file_nr in 1..table_row["nr_of_files"].to_i
|
34
|
+
create_other_file("#{@path_to_testdata}/#{@feature_dir}", "dummy no_feature #{file_nr}.#{table_row["file_type"]}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Then("the mindmap contains a root node named {string}") do |string|
|
41
|
+
expect(@mindmap.xpath("/map/node/@TEXT").first.to_s).to match("featuremap")
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
Then("the mindmap contains {int} nodes") do |int|
|
46
|
+
for file_nr in 1..int
|
47
|
+
expect(@mindmap.xpath("/map/node/node").count).to eq(int)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
Then("the mindmap contains only {int} feature nodes") do |int|
|
52
|
+
expect(@mindmap.xpath("//node[starts-with(@ID, 'feature_')]").count).to eq(int)
|
53
|
+
end
|
54
|
+
|
55
|
+
Then("the feature node in this mindmap is using a bold font") do
|
56
|
+
expect(@mindmap.xpath("//node[starts-with(@ID, 'feature_')]/font[@BOLD = 'true']").count).to eq(1)
|
57
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Given("a feature dir with a feature containing {int} scenarios") do |nr_of_scenarios|
|
2
|
+
@path_to_testdata = "#{@path_to_testdata}/scenarios_basic"
|
3
|
+
create_path(@path_to_testdata)
|
4
|
+
scenarios = []
|
5
|
+
for scenario_index in 1..nr_of_scenarios
|
6
|
+
scenarios.unshift(["scenario nr #{scenario_index}", "Scenario"])
|
7
|
+
end
|
8
|
+
create_feature(@path_to_testdata, "dummy feature with scenarios.feature", scenarios)
|
9
|
+
end
|
10
|
+
|
11
|
+
Given("a feature dir with a feature containing an outline scenario") do
|
12
|
+
@path_to_testdata = "#{@path_to_testdata}/scenarios_outline"
|
13
|
+
create_path(@path_to_testdata)
|
14
|
+
scenarios = [['sample outline', 'Scenario Outline']]
|
15
|
+
create_feature(@path_to_testdata, "dummy feature with scenarios.feature", scenarios)
|
16
|
+
end
|
17
|
+
|
18
|
+
Then("the mindmap contains a feature node") do
|
19
|
+
expect(@mindmap.xpath("/map/node/node[starts-with(@ID,'feature_')]").count).to eq(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
Then("the feature node contains {int} scenario subnodes") do |nr_of_subnodes|
|
23
|
+
expect(@mindmap.xpath("/map/node/node[starts-with(@ID,'feature_')]/node[starts-with(@ID,'scenario_')]").count).to eq(nr_of_subnodes)
|
24
|
+
end
|
25
|
+
|
26
|
+
Then("the feature node contains a scenario subnode") do
|
27
|
+
expect(@mindmap.xpath("/map/node/node[starts-with(@ID,'feature_')]/node[starts-with(@ID,'scenario_')]").count).to eq(1)
|
28
|
+
end
|
29
|
+
|
30
|
+
Then("the scenario subnode is marked with an list icon") do
|
31
|
+
expect(@mindmap.xpath("//node[starts-with(@ID,'scenario_')]/icon[@BUILTIN = 'list']").count).to eq(1)
|
32
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
Given("it contains at least one subdir") do
|
2
|
+
create_path("#{@path_to_testdata}/#{@feature_dir}/subdir")
|
3
|
+
end
|
4
|
+
|
5
|
+
Given("it contains a feature file") do
|
6
|
+
create_feature("#{@path_to_testdata}/#{@feature_dir}", "dummy.feature")
|
7
|
+
end
|
8
|
+
|
9
|
+
Given("the subdir contains a feature file") do
|
10
|
+
create_feature("#{@path_to_testdata}/#{@feature_dir}/subdir", "subdir.feature")
|
11
|
+
end
|
12
|
+
|
13
|
+
Given("the feature dir contains subdirs with a different amount of features") do |table|
|
14
|
+
@subdir_setup = table.hashes
|
15
|
+
table.hashes.each do |table_row|
|
16
|
+
subdir_path = "#{@path_to_testdata}/#{@feature_dir}/#{table_row["subdirs"]}"
|
17
|
+
create_path(subdir_path)
|
18
|
+
for feature_count in 1..table_row["nr_of_features"].to_i
|
19
|
+
create_feature(subdir_path, "dummy_#{feature_count}.feature")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Then("the mindmap contains a node with the feature name") do
|
25
|
+
expect(@mindmap.xpath("/map/node/node/@TEXT").first.to_s).to match("dummy feature for testing")
|
26
|
+
end
|
27
|
+
|
28
|
+
Then("the mindmap contains a node with the subdir") do
|
29
|
+
expect(@mindmap.xpath("/map/node/node/@TEXT").first.to_s).to match("subdir")
|
30
|
+
end
|
31
|
+
|
32
|
+
Then("the subdir node contains a node with the feature") do
|
33
|
+
expect(@mindmap.xpath("/map/node/node[starts-with(@ID,'subdir_')]/node[starts-with(@ID,'feature_')]").count).to eq(1)
|
34
|
+
end
|
35
|
+
|
36
|
+
Then("the subdir node is marked by a folder icon") do
|
37
|
+
expect(@mindmap.xpath("/map/node/node/icon").count).to eq(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
Then("the mindmap shows nodes with a folder icon for every subdir") do
|
41
|
+
@subdir_setup.each do |table_row|
|
42
|
+
subdir_path = table_row["subdirs"]
|
43
|
+
subdir_path.split("/").each do |subdir|
|
44
|
+
expect(@mindmap.xpath("//node[@TEXT = '#{subdir}']").count).to eq(1)
|
45
|
+
expect(@mindmap.xpath("//node[@TEXT = '#{subdir}']/icon").first.to_s).to match("<icon BUILTIN=\"folder\"/>")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Then("the node of every subdir contains the corresponding number of feature nodes") do
|
51
|
+
@subdir_setup.each do |table_row|
|
52
|
+
subdir_path = table_row["subdirs"]
|
53
|
+
subdir = subdir_path.split("/").pop
|
54
|
+
@log.debug "xpath: //node[@TEXT = '#{subdir}']/node[starts-with(@ID, 'feature_')]"
|
55
|
+
expect(@mindmap.xpath("//node[@TEXT = '#{subdir}']/node[starts-with(@ID, 'feature_')]").count).to eq(table_row["nr_of_features"].to_i)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
Then("the minmap does not contain a folder node {string}") do |node_name|
|
60
|
+
expect(@mindmap.xpath("//node[starts-with(@ID, 'subdir_') and @TEXT = '#{node_name}']").count).to eq(0)
|
61
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'english' # this is for speaking built-in variable names e.g. $CHILD_STATUS instead of $?
|
3
|
+
require 'featuremap' # include the featuremap main class
|
4
|
+
require 'nokogiri' # include xml creation and validation lib
|
5
|
+
require 'fileutils' # for setting access rights to test_data files and dirs
|
6
|
+
require 'open3' # to read from stderr
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# generate feature files as test data
|
2
|
+
# path: location of tthe feature file
|
3
|
+
# name: name of the feature
|
4
|
+
def create_feature(path, name, scenarios = [])
|
5
|
+
|
6
|
+
feature = <<DUMMY_FEATURE
|
7
|
+
Feature: dummy feature for testing
|
8
|
+
This is a dummy just for testing purposes
|
9
|
+
DUMMY_FEATURE
|
10
|
+
|
11
|
+
|
12
|
+
scenarios.each do |scenario_name, scenario_type|
|
13
|
+
feature += <<DUMMY_SCENARIO
|
14
|
+
|
15
|
+
#{scenario_type}: #{scenario_name}
|
16
|
+
Given something
|
17
|
+
When action
|
18
|
+
Then result
|
19
|
+
|
20
|
+
DUMMY_SCENARIO
|
21
|
+
end
|
22
|
+
|
23
|
+
create_file(path, name, feature)
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def create_other_file(path, name)
|
28
|
+
|
29
|
+
content = <<DUMMY_TEXT
|
30
|
+
1,dummy,22
|
31
|
+
2,dummy,23
|
32
|
+
DUMMY_TEXT
|
33
|
+
|
34
|
+
create_file(path, name, content)
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def create_file(path, name, content)
|
39
|
+
create_path(path)
|
40
|
+
# file anlegen
|
41
|
+
file = File.open("#{path}/#{name}", "w")
|
42
|
+
file.print(content)
|
43
|
+
file.close
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def create_path(path)
|
48
|
+
currentDir = Dir.getwd
|
49
|
+
|
50
|
+
#Schleife for each item in path
|
51
|
+
path.split('/').each do |dirname|
|
52
|
+
currentDir = "#{currentDir}/#{dirname}"
|
53
|
+
# prüfen ob Verzeichnis existiert
|
54
|
+
if not Dir.exists?(currentDir)
|
55
|
+
# wenn nicht anlegen
|
56
|
+
Dir.mkdir(currentDir)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def delete_path(path)
|
63
|
+
currentDir = Dir.getwd
|
64
|
+
|
65
|
+
if Dir.exists?("#{currentDir}/#{path}")
|
66
|
+
FileUtils.rm_rf(path)
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
def validate_mm(p_featuremap_path)
|
2
|
+
mindmap_content = File.read(p_featuremap_path)
|
3
|
+
validation_messages = validate_content(mindmap_content)
|
4
|
+
return validation_messages
|
5
|
+
end
|
6
|
+
|
7
|
+
def validate_content(p_mindmap_content)
|
8
|
+
schema = Nokogiri::XML::Schema(File.read("doc/definitions/freemind.xsd"))
|
9
|
+
document = Nokogiri::XML(p_mindmap_content)
|
10
|
+
validation_messages = schema.validate(document)
|
11
|
+
validation_messages.each { |error_msg| @log.info "schema err: #{error_msg}"}
|
12
|
+
return validation_messages
|
13
|
+
end
|
data/lib/featuremap.rb
CHANGED
@@ -6,106 +6,131 @@ require_relative 'mindmap'
|
|
6
6
|
|
7
7
|
class Featuremap
|
8
8
|
|
9
|
-
attr_reader :nodes, :exit_status, :
|
9
|
+
attr_reader :nodes, :exit_status, :mindmap_path, :features_path
|
10
10
|
|
11
|
-
def initialize(p_features_path, p_verbose = false)
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
def initialize(p_features_path, p_mindmap_path, p_verbose = false)
|
12
|
+
if p_mindmap_path == "STDOUT"
|
13
|
+
@log = Logger.new(STDERR)
|
14
|
+
else
|
15
|
+
@log = Logger.new(STDOUT)
|
16
|
+
end
|
17
|
+
@log.formatter = proc do |severity, datetime, progname, msg|
|
18
|
+
date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
|
19
|
+
"[#{date_format}] #{severity.ljust(5,' ')}: #{msg}\n"
|
20
|
+
end
|
15
21
|
@log.datetime_format = "%H:%M:%S"
|
16
22
|
if ENV['LOG_LEVEL'] == 'debug'
|
17
23
|
@log.level = Logger::DEBUG
|
18
24
|
elsif ENV['LOG_LEVEL'] == 'info'
|
19
25
|
@log.level = Logger::INFO
|
26
|
+
elsif ENV['LOG_LEVEL'] == 'warn'
|
27
|
+
@log.level = Logger::WARN
|
20
28
|
else
|
21
29
|
# default log level
|
22
30
|
@log.level = Logger::ERROR
|
23
31
|
end
|
24
|
-
if p_verbose
|
32
|
+
if p_verbose && @log.level != Logger::DEBUG && p_mindmap_path != "STDOUT"
|
25
33
|
@log.level = Logger::INFO
|
34
|
+
@log.info "set log level to verbose"
|
26
35
|
end
|
36
|
+
@exit_status = 0
|
37
|
+
@mindmap_path = p_mindmap_path
|
27
38
|
if Dir.exists?(p_features_path)
|
28
39
|
@features_path = p_features_path
|
40
|
+
@log.info("create a new featuremap")
|
41
|
+
@mindmap = Mindmap.new(@log)
|
29
42
|
else
|
30
43
|
@exit_status = 66 # see https://www.freebsd.org/cgi/man.cgi?query=sysexits&sektion=3 for more info
|
31
|
-
@
|
44
|
+
@log.error("can't find >>#{p_features_path}<< as feature dir")
|
45
|
+
return
|
32
46
|
end
|
33
|
-
@log.info("create a new featuremap")
|
34
|
-
@mindmap = Mindmap.new(@log)
|
35
47
|
end
|
36
48
|
|
37
49
|
# class entry point - create a mindmap for a given path
|
38
|
-
def create_featuremap(
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
50
|
+
def create_featuremap()
|
51
|
+
mindmap_path = @mindmap_path
|
52
|
+
if mindmap_path != "STDOUT"
|
53
|
+
while File.exists?(mindmap_path)
|
54
|
+
filename_parts = mindmap_path.split(".")
|
55
|
+
if filename_parts[0] =~ /-\d+$/
|
56
|
+
filename_parts = filename_parts[0].split("-")
|
57
|
+
mindmap_path = "#{filename_parts[0]}-#{filename_parts[1].to_i + 1}.mm"
|
58
|
+
else
|
59
|
+
mindmap_path = "#{filename_parts[0]}-1.mm"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
if mindmap_path != @mindmap_path
|
63
|
+
@log.warn("given mindmap name is already in use, created #{mindmap_path}")
|
64
|
+
end
|
65
|
+
begin
|
66
|
+
IO.write("#{mindmap_path}","")
|
67
|
+
rescue Exception
|
68
|
+
@log.error("can't write to #{mindmap_path}")
|
69
|
+
@exit_status = 74
|
70
|
+
return
|
71
|
+
end
|
43
72
|
end
|
44
|
-
|
45
|
-
|
46
|
-
if
|
47
|
-
|
48
|
-
|
73
|
+
read_features(@features_path)
|
74
|
+
if @exit_status == 0
|
75
|
+
if mindmap_path != "STDOUT"
|
76
|
+
mindmap_file = File.open(mindmap_path,"w")
|
77
|
+
mindmap_file.write(@mindmap.to_s)
|
78
|
+
mindmap_file.close
|
49
79
|
else
|
50
|
-
|
80
|
+
puts @mindmap.to_s
|
51
81
|
end
|
52
82
|
end
|
53
|
-
if featuremap_path != p_featuremap_path
|
54
|
-
@err_msg.push("given mindmap name is already in use, created #{featuremap_path}")
|
55
|
-
end
|
56
|
-
begin
|
57
|
-
IO.write("#{featuremap_path}","")
|
58
|
-
rescue Exception
|
59
|
-
@err_msg.push("can't write to #{featuremap_path}")
|
60
|
-
@log.warn @err_msg
|
61
|
-
@exit_status = 74
|
62
|
-
return
|
63
|
-
end
|
64
|
-
read_features(@features_path)
|
65
|
-
mindmap_file = File.open(featuremap_path,"w")
|
66
|
-
mindmap_file.write(@mindmap.to_s)
|
67
|
-
mindmap_file.close
|
68
83
|
end
|
69
84
|
|
70
85
|
# scan feature folder for feature files and subdirs
|
71
|
-
def read_features(p_features_path, p_parent_node = nil)
|
86
|
+
def read_features(p_features_path = @features_path, p_parent_node = nil)
|
72
87
|
# don't read features if some error happened before
|
73
88
|
if @exit_status == 0
|
74
89
|
feature_node = nil
|
75
90
|
begin
|
76
|
-
|
91
|
+
if p_features_path.end_with?("/")
|
92
|
+
features_path = p_features_path
|
93
|
+
else
|
94
|
+
features_path = p_features_path + "/"
|
95
|
+
end
|
96
|
+
features = Dir.entries(features_path)
|
77
97
|
rescue Exception
|
78
|
-
@
|
79
|
-
@log.warn @err_msg
|
98
|
+
@log.error("can't access >>#{features_path}<< as feature dir")
|
80
99
|
@exit_status = 66
|
81
100
|
return
|
82
101
|
end
|
102
|
+
@log.info "start reading features from dir #{features_path}"
|
103
|
+
feature_count = 0
|
104
|
+
scenario_count = 0
|
83
105
|
features.each do |feature_file|
|
84
106
|
#ignore files starting with .
|
85
107
|
if feature_file =~ /^[^\.]/
|
86
108
|
#look for features in only in .feature files
|
87
109
|
if feature_file =~ /\.feature$/
|
88
|
-
feature = File.read("#{
|
110
|
+
feature = File.read("#{features_path}#{feature_file}")
|
89
111
|
feature.scan(/^\s*(Feature|Ability|Business Need):\s*(\S.*)$/) do |feature_type, feature_name|
|
90
112
|
feature_node = @mindmap.add_node(feature_name, "feature", p_parent_node)
|
113
|
+
feature_count += 1
|
91
114
|
end
|
92
115
|
feature.scan(/^\s*(Scenario|Scenario Outline):\s*(\S.*)$/) do |scenario_type, scenario_name|
|
93
116
|
case scenario_type
|
94
|
-
|
117
|
+
when "Scenario Outline" then @mindmap.add_node(scenario_name, "scenario_outline", feature_node)
|
95
118
|
when "Scenario" then @mindmap.add_node(scenario_name, "scenario", feature_node)
|
96
119
|
end
|
120
|
+
scenario_count += 1
|
97
121
|
end
|
98
122
|
end
|
99
123
|
# look for subdirs
|
100
|
-
if File.directory?("#{
|
124
|
+
if File.directory?("#{features_path}#{feature_file}")
|
101
125
|
# ignore step_definitions and support folders because those are used for code
|
102
126
|
if feature_file != "step_definitions" && feature_file != "support"
|
103
127
|
subdir_node = @mindmap.add_node(feature_file, "subdir", p_parent_node)
|
104
|
-
read_features("#{
|
128
|
+
read_features("#{features_path}#{feature_file}", subdir_node)
|
105
129
|
end
|
106
130
|
end
|
107
131
|
end
|
108
132
|
end
|
133
|
+
@log.info "found #{feature_count} feature(s) and #{scenario_count} scenarios in dir #{features_path}"
|
109
134
|
end
|
110
135
|
end
|
111
136
|
|
data/lib/version.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: featuremap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthias Carell
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |-
|
14
14
|
Featurmaps helps you to visualize the functionality of your \
|
@@ -21,8 +21,21 @@ extensions: []
|
|
21
21
|
extra_rdoc_files: []
|
22
22
|
files:
|
23
23
|
- bin/featuremap
|
24
|
+
- features/give_feedback.feature
|
25
|
+
- features/show features and subdirs/show-features.feature
|
26
|
+
- features/show features and subdirs/show-scenarios.feature
|
27
|
+
- features/show features and subdirs/show-subdirs.feature
|
28
|
+
- features/step_definitions/common_steps.rb
|
29
|
+
- features/step_definitions/give_feedback_steps.rb
|
30
|
+
- features/step_definitions/show_features_steps.rb
|
31
|
+
- features/step_definitions/show_scenarios_steps.rb
|
32
|
+
- features/step_definitions/show_subdirs_steps.rb
|
33
|
+
- features/support/includes.rb
|
34
|
+
- features/support/testdata_gen.rb
|
35
|
+
- features/support/validate_xml.rb
|
24
36
|
- lib/featuremap.rb
|
25
37
|
- lib/mindmap.rb
|
38
|
+
- lib/version.rb
|
26
39
|
homepage: https://github.com/mckryton/featuremap
|
27
40
|
licenses: []
|
28
41
|
metadata: {}
|
@@ -46,4 +59,16 @@ rubygems_version: 2.6.14
|
|
46
59
|
signing_key:
|
47
60
|
specification_version: 4
|
48
61
|
summary: A script to convert Gherkin features into a mindmap
|
49
|
-
test_files:
|
62
|
+
test_files:
|
63
|
+
- features/give_feedback.feature
|
64
|
+
- features/show features and subdirs/show-features.feature
|
65
|
+
- features/show features and subdirs/show-scenarios.feature
|
66
|
+
- features/show features and subdirs/show-subdirs.feature
|
67
|
+
- features/step_definitions/common_steps.rb
|
68
|
+
- features/step_definitions/give_feedback_steps.rb
|
69
|
+
- features/step_definitions/show_features_steps.rb
|
70
|
+
- features/step_definitions/show_scenarios_steps.rb
|
71
|
+
- features/step_definitions/show_subdirs_steps.rb
|
72
|
+
- features/support/includes.rb
|
73
|
+
- features/support/testdata_gen.rb
|
74
|
+
- features/support/validate_xml.rb
|