Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
enkessler committed Feb 13, 2020
2 parents 1032720 + 93e5411 commit dc2c2e5
Show file tree
Hide file tree
Showing 30 changed files with 971 additions and 26 deletions.
5 changes: 5 additions & 0 deletions .travis.yml
Expand Up @@ -14,6 +14,11 @@ rvm:
- 2.6.0
- jruby-9.1.7.0


gemfile:
- testing/gemfiles/cuke_modeler1.gemfile
- testing/gemfiles/cuke_modeler2.gemfile

before_install: gem install bundler -v 1.16.2

script: bundle exec rake cuke_linter:ci_build
15 changes: 13 additions & 2 deletions CHANGELOG.md
Expand Up @@ -6,7 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

Nothing yet... *(see development branch)*
Nothing yet...

## [0.12.0] - 2020-02-13

### Added
- New linters
- ElementWithCommonTagsLinter
- ElementWithDuplicateTagsLinter
- FeatureFileWithMismatchedNameLinter

- Now compatible with CukeModeler 2.x


## [0.11.1] - 2019-11-07
Expand Down Expand Up @@ -119,7 +129,8 @@ Nothing yet... *(see development branch)*
- Custom linters, formatters, and command line usability


[Unreleased]: https://github.com/enkessler/cuke_linter/compare/v0.11.1...HEAD
[Unreleased]: https://github.com/enkessler/cuke_linter/compare/v0.12.0...HEAD
[0.12.0]: https://github.com/enkessler/cuke_linter/compare/v0.11.1...v0.12.0
[0.11.1]: https://github.com/enkessler/cuke_linter/compare/v0.11.0...v0.11.1
[0.11.0]: https://github.com/enkessler/cuke_linter/compare/v0.10.0...v0.11.0
[0.10.0]: https://github.com/enkessler/cuke_linter/compare/v0.9.0...v0.10.0
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.txt
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2018-2019 Eric Kessler
Copyright (c) 2018-2020 Eric Kessler

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
19 changes: 19 additions & 0 deletions appveyor.yml
Expand Up @@ -3,11 +3,30 @@ version: '1.0.{build}'
environment:
matrix:
- RUBY_VERSION: 23
BUNDLE_GEMFILE: testing/gemfiles/cuke_modeler1.gemfile
- RUBY_VERSION: 23-x64
BUNDLE_GEMFILE: testing/gemfiles/cuke_modeler1.gemfile
- RUBY_VERSION: 24
BUNDLE_GEMFILE: testing/gemfiles/cuke_modeler1.gemfile
- RUBY_VERSION: 24-x64
BUNDLE_GEMFILE: testing/gemfiles/cuke_modeler1.gemfile
- RUBY_VERSION: 25
BUNDLE_GEMFILE: testing/gemfiles/cuke_modeler1.gemfile
- RUBY_VERSION: 25-x64
BUNDLE_GEMFILE: testing/gemfiles/cuke_modeler1.gemfile

- RUBY_VERSION: 23
BUNDLE_GEMFILE: testing/gemfiles/cuke_modeler2.gemfile
- RUBY_VERSION: 23-x64
BUNDLE_GEMFILE: testing/gemfiles/cuke_modeler2.gemfile
- RUBY_VERSION: 24
BUNDLE_GEMFILE: testing/gemfiles/cuke_modeler2.gemfile
- RUBY_VERSION: 24-x64
BUNDLE_GEMFILE: testing/gemfiles/cuke_modeler2.gemfile
- RUBY_VERSION: 25
BUNDLE_GEMFILE: testing/gemfiles/cuke_modeler2.gemfile
- RUBY_VERSION: 25-x64
BUNDLE_GEMFILE: testing/gemfiles/cuke_modeler2.gemfile

install:
- set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH%
Expand Down
2 changes: 1 addition & 1 deletion cuke_linter.gemspec
Expand Up @@ -26,7 +26,7 @@ Gem::Specification.new do |spec|

spec.required_ruby_version = '~> 2.0'

spec.add_runtime_dependency 'cuke_modeler', '~> 1.5'
spec.add_runtime_dependency 'cuke_modeler', '>= 1.5', '< 3.0'

spec.add_development_dependency "bundler", "< 3.0"
spec.add_development_dependency "cucumber", "~> 3.0"
Expand Down
4 changes: 4 additions & 0 deletions environments/rspec_env.rb
Expand Up @@ -12,6 +12,10 @@
require_relative '../testing/rspec/spec/integration/formatters/formatter_integration_specs'
require_relative '../testing/rspec/spec/integration/linters/linter_integration_specs'

