Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
662 changes: 662 additions & 0 deletions .github/copilot-instructions.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions examples/python-calculator/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
__pycache__/
*.pyc
*.pyo
.pytest_cache/
69 changes: 69 additions & 0 deletions examples/python-calculator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Python Calculator Example

This is a simple example demonstrating how to use the Cucumber-Behave launcher with Eclipse.

## Prerequisites

1. Python 3.x installed
2. Behave package installed:
```bash
pip install behave
```

## Running the Example

### From Command Line

```bash
cd examples/python-calculator
behave
```

### From Eclipse

1. Open Eclipse with Cucumber Eclipse plugin installed
2. Import this project into Eclipse
3. Right-click on `features/calculator.feature`
4. Select "Run As" > "Cucumber-Behave"
5. In the launch configuration dialog:
- **Feature Path**: Select the `calculator.feature` file
- **Working Directory**: Set to the `examples/python-calculator` directory
- **Python Interpreter**: Use `python` or `python3` depending on your system
- Click "Run"

## Project Structure

```
python-calculator/
├── features/
│ ├── calculator.feature # Feature file with scenarios
│ └── steps/
│ └── calculator_steps.py # Step definitions
└── README.md
```

## Expected Output

When you run the tests, you should see output indicating that all three scenarios pass:

```
Feature: Calculator # features/calculator.feature:1

Scenario: Add two numbers # features/calculator.feature:6
Given I have a calculator # features/steps/calculator_steps.py:19
When I add 2 and 3 # features/steps/calculator_steps.py:23
Then the result should be 5 # features/steps/calculator_steps.py:35

Scenario: Subtract two numbers # features/calculator.feature:11
Given I have a calculator # features/steps/calculator_steps.py:19
When I subtract 3 from 5 # features/steps/calculator_steps.py:27
Then the result should be 2 # features/steps/calculator_steps.py:35

Scenario: Multiply two numbers # features/calculator.feature:16
Given I have a calculator # features/steps/calculator_steps.py:19
When I multiply 2 by 3 # features/steps/calculator_steps.py:31
Then the result should be 6 # features/steps/calculator_steps.py:35

3 scenarios (3 passed)
9 steps (9 passed)
```
19 changes: 19 additions & 0 deletions examples/python-calculator/features/calculator.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Feature: Calculator
As a user
I want to use a calculator
So that I can perform basic arithmetic operations

Scenario: Add two numbers
Given I have a calculator
When I add 2 and 3
Then the result should be 5

Scenario: Subtract two numbers
Given I have a calculator
When I subtract 3 from 5
Then the result should be 2

Scenario: Multiply two numbers
Given I have a calculator
When I multiply 2 by 3
Then the result should be 6
38 changes: 38 additions & 0 deletions examples/python-calculator/features/steps/calculator_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from behave import given, when, then

class Calculator:
def __init__(self):
self.result = 0

def add(self, a, b):
self.result = a + b
return self.result

def subtract(self, a, b):
self.result = a - b
return self.result

def multiply(self, a, b):
self.result = a * b
return self.result

@given('I have a calculator')
def step_impl(context):
context.calculator = Calculator()

@when('I add {a:d} and {b:d}')
def step_impl(context, a, b):
context.calculator.add(a, b)

@when('I subtract {a:d} from {b:d}')
def step_impl(context, a, b):
context.calculator.subtract(b, a)

@when('I multiply {a:d} by {b:d}')
def step_impl(context, a, b):
context.calculator.multiply(a, b)

@then('the result should be {expected:d}')
def step_impl(context, expected):
assert context.calculator.result == expected, \
f"Expected {expected}, but got {context.calculator.result}"
4 changes: 4 additions & 0 deletions io.cucumber.eclipse.feature/feature.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
id="io.cucumber.eclipse.java.plugins"
version="0.0.0"/>

<plugin
id="io.cucumber.eclipse.python"
version="0.0.0"/>

</feature>
7 changes: 7 additions & 0 deletions io.cucumber.eclipse.python/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>
1 change: 1 addition & 0 deletions io.cucumber.eclipse.python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bin/
28 changes: 28 additions & 0 deletions io.cucumber.eclipse.python/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>io.cucumber.eclipse.python</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
org.eclipse.jdt.core.compiler.compliance=21
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=21
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
classpath=true
dsVersion=V1_3
eclipse.preferences.version=1
enabled=true
generateBundleActivationPolicyLazy=true
path=OSGI-INF
validationErrorLevel=error
validationErrorLevel.missingImplicitUnbindMethod=error
175 changes: 175 additions & 0 deletions io.cucumber.eclipse.python/IMPLEMENTATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# Implementation Summary: io.cucumber.eclipse.python Bundle

This document describes the implementation of the new `io.cucumber.eclipse.python` bundle that enables launching Cucumber feature files using Python's Behave framework.

## Implementation Overview

The bundle provides a complete Eclipse launch configuration for running Cucumber feature files with Behave, following the same architectural pattern as the existing `io.cucumber.eclipse.java` bundle.

## Components Implemented

### 1. Core Bundle Configuration

- **MANIFEST.MF**: Defines bundle metadata, dependencies, and exported packages
- Dependencies include Eclipse UI/Debug framework and optional PyDev support
- Targets JavaSE-21 runtime environment
- Optional resolution for PyDev plugins to avoid hard dependency

- **plugin.xml**: Declares Eclipse extension points
- Launch configuration type: `cucumber.eclipse.python.launching.localCucumberBehave`
- Launch configuration UI (tab groups and icon)
- Launch shortcut for context menu integration
- Contextual launch support for `.feature` files

