cuke4php 0.9.2 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/HISTORY CHANGED
@@ -2,4 +2,14 @@
2
2
  * first gem release
3
3
 
4
4
  2011-01-27 -- 0.9.1
5
- * allow cuke4php to accept a feature filename instead of a path name so users can run just one feature file at a time
5
+ * allow cuke4php to accept a feature filename instead of a path name so users can run just one feature file at a time
6
+
7
+ 2011-01-27 -- 0.9.2
8
+ * fix a bug preventing use by just passing a directory name
9
+
10
+ 2011-01-28
11
+ * trap and handle php errors, convert them to exceptions and then let them bubble up as usual.
12
+
13
+ 2011-01-30
14
+ * use magic setters and getters to allow assignment and retrieval of properties on steps
15
+ * implement step argument transformations
data/README.md CHANGED
@@ -33,6 +33,7 @@ Roadmap
33
33
 
34
34
  * support an option like 'cuke4php --init' which will generate the directory structure and support files necessary to use cuke4php with a php project.
35
35
  * autodetect an available port and then use it to run the cuke4php server pass this on to cucumber by setting an environment variable (requires a modification to cucumber)
36
+ * lint check all php files in features directory before starting the cuke4php server
36
37
 
37
38
  ### Gemfile
38
39
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.2
1
+ 0.9.3
data/bin/cuke4php CHANGED
@@ -5,6 +5,8 @@
5
5
  # TODO: autodetect an available port and then use it to run the cuke4php server pass this on to cucumber by setting an environment variable (requires a modification to cucumber)
6
6
  # see https://github.com/olbrich/cucumber/commit/0c11d206e08e8d5647e03bf78be93723d59529ef
7
7
 
8
+ # TODO: lint check all php files before starting the cuke4php server
9
+
8
10
  # Note that changing the port number currently requires updating the Cuke4Php.wire file in your project's step_definitions
9
11
  # or cucumber will look for the cuke4php server on the wrong port.
10
12
  CUKE4PHP_PORT=ENV['CUKE4PHP_PORT'] || 16816
data/cuke4php.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{cuke4php}
8
- s.version = "0.9.2"
8
+ s.version = "0.9.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Kevin Olbrich", "Alessandro Dal Grande"]
12
- s.date = %q{2011-01-27}
12
+ s.date = %q{2011-03-23}
13
13
  s.default_executable = %q{cuke4php}
14
14
  s.description = %q{Using this protocol it is possible to directly interact with PHP code at any level without the need for a web server. To accomplish this, when cucumber is running against a directory containing feature files and it cannot resolve a particular step definition, it will ask a known wire server (as defined in a .wire file) to interpret and run those steps.}
15
15
  s.email = ["kevin.olbrich+cuke4php@gmail.com", "aledalgrande@gmail.com"]
@@ -30,10 +30,12 @@ Gem::Specification.new do |s|
30
30
  "cucumber.yml",
31
31
  "cuke4php.gemspec",
32
32
  "features/Cuke4Php.feature",
33
+ "features/scenario.feature",
33
34
  "features/step_definitions/Cuke4Php.wire",
34
35
  "features/step_definitions/TestSteps.php",
35
36
  "features/step_definitions/WireSteps.php",
36
37
  "features/support/Env.php",
38
+ "features/transform.feature",
37
39
  "lib/Cucumber.php",
38
40
  "lib/CucumberScenario.php",
39
41
  "lib/CucumberSteps.php",
@@ -40,3 +40,18 @@ Scenario Outline: run several steps many times
40
40
  | shoot | messenger | dead |
41
41
  | understand | meaning | clear |
42
42
 
