From c6a13bd6d2435ec5940ab3757ff70babf9ed15da Mon Sep 17 00:00:00 2001 From: Brian Cavalier Date: Thu, 3 Jan 2013 15:08:41 -0500 Subject: [PATCH] See #10. Initial method/func tracer aspect. API needs work, but guts are there --- aspect/trace.js | 76 +++++++++++++++++++++++++++++++++++++++ test/aspect/trace-test.js | 68 +++++++++++++++++++++++++++++++++++ test/buster.js | 2 +- 3 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 aspect/trace.js create mode 100644 test/aspect/trace-test.js diff --git a/aspect/trace.js b/aspect/trace.js new file mode 100644 index 0000000..8ed972c --- /dev/null +++ b/aspect/trace.js @@ -0,0 +1,76 @@ +/** + * trace + * @author: brian@hovercraftstudios.com + */ +(function(define) { +define(function(require) { + + var meld, joinpoint, padding, simpleReporter; + + meld = require('../meld'); + joinpoint = meld.joinpoint; + + // Padding characters for indenting traces + padding = '........'; + + // 2^12 padding = 4096. If you need more stack than that, + // you probably have bigger problems! + for(var i=0; i<9; i++) { + padding += padding; + } + + simpleReporter = { + enter: function(info, depth) { + console.log(indent(depth) + info.method, 'CALL', info.args); + }, + success: function(info, depth) { + console.log(indent(depth) + info.method, 'RETURN', info.result); + }, + fail: function(info, depth) { + console.warn(indent(depth) + info.method, 'THROW', info.exception); + } + }; + + return { + createAspect: createTraceAspect, + publicMethods: /^[^_]/, + allMethods: /.+/ + }; + + function createTraceAspect(reporter) { + var depth; + + depth = 0; + + if(!reporter) { + reporter = simpleReporter; + } + + return { + before: function() { + // Always increase depth + depth += 1; + reporter.enter && reporter.enter(joinpoint(), depth); + }, + + afterReturning: function() { + reporter.success && reporter.success(joinpoint(), depth); + }, + + afterThrowing: function() { + reporter.fail && reporter.fail(joinpoint(), depth); + }, + + after: function() { + // Always decrease depth + depth -= 1; + } + }; + } + + function indent(depth) { + return padding.slice(0, depth-1); + } + +}); +}(typeof define === 'function' ? define : function(factory) { module.exports = factory(require); })); diff --git a/test/aspect/trace-test.js b/test/aspect/trace-test.js new file mode 100644 index 0000000..6a0bc17 --- /dev/null +++ b/test/aspect/trace-test.js @@ -0,0 +1,68 @@ +(function(buster, meld, trace) { +'use strict'; + +var assert, refute, sentinel; + +assert = buster.assert; +refute = buster.refute; + +sentinel = {}; + +buster.testCase('aspect/trace', { + + 'should call enter upon entering advised method': function() { + var spy, advised, reporter; + + spy = this.spy(); + advised = { method: spy }; + reporter = { enter: this.spy() }; + + meld.add(advised, 'method', trace.createAspect(reporter)); + + advised.method(sentinel); + + assert.calledOnceWith(spy, sentinel); + assert.calledOnce(reporter.enter); + }, + + 'should call success upon returning from advised method': function() { + var advised, reporter; + + advised = { + method: function() { refute.called(reporter.success); } + }; + reporter = { success: this.spy() }; + + meld.add(advised, 'method', trace.createAspect(reporter)); + + advised.method(); + + assert.calledOnce(reporter.success); + }, + + 'should call fail upon throwing from advised method': function() { + var advised, reporter; + + advised = { + method: function() { + refute.called(reporter.fail); + throw sentinel; + } + }; + reporter = { fail: this.spy() }; + + meld.add(advised, 'method', trace.createAspect(reporter)); + + assert.exception(function() { + advised.method(); + assert.calledOnce(reporter.fail); + }); + } + +}); + +})( + require('buster'), + require('../../meld'), + require('../../aspect/trace') +); \ No newline at end of file diff --git a/test/buster.js b/test/buster.js index 0f2927d..32dcb98 100644 --- a/test/buster.js +++ b/test/buster.js @@ -1,4 +1,4 @@ exports['meld:node'] = { environment: 'node', - tests: ['*.js'] + tests: ['**/*.js'] };