Skip to content

Commit

Permalink
Basic testing based on headers is working. See README.md locutusjs#80
Browse files Browse the repository at this point in the history
  • Loading branch information
kvz committed May 6, 2013
1 parent e1debab commit 2b5b847
Show file tree
Hide file tree
Showing 11 changed files with 2,388 additions and 111 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ nbproject
gitup.dat
.project
.gitup.dat
_tools/nest/node_modules/
_tests/node_modules/
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ setup:
rake setup_github_pages\[[email protected]:kvz/phpjs.git\] && \
cd .. ; \

test:
find functions -type f |grep -v '/_' |xargs node _tests/cli.js -f

site:
git pull && \
cd _octopress && \
Expand Down
26 changes: 26 additions & 0 deletions _tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

# Cli

```bash
node cli.js -f ../functions/datetime/strtotime.js
node cli.js -f ../functions/datetime/date.js
```

# Web

```html
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="phpjs.js"></script>
<script type="text/javascript">
// Get `code`
Phpjs.parse(code, function (err, result) {
if (err) {
$('#content').append('<pre class="alert-warning alert">' + JSON.stringify(err, undefined, 2) + '</pre>');
}
$('#content').append('<pre>' + JSON.stringify(result, undefined, 2) + '</pre>');
console.log(result);
});
</script>
```

44 changes: 44 additions & 0 deletions _tests/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
var cli = require('cli').enable('status', 'help', 'version', 'glob', 'timeout');
var FS = require('fs');
var phpjs = require('./phpjs');

cli.parse({
function_file: ['f', 'Function to test', 'path'],
});

cli.main(function(args, options) {
if (!options.function_file) {
this.fatal('Please specify a file to test (-h for help)');
}

// cli.spinner('Working..');
// cli.spinner('Working.. done!', true); //End the spinner

FS.readFile(options.function_file, 'utf-8', function (err, code) {
if (err) {
return cli.fatal(err);
}

phpjs.parse(options.function_file, code, function (err, params) {
if (err) {
return cli.fatal(err);
}
// console.log(params['headKeys']);

phpjs.test(params, function(err, test, params) {
var testline = params['name'] +
'#' + test['number'] +
'\t' + test['example'] +
'\t' + test['expected'] +
'\t' + test['result'] +
'\t';

if (err) {
cli.error(testline + ' test failed :(');
}
cli.ok(testline + ' test passed :)');
});
});
});

});
170 changes: 170 additions & 0 deletions _tests/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>php.js demo</title>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet" />
</head>
<body>
<div class="container">
<h1>php.js demo</h1>
<div id="content"></div>
</div>
</body>

<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="phpjs.js"></script>

