Skip to content

Commit 2b5b847

Browse files
committed
Basic testing based on headers is working. See README.md locutusjs#80
1 parent e1debab commit 2b5b847

File tree

11 files changed

+2388
-111
lines changed

11 files changed

+2388
-111
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ nbproject
44
gitup.dat
55
.project
66
.gitup.dat
7-
_tools/nest/node_modules/
7+
_tests/node_modules/

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ setup:
44
rake setup_github_pages\[git@github.com:kvz/phpjs.git\] && \
55
cd .. ; \
66

7+
test:
8+
find functions -type f |grep -v '/_' |xargs node _tests/cli.js -f
9+
710
site:
811
git pull && \
912
cd _octopress && \

_tests/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
# Cli
3+
4+
```bash
5+
node cli.js -f ../functions/datetime/strtotime.js
6+
node cli.js -f ../functions/datetime/date.js
7+
```
8+
9+
# Web
10+
11+
```html
12+
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
13+
<script src="phpjs.js"></script>
14+
<script type="text/javascript">
15+
// Get `code`
16+
Phpjs.parse(code, function (err, result) {
17+
if (err) {
18+
$('#content').append('<pre class="alert-warning alert">' + JSON.stringify(err, undefined, 2) + '</pre>');
19+
}
20+
$('#content').append('<pre>' + JSON.stringify(result, undefined, 2) + '</pre>');
21+
22+
console.log(result);
23+
});
24+
</script>
25+
```
26+

_tests/cli.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
var cli = require('cli').enable('status', 'help', 'version', 'glob', 'timeout');
2+
var FS = require('fs');
3+
var phpjs = require('./phpjs');
4+
5+
cli.parse({
6+
function_file: ['f', 'Function to test', 'path'],
7+
});
8+
9+
cli.main(function(args, options) {
10+
if (!options.function_file) {
11+
this.fatal('Please specify a file to test (-h for help)');
12+
}
13+
14+
// cli.spinner('Working..');
15+
// cli.spinner('Working.. done!', true); //End the spinner
16+
17+
FS.readFile(options.function_file, 'utf-8', function (err, code) {
18+
if (err) {
19+
return cli.fatal(err);
20+
}
21+
22+
phpjs.parse(options.function_file, code, function (err, params) {
23+
if (err) {
24+
return cli.fatal(err);
25+
}
26+
// console.log(params['headKeys']);
27+
28+
phpjs.test(params, function(err, test, params) {
29+
var testline = params['name'] +
30+
'#' + test['number'] +
31+
'\t' + test['example'] +
32+
'\t' + test['expected'] +
33+
'\t' + test['result'] +
34+
'\t';
35+
36+
if (err) {
37+
cli.error(testline + ' test failed :(');
38+
}
39+
cli.ok(testline + ' test passed :)');
40+
});
41+
});
42+
});
43+
44+
});