# Convenient constants, just in case what kinds of elements are taggable ever changes
TAGGABLE_ELEMENTS = ['feature', 'scenario', 'outline', 'example']
ELEMENTS_WITH_TAGGABLE_CHILDREN = ['feature', 'outline']

RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
config.example_status_persistence_file_path = ".rspec_status"
Expand Down
6 changes: 6 additions & 0 deletions lib/cuke_linter.rb
Expand Up @@ -5,9 +5,12 @@
require 'cuke_linter/formatters/pretty_formatter'
require 'cuke_linter/linters/linter'
require 'cuke_linter/linters/background_does_more_than_setup_linter'
require 'cuke_linter/linters/element_with_common_tags_linter'
require 'cuke_linter/linters/element_with_duplicate_tags_linter'
require 'cuke_linter/linters/element_with_too_many_tags_linter'
require 'cuke_linter/linters/example_without_name_linter'
require 'cuke_linter/linters/feature_file_with_invalid_name_linter'
require 'cuke_linter/linters/feature_file_with_mismatched_name_linter'
require 'cuke_linter/linters/feature_with_too_many_different_tags_linter'
require 'cuke_linter/linters/feature_without_name_linter'
require 'cuke_linter/linters/feature_without_description_linter'
Expand All @@ -33,9 +36,12 @@
module CukeLinter