<script type="text/javascript">
var code = 'function strtotime (text, now) {\n' +
' // Convert string representation of date and time to a timestamp\n' +
' //\n' +
' // version: 1109.2015\n' +
' // discuss at: http://phpjs.org/functions/strtotime\n' +
' // + original by: Caio Ariede (http://caioariede.com)\n' +
' // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\n' +
' // + input by: David\n' +
' // + improved by: Caio Ariede (http://caioariede.com)\n' +
' // + improved by: Brett Zamir (http://brett-zamir.me)\n' +
' // + bugfixed by: Wagner B. Soares\n' +
' // + bugfixed by: Artur Tchernychev\n' +
' // + improved by: A. Matías Quezada (http://amatiasq.com)\n' +
' // % note 1: Examples all have a fixed timestamp to prevent tests to fail because of variable time(zones)\n' +
' // * example 1: strtotime(\'+1 day\', 1129633200);\n' +
' // * returns 1: 1129719600\n' +
' // * example 2: strtotime(\'+1 week 2 days 4 hours 2 seconds\', 1129633200);\n' +
' // * returns 2: 1130425202\n' +
' // * example 3: strtotime(\'last month\', 1129633200);\n' +
' // * returns 3: 1127041200\n' +
' // * example 4: strtotime(\'2009-05-04 08:30:00\');\n' +
' // * returns 4: 1241418600\n' +
' if (!text)\n' +
' return null;\n' +
'\n' +
' // Unecessary spaces\n' +
' text = text.trim()\n' +
' .replace(/\s{2,}/g, \' \')\n' +
' .replace(/[\t\r\n]/g, \'\')\n' +
' .toLowerCase();\n' +
'\n' +
' var parsed;\n' +
'\n' +
' if (text === \'now\')\n' +
' return now === null || isNaN(now) ? new Date().getTime() / 1000 | 0 : now | 0;\n' +
' else if (!isNaN(parse = Date.parse(text)))\n' +
' return parse / 1000 | 0;\n' +
' if (text === \'now\')\n' +
' return new Date().getTime() / 1000; // Return seconds, not milli-seconds\n' +
' else if (!isNaN(parsed = Date.parse(text)))\n' +
' return parsed / 1000;\n' +
'\n' +
' var match = text.match(/^(\d{2,4})-(\d{2})-(\d{2})(?:\s(\d{1,2}):(\d{2})(?::\d{2})?)?(?:\.(\d+)?)?$/);\n' +
' if (match) {\n' +
' var year = match[1] >= 0 && match[1] <= 69 ? +match[1] + 2000 : match[1];\n' +
' return new Date(year, parseInt(match[2], 10) - 1, match[3],\n' +
' match[4] || 0, match[5] || 0, match[6] || 0, match[7] || 0) / 1000;\n' +
' }\n' +
'\n' +
' var date = now ? new Date(now * 1000) : new Date();\n' +
' var days = {\n' +
' \'sun\': 0,\n' +
' \'mon\': 1,\n' +
' \'tue\': 2,\n' +
' \'wed\': 3,\n' +
' \'thu\': 4,\n' +
' \'fri\': 5,\n' +
' \'sat\': 6\n' +
' };\n' +
' var ranges = {\n' +
' \'yea\': \'FullYear\',\n' +
' \'mon\': \'Month\',\n' +
' \'day\': \'Date\',\n' +
' \'hou\': \'Hours\',\n' +
' \'min\': \'Minutes\',\n' +
' \'sec\': \'Seconds\'\n' +
' };\n' +
'\n' +
' function lastNext(type, range, modifier) {\n' +
' var day = days[range];\n' +
'\n' +
' if (typeof(day) !== \'undefined\') {\n' +
' var diff = day - date.getDay();\n' +
'\n' +
' if (diff === 0)\n' +
' diff = 7 * modifier;\n' +
' else if (diff > 0 && type === \'last\')\n' +
' diff -= 7;\n' +
' else if (diff < 0 && type === \'next\')\n' +
' diff += 7;\n' +
'\n' +
' date.setDate(date.getDate() + diff);\n' +
' }\n' +
' }\n' +
' function process(val) {\n' +
' var split = val.split(\' \');\n' +
' var type = split[0];\n' +
' var range = split[1].substring(0, 3);\n' +
' var typeIsNumber = /\d+/.test(type);\n' +
'\n' +
' var ago = split[2] === \'ago\';\n' +
' var num = (type === \'last\' ? -1 : 1) * (ago ? -1 : 1);\n' +
'\n' +
' if (typeIsNumber)\n' +
' num *= parseInt(type, 10);\n' +
'\n' +
' if (ranges.hasOwnProperty(range))\n' +
' return date[\'set\' + ranges[range]](date[\'get\' + ranges[range]]() + num);\n' +
' else if (range === \'wee\')\n' +
' return date.setDate(date.getDate() + (num * 7));\n' +
'\n' +
' if (type === \'next\' || type === \'last\')\n' +
' lastNext(type, range, num);\n' +
' else if (!typeIsNumber)\n' +
' return false;\n' +
'\n' +
' return true;\n' +
' }\n' +
'\n' +
' var regex = \'([+-]?\\d+\\s\' +\n' +
' \'(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?\' +\n' +
' \'|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday\' +\n' +
' \'|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday)|(last|next)\\s\' +\n' +
' \'(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?\' +\n' +
' \'|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday\' +\n' +
' \'|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday))(\\sago)?\';\n' +
'\n' +
' match = text.match(new RegExp(regex, \'gi\'));\n' +
' if (!match)\n' +
' return false;\n' +
'\n' +
' for (var i = 0, len = match.length; i < len; i++)\n' +
' if (!process(match[i]))\n' +
' return false;\n' +
'\n' +
' // ECMAScript 5 only\n' +
' //if (!match.every(process))\n' +
' // return false;\n' +
'\n' +
' return (date.getTime() / 1000);\n' +
'}\n' +
'\n';
</script>