_tests/index.html

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>php.js demo</title>
6+
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet" />
7+
</head>
8+
<body>
9+
<div class="container">
10+
<h1>php.js demo</h1>
11+
<div id="content"></div>
12+
</div>
13+
</body>
14+
15+
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
16+
<script src="phpjs.js"></script>
17+
18+
<script type="text/javascript">
19+
var code = 'function strtotime (text, now) {\n' +
20+
' // Convert string representation of date and time to a timestamp\n' +
21+
' //\n' +
22+
' // version: 1109.2015\n' +
23+
' // discuss at: http://phpjs.org/functions/strtotime\n' +
24+
' // + original by: Caio Ariede (http://caioariede.com)\n' +
25+
' // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\n' +
26+
' // + input by: David\n' +
27+
' // + improved by: Caio Ariede (http://caioariede.com)\n' +
28+
' // + improved by: Brett Zamir (http://brett-zamir.me)\n' +
29+
' // + bugfixed by: Wagner B. Soares\n' +
30+
' // + bugfixed by: Artur Tchernychev\n' +
31+
' // + improved by: A. Matías Quezada (http://amatiasq.com)\n' +
32+
' // % note 1: Examples all have a fixed timestamp to prevent tests to fail because of variable time(zones)\n' +
33+
' // * example 1: strtotime(\'+1 day\', 1129633200);\n' +
34+
' // * returns 1: 1129719600\n' +
35+
' // * example 2: strtotime(\'+1 week 2 days 4 hours 2 seconds\', 1129633200);\n' +
36+
' // * returns 2: 1130425202\n' +
37+
' // * example 3: strtotime(\'last month\', 1129633200);\n' +
38+
' // * returns 3: 1127041200\n' +
39+
' // * example 4: strtotime(\'2009-05-04 08:30:00\');\n' +
40+
' // * returns 4: 1241418600\n' +
41+
' if (!text)\n' +
42+
' return null;\n' +
43+
'\n' +
44+
' // Unecessary spaces\n' +
45+
' text = text.trim()\n' +
46+
' .replace(/\s{2,}/g, \' \')\n' +
47+
' .replace(/[\t\r\n]/g, \'\')\n' +
48+
' .toLowerCase();\n' +
49+
'\n' +
50+
' var parsed;\n' +
51+
'\n' +
52+
' if (text === \'now\')\n' +
53+
' return now === null || isNaN(now) ? new Date().getTime() / 1000 | 0 : now | 0;\n' +
54+
' else if (!isNaN(parse = Date.parse(text)))\n' +
55+
' return parse / 1000 | 0;\n' +
56+
' if (text === \'now\')\n' +
57+
' return new Date().getTime() / 1000; // Return seconds, not milli-seconds\n' +
58+
' else if (!isNaN(parsed = Date.parse(text)))\n' +
59+
' return parsed / 1000;\n' +
60+
'\n' +
61+
' var match = text.match(/^(\d{2,4})-(\d{2})-(\d{2})(?:\s(\d{1,2}):(\d{2})(?::\d{2})?)?(?:\.(\d+)?)?$/);\n' +
62+
' if (match) {\n' +
63+
' var year = match[1] >= 0 && match[1] <= 69 ? +match[1] + 2000 : match[1];\n' +
64+
' return new Date(year, parseInt(match[2], 10) - 1, match[3],\n' +
65+
' match[4] || 0, match[5] || 0, match[6] || 0, match[7] || 0) / 1000;\n' +
66+
' }\n' +
67+
'\n' +
68+
' var date = now ? new Date(now * 1000) : new Date();\n' +
69+
' var days = {\n' +
70+
' \'sun\': 0,\n' +
71+
' \'mon\': 1,\n' +
72+
' \'tue\': 2,\n' +
73+
' \'wed\': 3,\n' +
74+
' \'thu\': 4,\n' +
75+
' \'fri\': 5,\n' +
76+
' \'sat\': 6\n' +
77+
' };\n' +
78+
' var ranges = {\n' +
79+
' \'yea\': \'FullYear\',\n' +
80+
' \'mon\': \'Month\',\n' +
81+
' \'day\': \'Date\',\n' +
82+
' \'hou\': \'Hours\',\n' +
83+
' \'min\': \'Minutes\',\n' +
84+
' \'sec\': \'Seconds\'\n' +
85+
' };\n' +
86+
'\n' +
87+
' function lastNext(type, range, modifier) {\n' +
88+
' var day = days[range];\n' +
89+
'\n' +
90+
' if (typeof(day) !== \'undefined\') {\n' +
91+
' var diff = day - date.getDay();\n' +
92+
'\n' +
93+
' if (diff === 0)\n' +
94+
' diff = 7 * modifier;\n' +
95+
' else if (diff > 0 && type === \'last\')\n' +
96+
' diff -= 7;\n' +
97+
' else if (diff < 0 && type === \'next\')\n' +
98+
' diff += 7;\n' +
99+
'\n' +
100+
' date.setDate(date.getDate() + diff);\n' +
101+
' }\n' +
102+
' }\n' +
103+
' function process(val) {\n' +
104+
' var split = val.split(\' \');\n' +
105+
' var type = split[0];\n' +
106+
' var range = split[1].substring(0, 3);\n' +
107+
' var typeIsNumber = /\d+/.test(type);\n' +
108+
'\n' +
109+
' var ago = split[2] === \'ago\';\n' +
110+
' var num = (type === \'last\' ? -1 : 1) * (ago ? -1 : 1);\n' +
111+
'\n' +
112+
' if (typeIsNumber)\n' +
113+
' num *= parseInt(type, 10);\n' +
114+
'\n' +
115+
' if (ranges.hasOwnProperty(range))\n' +
116+
' return date[\'set\' + ranges[range]](date[\'get\' + ranges[range]]() + num);\n' +
117+
' else if (range === \'wee\')\n' +
118+
' return date.setDate(date.getDate() + (num * 7));\n' +
119+
'\n' +
120+
' if (type === \'next\' || type === \'last\')\n' +
121+
' lastNext(type, range, num);\n' +
122+
' else if (!typeIsNumber)\n' +
123+
' return false;\n' +
124+
'\n' +
125+
' return true;\n' +
126+
' }\n' +
127+
'\n' +
128+
' var regex = \'([+-]?\\d+\\s\' +\n' +
129+
' \'(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?\' +\n' +
130+
' \'|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday\' +\n' +
131+
' \'|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday)|(last|next)\\s\' +\n' +
132+
' \'(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?\' +\n' +
133+
' \'|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday\' +\n' +
134+
' \'|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday))(\\sago)?\';\n' +
135+
'\n' +
136+
' match = text.match(new RegExp(regex, \'gi\'));\n' +
137+
' if (!match)\n' +
138+
' return false;\n' +
139+
'\n' +
140+
' for (var i = 0, len = match.length; i < len; i++)\n' +
141+
' if (!process(match[i]))\n' +
142+
' return false;\n' +
143+
'\n' +
144+
' // ECMAScript 5 only\n' +
145+
' //if (!match.every(process))\n' +
146+
' // return false;\n' +
147+
'\n' +
148+
' return (date.getTime() / 1000);\n' +
149+
'}\n' +
150+
'\n';
151+
</script>
152+
153+
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
154+
<script src="phpjs.js"></script>
155+
<script type="text/javascript">
156+
Phpjs.parse('strtotime', code, function (err, result) {
157+
if (err) {
158+
$('#content').append('<pre class="alert-warning alert">' + JSON.stringify(err, undefined, 2) + '</pre>');
159+
}
160+
$('#content').append('<pre>' + JSON.stringify(result, undefined, 2) + '</pre>');
161+
162+
console.log(result);
163+
});
164+
</script>
165+
166+
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
167+
<script type="text/javascript">
168+
$('button[rel]').tooltip();
169+
</script>
170+
</html>
File renamed without changes.
File renamed without changes.