- **build.properties**: Maven/Tycho build configuration
- Source directory: `src/`
- Binary directory: `bin/`
- Includes plugin.xml, icons, and OSGI-INF

### 2. Launch Framework Classes

#### CucumberBehaveLaunchConstants
- Defines configuration attribute keys:
- `ATTR_FEATURE_PATH`: Path to feature file
- `ATTR_WORKING_DIRECTORY`: Working directory for execution
- `ATTR_PYTHON_INTERPRETER`: Python interpreter path
- `ATTR_TAGS`: Tag expression for filtering
- `ATTR_IS_VERBOSE`: Enable verbose output
- `ATTR_IS_NO_CAPTURE`: Disable output capture
- `ATTR_IS_DRY_RUN`: Enable dry-run mode

#### CucumberBehaveLaunchConfigurationDelegate
- Main launch delegate extending `LaunchConfigurationDelegate`
- Responsibilities:
- Read launch configuration attributes
- Build behave command with appropriate flags
- Create and manage Python process
- Handle working directory and environment
- Support for tags, verbose, no-capture, and dry-run options

#### CucumberBehaveTabGroup
- Launch configuration tab group
- Includes:
- CucumberBehaveMainTab (main configuration)
- EnvironmentTab (environment variables)
- CommonTab (common launch settings)

#### CucumberBehaveMainTab
- Main configuration UI tab extending `AbstractLaunchConfigurationTab`
- UI Components:
- Feature Path selector with file browser
- Working Directory selector with directory browser
- Python Interpreter text field
- Tags text field
- Behave Options checkboxes (Verbose, No Capture, Dry Run)
- Validates required fields (feature path, working directory)

#### CucumberBehaveLauncher
- Implements `ILauncher` interface for integration with editor's launch framework
- Registered as OSGi service component
- Automatically discovered by `CucumberFeatureLaunchShortcut` in editor bundle
- Supports running feature files and specific scenarios
- Handles tag filtering and temporary launch configurations

### 3. Bundle Infrastructure

- **Activator.java**: OSGi bundle activator
- **OSGI-INF/CucumberBehaveLauncher.xml**: OSGi Declarative Services descriptor for ILauncher registration
- **.project**: Eclipse project configuration (PDE plugin nature)
- **.classpath**: Java classpath configuration (JavaSE-21)
- **.settings/**: Eclipse project settings (JDT, PDE)
- **.gitignore**: Excludes bin/ directory from version control

## Integration with Existing Codebase

### Parent POM
- Added `io.cucumber.eclipse.python` module to parent `pom.xml`

### Feature Definition
- Added plugin entry to `io.cucumber.eclipse.feature/feature.xml`

## Example Project

Created `examples/python-calculator/` demonstrating usage:
- Simple calculator feature with scenarios
- Python step definitions using Behave
- README with setup and usage instructions
- Demonstrates add, subtract, and multiply operations

## Design Decisions

1. **Independent Bundle**: Created as a standalone bundle rather than extending existing Java bundle
- Cleaner separation of concerns
- Easier to maintain and update independently
- Follows Eclipse plugin architecture best practices

2. **ILauncher Implementation**: Implements the `ILauncher` interface from editor bundle
- Integrates with existing `CucumberFeatureLaunchShortcut` in editor
- Registered as OSGi service component for automatic discovery
- Supports running from editor or project explorer context menus
- No need for custom launch shortcut implementation

3. **Optional PyDev Dependencies**: Marked as optional in MANIFEST.MF
- Allows bundle to work without PyDev installed
- Provides better integration when PyDev is available
- Future enhancement: Could use PyDev for Python interpreter selection

4. **Simple Launch Delegate**: Uses standard ProcessBuilder
- Direct execution of behave command
- No dependency on PyDev launch infrastructure
- Easy to understand and maintain
- Future enhancement: Could integrate with PyDev's Python runner

5. **Behave-specific Options**: Focused on common Behave options
- Verbose, no-capture, and dry-run flags
- Tag filtering support
- Future enhancement: Could add more Behave-specific options (format, color, etc.)

## Future Enhancements

1. **PyDev Integration**
- Use PyDev's Python interpreter configuration
- Integrate with PyDev's Python project settings
- Use PyDev's console for output

2. **Debug Support**
- Integrate with Python debugger
- Breakpoint support in step definitions
- Variable inspection

3. **Advanced Behave Options**
- More formatter options (JSON, JUnit XML, etc.)
- Coverage integration
- Parallel execution support

4. **Step Definition Navigation**
- Jump from feature file to step definition
- Step definition completion
- Unused step detection

5. **Test Results Integration**
- Eclipse test results view integration
- Visual representation of test execution
- Failed test navigation

## Testing

The implementation has been designed to follow the same patterns as the Java bundle, but requires a full Eclipse environment with the plugin installed to test:

1. Import the bundle into Eclipse with PDE
2. Launch Eclipse Application (Run As > Eclipse Application)
3. Create a Python project with Behave installed
4. Create a feature file
5. Right-click and select "Run As > Cucumber-Behave"

## Compliance with Requirements

✅ New bundle `io.cucumber.eclipse.python` created
✅ Contains methods to launch Python process using Behave
✅ Reuses Eclipse Debug framework (similar to PyDev approach)
✅ Executes Cucumber feature files with Python glue code via Behave
✅ Defines `org.eclipse.debug.core.launchConfigurationTypes` as "Cucumber-Behave"
✅ Follows the Java implementation (`io.cucumber.eclipse.java`) as a blueprint
✅ Launch configuration UI with tabs for configuration
✅ Implements `ILauncher` interface for integration with editor's launch framework
✅ Registered as OSGi service component for automatic discovery
Loading