<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="phpjs.js"></script>
<script type="text/javascript">
Phpjs.parse('strtotime', code, function (err, result) {
if (err) {
$('#content').append('<pre class="alert-warning alert">' + JSON.stringify(err, undefined, 2) + '</pre>');
}
$('#content').append('<pre>' + JSON.stringify(result, undefined, 2) + '</pre>');

console.log(result);
});
</script>

<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
<script type="text/javascript">
$('button[rel]').tooltip();
</script>
</html>
File renamed without changes.
File renamed without changes.
124 changes: 124 additions & 0 deletions _tests/phpjs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
if (typeof require !== 'undefined') {
module.exports = Phpjs;
}
function Phpjs () {
}

Phpjs._commentBlocks = function(code) {
var cnt = 0;
var comment = [];
var commentBlocks = [];
var i = 0;
var lines = [];
var raise = false;
for (i in (lines = code.replace('\r', '').split('\n'))) {
// Detect if line is a comment, and return the actual comment
if ((comment = lines[i].match(/^\s*(\/\/|\/\*|\*)\s*(.*)$/))) {
if (raise === true) {
cnt = commentBlocks.length;
raise = false;
}
if (!commentBlocks[cnt]) {
commentBlocks[cnt] = {clean: [], raw: [], };
}

commentBlocks[cnt].clean.push(comment[2].trim());
commentBlocks[cnt].raw.push(lines[i]);
} else {
raise = true;
}
}

return commentBlocks;
}

Phpjs._headKeys = function(headLines) {
var i;
var keys = {};
var match = [];
var dmatch = [];
var key = '';
var val = '';
var num = 0;
for (i in headLines) {
if (!(match = headLines[i].match(/^[\s\W]*(.*?)\s*:\s*(.*)\s*$/))) {
continue;
}
key = match[1];
val = match[2];

if ((dmatch = key.match(/^(\w+)\s+(\d+)$/))) {
// Things like examples and notes can be grouped
key = dmatch[1];
num = dmatch[2]-1;

if (!keys[key]) {
keys[key] = [];
}
if (!keys[key][num]) {
keys[key][num] = [];
}
keys[key][num].push(val);
} else {
if (!keys[key]) {
keys[key] = [];
}
keys[key].push(val);
}
}

return keys;
}

Phpjs.parse = function(name, code, cb) {
var commentBlocks = this._commentBlocks(code);
var head = commentBlocks[0].raw.join('\n');
var body = code.replace(head, '');

var headKeys = this._headKeys(commentBlocks[0].clean);

cb(null, {
headKeys: headKeys,
body: body,
head: head,
name: name,
code: code,
commentBlocks: commentBlocks,
});
};

Phpjs.test = function(params, cb) {
var i = 0;
var j = 0;

// @todo(kvz)L if a function depends, we need to recursively
// add those.. needs to be done with callbacks cause
// getting code in browser / cli is very different..
eval(params['code']);
for (i in params['headKeys']['example']) {

var test = {
example: params['headKeys']['example'][i].join('\n'),
number: i,
};

// Needs an eval so types are cast properly, also, expected may
// contain code
eval('test.expected = ' + params['headKeys']['returns'][i].join('\n') + '');

// Let's do something evil. Execute line by line (see date.js why)
for (j in params['headKeys']['example'][i]) {
eval('test.result = ' + params['headKeys']['example'][i][j] + '');
}


if (test.expected !== test.result) {
var msg = 'Expected: ' + JSON.stringify(test.expected, undefined, 2) +
' but returned: ' + JSON.stringify(test.result, undefined, 2);
cb(msg, test, params);
} else {
cb(null, test, params)
}
}
};

Loading

0 comments on commit 2b5b847

Please sign in to comment.