From bdf3daac3903102e772f96bca511534b1e84dac3 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Tue, 21 May 2013 09:29:36 +0200 Subject: [PATCH] GraphViewer: Added JSLint to my karma script and JSLinted everythign again --- .../admin/js/graphViewer/graph/JSONAdapter.js | 2 +- .../js/graphViewer/graph/arangoAdapter.js | 33 ++- .../admin/js/graphViewer/graph/nodeReducer.js | 46 ++-- .../jasmine_test/helper/commMock.js | 2 +- .../specAdapter/arangoAdapterSpec.js | 196 ++++++++++-------- .../jasmine_test/specJSLint/jsLintSpec.js | 130 ++++++------ 6 files changed, 236 insertions(+), 173 deletions(-) diff --git a/html/admin/js/graphViewer/graph/JSONAdapter.js b/html/admin/js/graphViewer/graph/JSONAdapter.js index c54b38b89d..d9a9d8e2a9 100644 --- a/html/admin/js/graphViewer/graph/JSONAdapter.js +++ b/html/admin/js/graphViewer/graph/JSONAdapter.js @@ -155,7 +155,7 @@ function JSONAdapter(jsonPath, nodes, edges, width, height) { throw "Sorry this adapter is read-only"; }; - self.setNodeLimit = function (limit) { + self.setNodeLimit = function (limit, callback) { }; diff --git a/html/admin/js/graphViewer/graph/arangoAdapter.js b/html/admin/js/graphViewer/graph/arangoAdapter.js index a47a2f058c..93c5cc3501 100644 --- a/html/admin/js/graphViewer/graph/arangoAdapter.js +++ b/html/admin/js/graphViewer/graph/arangoAdapter.js @@ -1,5 +1,6 @@ /*jslint indent: 2, nomen: true, maxlen: 100, white: true plusplus: true */ /*global $, d3, _, console, document*/ +/*global NodeReducer*/ //////////////////////////////////////////////////////////////////////////////// /// @brief Graph functionality /// @@ -27,7 +28,6 @@ /// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -//function ArangoAdapter(arangodb, nodes, edges, nodeCollection, edgeCollection, width, height) { function ArangoAdapter(nodes, edges, config) { "use strict"; @@ -52,6 +52,7 @@ function ArangoAdapter(nodes, edges, config) { initialY = {}, api = {}, queries = {}, + cachedCommunities = {}, nodeCollection, edgeCollection, limit, @@ -254,6 +255,25 @@ function ArangoAdapter(nodes, edges, config) { } }); }, + + collapseCommunity = function (community) { + var commId = "community_1", + commNode = { + _id: commId, + x: 1, + y: 1 + }, + nodesToRemove = _.map(community, function(id) { + return findNode(id); + }); + cachedCommunities[commId] = nodesToRemove; + + _.each(nodesToRemove, function(n) { + removeNode(n); + removeEdgesForNode(n); + }); + nodes.push(commNode); + }, parseResultOfTraversal = function (result, callback) { result = result[0]; @@ -268,9 +288,11 @@ function ArangoAdapter(nodes, edges, config) { }); }); if (callback) { - var n = insertNode(result[0].vertex); + var n = insertNode(result[0].vertex), + com; if (limit < nodes.length) { - reducer.getCommunity(limit, n); + com = reducer.getCommunity(limit, n); + collapseCommunity(com); } callback(n); } @@ -350,7 +372,7 @@ function ArangoAdapter(nodes, edges, config) { + "paths: true" + "})"; queries.traversalByAttribute = function(attr) { - return "FOR n IN @@nodes " + return "FOR n IN @@nodes" + " FILTER n." + attr + " == @value" + " RETURN TRAVERSAL(" @@ -542,7 +564,8 @@ function ArangoAdapter(nodes, edges, config) { self.setNodeLimit = function (pLimit, callback) { limit = pLimit; if (limit < nodes.length) { - reducer.getCommunity(limit); + var com = reducer.getCommunity(limit); + collapseCommunity(com); if (callback !== undefined) { callback(); } diff --git a/html/admin/js/graphViewer/graph/nodeReducer.js b/html/admin/js/graphViewer/graph/nodeReducer.js index 53b5e5e884..839bb36a03 100644 --- a/html/admin/js/graphViewer/graph/nodeReducer.js +++ b/html/admin/js/graphViewer/graph/nodeReducer.js @@ -146,12 +146,13 @@ function NodeReducer(nodes, edges) { var lID = largest.lID, sID = largest.sID; _.each(nodes, function (n) { - var id = n._id; + var id = n._id, + c1, c2; if (id == sID || id == lID) { return null; } - var c1 = getDQValue(dQ, id, sID), - c2 = getDQValue(dQ, id, lID); + c1 = getDQValue(dQ, id, sID); + c2 = getDQValue(dQ, id, lID); if (c1 !== undefined) { if (c2 !== undefined) { setDQValue(dQ, heap, id, lID, c1 + c2); @@ -193,12 +194,22 @@ function NodeReducer(nodes, edges) { minDist = function(dist) { return function(a) { return dist[a]; - } + }; }, dijkstra = function(sID) { var dist = {}, - toDo, next, neigh; + toDo, next, neigh, + filterNotNext = function(e) { + return e !== next; + }, + computeNeighbours = function(v) { + if (_.contains(toDo, v)) { + if (dist[v] > dist[next] + 1) { + dist[v] = dist[next] + 1; + } + } + }; toDo = _.pluck(nodes, "_id"); _.each(toDo, function(n) { @@ -210,15 +221,9 @@ function NodeReducer(nodes, edges) { if (next === Number.POSITIVE_INFINITY) { break; } - toDo = toDo.filter(function(e) {return e !== next}); + toDo = toDo.filter(filterNotNext); neigh = neighbors(next); - _.each(neigh, function(v) { - if (_.contains(toDo, v)) { - if (dist[v] > dist[next] + 1) { - dist[v] = dist[next] + 1; - } - } - }); + _.each(neigh, computeNeighbours); } return dist; }, @@ -285,22 +290,15 @@ function NodeReducer(nodes, edges) { throw "Load some nodes first."; } populateValues(dQ, a, heap); - var max = 0; - while (communityDetectionStep(dQ, a, heap, coms)) { - // InfiniteLoopCheck should be removed! - max++; - if (max > 100) { - break; - } - } + while (communityDetectionStep(dQ, a, heap, coms)) {} res = _.pluck(_.values(coms), "com"); if (focus !== undefined) { dist = floatDist(focus._id); - res = res.filter(function(e) {return !_.contains(e, focus._id)}); - res = res.filter(function(e) {return e.length > 1}); + res = res.filter(function(e) {return !_.contains(e, focus._id);}); + res = res.filter(function(e) {return e.length > 1;}); res.sort(sortByDistance); } else { - res = res.filter(function(e) {return e.length > 1}); + res = res.filter(function(e) {return e.length > 1;}); } return res[0]; }; diff --git a/html/admin/js/graphViewer/jasmine_test/helper/commMock.js b/html/admin/js/graphViewer/jasmine_test/helper/commMock.js index c11b7fc07a..bcad5bbde7 100644 --- a/html/admin/js/graphViewer/jasmine_test/helper/commMock.js +++ b/html/admin/js/graphViewer/jasmine_test/helper/commMock.js @@ -1,5 +1,5 @@ /*jslint indent: 2, nomen: true, maxlen: 100, white: true plusplus: true */ -/*global document, window*/ +/*global document, window, d3*/ //////////////////////////////////////////////////////////////////////////////// /// @brief Graph functionality diff --git a/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterSpec.js b/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterSpec.js index 2692f2a5c3..bf3c65f866 100644 --- a/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterSpec.js +++ b/html/admin/js/graphViewer/jasmine_test/specAdapter/arangoAdapterSpec.js @@ -263,25 +263,25 @@ describe('setup correctly', function() { - var travQ, - filterQ, - childQ, - travVars, - filterVars, + var traversalQuery, + filterQuery, + childrenQuery, loadGraph, requests; beforeEach(function() { - var self = this; + var self = this, + host = window.location.protocol + "//" + window.location.host, + apibase = host + "/_api/", + apiCursor = apibase + 'cursor'; self.fakeReducerRequest = function() {}; spyOn(window, "NodeReducer").andCallFake(function(v, e) { return { getCommunity: function(limit, focus) { if (focus !== undefined) { - self.fakeReducerRequest(limit, focus); - } else { - self.fakeReducerRequest(limit); + return self.fakeReducerRequest(limit, focus); } + return self.fakeReducerRequest(limit); } }; }); @@ -295,28 +295,50 @@ height: 40 } ); - travQ = '{"query":"RETURN TRAVERSAL(@@nodes, @@edges, @id, \\"outbound\\", {strategy: \\"depthfirst\\",maxDepth: 1,paths: true})"'; - filterQ = '{"query":"FOR n IN @@nodes FILTER n.id == @value RETURN TRAVERSAL(@@nodes, @@edges, n._id, \\"outbound\\", {strategy: \\"depthfirst\\",maxDepth: 1,paths: true})"'; - childQ = '{"query":"FOR u IN @@nodes FILTER u._id == @id LET g = ( FOR l in @@edges FILTER l._from == u._id RETURN 1 ) RETURN length(g)"'; - var host = window.location.protocol + "//" + window.location.host, - apibase = host + "/_api/", - apiCursor = apibase + 'cursor'; - travVars = function(id, nods, edgs) { - return '"bindVars":{"id":"' + id + '","@nodes":"' + nods + '","@edges":"' + edgs + '"}}'; + traversalQuery = function(id, nods, edgs) { + return JSON.stringify({ + query: "RETURN TRAVERSAL(@@nodes, @@edges, @id, \"outbound\"," + + " {strategy: \"depthfirst\",maxDepth: 1,paths: true})", + bindVars: { + id: id, + "@nodes": nods, + "@edges": edgs + } + }); }; - filterVars = function(v, nods, edgs) { - return '"bindVars":{"value":' + v + ',"@nodes":"' + nods + '","@edges":"' + edgs + '"}}'; + filterQuery = function(v, nods, edgs) { + return JSON.stringify({ + query: "FOR n IN @@nodes FILTER n.id == @value" + + " RETURN TRAVERSAL(@@nodes, @@edges, n._id, \"outbound\"," + + " {strategy: \"depthfirst\",maxDepth: 1,paths: true})", + bindVars: { + value: v, + "@nodes": nods, + "@edges": edgs + } + }); }; - + childrenQuery = function(id, nods, edgs) { + return JSON.stringify({ + query: "FOR u IN @@nodes FILTER u._id == @id" + + " LET g = ( FOR l in @@edges FILTER l._from == u._id RETURN 1 )" + + " RETURN length(g)", + bindVars: { + id: id, + "@nodes": nods, + "@edges": edgs + } + }); + }; loadGraph = function(vars) { - var nid = vars["id"]; - var ncol = vars["@nodes"]; - var ecol = vars["@edges"]; - var res = []; - var inner = []; + var nid = vars.id, + ncol = vars["@nodes"], + ecol = vars["@edges"], + res = [], + inner = [], + first = {}, + node1 = readNode(ncol, nid); res.push(inner); - var first = {}; - var node1 = readNode(ncol, nid); first.vertex = node1; first.path = { edges: [], @@ -365,7 +387,7 @@ patch: function(id, data) { return $.extend(base, {url: write + id, type: "PUT", data: JSON.stringify(data)}); }, - delete: function(id) { + del: function(id) { return $.extend(base, {url: write + id, type: "DELETE"}); } }; @@ -387,7 +409,7 @@ type: "POST", data: JSON.stringify(data) }); - }, + } }; }; }); @@ -428,7 +450,7 @@ existNodes([c0, c1, c2, c3, c4]); expect(nodes.length).toEqual(5); expect($.ajax).toHaveBeenCalledWith( - requests.cursor(travQ + ',' + travVars(c0, nodesCollection, edgesCollection)) + requests.cursor(traversalQuery(c0, nodesCollection, edgesCollection)) ); }); }); @@ -442,7 +464,7 @@ spyOn($, "ajax").andCallFake(function(request) { var vars = JSON.parse(request.data).bindVars; if (vars !== undefined) { - vars["id"] = c0; + vars.id = c0; request.success({result: loadGraph(vars)}); } }); @@ -471,7 +493,7 @@ existNodes([c0, c1, c2, c3, c4]); expect(nodes.length).toEqual(5); expect($.ajax).toHaveBeenCalledWith( - requests.cursor(filterQ + ',' + filterVars("0", nodesCollection, edgesCollection)) + requests.cursor(filterQuery(0, nodesCollection, edgesCollection)) ); }); }); @@ -499,7 +521,7 @@ runs(function() { expect(children).toEqual(4); expect($.ajax).toHaveBeenCalledWith( - requests.cursor(childQ + ',' + travVars(c0, nodesCollection, edgesCollection)) + requests.cursor(childrenQuery(c0, nodesCollection, edgesCollection)) ); }); }); @@ -554,7 +576,7 @@ label: "knows" }); expect($.ajax).toHaveBeenCalledWith( - requests.cursor(travQ + ',' + travVars(c0, nodesCollection, edgesCollection)) + requests.cursor(traversalQuery(c0, nodesCollection, edgesCollection)) ); }); @@ -593,7 +615,7 @@ existNodes([c0, c1]); expect(nodes.length).toEqual(2); expect($.ajax).toHaveBeenCalledWith( - requests.cursor(travQ + ',' + travVars(c0, altNodesCollection, altEdgesCollection)) + requests.cursor(traversalQuery(c0, altNodesCollection, altEdgesCollection)) ); callbackCheck = false; @@ -754,7 +776,7 @@ existNodes([c0, c1, c2, c3, c4, c5, c6, c7]); expect(nodes.length).toEqual(8); expect($.ajax).toHaveBeenCalledWith( - requests.cursor(travQ + ',' + travVars(c1, nodesCollection, edgesCollection)) + requests.cursor(traversalQuery(c1, nodesCollection, edgesCollection)) ); }); }); @@ -820,7 +842,7 @@ runs(function() { expect($.ajax).toHaveBeenCalledWith( - requests.node(edgesCollection).delete(toDelete._id) + requests.node(edgesCollection).del(toDelete._id) ); notExistEdge(c0, c4); }); @@ -861,29 +883,6 @@ }); }); - - it('should render a reduced set of nodes if too many nodes are added', function() { - runs(function() { - adapter.setNodeLimit(6); - spyOn(this, "fakeReducerRequest").andCallFake(function() { - return [0, 1, 2, 3]; - }); - adapter.loadNodeFromTreeById(c1, checkCallbackFunction); - }); - - waitsFor(function() { - return callbackCheck; - }); - - runs(function() { - notExistNodes([c0, c1, c2, c3]); - existNodes([c4, c5, c6, c7]); - expect(nodes.length).toEqual(5); - - }); - - }); - it('should not trigger the reducer if the limit is set large enough', function() { spyOn(this, "fakeReducerRequest"); adapter.setNodeLimit(10); @@ -897,26 +896,59 @@ expect(this.fakeReducerRequest).toHaveBeenCalledWith(2); }); - it('should reshape all objects if limit is set too small', function() { - var called = false; - var callback = function() { - called = true; - }; - spyOn(this, "fakeReducerRequest").andCallFake(function() { - return [0, 1, 2]; + + describe('checking community nodes', function() { + + it('should create a community node if limit is set too small', function() { + var called = false, + callback = function() { + called = true; + }; + spyOn(this, "fakeReducerRequest").andCallFake(function() { + return [c0, c1, c2]; + }); + adapter.setNodeLimit(2, callback); + + notExistNodes([c0, c1, c2]); + existNode("community_1"); + existNodes([c3]); + expect(nodes.length).toEqual(2); + existEdge("community_1", c3); + expect(edges.length).toEqual(1); + + expect(called).toBeTruthy(); }); - adapter.setNodeLimit(2, callback); - notExistNodes([c0, c1, c2]); - existNodes([c3]); - expect(nodes.length).toEqual(2); + it('should create a community node if too many nodes are added', function() { + runs(function() { + adapter.setNodeLimit(6); + spyOn(this, "fakeReducerRequest").andCallFake(function() { + return [c0, c1, c2, c3]; + }); + adapter.loadNodeFromTreeById(c1, checkCallbackFunction); + }); - expect(called).toBeTruthy(); + waitsFor(function() { + return callbackCheck; + }); + + runs(function() { + notExistNodes([c0, c1, c2, c3]); + existNode("community_1"); + existNodes([c4, c5, c6, c7]); + expect(nodes.length).toEqual(5); + + existEdge("community_1", c4); + existEdge("community_1", c5); + existEdge("community_1", c6); + existEdge("community_1", c7); + expect(edges.length).toEqual(4); + }); + }); }); - describe('that has loaded several queries', function() { var c8, c9, e2_8; @@ -1020,7 +1052,7 @@ return false; } return true; - } + }; fakeResult = ""; toDelete = nodeWithID(c2); adapter.deleteNode(toDelete, checkCallbackFunction); @@ -1030,11 +1062,11 @@ runs(function() { expect($.ajax).toHaveBeenCalledWith( - requests.node(nodesCollection).delete(toDelete._id) + requests.node(nodesCollection).del(toDelete._id) ); notExistNode(c2); expect($.ajax).toHaveBeenCalledWith( - requests.node(edgesCollection).delete(e2_8) + requests.node(edgesCollection).del(e2_8) ); notExistEdge(c2, c8); }); @@ -1063,8 +1095,8 @@ s1_toDel = insertEdge(edgesCollection, s1, toDel); toDel_t0 = insertEdge(edgesCollection, toDel, t0); - var loaded = false; - var fakeResult = ""; + var loaded = false, + fakeResult = ""; spyOn($, "ajax").andCallFake(function(request) { if (request.url.indexOf("cursor", request.url.length - "cursor".length) !== -1) { @@ -1114,16 +1146,16 @@ notExistEdge(toDel, t0); expect($.ajax).toHaveBeenCalledWith( - requests.node(nodesCollection).delete(toDel) + requests.node(nodesCollection).del(toDel) ); expect($.ajax).toHaveBeenCalledWith( - requests.node(edgesCollection).delete(s0_toDel) + requests.node(edgesCollection).del(s0_toDel) ); expect($.ajax).toHaveBeenCalledWith( - requests.node(edgesCollection).delete(s1_toDel) + requests.node(edgesCollection).del(s1_toDel) ); expect($.ajax).toHaveBeenCalledWith( - requests.node(edgesCollection).delete(toDel_t0) + requests.node(edgesCollection).del(toDel_t0) ); // Check if counter is set correctly diff --git a/html/admin/js/graphViewer/jasmine_test/specJSLint/jsLintSpec.js b/html/admin/js/graphViewer/jasmine_test/specJSLint/jsLintSpec.js index 6392b4abc3..fb48a51e0c 100644 --- a/html/admin/js/graphViewer/jasmine_test/specJSLint/jsLintSpec.js +++ b/html/admin/js/graphViewer/jasmine_test/specJSLint/jsLintSpec.js @@ -1,68 +1,78 @@ -describe('JSLint', function () { - var options = {}, - lint = /^\/specJSLint|.jsLintSpec\.js$/; +/*jslint indent: 2, nomen: true, maxlen: 100, white: true plusplus: true */ +/*global beforeEach, afterEach */ +/*global describe, it, expect, jasmine, spyOn*/ +/*global waitsFor, runs, waits */ +/*global _, JSLINT*/ +/*global document*/ - function get(path) { - path = path + "?" + new Date().getTime(); +(function () { + "use strict"; + describe('JSLint', function () { + var options = {}, + lint = /^\/specJSLint|[\w\W]jsLintSpec\.js$/; - var xhr; - try { - xhr = new jasmine.XmlHttpRequest(); - xhr.open("GET", path, false); - xhr.send(null); - } catch (e) { - throw new Error("couldn't fetch " + path + ": " + e); - } - if (xhr.status < 200 || xhr.status > 299) { - throw new Error("Could not load '" + path + "'."); - } + function get(path) { + path = path + "?" + new Date().getTime(); - return xhr.responseText; - } - - describe('checking codeFiles', function() { - var files = /^(.*lib\/.*)|(.*Spec\.js)$/; - - _.each(document.getElementsByTagName('script'), function (element) { - var script = element.getAttribute('src'); - if (files.test(script)) { - return; + var xhr; + try { + xhr = new jasmine.XmlHttpRequest(); + xhr.open("GET", path, false); + xhr.send(null); + } catch (e) { + throw new Error("couldn't fetch " + path + ": " + e); } - it(script, function () { - var self = this; - var source = get(script); - var result = JSLINT(source, options); - _.each(JSLINT.errors, function (error) { - self.addMatcherResult(new jasmine.ExpectationResult({ - passed: false, - message: "line " + error.line + ' - ' + error.reason + ' - ' + error.evidence - })); + if (xhr.status < 200 || xhr.status > 299) { + throw new Error("Could not load '" + path + "'."); + } + + return xhr.responseText; + } + + describe('checking codeFiles', function() { + var files = /^([\w\W]*lib\/[\w\W]*)|([\w\W]*Spec\.js)$/; + + _.each(document.getElementsByTagName('script'), function (element) { + var script = element.getAttribute('src'); + if (script === null || files.test(script)) { + return; + } + it(script, function () { + var self = this, + source = get(script), + result = JSLINT(source, options); + _.each(JSLINT.errors, function (error) { + self.addMatcherResult(new jasmine.ExpectationResult({ + passed: false, + message: "line " + error.line + ' - ' + error.reason + ' - ' + error.evidence + })); + }); + expect(true).toBe(true); // force spec to show up if there are no errors + }); + }); + }); + + describe('checking specFiles', function() { + var files = /^\/spec*|[\w\W]*Spec\.js$/; + + _.each(document.getElementsByTagName('script'), function (element) { + var script = element.getAttribute('src'); + if (!files.test(script) || lint.test(script)) { + return; + } + it(script, function () { + var self = this, + source = get(script), + result = JSLINT(source, options); + _.each(JSLINT.errors, function (error) { + self.addMatcherResult(new jasmine.ExpectationResult({ + passed: false, + message: "line " + error.line + ' - ' + error.reason + ' - ' + error.evidence + })); + }); + expect(true).toBe(true); // force spec to show up if there are no errors }); - expect(true).toBe(true); // force spec to show up if there are no errors }); }); }); - - describe('checking specFiles', function() { - var files = /^\/spec*|.*Spec\.js$/; - - _.each(document.getElementsByTagName('script'), function (element) { - var script = element.getAttribute('src'); - if (!files.test(script) || lint.test(script)) { - return; - } - it(script, function () { - var self = this; - var source = get(script); - var result = JSLINT(source, options); - _.each(JSLINT.errors, function (error) { - self.addMatcherResult(new jasmine.ExpectationResult({ - passed: false, - message: "line " + error.line + ' - ' + error.reason + ' - ' + error.evidence - })); - }); - expect(true).toBe(true); // force spec to show up if there are no errors - }); - }); - }); -}); \ No newline at end of file +}()); \ No newline at end of file