UNPKG

georedis

Version:
718 lines (576 loc) 17.3 kB
var geohash = require('ngeohash'); var client; var geo; var geoSet; var interfce; var people; var places; var locationSet = {}; var lat = 43.646838; var lon = -79.403723; var startRadius = 0.4; var testPoint = { latitude: lat, longitude: lon }; var setLength; module.exports = { setGeo: function(testingGeo, testingClient, testingGeoSet, testingInterface) { geo = testingGeo; client = testingClient; geoSet = testingGeoSet; interfce = testingInterface; }, 'Exporting OK': function(t) { client.del(geoSet); t.expect(4); t.equal(typeof geo === 'object', true); t.equal(typeof geo.initialize === 'function', true); t.equal(geo.clientInterface.client.constructor.name, interfce); t.equal(geo.zset, geoSet); t.done(); }, 'Location Null': function(t) { client.del(geoSet); t.expect(2); geo.location('Toronto', function(err, reply) { t.equal(err, null); t.equal(reply, null); t.done(); }); }, 'Add Location': function(t) { client.del(geoSet); t.expect(2); geo.addLocation('Toronto', { latitude: 43.6667, longitude: -79.4167 }, function(err, reply) { t.equal(err, null); t.equal(reply, 1); t.done(); }); }, 'Add Locations': function(t) { var locationRange; var distance = 0; var count = 1; client.del(geoSet); t.expect(2); locationSet = {}; locationSet['center_0'] = testPoint; for (var i = 0; i < 5000; i++) { distance = i * (i / 100); locationRange = getMinMaxs(lat, lon, distance); locationSet['sw_' + distance] = { latitude: locationRange.latmin % 85, longitude: locationRange.lonmin % 180 }; locationSet['nw_' + distance] = { latitude: locationRange.latmax % 85, longitude: locationRange.lonmin % 180 }; locationSet['se_' + distance] = { latitude: locationRange.latmin % 85, longitude: locationRange.lonmax % 180 }; locationSet['ne_' + distance] = { latitude: locationRange.latmax % 85, longitude: locationRange.lonmax % 180 }; count += 4; } geo.addLocations(locationSet, function(err, reply) { t.equal(err, null); t.equal(count, reply); t.done(); }); }, 'Get Location': function(t) { var locations = Object.keys(locationSet); var instance = locations[Math.round(locations.length / 2)]; t.expect(3); geo.location(instance, function(err, point) { if (err) throw err; t.equal(err, null); t.equal(Math.round(point.latitude * 100), Math.round(locationSet[instance].latitude * 100)); t.equal(Math.round(point.longitude * 100), Math.round(locationSet[instance].longitude * 100)); t.done(); }); }, 'Get Locations': function(t) { var locationQuery = []; var point; var i = 0; var latlon; for (var locationName in locationSet) { if (i++ % 100 === 0) { locationQuery.push(locationName); } } t.expect((locationQuery.length * 3) + 2); i = 0; geo.locations(locationQuery, function(err, points) { if (err) throw err; t.equal(err, null); t.equal(Object.keys(points).length, locationQuery.length); for (var pointName in points) { latlon = geohash.decode_int(geohash.encode_int(locationSet[locationQuery[i]].latitude, locationSet[locationQuery[i]].longitude)); point = points[pointName]; t.equal(pointName, locationQuery[i]); t.equal(Math.round(point.latitude), Math.round(latlon.latitude)); t.equal(Math.round(point.longitude), Math.round(latlon.longitude)); i++; } t.done(); }); }, 'Get Distance': function(t) { var locations = Object.keys(locationSet); var instance = locations[Math.round(locations.length / 2)]; var expected = 78974; var errorThreshold = 200; t.expect(2); geo.distance(instance, 'center_0', function(err, distance) { if (err) throw err; t.ok(isBetween(distance, expected - errorThreshold, expected + errorThreshold)); }); geo.distance(instance, 'center_0', { units: 'ft' }, function(err, distance) { if (err) throw err; t.ok(isBetween(distance, (expected * 3.28084) - errorThreshold, (expected * 3.28084) + errorThreshold)); t.done(); }); }, 'Locations Null': function(t) { t.expect(6); var locationQuery = [ 'sw_4682463.21', 'nw_4693288.96', 'se_4704127.21', 'non-existent', 'ne_4714977.96', 'sw_4726276', 'nw_4737152.25', 'se_4748041', 'ne_4758942.25', 'sw_4770292.81' ]; geo.locations(locationQuery, function(err, points) { if (err) throw err; t.equal(err, null); t.equal(Object.keys(points).length, 10); t.equal(typeof points['non-existent'], 'object'); t.equal(typeof points['sw_4682463.21'], 'object'); t.equal(typeof points['nw_4737152.25'], 'object'); t.equal(points['non-existent'], null); t.done(); }); }, 'Basic Query': function(t) { t.expect(5); geo.nearby(testPoint, 50000, function(err, replies) { if (err) throw err; setLength = replies.length; t.equal(typeof replies, 'object'); t.equal(Array.isArray(replies), true); t.ok(isBetween(replies.length, 5000, 9000)); t.equal(typeof replies[0], 'string'); t.equal(typeof replies.locationSet, 'object'); t.done(); }); }, 'Basic Query by Member': function(t) { t.expect(5); geo.nearby('center_0', 50000, function(err, replies) { if (err) throw err; t.equal(typeof replies, 'object'); t.equal(Array.isArray(replies), true); t.equal(replies.length, setLength); t.equal(typeof replies[0], 'string'); t.equal(typeof replies.locationSet, 'object'); t.done(); }); }, 'Basic Query by Null Member': function(t) { t.expect(4); geo.nearby('non-existent', 50000, function(err, replies) { t.equal(err.message, 'ERR could not decode requested zset member'); t.equal((err === null), false); t.equal(Array.isArray(replies), false); t.equal(replies, null); t.done(); }); }, 'Basic Query with Count': function(t) { t.expect(5); geo.nearby(testPoint, 50000, { count: 10 }, function(err, replies) { if (err) throw err; t.equal(typeof replies, 'object'); t.equal(Array.isArray(replies), true); t.equal(replies.length, 10); t.equal(typeof replies[0], 'string'); t.equal(typeof replies.locationSet, 'object'); t.done(); }); }, 'Basic Query in Order': function(t) { t.expect(5); geo.nearby(testPoint, 50000, { order: true }, function(err, replies) { if (err) throw err; t.equal(typeof replies, 'object'); t.equal(Array.isArray(replies), true); t.equal(replies.length, setLength); t.ok(typeof replies[0] === 'object' || typeof replies[0] === 'string'); t.equal(typeof replies.locationSet, 'object'); t.done(); }); }, 'Basic Query with Coordinates': function(t) { var options = { withCoordinates: true }; t.expect(9); geo.nearby(testPoint, 50000, options, function(err, replies) { if (err) throw err; t.equal(typeof replies, 'object'); t.equal(Array.isArray(replies), true); t.equal(replies.length, setLength); t.equal(typeof replies[0], 'object'); t.equal(typeof replies[0].distance, 'undefined'); t.equal(typeof replies[0].hash, 'undefined'); t.equal(typeof replies[0].latitude, 'number'); t.equal(typeof replies[0].longitude, 'number'); t.equal(typeof replies.locationSet, 'object'); t.done(); }); }, 'Basic Query with Coordinates and Count': function(t) { var options = { withCoordinates: true, count: 10 }; t.expect(9); geo.nearby(testPoint, 50000, options, function(err, replies) { if (err) throw err; t.equal(typeof replies, 'object'); t.equal(Array.isArray(replies), true); t.equal(replies.length, 10); t.equal(typeof replies[0], 'object'); t.equal(typeof replies[0].distance, 'undefined'); t.equal(typeof replies[0].hash, 'undefined'); t.equal(typeof replies[0].latitude, 'number'); t.equal(typeof replies[0].longitude, 'number'); t.equal(typeof replies.locationSet, 'object'); t.done(); }); }, 'Basic Query with Hashes': function(t) { var options = { withCoordinates: true, withHashes: true }; t.expect(9); geo.nearby(testPoint, 50000, options, function(err, replies) { if (err) throw err; t.equal(typeof replies, 'object'); t.equal(Array.isArray(replies), true); t.equal(replies.length, setLength); t.equal(typeof replies[0], 'object'); t.equal(typeof replies[0].distance, 'undefined'); t.equal(typeof replies[0].hash, 'number'); t.equal(typeof replies[0].latitude, 'number'); t.equal(typeof replies[0].longitude, 'number'); t.equal(typeof replies.locationSet, 'object'); t.done(); }); }, 'Basic Query with Coordinates and Precision': function(t) { var options = { withCoordinates: true, withDistances: true, accurate: true }; geo.nearby(testPoint, 50000, options, function(err, replies) { if (err) throw err; t.expect(9 + replies.length); for (var i = 0; i < replies.length; i++) { t.equal((replies[i].distance <= 50000), true); } t.equal(typeof replies, 'object'); t.equal(Array.isArray(replies), true); t.ok(isBetween(replies.length, setLength - 2000, setLength + 2000)); t.equal(typeof replies[0], 'object'); t.equal(typeof replies[0].distance, 'number'); t.equal(typeof replies[0].latitude, 'number'); t.equal(typeof replies[0].longitude, 'number'); t.equal(typeof replies[0].hash, 'undefined'); t.equal(typeof replies.locationSet, 'object'); t.done(); }); }, 'Remove Location': function(t) { t.expect(1); var oneToDelete = ''; geo.nearby(testPoint, 50000, function(err, replies) { if (err) throw err; oneToDelete = replies[replies.length - 1]; geo.removeLocation(oneToDelete, function(err, numberRemoved) { if (err) throw err; t.equal(numberRemoved, 1); t.done(); }); }); }, 'Remove Locations': function(t) { t.expect(1); var arrayToDelete = []; geo.nearby(testPoint, 50000, function(err, replies) { if (err) throw err; arrayToDelete = replies; geo.removeLocations(arrayToDelete, function(err, numberRemoved) { if (err) throw err; t.equal(numberRemoved, setLength - 1); t.done(); }); }); }, 'Large Radius': function(t) { client.del(geoSet); t.expect(2); geo.addLocation('debugger', { latitude: 1, longitude: 2 }, function(err, reply) {}); geo.addLocation('boostbob', { latitude: 2, longitude: 3 }, function(err, reply) {}); geo.nearby({ latitude: 2, longitude: 2 }, 100000000, function(err, replies) { t.equal(err, null); t.equal(replies[2], null); t.done(); }); }, 'Add Nearby Ranges': function(t) { var locationRange; var distance = 0; var count = 1; client.del(geoSet); t.expect(2); locationSet = {}; locationSet['center_0'] = testPoint; for (var i = 0; i < 5000; i++) { distance = i * (i / 100); locationRange = getMinMaxs(lat, lon, distance); locationSet['sw_' + distance] = { latitude: locationRange.latmin % 85, longitude: locationRange.lonmin % 180 }; locationSet['nw_' + distance] = { latitude: locationRange.latmax % 85, longitude: locationRange.lonmin % 180 }; locationSet['se_' + distance] = { latitude: locationRange.latmin % 85, longitude: locationRange.lonmax % 180 }; locationSet['ne_' + distance] = { latitude: locationRange.latmax % 85, longitude: locationRange.lonmax % 180 }; count += 4; } geo.addLocations(locationSet, function(err, reply) { if (err) throw err; t.equal(err, null); t.equal(count, reply); t.done(); }); }, 'Radii Ranges': function(t) { t.expect(22); queryRadius(startRadius, t, function() { t.done(); }); }, 'Multiple Sets': function(t) { var peopleLocations = { 'John': { latitude: 43.6667, longitude: -79.4167 }, 'Shankar': { latitude: 39.9523, longitude: -75.1638 }, 'Cynthia': { latitude: 37.4688, longitude: -122.1411 }, 'Chen': { latitude: 37.7691, longitude: -122.4449 } }; var placesLocations = { 'Toronto': { latitude: 43.6667, longitude: -79.4167 }, 'Philadelphia': { latitude: 39.9523, longitude: -75.1638 }, 'Palo Alto': { latitude: 37.4688, longitude: -122.1411 }, 'San Francisco': { latitude: 37.7691, longitude: -122.4449 }, 'St. John\'s': { latitude: 47.5500, longitude: -52.6667 } }; t.expect(2); places = geo.addSet(); people = geo.addSet('people'); people.addLocations(peopleLocations, function(err, reply) { if (err) throw err; places.addLocations(placesLocations, function(err, reply) { if (err) throw err; people.nearby({ latitude: 39.9523, longitude: -75.1638 }, 5000, function(err, people) { if (err) throw err; t.equal(people[0], 'Shankar'); places.nearby({ latitude: 39.9523, longitude: -75.1638 }, 5000, function(err, places) { if (err) throw err; t.equal(places[0], 'Philadelphia'); t.done(); }); }); }); }); }, 'Multiple Sets With Values': function(t) { t.expect(6); people.nearby({ latitude: 39.9523, longitude: -75.1638 }, 5000000, { withCoordinates: true }, function(err, people) { if (err) throw err; people = people.locationSet; var cynthia = people['Cynthia']; var inlatRange = (cynthia.latitude > 37.4688 - 0.005 && cynthia.latitude < 37.4688 + 0.005) ? true : false; var inlonRange = (cynthia.longitude > -122.1411 - 0.005 && cynthia.longitude < -122.1411 + 0.005) ? true : false; t.equal(typeof cynthia, 'object'); t.equal(inlatRange, true); t.equal(inlonRange, true); places.nearby({ latitude: 39.9523, longitude: -75.1638 }, 5000000, { withCoordinates: true }, function(err, places) { if (err) throw err; places = places.locationSet; var philadelphia = places['Philadelphia']; inlatRange = (philadelphia.latitude > 39.9523 - 0.005 && philadelphia.latitude < 39.9523 + 0.005) ? true : false; inlonRange = (philadelphia.longitude > -75.1638 - 0.005 && philadelphia.longitude < -75.1638 + 0.005) ? true : false; t.equal(typeof philadelphia, 'object'); t.equal(inlatRange, true); t.equal(inlonRange, true); t.done(); }); }); }, 'Deleting Set': function(t) { t.expect(2); geo.deleteSet('people', function(err, res) { people.nearby({ latitude: 39.9523, longitude: -75.1638 }, 5000000, { withCoordinates: true }, function(err, people) { t.equal(people.length, 0); }); }); places.delete(function(err, res) { places.nearby({ latitude: 39.9523, longitude: -75.1638 }, 5000000, { withCoordinates: true }, function(err, places) { t.equal(places.length, 0); t.done(); }); }); }, 'Quitting Client': function(t) { client.quit(); t.done(); }, tearDown: function(done) { done(); } }; function queryRadius(radius, t, next) { geo.nearby({ latitude: lat, longitude: lon }, radius, function(err, replies) { if (err) throw err; var max = 0; for (var i = 0; i < replies.length; i++) { var split = replies[i].split('_'); if (Number(split[1]) > max) { max = Number(split[1]); } } t.equal((max > radius - (radius / 2) || max < radius + (radius / 2)), true); startRadius *= 2; if (startRadius < 1000000) { queryRadius(startRadius, t, next); } else { next(); } }); } // helpers function getMinMaxs(latitude, longitude, radius) { var latr = radius / 111111; var lonr = radius / (111111 * Math.abs(Math.cos(latitude))); var latmin = latitude - latr; var latmax = latitude + latr; var lonmin = longitude - lonr; var lonmax = longitude + lonr; return { latmin: latmin, latmax: latmax, lonmin: lonmin, lonmax: lonmax }; } function isBetween(val, low, high) { return (low <= val && high >= val); }