text: /**
   * Copyright (c) 2013, Yanis Wang <yanis.wang@gmail.com>
   * MIT Licensed
   */
  
  var expect  = require("expect.js");
  
  var HTMLParser  = require("../index").HTMLParser;
  
  expect.Assertion.prototype.event = function(type, attr){
      var self = this,
          obj = self.obj;
      if(attr !== undefined){
          attr.type = type;
      }
      else{
          attr = {'type': type};
      }
      self.assert(
          eqlEvent(obj, attr),
          function(){ return 'expected "'+JSON.stringify(obj)+'" to event "'+JSON.stringify(attr)+'"'; },
          function(){ return 'expected "'+JSON.stringify(obj)+'" not to event "'+JSON.stringify(attr)+'"'; });
  };
  
  function eqlEvent(event, attr){
      for(var name in attr){
          if(event[name] !== attr[name]){
              return false;
          }
      }
      return true;
  }
  
  function getAllEvents(parser, arrEvents, callback){
        parser.addListener('all', function(e){
          arrEvents.push(e);
          if(e.type === 'end'){
              callback();
          }
        });
  }
  
  describe('HTMLParser: Base parse', function(){
  
      it('should parse html code1', function(done){
        var parser = new HTMLParser();
        var arrEvents = [];
        var targetEvents = [{"pos":0,"line":1,"col":1,"type":"start"},{"content":"DOCTYPE HTML","long":false,"raw":"<!DOCTYPE HTML>","pos":0,"line":1,"col":1,"type":"comment"},{"tagName":"html","attrs":[],"close":"","raw":"<html>","pos":15,"line":1,"col":16,"type":"tagstart"},{"tagName":"head","attrs":[],"close":"","raw":"<head>","pos":21,"line":1,"col":22,"type":"tagstart"},{"tagName":"meta","attrs":[{"name":"charset","value":"UTF-8","quote":"\"","index":0,"raw":" charset=\"UTF-8\""}],"close":"","raw":"<meta charset=\"UTF-8\">","pos":27,"line":1,"col":28,"type":"tagstart"},{"tagName":"title","attrs":[],"close":"","raw":"<title>","pos":49,"line":1,"col":50,"type":"tagstart"},{"raw":"testtitle","pos":56,"line":1,"col":57,"type":"text"},{"tagName":"title","raw":"</title>","pos":65,"line":1,"col":66,"type":"tagend"},{"tagName":"head","raw":"</head>","pos":73,"line":1,"col":74,"type":"tagend"},{"tagName":"body","attrs":[],"close":"","raw":"<body>","pos":80,"line":1,"col":81,"type":"tagstart"},{"tagName":"p","attrs":[],"close":"","raw":"<p>","pos":86,"line":1,"col":87,"type":"tagstart"},{"tagName":"a","attrs":[{"name":"href","value":"testhref","quote":"\"","index":0,"raw":" href=\"testhref\""},{"name":"title","value":"atitle","quote":"\"","index":16,"raw":" title=\"atitle\""}],"close":"","raw":"<a href=\"testhref\" title=\"atitle\">","pos":89,"line":1,"col":90,"type":"tagstart"},{"raw":"aaa","pos":123,"line":1,"col":124,"type":"text"},{"tagName":"span","attrs":[],"close":"","raw":"<span>","pos":126,"line":1,"col":127,"type":"tagstart"},{"raw":"bbb","pos":132,"line":1,"col":133,"type":"text"},{"tagName":"span","raw":"</span>","pos":135,"line":1,"col":136,"type":"tagend"},{"raw":"ccc","pos":142,"line":1,"col":143,"type":"text"},{"tagName":"a","raw":"</a>","pos":145,"line":1,"col":146,"type":"tagend"},{"tagName":"p","raw":"</p>","pos":149,"line":1,"col":150,"type":"tagend"},{"tagName":"body","raw":"</body>","pos":153,"line":1,"col":154,"type":"tagend"},{"tagName":"html","raw":"</html>","pos":160,"line":1,"col":161,"type":"tagend"},{"pos":167,"line":1,"col":168,"type":"end"}];
        getAllEvents(parser, arrEvents, function(){
          expect(arrEvents).to.eql(targetEvents);
          done();
        });
        parser.parse('<!DOCTYPE HTML><html><head><meta charset="UTF-8"><title>testtitle</title></head><body><p><a href="testhref" title="atitle">aaa<span>bbb</span>ccc</a></p></body></html>');
      });
  
  });
  
  describe('HTMLParser: Object parse', function(){
  
      it('should parse doctype: HTML Strict DTD', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('comment',
              {
                  content: 'DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"',
                  long: false
              });
              done();
          });
          parser.parse('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">');
      });
  
      it('should parse doctype: HTML Transitional DTD', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('comment',
              {
                  content: 'DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"',
                  long: false
              });
              done();
          });
          parser.parse('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">');
      });
  
  
      it('should parse doctype: HTML Frameset DTD', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('comment',
              {
                  content: 'DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd"',
                  long: false
              });
              done();
          });
          parser.parse('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">');
      });
  
      it('should parse doctype: XHTML 1.0 Strict', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('comment',
              {
                  content: 'DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"',
                  long: false
              });
              done();
          });
          parser.parse('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">');
      });
  
      it('should parse doctype: XHTML 1.0 Transitional', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('comment',
              {
                  content: 'DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"',
                  long: false
              });
              done();
          });
          parser.parse('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
      });
  
      it('should parse doctype: XHTML 1.0 Frameset', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('comment',
              {
                  content: 'DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"',
                  long: false
              });
              done();
          });
          parser.parse('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">');
      });
  
  
      it('should parse doctype: XHTML 1.1', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('comment',
              {
                  content: 'DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"',
                  long: false
              });
              done();
          });
          parser.parse('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">');
      });
  
      it('should parse doctype: html5', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('comment',
              {
                  content: 'DOCTYPE HTML',
                  long: false
              });
              done();
          });
          parser.parse('<!DOCTYPE HTML>');
      });
  
      it('should parse start tag: <p>', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('tagstart',
              {
                  tagName: 'p'
              });
              done();
          });
          parser.parse('<p>');
      });
  
      it('should not parse start tag: <div class"foo">', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('text',
              {
                  raw: '<div class"foo">'
              });
              done();
          });
          parser.parse('<div class"foo">');
      });
  
      it('should not parse start tag: <div class="foo>', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('text',
              {
                  raw: '<div class="foo>'
              });
              done();
          });
          parser.parse('<div class="foo>');
      });
  
      it('should not parse start tag: <div class=foo">', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('text',
              {
                  raw: '<div class=foo">'
              });
              done();
          });
          parser.parse('<div class=foo">');
      });
  
      it('should not parse start tag: <div class="foo"">', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('text',
              {
                  raw: '<div class="foo"">'
              });
              done();
          });
          parser.parse('<div class="foo"">');
      });
  
      it('should not parse start tag: <div class="foo""><span">', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('text',
              {
                  raw: '<div class="foo""><span">'
              });
              done();
          });
          parser.parse('<div class="foo""><span">');
      });
  
      it('should not parse start tag: <div class="foo""><a><span">', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('text',
              {
                  raw: '<div class="foo"">'
              });
              done();
          });
          parser.parse('<div class="foo""><a><span">');
      });
  
      it('should parse tag attrs', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('tagstart',
              {
                  tagName: 'img'
              });
              var attrWidth = arrEvents[1].attrs[0];
              expect(attrWidth.name).to.be('width');
              expect(attrWidth.value).to.be('200');
              expect(attrWidth.quote).to.be('"');
              var attrHeight = arrEvents[1].attrs[1];
              expect(attrHeight.name).to.be('height');
              expect(attrHeight.value).to.be('300');
              expect(attrHeight.quote).to.be("'");
              var attrAlt = arrEvents[1].attrs[2];
              expect(attrAlt.name).to.be('alt');
              expect(attrAlt.value).to.be('abc');
              expect(attrAlt.quote).to.be("");
              done();
          });
          parser.parse('<img width="200" height=\'300\' alt=abc>');
      });
  
      it('should parse end tag', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('tagend',
              {
                  tagName: 'p'
              });
              done();
          });
          parser.parse('</p>');
      });
  
      it('should parse selfclose tag', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('tagstart',
              {
                  tagName: 'br',
                  close: '/'
              });
              done();
          });
          parser.parse('<br />');
      });
  
      it('should parse text', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[2]).to.event('text',
              {
                  raw: 'abc'
              });
              done();
          });
          parser.parse('<span>abc</span>');
      });
  
      it('should parse text in last', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[2]).to.event('text',
              {
                  raw: 'bbb'
              });
              done();
          });
          parser.parse('<p>bbb');
      });
  
      it('should parse comment', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('comment',
              {
                  content: 'comment\r\ntest',
                  long: true
              });
              done();
          });
          parser.parse('<!--comment\r\ntest-->');
      });
  
      it('should parse cdata: script', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              var mapAttrs;
              expect(arrEvents[1]).to.event('tagstart',
              {
                  tagName: 'script'
              });
              mapAttrs = parser.getMapAttrs(arrEvents[1].attrs);
              expect(mapAttrs.type).to.be('text/javascript');
              expect(arrEvents[2]).to.event('cdata',
              {
                  tagName: 'script',
                  raw: 'alert(1);\r\nalert("</html>");'
              });
              mapAttrs = parser.getMapAttrs(arrEvents[2].attrs);
              expect(mapAttrs.type).to.be('text/javascript');
              expect(arrEvents[3]).to.event('tagend',
              {
                  tagName: 'script'
              });
              done();
          });
          parser.parse('<script type="text/javascript">alert(1);\r\nalert("</html>");</script>');
      });
  
  
      it('should parse cdata: style', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('tagstart',
              {
                  tagName: 'style',
                  type: 'text/css'
              });
              expect(arrEvents[2]).to.event('cdata',
              {
                  tagName: 'style',
                  raw: 'body{font-size:12px;\r\nbackground-color:green;}'
              });
              expect(arrEvents[3]).to.event('tagend',
              {
                  tagName: 'style'
              });
              done();
          });
          parser.parse('<style type="text/css">body{font-size:12px;\r\nbackground-color:green;}</style>');
      });
  
  });
  
  describe('HTMLParser: Case parse', function(){
  
      it('should parse special end tag', function(done){
          var parser = new HTMLParser();
          var arrEvents = [];
          getAllEvents(parser, arrEvents, function(){
              expect(arrEvents[1]).to.event('tagend',
              {
                  tagName: 'p'
              });
              done();
          });
          parser.parse('</p >');
      });
  
  });