diff options
-rw-r--r-- | lib/search.js | 2 | ||||
-rw-r--r-- | test/tap/search.js | 265 |
2 files changed, 266 insertions, 1 deletions
diff --git a/lib/search.js b/lib/search.js index 3be8b0d27..5dd060f82 100644 --- a/lib/search.js +++ b/lib/search.js @@ -218,7 +218,7 @@ function addColorMarker (str, arg, i) { if (arg.charAt(0) === "/") { //arg = arg.replace(/\/$/, "") - return str.replace( new RegExp(arg.substr(1, arg.length - 1), "gi") + return str.replace( new RegExp(arg.substr(1, arg.length - 2), "gi") , function (bit) { return markStart + bit + markEnd } ) } diff --git a/test/tap/search.js b/test/tap/search.js new file mode 100644 index 000000000..d4c566973 --- /dev/null +++ b/test/tap/search.js @@ -0,0 +1,265 @@ +var common = require("../common-tap.js") +var test = require("tap").test +var rimraf = require("rimraf") +var mr = require("npm-registry-mock") +var fs = require("fs") +var path = require("path") +var pkg = path.resolve(__dirname, "search") +var cache = path.resolve(pkg, "cache") +var registryCache = path.resolve(cache, "localhost_1337", "-", "all") +var cacheJsonFile = path.resolve(registryCache, ".cache.json") +var mkdirp = require("mkdirp") + +var timeMock = { + epoch: 1411727900, + future: 1411727900+100, + all: 1411727900+25, + since: 0 // filled by since server callback +} + +var EXEC_OPTS = {} + +function cleanupCache() { + rimraf.sync(cache) +} +function cleanup () { cleanupCache() } + +function setupCache() { + mkdirp.sync(cache) + mkdirp.sync(registryCache) + var res = fs.writeFileSync(cacheJsonFile, stringifyUpdated(timeMock.epoch)) + if (res) throw new Error("Creating cache file failed") +} + +var mocks = { + /* Since request, always response with an _update time > the time requested */ + sinceFuture: function(server) { + server.filteringPathRegEx(/startkey=[^&]*/g, function(s) { + var _allMock = JSON.parse(JSON.stringify(allMock)) + timeMock.since = _allMock._updated = s.replace("startkey=", "") + server.get("/-/all/since?stale=update_after&" + s) + .reply(200, _allMock) + return s + }) + }, + allFutureUpdatedOnly: function(server) { + server.get("/-/all") + .reply(200, stringifyUpdated(timeMock.future)) + }, + all: function(server) { + server.get("/-/all") + .reply(200, allMock) + } +} + + +test("No previous cache, init cache triggered by first search", function(t) { + cleanupCache() + + mr({ port: common.port, mocks: mocks.allFutureUpdatedOnly }, function (s) { + common.npm([ + "search", "do not do extra search work on my behalf", + "--registry", common.registry, + "--cache", cache, + "--loglevel", "silent", + "--color", "always" + ], + EXEC_OPTS, + function(err, code) { + s.close() + t.equal(code, 0, "search finished successfully") + t.ifErr(err, "search finished successfully") + + t.ok(fs.existsSync(cacheJsonFile), + cacheJsonFile + " expected to have been created") + var cacheData = JSON.parse(fs.readFileSync(cacheJsonFile, "utf8")) + t.equal(cacheData._updated, String(timeMock.future)) + t.end() + }) + }) +}) + +test("previous cache, _updated set, should trigger since request", function(t) { + cleanupCache() + setupCache() + + function m(server) { + [ mocks.all, mocks.sinceFuture ].forEach(function(m) { + m(server) + }) + } + mr({ port: common.port, mocks: m }, function (s) { + common.npm([ + "search", "do not do extra search work on my behalf", + "--registry", common.registry, + "--cache", cache, + "--loglevel", "silly", + "--color", "always" + ], + EXEC_OPTS, + function(err, code) { + s.close() + t.equal(code, 0, "search finished successfully") + t.ifErr(err, "search finished successfully") + + var cacheData = JSON.parse(fs.readFileSync(cacheJsonFile, "utf8")) + t.equal(cacheData._updated, + timeMock.since, + "cache update time gotten from since response") + cleanupCache() + t.end() + }) + }) +}) + + +var searches = [ + { + term: "f36b6a6123da50959741e2ce4d634f96ec668c56", + description: "non-regex", + location: 241 + }, + { + term: "/f36b6a6123da50959741e2ce4d634f96ec668c56/", + description: "regex", + location: 241 + } +] + +searches.forEach(function(search) { + test(search.description + " search in color", function(t) { + cleanupCache() + mr({ port: common.port, mocks: mocks.all }, function (s) { + common.npm([ + "search", search.term, + "--registry", common.registry, + "--cache", cache, + "--loglevel", "silent", + "--color", "always" + ], + EXEC_OPTS, + function(err, code, stdout) { + s.close() + t.equal(code, 0, "search finished successfully") + t.ifErr(err, "search finished successfully") + // \033 == \u001B + var markStart = "\u001B\\[[0-9][0-9]m" + var markEnd = "\u001B\\[0m" + + var re = new RegExp(markStart + ".*?" + markEnd) + + var cnt = stdout.search(re) + t.equal(cnt, search.location, + search.description + " search for " + search.term) + t.end() + }) + }) + }) +}) + +test("cleanup", function (t) { + cleanup() + t.end() +}) + +function stringifyUpdated(time) { + return JSON.stringify({ _updated : String(time) }) +} + +var allMock = { + "_updated": timeMock.all, + "generator-frontcow": { + "name": "generator-frontcow", + "description": "f36b6a6123da50959741e2ce4d634f96ec668c56 This is a fake description to ensure we do not accidentally search the real npm registry or use some kind of cache", + "dist-tags": { + "latest": "0.1.19" + }, + "maintainers": [ + { + "name": "bcabanes", + "email": "contact@benjamincabanes.com" + } + ], + "homepage": "https://github.com/bcabanes/generator-frontcow", + "keywords": [ + "sass", + "frontend", + "yeoman-generator", + "atomic", + "design", + "sass", + "foundation", + "foundation5", + "atomic design", + "bourbon", + "polyfill", + "font awesome" + ], + "repository": { + "type": "git", + "url": "https://github.com/bcabanes/generator-frontcow" + }, + "author": { + "name": "ben", + "email": "contact@benjamincabanes.com", + "url": "https://github.com/bcabanes" + }, + "bugs": { + "url": "https://github.com/bcabanes/generator-frontcow/issues" + }, + "license": "MIT", + "readmeFilename": "README.md", + "time": { + "modified": "2014-10-03T02:26:18.406Z" + }, + "versions": { + "0.1.19": "latest" + } + }, + "marko": { + "name": "marko", + "description": "Marko is an extensible, streaming, asynchronous, high performance, HTML-based templating language that can be used in Node.js or in the browser.", + "dist-tags": { + "latest": "1.2.16" + }, + "maintainers": [ + { + "name": "pnidem", + "email": "pnidem@gmail.com" + }, + { + "name": "philidem", + "email": "phillip.idem@gmail.com" + } + ], + "homepage": "https://github.com/raptorjs/marko", + "keywords": [ + "templating", + "template", + "async", + "streaming" + ], + "repository": { + "type": "git", + "url": "https://github.com/raptorjs/marko.git" + }, + "author": { + "name": "Patrick Steele-Idem", + "email": "pnidem@gmail.com" + }, + "bugs": { + "url": "https://github.com/raptorjs/marko/issues" + }, + "license": "Apache License v2.0", + "readmeFilename": "README.md", + "users": { + "pnidem": true + }, + "time": { + "modified": "2014-10-03T02:27:31.775Z" + }, + "versions": { + "1.2.16": "latest" + } + } +} |