2010年2月6日土曜日

JSSpecのなか。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
コアっぽいコードを発見。そのなかでも特に注目すべきは次の点だろう。
  • setTimeout 0している。
  • targetの中で各test caseを実行しているのだろう。
    result = self.target();
       self.onSuccess(self, result);
    
JSSpec.Executor.prototype.run = function() {
  var self = this;
  var target = this.target;
  var onSuccess = this.onSuccess;
  var onException = this.onException;

  window.setTimeout(
    function() {
      var result;
      if(JSSpec.Browser.Trident) {
        window._curExecutor = self;

        result = self.target();
        self.onSuccess(self, result);
      } else {
        try {
          result = self.target();
          self.onSuccess(self, result);
        } catch(ex) {
          if(JSSpec.Browser.Webkit) ex = {message:ex.message, fileName:ex.sourceURL, lineNumber:ex.line};

          if(JSSpec._secondPass)  {
            ex = self.mergeExceptions(JSSpec._assertionFailure, ex);
            delete JSSpec._secondPass;
            delete JSSpec._assertionFailure;

            ex.type = "failure";
            self.onException(self, ex);
          } else if(JSSpec._assertionFailure) {
            JSSpec._secondPass = true;
            self.run();
          } else {
            self.onException(self, ex);
          }
        }
      }
    },
    0
  );
};
もっともhighレベルで呼ばれるrunはこれ。Runnerがspecからcaseを読み込んでexecuterとして追加し、その後実行している。
JSSpec.Runner.prototype.run = function() {
        JSSpec.log.onRunnerStart();
        var executor = new JSSpec.CompositeExecutor(function() {JSSpec.log.onRunnerEnd()},null,true);
        for(var i = 0; i < this.specs.length; i++) {
                executor.addExecutor(this.specs[i].getExecutor());
        }
        executor.run();
};
addExecuterの中身。Executerインスタンスが作るツリーをトラバースしながらcaseを実行していく。 Composite Patternを使っているのでCompositeExecuter。Unittestの実装では普通な実装。 呼び出す順序はここで決まってしまう。
JSSpec.CompositeExecutor.prototype.addExecutor = function(executor) {
        var last = this.queue.length == 0 ? null : this.queue[this.queue.length - 1];
        if(last) {
                last.next = executor;
        }
        
        executor.parent = this;
        executor.onSuccessBackup = executor.onSuccess;
        executor.onSuccess = function(result) {
                this.onSuccessBackup(result);
                if(this.next) {
                        this.next.run();
                } else {
                        this.parent.onSuccess();
                }
        };
        executor.onExceptionBackup = executor.onException;
        executor.onException = function(executor, ex) {
                this.onExceptionBackup(executor, ex);

                if(this.parent.continueOnException) {
                        if(this.next) {
                                this.next.run();
                        } else {
                                this.parent.onSuccess();
                        }
                } else {
                        this.parent.onException(executor, ex);
                }
        };

        this.queue.push(executor);
};

大筋で理解はしたつもりだが、Deferredと混ぜるのはどうすれば良いのやら。

0 件のコメント: