Cucumber-TagExpressions-6.1.0000755001751000177 014547500574 16220 5ustar00runnerdocker000000000000LICENSE100644001751000177 206214547500574 17306 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0The MIT License (MIT) Copyright (c) Cucumber Ltd Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. META.yml100644001751000177 301614547500574 17552 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0--- abstract: 'A library for parsing and evaluating cucumber tag expressions (filters)' author: - 'Erik Huelsmann ' - 'Cucumber Ltd' build_requires: Test2::Tools::Exception: '0' Test2::V0: '0' YAML: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'Dist::Zilla version 6.031, CPAN::Meta::Converter version 2.150010' license: mit meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Cucumber-TagExpressions provides: Cucumber::TagExpressions: file: lib/Cucumber/TagExpressions.pm version: v6.1.0 Cucumber::TagExpressions::AndNode: file: lib/Cucumber/TagExpressions/Node.pm version: v6.1.0 Cucumber::TagExpressions::ExpressionNode: file: lib/Cucumber/TagExpressions/Node.pm version: v6.1.0 Cucumber::TagExpressions::LiteralNode: file: lib/Cucumber/TagExpressions/Node.pm version: v6.1.0 Cucumber::TagExpressions::Node: file: lib/Cucumber/TagExpressions/Node.pm version: v6.1.0 Cucumber::TagExpressions::NotNode: file: lib/Cucumber/TagExpressions/Node.pm version: v6.1.0 Cucumber::TagExpressions::OrNode: file: lib/Cucumber/TagExpressions/Node.pm version: v6.1.0 requires: List::Util: '1.63' Moo: '0' perl: v5.14.4 resources: bugtracker: https://github.com/cucumber/tag-expressions/issues repository: https://github.com/cucumber/tag-expressions.git version: 6.1.0 x_generated_by_perl: v5.34.0 x_serialization_backend: 'YAML::Tiny version 1.74' x_spdx_expression: MIT MANIFEST100644001751000177 42114547500574 17407 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.031. CHANGELOG.md LICENSE MANIFEST META.json META.yml Makefile.PL README.md cpanfile dist.ini lib/Cucumber/TagExpressions.pm lib/Cucumber/TagExpressions/Node.pm t/02-evaluate.t t/03-shared-tests.t cpanfile100644001751000177 105114547500574 20002 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0#!perl requires 'perl' => '5.14.4'; requires 'Moo'; # Although List::Util is a core module (better: it's dual life), it only # grew support for 'any' and 'all' in 1.33, which doesn't come with some # of the older Perl versions. Specifying the number explicitly makes older # Perls install this module from CPAN while allowing newer Perls to use the # version they come with. requires 'List::Util' => '1.63'; # for 'any' and 'all' functions. on 'test' => sub { requires 'Test2::V0'; requires 'Test2::Tools::Exception'; requires 'YAML'; }; dist.ini100644001751000177 242514547500574 17750 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0; The name of the 'dist' (the base name of the release tarball) name = Cucumber-TagExpressions ; A short description of the content of the dist abstract = A library for parsing and evaluating cucumber tag expressions (filters) ; The main module presents the primary page shown on MetaCPAN.org for the dist main_module = lib/Cucumber/TagExpressions.pm ; A list of authors, one author per 'author=' row author = Erik Huelsmann author = Cucumber Ltd license = MIT is_trial = 0 copyright_holder = Erik Huelsmann, Cucumber Ltd [MetaResources] bugtracker.web = https://github.com/cucumber/tag-expressions/issues repository.url = https://github.com/cucumber/tag-expressions.git repository.web = https://github.com/cucumber/tag-expressions repository.type = git [@Filter] -bundle=@Basic -remove=Readme -remove=ConfirmRelease -remove=License -remove=GatherDir [MetaJSON] [MetaProvides::Package] [PkgVersion] [Prereqs::FromCPANfile] [Git::GatherDir] exclude_filename=default.mk exclude_filename=Makefile exclude_filename=VERSION [GatherFile] ; explicitly add unversioned files root=../ filename=CHANGELOG.md filename=LICENSE filename=README.md [Hook::VersionProvider] . = my $v = `cat ./VERSION`; chomp( $v ); $v; META.json100644001751000177 460614547500574 17730 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0{ "abstract" : "A library for parsing and evaluating cucumber tag expressions (filters)", "author" : [ "Erik Huelsmann ", "Cucumber Ltd" ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 6.031, CPAN::Meta::Converter version 2.150010", "license" : [ "mit" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Cucumber-TagExpressions", "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "List::Util" : "1.63", "Moo" : "0", "perl" : "v5.14.4" } }, "test" : { "requires" : { "Test2::Tools::Exception" : "0", "Test2::V0" : "0", "YAML" : "0" } } }, "provides" : { "Cucumber::TagExpressions" : { "file" : "lib/Cucumber/TagExpressions.pm", "version" : "v6.1.0" }, "Cucumber::TagExpressions::AndNode" : { "file" : "lib/Cucumber/TagExpressions/Node.pm", "version" : "v6.1.0" }, "Cucumber::TagExpressions::ExpressionNode" : { "file" : "lib/Cucumber/TagExpressions/Node.pm", "version" : "v6.1.0" }, "Cucumber::TagExpressions::LiteralNode" : { "file" : "lib/Cucumber/TagExpressions/Node.pm", "version" : "v6.1.0" }, "Cucumber::TagExpressions::Node" : { "file" : "lib/Cucumber/TagExpressions/Node.pm", "version" : "v6.1.0" }, "Cucumber::TagExpressions::NotNode" : { "file" : "lib/Cucumber/TagExpressions/Node.pm", "version" : "v6.1.0" }, "Cucumber::TagExpressions::OrNode" : { "file" : "lib/Cucumber/TagExpressions/Node.pm", "version" : "v6.1.0" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/cucumber/tag-expressions/issues" }, "repository" : { "type" : "git", "url" : "https://github.com/cucumber/tag-expressions.git", "web" : "https://github.com/cucumber/tag-expressions" } }, "version" : "6.1.0", "x_generated_by_perl" : "v5.34.0", "x_serialization_backend" : "Cpanel::JSON::XS version 4.37", "x_spdx_expression" : "MIT" } README.md100644001751000177 566314547500574 17572 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0[![test-go](https://github.com/cucumber/tag-expressions/actions/workflows/test-go.yml/badge.svg)](https://github.com/cucumber/tag-expressions/actions/workflows/test-go.yml) [![test-java](https://github.com/cucumber/tag-expressions/actions/workflows/test-java.yml/badge.svg)](https://github.com/cucumber/tag-expressions/actions/workflows/test-java.yml) [![test-javascript](https://github.com/cucumber/tag-expressions/actions/workflows/test-javascript.yml/badge.svg)](https://github.com/cucumber/tag-expressions/actions/workflows/test-javascript.yml) [![test-perl](https://github.com/cucumber/tag-expressions/actions/workflows/test-perl.yml/badge.svg)](https://github.com/cucumber/tag-expressions/actions/workflows/test-perl.yml) [![test-python](https://github.com/cucumber/tag-expressions/actions/workflows/test-python.yml/badge.svg)](https://github.com/cucumber/tag-expressions/actions/workflows/test-python.yml) [![test-ruby](https://github.com/cucumber/tag-expressions/actions/workflows/test-ruby.yml/badge.svg)](https://github.com/cucumber/tag-expressions/actions/workflows/test-ruby.yml) # Tag Expressions Tag Expressions is a simple query language for tags. The simplest tag expression is simply a single tag, for example: @smoke A slightly more elaborate expression may combine tags, for example: @smoke and not @ui Tag Expressions are used for two purposes: 1. Run a subset of scenarios (using the `--tags expression` option of the [command line](https://cucumber.io/docs/cucumber/api/#running-cucumber)) 2. Specify that a hook should only run for a subset of scenarios (using [conditional hooks](https://cucumber.io/docs/cucumber/api/#hooks)) Tag Expressions are [boolean expressions](https://en.wikipedia.org/wiki/Boolean_expression) of tags with the logical operators `and`, `or` and `not`. For more complex Tag Expressions you can use parenthesis for clarity, or to change operator precedence: (@smoke or @ui) and (not @slow) ## Escaping If you need to use one of the reserved characters `(`, `)`, `\` or ` ` (whitespace) in a tag, you can escape it with a `\`. Examples: | Gherkin Tag | Escaped Tag Expression | | ------------- | ---------------------- | | @x(y) | @x\\(y\\) | | @x\y | @x\\\\y | ## Migrating from old style tags Older versions of Cucumber used a different syntax for tags. The list below provides some examples illustrating how to migrate to tag expressions. | Old style command line | Cucumber Expressions style command line | | ----------------------------- | --------------------------------------- | | --tags @dev | --tags @dev | | --tags ~@dev | --tags "not @dev" | | --tags @foo,@bar | --tags "@foo or @bar" | | --tags @foo --tags @bar | --tags "@foo and bar" | | --tags ~@foo --tags @bar,@zap | --tags "not @foo and (@bar or @zap)" | Makefile.PL100644001751000177 234714547500574 20261 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.031. use strict; use warnings; use 5.014004; use ExtUtils::MakeMaker; my %WriteMakefileArgs = ( "ABSTRACT" => "A library for parsing and evaluating cucumber tag expressions (filters)", "AUTHOR" => "Erik Huelsmann , Cucumber Ltd", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "Cucumber-TagExpressions", "LICENSE" => "mit", "MIN_PERL_VERSION" => "5.014004", "NAME" => "Cucumber::TagExpressions", "PREREQ_PM" => { "List::Util" => "1.63", "Moo" => 0 }, "TEST_REQUIRES" => { "Test2::Tools::Exception" => 0, "Test2::V0" => 0, "YAML" => 0 }, "VERSION" => "6.1.0", "test" => { "TESTS" => "t/*.t" } ); my %FallbackPrereqs = ( "List::Util" => "1.63", "Moo" => 0, "Test2::Tools::Exception" => 0, "Test2::V0" => 0, "YAML" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); CHANGELOG.md100644001751000177 2145114547500574 20135 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ## [6.1.0] - 2024-01-10 ### Added - [Python] Support the feature of escaping also in Python ([#144](https://github.com/cucumber/tag-expressions/pull/144)) ### Fixed - [Python] Added workflow to release to Pypi ([#145](https://github.com/cucumber/tag-expressions/pull/145), [#146](https://github.com/cucumber/tag-expressions/pull/146), [#20](https://github.com/cucumber/tag-expressions/issues/20)) - [Ruby] Fixed up around 75% of all rubocop offenses ([#138](https://github.com/cucumber/tag-expressions/pull/138)) ## [6.0.0] - 2023-10-13 ### Added - [Ruby] Initial rubocop gems and basic compliance added (More work to come) ([#133](https://github.com/cucumber/tag-expressions/pull/133)) ### Changed - [Ruby] Minimum ruby version is now bumped from 1.9 to 2.3 ([#133](https://github.com/cucumber/tag-expressions/pull/133)) ### Fixed - [Perl] Include README.md and LICENSE in the release tarball (by [ehuelsmann](https://github.com/ehuelsmann)) ## [5.0.6] - 2023-08-13 ### Fixed - [Perl] Fixed test failures when running tests out-of-tree by resticting testdata based tests to run in development only (by [ehuelsmann](https://github.com/ehuelsmann)) ## [5.0.5] - 2023-08-11 ### Fixed - [Perl] Fixed inclusion of CHANGELOG.md causing release to fail (by [ehuelsmann](https://github.com/ehuelsmann)) ## [5.0.4] - 2023-08-10 ### Fixed - [Perl] Corrected working directory for CPAN upload action (by [ehuelsmann](https://github.com/ehuelsmann)) ## [5.0.3] - 2023-08-10 ### Fixed - [Perl] Fixed CPAN upload in release process (by [ehuelsmann](https://github.com/ehuelsmann)) ## [5.0.2] - 2023-07-15 ### Added - [Python] Make tests pass against shared test data (except: backslash-escaped) ([#18](https://github.com/cucumber/tag-expressions/issues/18) by [jenisys](https://github.com/jenisys)) ### Fixed - [All] `Not.to_string()` conversion has unneeded double-parenthesis if binary operator is contained ([#94](https://github.com/cucumber/tag-expressions/issues/94) by [jenisys](https://github.com/jenisys)) ## [5.0.1] - 2023-01-03 ### Fixed - [Java] Fix scm and project urls ## [5.0.0] - 2023-01-02 ### Added - [JavaScript] Support for EcmaScript modules (aka ESM). ([#5](https://github.com/cucumber/tag-expressions/pull/5)) - [Java] Enabled reproducible builds ### Changed - Only allow escape character `\` in front of `(`, `)`, `\` or whitespace. Throw error otherwise. ([#17](https://github.com/cucumber/tag-expressions/pull/17)) ### Deprecated ### Fixed - [Perl] Fixed missing dependency as well as new syntax in the tests ([cucumber/tag-expressions#15](https://github.com/cucumber/tag-expressions/pull/15) [ehuelsmann](https://github.com/ehuelsmann)) - Document escaping. ([#16](https://github.com/cucumber/tag-expressions/issues/16), [#17](https://github.com/cucumber/tag-expressions/pull/17)) - [Ruby], [Perl] Empty expression evaluates to true - [Go] Fix module name ([#82](https://github.com/cucumber/tag-expressions/pull/82)) ### Removed ## [4.1.0] - 2021-10-08 ### Added - [Perl] Add new implementation ([#1782](https://github.com/cucumber/common/pull/1782) [ehuelsmann](https://github.com/ehuelsmann)) ### Fixed - [Go], [JavaScript], [Java], [Ruby] Support backslash-escape in tag expressions ([#1778](https://github.com/cucumber/common/pull/1778) [yusuke-noda](https://github.com/yusuke-noda)) ## [4.0.2] - 2021-09-13 ### Fixed - [Python] Remove call to deprecated `2to3` library causing `pip install` to fail ([#1736](https://github.com/cucumber/common/issues/1736) [krisgesling](https://github.com/krisgesling)) ## [4.0.0] - 2021-09-02 ### Changed - [Go] Move module paths to point to monorepo ([#1550](https://github.com/cucumber/common/issues/1550)) ## [3.0.1] - 2021-03-31 ### Fixed - Previous release 3.0.0 did not publish to npm for some reason. Re-releasing. ## [3.0.0] - 2020-06-11 ### Added - [Java] Enable consumers to find our version at runtime using `clazz.getPackage().getImplementationVersion()` by upgrading to `cucumber-parent:2.1.0` ([#976](https://github.com/cucumber/cucumber/pull/976) [aslakhellesoy](https://github.com/aslakhellesoy)) ### Changed - [Java] Updated `TagExpressionParser` to use a static method to parse a tag expression and return an `Expression` object to the user. - [Java] Reduced public API to the bare minimum required. - [Java] Added more informative error messages for `TagExpressionParser` through the `TagExpressionException`. ([#1005](https://github.com/cucumber/cucumber/pull/1005) [cyocum](https://github.com/cyocum) ## [2.0.4] - 2020-01-10 ### Changed - [JavaScript] changed module name to `@cucumber/tag-expressions` ## 2.0.3 - 2019-12-10 ### Changed - [Java] Upgrades to `cucumber-parent:2.0.2` - [Ruby] Renamed gem to `tag-expressions` ### Removed - [Ruby] Removed `tag-expressions` executable ## [2.0.2] - 2019-07-15 ### Fixed - Fix incomplete 2.0.1 release ## 2.0.1 - 2019-07-15 ### Fixed - Fix incomplete 2.0.0 release ## [2.0.0] - 2019-07-10 ### Added - Go: New implementation. ([#339](https://github.com/cucumber/cucumber/pull/339) [charlierudolph](https://github.com/charlierudolph)) ### Changed - JavaScript: Changed API to return a `parse` function rather than a class with a `parse` method. - JavaScript: Refactored to TypeScript ### Fixed - Documentation links now point to new website (cucumber.io) ([#560](https://github.com/cucumber/cucumber/issues/560) [luke-hill](https://github.com/luke-hill)) ### Removed - Java: OSGi support has been removed. ([#412](https://github.com/cucumber/cucumber/issues/412) [aslakhellesoy](https://github.com/aslakhellesoy)) ## [1.1.1] - 2017-12-01 ### Fixed - Java: Fix OSGI exported package ([#309](https://github.com/cucumber/cucumber/pull/309) by [mpkorstanje](https://github.com/mpkorstanje)) ## [1.1.0] - 2017-11-28 ### Added - Ruby: Added `tag-expressions` command-line tool for tag expressions ([#282](https://github.com/cucumber/cucumber/pull/282) by [aslakhellesoy](https://github.com/aslakhellesoy)) - Escape special chars in tags ([#286](https://github.com/cucumber/cucumber/pull/286) [#285](https://github.com/cucumber/cucumber/issues/285) by [link89](https://github.com/link89)) ### Fixed - Don't support RPN ([#304](https://github.com/cucumber/cucumber/issues/304) by [aslakhellesoy](https://github.com/aslakhellesoy)) - Parse empty tag expressions (always evaluates to true) ([#296](https://github.com/cucumber/cucumber/issues/296) by [aslakhellesoy](https://github.com/aslakhellesoy)) ## [1.0.1] - 2017-05-28 ### Fixed - javascript: ([#76](https://github.com/cucumber/cucumber/pull/76) [#78](https://github.com/cucumber/cucumber/pull/78) [#104](https://github.com/cucumber/cucumber/issues/104) by [charlierudolph](https://github.com/charlierudolph)) - java: Make the jar a bundle to support OSGi ([#99](https://github.com/cucumber/cucumber/pull/99) by [brasmusson](https://github.com/brasmusson)) - Add a [changelog](keepachangelog.com) ([#213](https://github.com/cucumber/cucumber/issues/213) by [aslakhellesoy](https://github.com/aslakhellesoy)) ## [1.0.0] - 2016-09-01 ### Added - First stable release! [Unreleased]: https://github.com/cucumber/tag-expressions/compare/v6.1.0...HEAD [6.1.0]: https://github.com/cucumber/tag-expressions/compare/v6.0.0...v6.1.0 [6.0.0]: https://github.com/cucumber/tag-expressions/compare/v5.0.6...v6.0.0 [5.0.6]: https://github.com/cucumber/tag-expressions/compare/v5.0.5...v5.0.6 [5.0.5]: https://github.com/cucumber/tag-expressions/compare/v5.0.4...v5.0.5 [5.0.4]: https://github.com/cucumber/tag-expressions/compare/v5.0.3...v5.0.4 [5.0.3]: https://github.com/cucumber/tag-expressions/compare/v5.0.2...v5.0.3 [5.0.2]: https://github.com/cucumber/tag-expressions/compare/v5.0.1...v5.0.2 [5.0.1]: https://github.com/cucumber/tag-expressions/compare/v5.0.0...v5.0.1 [5.0.0]: https://github.com/cucumber/tag-expressions/compare/v4.1.0...v5.0.0 [4.1.0]: https://github.com/cucumber/tag-expressions/compare/v4.0.2...v4.1.0 [4.0.2]: https://github.com/cucumber/tag-expressions/compare/v4.0.0...v4.0.2 [4.0.0]: https://github.com/cucumber/tag-expressions/compare/v3.0.1...v4.0.0 [3.0.1]: https://github.com/cucumber/tag-expressions/compare/v3.0.0...v3.0.1 [3.0.0]: https://github.com/cucumber/tag-expressions/compare/v2.0.4...v3.0.0 [2.0.4]: https://github.com/cucumber/tag-expressions/compare/v2.0.2...v2.0.4 [2.0.2]: https://github.com/cucumber/tag-expressions/compare/v2.0.0...v2.0.2 [2.0.0]: https://github.com/cucumber/tag-expressions/compare/v1.1.1...v2.0.0 [1.1.1]: https://github.com/cucumber/tag-expressions/compare/v1.1.0...v1.1.1 [1.1.0]: https://github.com/cucumber/tag-expressions/compare/v1.0.1...v1.1.0 [1.0.1]: https://github.com/cucumber/tag-expressions/compare/v1.0.0...v1.0.1 [1.0.0]: https://github.com/cucumber/tag-expressions/releases/tag/v1.0.0 t000755001751000177 014547500574 16404 5ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.002-evaluate.t100644001751000177 1070414547500574 21000 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0/t#!perl use strict; use warnings; use Test2::V0; use Cucumber::TagExpressions; my @good = ( { expr => '@a\ or @b', tests => [ { tags => [ '@a\ ' ], outcome => !!0 }, { tags => [ '@a ' ], outcome => 1 }, { tags => [ '@b' ], outcome => 1 }, { tags => [ '@a' ], outcome => !!0 }, ] }, { expr => "\@a\\\\", tests => [] }, { expr => '@a', tests => [ { tags => [ qw/@a/ ], outcome => 1 }, { tags => [ qw/@b/ ], outcome => !!0 }, { tags => [ qw/@a @b/ ], outcome => 1 }, ] }, { expr => 'not @a', tests => [ { tags => [ qw/@a/ ], outcome => !!0 }, { tags => [ qw/@b/ ], outcome => 1 }, { tags => [ qw/@a @b/ ], outcome => !!0 }, ] }, { expr => '@a and @b', tests => [ { tags => [ qw/@a/ ], outcome => !!0 }, { tags => [ qw/@b/ ], outcome => !!0 }, { tags => [ qw/@a @b/ ], outcome => 1 }, ] }, { expr => 'not (@a and @b)', tests => [ { tags => [ qw/@a/ ], outcome => 1 }, { tags => [ qw/@b/ ], outcome => 1 }, { tags => [ qw/@a @b/ ], outcome => !!0 }, ] }, { expr => '@a or @b', tests => [ { tags => [ qw/@a/ ], outcome => 1 }, { tags => [ qw/@b/ ], outcome => 1 }, { tags => [ qw/@a @b/ ], outcome => 1 }, ] }, { expr => 'not @a or @b', tests => [ { tags => [ qw/@a/ ], outcome => !!0 }, { tags => [ qw/@b/ ], outcome => 1 }, { tags => [ qw/@a @b/ ], outcome => 1 }, { tags => [ qw/@q/ ], outcome => 1 }, ] }, { expr => '@a and not @b', tests => [ { tags => [ qw/@a/ ], outcome => 1 }, { tags => [ qw/@b/ ], outcome => !!0 }, { tags => [ qw/@a @b/ ], outcome => !!0 }, { tags => [ qw/@q/ ], outcome => !!0 }, { tags => [ qw/@a @q/ ], outcome => 1 }, ] }, { expr => '@a or @b and @c', tests => [ { tags => [ qw/@a/ ], outcome => 1 }, { tags => [ qw/@b/ ], outcome => !!0 }, { tags => [ qw/@a @b/ ], outcome => 1 }, { tags => [ qw/@a @c/ ], outcome => 1 }, { tags => [ qw/@b @c/ ], outcome => 1 }, ] }, { expr => '@a and @b or not @c', tests => [ { tags => [ qw/@a/ ], outcome => 1 }, { tags => [ qw/@b/ ], outcome => 1 }, { tags => [ qw/@c/ ], outcome => !!0 }, { tags => [ qw/@q/ ], outcome => 1 }, { tags => [ qw/@a @b/ ], outcome => 1 }, { tags => [ qw/@a @c/ ], outcome => !!0 }, { tags => [ qw/@b @c/ ], outcome => !!0 }, ] }, { expr => '@a or ((@b or @c) and (@d or @e))', tests => [ { tags => [ qw/@a/ ], outcome => 1 }, { tags => [ qw/@b/ ], outcome => !!0 }, { tags => [ qw/@d/ ], outcome => !!0 }, { tags => [ qw/@b @d/ ], outcome => 1 }, { tags => [ qw/@q/ ], outcome => !!0 }, ] }, { expr => "\@a\\\\b", tests => [ { tags => [ "\@a\\b" ], outcome => 1 }, { tags => [ '@ab' ], outcome => !!0 }, { tags => [ qw/@a/ ], outcome => !!0 }, ] }, ); for my $ex (@good) { my $e; ok( lives { $e = Cucumber::TagExpressions->parse($ex->{expr}); }, "Parsing $ex->{expr}") or note($@); for my $test ( @{ $ex->{tests} } ) { my @tags = @{ $test->{tags} }; is( $e->evaluate(@tags), $test->{outcome}, "Expr $ex->{expr}; Tags: @tags; Outcome: $test->{outcome} " ) or diag( "Parsed expression: " . $e->stringify ); } } my %bad_syntax = ( '@a @b' => q{Expected operator.}, '@a not' => q{Expected operator.}, '@a or' => 'Unexpected end of input parsing tag expression', '@a not @b' => q{Expected operator.}, '@a or (' => 'Unexpected end of input parsing tag expression', '@a and @b)' => q{Unmatched ).}, "\@a\\" => q{Illegal escape before ""}, ); for my $expr (keys %bad_syntax) { like( dies { Cucumber::TagExpressions->parse($expr); }, qr/\Q$bad_syntax{$expr}\E/, "Parsing bad expression '$expr'" ); } done_testing; 03-shared-tests.t100644001751000177 306014547500574 21556 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0/t#!perl use strict; use warnings; use Test2::V0; use Test2::Tools::Exception qw(lives dies); use YAML qw(LoadFile); use Cucumber::TagExpressions; plan skip_all => 'AUTHOR_TESTING not enabled' if not $ENV{AUTHOR_TESTING}; my $cases = LoadFile('../testdata/evaluations.yml'); for my $case ( @{ $cases } ) { my $evaluator; ok( lives { $evaluator = Cucumber::TagExpressions->parse( $case->{expression} ); }, qq{Parsing "$case->{expression}"} ) or diag($@); ok( $evaluator, "Have an evaluator object from the parser" ); if ($evaluator) { for my $test ( @{ $case->{tests} } ) { my $result = $evaluator->evaluate( @{ $test->{variables} } ); is( $result ? "true" : "false", $test->{result}, "Evaluating $case->{expression} with variables @{$test->{variables}}" ); } } } $cases = LoadFile('../testdata/errors.yml'); for my $case ( @{ $cases } ) { like( dies { Cucumber::TagExpressions->parse( $case->{expression} ); }, qr/\Q$case->{error}\E/, qq{Parsing "$case->{expression}"} ); } $cases = LoadFile('../testdata/parsing.yml'); for my $case ( @{ $cases } ) { my $evaluator; ok( lives { $evaluator = Cucumber::TagExpressions->parse( $case->{expression} ); }, qq{Parsing "$case->{expression}"} ) or diag($@); is( $evaluator->stringify, $case->{formatted}, "Stringified parser for $case->{expression}" ); } done_testing; Cucumber000755001751000177 014547500574 20454 5ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0/libTagExpressions.pm100644001751000177 1273714547500574 24162 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0/lib/Cucumber package Cucumber::TagExpressions; $Cucumber::TagExpressions::VERSION = '6.1.0'; =head1 NAME Cucumber::TagExpressions - Tag expression parser =head1 SYNOPSIS use Cucumber::TagExpressions; my $expr = Cucumber::TagExpressions->parse( '@a and @b' ); if ( $expr->evaluate( qw/x y z/ ) ) { say "The evaluation returned false"; } =head1 DESCRIPTION Cucumber tag expressions allow users to define the subset of Gherkin scenarios they want to run. This library parses the expression and returns an evaluator object which can be used to test the tags specified on a scenario against the filter expression. =head1 CLASS METHODS =cut use strict; use warnings; use Cucumber::TagExpressions::Node; sub _expect_token { my ( $state, $token ) = @_; my $actual = _get_token( $state ); die "Expecting token '$token' but found '$actual'" if $token ne $actual; } sub _consume_char { my ( $state, $allow_eof ) = @_; if ( length($state->{text}) <= $state->{pos} ) { return if $allow_eof; die "Unexpected end of string parsing tag expression: $state->{text}"; } return substr( $state->{text}, $state->{pos}++, 1 ); } sub _get_token { my ( $state ) = @_; return delete $state->{saved_token} if defined $state->{saved_token}; my $token = ''; while (1) { my $char = _consume_char( $state, 1 ); return ($token ? $token : undef) if not defined $char; if ( $char =~ m/\s/ ) { if ( $token ) { return $token; } else { next; } } elsif ( $char eq '(' or $char eq ')' ) { if ( $token ) { _save_token( $state, $char ); return $token; } else { return $char; } } if ( $char eq "\\" ) { $char = _consume_char( $state, 1 ) // ''; if ( $char eq '(' or $char eq ')' or $char eq "\\" or $char =~ /\s/ ) { $token .= $char; } else { die qq{Tag expression "$state->{text}" could not be parsed because of syntax error: Illegal escape before "$char".}; } } else { $token .= $char; } } } sub _save_token { my ( $state, $token ) = @_; $state->{saved_token} = $token; } sub _term_expr { my ( $state ) = @_; my $token = _get_token( $state ); die 'Unexpected end of input parsing tag expression' if not defined $token; if ( $token eq '(' ) { my $expr = _expr( $state ); my $token = _get_token( $state ); if ( not $token or $token ne ')' ) { die qq{Tag expression "$state->{text}" could not be parsed because of syntax error: Unmatched (.} } return $expr; } elsif ( $token eq 'not' ) { return Cucumber::TagExpressions::NotNode->new( expression => _term_expr( $state ) ); } else { if ( $token eq 'and' or $token eq 'or' or $token eq 'not' ) { die qq{Tag expression "$state->{text}" could not be parsed because of syntax error: Expected operand."}; } return Cucumber::TagExpressions::LiteralNode->new( tag => $token ); } } sub _expr { my ( $state ) = @_; my @terms = ( _term_expr( $state ) ); while ( my $token = _get_token( $state ) ) { if ( not defined $token or $token eq ')' ) { _save_token( $state, $token ); last; } if ( not ( $token eq 'or' or $token eq 'and' ) ) { die qq{Tag expression "$state->{text}" could not be parsed because of syntax error: Expected operator.} } my $term = _term_expr( $state ); if ( $token eq 'and' ) { # immediately combine _and_ terms push @terms, Cucumber::TagExpressions::AndNode->new( terms => [ pop(@terms), $term ] ); } else { # collect _or_ terms push @terms, $term; } } if ( scalar(@terms) > 1 ) { return Cucumber::TagExpressions::OrNode->new( terms => \@terms ); } # don't wrap a single-term expression in an Or node return $terms[0]; } =head2 $class->parse( $expression ) Parses the string specified in C<$expression> and returns a L instance. =cut sub parse { my ( $class, $text ) = @_; return Cucumber::TagExpressions::ExpressionNode->new( sub_expression => undef ) if $text =~ /^\s*$/; # match the empty string or space-only string as "constant true" my $state = { pos => 0, text => $text, saved_token => undef }; my $expr = _expr( $state ); my $token = _get_token( $state ); if ( defined $token ) { if ( $token eq ')' ) { die qq{Tag expression "$state->{text}" could not be parsed because of syntax error: Unmatched ).}; } die "Junk at end of expression: $token"; } return Cucumber::TagExpressions::ExpressionNode->new( sub_expression => $expr ); } 1; __END__ =head1 LICENSE Please see the included LICENSE for the canonical version. In summary: The MIT License (MIT) Copyright (c) 2021 Erik Huelsmann Copyright (c) 2021 Cucumber Ltd This work is loosely derived from prior work of the same library for Ruby, called C. =cut TagExpressions000755001751000177 014547500574 23432 5ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0/lib/CucumberNode.pm100644001751000177 1377714547500574 25054 0ustar00runnerdocker000000000000Cucumber-TagExpressions-6.1.0/lib/Cucumber/TagExpressions package Cucumber::TagExpressions::Node; $Cucumber::TagExpressions::Node::VERSION = '6.1.0'; =head1 NAME Cucumber::TagExpressions::Node - Cucumber Tag expression components =head1 SYNOPSIS use Cucumber::TagExpressions; my $expr = Cucumber::TagExpressions->parse( '@a and @b' ); if ( $expr->evaluate( qw/x y z/ ) ) { say "The evaluation returned false"; } =head1 DESCRIPTION This module defines the components making up the tag expressions. =head1 METHODS =cut use Moo; # 'use Moo' implies 'use strict; use warnings;' =head2 evaluate( @tags ) Returns C when the tag set specified in C<$tags> satisfies the condition(s) of the expression, C otherwise. C<@tags> can be a list of tags to be used in the expression. It can also be a reference to a hash with the keys being the tags and the values being considered boolean values indicating whether the tag (key) is considered part of the tagset (true) or not (false). =cut sub evaluate { die 'Abstract superclass; override "evaluate" method'; } =head2 stringify Returns a string representation of the expression node. =cut sub stringify { } =head1 NODE CLASSES =cut package Cucumber::TagExpressions::LiteralNode { $Cucumber::TagExpressions::LiteralNode::VERSION = '6.1.0'; =head2 Cucumber::TagExpressions::LiteralNode =head3 DESCRIPTION This node class returns C if the literal tag is specified as part of the tag-list in the expression evaluation. =head3 ATTRIBUTES =head4 tag The tag to test presence for. =cut use Moo; # 'use Moo' implies 'use strict; use warnings;' extends 'Cucumber::TagExpressions::Node'; has tag => ( is => 'ro', required => 1 ); sub evaluate { my ( $self, $tags ) = @_; return $tags->{ $self->tag }; } sub stringify { my ( $self ) = @_; return ($self->tag =~ s/([ ()\\])/\\$1/gr); } } package Cucumber::TagExpressions::AndNode { $Cucumber::TagExpressions::AndNode::VERSION = '6.1.0'; =head2 Cucumber::TagExpressions::AndNode =head3 DESCRIPTION This node class type evaluates one or more sub-expressions ("terms") and returns C if any of the terms does. It returns C if all of the terms return C. =head3 ATTRIBUTES =head4 terms The sub-expressions to evaluate. =cut use Moo; # 'use Moo' implies 'use strict; use warnings;' extends 'Cucumber::TagExpressions::Node'; use List::Util qw( all reduce ); has terms => ( is => 'ro', required => 1 ); sub evaluate { my ( $self, $tags ) = @_; return all { $_->evaluate( $tags ) } @{ $self->terms }; } sub stringify { my ( $self ) = @_; return reduce { '( ' . $a . ' and ' . $b . ' )' } map { $_->stringify } @{ $self->terms }; } } package Cucumber::TagExpressions::OrNode { $Cucumber::TagExpressions::OrNode::VERSION = '6.1.0'; =head2 Cucumber::TagExpressions::OrNode =head3 DESCRIPTION This node class type evaluates one or more sub-expressions ("terms") and returns C if any of the terms does. It returns C if all of the terms return C. =head3 ATTRIBUTES =head4 terms The sub-expressions to evaluate. =cut use Moo; # 'use Moo' implies 'use strict; use warnings;' extends 'Cucumber::TagExpressions::Node'; use List::Util qw( any reduce ); has terms => ( is => 'ro', required => 1 ); sub evaluate { my ( $self, $tags ) = @_; return any { $_->evaluate( $tags ) } @{ $self->terms }; } sub stringify { my ( $self ) = @_; return reduce { '( ' . $a . ' or ' . $b . ' )' } map { $_->stringify } @{ $self->terms }; } } package Cucumber::TagExpressions::NotNode { $Cucumber::TagExpressions::NotNode::VERSION = '6.1.0'; =head2 Cucumber::TagExpressions::NotNode =head3 DESCRIPTION This class wraps one of the other node class types, negating its result on evaluation. =head3 ATTRIBUTES =head4 expression The wrapped node class instance for which to negate the result. =cut use Moo; # 'use Moo' implies 'use strict; use warnings;' extends 'Cucumber::TagExpressions::Node'; has expression => ( is => 'ro', required => 1 ); sub evaluate { my ( $self, $tags ) = @_; return not $self->expression->evaluate( $tags ); } sub stringify { my ( $self ) = @_; if ($self->expression->isa('Cucumber::TagExpressions::AndNode') || $self->expression->isa('Cucumber::TagExpressions::OrNode')) { # -- HINT: Binary Operators already have already '( ... )'. return 'not ' . $self->expression->stringify; } return 'not ( ' . $self->expression->stringify . ' )'; } } package Cucumber::TagExpressions::ExpressionNode { $Cucumber::TagExpressions::ExpressionNode::VERSION = '6.1.0'; =head2 Cucumber::TagExpressions::ExpressionNode =head3 DESCRIPTION This class models the outer-most node in the tag expression; it wraps all other nodes and is the entry-point for tag expression evaluation. =head3 ATTRIBUTES =head4 sub_expression An instance of one of the other node class types. =cut use Moo; # 'use Moo' implies 'use strict; use warnings;' extends 'Cucumber::TagExpressions::Node'; has sub_expression => ( is => 'ro', required => 1 ); sub evaluate { my ( $self, @tags ) = @_; my $tags = (ref $tags[0] and ref $tags[0] eq 'HASH') ? $tags[0] : { map { $_ => 1 } @tags }; return 1==1 if not defined $self->sub_expression; return not not $self->sub_expression->evaluate( $tags ); } sub stringify { my ( $self ) = @_; return 'true' if not defined $self->sub_expression; return $self->sub_expression->stringify; } } 1; __END__ =head1 LICENSE Please see the included LICENSE for the canonical version. In summary: The MIT License (MIT) Copyright (c) 2021 Erik Huelsmann Copyright (c) 2021 Cucumber Ltd This work is loosely derived from prior work of the same library for Ruby, called C. =cut