From 5b5e4a38e5a2cd933d5e6734d4e413f0a62a05ec Mon Sep 17 00:00:00 2001 From: mathematicalcoffee Date: Mon, 4 Feb 2013 16:56:04 +1000 Subject: [PATCH] Made Tutorial#addChild and Tutorial#removeChild modify the child's parent (as well as the parent's children property) --- lib/jsdoc/tutorial.js | 36 ++++++++++++++++----- test/specs/jsdoc/tutorial.js | 63 ++++++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 10 deletions(-) diff --git a/lib/jsdoc/tutorial.js b/lib/jsdoc/tutorial.js index 28f794db..81ef5b5b 100644 --- a/lib/jsdoc/tutorial.js +++ b/lib/jsdoc/tutorial.js @@ -6,6 +6,27 @@ var markdown = require('jsdoc/util/markdown'); +/** Removes child tutorial from the parent. Does *not* unset child.parent though. + @param {Tutorial} parent - parent tutorial. + @param {Tutorial} child - Old child. + @private + */ +function removeChild(parent, child) { + var index = parent.children.indexOf(child); + if (index != -1) { + parent.children.splice(index, 1); + } +} + +/** Adds a child to the parent tutorial. Does *not* set child.parent though. + @param {Tutorial} parent - parent tutorial. + @param {Tutorial} child - New child. + @private + */ +function addChild(parent, child) { + parent.children.push(child); +} + /** @module jsdoc/tutorial */ @@ -28,33 +49,32 @@ exports.Tutorial = function(name, content, type) { }; /** Moves children from current parent to different one. - @param {Tutorial} parent - New parent. + @param {?Tutorial} parent - New parent. If null, the tutorial has no parent. */ exports.Tutorial.prototype.setParent = function(parent) { // removes node from old parent if (this.parent) { - this.parent.removeChild(this); + removeChild(this.parent, this); } this.parent = parent; - this.parent.addChild(this); + if (parent) { + addChild(parent, this); + } }; /** Removes children from current node. @param {Tutorial} child - Old child. */ exports.Tutorial.prototype.removeChild = function(child) { - var index = this.children.indexOf(child); - if (index != -1) { - this.children.splice(index, 1); - } + child.setParent(null); }; /** Adds new children to current node. @param {Tutorial} child - New child. */ exports.Tutorial.prototype.addChild = function(child) { - this.children.push(child); + child.setParent(this); }; /** Prepares source. diff --git a/test/specs/jsdoc/tutorial.js b/test/specs/jsdoc/tutorial.js index 92f215ae..7824b1fb 100644 --- a/test/specs/jsdoc/tutorial.js +++ b/test/specs/jsdoc/tutorial.js @@ -110,11 +110,19 @@ describe("jsdoc/tutorial", function() { expect(par2.children.indexOf(tute)).not.toEqual(-1); expect(par.children.indexOf(tute)).toEqual(-1); }); + + it("calling setParent with a null parent unsets the child's parent and removes the child from its previous parent", function() { + expect(par2.children.indexOf(tute)).not.toEqual(-1); + tute.setParent(null); + + expect(tute.parent).toEqual(null); + expect(par2.children.indexOf(tute)).toEqual(-1); + }); }); describe("addChild", function() { - // currently tute is unparented. it("adding a child tutorial adds the child to the parent's 'children' property", function() { + tute.setParent(null); var n = par.children.length; par.addChild(tute); @@ -122,13 +130,27 @@ describe("jsdoc/tutorial", function() { expect(par.children.length).toEqual(n + 1); expect(par.children.indexOf(tute)).not.toEqual(-1); }); + + it("adding a child tutorial sets the child's parent to to the parent tutorial", function() { + expect(tute.parent).toEqual(par); + }); + + it("adding a child tutorial removes the child from its old parent", function() { + // tue is currently owned by par; we reparent it to par2 + expect(tute.parent).toEqual(par); + par2.addChild(tute); + + expect(tute.parent).toEqual(par2); + expect(par.children.indexOf(tute)).toEqual(-1); + expect(par2.children.indexOf(tute)).not.toEqual(-1); + }); }); describe("removeChild", function() { - // currently tute is unparented. function removeChild() { par2.removeChild(par); } + it("removing a tutorial that is not a child silently passes", function() { var n = par2.children.length; expect(removeChild).not.toThrow(); @@ -136,11 +158,48 @@ describe("jsdoc/tutorial", function() { }); it("removing a child removes the child from the parent's 'children' property", function() { + tute.setParent(par2); expect(par2.children.length).toEqual(1); + par2.removeChild(tute); + expect(par2.children.indexOf(tute)).toEqual(-1); expect(par2.children.length).toEqual(0); }); + + it("removing a child unsets the child's 'parent' property", function() { + expect(tute.parent).toEqual(null); + }); + }); + + describe("various inheritance tests with addChild, setParent and removeChild", function() { + it("parenting and unparenting via addChild, setParent and removeChild makes sure inheritance is set accordingly", function() { + // unparent everything. + tute.setParent(null); + par.setParent(null); + par2.setParent(null); + + // let tute belong to par + tute.setParent(par); + expect(tute.parent).toEqual(par); + expect(par2.children.length).toEqual(0); + expect(par.children.length).toEqual(1); + expect(par.children[0]).toEqual(tute); + + // addChild tute to par2. its parent should now be par2, and + // it can't be the child of two parents + par2.addChild(tute); + expect(tute.parent).toEqual(par2); + expect(par.children.length).toEqual(0); + expect(par2.children.length).toEqual(1); + expect(par2.children[0]).toEqual(tute); + + // removeChild tute from par2. tute should now be unparented. + par2.removeChild(tute); + expect(tute.parent).toEqual(null); + expect(par.children.length).toEqual(0); + expect(par2.children.length).toEqual(0); + }); }); describe("parse", function() {