describe('track ids', function() {
  var context;
  beforeEach(function() {
    context = { is: { a: 'foo' }, slave: { driver: 'bar' } };
  });

  it('should not include anything without the flag', function() {
    var template = CompilerContext.compile('{{wycats is.a slave.driver}}');

    var helpers = {
      wycats: function(passiveVoice, noun, options) {
        equal(options.ids, undefined);
        equal(options.hashIds, undefined);

        return 'success';
      }
    };

    equals(template({}, { helpers: helpers }), 'success');
  });
  it('should include argument ids', function() {
    var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {
      trackIds: true
    });

    var helpers = {
      wycats: function(passiveVoice, noun, options) {
        equal(options.ids[0], 'is.a');
        equal(options.ids[1], 'slave.driver');

        return (
          'HELP ME MY BOSS ' +
          options.ids[0] +
          ':' +
          passiveVoice +
          ' ' +
          options.ids[1] +
          ':' +
          noun
        );
      }
    };

    equals(
      template(context, { helpers: helpers }),
      'HELP ME MY BOSS is.a:foo slave.driver:bar'
    );
  });
  it('should include hash ids', function() {
    var template = CompilerContext.compile(
      '{{wycats bat=is.a baz=slave.driver}}',
      { trackIds: true }
    );

    var helpers = {
      wycats: function(options) {
        equal(options.hashIds.bat, 'is.a');
        equal(options.hashIds.baz, 'slave.driver');

        return (
          'HELP ME MY BOSS ' +
          options.hashIds.bat +
          ':' +
          options.hash.bat +
          ' ' +
          options.hashIds.baz +
          ':' +
          options.hash.baz
        );
      }
    };

    equals(
      template(context, { helpers: helpers }),
      'HELP ME MY BOSS is.a:foo slave.driver:bar'
    );
  });
  it('should note ../ and ./ references', function() {
    var template = CompilerContext.compile(
      '{{wycats ./is.a ../slave.driver this.is.a this}}',
      { trackIds: true }
    );

    var helpers = {
      wycats: function(passiveVoice, noun, thiz, thiz2, options) {
        equal(options.ids[0], 'is.a');
        equal(options.ids[1], '../slave.driver');
        equal(options.ids[2], 'is.a');
        equal(options.ids[3], '');

        return (
          'HELP ME MY BOSS ' +
          options.ids[0] +
          ':' +
          passiveVoice +
          ' ' +
          options.ids[1] +
          ':' +
          noun
        );
      }
    };

    equals(
      template(context, { helpers: helpers }),
      'HELP ME MY BOSS is.a:foo ../slave.driver:undefined'
    );
  });
  it('should note @data references', function() {
    var template = CompilerContext.compile('{{wycats @is.a @slave.driver}}', {
      trackIds: true
    });

    var helpers = {
      wycats: function(passiveVoice, noun, options) {
        equal(options.ids[0], '@is.a');
        equal(options.ids[1], '@slave.driver');

        return (
          'HELP ME MY BOSS ' +
          options.ids[0] +
          ':' +
          passiveVoice +
          ' ' +
          options.ids[1] +
          ':' +
          noun
        );
      }
    };

    equals(
      template({}, { helpers: helpers, data: context }),
      'HELP ME MY BOSS @is.a:foo @slave.driver:bar'
    );
  });

  it('should return null for constants', function() {
    var template = CompilerContext.compile('{{wycats 1 "foo" key=false}}', {
      trackIds: true
    });

    var helpers = {
      wycats: function(passiveVoice, noun, options) {
        equal(options.ids[0], null);
        equal(options.ids[1], null);
        equal(options.hashIds.key, null);

        return (
          'HELP ME MY BOSS ' +
          passiveVoice +
          ' ' +
          noun +
          ' ' +
          options.hash.key
        );
      }
    };

    equals(
      template(context, { helpers: helpers }),
      'HELP ME MY BOSS 1 foo false'
    );
  });
  it('should return true for subexpressions', function() {
    var template = CompilerContext.compile('{{wycats (sub)}}', {
      trackIds: true
    });

    var helpers = {
      sub: function() {
        return 1;
      },
      wycats: function(passiveVoice, options) {
        equal(options.ids[0], true);

        return 'HELP ME MY BOSS ' + passiveVoice;
      }
    };

    equals(template(context, { helpers: helpers }), 'HELP ME MY BOSS 1');
  });

  it('should use block param paths', function() {
    var template = CompilerContext.compile(
      '{{#doIt as |is|}}{{wycats is.a slave.driver is}}{{/doIt}}',
      { trackIds: true }
    );

    var helpers = {
      doIt: function(options) {
        var blockParams = [this.is];
        blockParams.path = ['zomg'];
        return options.fn(this, { blockParams: blockParams });
      },
      wycats: function(passiveVoice, noun, blah, options) {
        equal(options.ids[0], 'zomg.a');
        equal(options.ids[1], 'slave.driver');
        equal(options.ids[2], 'zomg');

        return (
          'HELP ME MY BOSS ' +
          options.ids[0] +
          ':' +
          passiveVoice +
          ' ' +
          options.ids[1] +
          ':' +
          noun
        );
      }
    };

    equals(
      template(context, { helpers: helpers }),
      'HELP ME MY BOSS zomg.a:foo slave.driver:bar'
    );
  });

  describe('builtin helpers', function() {
    var helpers = {
      blockParams: function(name, options) {
        return name + ':' + options.ids[0] + '\n';
      },
      wycats: function(name, options) {
        return name + ':' + options.data.contextPath + '\n';
      }
    };

    describe('#each', function() {
      it('should track contextPath for arrays', function() {
        var template = CompilerContext.compile(
          '{{#each array}}{{wycats name}}{{/each}}',
          { trackIds: true }
        );

        equals(
          template(
            { array: [{ name: 'foo' }, { name: 'bar' }] },
            { helpers: helpers }
          ),
          'foo:array.0\nbar:array.1\n'
        );
      });
      it('should track contextPath for keys', function() {
        var template = CompilerContext.compile(
          '{{#each object}}{{wycats name}}{{/each}}',
          { trackIds: true }
        );

        equals(
          template(
            { object: { foo: { name: 'foo' }, bar: { name: 'bar' } } },
            { helpers: helpers }
          ),
          'foo:object.foo\nbar:object.bar\n'
        );
      });
      it('should handle nesting', function() {
        var template = CompilerContext.compile(
          '{{#each .}}{{#each .}}{{wycats name}}{{/each}}{{/each}}',
          { trackIds: true }
        );

        equals(
          template(
            { array: [{ name: 'foo' }, { name: 'bar' }] },
            { helpers: helpers }
          ),
          'foo:.array..0\nbar:.array..1\n'
        );
      });
      it('should handle block params', function() {
        var template = CompilerContext.compile(
          '{{#each array as |value|}}{{blockParams value.name}}{{/each}}',
          { trackIds: true }
        );

        equals(
          template(
            { array: [{ name: 'foo' }, { name: 'bar' }] },
            { helpers: helpers }
          ),
          'foo:array.0.name\nbar:array.1.name\n'
        );
      });
    });
    describe('#with', function() {
      it('should track contextPath', function() {
        var template = CompilerContext.compile(
          '{{#with field}}{{wycats name}}{{/with}}',
          { trackIds: true }
        );

        equals(
          template({ field: { name: 'foo' } }, { helpers: helpers }),
          'foo:field\n'
        );
      });
      it('should handle nesting', function() {
        var template = CompilerContext.compile(
          '{{#with bat}}{{#with field}}{{wycats name}}{{/with}}{{/with}}',
          { trackIds: true }
        );

        equals(
          template({ bat: { field: { name: 'foo' } } }, { helpers: helpers }),
          'foo:bat.field\n'
        );
      });
    });
    describe('#blockHelperMissing', function() {
      it('should track contextPath for arrays', function() {
        var template = CompilerContext.compile(
          '{{#field}}{{wycats name}}{{/field}}',
          { trackIds: true }
        );

        equals(
          template({ field: [{ name: 'foo' }] }, { helpers: helpers }),
          'foo:field.0\n'
        );
      });
      it('should track contextPath for keys', function() {
        var template = CompilerContext.compile(
          '{{#field}}{{wycats name}}{{/field}}',
          { trackIds: true }
        );

        equals(
          template({ field: { name: 'foo' } }, { helpers: helpers }),
          'foo:field\n'
        );
      });
      it('should handle nesting', function() {
        var template = CompilerContext.compile(
          '{{#bat}}{{#field}}{{wycats name}}{{/field}}{{/bat}}',
          { trackIds: true }
        );

        equals(
          template({ bat: { field: { name: 'foo' } } }, { helpers: helpers }),
          'foo:bat.field\n'
        );
      });
    });
  });

  describe('partials', function() {
    var helpers = {
      blockParams: function(name, options) {
        return name + ':' + options.ids[0] + '\n';
      },
      wycats: function(name, options) {
        return name + ':' + options.data.contextPath + '\n';
      }
    };

    it('should pass track id for basic partial', function() {
      var template = CompilerContext.compile(
          'Dudes: {{#dudes}}{{> dude}}{{/dudes}}',
          { trackIds: true }
        ),
        hash = {
          dudes: [
            { name: 'Yehuda', url: 'http://yehuda' },
            { name: 'Alan', url: 'http://alan' }
          ]
        };

      var partials = {
        dude: CompilerContext.compile('{{wycats name}}', { trackIds: true })
      };

      equals(
        template(hash, { helpers: helpers, partials: partials }),
        'Dudes: Yehuda:dudes.0\nAlan:dudes.1\n'
      );
    });

    it('should pass track id for context partial', function() {
      var template = CompilerContext.compile('Dudes: {{> dude dudes}}', {
          trackIds: true
        }),
        hash = {
          dudes: [
            { name: 'Yehuda', url: 'http://yehuda' },
            { name: 'Alan', url: 'http://alan' }
          ]
        };

      var partials = {
        dude: CompilerContext.compile(
          '{{#each this}}{{wycats name}}{{/each}}',
          { trackIds: true }
        )
      };

      equals(
        template(hash, { helpers: helpers, partials: partials }),
        'Dudes: Yehuda:dudes..0\nAlan:dudes..1\n'
      );
    });

    it('should invalidate context for partials with parameters', function() {
      var template = CompilerContext.compile(
          'Dudes: {{#dudes}}{{> dude . bar="foo"}}{{/dudes}}',
          { trackIds: true }
        ),
        hash = {
          dudes: [
            { name: 'Yehuda', url: 'http://yehuda' },
            { name: 'Alan', url: 'http://alan' }
          ]
        };

      var partials = {
        dude: CompilerContext.compile('{{wycats name}}', { trackIds: true })
      };

      equals(
        template(hash, { helpers: helpers, partials: partials }),
        'Dudes: Yehuda:true\nAlan:true\n'
      );
    });
  });
});
