From f0b9776f43360c1c66d35db87e91f6f5a7cbe10f Mon Sep 17 00:00:00 2001 From: mathematicalcoffee Date: Thu, 7 Feb 2013 23:09:45 +1000 Subject: [PATCH 01/11] added tests for dictionary.js and dictionary/definitions.js --- test/specs/jsdoc/tag/dictionary.js | 107 +++++++++++++++++- .../specs/jsdoc/tag/dictionary/definitions.js | 15 +++ 2 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 test/specs/jsdoc/tag/dictionary/definitions.js diff --git a/test/specs/jsdoc/tag/dictionary.js b/test/specs/jsdoc/tag/dictionary.js index af8f72d0..75e1bbc5 100644 --- a/test/specs/jsdoc/tag/dictionary.js +++ b/test/specs/jsdoc/tag/dictionary.js @@ -1,3 +1,104 @@ -describe("jsdoc/tag/dictionary", function() { - //TODO -}); \ No newline at end of file +describe('jsdoc/tag/dictionary', function() { + var dictionary = require('jsdoc/tag/dictionary'); + + it('should exist', function() { + expect(dictionary).toBeDefined(); + expect(typeof dictionary).toEqual('object'); + }); + + it('should export a defineTag function', function() { + expect(dictionary.defineTag).toBeDefined(); + expect(typeof dictionary.defineTag).toEqual('function'); + }); + + it('should export a lookUp function', function() { + expect(dictionary.lookUp).toBeDefined(); + expect(typeof dictionary.lookUp).toEqual('function'); + }); + + it('should export a isNamespace function', function() { + expect(dictionary.isNamespace).toBeDefined(); + expect(typeof dictionary.isNamespace).toEqual('function'); + }); + + it('should export a normalise function', function() { + expect(dictionary.normalise).toBeDefined(); + expect(typeof dictionary.normalise).toEqual('function'); + }); + + // TODO: should really remove this tag from the dictionary after, but how? + var tagOptions = { + canHaveValue: true, + isNamespace: true + }, + tagTitle = 'testTag', + tagSynonym = 'testTag2'; + var def = dictionary.defineTag(tagTitle, tagOptions).synonym(tagSynonym); + // Should really test TagDefinition but they are private. + // Instead, we'll just tests all the properties we expect of it. + describe("defineTag", function() { + + // Since TagDefinition is private, I'll just test for its properties here. + it("returns an object with 'title' property", function() { + expect(typeof def).toEqual('object'); + // how to test? + expect(def.title).toBeDefined(); + expect(typeof def.title).toEqual('string'); + expect(def.title).toEqual(dictionary.normalise(tagTitle)); + }); + + it("returned object has all the tag properties copied over", function() { + for (var prop in tagOptions) { + if (tagOptions.hasOwnProperty(prop)) { + expect(def[prop]).toEqual(tagOptions[prop]); + } + } + }); + }); + + xdescribe("lookUp", function() { + // TODO: BUG: tags are stored in the dictionary with their un-normalised name, + // so if your tag had capital letters then it would be stored as + // _definitions[with capital letters]. However, we *look tags up* + // under their *normalised* names, i.e. will be lower case. + // We should store in the _definitions table under the normalised name. + it("retrieves definition when using the tag's canonical name", function() { + expect(dictionary.lookUp(tagTitle)).toEqual(def); + }); + + it("retrieves definition when using a synonym", function() { + expect(dictionary.lookUp(tagSynonym)).toEqual(def); + }); + + it("returns FALSE when a tag is not found", function() { + expect(dictionary.lookUp('lkjas1l24jk')).toEqual(false); + }); + }); + + describe("isNamespace", function() { + it("returns whether a tag is a namespace when using its canonical name", function() { + expect(dictionary.isNamespace(tagTitle)).toEqual(true); + }); + + // TODO: BUG: isNamespace should use a normalised title. + xit("returns whether a tag is a namespace when using its synonym", function() { + expect(dictionary.isNamespace(tagSynonym)).toEqual(true); + }); + + it("non-existent tags or non-namespace tags should return false", function() { + expect(dictionary.isNamespace('see')).toEqual(false); + expect(dictionary.isNamespace('lkjasd90034')).toEqual(false); + }); + }); + + describe("normalise", function() { + it("should return the tag's title if it is not a synonym", function() { + expect(dictionary.normalise('FooBar')).toEqual('foobar'); + expect(dictionary.normalise(tagTitle)).toEqual(def.title); + }); + + it("should return the canonical name of a tag if the synonym is normalised", function() { + expect(dictionary.normalise(tagSynonym)).toEqual(def.title); + }); + }); +}); diff --git a/test/specs/jsdoc/tag/dictionary/definitions.js b/test/specs/jsdoc/tag/dictionary/definitions.js new file mode 100644 index 00000000..831ae626 --- /dev/null +++ b/test/specs/jsdoc/tag/dictionary/definitions.js @@ -0,0 +1,15 @@ +describe('jsdoc/tag/dictionary/definitions', function() { + var type = require('jsdoc/tag/dictionary/definitions'); + + it('should exist', function() { + expect(type).toBeDefined(); + expect(typeof type).toEqual('object'); + }); + + it('should export a defineTags function', function() { + expect(type.defineTags).toBeDefined(); + expect(typeof type.defineTags).toEqual('function'); + }); + // whole bit of dictionary.defineTags...but it just calls dictionary.defineTag + // and if I validate that then the rest is automatically validated? +}); From 5fadd37fb5e353b5b64b62ac7fbef10394f8be1e Mon Sep 17 00:00:00 2001 From: mathematicalcoffee Date: Fri, 8 Feb 2013 10:02:58 +1000 Subject: [PATCH 02/11] FIX: dictionary.defineTag should store tags under the normalised name. --- lib/jsdoc/tag/dictionary.js | 8 +++++--- test/specs/jsdoc/tag/dictionary.js | 11 +++-------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/jsdoc/tag/dictionary.js b/lib/jsdoc/tag/dictionary.js index 033e6134..c10f8f22 100644 --- a/lib/jsdoc/tag/dictionary.js +++ b/lib/jsdoc/tag/dictionary.js @@ -33,13 +33,15 @@ TagDefinition.prototype.synonym = function(synonymName) { dictionary = { /** @function */ defineTag: function(title, opts) { - _definitions[title] = new TagDefinition(title, opts); + var def = new TagDefinition(title, opts); + // all the other dictionary functions use normalised names; we should too. + _definitions[def.title] = def; if (opts.isNamespace) { - _namespaces.push(title); + _namespaces.push(def.title); } - return _definitions[title]; + return _definitions[def.title]; }, /** @function */ diff --git a/test/specs/jsdoc/tag/dictionary.js b/test/specs/jsdoc/tag/dictionary.js index 75e1bbc5..dfa37525 100644 --- a/test/specs/jsdoc/tag/dictionary.js +++ b/test/specs/jsdoc/tag/dictionary.js @@ -56,12 +56,7 @@ describe('jsdoc/tag/dictionary', function() { }); }); - xdescribe("lookUp", function() { - // TODO: BUG: tags are stored in the dictionary with their un-normalised name, - // so if your tag had capital letters then it would be stored as - // _definitions[with capital letters]. However, we *look tags up* - // under their *normalised* names, i.e. will be lower case. - // We should store in the _definitions table under the normalised name. + describe("lookUp", function() { it("retrieves definition when using the tag's canonical name", function() { expect(dictionary.lookUp(tagTitle)).toEqual(def); }); @@ -76,11 +71,11 @@ describe('jsdoc/tag/dictionary', function() { }); describe("isNamespace", function() { - it("returns whether a tag is a namespace when using its canonical name", function() { + // TODO: BUG: isNamespace should use a normalised title. + xit("returns whether a tag is a namespace when using its canonical name", function() { expect(dictionary.isNamespace(tagTitle)).toEqual(true); }); - // TODO: BUG: isNamespace should use a normalised title. xit("returns whether a tag is a namespace when using its synonym", function() { expect(dictionary.isNamespace(tagSynonym)).toEqual(true); }); From e384a06b455ae1a165bb9b8c22763aae376d2905 Mon Sep 17 00:00:00 2001 From: mathematicalcoffee Date: Fri, 8 Feb 2013 10:03:47 +1000 Subject: [PATCH 03/11] FIX: dictionary.isNamespace should do the lookup under the normalised name --- lib/jsdoc/tag/dictionary.js | 7 +++++-- test/specs/jsdoc/tag/dictionary.js | 5 ++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/jsdoc/tag/dictionary.js b/lib/jsdoc/tag/dictionary.js index c10f8f22..18190502 100644 --- a/lib/jsdoc/tag/dictionary.js +++ b/lib/jsdoc/tag/dictionary.js @@ -57,8 +57,11 @@ dictionary = { /** @function */ isNamespace: function(kind) { - if ( _namespaces.indexOf(kind) !== -1) { - return true; + if (kind) { + kind = dictionary.normalise(kind); + if ( _namespaces.indexOf(kind) !== -1) { + return true; + } } return false; diff --git a/test/specs/jsdoc/tag/dictionary.js b/test/specs/jsdoc/tag/dictionary.js index dfa37525..6c0768b9 100644 --- a/test/specs/jsdoc/tag/dictionary.js +++ b/test/specs/jsdoc/tag/dictionary.js @@ -71,12 +71,11 @@ describe('jsdoc/tag/dictionary', function() { }); describe("isNamespace", function() { - // TODO: BUG: isNamespace should use a normalised title. - xit("returns whether a tag is a namespace when using its canonical name", function() { + it("returns whether a tag is a namespace when using its canonical name", function() { expect(dictionary.isNamespace(tagTitle)).toEqual(true); }); - xit("returns whether a tag is a namespace when using its synonym", function() { + it("returns whether a tag is a namespace when using its synonym", function() { expect(dictionary.isNamespace(tagSynonym)).toEqual(true); }); From 0f1f9ff6637a2e67652f4e854f4c75a6c3079a91 Mon Sep 17 00:00:00 2001 From: mathematicalcoffee Date: Fri, 8 Feb 2013 11:05:29 +1000 Subject: [PATCH 04/11] added tests for jsdoc/tag/validator.js --- test/specs/jsdoc/tag/validator.js | 99 ++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 3 deletions(-) diff --git a/test/specs/jsdoc/tag/validator.js b/test/specs/jsdoc/tag/validator.js index 4dd4be63..1a5175e2 100644 --- a/test/specs/jsdoc/tag/validator.js +++ b/test/specs/jsdoc/tag/validator.js @@ -1,3 +1,96 @@ -describe("jsdoc/tag/validator", function() { - //TODO -}); \ No newline at end of file +describe('jsdoc/tag/validator', function() { + var validator = require('jsdoc/tag/validator'), + tag = require('jsdoc/tag'); + + it('should exist', function() { + expect(validator).toBeDefined(); + expect(typeof validator).toEqual('object'); + }); + + it('should export a validate function', function() { + expect(validator.validate).toBeDefined(); + expect(typeof validator.validate).toEqual('function'); + }); + + // Note: various Error classes are private so we just test whether *any* + // error was thrown, not against particular types (e.g. UnknownTagError). + describe('validate', function() { + var lenient = !!env.opts.lenient, + allowUnknown = !!env.conf.tags.allowUnknownTags, + log = eval(console.log), + badTag = {title: 'lkjasdlkjfb'}, + meta = {filename: 'asdf.js', lineno: 1}, + goodTag = new tag.Tag('name', 'MyDocletName', meta), // mustHaveValue + goodTag2 = new tag.Tag('ignore', '', meta); // mustNotHaveValue + + function validateTag(tag) { + return function() { validator.validate(tag, meta); }; + } + + beforeEach(function() { + console.log = function() {}; + }); + + afterEach(function() { + env.opts.lenient = lenient; + env.conf.tags.allowUnknownTags = allowUnknown; + console.log = log; + }); + + it("throws an error if the tag is not in the dictionary, conf.tags.allowUnknownTags is false and lenient is false", function() { + env.opts.lenient = false; + env.conf.tags.allowUnknownTags = false; + expect(validateTag(badTag)).toThrow(); + }); + + it("throws NO error if the tag is not in the dictionary, conf.tags.allowUnknownTags is false and lenient is true", function() { + env.opts.lenient = true; + env.conf.tags.allowUnknownTags = false; + expect(validateTag(badTag)).not.toThrow(); + }); + + it("doesn't throw an error if the tag is not in the dictionary and conf.tags.allowUnknownTags is true, regardless of lenience", function() { + // if it doesn't throw an error with lenient false, then it won't throw it with lenient true (we have + // tested lenient already in util/error.js) + env.opts.lenient = false; + env.conf.tags.allowUnknownTags = true; + expect(validateTag(badTag)).not.toThrow(); + }); + + it("throws no error for valid tags", function() { + env.opts.lenient = false; + expect(validateTag(goodTag)).not.toThrow(); + expect(validateTag(goodTag2)).not.toThrow(); + }); + + it("throws an error if the tag has no text but .mustHaveValue is true and lenient is false, or none if it's true", function() { + // the name tag has .mustHaveValue. + var oldText = goodTag.text; + delete goodTag.text; + + env.opts.lenient = false; + expect(validateTag(goodTag)).toThrow(); + + env.opts.lenient = true; + expect(validateTag(goodTag)).not.toThrow(); + + goodTag.text = oldText; + }); + + it("throws an error if the tag has text but .mustNotHaveValue is true and lenient is false, or none if it's true", function() { + var oldVal = goodTag2.mustNotHaveValue, + text = goodTag2.text; + goodTag2.mustNotHaveValue = true; + goodTag2.text = goodTag2.text || 'asdf'; + + env.opts.lenient = false; + expect(validateTag(goodTag2)).toThrow(); + + env.opts.lenient = true; + expect(validateTag(goodTag2)).not.toThrow(); + + goodTag2.mustNotHaveValue = oldVal; + goodTag2.text = oldVal; + }); + }); +}); From 2161359eeb6fe6288c5811641af63cc7a3f247d0 Mon Sep 17 00:00:00 2001 From: mathematicalcoffee Date: Fri, 8 Feb 2013 13:41:30 +1000 Subject: [PATCH 05/11] added tests for jsdoc/tag. --- test/specs/jsdoc/tag.js | 181 ++++++++++++++++++++++++++++++++++------ 1 file changed, 156 insertions(+), 25 deletions(-) diff --git a/test/specs/jsdoc/tag.js b/test/specs/jsdoc/tag.js index af71b0a0..e874a097 100644 --- a/test/specs/jsdoc/tag.js +++ b/test/specs/jsdoc/tag.js @@ -1,33 +1,164 @@ /*global describe: true, env: true, it: true */ describe("jsdoc/tag", function() { - /*jshint evil: true */ - - // TODO: more tests + var jsdoc = { + tag: require('jsdoc/tag'), + dictionary: require('jsdoc/tag/dictionary'), + type: require('jsdoc/tag/type') + }; - var lenient = !!env.opts.lenient, - log = eval(console.log); - - function badTag() { - var Tag = require("jsdoc/tag").Tag; - var tag = new Tag("name"); - return tag; - } - - afterEach(function() { - env.opts.lenient = lenient; - console.log = log; + it('should exist', function() { + expect(jsdoc.tag).toBeDefined(); + expect(typeof jsdoc.tag).toEqual('object'); }); - it("throws an exception for bad tags if the lenient option is not enabled", function() { - env.opts.lenient = false; - - expect(badTag).toThrow(); + it('should export a Tag function', function() { + expect(jsdoc.tag.Tag).toBeDefined(); + expect(typeof jsdoc.tag.Tag).toEqual('function'); }); - - it("doesn't throw an exception for bad tags if the lenient option is enabled", function() { - console.log = function() {}; - env.opts.lenient = true; - expect(badTag).not.toThrow(); + describe('Tag', function() { + var meta = {lineno: 1, filename: 'asdf.js'}, + desc = 'lalblakd lkjasdlib\n lija', + text = '{!number} [foo=] - ' + desc, + textEg = 'Asdf\n' + + ' * myFunction(1, 2); // returns 3\n' + + ' * myFunction(3, 4); // returns 7\n'; + // note arg is a synonym of param. + var tagArg = new jsdoc.tag.Tag('arg ', text, meta), // <-- a symonym, space in the title. + tagEg = new jsdoc.tag.Tag('example', textEg, meta), // <-- for keepsWhitespace + tagType = new jsdoc.tag.Tag('type', 'MyType ', meta); // <-- for onTagText + + it("should have a 'originalTitle' property, a string", function() { + expect(tagArg.originalTitle).toBeDefined(); + expect(typeof tagArg.originalTitle).toEqual('string'); + }); + + it("'originalTitle' property should be the initial tag title, trimmed of whitespace", function() { + expect(tagArg.originalTitle).toEqual('arg'); + expect(tagEg.originalTitle).toEqual('example'); + }); + + it("should have a 'title' property, a string", function() { + expect(tagArg.title).toBeDefined(); + expect(typeof tagArg.title).toEqual('string'); + }); + + it("'title' property should be the normalised tag title", function() { + expect(tagArg.title).toEqual(jsdoc.dictionary.normalise(tagArg.originalTitle)); + expect(tagEg.title).toEqual(jsdoc.dictionary.normalise(tagEg.originalTitle)); + }); + + it("should have a 'text' property. a string", function () { + expect(tagArg.text).toBeDefined(); + expect(typeof tagArg.text).toEqual('string'); + }); + + it("should have a 'value' property", function () { + expect(tagArg.value).toBeDefined(); + expect(tagEg.value).toBeDefined(); + expect(tagType.value).toBeDefined(); + }); + + describe("'text' property", function() { + it("'text' property should be the trimmed tag text, with all leading and trailing space removed unless tagDef.keepsWhitespace", function() { + // @example has keepsWhitespace, @param doesn't. + // should realy use module:jsdoc/tag~trim here but it's private. + expect(tagArg.text).toEqual(text.replace(/^\s+|\s+$/g, '')); + expect(tagEg.text).toEqual(textEg.replace(/^[\n\r\f]+|[\n\r\f]+$/g, '')); + }); + + it("'text' property should have onTagText run on it if it has it.", function() { + var def = jsdoc.dictionary.lookUp('type'); + expect(def.onTagText).toBeDefined(); + expect(typeof def.onTagText).toEqual('function'); + + // @type adds {} around the type if necessary. + expect(tagType.text).toBeDefined(); + expect(tagType.text).toEqual(def.onTagText('MyType')); + }); + }); + + // BUG: when Tag() looks up a tag definition it should used the trimmed tag title. + // otherwise, tag properties are not looked up. + // This makes all of tagArg.value wrong (because of the spaces in the name). + describe("'value' property", function() { + it("'value' property should equal tag text if tagDef.canHaveType and canHaveName are both false", function() { + // @example can't have type or name + expect(typeof tagEg.value).toEqual('string'); + expect(tagEg.value).toEqual(tagEg.text); + }); + + it("'value' property should be an object if tagDef can have type or name", function () { + expect(typeof tagType.value).toEqual('object'); + // expect(typeof tagArg.value).toEqual('object'); + }); + + function verifyTagType(tag) { + var def = jsdoc.dictionary.lookUp(tag.title); + expect(def).not.toEqual(false); + var info = jsdoc.type.parse(tag.text, def.canHaveName, def.canHaveType); + + var props_that_should_be_copied = ['optional', 'nullable', 'variable', 'defaultvalue']; + for (var i = 0; i < props_that_should_be_copied.length; ++i) { + var prop = props_that_should_be_copied[i]; + if (info.hasOwnProperty(prop)) { + expect(tag.value[prop]).toEqual(info[prop]); + } + } + expect(tag.value.type).toBeDefined(); + expect(typeof tag.value.type).toEqual('object'); + expect(tag.value.type.names).toBeDefined(); + expect(tag.value.type.names).toEqual(info.type); + } + it("if the tag has a type, tag.value should contain the type information", function() { + // we assume jsdoc/tag/type.parse works (it has its own tests to verify this); + verifyTagType(tagType); + // verifyTagType(tagArg); + }); + + it("if the tag has a description beyond the name/type, this should be in tag.value.description", function() { + expect(tagType.value.description).not.toBeDefined(); + + // expect(tagArg.value.description).toBeDefined(); + // expect(tagArg.value.description).toEqual(desc); + }); + + it("if the tag can have a name, it should be stored in tag.value.name", function() { + //expect(tagArg.value.name).toBeDefined(); + //expect(tagArg.value.name).toEqual('foo'); + + expect(tagType.value.name).not.toBeDefined(); + }); + }); + + // further tests for this sort of thing are in jsdoc/tag/validator.js tests. + describe("tag validating", function() { + /*jshint evil: true */ + var lenient = !!env.opts.lenient, + log = eval(console.log); + + function badTag() { + var tag = new jsdoc.tag.Tag("name"); + return tag; + } + + afterEach(function() { + env.opts.lenient = lenient; + console.log = log; + }); + + it("throws an exception for bad tags if the lenient option is not enabled", function() { + env.opts.lenient = false; + + expect(badTag).toThrow(); + }); + + it("doesn't throw an exception for bad tags if the lenient option is enabled", function() { + console.log = function() {}; + env.opts.lenient = true; + + expect(badTag).not.toThrow(); + }); + }); }); -}); \ No newline at end of file +}); From 1c52170c096ca912c4871becb25c150d9cc0261c Mon Sep 17 00:00:00 2001 From: mathematicalcoffee Date: Fri, 8 Feb 2013 13:52:12 +1000 Subject: [PATCH 06/11] FIX: in Tag constructor, we should look up the tag definition using the trimmed (and lowercased) title --- lib/jsdoc/tag.js | 3 ++- test/specs/jsdoc/tag.js | 20 ++++++++------------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/lib/jsdoc/tag.js b/lib/jsdoc/tag.js index 349b15c5..32808562 100644 --- a/lib/jsdoc/tag.js +++ b/lib/jsdoc/tag.js @@ -41,13 +41,14 @@ function trim(text, newlines) { @param {object=} meta */ exports.Tag = function(tagTitle, tagBody, meta) { - var tagDef = jsdoc.tag.dictionary.lookUp(tagTitle); meta = meta || {}; this.originalTitle = trim(tagTitle); /** The title part of the tag: @title text */ this.title = jsdoc.tag.dictionary.normalise( this.originalTitle ); + + var tagDef = jsdoc.tag.dictionary.lookUp(this.title); /** The text part of the tag: @title text */ this.text = trim(tagBody, tagDef.keepsWhitespace); diff --git a/test/specs/jsdoc/tag.js b/test/specs/jsdoc/tag.js index e874a097..e40a55a5 100644 --- a/test/specs/jsdoc/tag.js +++ b/test/specs/jsdoc/tag.js @@ -19,12 +19,11 @@ describe("jsdoc/tag", function() { describe('Tag', function() { var meta = {lineno: 1, filename: 'asdf.js'}, desc = 'lalblakd lkjasdlib\n lija', - text = '{!number} [foo=] - ' + desc, + text = '{!number} [foo=1] - ' + desc, textEg = 'Asdf\n' + ' * myFunction(1, 2); // returns 3\n' + ' * myFunction(3, 4); // returns 7\n'; - // note arg is a synonym of param. - var tagArg = new jsdoc.tag.Tag('arg ', text, meta), // <-- a symonym, space in the title. + var tagArg = new jsdoc.tag.Tag('arg ', text, meta), // <-- a symonym of param, space in the title. tagEg = new jsdoc.tag.Tag('example', textEg, meta), // <-- for keepsWhitespace tagType = new jsdoc.tag.Tag('type', 'MyType ', meta); // <-- for onTagText @@ -78,9 +77,6 @@ describe("jsdoc/tag", function() { }); }); - // BUG: when Tag() looks up a tag definition it should used the trimmed tag title. - // otherwise, tag properties are not looked up. - // This makes all of tagArg.value wrong (because of the spaces in the name). describe("'value' property", function() { it("'value' property should equal tag text if tagDef.canHaveType and canHaveName are both false", function() { // @example can't have type or name @@ -90,7 +86,7 @@ describe("jsdoc/tag", function() { it("'value' property should be an object if tagDef can have type or name", function () { expect(typeof tagType.value).toEqual('object'); - // expect(typeof tagArg.value).toEqual('object'); + expect(typeof tagArg.value).toEqual('object'); }); function verifyTagType(tag) { @@ -113,19 +109,19 @@ describe("jsdoc/tag", function() { it("if the tag has a type, tag.value should contain the type information", function() { // we assume jsdoc/tag/type.parse works (it has its own tests to verify this); verifyTagType(tagType); - // verifyTagType(tagArg); + verifyTagType(tagArg); }); it("if the tag has a description beyond the name/type, this should be in tag.value.description", function() { expect(tagType.value.description).not.toBeDefined(); - // expect(tagArg.value.description).toBeDefined(); - // expect(tagArg.value.description).toEqual(desc); + expect(tagArg.value.description).toBeDefined(); + expect(tagArg.value.description).toEqual(desc); }); it("if the tag can have a name, it should be stored in tag.value.name", function() { - //expect(tagArg.value.name).toBeDefined(); - //expect(tagArg.value.name).toEqual('foo'); + expect(tagArg.value.name).toBeDefined(); + expect(tagArg.value.name).toEqual('foo'); expect(tagType.value.name).not.toBeDefined(); }); From ed6de4a5d9141576c4643ca70747f1c81d294baf Mon Sep 17 00:00:00 2001 From: mathematicalcoffee Date: Fri, 8 Feb 2013 13:59:21 +1000 Subject: [PATCH 07/11] added tests for jsdoc/tag/type/closerCompilerType --- .../jsdoc/tag/type/closureCompilerType.js | 58 ++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/test/specs/jsdoc/tag/type/closureCompilerType.js b/test/specs/jsdoc/tag/type/closureCompilerType.js index 61c556ca..d6ae73c2 100644 --- a/test/specs/jsdoc/tag/type/closureCompilerType.js +++ b/test/specs/jsdoc/tag/type/closureCompilerType.js @@ -1,7 +1,5 @@ /*global describe: true, expect: true, it: true */ describe('jsdoc/tag/type/closureCompilerType', function() { - // TODO: more tests - var type = require('jsdoc/tag/type/closureCompilerType'); it('should exist', function() { @@ -15,11 +13,67 @@ describe('jsdoc/tag/type/closureCompilerType', function() { }); describe('parse', function() { + it('should parse optional types', function() { + var info = type.parse({type: 'Asdf.Foobar='}); + expect(info.type).toEqual('Asdf.Foobar'); + expect(info.optional).toEqual(true); + }); + + it('should parse nullable types', function() { + var info = type.parse({type: '?Asdf.Foobar'}); + expect(info.type).toEqual('Asdf.Foobar'); + expect(info.nullable).toEqual(true); + }); + + it('should parse non-nullable types', function() { + var info = type.parse({type: '!Asdf.Foobar'}); + expect(info.type).toEqual('Asdf.Foobar'); + expect(info.nullable).toEqual(false); + }); + + it('should parse variable types', function() { + var info = type.parse({type: '...Fdsa.Baz'}); + expect(info.type).toEqual('Fdsa.Baz'); + expect(info.variable).toEqual(true); + }); + it('should correctly parse types that are both optional and nullable', function() { var info = type.parse( {type: '?string='} ); expect(info.type).toEqual('string'); expect(info.optional).toEqual(true); expect(info.nullable).toEqual(true); }); + + it('should correctly parse types that are both optional and variable', function() { + var info = type.parse( {type: '...string='} ); + expect(info.type).toEqual('string'); + expect(info.optional).toEqual(true); + expect(info.variable).toEqual(true); + }); + + it("should only change the `type`, `optional`, `nullable` and `variable` properties", function() { + var obj = { + name: "foo", + type: "?...number=", + text: "Sample text.", + optional: null, + nullable: null, + variable: null, + defaultvalue: null + }; + var shouldChange = [ "type", "optional", "nullable", "variable" ]; + + var info = type.parse(obj); + for (var key in info) { + if ( hasOwnProp.call(info, key) ) { + if ( shouldChange.indexOf(key) !== -1 ) { + expect( info[key] ).not.toEqual( obj[key] ); + } + else { + expect( info[key] ).toEqual( obj[key] ); + } + } + } + }); }); }); From d985da693ea6c52438b0cdcb1e1665bccdcd01e3 Mon Sep 17 00:00:00 2001 From: mathematicalcoffee Date: Tue, 12 Feb 2013 13:55:20 +1000 Subject: [PATCH 08/11] BUGFIX: '@param [foo]' should have the 'optional' property set (tags with no type but implied properties in the name should have those properties set on the tag) --- lib/jsdoc/tag.js | 12 ++++++++---- test/fixtures/paramtag.js | 6 ++++++ test/specs/jsdoc/tag.js | 12 ++++++++---- test/specs/jsdoc/tag/type.js | 4 ++++ test/specs/tags/paramtag.js | 16 ++++++++++++++-- 5 files changed, 40 insertions(+), 10 deletions(-) diff --git a/lib/jsdoc/tag.js b/lib/jsdoc/tag.js index 32808562..b7b479cf 100644 --- a/lib/jsdoc/tag.js +++ b/lib/jsdoc/tag.js @@ -66,10 +66,14 @@ exports.Tag = function(tagTitle, tagBody, meta) { var tagType = jsdoc.tag.type.parse(this.text, tagDef.canHaveName, tagDef.canHaveType); - if (tagType.type && tagType.type.length) { - this.value.type = { - names: tagType.type - }; + // BUG: a tag can *not* have a type but still have optional, nullable, variable, defaultvalue. + // e.g. @param [foo] has name 'foo' and property optional=true but *no type*. + if (tagType.type) { + if (tagType.type.length) { + this.value.type = { + names: tagType.type + }; + } this.value.optional = tagType.optional; this.value.nullable = tagType.nullable; this.value.variable = tagType.variable; diff --git a/test/fixtures/paramtag.js b/test/fixtures/paramtag.js index db431bfc..c6fd831c 100644 --- a/test/fixtures/paramtag.js +++ b/test/fixtures/paramtag.js @@ -39,3 +39,9 @@ function split(delimiter) { */ function commit(atomic) { } + +/** + * @param [async=true] - whether to be asynchronous + */ +function request(async) { +} diff --git a/test/specs/jsdoc/tag.js b/test/specs/jsdoc/tag.js index e40a55a5..52d6938a 100644 --- a/test/specs/jsdoc/tag.js +++ b/test/specs/jsdoc/tag.js @@ -24,6 +24,7 @@ describe("jsdoc/tag", function() { ' * myFunction(1, 2); // returns 3\n' + ' * myFunction(3, 4); // returns 7\n'; var tagArg = new jsdoc.tag.Tag('arg ', text, meta), // <-- a symonym of param, space in the title. + tagParam = new jsdoc.tag.Tag('param', '[foo=1]', meta), // no type, but has optional and defaultvalue. tagEg = new jsdoc.tag.Tag('example', textEg, meta), // <-- for keepsWhitespace tagType = new jsdoc.tag.Tag('type', 'MyType ', meta); // <-- for onTagText @@ -101,15 +102,18 @@ describe("jsdoc/tag", function() { expect(tag.value[prop]).toEqual(info[prop]); } } - expect(tag.value.type).toBeDefined(); - expect(typeof tag.value.type).toEqual('object'); - expect(tag.value.type.names).toBeDefined(); - expect(tag.value.type.names).toEqual(info.type); + if (info.type && info.type.length) { + expect(tag.value.type).toBeDefined(); + expect(typeof tag.value.type).toEqual('object'); + expect(tag.value.type.names).toBeDefined(); + expect(tag.value.type.names).toEqual(info.type); + } } it("if the tag has a type, tag.value should contain the type information", function() { // we assume jsdoc/tag/type.parse works (it has its own tests to verify this); verifyTagType(tagType); verifyTagType(tagArg); + verifyTagType(tagParam); }); it("if the tag has a description beyond the name/type, this should be in tag.value.description", function() { diff --git a/test/specs/jsdoc/tag/type.js b/test/specs/jsdoc/tag/type.js index 5f985b33..c9953133 100644 --- a/test/specs/jsdoc/tag/type.js +++ b/test/specs/jsdoc/tag/type.js @@ -122,6 +122,10 @@ describe("jsdoc/tag/type", function() { desc = "{string=} [foo]"; info = jsdoc.tag.type.parse(desc, true, true); expect(info.optional).toEqual(true); + + desc = "[foo]"; + info = jsdoc.tag.type.parse(desc, true, true); + expect(info.optional).toEqual(true); }); it("should return the types as an array", function() { diff --git a/test/specs/tags/paramtag.js b/test/specs/tags/paramtag.js index 14d628ad..b0e1046c 100644 --- a/test/specs/tags/paramtag.js +++ b/test/specs/tags/paramtag.js @@ -6,7 +6,8 @@ describe("@param tag", function() { getElement = docSet.getByLongname('getElement')[0], combine = docSet.getByLongname('combine')[0], split = docSet.getByLongname('split')[0], - commit = docSet.getByLongname('commit')[0]; + commit = docSet.getByLongname('commit')[0], + request = docSet.getByLongname('request')[0]; it('When a symbol has an @param tag with a type before the name, the doclet has a params property that includes that param.', function() { expect(typeof find.params).toEqual('object'); @@ -62,7 +63,18 @@ describe("@param tag", function() { expect(commit.params[0].description).toEqual('If true make the commit atomic.'); }); + it('When a symbol has a @param tag with no type but a name that indicates a default value or optional type, this infor is copied over to the params property.', function() { + expect(typeof request.params).toEqual('object'); + expect(request.params.length).toEqual(1); + expect(request.params[0].type).toBeUndefined(); + expect(request.params[0].name).toBe('async'); + expect(request.params[0].defaultvalue).toBe('true'); + expect(request.params[0].optional).toBe(true); + expect(request.params[0].description).toEqual('whether to be asynchronous'); + }); + it('When a symbol has an @param tag with no name and a name is given in the code, the doclet has a params property that includes that param with the name from the code.', function() { expect(commit.params[0].name).toEqual('atomic'); }); -}); \ No newline at end of file + +}); From 74555ae863baa26926d1976762ed51f48831d88e Mon Sep 17 00:00:00 2001 From: mathematicalcoffee Date: Tue, 12 Feb 2013 13:57:58 +1000 Subject: [PATCH 09/11] fixed an old comment --- lib/jsdoc/tag.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/jsdoc/tag.js b/lib/jsdoc/tag.js index b7b479cf..ac261585 100644 --- a/lib/jsdoc/tag.js +++ b/lib/jsdoc/tag.js @@ -66,8 +66,9 @@ exports.Tag = function(tagTitle, tagBody, meta) { var tagType = jsdoc.tag.type.parse(this.text, tagDef.canHaveName, tagDef.canHaveType); - // BUG: a tag can *not* have a type but still have optional, nullable, variable, defaultvalue. - // e.g. @param [foo] has name 'foo' and property optional=true but *no type*. + // It is possible for a tag to *not* have a type but still have + // optional or defaultvalue, e.g. '@param [foo]'. + // Although tagType.type.length == 0 we should still copy the other properties. if (tagType.type) { if (tagType.type.length) { this.value.type = { From 59e821aeae6ce82ed87dc7c811da58943841928d Mon Sep 17 00:00:00 2001 From: mathematicalcoffee Date: Thu, 14 Feb 2013 15:28:41 +1000 Subject: [PATCH 10/11] test alterations: some toEqual->toBe, instanceof Array -> Array.isArray, .indexOf() -> .toContain --- test/specs/jsdoc/tag.js | 44 ++++++------- test/specs/jsdoc/tag/dictionary.js | 38 ++++++------ .../specs/jsdoc/tag/dictionary/definitions.js | 4 +- test/specs/jsdoc/tag/type.js | 52 ++++++++-------- .../jsdoc/tag/type/closureCompilerType.js | 34 +++++----- test/specs/jsdoc/tag/validator.js | 4 +- test/specs/tags/paramtag.js | 62 +++++++++---------- 7 files changed, 119 insertions(+), 119 deletions(-) diff --git a/test/specs/jsdoc/tag.js b/test/specs/jsdoc/tag.js index 52d6938a..937a21af 100644 --- a/test/specs/jsdoc/tag.js +++ b/test/specs/jsdoc/tag.js @@ -8,12 +8,12 @@ describe("jsdoc/tag", function() { it('should exist', function() { expect(jsdoc.tag).toBeDefined(); - expect(typeof jsdoc.tag).toEqual('object'); + expect(typeof jsdoc.tag).toBe('object'); }); it('should export a Tag function', function() { expect(jsdoc.tag.Tag).toBeDefined(); - expect(typeof jsdoc.tag.Tag).toEqual('function'); + expect(typeof jsdoc.tag.Tag).toBe('function'); }); describe('Tag', function() { @@ -30,27 +30,27 @@ describe("jsdoc/tag", function() { it("should have a 'originalTitle' property, a string", function() { expect(tagArg.originalTitle).toBeDefined(); - expect(typeof tagArg.originalTitle).toEqual('string'); + expect(typeof tagArg.originalTitle).toBe('string'); }); it("'originalTitle' property should be the initial tag title, trimmed of whitespace", function() { - expect(tagArg.originalTitle).toEqual('arg'); - expect(tagEg.originalTitle).toEqual('example'); + expect(tagArg.originalTitle).toBe('arg'); + expect(tagEg.originalTitle).toBe('example'); }); it("should have a 'title' property, a string", function() { expect(tagArg.title).toBeDefined(); - expect(typeof tagArg.title).toEqual('string'); + expect(typeof tagArg.title).toBe('string'); }); it("'title' property should be the normalised tag title", function() { - expect(tagArg.title).toEqual(jsdoc.dictionary.normalise(tagArg.originalTitle)); - expect(tagEg.title).toEqual(jsdoc.dictionary.normalise(tagEg.originalTitle)); + expect(tagArg.title).toBe(jsdoc.dictionary.normalise(tagArg.originalTitle)); + expect(tagEg.title).toBe(jsdoc.dictionary.normalise(tagEg.originalTitle)); }); it("should have a 'text' property. a string", function () { expect(tagArg.text).toBeDefined(); - expect(typeof tagArg.text).toEqual('string'); + expect(typeof tagArg.text).toBe('string'); }); it("should have a 'value' property", function () { @@ -63,48 +63,48 @@ describe("jsdoc/tag", function() { it("'text' property should be the trimmed tag text, with all leading and trailing space removed unless tagDef.keepsWhitespace", function() { // @example has keepsWhitespace, @param doesn't. // should realy use module:jsdoc/tag~trim here but it's private. - expect(tagArg.text).toEqual(text.replace(/^\s+|\s+$/g, '')); - expect(tagEg.text).toEqual(textEg.replace(/^[\n\r\f]+|[\n\r\f]+$/g, '')); + expect(tagArg.text).toBe(text.replace(/^\s+|\s+$/g, '')); + expect(tagEg.text).toBe(textEg.replace(/^[\n\r\f]+|[\n\r\f]+$/g, '')); }); it("'text' property should have onTagText run on it if it has it.", function() { var def = jsdoc.dictionary.lookUp('type'); expect(def.onTagText).toBeDefined(); - expect(typeof def.onTagText).toEqual('function'); + expect(typeof def.onTagText).toBe('function'); // @type adds {} around the type if necessary. expect(tagType.text).toBeDefined(); - expect(tagType.text).toEqual(def.onTagText('MyType')); + expect(tagType.text).toBe(def.onTagText('MyType')); }); }); describe("'value' property", function() { it("'value' property should equal tag text if tagDef.canHaveType and canHaveName are both false", function() { // @example can't have type or name - expect(typeof tagEg.value).toEqual('string'); - expect(tagEg.value).toEqual(tagEg.text); + expect(typeof tagEg.value).toBe('string'); + expect(tagEg.value).toBe(tagEg.text); }); it("'value' property should be an object if tagDef can have type or name", function () { - expect(typeof tagType.value).toEqual('object'); - expect(typeof tagArg.value).toEqual('object'); + expect(typeof tagType.value).toBe('object'); + expect(typeof tagArg.value).toBe('object'); }); function verifyTagType(tag) { var def = jsdoc.dictionary.lookUp(tag.title); - expect(def).not.toEqual(false); + expect(def).not.toBe(false); var info = jsdoc.type.parse(tag.text, def.canHaveName, def.canHaveType); var props_that_should_be_copied = ['optional', 'nullable', 'variable', 'defaultvalue']; for (var i = 0; i < props_that_should_be_copied.length; ++i) { var prop = props_that_should_be_copied[i]; if (info.hasOwnProperty(prop)) { - expect(tag.value[prop]).toEqual(info[prop]); + expect(tag.value[prop]).toBe(info[prop]); } } if (info.type && info.type.length) { expect(tag.value.type).toBeDefined(); - expect(typeof tag.value.type).toEqual('object'); + expect(typeof tag.value.type).toBe('object'); expect(tag.value.type.names).toBeDefined(); expect(tag.value.type.names).toEqual(info.type); } @@ -120,12 +120,12 @@ describe("jsdoc/tag", function() { expect(tagType.value.description).not.toBeDefined(); expect(tagArg.value.description).toBeDefined(); - expect(tagArg.value.description).toEqual(desc); + expect(tagArg.value.description).toBe(desc); }); it("if the tag can have a name, it should be stored in tag.value.name", function() { expect(tagArg.value.name).toBeDefined(); - expect(tagArg.value.name).toEqual('foo'); + expect(tagArg.value.name).toBe('foo'); expect(tagType.value.name).not.toBeDefined(); }); diff --git a/test/specs/jsdoc/tag/dictionary.js b/test/specs/jsdoc/tag/dictionary.js index 6c0768b9..b6e0544c 100644 --- a/test/specs/jsdoc/tag/dictionary.js +++ b/test/specs/jsdoc/tag/dictionary.js @@ -3,27 +3,27 @@ describe('jsdoc/tag/dictionary', function() { it('should exist', function() { expect(dictionary).toBeDefined(); - expect(typeof dictionary).toEqual('object'); + expect(typeof dictionary).toBe('object'); }); it('should export a defineTag function', function() { expect(dictionary.defineTag).toBeDefined(); - expect(typeof dictionary.defineTag).toEqual('function'); + expect(typeof dictionary.defineTag).toBe('function'); }); it('should export a lookUp function', function() { expect(dictionary.lookUp).toBeDefined(); - expect(typeof dictionary.lookUp).toEqual('function'); + expect(typeof dictionary.lookUp).toBe('function'); }); it('should export a isNamespace function', function() { expect(dictionary.isNamespace).toBeDefined(); - expect(typeof dictionary.isNamespace).toEqual('function'); + expect(typeof dictionary.isNamespace).toBe('function'); }); it('should export a normalise function', function() { expect(dictionary.normalise).toBeDefined(); - expect(typeof dictionary.normalise).toEqual('function'); + expect(typeof dictionary.normalise).toBe('function'); }); // TODO: should really remove this tag from the dictionary after, but how? @@ -40,17 +40,17 @@ describe('jsdoc/tag/dictionary', function() { // Since TagDefinition is private, I'll just test for its properties here. it("returns an object with 'title' property", function() { - expect(typeof def).toEqual('object'); + expect(typeof def).toBe('object'); // how to test? expect(def.title).toBeDefined(); - expect(typeof def.title).toEqual('string'); - expect(def.title).toEqual(dictionary.normalise(tagTitle)); + expect(typeof def.title).toBe('string'); + expect(def.title).toBe(dictionary.normalise(tagTitle)); }); it("returned object has all the tag properties copied over", function() { for (var prop in tagOptions) { if (tagOptions.hasOwnProperty(prop)) { - expect(def[prop]).toEqual(tagOptions[prop]); + expect(def[prop]).toBe(tagOptions[prop]); } } }); @@ -58,41 +58,41 @@ describe('jsdoc/tag/dictionary', function() { describe("lookUp", function() { it("retrieves definition when using the tag's canonical name", function() { - expect(dictionary.lookUp(tagTitle)).toEqual(def); + expect(dictionary.lookUp(tagTitle)).toBe(def); }); it("retrieves definition when using a synonym", function() { - expect(dictionary.lookUp(tagSynonym)).toEqual(def); + expect(dictionary.lookUp(tagSynonym)).toBe(def); }); it("returns FALSE when a tag is not found", function() { - expect(dictionary.lookUp('lkjas1l24jk')).toEqual(false); + expect(dictionary.lookUp('lkjas1l24jk')).toBe(false); }); }); describe("isNamespace", function() { it("returns whether a tag is a namespace when using its canonical name", function() { - expect(dictionary.isNamespace(tagTitle)).toEqual(true); + expect(dictionary.isNamespace(tagTitle)).toBe(true); }); it("returns whether a tag is a namespace when using its synonym", function() { - expect(dictionary.isNamespace(tagSynonym)).toEqual(true); + expect(dictionary.isNamespace(tagSynonym)).toBe(true); }); it("non-existent tags or non-namespace tags should return false", function() { - expect(dictionary.isNamespace('see')).toEqual(false); - expect(dictionary.isNamespace('lkjasd90034')).toEqual(false); + expect(dictionary.isNamespace('see')).toBe(false); + expect(dictionary.isNamespace('lkjasd90034')).toBe(false); }); }); describe("normalise", function() { it("should return the tag's title if it is not a synonym", function() { - expect(dictionary.normalise('FooBar')).toEqual('foobar'); - expect(dictionary.normalise(tagTitle)).toEqual(def.title); + expect(dictionary.normalise('FooBar')).toBe('foobar'); + expect(dictionary.normalise(tagTitle)).toBe(def.title); }); it("should return the canonical name of a tag if the synonym is normalised", function() { - expect(dictionary.normalise(tagSynonym)).toEqual(def.title); + expect(dictionary.normalise(tagSynonym)).toBe(def.title); }); }); }); diff --git a/test/specs/jsdoc/tag/dictionary/definitions.js b/test/specs/jsdoc/tag/dictionary/definitions.js index 831ae626..4abae895 100644 --- a/test/specs/jsdoc/tag/dictionary/definitions.js +++ b/test/specs/jsdoc/tag/dictionary/definitions.js @@ -3,12 +3,12 @@ describe('jsdoc/tag/dictionary/definitions', function() { it('should exist', function() { expect(type).toBeDefined(); - expect(typeof type).toEqual('object'); + expect(typeof type).toBe('object'); }); it('should export a defineTags function', function() { expect(type.defineTags).toBeDefined(); - expect(typeof type.defineTags).toEqual('function'); + expect(typeof type.defineTags).toBe('function'); }); // whole bit of dictionary.defineTags...but it just calls dictionary.defineTag // and if I validate that then the rest is automatically validated? diff --git a/test/specs/jsdoc/tag/type.js b/test/specs/jsdoc/tag/type.js index c9953133..2b430672 100644 --- a/test/specs/jsdoc/tag/type.js +++ b/test/specs/jsdoc/tag/type.js @@ -32,17 +32,17 @@ describe("jsdoc/tag/type", function() { it("should exist", function() { expect(jsdoc.tag.type).toBeDefined(); - expect(typeof jsdoc.tag.type).toEqual("object"); + expect(typeof jsdoc.tag.type).toBe("object"); }); it("should export a getTagInfo function", function() { expect(jsdoc.tag.type.getTagInfo).toBeDefined(); - expect(typeof jsdoc.tag.type.getTagInfo).toEqual("function"); + expect(typeof jsdoc.tag.type.getTagInfo).toBe("function"); }); it("should export a parse function", function() { expect(jsdoc.tag.type.parse).toBeDefined(); - expect(typeof jsdoc.tag.type.parse).toEqual("function"); + expect(typeof jsdoc.tag.type.parse).toBe("function"); }); describe("getTagInfo", function() { @@ -56,27 +56,27 @@ describe("jsdoc/tag/type", function() { it("should not extract a name or type if canHaveName and canHaveType are not set", function() { var desc = "{number} foo The foo parameter."; var info = jsdoc.tag.type.getTagInfo(desc); - expect(info.type).toEqual(''); - expect(info.name).toEqual(''); - expect(info.text).toEqual(desc); + expect(info.type).toBe(''); + expect(info.name).toBe(''); + expect(info.text).toBe(desc); }); it("should extract a name, but not a type, if canHaveName === true and canHaveType === false", function() { var name = "bar"; var desc = "The bar parameter."; var info = jsdoc.tag.type.getTagInfo( buildText(null, name, desc), true, false ); - expect(info.type).toEqual(''); - expect(info.name).toEqual(name); - expect(info.text).toEqual(desc); + expect(info.type).toBe(''); + expect(info.name).toBe(name); + expect(info.text).toBe(desc); }); it("should extract a type, but not a name, if canHaveName === false and canHaveType === true", function() { var type = "boolean"; var desc = "Set to true on alternate Thursdays."; var info = jsdoc.tag.type.getTagInfo( buildText(type, null, desc), false, true ); - expect(info.type).toEqual(type); - expect(info.name).toEqual(''); - expect(info.text).toEqual(desc); + expect(info.type).toBe(type); + expect(info.name).toBe(''); + expect(info.text).toBe(desc); }); it("should extract a name and type if canHaveName and canHaveType are true", function() { @@ -84,32 +84,32 @@ describe("jsdoc/tag/type", function() { var name = "baz"; var desc = "The baz parameter."; var info = jsdoc.tag.type.getTagInfo( buildText(type, name, desc), true, true ); - expect(info.type).toEqual(type); - expect(info.name).toEqual(name); - expect(info.text).toEqual(desc); + expect(info.type).toBe(type); + expect(info.name).toBe(name); + expect(info.text).toBe(desc); }); it("should work with JSDoc-style optional parameters", function() { var name = "[qux]"; var desc = "The qux parameter."; var info = jsdoc.tag.type.getTagInfo( buildText(null, name, desc), true, false ); - expect(info.name).toEqual(name); - expect(info.text).toEqual(desc); + expect(info.name).toBe(name); + expect(info.text).toBe(desc); name = "[ qux ]"; info = jsdoc.tag.type.getTagInfo( buildText(null, name, desc), true, false ); - expect(info.name).toEqual(name); - expect(info.text).toEqual(desc); + expect(info.name).toBe(name); + expect(info.text).toBe(desc); name = "[qux=hooray]"; info = jsdoc.tag.type.getTagInfo( buildText(null, name, desc), true, false ); - expect(info.name).toEqual(name); - expect(info.text).toEqual(desc); + expect(info.name).toBe(name); + expect(info.text).toBe(desc); name = "[ qux = hooray ]"; info = jsdoc.tag.type.getTagInfo( buildText(null, name, desc), true, false ); - expect(info.name).toEqual(name); - expect(info.text).toEqual(desc); + expect(info.name).toBe(name); + expect(info.text).toBe(desc); }); }); @@ -117,15 +117,15 @@ describe("jsdoc/tag/type", function() { it("should report optional types correctly no matter which syntax we use", function() { var desc = "{string} [foo]"; var info = jsdoc.tag.type.parse(desc, true, true); - expect(info.optional).toEqual(true); + expect(info.optional).toBe(true); desc = "{string=} [foo]"; info = jsdoc.tag.type.parse(desc, true, true); - expect(info.optional).toEqual(true); + expect(info.optional).toBe(true); desc = "[foo]"; info = jsdoc.tag.type.parse(desc, true, true); - expect(info.optional).toEqual(true); + expect(info.optional).toBe(true); }); it("should return the types as an array", function() { diff --git a/test/specs/jsdoc/tag/type/closureCompilerType.js b/test/specs/jsdoc/tag/type/closureCompilerType.js index d6ae73c2..ec43ddef 100644 --- a/test/specs/jsdoc/tag/type/closureCompilerType.js +++ b/test/specs/jsdoc/tag/type/closureCompilerType.js @@ -4,51 +4,51 @@ describe('jsdoc/tag/type/closureCompilerType', function() { it('should exist', function() { expect(type).toBeDefined(); - expect(typeof type).toEqual('object'); + expect(typeof type).toBe('object'); }); it('should export a parse function', function() { expect(type.parse).toBeDefined(); - expect(typeof type.parse).toEqual('function'); + expect(typeof type.parse).toBe('function'); }); describe('parse', function() { it('should parse optional types', function() { var info = type.parse({type: 'Asdf.Foobar='}); - expect(info.type).toEqual('Asdf.Foobar'); - expect(info.optional).toEqual(true); + expect(info.type).toBe('Asdf.Foobar'); + expect(info.optional).toBe(true); }); it('should parse nullable types', function() { var info = type.parse({type: '?Asdf.Foobar'}); - expect(info.type).toEqual('Asdf.Foobar'); - expect(info.nullable).toEqual(true); + expect(info.type).toBe('Asdf.Foobar'); + expect(info.nullable).toBe(true); }); it('should parse non-nullable types', function() { var info = type.parse({type: '!Asdf.Foobar'}); - expect(info.type).toEqual('Asdf.Foobar'); - expect(info.nullable).toEqual(false); + expect(info.type).toBe('Asdf.Foobar'); + expect(info.nullable).toBe(false); }); it('should parse variable types', function() { var info = type.parse({type: '...Fdsa.Baz'}); - expect(info.type).toEqual('Fdsa.Baz'); - expect(info.variable).toEqual(true); + expect(info.type).toBe('Fdsa.Baz'); + expect(info.variable).toBe(true); }); it('should correctly parse types that are both optional and nullable', function() { var info = type.parse( {type: '?string='} ); - expect(info.type).toEqual('string'); - expect(info.optional).toEqual(true); - expect(info.nullable).toEqual(true); + expect(info.type).toBe('string'); + expect(info.optional).toBe(true); + expect(info.nullable).toBe(true); }); it('should correctly parse types that are both optional and variable', function() { var info = type.parse( {type: '...string='} ); - expect(info.type).toEqual('string'); - expect(info.optional).toEqual(true); - expect(info.variable).toEqual(true); + expect(info.type).toBe('string'); + expect(info.optional).toBe(true); + expect(info.variable).toBe(true); }); it("should only change the `type`, `optional`, `nullable` and `variable` properties", function() { @@ -70,7 +70,7 @@ describe('jsdoc/tag/type/closureCompilerType', function() { expect( info[key] ).not.toEqual( obj[key] ); } else { - expect( info[key] ).toEqual( obj[key] ); + expect( info[key] ).toBe( obj[key] ); } } } diff --git a/test/specs/jsdoc/tag/validator.js b/test/specs/jsdoc/tag/validator.js index 1a5175e2..60ed3b4f 100644 --- a/test/specs/jsdoc/tag/validator.js +++ b/test/specs/jsdoc/tag/validator.js @@ -4,12 +4,12 @@ describe('jsdoc/tag/validator', function() { it('should exist', function() { expect(validator).toBeDefined(); - expect(typeof validator).toEqual('object'); + expect(typeof validator).toBe('object'); }); it('should export a validate function', function() { expect(validator.validate).toBeDefined(); - expect(typeof validator.validate).toEqual('function'); + expect(typeof validator.validate).toBe('function'); }); // Note: various Error classes are private so we just test whether *any* diff --git a/test/specs/tags/paramtag.js b/test/specs/tags/paramtag.js index b0e1046c..05cb3aa3 100644 --- a/test/specs/tags/paramtag.js +++ b/test/specs/tags/paramtag.js @@ -10,71 +10,71 @@ describe("@param tag", function() { request = docSet.getByLongname('request')[0]; it('When a symbol has an @param tag with a type before the name, the doclet has a params property that includes that param.', function() { - expect(typeof find.params).toEqual('object'); - expect(find.params.length).toEqual(1); - expect(find.params[0].type.names.join(', ')).toEqual('String, Array'); - expect(find.params[0].name).toEqual('targetName'); - expect(find.params[0].description).toEqual('The name (or names) of what to find.'); + expect(typeof find.params).toBe('object'); + expect(find.params.length).toBe(1); + expect(find.params[0].type.names.join(', ')).toBe('String, Array'); + expect(find.params[0].name).toBe('targetName'); + expect(find.params[0].description).toBe('The name (or names) of what to find.'); }); it('When a symbol has an @param tag with only a type and name, the doclet has a params property that includes that param.', function() { - expect(typeof bind.params).toEqual('object'); - expect(bind.params.length).toEqual(1); - expect(bind.params[0].type.names.join(', ')).toEqual('function'); - expect(bind.params[0].name).toEqual('callback'); + expect(typeof bind.params).toBe('object'); + expect(bind.params.length).toBe(1); + expect(bind.params[0].type.names.join(', ')).toBe('function'); + expect(bind.params[0].name).toBe('callback'); expect(bind.params[0].description).toBeUndefined(); }); it('When a symbol has an @param tag with only a type, the doclet has a params property that includes that param.', function() { - expect(typeof unbind.params).toEqual('object'); - expect(unbind.params.length).toEqual(1); - expect(unbind.params[0].type.names.join(', ')).toEqual('function'); + expect(typeof unbind.params).toBe('object'); + expect(unbind.params.length).toBe(1); + expect(unbind.params[0].type.names.join(', ')).toBe('function'); expect(unbind.params[0].description).toBeUndefined(); }); it('When a symbol has an @param tag with no type, the doclet has a params property that includes that param.', function() { - expect(typeof getElement.params).toEqual('object'); - expect(getElement.params.length).toEqual(1); + expect(typeof getElement.params).toBe('object'); + expect(getElement.params.length).toBe(1); expect(getElement.params[0].type).toBeUndefined(); - expect(getElement.params[0].name).toEqual('id'); - expect(getElement.params[0].description).toEqual('The id of the element.'); + expect(getElement.params[0].name).toBe('id'); + expect(getElement.params[0].description).toBe('The id of the element.'); }); it('When a symbol has an @param tag with a non-alpha name like "...", the doclet has a params property that includes that param.', function() { - expect(typeof combine.params).toEqual('object'); - expect(combine.params.length).toEqual(1); + expect(typeof combine.params).toBe('object'); + expect(combine.params.length).toBe(1); expect(combine.params[0].type).toBeUndefined(); - expect(combine.params[0].name).toEqual('...'); - expect(combine.params[0].description).toEqual('Two or more elements.'); + expect(combine.params[0].name).toBe('...'); + expect(combine.params[0].description).toBe('Two or more elements.'); }); it('When a symbol has an @param tag with name followed by a dash, the doclet has a params property that includes that param.', function() { - expect(typeof split.params).toEqual('object'); - expect(split.params.length).toEqual(1); + expect(typeof split.params).toBe('object'); + expect(split.params.length).toBe(1); expect(split.params[0].type).toBeUndefined(); - expect(split.params[0].name).toEqual('delimiter'); - expect(split.params[0].description).toEqual('What to split on.'); + expect(split.params[0].name).toBe('delimiter'); + expect(split.params[0].description).toBe('What to split on.'); }); it('When a symbol has an @param tag with no name or type, the doclet has a params property that includes that param.', function() { - expect(typeof commit.params).toEqual('object'); - expect(commit.params.length).toEqual(1); + expect(typeof commit.params).toBe('object'); + expect(commit.params.length).toBe(1); expect(commit.params[0].type).toBeUndefined(); - expect(commit.params[0].description).toEqual('If true make the commit atomic.'); + expect(commit.params[0].description).toBe('If true make the commit atomic.'); }); it('When a symbol has a @param tag with no type but a name that indicates a default value or optional type, this infor is copied over to the params property.', function() { - expect(typeof request.params).toEqual('object'); - expect(request.params.length).toEqual(1); + expect(typeof request.params).toBe('object'); + expect(request.params.length).toBe(1); expect(request.params[0].type).toBeUndefined(); expect(request.params[0].name).toBe('async'); expect(request.params[0].defaultvalue).toBe('true'); expect(request.params[0].optional).toBe(true); - expect(request.params[0].description).toEqual('whether to be asynchronous'); + expect(request.params[0].description).toBe('whether to be asynchronous'); }); it('When a symbol has an @param tag with no name and a name is given in the code, the doclet has a params property that includes that param with the name from the code.', function() { - expect(commit.params[0].name).toEqual('atomic'); + expect(commit.params[0].name).toBe('atomic'); }); }); From 245cce82023aa37267e656a1990fbb9cd991e423 Mon Sep 17 00:00:00 2001 From: mathematicalcoffee Date: Tue, 26 Feb 2013 14:01:21 +1000 Subject: [PATCH 11/11] switch to spyOn(console, 'log'). paramtag: fixed typo in test text --- test/specs/jsdoc/tag.js | 6 ++---- test/specs/jsdoc/tag/validator.js | 4 +--- test/specs/tags/paramtag.js | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/test/specs/jsdoc/tag.js b/test/specs/jsdoc/tag.js index 937a21af..a324a9c3 100644 --- a/test/specs/jsdoc/tag.js +++ b/test/specs/jsdoc/tag.js @@ -134,8 +134,7 @@ describe("jsdoc/tag", function() { // further tests for this sort of thing are in jsdoc/tag/validator.js tests. describe("tag validating", function() { /*jshint evil: true */ - var lenient = !!env.opts.lenient, - log = eval(console.log); + var lenient = !!env.opts.lenient; function badTag() { var tag = new jsdoc.tag.Tag("name"); @@ -144,7 +143,6 @@ describe("jsdoc/tag", function() { afterEach(function() { env.opts.lenient = lenient; - console.log = log; }); it("throws an exception for bad tags if the lenient option is not enabled", function() { @@ -154,7 +152,7 @@ describe("jsdoc/tag", function() { }); it("doesn't throw an exception for bad tags if the lenient option is enabled", function() { - console.log = function() {}; + spyOn(console, 'log'); env.opts.lenient = true; expect(badTag).not.toThrow(); diff --git a/test/specs/jsdoc/tag/validator.js b/test/specs/jsdoc/tag/validator.js index 60ed3b4f..56070edb 100644 --- a/test/specs/jsdoc/tag/validator.js +++ b/test/specs/jsdoc/tag/validator.js @@ -17,7 +17,6 @@ describe('jsdoc/tag/validator', function() { describe('validate', function() { var lenient = !!env.opts.lenient, allowUnknown = !!env.conf.tags.allowUnknownTags, - log = eval(console.log), badTag = {title: 'lkjasdlkjfb'}, meta = {filename: 'asdf.js', lineno: 1}, goodTag = new tag.Tag('name', 'MyDocletName', meta), // mustHaveValue @@ -28,13 +27,12 @@ describe('jsdoc/tag/validator', function() { } beforeEach(function() { - console.log = function() {}; + spyOn(console, 'log'); }); afterEach(function() { env.opts.lenient = lenient; env.conf.tags.allowUnknownTags = allowUnknown; - console.log = log; }); it("throws an error if the tag is not in the dictionary, conf.tags.allowUnknownTags is false and lenient is false", function() { diff --git a/test/specs/tags/paramtag.js b/test/specs/tags/paramtag.js index 05cb3aa3..d3d71536 100644 --- a/test/specs/tags/paramtag.js +++ b/test/specs/tags/paramtag.js @@ -63,7 +63,7 @@ describe("@param tag", function() { expect(commit.params[0].description).toBe('If true make the commit atomic.'); }); - it('When a symbol has a @param tag with no type but a name that indicates a default value or optional type, this infor is copied over to the params property.', function() { + it('When a symbol has a @param tag with no type but a name that indicates a default value or optional type, this is copied over to the params property.', function() { expect(typeof request.params).toBe('object'); expect(request.params.length).toBe(1); expect(request.params[0].type).toBeUndefined();