43
+ @error
44
+ Scenario Outline: Error Handling
45
+ When an error "<error_constant>" with message "<error_message>" occurs
46
+ Then an "<exception>" should be caught
47
+
48
+ Examples:
49
+ | error_constant | error_message | exception |
50
+ | E_USER_ERROR | an error has occurred | PHPUnit_Framework_Error |
51
+ | E_USER_WARNING | a warning message | PHPUnit_Framework_Error_Warning |
52
+ | E_USER_NOTICE | a notice message | PHPUnit_Framework_Error_Notice |
53
+
54
+ @exception
55
+ Scenario: Exception Handling
56
+ When an "Exception" is thrown with message "generic exception"
57
+ Then an "Exception" should be caught
@@ -0,0 +1,45 @@
1
+ Feature: Scenarios
2
+
3
+ Scenario Outline: I save values as properties and use them again later
4
+ Given I store "<value>" into "<value>"
5
+ Then "<value>" should equal "<value>"
6
+
7
+ Examples:
8
+ | value |
9
+ | ! |
10
+ | @ |
11
+ | # |
12
+ | $ |
13
+ | % |
14
+ | ^ |
15
+ | & |
16
+ | * |
17
+ | ( |
18
+ | ) |
19
+ | - |
20
+ | = |
21
+ | () |
22
+ | with spaces |
23
+ | $sVar |
24
+
25
+ Scenario: I save an array as a property
26
+ Given "value" is:
27
+ | key | value |
28
+ | key1 | value1 |
29
+ | key2 | value2 |
30
+ Then "value" should be set
31
+ Then "non-value" should not be set
32
+ And "value" should equal:
33
+ | key | value |
34
+ | key1 | value1 |
35
+ | key2 | value2 |
36
+
37
+ Scenario: I unset a property
38
+ Given I store "Foo" into "Bar"
39
+ When I unset "Bar"
40
+ Then "Bar" should not be set
41
+
42
+ Scenario: I try to read a property that was not set first
43
+ Given "Foo" should not be set
44
+ Then getting "Foo" should raise an "PHPUnit_Framework_Error"
45
+
@@ -45,7 +45,7 @@ class TestSteps extends CucumberSteps {
45
45
  * Given /^an exception is thrown$/
46
46
  */
47
47
  public function stepException() {
48
- throw new TestException('Exception');
48
+ throw new Exception('test exception');
49
49
  }
50
50
 
51
51
  /**
@@ -11,7 +11,7 @@ class WireSteps extends CucumberSteps {
11
11
  * @wire
12
12
  */
13
13
  function beforeWire() {
14
- $this->aGlobals['before'] = 'beforeWire';
14
+ $this->before = 'beforeWire';
15
15
  }
16
16
 
17
17
  function beforeAll() {
@@ -81,7 +81,137 @@ class WireSteps extends CucumberSteps {
81
81
 
82
82
  }
83
83
 
84
+ /**
85
+ * When /^an error "([^"]*)" with message "([^"]*)" occurs$/
86
+ **/
87
+ public function stepAnErrorParameterWithMessageParameterOccurs($sType,$sMessage) {
88
+ try {
89
+ trigger_error($sMessage, constant($sType));
90
+ } catch (Exception $e) {
91
+ $this->exception = $e;
92
+ }
93
+ }
94
+
95
+ /**
96
+ * When /^an? "([^"]*)" is thrown with message "([^"]*)"$/
97
+ **/
98
+ public function stepAnExceptionParameterIsThrownWithMessageParameter($sExceptionClass,$sMessage) {
99
+ try {
100
+ throw new $sExceptionClass($sMessage);
101
+ } catch (Exception $e) {
102
+ $this->exception = $e;
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Then /^an? "([^"]*)" should be caught$/
108
+ **/
109
+ public function stepAParameterExceptionShouldBeCaught($sExceptionType) {
110
+ self::assertInstanceOf($sExceptionType, $this->exception);
111
+ }
112
+
113
+ /**
114
+ * Given /^I store "([^"]*)" into "([^"]*)"$/
115
+ **/
116
+ public function stepIStoreParameterIntoParameter($sValue,$sKey) {
117
+ $this->$sKey = $sValue;
118
+ }
119
+
120
+
121
+ /**
122
+ * Then /^"([^"]*)" should equal "([^"]*)"$/
123
+ **/
124
+ public function stepParameterShouldEqualParameter($sKey,$sValue) {
125
+ self::assertEquals($sValue, $this->$sKey);
126
+ }
127
+
128
+ /**
129
+ * When /^I unset "([^"]*)"$/
130
+ **/
131
+ public function stepIUnsetParameter($sKey) {
132
+ unset($this->$sKey);
133
+ }
134
+
135
+ /**
136
+ * Then /^"([^"]*)" (should|should not) be set$/
137
+ **/
138
+ public function stepParameterShouldBeSet($sKey, $sShould) {
139
+ self::assertEquals(($sShould == "should"), isset($this->$sKey));
140
+ }
141
+
142
+ /**
143
+ * Given /^"([^"]*)" is\:$/
144
+ **/
145
+ public function stepParameterIs($sKey,$aTable) {
146
+ array_shift($aTable); // peel off the table column headings
147
+ $this->$sKey = $aTable;
148
+ }
84
149
 
150
+ /**
151
+ * Then /^"([^"]*)" should equal\:$/
152
+ **/
153
+ public function stepParameterShouldEqual($sKey,$aTable) {
154
+ array_shift($aTable); // peel off the table column headings
155
+ self::assertEquals($aTable, $this->$sKey);
156
+ }
157
+
158
+ /**
159
+ * Then /^getting "([^"]*)" should raise an? "([^"]*)"$/
160
+ **/
161
+ public function stepGettingParameterShouldRaiseAnParameter($sKey, $sExceptionClass) {
162
+ unset($this->exception);
163
+ try {
164
+ $this->$sKey;
165
+ self::fail("No Exception Caught");
166
+ } catch (Exception $e) {
167
+ $this->exception = $e;
168
+ }
169
+ self::assertInstanceOf($sExceptionClass, $this->exception);
170
+ }
171
+
172
+ /**
173
+ * Transform /^(\d+)$/
174
+ **/
175
+ public function transformToInteger($sArg) {
176
+ return intval($sArg);
177
+ }
178
+
179
+ /**
180
+ * Transform /^(abcd)$/
181
+ **/
182
+ public function transformReverse($sArg) {
183
+ return "dcba";
184
+ }
185
+
186
+ /**
187
+ * Transform /^(abcd)$/
188
+ **/
189
+ public function transformCapitalize($sArg) {
190
+ return "ABCD";
191
+ }
192
+
193
+ /**
194
+ * Transform /^\{(.*)\}$/
195
+ **/
196
+ public function transformSubstituteValues($sArg) {
197
+ return $this->$sArg;
198
+ }
199
+
200
+ /**
201
+ * Transform /^table:reverse$/
202
+ **/
203
+ public function transformReverseTable($aTable) {
204
+ return array_reverse($aTable);
205
+ }
206
+
207
+
208
+ /**
209
+ * Then /^"([^"]*)" should be a kind of "([^"]*)"$/
210
+ **/
211
+ public function stepParameterShouldBeAKindOfParameter($sKey,$sTypeName) {
212
+ self::assertInternalType($sTypeName, $this->$sKey);
213
+ }
214
+
85
215
  }
86
216
 
87
217
  ?>
@@ -0,0 +1,30 @@
1
+ Feature: Argument Transformation
2
+ As a user of cuke4php
3
+ I want to use step argument transforms
4
+ So that I can simplify my code
5
+ Example transforms can be found in WireSteps.php
6
+
7
+ Scenario: An argument is transformed to an integer
8
+ Given I store "123" into "Foo"
9
+ Then "Foo" should be a kind of "integer"
10
+
11
+ Scenario: use a transform to substitute variable in arguments
12
+ Given I store "foo" into "Bar"
13
+ And I store "{Bar}" into "Foo"
14
+ Then "Foo" should equal "foo"
15
+
16
+ Scenario: An argument is transformed, but the second defined transform wins
17
+ Given I store "abcd" into "Foo"
18
+ Then "Foo" should equal "ABCD"
19
+
20
+ Scenario: transform a table
21
+ Given "table" is:
22
+ | reverse |
23
+ | one |
24
+ | two |
25
+ | three |
26
+ Then "table" should equal:
27
+ | reverse |
28
+ | three |
29
+ | two |
30
+ | one |
@@ -58,38 +58,46 @@ class CucumberScenario {
58
58
  * @return array
59
59
  * invokes all the before hooks defined that either have no tags or tags corresponding to this scenario's tags
60
60
  */
61
- function invokeBeforeHooks($aTags) {
62
- foreach ($this->aWorld['before'] as $aBeforeHook) {
63
- if (array_key_exists('tags', $aBeforeHook))
64
- if (count($aBeforeHook['tags']) == 0 || count(array_intersect($aTags, $aBeforeHook['tags'])) > 0) {
65
- $oStep = CucumberSteps::getInstance($aBeforeHook['class'], $this->aGlobals);
66
- $oResult = $oStep->invoke($aBeforeHook['method']);
67
- if ($oResult === false) {
68
- return array('failure');
69
- }
70
- }
71
- }
72
- return array('success');
73
- }
61
+ function invokeBeforeHooks($aTags) {
62
+ if (is_null($aTags)) {
63
+ $aTags = array();
64
+ }
65
+ foreach ($this->aWorld['before'] as $aBeforeHook) {
66
+ if (array_key_exists('tags', $aBeforeHook)) {
67
+ if (count($aBeforeHook['tags']) == 0 || count(array_intersect($aTags, $aBeforeHook['tags'])) > 0) {
68
+ $oStep = CucumberSteps::getInstance($aBeforeHook['class'], $this->aGlobals);
69
+ $oResult = $oStep->invoke($aBeforeHook['method']);
70
+ if ($oResult === false) {
71
+ return array('failure');
72
+ }
73
+ }
74
+ }
75
+ }
76
+ return array('success');
77
+ }
74
78
 
75
79
  /**
76
80
  * @param $aTags
77
81
  * @return array
78
82
  * invoke all after hooks defined that either have no tags, or tags that match the tags of the current scenario
79
83
  */
80
- function invokeAfterHooks($aTags) {
81
- foreach ($this->aWorld['after'] as $aAfterHook) {
82
- if (array_key_exists('tags', $aAfterHook))
83
- if (count($aAfterHook['tags']) == 0 || count(array_intersect($aTags, $aAfterHook['tags'])) > 0) {
84
- $oStep = CucumberSteps::getInstance($aAfterHook['class'], $this->aGlobals);
85
- $oResult = $oStep->invoke($aAfterHook['method']);
86
- if ($oResult === false) {
87
- return array('failure');
88
- }
89
- }
90
- }
91
- return array('success');
92
- }
84
+ function invokeAfterHooks($aTags) {
85
+ if (is_null($aTags)) {
86
+ $aTags = array();
87
+ }
88
+ foreach ($this->aWorld['after'] as $aAfterHook) {
89
+ if (array_key_exists('tags', $aAfterHook)) {
90
+ if (count($aAfterHook['tags']) == 0 || count(array_intersect($aTags, $aAfterHook['tags'])) > 0) {
91
+ $oStep = CucumberSteps::getInstance($aAfterHook['class'], $this->aGlobals);
92
+ $oResult = $oStep->invoke($aAfterHook['method']);
93
+ if ($oResult === false) {
94
+ return array('failure');
95
+ }
96
+ }
97
+ }
98
+ }
99
+ return array('success');
100
+ }
93
101
 
94
102
  /**
95
103
  * @param $iStepId
@@ -104,6 +112,25 @@ class CucumberScenario {
104
112
  function invoke($iStepId, $aArgs) {
105
113
  $aStep = $this->aWorld['steps'][$iStepId];
106
114
  $oStep = new $aStep['class']($this->aGlobals);
115
+ foreach ($aArgs as &$sArg) {
116
+ $sArgTest = $sArg;
117
+ if (is_array($sArgTest)) {
118
+ $sArgTest = "table:" . implode(",",$sArgTest[0]);
119
+ }
120
+ foreach (array_reverse($this->aWorld['transform'],true) as $aTransform) {
121
+ $aMatches = array();
122
+ if (preg_match_all($aTransform['regexp'], $sArgTest, $aMatches, PREG_OFFSET_CAPTURE)) {
123
+ $oTransform = new $aTransform['class']($this->aGlobals);
124
+ if (is_array($sArg)) {
125
+ $sArg = call_user_func_array(array($oTransform, $aTransform['method']),$sArg);
126
+ } else {
127
+ $sArg = call_user_func_array(array($oTransform, $aTransform['method']),$aMatches[1][0]);
128
+ }
129
+ break;
130
+ }
131
+ }
132
+
133
+ }
107
134
  try {
108
135
  call_user_func_array(array($oStep, $aStep['method']),$aArgs);
109
136
  } catch (PHPUnit_Framework_IncompleteTestError $e) {
@@ -113,7 +140,7 @@ class CucumberScenario {
113
140
  } catch (PHPUnit_Framework_ExpectationFailedException $e) {
114
141
  return array('fail', array('message' => $e->getMessage()));
115
142
  } catch (Exception $e) {
116
- return array('fail', array('exception' => $e->__toString()));
143
+ return array('fail', array('message' => $e->getMessage() . " " . $e->getFile() . ":" . $e->getLine(), 'exception' => get_class($e), 'backtrace' => $e->getTraceAsString()));
117
144
  }
118
145
  return array('success');
119
146
  }
@@ -74,6 +74,26 @@ class CucumberSteps extends PHPUnit_Framework_Assert {
74
74
  return new $sClass($aGlobals);
75
75
  }
76
76
  }
77
+
78
+ public function __set($sName, $sValue) {
79
+ $this->aGlobals[$sName] = $sValue;
80
+ }
81
+
82
+ public function __get($sName) {
83
+ if (array_key_exists($sName, $this->aGlobals)) {
84
+ return $this->aGlobals[$sName];
85
+ } else {
86
+ trigger_error("Property ($sName) not defined", E_USER_ERROR);
87
+ }
88
+ }
89
+
90
+ public function __unset($sName) {
91
+ unset($this->aGlobals[$sName]);
92
+ }
93
+
94
+ public function __isset($sName) {
95
+ return isset($this->aGlobals[$sName]);
96
+ }
77
97
  }
78
98
 
79
99
  ?>
data/lib/Cuke4Php.php CHANGED
@@ -21,7 +21,8 @@ class Cuke4Php {
21
21
  public $aWorld = array(
22
22
  'steps' => array(),
23
23
  'before' => array(),
24
- 'after' => array()
24
+ 'after' => array(),
25
+ 'transform' => array()
25
26
  );
26
27
 
27
28
  function __construct($_sFeaturePath, $_iPort = 16816) {
@@ -33,10 +34,15 @@ class Cuke4Php {
33
34
  } else {
34
35
  $this->iPort = 16816;
35
36
  }
36
-
37
+
37
38
  foreach (self::rglob("*.php", 0, $_sFeaturePath . "/support") as $sFilename) {
38
39
  require_once $sFilename;
39
40
  }
41
+ set_error_handler(
42
+ array('PHPUnit_Util_ErrorHandler', 'handleError'),
43
+ E_ALL | E_STRICT
44
+ );
45
+
40
46
  require_once "Cucumber.php";
41
47
  foreach (self::rglob("*.php", 0, $_sFeaturePath . "/step_definitions") as $sFilename) {
42
48
  require_once $sFilename;
@@ -71,6 +77,12 @@ class Cuke4Php {
71
77
  $this->aWorld['after'][] = $aMethod;
72
78
  continue;
73
79
  }
80
+ if (substr($oMethod->name, 0, 9) == "transform") {
81
+ preg_match("/(?:Transform) (.+)$/im", $sComment, $aMatches);
82
+ $aMethod['regexp'] = $aMatches[1];
83
+ $this->aWorld['transform'][] = $aMethod;
84
+ continue;
85
+ }
74
86
  }
75
87
  }
76
88
  }
@@ -114,9 +126,9 @@ class Cuke4Php {
114
126
  $data = trim($input);
115
127
  if ($data !== "") {
116
128
  $output = json_encode($this->process($data)) . "\n";
117
- if ($this->bRun) {
118
- socket_write($connection, $output);
119
- }
129
+ if ($this->bRun) {
130
+ socket_write($connection, $output);
131
+ }
120
132
  }
121
133
  }
122
134
  socket_close($connection);
@@ -134,7 +146,8 @@ class Cuke4Php {
134
146
  default:
135
147
  $aCommand = json_decode($sInput);
136
148
  $sAction = $aCommand[0];
137
- $sData = NULL;
149
+ $sData = new stdClass;
150
+ $sData->tags = array();
138
151
  if (array_key_exists(1, $aCommand)) {
139
152
  $sData = $aCommand[1];
140
153
  }
@@ -35,6 +35,7 @@ class CucumberScenarioTest extends PHPUnit_Framework_TestCase {
35
35
  public function setup() {
36
36
  CucumberSteps::clearMocks();
37
37
  $this->aWorld = array(
38
+ 'transform' => array(),
38
39
  'before' => array(
39
40
  array(
40
41
  'tags' => array('one'),
@@ -149,7 +150,10 @@ class CucumberScenarioTest extends PHPUnit_Framework_TestCase {
149
150
  }
150
151
 
151
152
  public function testInvokeShouldFailWhenExceptionThrown() {
152
- self::assertEquals(array('fail',array('exception' => 'TestException')), $this->oScenario->invoke(5,array()));
153
+ $aResult = $this->oScenario->invoke(5,array());
154
+ self::assertEquals('fail',$aResult[0]);
155
+ self::assertEquals('Exception', $aResult[1]['exception']);
156
+ self::assertEquals('test exception /Users/kolbrich/local_src/cuke4php/features/step_definitions/TestSteps.php:48', $aResult[1]['message']);
153
157
  }
154
158
 
155
159
  public function testInvokeShouldSucceedWithParameters() {
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cuke4php
3
3
  version: !ruby/object:Gem::Version
4
- hash: 63
4
+ hash: 61
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
- - 2
10
- version: 0.9.2
9
+ - 3
10
+ version: 0.9.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kevin Olbrich
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-01-27 00:00:00 -05:00
19
+ date: 2011-03-23 00:00:00 -04:00
20
20
  default_executable: cuke4php
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -85,10 +85,12 @@ files:
85
85
  - cucumber.yml
86
86
  - cuke4php.gemspec
87
87
  - features/Cuke4Php.feature
88
+ - features/scenario.feature
88
89
  - features/step_definitions/Cuke4Php.wire
89
90
  - features/step_definitions/TestSteps.php
90
91
  - features/step_definitions/WireSteps.php
91
92
  - features/support/Env.php
93
+ - features/transform.feature
92
94
  - lib/Cucumber.php
93
95
  - lib/CucumberScenario.php
94
96
  - lib/CucumberSteps.php