Browse files

add some tests about tracks and artists

  • Loading branch information...
1 parent 8f86c30 commit 51a4f741c415b9a5b8de38f06efcb836fd8353fc @Floby committed Jan 3, 2013
Showing with 255 additions and 13 deletions.
  1. +1 −0 binding.gyp
  2. +24 −0 lib/Artist.js
  3. +1 −1 lib/Player.js
  4. +49 −0 lib/SpObject.js
  5. +14 −11 lib/Track.js
  6. +1 −0 lib/libspotify.js
  7. +2 −1 package.json
  8. +65 −0 src/artist.cc
  9. +1 −0 src/binding.cc
  10. +4 −0 src/common.h
  11. +63 −0 src/track.cc
  12. +30 −0 test/test-030-track.js
View
1 binding.gyp
@@ -7,6 +7,7 @@
"src/session.cc",
"src/search.cc",
"src/track.cc",
+ "src/artist.cc",
"src/player.cc",
"src/audio.cc",
],
View
24 lib/Artist.js
@@ -0,0 +1,24 @@
+var b = require('bindings')('spotify.node');
+var sp = require('./libspotify');
+var util = require('util');
+var SpObject = require('./SpObject');
+
+function Artist (sp_artist) {
+ this._sp_object = sp_artist;
+ SpObject.apply(this);
+}
+util.inherits(Artist, SpObject);
+
+Artist.prototype._object_type = 'artist';
+
+Artist.prototype._populateAttributes = function _populateAttributes() {
+ this.name = b.artist_name(this._sp_object);
+};
+
+Artist.prototype.toString = function toString() {
+ return this.name;
+};
+
+
+module.exports = Artist;
+
View
2 lib/Player.js
@@ -27,7 +27,7 @@ Player.prototype.pipe = stream.Stream.prototype.pipe;
Player.prototype.load = function load(track) {
assert(track instanceof sp.Track);
- b.session_player_load(this._session._sp_session, track._sp_track);
+ b.session_player_load(this._session._sp_session, track._sp_object);
};
Player.prototype.play = function play() {
View
49 lib/SpObject.js
@@ -0,0 +1,49 @@
+var b = require('bindings')('spotify.node');
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+var backoff = require('backoff');
+
+
+function SpObject () {
+ EventEmitter.apply(this);
+ var bo = backoff.fibonacci({
+ initialDelay: 10,
+ maxDelay: 1000
+ });
+ bo.failAfter(10);
+ var self = this;
+ if(this.isReady()) {
+ this._populateAttributes();
+ setTimeout(function() {self.emit('ready')}, 1);
+ }
+ else {
+ bo.on('ready', function(number, delay) {
+ if(!self.isReady()) {
+ bo.backoff();
+ }
+ else {
+ self._populateAttributes();
+ self.emit('ready');
+ }
+ });
+ bo.on('fail', function() {
+ self._loadingTimeout();
+ });
+ }
+}
+util.inherits(SpObject, EventEmitter);
+
+SpObject.prototype.isReady = function isReady() {
+ return this._is_loaded(this._sp_object);
+};
+
+SpObject.prototype._is_loaded = function _is_loaded(obj) {
+ return b[this._object_type+'_is_loaded'](obj);
+};
+
+SpObject.prototype._loadingTimeout = function _loadingTimeout() {
+ this.emit('load-timeout');
+};
+
+
+module.exports = SpObject;
View
25 lib/Track.js
@@ -1,27 +1,30 @@
var b = require('bindings')('spotify.node');
-var Session = require('./Session');
+var sp = require('./libspotify');
var util = require('util');
-var EventEmitter = require('events').EventEmitter;
+var SpObject = require('./SpObject');
function Track (sp_track) {
- this._sp_track = sp_track;
- if(this.isReady()) {
- this._populateAttributes();
- }
+ this._sp_object = sp_track;
+ SpObject.apply(this);
}
-util.inherits(Track, EventEmitter);
+util.inherits(Track, SpObject);
-Track.prototype.isReady = function isReady() {
- return b.track_is_loaded(this._sp_track);
-};
+Track.prototype._object_type = 'track';
Track.prototype._populateAttributes = function _populateAttributes() {
- var dms = this.duration = b.track_duration(this._sp_track);
+ var dms = this.duration = b.track_duration(this._sp_object);
// get seconds instead
dms = Math.floor(dms / 1000);
var min = Math.floor(dms / 60);
var sec = (dms % 60); if(sec < 10) sec = '0'+sec;
this.humanDuration = min+':'+sec;
+
+ this.name = this.title = b.track_name(this._sp_object);
+ this.artists = [];
+ for (var i = 0; i < b.track_num_artists(this._sp_object); ++i) {
+ this.artists.push(b.track_artist(this._sp_object, i));
+ }
+ this.artist = new sp.Artist(b.track_artist(this._sp_object, 0));
};
View
1 lib/libspotify.js
@@ -2,3 +2,4 @@ exports.Player = require('./Player');
exports.Session = require('./Session');
exports.Search = require('./Search');
exports.Track = require('./Track');
+exports.Artist = require('./Artist');
View
3 package.json
@@ -27,7 +27,8 @@
"dependencies": {
"bindings": "~1.0.0",
"i":"~0.3",
- "format":"0.1"
+ "format":"0.1",
+ "backoff":"~1.2"
},
"devDependencies": {
"nodeunit": "~0.7",
View
65 src/artist.cc
@@ -0,0 +1,65 @@
+/*
+ * =====================================================================================
+ *
+ * Filename: artist.cc
+ *
+ * Description: bindings for the artist subsystem
+ *
+ * Version: 1.0
+ * Created: 03/01/2013 15:18:14
+ * Revision: none
+ * Compiler: gcc
+ *
+ * Author: Florent Jaby (FJ), florent.jaby@gmail.com
+ * Company: Florent Jaby
+ *
+ * =====================================================================================
+ */
+
+
+#include "common.h"
+
+using namespace v8;
+using namespace nsp;
+
+/**
+ * JS artist_is_loaded implementation. checks if a given artist is loaded
+ */
+static Handle<Value> Artist_Is_Loaded(const Arguments& args) {
+ HandleScope scope;
+
+ // test arguments sanity
+ assert(args.Length() == 1);
+ assert(args[0]->IsObject());
+
+ // gets sp_artist pointer from given object
+ ObjectHandle<sp_artist>* artist = ObjectHandle<sp_artist>::Unwrap(args[0]);
+
+ // actually call sp_artist_is_loaded
+ bool loaded = sp_artist_is_loaded(artist->pointer);
+
+ return scope.Close(Boolean::New(loaded));
+}
+
+/**
+ * JS artist_name implementation. checks if a given artist is loaded
+ */
+static Handle<Value> Artist_Name(const Arguments& args) {
+ HandleScope scope;
+
+ // test arguments sanity
+ assert(args.Length() == 1);
+ assert(args[0]->IsObject());
+
+ // gets sp_artist pointer from given object
+ ObjectHandle<sp_artist>* artist = ObjectHandle<sp_artist>::Unwrap(args[0]);
+
+ const char* name = sp_artist_name(artist->pointer);
+
+ return scope.Close(String::New(name));
+}
+
+void nsp::init_artist(Handle<Object> target) {
+ NODE_SET_METHOD(target, "artist_is_loaded", Artist_Is_Loaded);
+ NODE_SET_METHOD(target, "artist_name", Artist_Name);
+}
View
1 src/binding.cc
@@ -29,6 +29,7 @@ extern "C" {
nsp::init_session(target);
nsp::init_search(target);
nsp::init_track(target);
+ nsp::init_artist(target);
nsp::init_player(target);
}
}
View
4 src/common.h
@@ -135,6 +135,10 @@ namespace nsp {
* init the player related functions to the target module exports
*/
void init_player(v8::Handle<v8::Object> target);
+ /**
+ * init the artist related functions to the target module exports
+ */
+ void init_artist(v8::Handle<v8::Object> target);
/**
View
63 src/track.cc
@@ -59,7 +59,70 @@ static Handle<Value> Track_Duration(const Arguments& args) {
return scope.Close(Number::New(duration));
}
+/**
+ * JS track_num_artists implementation. checks if a given track is loaded
+ */
+static Handle<Value> Track_Num_Artists(const Arguments& args) {
+ HandleScope scope;
+
+ // test arguments sanity
+ assert(args.Length() == 1);
+ assert(args[0]->IsObject());
+
+ // gets sp_track pointer from given object
+ ObjectHandle<sp_track>* track = ObjectHandle<sp_track>::Unwrap(args[0]);
+
+ int num_artists = sp_track_num_artists(track->pointer);
+
+ return scope.Close(Number::New(num_artists));
+}
+
+/**
+ * JS track_name implementation. checks if a given track is loaded
+ */
+static Handle<Value> Track_Name(const Arguments& args) {
+ HandleScope scope;
+
+ // test arguments sanity
+ assert(args.Length() == 1);
+ assert(args[0]->IsObject());
+
+ // gets sp_track pointer from given object
+ ObjectHandle<sp_track>* track = ObjectHandle<sp_track>::Unwrap(args[0]);
+
+ const char* name = sp_track_name(track->pointer);
+
+ return scope.Close(String::New(name));
+}
+
+/**
+ * JS track_artist implementation. checks if a given track is loaded
+ */
+static Handle<Value> Track_Artist(const Arguments& args) {
+ HandleScope scope;
+
+ // test arguments sanity
+ assert(args.Length() == 2);
+ assert(args[0]->IsObject());
+ assert(args[1]->IsNumber());
+
+ // gets sp_track pointer from given object
+ ObjectHandle<sp_track>* track = ObjectHandle<sp_track>::Unwrap(args[0]);
+ int index = args[1]->ToNumber()->Int32Value();
+ assert(index >= 0);
+ assert(index < sp_track_num_artists(track->pointer));
+
+ sp_artist* spartist = sp_track_artist(track->pointer, index);
+ ObjectHandle<sp_artist>* artist = new ObjectHandle<sp_artist>("sp_artist");
+ artist->pointer = spartist;
+
+ return scope.Close(artist->object);
+}
+
void nsp::init_track(Handle<Object> target) {
NODE_SET_METHOD(target, "track_is_loaded", Track_Is_Loaded);
NODE_SET_METHOD(target, "track_duration", Track_Duration);
+ NODE_SET_METHOD(target, "track_num_artists", Track_Num_Artists);
+ NODE_SET_METHOD(target, "track_name", Track_Name);
+ NODE_SET_METHOD(target, "track_artist", Track_Artist);
}
View
30 test/test-030-track.js
@@ -0,0 +1,30 @@
+var sp = require('../lib/libspotify');
+var testutil = require('./util');
+
+var session = null;
+
+exports.track = {
+ setUp: function(cb) {
+ testutil.getDefaultTestSession(function(s) {
+ session = s;
+ cb();
+ })
+ },
+ testAttributesAreMapped: function(test) {
+ var search = new sp.Search('artist:"Guillemots" track:"Fleet"');
+ search.execute(function() {
+ test.ok(search.tracks.length > 0, "the search should return at least one result");
+ var first = search.tracks[0];
+ test.ok(first instanceof sp.Track, "the track results should be loaded track objects");
+ test.ok(first.isReady());
+ test.ok(first.artist.isReady(), 'the artist of the track should be loaded');
+ test.equal('Guillemots', first.artist.name, "the track should be a guillemots song");
+ test.equal('Guillemots', first.artist, "the track should be a guillemots song");
+ test.equal('Fleet', first.title, "the track should be a guillemots song");
+ test.ok(first.duration > 0, 'The track should have a non zero duration');
+ return test.done();
+ });
+ }
+};
+
+

0 comments on commit 51a4f74

Please sign in to comment.