_tests/phpjs.js

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
if (typeof require !== 'undefined') {
2+
module.exports = Phpjs;
3+
}
4+
function Phpjs () {
5+
}
6+
7+
Phpjs._commentBlocks = function(code) {
8+
var cnt = 0;
9+
var comment = [];
10+
var commentBlocks = [];
11+
var i = 0;
12+
var lines = [];
13+
var raise = false;
14+
for (i in (lines = code.replace('\r', '').split('\n'))) {
15+
// Detect if line is a comment, and return the actual comment
16+
if ((comment = lines[i].match(/^\s*(\/\/|\/\*|\*)\s*(.*)$/))) {
17+
if (raise === true) {
18+
cnt = commentBlocks.length;
19+
raise = false;
20+
}
21+
if (!commentBlocks[cnt]) {
22+
commentBlocks[cnt] = {clean: [], raw: [], };
23+
}
24+
25+
commentBlocks[cnt].clean.push(comment[2].trim());
26+
commentBlocks[cnt].raw.push(lines[i]);
27+
} else {
28+
raise = true;
29+
}
30+
}
31+
32+
return commentBlocks;
33+
}
34+
35+
Phpjs._headKeys = function(headLines) {
36+
var i;
37+
var keys = {};
38+
var match = [];
39+
var dmatch = [];
40+
var key = '';
41+
var val = '';
42+
var num = 0;
43+
for (i in headLines) {
44+
if (!(match = headLines[i].match(/^[\s\W]*(.*?)\s*:\s*(.*)\s*$/))) {
45+
continue;
46+
}
47+
key = match[1];
48+
val = match[2];
49+
50+
if ((dmatch = key.match(/^(\w+)\s+(\d+)$/))) {
51+
// Things like examples and notes can be grouped
52+
key = dmatch[1];
53+
num = dmatch[2]-1;
54+
55+
if (!keys[key]) {
56+
keys[key] = [];
57+
}
58+
if (!keys[key][num]) {
59+
keys[key][num] = [];
60+
}
61+
keys[key][num].push(val);
62+
} else {
63+
if (!keys[key]) {
64+
keys[key] = [];
65+
}
66+
keys[key].push(val);
67+
}
68+
}
69+
70+
return keys;
71+
}
72+
73+
Phpjs.parse = function(name, code, cb) {
74+
var commentBlocks = this._commentBlocks(code);
75+
var head = commentBlocks[0].raw.join('\n');
76+
var body = code.replace(head, '');
77+
78+
var headKeys = this._headKeys(commentBlocks[0].clean);
79+
80+
cb(null, {
81+
headKeys: headKeys,
82+
body: body,
83+
head: head,
84+
name: name,
85+
code: code,
86+
commentBlocks: commentBlocks,
87+
});
88+
};
89+
90+
Phpjs.test = function(params, cb) {
91+
var i = 0;
92+
var j = 0;
93+
94+
// @todo(kvz)L if a function depends, we need to recursively
95+
// add those.. needs to be done with callbacks cause
96+
// getting code in browser / cli is very different..
97+
eval(params['code']);
98+
for (i in params['headKeys']['example']) {
99+
100+
var test = {
101+
example: params['headKeys']['example'][i].join('\n'),
102+
number: i,
103+
};
104+
105+
// Needs an eval so types are cast properly, also, expected may
106+
// contain code
107+
eval('test.expected = ' + params['headKeys']['returns'][i].join('\n') + '');
108+
109+
// Let's do something evil. Execute line by line (see date.js why)
110+
for (j in params['headKeys']['example'][i]) {
111+
eval('test.result = ' + params['headKeys']['example'][i][j] + '');
112+
}
113+
114+
115+
if (test.expected !== test.result) {
116+
var msg = 'Expected: ' + JSON.stringify(test.expected, undefined, 2) +
117+
' but returned: ' + JSON.stringify(test.result, undefined, 2);
118+
cb(msg, test, params);
119+
} else {
120+
cb(null, test, params)
121+
}
122+
}
123+
};
124+

0 commit comments

Comments
 (0)