@original_linters = { 'BackgroundDoesMoreThanSetupLinter' => BackgroundDoesMoreThanSetupLinter.new,
'ElementWithCommonTagsLinter' => ElementWithCommonTagsLinter.new,
'ElementWithDuplicateTagsLinter' => ElementWithDuplicateTagsLinter.new,
'ElementWithTooManyTagsLinter' => ElementWithTooManyTagsLinter.new,
'ExampleWithoutNameLinter' => ExampleWithoutNameLinter.new,
'FeatureFileWithInvalidNameLinter' => FeatureFileWithInvalidNameLinter.new,
'FeatureFileWithMismatchedNameLinter' => FeatureFileWithMismatchedNameLinter.new,
'FeatureWithTooManyDifferentTagsLinter' => FeatureWithTooManyDifferentTagsLinter.new,
'FeatureWithoutDescriptionLinter' => FeatureWithoutDescriptionLinter.new,
'FeatureWithoutNameLinter' => FeatureWithoutNameLinter.new,
Expand Down
41 changes: 41 additions & 0 deletions lib/cuke_linter/linters/element_with_common_tags_linter.rb
@@ -0,0 +1,41 @@
module CukeLinter

# A linter that detects Gherkin elements that have the same tag on all of their taggable child elements

class ElementWithCommonTagsLinter < Linter

# The rule used to determine if a model has a problem
def rule(model)
return false unless model.is_a?(CukeModeler::Feature) || model.is_a?(CukeModeler::Outline)

@linted_model_class = model.class

child_accessor_method = model.is_a?(CukeModeler::Feature) ? :tests : :examples
child_models = model.send(child_accessor_method) || []

tag_sets = child_models.collect { |child_model| child_model.tags || [] }
tag_name_sets = tag_sets.collect { |tags| tags.map(&:name) }

return false if tag_name_sets.count < 2

@common_tag = tag_name_sets.reduce(:&).first

!@common_tag.nil?
end

# The message used to describe the problem that has been found
def message
class_name = @linted_model_class.name.split('::').last

case class_name
when 'Feature'
"All tests in #{class_name} have tag '#{@common_tag}'. Move tag to #{class_name} level."
when 'Outline'
"All Examples in #{class_name} have tag '#{@common_tag}'. Move tag to #{class_name} level."
else
raise("Linted an unexpected model type '#{class_name}'!")
end
end

end
end
44 changes: 44 additions & 0 deletions lib/cuke_linter/linters/element_with_duplicate_tags_linter.rb
@@ -0,0 +1,44 @@
module CukeLinter

# A linter that detects taggable Gherkin elements that have duplicate tags

class ElementWithDuplicateTagsLinter < Linter

# Changes the linting settings on the linter using the provided configuration
def configure(options)
@tag_inheritance = options['IncludeInheritedTags']
end

# The rule used to determine if a model has a problem
def rule(model)
return false unless model.is_a?(CukeModeler::Feature) ||
model.is_a?(CukeModeler::Scenario) ||
model.is_a?(CukeModeler::Outline) ||
model.is_a?(CukeModeler::Example)


@linted_model_class = model.class

if @tag_inheritance
relevant_tags = model.all_tags
else
relevant_tags = model.tags || []
end


tag_names = relevant_tags.map(&:name)

@duplicate_tag = tag_names.find { |tag| tag_names.count(tag) > 1 }

!@duplicate_tag.nil?
end

# The message used to describe the problem that has been found
def message
class_name = @linted_model_class.name.split('::').last

"#{class_name} has duplicate tag '#{@duplicate_tag}'."
end

end
end
@@ -0,0 +1,26 @@
module CukeLinter

# A linter that detects mismatched feature file names

class FeatureFileWithMismatchedNameLinter < Linter

# The rule used to determine if a model has a problem
def rule(model)
return false unless model.is_a?(CukeModeler::FeatureFile)

file_name = File.basename(model.path, '.feature')
feature_name = model.feature.name

normalized_file_name = file_name.downcase.delete('_ -')
normalized_feature_name = feature_name.downcase.delete('_ -')

normalized_file_name != normalized_feature_name
end

# The message used to describe the problem that has been found
def message
'Feature file name does not match feature name.'
end

end
end
2 changes: 1 addition & 1 deletion lib/cuke_linter/version.rb
@@ -1,4 +1,4 @@
module CukeLinter
# The release version of this gem
VERSION = '0.11.1'
VERSION = '0.12.0'
end
14 changes: 7 additions & 7 deletions testing/cucumber/features/command_line.feature
Expand Up @@ -57,14 +57,14 @@ Feature: Using cuke_linter on the command line
"""

Scenario: Specifying directories and files to lint
Given the following feature file "some.feature":
Given the following feature file "some_feature.feature":
"""
Feature: Some feature
Scenario: A scenario
When a step
Then a step
"""
And the following feature file "a_directory/with_a.feature":
And the following feature file "a_directory/with/some_feature.feature":
"""
Feature: Some feature
Scenario: A scenario
Expand All @@ -73,14 +73,14 @@ Feature: Using cuke_linter on the command line
"""
When the following command is executed:
"""
cuke_linter -p <path_to>/some.feature -p <path_to>/a_directory
cuke_linter -p <path_to>/some_feature.feature -p <path_to>/a_directory
"""
Then the resulting output is the following:
"""
FeatureWithoutDescriptionLinter
Feature has no description
<path_to>/a_directory/with_a.feature:1
<path_to>/some.feature:1
<path_to>/a_directory/with/some_feature.feature:1
<path_to>/some_feature.feature:1
2 issues found
"""
Expand Down Expand Up @@ -173,8 +173,8 @@ Feature: Using cuke_linter on the command line

Given the following feature file "has_no_scenarios.feature":
"""
Feature: This feature
has no scenarios
Feature: Has no scenarios
Not a single one
"""
And the following configuration file "my_config.file":
"""
Expand Down
3 changes: 3 additions & 0 deletions testing/cucumber/features/default_linters.feature
Expand Up @@ -9,9 +9,12 @@ Feature: Default Linters
Given no other linters have been registered or unregistered
Then the following linters are registered by default
| BackgroundDoesMoreThanSetupLinter |
| ElementWithCommonTagsLinter |
| ElementWithDuplicateTagsLinter |
| ElementWithTooManyTagsLinter |
| ExampleWithoutNameLinter |
| FeatureFileWithInvalidNameLinter |
| FeatureFileWithMismatchedNameLinter |
| FeatureWithTooManyDifferentTagsLinter |
| FeatureWithoutDescriptionLinter |
| FeatureWithoutNameLinter |
Expand Down
28 changes: 28 additions & 0 deletions testing/cucumber/features/linters/element_with_common_tags.feature
@@ -0,0 +1,28 @@
Feature: Element with common tags linter

As a writer of documentation
I want taggable elements to not needlessly have the same tags
So that redundancy is minimized


Scenario: Linting

Note: Also works on outlines that have common tags on their examples

Given a linter for elements with common tags
And the following feature:
"""
Feature:
@same_tag
Scenario:
* a step
@same_tag
Scenario:
* a step
"""
When it is linted
Then an error is reported:
| linter | problem | location |
| ElementWithCommonTagsLinter | All tests in Feature have tag '@same_tag'. Move tag to Feature level. | <path_to_file>:1 |

0 comments on commit dc2c2e5

Please sign in to comment.