'});
             var dir = CompileDirectiveMetadata.create({
               selector: '[a]',
               exportAs: 'someExport',
               isComponent: false,
               type: SomeDirTypeMeta,
               host: {'(click)': 'doIt()', '(window:scroll)': 'doIt()', 'role': 'button'}
             });
             run(rootComp, [dir])
                 .then((data) => {
                   expect(data).toEqual([
                     [
                       BEGIN_ELEMENT,
                       'div',
                       ['a', '', 'role', 'button'],
                       [null, 'click', 'window', 'scroll'],
                       ['someVar', 0],
                       ['SomeDirType'],
                       true,
                       null
                     ],
                     [END_ELEMENT]
                   ]);
                   async.done();
                 });
           }));
        it('should emulate style encapsulation', inject([AsyncTestCompleter], (async) => {
             var rootComp = createComp({
               type: RootCompTypeMeta,
               template: '
',
               encapsulation: ViewEncapsulation.Emulated
             });
             run(rootComp, [])
                 .then((data) => {
                   expect(data).toEqual([
                     [BEGIN_ELEMENT, 'div', ['_ngcontent-1', ''], [], [], [], false, null],
                     [END_ELEMENT]
                   ]);
                   async.done();
                 });
           }));
        it('should create nested nodes', inject([AsyncTestCompleter], (async) => {
             var rootComp = createComp({type: RootCompTypeMeta, template: '
a
'});
             run(rootComp, [])
                 .then((data) => {
                   expect(data).toEqual([
                     [BEGIN_ELEMENT, 'div', [], [], [], [], false, null],
                     [TEXT, 'a', false, null],
                     [END_ELEMENT]
                   ]);
                   async.done();
                 });
           }));
      });
      describe('components', () => {
        it('should create component commands', inject([AsyncTestCompleter], (async) => {
             var rootComp = createComp(
                 {type: RootCompTypeMeta, template: '
'});
             var comp = createComp({type: ACompTypeMeta, selector: 'a'});
             run(rootComp, [comp])
                 .then((data) => {
                   expect(data).toEqual([
                     [
                       BEGIN_COMPONENT,
                       'a',
                       ['a', 'b'],
                       [null, 'click'],
                       ['someVar', 0],
                       ['ACompType'],
                       false,
                       null,
                       3
                     ],
                     [END_COMPONENT]
                   ]);
                   async.done();
                 });
           }));
        it('should emulate style encapsulation on host elements',
           inject([AsyncTestCompleter], (async) => {
             var rootComp = createComp({
               type: RootCompTypeMeta,
               template: '',
               encapsulation: ViewEncapsulation.Emulated
             });
             var comp = createComp(
                 {type: ACompTypeMeta, selector: 'a', encapsulation: ViewEncapsulation.Emulated});
             run(rootComp, [comp])
                 .then((data) => {
                   expect(data).toEqual([
                     [
                       BEGIN_COMPONENT,
                       'a',
                       ['_nghost-3', '', '_ngcontent-1', ''],
                       [],
                       [],
                       ['ACompType'],
                       false,
                       null,
                       3
                     ],
                     [END_COMPONENT]
                   ]);
                   async.done();
                 });
           }));
        it('should set nativeShadow flag', inject([AsyncTestCompleter], (async) => {
             var rootComp = createComp({type: RootCompTypeMeta, template: '
'});
             var comp = createComp(
                 {type: ACompTypeMeta, selector: 'a', encapsulation: ViewEncapsulation.Native});
             run(rootComp, [comp])
                 .then((data) => {
                   expect(data).toEqual([
                     [BEGIN_COMPONENT, 'a', [], [], [], ['ACompType'], true, null, 3],
                     [END_COMPONENT]
                   ]);
                   async.done();
                 });
           }));
        it('should create nested nodes and set ngContentIndex',
           inject([AsyncTestCompleter], (async) => {
             var rootComp = createComp({type: RootCompTypeMeta, template: '
t'});
             var comp = createComp({type: ACompTypeMeta, selector: 'a', ngContentSelectors: ['*']});
             run(rootComp, [comp])
                 .then((data) => {
                   expect(data).toEqual([
                     [BEGIN_COMPONENT, 'a', [], [], [], ['ACompType'], false, null, 3],
                     [TEXT, 't', false, 0],
                     [END_COMPONENT]
                   ]);
                   async.done();
                 });
           }));
      });
      describe('embedded templates', () => {
        it('should create embedded template commands', inject([AsyncTestCompleter], (async) => {
             var rootComp =
                 createComp({type: RootCompTypeMeta, template: '
'});
             var dir = createDirective(SomeDirTypeMeta, '[a]');
             run(rootComp, [dir], 1)
                 .then((data) => {
                   expect(data).toEqual([
                     [EMBEDDED_TEMPLATE, ['a', 'b'], [], ['SomeDirType'], false, null, 'cd1', []]
                   ]);
                   async.done();
                 });
           }));
        it('should keep variable name and value for 
 elements',
           inject([AsyncTestCompleter], (async) => {
             var rootComp = createComp({
               type: RootCompTypeMeta,
               template: ''
             });
             var dir = createDirective(SomeDirTypeMeta, '[a]');
             run(rootComp, [dir], 1)
                 .then((data) => {
                   expect(data[0][2])
                       .toEqual(['someEmptyVar', '$implicit', 'someVar', 'someValue']);
                   async.done();
                 });
           }));
        it('should keep variable name and value for template attributes',
           inject([AsyncTestCompleter], (async) => {
             var rootComp = createComp({
               type: RootCompTypeMeta,
               template: ''
             });
             var dir = createDirective(SomeDirTypeMeta, '[a]');
             run(rootComp, [dir], 1)
                 .then((data) => {
                   expect(data[0][2])
                       .toEqual(['someVar', 'someValue', 'someEmptyVar', '$implicit']);
                   async.done();
                 });
           }));
        it('should created nested nodes', inject([AsyncTestCompleter], (async) => {
             var rootComp =
                 createComp({type: RootCompTypeMeta, template: 't'});
             run(rootComp, [], 1)
                 .then((data) => {
                   expect(data).toEqual([
                     [
                       EMBEDDED_TEMPLATE,
                       [],
                       [],
                       [],
                       false,
                       null,
                       'cd1',
                       [[TEXT, 't', false, null]]
                     ]
                   ]);
                   async.done();
                 });
           }));
        it('should calculate wether the template is merged based on nested ng-content elements',
           inject([AsyncTestCompleter], (async) => {
             var rootComp = createComp({
               type: RootCompTypeMeta,
               template: ''
             });
             run(rootComp, [], 1)
                 .then((data) => {
                   expect(data).toEqual(
                       [[EMBEDDED_TEMPLATE, [], [], [], true, null, 'cd1', [[NG_CONTENT, null]]]]);
                   async.done();
                 });
           }));
      });
      describe('ngContent', () => {
        it('should create ng-content commands', inject([AsyncTestCompleter], (async) => {
             var rootComp =
                 createComp({type: RootCompTypeMeta, template: ''});
             run(rootComp, [])
                 .then((data) => {
                   expect(data).toEqual([[NG_CONTENT, null]]);
                   async.done();
                 });
           }));
      });
    }
    describe('compileComponentRuntime', () => {
      beforeEach(() => {
        componentTemplateFactory = (directive: CompileDirectiveMetadata) => {
          return new CompiledTemplate(directive.type.id, () => []);
        };
      });
      function run(component: CompileDirectiveMetadata, directives: CompileDirectiveMetadata[],
                   embeddedTemplateCount: number = 0): Promise {
        var changeDetectorFactories = [];
        for (var i = 0; i < embeddedTemplateCount + 1; i++) {
          (function(i) { changeDetectorFactories.push((_) => `cd${i}`); })(i);
        }
        var parsedTemplate =
            parser.parse(component.template.template, directives, component.type.name);
        var commands = commandCompiler.compileComponentRuntime(
            component, parsedTemplate, changeDetectorFactories, componentTemplateFactory);
        return PromiseWrapper.resolve(humanize(commands));
      }
      createTests(run);
    });
    describe('compileComponentCodeGen', () => {
      beforeEach(() => {
        componentTemplateFactory = (directive: CompileDirectiveMetadata) => {
          return `new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledTemplate(${directive.type.id}, ${codeGenValueFn([], '{}')})`;
        };
      });
      function run(component: CompileDirectiveMetadata, directives: CompileDirectiveMetadata[],
                   embeddedTemplateCount: number = 0): Promise {
        var changeDetectorFactoryExpressions = [];
        for (var i = 0; i < embeddedTemplateCount + 1; i++) {
          changeDetectorFactoryExpressions.push(codeGenValueFn(['_'], `'cd${i}'`));
        }
        var parsedTemplate =
            parser.parse(component.template.template, directives, component.type.name);
        var sourceModule = commandCompiler.compileComponentCodeGen(
            component, parsedTemplate, changeDetectorFactoryExpressions, componentTemplateFactory);
        var testableModule = createTestableModule(sourceModule).getSourceWithImports();
        return evalModule(testableModule.source, testableModule.imports, null);
      }
      createTests(run);
    });
  });
}
// Attention: read by eval!
export function humanize(cmds: TemplateCmd[]): any[][] {
  var visitor = new CommandHumanizer();
  visitAllCommands(visitor, cmds);
  return visitor.result;
}
function checkAndStringifyType(type: Type): string {
  expect(isType(type)).toBe(true);
  return `${stringify(type)}Type`;
}
class CommandHumanizer implements CommandVisitor {
  result: any[][] = [];
  visitText(cmd: TextCmd, context: any): any {
    this.result.push([TEXT, cmd.value, cmd.isBound, cmd.ngContentIndex]);
    return null;
  }
  visitNgContent(cmd: NgContentCmd, context: any): any {
    this.result.push([NG_CONTENT, cmd.ngContentIndex]);
    return null;
  }
  visitBeginElement(cmd: BeginElementCmd, context: any): any {
    this.result.push([
      BEGIN_ELEMENT,
      cmd.name,
      cmd.attrNameAndValues,
      cmd.eventTargetAndNames,
      cmd.variableNameAndValues,
      cmd.directives.map(checkAndStringifyType),
      cmd.isBound,
      cmd.ngContentIndex
    ]);
    return null;
  }
  visitEndElement(context: any): any {
    this.result.push([END_ELEMENT]);
    return null;
  }
  visitBeginComponent(cmd: BeginComponentCmd, context: any): any {
    this.result.push([
      BEGIN_COMPONENT,
      cmd.name,
      cmd.attrNameAndValues,
      cmd.eventTargetAndNames,
      cmd.variableNameAndValues,
      cmd.directives.map(checkAndStringifyType),
      cmd.nativeShadow,
      cmd.ngContentIndex,
      cmd.template.id
    ]);
    return null;
  }
  visitEndComponent(context: any): any {
    this.result.push([END_COMPONENT]);
    return null;
  }
  visitEmbeddedTemplate(cmd: EmbeddedTemplateCmd, context: any): any {
    this.result.push([
      EMBEDDED_TEMPLATE,
      cmd.attrNameAndValues,
      cmd.variableNameAndValues,
      cmd.directives.map(checkAndStringifyType),
      cmd.isMerged,
      cmd.ngContentIndex,
      cmd.changeDetectorFactory(null),
      humanize(cmd.children)
    ]);
    return null;
  }
}
function createTestableModule(source: SourceExpression): SourceModule {
  var resultExpression = `${THIS_MODULE_REF}humanize(${source.expression})`;
  var testableSource = `${source.declarations.join('\n')}
  ${codeGenExportVariable('run')}${codeGenValueFn(['_'], resultExpression)};`;
  return new SourceModule(null, testableSource);
}