<commit_before>/**
 *  API for DB Collection objects
 *
 *
 * @fileOverview dbutil.js - 10gen Database Collection  API
 * @name 10gen Database Collection API
 */

 /**
  * Database collection  API
 *  @class 10gen Database Collection  API
 * @docmodule system.database.collection
 */
 var DBCollection = function(){}

/**
 *
Drop all indexes on the specified collection.

 *
 *
Note : alpha: space is not reclaimed.

 *
 *
Note : When you drop an index, any open cursors for the collection are
 *            invalidated (even if those cursors use a different index.

 *
 * @return A result object.  result.ok will be true if successful.
 */
DBCollection.prototype.dropIndexes = function() {
    var res = this._dbCommand( { deleteIndexes: this.getName(), index: "*" } );
    if( res && res.ok && res.ok == 1 ) {
	// this.getDB().system.indexes.remove( { ns: this.getFullName() } );
	// this.getDB().system.namespaces.remove( { name: RegExp(this.getFullName() + "[.][$].*") } );
    }

    this.resetIndexCache();

    return res;
}

/**
 *
Drop a specified index.

 *
 *

 * Name is the name of the index in the system.indexes name field. (Run db.system.indexes.find() to
 *  see example data.)
 *

 *
 *
Note :  alpha: space is not reclaimed

 * @param {String} name of index to delete.
 * @return A result object.  result.ok will be true if successful.
 */
 DBCollection.prototype.dropIndex =  function(index) {
    assert(index);

    if ( ! isString( index ) && isObject( index ) )
    	index = this.genIndexName( index );

    var res = this._dbCommand( { deleteIndexes: this.getName(), index: index } );
    if( res && res.ok && res.ok == 1 ) {
        //this.getDB().system.indexes.remove( { ns: this.getFullName(), name: index } );
	//this.getDB().system.namespaces.remove( { name: this.getFullName() + ".$"+index } );
    }

    this.resetIndexCache();

    return res;
}

/**
 *

 *    Returns an array of the indexes for the collection.
 *

 *

 *   Each entry in the array is an index descriptor object than contains the
 *   following properties :
 *

 *

 *
 name : name of the index

 *
 ns : name of the namespace the index is in

 *
 key : object property that's being indexed

 *

 *
 *   @return database cursor of index descriptor objects
 */
DBCollection.prototype.getIndexes = function(){
    return this.getDB().system.indexes.find( { ns : this.getFullName() } );
}

/**
 *

 *   Re-indexes the collection
 *

 */
DBCollection.prototype.reIndex = function(){

    var coll = this;

    var all = this.getDB().system.indexes.find( { ns : this.getFullName() } ).toArray();

    all.forEach(
        function(z){
            print( z.name );
            coll._dbCommand( { clean: coll + ".$" + z.name } );
            coll.dropIndex( z.name );
            coll.ensureIndex( z.key );
        }
    );
}

/**
 * clean the collection AND all of its indexes
 * note: prints output to the console.
 */
DBCollection.prototype.cleanAll = function(){
    var coll = this;
    print("cleaning " + coll);
    print( tojson( coll.clean() ) );
    var all = this.getDB().system.indexes.find( { ns : this.getFullName() } ).toArray();
    all.forEach(
        function(z){
	    var idx = coll + ".$" + z.name;
	    print("cleaning " + idx);
	    // print("db: " + coll.getDB());
	    print( tojson(coll.getDB()[idx].clean()) );
        }
    );
}

/**
 * Validate the data in a collection, returning some stats.
 * @return An object with several fields set including:
 *

 *
result : textual description of the validation result

 *
ok : true if validate operation was performed

 *
valid : true if the collection is not corrupt

 *

 */
DBCollection.prototype.validate = function() {
    var res = this._dbCommand( { validate: this.getName() } );

    res.valid = false;

    if ( res.result ){
        var str = "-" + tojson( res.result );
        res.valid = ! ( str.match( /exception/ ) || str.match( /corrupt/ ) );

        var p = /lastExtentSize:(\d+)/;
        var r = p.exec( str );
        if ( r ){
            res.lastExtentSize = parseNumber( r[1] );
        }
    }

    return res;
}

/**
 *
drops all objects in the collection

 *
Note :  alpha: space not reclaimed.

 *
 * @return A result object.  result.ok will be true if successful.
 */
DBCollection.prototype.drop = function()
{
    var res = this.dropIndexes();
    if( !res )
	return res;
    if( !res.ok ) {
	res.errmsg = "dropping indexes..." + res.errmsg;
	return res;
    }

    res = this._dbCommand( { drop: this.getName() } );
    if( res && res.ok && res.ok == 1 ) {
	/* note: database does this now.
	   this.getDB().system.namespaces.remove( { name: this.getFullName() } );
	*/
    }
    return res;
}

/**
 *  Drop free lists. Normally not used.
 *  Note this only does the collection itself, not the namespaces of its indexes (see cleanAll).
 */
DBCollection.prototype.clean = function() {
    return this._dbCommand( { clean: this.getName() } );
}

/**
 *

 *  count # of objects in a collection
 *

 *
 *
  You can specify a filter for counting through the optional  parameter.
 *      This parameter specifies condition that must be true for the objects to
 *        be counted.
 *

 *
Example:

 *
 *   c = count({active:true});
 *
 * @param {Object} query Optional query to use to filter objects for counting
 * @return number of objects in the collection that optionally match the filter condition
 */
DBCollection.prototype.count = function(query) {
    var cmd = { count: this.getName() };
    if( query ) cmd.query = query;
    var res = this._dbCommand( cmd );
    if( res && res.n != null ) return res.n;
    throw { exception: "count failed", res: res };
}

/* Run the specified database "command" object.
*/
DBCollection.prototype._dbCommand = function( cmdObj ) {
    return this.getDB().$cmd.findOne(cmdObj);
}

DBCollection.prototype.checksum = function(){
    var r = this.getDB().eval(
        function(){
	    var sum = 0;
	    var c = db[args[0]].find();
	    while ( c.hasNext() ){
		sum += c.next().hashCode();
	    }

	    var c = db.system.indexes.find( { ns : args[1] } );

	    while(c.hasNext()) {
	      	sum += c.next().hashCode();
	    }

    	    return sum;
        } ,
        this.getName(), this.getFullName()
    );
    return r;
}

DBCollection.prototype.sample = function( num , query , fields ){
    var r = this.getDB().eval(
        function(){
            var a = db[args[0]].find( args[2] || {} , args[3] ).limit(10000).toArray();
            a.shuffle();
            return a.splice( 0 , args[1] );
        } ,
        this.getName() , num , query , fields
    );
    var a = [];
    for ( var k in r ){
        a.push( r[k] );
    }
    return a;
}

var mydb  = arguments[0];

if (!mydb) {
       throw "Error : no db object passed to augmentor for Collection";
}

Object.extend( mydb.getCollectionPrototype() , DBCollection.prototype );

return null;

//
//  other stuff
//

/**
 *  RESET - FOLLOWING IS FOR DOCUMENTATION PURPOSES ONLY
 */
DBCollection.prototype = {};

/**
 *
Returns the name of the collection.

 *
 * @return {String} Name of the collection
 */
DBCollection.prototype.name = function() {
    throw {exception : "Native Call name() : shouldn't have JS implementation"};
}

//       _entries.put( "base" , _base.getName() );

 /**
 *

 * Saves an object in the collection, or update if the object (as identified by _id)
 * is already there.
 *

 *
 *

 * If your object has a presave $TODO_DOC method, that method will be called
 * before the object is saved to the db (before both updates and inserts).
 *

 * @return SOMETHING_FIXME
 */
DBCollection.prototype.save = function(obj) {
    throw {exception : "Native Call save() : shouldn't have JS implementation"};
}

 /**
 *

 * Update an object in the database, based on supplied query criteria and options.  Normally
 * you should just use the save() method.
 *

 *

 * Current options include :
 *

 *

 *
upsert:true - perform an update if exists, or insert new if doesn't exist

 *
ids : false - do not add an object _id field

 *

 *
 *

 * Example :
 *

 * db.myColl.update( { name: "Joe" }, { name: "Joe", age: 20 }, { upsert: true } );
 *
 *
 @see  http://admin.10gen.com/wiki/pub.db.update

 *
 * @param {Object} criteria  query which selects the record @TODO{more than one?} to update
 * @param {Object} obj  updated object
 * @param {Object} options  optional options object to use in the update
 * @return SOMETHING_FIXME
 */
DBCollection.prototype.update = function(criteria, obj, options) {
    throw {exception : "Native Call update() : shouldn't have JS implementation"};
}

 /**
 *

 * Removes all objects from the collection that match the optional criteria.
 *

 *

 * Example :
 *

 * db.myColl.remove( { name: "Joe" });
 *
 * @param {Object} criteria  query which selects the records  to be removed from the collection
 * @return SOMETHING_FIXME
 */
DBCollection.prototype.remove = function(criteria) {
    throw {exception : "Native Call remove() : shouldn't have JS implementation"};
}

/**
 *

 *    @TODO - does something
 *

 *
 *   @param {Object} obj obj to apply
 *   @return SOMETHING_FIXME
 */
DBCollection.prototype.apply = function(obj) {
    throw {exception : "Native Call apply() : shouldn't have JS implementation"};
}

/**
 *

 *    Finds one or more objects in the collection based on the optional specified criteria.
 *

 *
 *

 *   Example :
 *

 *   db.blogposts.find();
 *

 *   db.blogposts.find({title : /10gen/} );
 *

 *   In addition to the criteria, a field selector may be applied to limit the fields that
 *   are returned in the objects.
 *

 *

 *   Example :
 *

 *   db.blogposts.find({}, {comments:true});
 *
 *

 *   The Cursor returned by find can have modifiers applied for more advanced functionalty.
 *   See @see $TODO-LINK_TO_CURSOR_DOC for more informatiion.
 *

 *   @param {Object} criteria Optional criteria for selection of object(s) to be returned
 *   @param {Object} selector Optional selector to specify the fields that should be returned in each object
 *   @return {Cursor} Cursor for the found object set
 */
DBCollection.prototype.find = function(criteria, selector) {
    throw {exception : "Native Call find() : shouldn't have JS implementation"};
}

/**
 *

 *    Finds a single objects in the collection based on the specified criteria.
 *

 *
 *

 *   Example :
 *

 *   db.blogposts.findOne({title : /10gen/} );
 *   @param {Object} criteria Criteria for selection of object to be returned
 *   @return {Object} Found object or null if no objects match the criteria
 */
DBCollection.prototype.findOne = function(criteria) {
    throw {exception : "Native Call findOne(): shouldn't have JS implementation"};
}

/**
 *

 *    Returns a JSON representation of the collection.
 *
 *   @return {String} JSON representation of the collection
 */
DBCollection.prototype.tojson = function() {
    throw {exception : "Native Call tojson() : shouldn't have JS implementation"};
}
<commit_msg>append<commit_after>/**
 *  API for DB Collection objects
 *
 *
 * @fileOverview dbutil.js - 10gen Database Collection  API
 * @name 10gen Database Collection API
 */

 /**
  * Database collection  API
 *  @class 10gen Database Collection  API
 * @docmodule system.database.collection
 */
 var DBCollection = function(){}

/**
 *
Drop all indexes on the specified collection.

 *
 *
Note : alpha: space is not reclaimed.

 *
 *
Note : When you drop an index, any open cursors for the collection are
 *            invalidated (even if those cursors use a different index.

 *
 * @return A result object.  result.ok will be true if successful.
 */
DBCollection.prototype.dropIndexes = function() {
    var res = this._dbCommand( { deleteIndexes: this.getName(), index: "*" } );
    if( res && res.ok && res.ok == 1 ) {
	// this.getDB().system.indexes.remove( { ns: this.getFullName() } );
	// this.getDB().system.namespaces.remove( { name: RegExp(this.getFullName() + "[.][$].*") } );
    }

    this.resetIndexCache();

    return res;
}

/**
 *
Drop a specified index.

 *
 *

 * Name is the name of the index in the system.indexes name field. (Run db.system.indexes.find() to
 *  see example data.)
 *

 *
 *
Note :  alpha: space is not reclaimed

 * @param {String} name of index to delete.
 * @return A result object.  result.ok will be true if successful.
 */
 DBCollection.prototype.dropIndex =  function(index) {
    assert(index);

    if ( ! isString( index ) && isObject( index ) )
    	index = this.genIndexName( index );

    var res = this._dbCommand( { deleteIndexes: this.getName(), index: index } );
    if( res && res.ok && res.ok == 1 ) {
        //this.getDB().system.indexes.remove( { ns: this.getFullName(), name: index } );
	//this.getDB().system.namespaces.remove( { name: this.getFullName() + ".$"+index } );
    }

    this.resetIndexCache();

    return res;
}

/**
 *

 *    Returns an array of the indexes for the collection.
 *

 *

 *   Each entry in the array is an index descriptor object than contains the
 *   following properties :
 *

 *

 *
 name : name of the index

 *
 ns : name of the namespace the index is in

 *
 key : object property that's being indexed

 *

 *
 *   @return database cursor of index descriptor objects
 */
DBCollection.prototype.getIndexes = function(){
    return this.getDB().system.indexes.find( { ns : this.getFullName() } );
}

/**
 *

 *   Re-indexes the collection
 *

 */
DBCollection.prototype.reIndex = function(){

    var coll = this;

    var all = this.getDB().system.indexes.find( { ns : this.getFullName() } ).toArray();

    all.forEach(
        function(z){
            print( z.name );
            coll._dbCommand( { clean: coll + ".$" + z.name } );
            coll.dropIndex( z.name );
            coll.ensureIndex( z.key );
        }
    );
}

/**
 * clean the collection AND all of its indexes
 * note: prints output to the console.
 */
DBCollection.prototype.cleanAll = function(){
    var coll = this;
    print("cleaning " + coll);
    print( tojson( coll.clean() ) );
    var all = this.getDB().system.indexes.find( { ns : this.getFullName() } ).toArray();
    all.forEach(
        function(z){
	    var idx = coll + ".$" + z.name;
	    print("cleaning " + idx);
	    // print("db: " + coll.getDB());
	    print( tojson(coll.getDB()[idx].clean()) );
        }
    );
}

/**
 * Validate the data in a collection, returning some stats.
 * @return An object with several fields set including:
 *

 *
result : textual description of the validation result

 *
ok : true if validate operation was performed

 *
valid : true if the collection is not corrupt

 *

 */
DBCollection.prototype.validate = function() {
    var res = this._dbCommand( { validate: this.getName() } );

    res.valid = false;

    if ( res.result ){
        var str = "-" + tojson( res.result );
        res.valid = ! ( str.match( /exception/ ) || str.match( /corrupt/ ) );

        var p = /lastExtentSize:(\d+)/;
        var r = p.exec( str );
        if ( r ){
            res.lastExtentSize = parseNumber( r[1] );
        }
    }

    return res;
}

/**
 *
drops all objects in the collection

 *
Note :  alpha: space not reclaimed.

 *
 * @return A result object.  result.ok will be true if successful.
 */
DBCollection.prototype.drop = function()
{
    var res = this.dropIndexes();
    if( !res )
	return res;
    if( !res.ok ) {
	res.errmsg = "dropping indexes..." + res.errmsg;
	return res;
    }

    res = this._dbCommand( { drop: this.getName() } );
    if( res && res.ok && res.ok == 1 ) {
	/* note: database does this now.
	   this.getDB().system.namespaces.remove( { name: this.getFullName() } );
	*/
    }
    return res;
}

/**
 *  Drop free lists. Normally not used.
 *  Note this only does the collection itself, not the namespaces of its indexes (see cleanAll).
 */
DBCollection.prototype.clean = function() {
    return this._dbCommand( { clean: this.getName() } );
}

/**
 *

 *  count # of objects in a collection
 *

 *
 *
  You can specify a filter for counting through the optional  parameter.
 *        This parameter specifies condition that must be true for the objects to
 *        be counted.
 *

 *
Example:

 *
 *   c = count({active:true});
 *
 * @param {Object} query Optional query to use to filter objects for counting
 * @return number of objects in the collection that optionally match the filter condition
 */
DBCollection.prototype.count = function(query) {
    var cmd = { count: this.getName() };
    if( query ) cmd.query = query;
    var res = this._dbCommand( cmd );
    if( res && res.n != null ) return res.n;
    throw { exception: "count failed", res: res };
}

/* Run the specified database "command" object.
*/
DBCollection.prototype._dbCommand = function( cmdObj ) {
    return this.getDB().$cmd.findOne(cmdObj);
}

/**
 *

 * Append elements to existing objects in the collection.
 *

 *
 * @param {Object} criteria - query to match
 * @param {Object} fields - fields to append
 */
DBCollection.prototype.append = function(criteria, fields) {
    assert( criteria );
    assert( fields );
    var coll = this.getName();
    return this.getDB().eval(
		      function() {
			  var n = 0;
			  var f = fields;
			  db[coll].find(criteria).forEach(
							  function(o) {
							      Object.extend(o, f);
							      db[coll].save(o);
							      n++;
							  } );
			  return n;
		      }
			    );
}

/**
 *

 *  Calculate a checksum for all objects in this collection.
 *

 */
DBCollection.prototype.checksum = function(){
    var r = this.getDB().eval(
        function(){
	    var sum = 0;
	    var c = db[args[0]].find();
	    while ( c.hasNext() ){
		sum += c.next().hashCode();
	    }

	    var c = db.system.indexes.find( { ns : args[1] } );

	    while(c.hasNext()) {
	      	sum += c.next().hashCode();
	    }

    	    return sum;
        } ,
        this.getName(), this.getFullName()
    );
    return r;
}

DBCollection.prototype.sample = function( num , query , fields ){
    var r = this.getDB().eval(
        function(){
            var a = db[args[0]].find( args[2] || {} , args[3] ).limit(10000).toArray();
            a.shuffle();
            return a.splice( 0 , args[1] );
        } ,
        this.getName() , num , query , fields
    );
    var a = [];
    for ( var k in r ){
        a.push( r[k] );
    }
    return a;
}

var mydb  = arguments[0];

if (!mydb) {
       throw "Error : no db object passed to augmentor for Collection";
}

Object.extend( mydb.getCollectionPrototype() , DBCollection.prototype );

return null;

//
//  other stuff
//

/**
 *  RESET - FOLLOWING IS FOR DOCUMENTATION PURPOSES ONLY
 */
DBCollection.prototype = {};

/**
 *
Returns the name of the collection.

 *
 * @return {String} Name of the collection
 */
DBCollection.prototype.name = function() {
    throw {exception : "Native Call name() : shouldn't have JS implementation"};
}

//       _entries.put( "base" , _base.getName() );

 /**
 *

 * Saves an object in the collection, or update if the object (as identified by _id)
 * is already there.
 *

 *
 *

 * If your object has a presave $TODO_DOC method, that method will be called
 * before the object is saved to the db (before both updates and inserts).
 *

 * @return SOMETHING_FIXME
 */
DBCollection.prototype.save = function(obj) {
    throw {exception : "Native Call save() : shouldn't have JS implementation"};
}

 /**
 *

 * Update an object in the database, based on supplied query criteria and options.  Normally
 * you should just use the save() method.
 *

 *

 * Current options include :
 *

 *

 *
upsert:true - perform an update if exists, or insert new if doesn't exist

 *
ids : false - do not add an object _id field

 *

 *
 *

 * Example :
 *

 * db.myColl.update( { name: "Joe" }, { name: "Joe", age: 20 }, { upsert: true } );
 *
 *
 @see  http://admin.10gen.com/wiki/pub.db.update

 *
 * @param {Object} criteria  query which selects the record @TODO{more than one?} to update
 * @param {Object} obj  updated object
 * @param {Object} options  optional options object to use in the update
 * @return SOMETHING_FIXME
 */
DBCollection.prototype.update = function(criteria, obj, options) {
    throw {exception : "Native Call update() : shouldn't have JS implementation"};
}

 /**
 *

 * Removes all objects from the collection that match the optional criteria.
 *

 *

 * Example :
 *

 * db.myColl.remove( { name: "Joe" });
 *
 * @param {Object} criteria  query which selects the records  to be removed from the collection
 * @return SOMETHING_FIXME
 */
DBCollection.prototype.remove = function(criteria) {
    throw {exception : "Native Call remove() : shouldn't have JS implementation"};
}

/**
 *

 *    @TODO - does something
 *

 *
 *   @param {Object} obj obj to apply
 *   @return SOMETHING_FIXME
 */
DBCollection.prototype.apply = function(obj) {
    throw {exception : "Native Call apply() : shouldn't have JS implementation"};
}

/**
 *

 *    Finds one or more objects in the collection based on the optional specified criteria.
 *

 *
 *

 *   Example :
 *

 *   db.blogposts.find();
 *

 *   db.blogposts.find({title : /10gen/} );
 *

 *   In addition to the criteria, a field selector may be applied to limit the fields that
 *   are returned in the objects.
 *

 *

 *   Example :
 *

 *   db.blogposts.find({}, {comments:true});
 *
 *

 *   The Cursor returned by find can have modifiers applied for more advanced functionalty.
 *   See @see $TODO-LINK_TO_CURSOR_DOC for more informatiion.
 *

 *   @param {Object} criteria Optional criteria for selection of object(s) to be returned
 *   @param {Object} selector Optional selector to specify the fields that should be returned in each object
 *   @return {Cursor} Cursor for the found object set
 */
DBCollection.prototype.find = function(criteria, selector) {
    throw {exception : "Native Call find() : shouldn't have JS implementation"};
}

/**
 *

 *    Finds a single objects in the collection based on the specified criteria.
 *

 *
 *

 *   Example :
 *

 *   db.blogposts.findOne({title : /10gen/} );
 *   @param {Object} criteria Criteria for selection of object to be returned
 *   @return {Object} Found object or null if no objects match the criteria
 */
DBCollection.prototype.findOne = function(criteria) {
    throw {exception : "Native Call findOne(): shouldn't have JS implementation"};
}

/**
 *

 *    Returns a JSON representation of the collection.
 *
 *   @return {String} JSON representation of the collection
 */
DBCollection.prototype.tojson = function() {
    throw {exception : "Native Call tojson() : shouldn't have JS implementation"};
}
<|endoftext|>


<commit_before>import { app, Menu, Tray } from 'electron';
import path from 'path';

import { showDesktopSettings } from './desktopSettings';

let appIcon = null;
const mainWindow = WindowManager.getAll('main')[0];

let audioDeviceMenu = [
  {
    label: 'Loading Devices...',
    enabled: false,
  },
];

if (process.platform === 'darwin') {
  appIcon = new Tray(path.resolve(`${__dirname}/../../../assets/img/macTemplate.png`));
} else {
  appIcon = new Tray(path.resolve(`${__dirname}/../../../assets/img/main_tray.png`));
}

const setContextMenu = () => {
  const contextMenu = Menu.buildFromTemplate([
    { label: 'Show',
      click: () => {
        mainWindow.setSkipTaskbar(false);
        mainWindow.show();
      },
    },
    {
      label: 'Audio Device',
      submenu: audioDeviceMenu,
    },
    { label: 'Settings', click: () => { showDesktopSettings(); } },
    { type: 'separator' },
    { label: 'Quit', click: () => { global.quiting = true; app.quit(); } },
  ]);
  appIcon.setContextMenu(contextMenu);
};
setContextMenu();

/**
 * Toggle the main window (on tray click).
 * If in background, bring to foreground.
 */
function toggleMainWindow() {
  // the mainWindow variable will be GC'd
  // we must find the window ourselves
  const win = WindowManager.getAll('main')[0];

  if (process.platform === 'darwin') { // OS-X - Not tested!
    if (!win.isVisible()) {
      // Show
      win.setSkipTaskbar(false);
      win.show();
    } else {
      // Hide to tray, if configured
      if (Settings.get('minToTray', true)) {
        win.hide();
      }
    }
  } else { // Windows, Linux
    if (win.isMinimized()) {
      win.setSkipTaskbar(false);
      win.restore();
    } else {
      // Hide to tray, if configured
      if (Settings.get('minToTray', true)) {
        win.minimize();
        win.setSkipTaskbar(true);
      }
    }
  }
}

appIcon.setToolTip('Google Play Music');
//appIcon.on('double-click', toggleMainWindow);
appIcon.on('click', toggleMainWindow);

// DEV: Keep the icon in the global scope or it gets garbage collected........
global.appIcon = appIcon;

app.on('before-quit', () => {
  appIcon.destroy();
  delete global.appIcon;
  appIcon = null;
});

Emitter.on('audiooutput:list', (event, devices) => {
  audioDeviceMenu = [];
  devices.forEach((device) => {
    if (device.kind === 'audiooutput') {
      let label = device.label;
      if (!label) {
        switch (device.deviceId) {
          case 'default':
            label = 'System Default';
            break;
          case 'communications':
            label = 'System Default Communications';
            break;
          default:
            label = 'Unknown Device';
            break;
        }
      }
      audioDeviceMenu.push({
        label,
        type: 'radio',
        click: () => {
          Emitter.sendToGooglePlayMusic('audiooutput:set', device.deviceId);
          Settings.set('audiooutput', label);
        },
        checked: (label === Settings.get('audiooutput')),
      });
    }
  });
  setContextMenu();
});

Emitter.sendToGooglePlayMusic('audiooutput:fetch');
Emitter.on('audiooutput:set', () => Emitter.sendToGooglePlayMusic('audiooutput:fetch'));
<commit_msg>fix Travis stupid error<commit_after>import { app, Menu, Tray } from 'electron';
import path from 'path';

import { showDesktopSettings } from './desktopSettings';

let appIcon = null;
const mainWindow = WindowManager.getAll('main')[0];

let audioDeviceMenu = [
  {
    label: 'Loading Devices...',
    enabled: false,
  },
];

if (process.platform === 'darwin') {
  appIcon = new Tray(path.resolve(`${__dirname}/../../../assets/img/macTemplate.png`));
} else {
  appIcon = new Tray(path.resolve(`${__dirname}/../../../assets/img/main_tray.png`));
}

const setContextMenu = () => {
  const contextMenu = Menu.buildFromTemplate([
    { label: 'Show',
      click: () => {
        mainWindow.setSkipTaskbar(false);
        mainWindow.show();
      },
    },
    {
      label: 'Audio Device',
      submenu: audioDeviceMenu,
    },
    { label: 'Settings', click: () => { showDesktopSettings(); } },
    { type: 'separator' },
    { label: 'Quit', click: () => { global.quiting = true; app.quit(); } },
  ]);
  appIcon.setContextMenu(contextMenu);
};
setContextMenu();

/**
 * Toggle the main window (on tray click).
 * If in background, bring to foreground.
 */
function toggleMainWindow() {
  // the mainWindow variable will be GC'd
  // we must find the window ourselves
  const win = WindowManager.getAll('main')[0];

  if (process.platform === 'darwin') { // OS-X - Not tested!
    if (!win.isVisible()) {
      // Show
      win.setSkipTaskbar(false);
      win.show();
    } else {
      // Hide to tray, if configured
      if (Settings.get('minToTray', true)) {
        win.hide();
      }
    }
  } else { // Windows, Linux
    if (win.isMinimized()) {
      win.setSkipTaskbar(false);
      win.restore();
    } else {
      // Hide to tray, if configured
      if (Settings.get('minToTray', true)) {
        win.minimize();
        win.setSkipTaskbar(true);
      }
    }
  }
}

appIcon.setToolTip('Google Play Music');
// appIcon.on('double-click', toggleMainWindow);
appIcon.on('click', toggleMainWindow);

// DEV: Keep the icon in the global scope or it gets garbage collected........
global.appIcon = appIcon;

app.on('before-quit', () => {
  appIcon.destroy();
  delete global.appIcon;
  appIcon = null;
});

Emitter.on('audiooutput:list', (event, devices) => {
  audioDeviceMenu = [];
  devices.forEach((device) => {
    if (device.kind === 'audiooutput') {
      let label = device.label;
      if (!label) {
        switch (device.deviceId) {
          case 'default':
            label = 'System Default';
            break;
          case 'communications':
            label = 'System Default Communications';
            break;
          default:
            label = 'Unknown Device';
            break;
        }
      }
      audioDeviceMenu.push({
        label,
        type: 'radio',
        click: () => {
          Emitter.sendToGooglePlayMusic('audiooutput:set', device.deviceId);
          Settings.set('audiooutput', label);
        },
        checked: (label === Settings.get('audiooutput')),
      });
    }
  });
  setContextMenu();
});

Emitter.sendToGooglePlayMusic('audiooutput:fetch');
Emitter.on('audiooutput:set', () => Emitter.sendToGooglePlayMusic('audiooutput:fetch'));
<|endoftext|>


<commit_before>import {assert} from 'chai';
import sinon from 'sinon';
import Cell from '../../src/Cell';

describe('Cell', () => {
  it('Should properly create cell with default arguments', () => {
    const cell = new Cell();

    assert.instanceOf(cell, Cell);
    assert.equal(cell._char, ' ');
    assert.equal(cell._x, 0);
    assert.equal(cell._y, 0);
    assert.deepEqual(cell._background, {r: -1, g: -1, b: -1});
    assert.deepEqual(cell._foreground, {r: -1, g: -1, b: -1});
    assert.deepEqual(cell._display, {
      bold: false,
      dim: false,
      underlined: false,
      blink: false,
      reverse: false,
      hidden: false
    });
  });

  it('Should properly create cell with custom arguments', () => {
    const cell = new Cell(' ', {
      x: 10,
      y: 10,
      background: {r: 1, g: 2, b: 3},
      foreground: {r: 1, g: 2, b: 3},
      display: {bold: true}
    });

    assert.instanceOf(cell, Cell);
    assert.equal(cell._char, ' ');
    assert.equal(cell._x, 10);
    assert.equal(cell._y, 10);
    assert.deepEqual(cell._background, {r: 1, g: 2, b: 3});
    assert.deepEqual(cell._foreground, {r: 1, g: 2, b: 3});
    assert.deepEqual(cell._display, {
      bold: true,
      dim: false,
      underlined: false,
      blink: false,
      reverse: false,
      hidden: false
    });
  });

  it('Should properly get/set char', () => {
    const cell = new Cell();

    assert.equal(cell.getChar(), ' ');
    assert.instanceOf(cell.setChar('t'), Cell);
    assert.equal(cell.getChar(), 't');
    assert.instanceOf(cell.setChar('long text'), Cell);
    assert.equal(cell.getChar(), 'l');
  });

  it('Should properly get/set X coordinate', () => {
    const cell = new Cell();

    assert.equal(cell.getX(), 0);
    assert.instanceOf(cell.setX(40), Cell);
    assert.equal(cell.getX(), 40);
    assert.instanceOf(cell.setX(50.99), Cell);
    assert.equal(cell.getX(), 50);
  });

  it('Should properly get/set Y coordinate', () => {
    const cell = new Cell();

    assert.equal(cell.getY(), 0);
    assert.instanceOf(cell.setY(40), Cell);
    assert.equal(cell.getY(), 40);
    assert.instanceOf(cell.setY(50.99), Cell);
    assert.equal(cell.getY(), 50);
  });

  it('Should properly get/set background color', () => {
    const cell = new Cell();

    assert.deepEqual(cell.getBackground(), {r: -1, g: -1, b: -1});
    assert.instanceOf(cell.setBackground(0, 100, 200), Cell);
    assert.deepEqual(cell.getBackground(), {r: 0, g: 100, b: 200});
    assert.instanceOf(cell.setBackground(), Cell);
    assert.deepEqual(cell.getBackground(), {r: -1, g: -1, b: -1});
  });

  it('Should properly get/set foreground color', () => {
    const cell = new Cell();

    assert.deepEqual(cell.getForeground(), {r: -1, g: -1, b: -1});
    assert.instanceOf(cell.setForeground(0, 100, 200), Cell);
    assert.deepEqual(cell.getForeground(), {r: 0, g: 100, b: 200});
    assert.instanceOf(cell.setForeground(), Cell);
    assert.deepEqual(cell.getForeground(), {r: -1, g: -1, b: -1});
  });

  it('Should properly get/set display modes', () => {
    const cell = new Cell();

    assert.deepEqual(cell.getDisplay(), {
      bold: false,
      dim: false,
      underlined: false,
      blink: false,
      reverse: false,
      hidden: false
    });

    assert.instanceOf(cell.setDisplay(true, false, true, false, false, false), Cell);
    assert.deepEqual(cell.getDisplay(), {
      bold: true,
      dim: false,
      underlined: true,
      blink: false,
      reverse: false,
      hidden: false
    });

    assert.instanceOf(cell.setDisplay(), Cell);
    assert.deepEqual(cell.getDisplay(), {
      bold: false,
      dim: false,
      underlined: false,
      blink: false,
      reverse: false,
      hidden: false
    });
  });

  it('Should properly mark cell as modified', () => {
    const cell = new Cell();

    assert.notOk(cell.isModified());
    assert.instanceOf(cell.setModified(false), Cell);
    assert.notOk(cell.isModified());
    assert.instanceOf(cell.setModified(), Cell);
    assert.ok(cell.isModified());
  });

  it('Should properly reset the cell contents and display settings', () => {
    const cell = new Cell();
    const mock = sinon.mock(cell);

    mock.expects('setChar').once().withExactArgs(' ').returns(cell);
    mock.expects('setBackground').once().withExactArgs(-1, -1, -1).returns(cell);
    mock.expects('setForeground').once().withExactArgs(-1, -1, -1).returns(cell);
    mock.expects('setDisplay').once().withExactArgs(false, false, false, false, false, false).returns(cell);

    assert.instanceOf(cell.reset(), Cell);
    mock.verify();
  });

  it('Should properly convert Cell into ASCII sequence', () => {
    const cell = new Cell();

    assert.equal(cell.toString(), '\u001b[1;1f \u001b[0m');
    assert.instanceOf(cell.setX(20), Cell);
    assert.equal(cell.toString(), '\u001b[1;21f \u001b[0m');
    assert.instanceOf(cell.setY(10), Cell);
    assert.equal(cell.toString(), '\u001b[11;21f \u001b[0m');
    assert.instanceOf(cell.setBackground(0, 100, 200), Cell);
    assert.equal(cell.toString(), '\u001b[11;21f\u001b[48;2;0;100;200m \u001b[0m');
    assert.instanceOf(cell.setForeground(200, 100, 0), Cell);
    assert.equal(cell.toString(), '\u001b[11;21f\u001b[48;2;0;100;200m\u001b[38;2;200;100;0m \u001b[0m');
    assert.instanceOf(cell.setDisplay(true, false, true, false, false, false), Cell);
    assert.equal(cell.toString(), '\u001b[11;21f\u001b[48;2;0;100;200m\u001b[38;2;200;100;0m\u001b[1m\u001b[4m \u001b[0m');
  });

  it('Should properly create Cell instance from static create()', () => {
    const cell = Cell.create(' ', {x: 10, y: 20});

    assert.instanceOf(cell, Cell);
    assert.equal(cell._char, ' ');
    assert.equal(cell._x, 10);
    assert.equal(cell._y, 20);
    assert.deepEqual(cell._background, {r: -1, g: -1, b: -1});
    assert.deepEqual(cell._foreground, {r: -1, g: -1, b: -1});
    assert.deepEqual(cell._display, {
      bold: false,
      dim: false,
      underlined: false,
      blink: false,
      reverse: false,
      hidden: false
    });
  })
});
<commit_msg>test(cell): Improve test coverage<commit_after>import {assert} from 'chai';
import sinon from 'sinon';
import Cell from '../../src/Cell';

describe('Cell', () => {
  it('Should properly create cell with default arguments', () => {
    const cell = new Cell();

    assert.instanceOf(cell, Cell);
    assert.equal(cell._char, ' ');
    assert.equal(cell._x, 0);
    assert.equal(cell._y, 0);
    assert.deepEqual(cell._background, {r: -1, g: -1, b: -1});
    assert.deepEqual(cell._foreground, {r: -1, g: -1, b: -1});
    assert.deepEqual(cell._display, {
      bold: false,
      dim: false,
      underlined: false,
      blink: false,
      reverse: false,
      hidden: false
    });
  });

  it('Should properly create cell with custom arguments', () => {
    const cell = new Cell(' ', {
      x: 10,
      y: 10,
      background: {r: 1, g: 2, b: 3},
      foreground: {r: 1, g: 2, b: 3},
      display: {bold: true}
    });

    assert.instanceOf(cell, Cell);
    assert.equal(cell._char, ' ');
    assert.equal(cell._x, 10);
    assert.equal(cell._y, 10);
    assert.deepEqual(cell._background, {r: 1, g: 2, b: 3});
    assert.deepEqual(cell._foreground, {r: 1, g: 2, b: 3});
    assert.deepEqual(cell._display, {
      bold: true,
      dim: false,
      underlined: false,
      blink: false,
      reverse: false,
      hidden: false
    });
  });

  it('Should properly get/set char', () => {
    const cell = new Cell();

    assert.equal(cell.getChar(), ' ');
    assert.instanceOf(cell.setChar('t'), Cell);
    assert.equal(cell.getChar(), 't');
    assert.instanceOf(cell.setChar('long text'), Cell);
    assert.equal(cell.getChar(), 'l');
  });

  it('Should properly get/set X coordinate', () => {
    const cell = new Cell();

    assert.equal(cell.getX(), 0);
    assert.instanceOf(cell.setX(40), Cell);
    assert.equal(cell.getX(), 40);
    assert.instanceOf(cell.setX(50.99), Cell);
    assert.equal(cell.getX(), 50);
  });

  it('Should properly get/set Y coordinate', () => {
    const cell = new Cell();

    assert.equal(cell.getY(), 0);
    assert.instanceOf(cell.setY(40), Cell);
    assert.equal(cell.getY(), 40);
    assert.instanceOf(cell.setY(50.99), Cell);
    assert.equal(cell.getY(), 50);
  });

  it('Should properly get/set background color', () => {
    const cell = new Cell();

    assert.deepEqual(cell.getBackground(), {r: -1, g: -1, b: -1});
    assert.instanceOf(cell.setBackground(0, 100, 200), Cell);
    assert.deepEqual(cell.getBackground(), {r: 0, g: 100, b: 200});
    assert.instanceOf(cell.setBackground(), Cell);
    assert.deepEqual(cell.getBackground(), {r: -1, g: -1, b: -1});
  });

  it('Should properly get/set foreground color', () => {
    const cell = new Cell();

    assert.deepEqual(cell.getForeground(), {r: -1, g: -1, b: -1});
    assert.instanceOf(cell.setForeground(0, 100, 200), Cell);
    assert.deepEqual(cell.getForeground(), {r: 0, g: 100, b: 200});
    assert.instanceOf(cell.setForeground(), Cell);
    assert.deepEqual(cell.getForeground(), {r: -1, g: -1, b: -1});
  });

  it('Should properly get/set display modes', () => {
    const cell = new Cell();

    assert.deepEqual(cell.getDisplay(), {
      bold: false,
      dim: false,
      underlined: false,
      blink: false,
      reverse: false,
      hidden: false
    });

    assert.instanceOf(cell.setDisplay(true, false, true, false, false, false), Cell);
    assert.deepEqual(cell.getDisplay(), {
      bold: true,
      dim: false,
      underlined: true,
      blink: false,
      reverse: false,
      hidden: false
    });

    assert.instanceOf(cell.setDisplay(), Cell);
    assert.deepEqual(cell.getDisplay(), {
      bold: false,
      dim: false,
      underlined: false,
      blink: false,
      reverse: false,
      hidden: false
    });
  });

  it('Should properly mark cell as modified', () => {
    const cell = new Cell();

    assert.notOk(cell.isModified());
    assert.instanceOf(cell.setModified(false), Cell);
    assert.notOk(cell.isModified());
    assert.instanceOf(cell.setModified(), Cell);
    assert.ok(cell.isModified());
  });

  it('Should properly reset the cell contents and display settings', () => {
    const cell = new Cell();
    const mock = sinon.mock(cell);

    mock.expects('setChar').once().withExactArgs(' ').returns(cell);
    mock.expects('setBackground').once().withExactArgs(-1, -1, -1).returns(cell);
    mock.expects('setForeground').once().withExactArgs(-1, -1, -1).returns(cell);
    mock.expects('setDisplay').once().withExactArgs(false, false, false, false, false, false).returns(cell);

    assert.instanceOf(cell.reset(), Cell);
    mock.verify();
  });

  it('Should properly convert Cell into ASCII sequence', () => {
    const cell = new Cell();

    assert.equal(cell.toString(), '\u001b[1;1f \u001b[0m');
    assert.instanceOf(cell.setX(20), Cell);
    assert.equal(cell.toString(), '\u001b[1;21f \u001b[0m');
    assert.instanceOf(cell.setY(10), Cell);
    assert.equal(cell.toString(), '\u001b[11;21f \u001b[0m');
    assert.instanceOf(cell.setBackground(0, 100, 200), Cell);
    assert.equal(cell.toString(), '\u001b[11;21f\u001b[48;2;0;100;200m \u001b[0m');
    assert.instanceOf(cell.setForeground(200, 100, 0), Cell);
    assert.equal(cell.toString(), '\u001b[11;21f\u001b[48;2;0;100;200m\u001b[38;2;200;100;0m \u001b[0m');
    assert.instanceOf(cell.setDisplay(true, true, true, true, true, true), Cell);
    assert.equal(cell.toString(), '\u001b[11;21f\u001b[48;2;0;100;200m\u001b[38;2;200;100;0m\u001b[1m\u001b[2m\u001b[4m\u001b[5m\u001b[7m\u001b[8m \u001b[0m');
  });

  it('Should properly create Cell instance from static create()', () => {
    const cell = Cell.create(' ', {x: 10, y: 20});

    assert.instanceOf(cell, Cell);
    assert.equal(cell._char, ' ');
    assert.equal(cell._x, 10);
    assert.equal(cell._y, 20);
    assert.deepEqual(cell._background, {r: -1, g: -1, b: -1});
    assert.deepEqual(cell._foreground, {r: -1, g: -1, b: -1});
    assert.deepEqual(cell._display, {
      bold: false,
      dim: false,
      underlined: false,
      blink: false,
      reverse: false,
      hidden: false
    });
  })
});
<|endoftext|>


<commit_before>import {assert} from 'chai';
import sinon from 'sinon';
import Text from '../../src/Text';
import Cursor from 'kittik-cursor';

const cursor = Cursor.create();

describe('Shape::Text', () => {
  it('Should properly create Text instance', () => {
    const text = new Text(cursor);
    assert.instanceOf(text, Text);
  });

  it('Should properly get actual width of the shape', () => {
    const text = new Text(cursor, {text: 'test'});
    assert.equal(text.getWidth(), 4);
  });

  it('Should properly get actual height of the shape', () => {
    const text = new Text(cursor, {text: 'test'});
    assert.equal(text.getHeight(), 1);
  });

  it('Should properly get/set bold mode', () => {
    const text = new Text(cursor);
    assert.notOk(text.isBold());
    assert.instanceOf(text.setBold(true), Text);
    assert.ok(text.isBold());
  });

  it('Should properly get/set dim mode', () => {
    const text = new Text(cursor);
    assert.notOk(text.isDim());
    assert.instanceOf(text.setDim(true), Text);
    assert.ok(text.isDim());
  });

  it('Should properly get/set underlined mode', () => {
    const text = new Text(cursor);
    assert.notOk(text.isUnderlined());
    assert.instanceOf(text.setUnderlined(true), Text);
    assert.ok(text.isUnderlined());
  });

  it('Should properly get/set blink mode', () => {
    const text = new Text(cursor);
    assert.notOk(text.isBlink());
    assert.instanceOf(text.setBlink(true), Text);
    assert.ok(text.setBlink());
  });

  it('Should properly get/set reverse mode', () => {
    const text = new Text(cursor);
    assert.notOk(text.isReverse());
    assert.instanceOf(text.setReverse(true), Text);
    assert.ok(text.isReverse());
  });

  it('Should properly get/set hidden mode', () => {
    const text = new Text(cursor);
    assert.notOk(text.isHidden());
    assert.instanceOf(text.setHidden(true), Text);
    assert.ok(text.isHidden());
  });

  it('Should properly throw exception if align is not supported', () => {
    const text = new Text(cursor);
    assert.throws(() => text.setAlign('wrong'), Error, 'Unknown align option: wrong');
  });

  it('Should properly get/set align', () => {
    const text = new Text(cursor);
    assert.equal(text.getAlign(), 'center');
    assert.instanceOf(text.setAlign('right'), Text);
    assert.equal(text.getAlign(), 'right');
  });

  it('Should properly render with default options', () => {
    const cursor = Cursor.create();
    const text = new Text(cursor);
    const mock = sinon.mock(cursor);

    mock.expects('foreground').once().withExactArgs(false).returns(cursor);
    mock.expects('background').once().withExactArgs(false).returns(cursor);
    mock.expects('bold').once().withArgs(false).returns(cursor);
    mock.expects('dim').once().withArgs(false).returns(cursor);
    mock.expects('underlined').once().withArgs(false).returns(cursor);
    mock.expects('blink').once().withArgs(false).returns(cursor);
    mock.expects('reverse').once().withArgs(false).returns(cursor);
    mock.expects('hidden').once().withArgs(false).returns(cursor);
    mock.expects('moveTo').once(10, 10).returns(cursor);
    mock.expects('write').once().withArgs('');

    text.render();

    mock.verify();
  });

  it('Should properly render with text align to left', () => {
    const cursor = Cursor.create();
    const text = new Text(cursor, {align: 'left'});
    const mock = sinon.mock(cursor);

    mock.expects('foreground').once().withExactArgs(false).returns(cursor);
    mock.expects('background').once().withExactArgs(false).returns(cursor);
    mock.expects('bold').once().withArgs(false).returns(cursor);
    mock.expects('dim').once().withArgs(false).returns(cursor);
    mock.expects('underlined').once().withArgs(false).returns(cursor);
    mock.expects('blink').once().withArgs(false).returns(cursor);
    mock.expects('reverse').once().withArgs(false).returns(cursor);
    mock.expects('hidden').once().withArgs(false).returns(cursor);
    mock.expects('moveTo').once(10, 10).returns(cursor);
    mock.expects('write').once().withArgs('');

    text.render();

    mock.verify();
  });

  it('Should properly render with text align to center', () => {
    const cursor = Cursor.create();
    const text = new Text(cursor, {align: 'center'});
    const mock = sinon.mock(cursor);

    mock.expects('foreground').once().withExactArgs(false).returns(cursor);
    mock.expects('background').once().withExactArgs(false).returns(cursor);
    mock.expects('bold').once().withArgs(false).returns(cursor);
    mock.expects('dim').once().withArgs(false).returns(cursor);
    mock.expects('underlined').once().withArgs(false).returns(cursor);
    mock.expects('blink').once().withArgs(false).returns(cursor);
    mock.expects('reverse').once().withArgs(false).returns(cursor);
    mock.expects('hidden').once().withArgs(false).returns(cursor);
    mock.expects('moveTo').once(10, 10).returns(cursor);
    mock.expects('write').once().withArgs('');

    text.render();

    mock.verify();
  });

  it('Should properly render with text align to right', () => {
    const cursor = Cursor.create();
    const text = new Text(cursor, {align: 'right'});
    const mock = sinon.mock(cursor);

    mock.expects('foreground').once().withExactArgs(false).returns(cursor);
    mock.expects('background').once().withExactArgs(false).returns(cursor);
    mock.expects('bold').once().withArgs(false).returns(cursor);
    mock.expects('dim').once().withArgs(false).returns(cursor);
    mock.expects('underlined').once().withArgs(false).returns(cursor);
    mock.expects('blink').once().withArgs(false).returns(cursor);
    mock.expects('reverse').once().withArgs(false).returns(cursor);
    mock.expects('hidden').once().withArgs(false).returns(cursor);
    mock.expects('moveTo').once(10, 10).returns(cursor);
    mock.expects('write').once().withArgs('');

    text.render();

    mock.verify();
  });

  it('Should properly render with custom options', () => {
    const cursor = Cursor.create();
    const mock = sinon.mock(cursor);
    const text = Text.create(cursor, {
      text: 'test',
      x: 'left',
      y: 1,
      background: 'yellow',
      foreground: 'black',
      bold: true,
      underlined: true
    });

    mock.expects('foreground').once().withArgs('black').returns(cursor);
    mock.expects('background').once().withArgs('yellow').returns(cursor);
    mock.expects('bold').once().withArgs(true).returns(cursor);
    mock.expects('dim').once().withArgs(false).returns(cursor);
    mock.expects('underlined').once().withArgs(true).returns(cursor);
    mock.expects('blink').once().withArgs(false).returns(cursor);
    mock.expects('reverse').once().withArgs(false).returns(cursor);
    mock.expects('hidden').once().withArgs(false).returns(cursor);
    mock.expects('moveTo').once(1, 1).returns(cursor);
    mock.expects('write').once().withArgs('test');

    text.render();

    mock.verify();
  });

  it('Should properly render multi-lined text', () => {
    const cursor = Cursor.create();
    const mock = sinon.mock(cursor);
    const text = Text.create(cursor, {
      text: 'test\nanother',
      x: 'left',
      y: 1,
      background: 'yellow',
      foreground: 'black',
      bold: true,
      underlined: true
    });

    mock.expects('foreground').once().withArgs('black').returns(cursor);
    mock.expects('background').once().withArgs('yellow').returns(cursor);
    mock.expects('bold').once().withArgs(true).returns(cursor);
    mock.expects('dim').once().withArgs(false).returns(cursor);
    mock.expects('underlined').once().withArgs(true).returns(cursor);
    mock.expects('blink').once().withArgs(false).returns(cursor);
    mock.expects('reverse').once().withArgs(false).returns(cursor);
    mock.expects('hidden').once().withArgs(false).returns(cursor);
    mock.expects('moveTo').twice().returns(cursor);
    mock.expects('write').twice().returns(cursor);

    text.render();

    mock.verify();
  });

  it('Should properly serialize shape to Object representation', () => {
    const text = Text.create(cursor, {text: 'test', bold: true});
    const obj = text.toObject();

    assert.deepEqual(obj, {
      type: 'Text',
      options: {
        text: 'test',
        width: 15,
        height: 5,
        x: 10,
        y: 10,
        background: false,
        foreground: false,
        bold: true,
        dim: false,
        underlined: false,
        blink: false,
        reverse: false,
        hidden: false,
        align: 'center'
      }
    });
  });

  it('Should properly create text from Object representation', () => {
    const obj = {
      type: 'Text',
      options: {
        text: 'test',
        x: 'left',
        y: 'top',
        background: undefined,
        foreground: undefined,
        bold: true,
        underlined: true,
        align: 'right'
      }
    };

    const text = Text.fromObject(obj, cursor);
    assert.instanceOf(text, Text);
    assert.instanceOf(text.getCursor(), Cursor);
    assert.equal(text.getText(), 'test');
    assert.equal(text.getWidth(), 4);
    assert.equal(text.getHeight(), 1);
    assert.equal(text.getX(), 0);
    assert.equal(text.getY(), 0);
    assert.notOk(text.getBackground());
    assert.notOk(text.getForeground());
    assert.ok(text.isBold());
    assert.notOk(text.isDim());
    assert.ok(text.isUnderlined());
    assert.notOk(text.isBlink());
    assert.notOk(text.isReverse());
    assert.notOk(text.isHidden());
    assert.equal(text.getAlign(), 'right');
  });
});
<commit_msg>fix(shape): Fix issue with True Color<commit_after>import {assert} from 'chai';
import sinon from 'sinon';
import Text from '../../src/Text';
import Cursor from 'kittik-cursor';

const cursor = Cursor.create();

describe('Shape::Text', () => {
  it('Should properly create Text instance', () => {
    const text = new Text(cursor);
    assert.instanceOf(text, Text);
  });

  it('Should properly get actual width of the shape', () => {
    const text = new Text(cursor, {text: 'test'});
    assert.equal(text.getWidth(), 4);
  });

  it('Should properly get actual height of the shape', () => {
    const text = new Text(cursor, {text: 'test'});
    assert.equal(text.getHeight(), 1);
  });

  it('Should properly get/set bold mode', () => {
    const text = new Text(cursor);
    assert.notOk(text.isBold());
    assert.instanceOf(text.setBold(true), Text);
    assert.ok(text.isBold());
  });

  it('Should properly get/set dim mode', () => {
    const text = new Text(cursor);
    assert.notOk(text.isDim());
    assert.instanceOf(text.setDim(true), Text);
    assert.ok(text.isDim());
  });

  it('Should properly get/set underlined mode', () => {
    const text = new Text(cursor);
    assert.notOk(text.isUnderlined());
    assert.instanceOf(text.setUnderlined(true), Text);
    assert.ok(text.isUnderlined());
  });

  it('Should properly get/set blink mode', () => {
    const text = new Text(cursor);
    assert.notOk(text.isBlink());
    assert.instanceOf(text.setBlink(true), Text);
    assert.ok(text.setBlink());
  });

  it('Should properly get/set reverse mode', () => {
    const text = new Text(cursor);
    assert.notOk(text.isReverse());
    assert.instanceOf(text.setReverse(true), Text);
    assert.ok(text.isReverse());
  });

  it('Should properly get/set hidden mode', () => {
    const text = new Text(cursor);
    assert.notOk(text.isHidden());
    assert.instanceOf(text.setHidden(true), Text);
    assert.ok(text.isHidden());
  });

  it('Should properly throw exception if align is not supported', () => {
    const text = new Text(cursor);
    assert.throws(() => text.setAlign('wrong'), Error, 'Unknown align option: wrong');
  });

  it('Should properly get/set align', () => {
    const text = new Text(cursor);
    assert.equal(text.getAlign(), 'center');
    assert.instanceOf(text.setAlign('right'), Text);
    assert.equal(text.getAlign(), 'right');
  });

  it('Should properly render with default options', () => {
    const cursor = Cursor.create();
    const text = new Text(cursor);
    const mock = sinon.mock(cursor);

    mock.expects('foreground').once().withExactArgs('none').returns(cursor);
    mock.expects('background').once().withExactArgs('none').returns(cursor);
    mock.expects('bold').once().withArgs(false).returns(cursor);
    mock.expects('dim').once().withArgs(false).returns(cursor);
    mock.expects('underlined').once().withArgs(false).returns(cursor);
    mock.expects('blink').once().withArgs(false).returns(cursor);
    mock.expects('reverse').once().withArgs(false).returns(cursor);
    mock.expects('hidden').once().withArgs(false).returns(cursor);
    mock.expects('moveTo').once(10, 10).returns(cursor);
    mock.expects('write').once().withArgs('');

    text.render();

    mock.verify();
  });

  it('Should properly render with text align to left', () => {
    const cursor = Cursor.create();
    const text = new Text(cursor, {align: 'left'});
    const mock = sinon.mock(cursor);

    mock.expects('foreground').once().withExactArgs('none').returns(cursor);
    mock.expects('background').once().withExactArgs('none').returns(cursor);
    mock.expects('bold').once().withArgs(false).returns(cursor);
    mock.expects('dim').once().withArgs(false).returns(cursor);
    mock.expects('underlined').once().withArgs(false).returns(cursor);
    mock.expects('blink').once().withArgs(false).returns(cursor);
    mock.expects('reverse').once().withArgs(false).returns(cursor);
    mock.expects('hidden').once().withArgs(false).returns(cursor);
    mock.expects('moveTo').once(10, 10).returns(cursor);
    mock.expects('write').once().withArgs('');

    text.render();

    mock.verify();
  });

  it('Should properly render with text align to center', () => {
    const cursor = Cursor.create();
    const text = new Text(cursor, {align: 'center'});
    const mock = sinon.mock(cursor);

    mock.expects('foreground').once().withExactArgs('none').returns(cursor);
    mock.expects('background').once().withExactArgs('none').returns(cursor);
    mock.expects('bold').once().withArgs(false).returns(cursor);
    mock.expects('dim').once().withArgs(false).returns(cursor);
    mock.expects('underlined').once().withArgs(false).returns(cursor);
    mock.expects('blink').once().withArgs(false).returns(cursor);
    mock.expects('reverse').once().withArgs(false).returns(cursor);
    mock.expects('hidden').once().withArgs(false).returns(cursor);
    mock.expects('moveTo').once(10, 10).returns(cursor);
    mock.expects('write').once().withArgs('');

    text.render();

    mock.verify();
  });

  it('Should properly render with text align to right', () => {
    const cursor = Cursor.create();
    const text = new Text(cursor, {align: 'right'});
    const mock = sinon.mock(cursor);

    mock.expects('foreground').once().withExactArgs('none').returns(cursor);
    mock.expects('background').once().withExactArgs('none').returns(cursor);
    mock.expects('bold').once().withArgs(false).returns(cursor);
    mock.expects('dim').once().withArgs(false).returns(cursor);
    mock.expects('underlined').once().withArgs(false).returns(cursor);
    mock.expects('blink').once().withArgs(false).returns(cursor);
    mock.expects('reverse').once().withArgs(false).returns(cursor);
    mock.expects('hidden').once().withArgs(false).returns(cursor);
    mock.expects('moveTo').once(10, 10).returns(cursor);
    mock.expects('write').once().withArgs('');

    text.render();

    mock.verify();
  });

  it('Should properly render with custom options', () => {
    const cursor = Cursor.create();
    const mock = sinon.mock(cursor);
    const text = Text.create(cursor, {
      text: 'test',
      x: 'left',
      y: 1,
      background: 'yellow',
      foreground: 'black',
      bold: true,
      underlined: true
    });

    mock.expects('foreground').once().withArgs('black').returns(cursor);
    mock.expects('background').once().withArgs('yellow').returns(cursor);
    mock.expects('bold').once().withArgs(true).returns(cursor);
    mock.expects('dim').once().withArgs(false).returns(cursor);
    mock.expects('underlined').once().withArgs(true).returns(cursor);
    mock.expects('blink').once().withArgs(false).returns(cursor);
    mock.expects('reverse').once().withArgs(false).returns(cursor);
    mock.expects('hidden').once().withArgs(false).returns(cursor);
    mock.expects('moveTo').once(1, 1).returns(cursor);
    mock.expects('write').once().withArgs('test');

    text.render();

    mock.verify();
  });

  it('Should properly render multi-lined text', () => {
    const cursor = Cursor.create();
    const mock = sinon.mock(cursor);
    const text = Text.create(cursor, {
      text: 'test\nanother',
      x: 'left',
      y: 1,
      background: 'yellow',
      foreground: 'black',
      bold: true,
      underlined: true
    });

    mock.expects('foreground').once().withArgs('black').returns(cursor);
    mock.expects('background').once().withArgs('yellow').returns(cursor);
    mock.expects('bold').once().withArgs(true).returns(cursor);
    mock.expects('dim').once().withArgs(false).returns(cursor);
    mock.expects('underlined').once().withArgs(true).returns(cursor);
    mock.expects('blink').once().withArgs(false).returns(cursor);
    mock.expects('reverse').once().withArgs(false).returns(cursor);
    mock.expects('hidden').once().withArgs(false).returns(cursor);
    mock.expects('moveTo').twice().returns(cursor);
    mock.expects('write').twice().returns(cursor);

    text.render();

    mock.verify();
  });

  it('Should properly serialize shape to Object representation', () => {
    const text = Text.create(cursor, {text: 'test', bold: true});
    const obj = text.toObject();

    assert.deepEqual(obj, {
      type: 'Text',
      options: {
        text: 'test',
        width: 15,
        height: 5,
        x: 10,
        y: 10,
        background: 'none',
        foreground: 'none',
        bold: true,
        dim: false,
        underlined: false,
        blink: false,
        reverse: false,
        hidden: false,
        align: 'center'
      }
    });
  });

  it('Should properly create text from Object representation', () => {
    const obj = {
      type: 'Text',
      options: {
        text: 'test',
        x: 'left',
        y: 'top',
        background: undefined,
        foreground: undefined,
        bold: true,
        underlined: true,
        align: 'right'
      }
    };

    const text = Text.fromObject(obj, cursor);
    assert.instanceOf(text, Text);
    assert.instanceOf(text.getCursor(), Cursor);
    assert.equal(text.getText(), 'test');
    assert.equal(text.getWidth(), 4);
    assert.equal(text.getHeight(), 1);
    assert.equal(text.getX(), 0);
    assert.equal(text.getY(), 0);
    assert.equal(text.getBackground(), 'none');
    assert.equal(text.getForeground(), 'none');
    assert.ok(text.isBold());
    assert.notOk(text.isDim());
    assert.ok(text.isUnderlined());
    assert.notOk(text.isBlink());
    assert.notOk(text.isReverse());
    assert.notOk(text.isHidden());
    assert.equal(text.getAlign(), 'right');
  });
});
<|endoftext|>


<commit_before>/*
Name:         piwik
Description:  Access a Piwik API from node.js.
Source:       https://github.com/fvdm/nodejs-piwik
Feedback:     https://github.com/fvdm/nodejs-piwik/issues
License:      Unlicense / Public Domain (see UNLICENSE file)
*/

var urltool = require('url')
var querystring = require('querystring')
var http = null

var app = {settings: {}}

// SETUP basics
app.setup = function( baseURL, token ) {
  var url = urltool.parse( baseURL, true )

  switch( url.protocol ) {
    case 'http:':
      http = require('http')
      app.settings.apiport = url.port || 80
      break

    case 'https:':
      http = require('https')
      app.settings.apiport = url.port || 443
      break
  }

  // token in baseURL?
  if( url.query && url.query.token_auth ) {
    app.settings.token = url.query.token_auth
  }

  // override with custom token, if any
  if( token ) {
    app.settings.token = token
  }

  app.settings.apihost = url.hostname
  app.settings.apipath = url.pathname

  return app
}

// API call
app.api = function( vars, cb ) {
  var vars = typeof vars == 'object' ? vars : {}
  vars.module = 'API'
  vars.format = 'JSON'
  vars.token_auth = app.settings.token
  get( {query: vars}, cb )
  return app
}

// Track
app.track = function( vars, cb ) {
  vars = typeof vars === 'object' ? vars : {}
  vars.rec = 1
  vars.apiv = 1
  if( app.settings.token ) {
    vars.token_auth = app.settings.token
  }
  get( {path: 'piwik.php', query: vars}, function( data ) {
    cb( data.substr(0,3) === 'GIF' )
  })
  return app
}

// HTTP GET
function get( props, cb ) {
  var keys = Object.keys( props.query )
  for( var i = 0; i < keys.length; i++ ) {
    var key = keys[i]
    if( typeof props.query[ key ] === 'object' ) {
      props.query[ key ] = JSON.stringify( props.query[ key ] )
    }
  }

  http.get(
    {
      host: app.settings.apihost,
      port: app.settings.apiport,
      path: app.settings.apipath + (props.path || '') +'?'+ querystring.stringify( props.query )
    },
    function( response ) {
      var data = []
      var size = 0

      response.on( 'data', function( chunk ) {
        data.push( chunk )
        size += chunk.length
      })

      response.on( 'end', function() {
        data = new Buffer.concat( data, size ).toString().trim()
        try { data = JSON.parse( data ) } catch(e) {}
        cb( data )
      })
    }
  )
}

// ready
module.exports = app
<commit_msg>Use the correct protocol<commit_after>/*
Name:         piwik
Description:  Access a Piwik API from node.js.
Source:       https://github.com/fvdm/nodejs-piwik
Feedback:     https://github.com/fvdm/nodejs-piwik/issues
License:      Unlicense / Public Domain (see UNLICENSE file)
*/

var urltool = require('url')
var querystring = require('querystring')
var http = null

var app = {settings: {}}

// SETUP basics
app.setup = function( baseURL, token ) {
  var url = urltool.parse( baseURL, true )

  if (url.protocol === 'https:') {
    http = require('https')
    app.settings.apiprotocol = 'https:'
    app.settings.apiport = url.port || 443
  } else {
    http = require('http')
    app.settings.apiprotocol = 'http:'
    app.settings.apiport = url.port || 80
  }

  // token in baseURL?
  if( url.query && url.query.token_auth ) {
    app.settings.token = url.query.token_auth
  }

  // override with custom token, if any
  if( token ) {
    app.settings.token = token
  }

  app.settings.apihost = url.hostname
  app.settings.apipath = url.pathname

  return app
}

// API call
app.api = function( vars, cb ) {
  var vars = typeof vars == 'object' ? vars : {}
  vars.module = 'API'
  vars.format = 'JSON'
  vars.token_auth = app.settings.token
  get( {query: vars}, cb )
  return app
}

// Track
app.track = function( vars, cb ) {
  vars = typeof vars === 'object' ? vars : {}
  vars.rec = 1
  vars.apiv = 1
  if( app.settings.token ) {
    vars.token_auth = app.settings.token
  }
  get( {path: 'piwik.php', query: vars}, function( data ) {
    cb( data.substr(0,3) === 'GIF' )
  })
  return app
}

// HTTP GET
function get( props, cb ) {
  var keys = Object.keys( props.query )
  for( var i = 0; i < keys.length; i++ ) {
    var key = keys[i]
    if( typeof props.query[ key ] === 'object' ) {
      props.query[ key ] = JSON.stringify( props.query[ key ] )
    }
  }

  http.get(
    {
      protocol: app.settings.apiprotocol,
      host: app.settings.apihost,
      port: app.settings.apiport,
      path: app.settings.apipath + (props.path || '') +'?'+ querystring.stringify( props.query )
    },
    function( response ) {
      var data = []
      var size = 0

      response.on( 'data', function( chunk ) {
        data.push( chunk )
        size += chunk.length
      })

      response.on( 'end', function() {
        data = new Buffer.concat( data, size ).toString().trim()
        try { data = JSON.parse( data ) } catch(e) {}
        cb( data )
      })
    }
  )
}

// ready
module.exports = app
<|endoftext|>


<commit_before>var is = require('is');
var extend = require('node.extend');
var converter = require("color-convert")();

var slice = function(arr) {
  return Array.prototype.slice.call(arr);
};

var TYPES = {
  GRAYSCALE: 'GRAYSCALE',
  RGB: 'RGB',
  RGBA: 'RGBA'
}; // TODO, support more types

//TODO, hardcode some colors. e.g. COLORS.RED = "#FF0000"
//and then take these color names as args to pixel

//TODO, make this a proxy once that hits standards
//so that .R/.G/.B can proxy through to the storage array
//TODO types: string of #FFF/#FFFFFF
function Pixel(fakeArgs) {
  var i;
  var args = slice(arguments);
  this.channels = [];
  if(args.length == 1 && Buffer.isBuffer(args[0])) {
    for(i=0;i<args[0].length;i++) {
      this.channels.push(args[0][i]);
    }
  } else if((args.length == 1 || args.length == 3 || args.length == 4) && is.number(args[0])) {
    for(i=0;i<args.length;i++) {
      if(!is.number(args[i])) throw new TypeError("Invalid argument type. Expected all to be numbers.");
      this.channels.push(args[i]);
    }
  } else if(args.length == 1 && is.array(args[0])) {
    this.channels = slice(args[0]);
  } else {
    console.log(args);
    throw new TypeError("Argument type unsupported for now");
  }
  if(this.channels.length == 3) this.type = TYPES.RGB;
  if(this.channels.length == 4) this.type = TYPES.RGBA;
  if(this.channels.length == 1) this.type = TYPES.GRAYSCALE;

  this.toBuffer = function() {
    var ret = new Buffer(this.channels.length);
    for(var i=0;i<this.channels.length;i++) {
      ret[i] = this.channels[i];
    }
    return ret;
  };
  this.clamp = function() {
    var ret = extend(true, {}, this);
    for(var i=0;i<ret.channels.length;i++) {
      ret.channels[i] = Math.max(0, Math.min(255, this.channels[i]));
    }
    return ret;
  };

  this.minus = function(rhs) {
    var ret;
    if(rhs.channels.length > this.channels.length) {
      ret = extend(true, {}, rhs);
    } else {
      ret = extend(true, {}, this);
    }
    for(var i=0;i<ret.channels.length;i++) {
      if(rhs.channels.length <= i || this.channels.length <= i) {
        ret.channels[i] = 255; //max diff if the channels don't line up
      } else {
        ret.channels[i] = this.channels[i] - rhs.channels[i];
      }
    }
    return ret;
  };
  this.plus = function(rhs) {
    var ret = new Pixel(this.channels);
    for(var i=0;i<this.channels.length;i++) {
      if(rhs.channels.length <= i || this.channels.length <= i) {
        ret.channels[i] = (this.channels.length <= i) ? 255 : this.channels[i];
      } else {
        ret.channels[i] = this.channels[i] + rhs.channels[i];
      }
    }
    return ret;
  };
  this.abs = function() {
    var ret = extend(true, {}, this);
    for(var i=0;i<this.channels.length;i++) {
      ret.channels[i] = Math.abs(this.channels[i]);
    }
    return ret;
  };
  this.getAvg = function() {
    var total = 0;
    for(var i=0;i<this.channels.length;i++) {
      total += this.channels[i];
    }
    return total / this.channels.length;
  };
  this.getRGBAvg = function() {
    var total = 0;
    var numChans = this.channels.length == 4 ? 3 : this.channels.length;
    for(var i=0;i<numChans;i++) {
      total += this.channels[i];
    }
    return total / numChans;

  };
  this.desaturate = function() {
    var ret = extend(true, {}, this);
    if(this.channels.length >= 3) {
      var hsl = converter.rgb(this.channels.slice(0,3)).hsl();
      hsl[1] = 0;
      var rgb = converter.hsl(hsl).rgb();
      ret.channels[0] = rgb[0];
      ret.channels[1] = rgb[1];
      ret.channels[2] = rgb[2];
    }
    return ret;
  };

  this.scaledBy = function(val) {
    var ret = new Pixel(this.channels);
    for(var i=0;i<ret.channels.length;i++) {
      ret.channels[i] *= val;
    }
    return ret;
  };
}
Pixel.TYPES = TYPES;

module.exports = Pixel;
<commit_msg>FASTER!<commit_after>var is = require('is');
var extend = require('node.extend');
var converter = require("color-convert")();

var slice = function(arr) {
  return Array.prototype.slice.call(arr);
};

var TYPES = {
  GRAYSCALE: 'GRAYSCALE',
  RGB: 'RGB',
  RGBA: 'RGBA'
}; // TODO, support more types

//TODO, hardcode some colors. e.g. COLORS.RED = "#FF0000"
//and then take these color names as args to pixel

//TODO, make this a proxy once that hits standards
//so that .R/.G/.B can proxy through to the storage array
//TODO types: string of #FFF/#FFFFFF
function Pixel(fakeArgs) {
  var i;
  var args = slice(arguments);
  this.channels = [];
  if(args.length == 1 && Buffer.isBuffer(args[0])) {
    for(i=0;i<args[0].length;i++) {
      this.channels.push(args[0][i]);
    }
  } else if((args.length == 1 || args.length == 3 || args.length == 4) && is.number(args[0])) {
    for(i=0;i<args.length;i++) {
      if(!is.number(args[i])) throw new TypeError("Invalid argument type. Expected all to be numbers.");
      this.channels.push(args[i]);
    }
  } else if(args.length == 1 && is.array(args[0])) {
    this.channels = slice(args[0]);
  } else {
    console.log(args);
    throw new TypeError("Argument type unsupported for now");
  }
  if(this.channels.length == 3) this.type = TYPES.RGB;
  if(this.channels.length == 4) this.type = TYPES.RGBA;
  if(this.channels.length == 1) this.type = TYPES.GRAYSCALE;

}
Pixel.TYPES = TYPES;
Pixel.prototype.toBuffer = function() {
  var ret = new Buffer(this.channels.length);
  for(var i=0;i<this.channels.length;i++) {
    ret[i] = this.channels[i];
  }
  return ret;
};
Pixel.prototype.clamp = function() {
  var ret = extend(true, {}, this);
  for(var i=0;i<ret.channels.length;i++) {
    ret.channels[i] = Math.max(0, Math.min(255, this.channels[i]));
  }
  return ret;
};

Pixel.prototype.minus = function(rhs) {
  var ret;
  if(rhs.channels.length > this.channels.length) {
    ret = extend(true, {}, rhs);
  } else {
    ret = extend(true, {}, this);
  }
  for(var i=0;i<ret.channels.length;i++) {
    if(rhs.channels.length <= i || this.channels.length <= i) {
      ret.channels[i] = 255; //max diff if the channels don't line up
    } else {
      ret.channels[i] = this.channels[i] - rhs.channels[i];
    }
  }
  return ret;
};
Pixel.prototype.plus = function(rhs) {
  var ret = new Pixel(this.channels);
  for(var i=0;i<this.channels.length;i++) {
    if(rhs.channels.length <= i || this.channels.length <= i) {
      ret.channels[i] = (this.channels.length <= i) ? 255 : this.channels[i];
    } else {
      ret.channels[i] = this.channels[i] + rhs.channels[i];
    }
  }
  return ret;
};
Pixel.prototype.abs = function() {
  var ret = extend(true, {}, this);
  for(var i=0;i<this.channels.length;i++) {
    ret.channels[i] = Math.abs(this.channels[i]);
  }
  return ret;
};
Pixel.prototype.getAvg = function() {
  var total = 0;
  for(var i=0;i<this.channels.length;i++) {
    total += this.channels[i];
  }
  return total / this.channels.length;
};
Pixel.prototype.getRGBAvg = function() {
  var total = 0;
  var numChans = this.channels.length == 4 ? 3 : this.channels.length;
  for(var i=0;i<numChans;i++) {
    total += this.channels[i];
  }
  return total / numChans;

};
Pixel.prototype.desaturate = function() {
  var ret = extend(true, {}, this);
  if(this.channels.length >= 3) {
    var hsl = converter.rgb(this.channels.slice(0,3)).hsl();
    hsl[1] = 0;
    var rgb = converter.hsl(hsl).rgb();
    ret.channels[0] = rgb[0];
    ret.channels[1] = rgb[1];
    ret.channels[2] = rgb[2];
  }
  return ret;
};

Pixel.prototype.scaledBy = function(val) {
  var ret = new Pixel(this.channels);
  for(var i=0;i<ret.channels.length;i++) {
    ret.channels[i] *= val;
  }
  return ret;
};

module.exports = Pixel;
<|endoftext|>


<commit_before>import watch from '../../../src/api/watch';

describe('api/watch', function () {
  var parent;
  var child;
  var descendant;

  beforeEach(function () {
    parent = document.createElement('div');
    child = document.createElement('div');
    descendant = document.createElement('div');
  });

  it('should watch for added childNodes', function (done) {
    watch(parent, function (added, removed) {
      expect(added.length).to.equal(1);
      expect(removed.length).to.equal(0);
      done();
    });

    parent.appendChild(child);
  });

  it('should watch for removed childNodes', function (done) {
    parent.appendChild(child);

    watch(parent, function (added, removed) {
      expect(added.length).to.equal(0);
      expect(removed.length).to.equal(1);
      done();
    });

    parent.removeChild(child);
  });

  it('should only watch immediate childNodes by default', function (done) {
    parent.appendChild(child);
    child.appendChild(descendant);

    watch(parent, function () {
      done('watcher triggered');
    });

    child.removeChild(descendant);
    setTimeout(done, 100);
  });

  it('should watch descendants if { subtree: true }', function (done) {
    parent.appendChild(child);
    child.appendChild(descendant);

    watch(parent, function (added, removed) {
      expect(added.length).to.equal(0);
      expect(removed.length).to.equal(1);
      done();
    }, {
      subtree: true
    });

    child.removeChild(descendant);
  });
});
<commit_msg>tests: Mutation events only fire for elements in actually in the DOM.<commit_after>import watch from '../../../src/api/watch';

describe('api/watch', function () {
  var parent;
  var child;
  var descendant;

  beforeEach(function () {
    parent = document.body.appendChild(document.createElement('div'));
    child = document.createElement('div');
    descendant = document.createElement('div');
  });

  afterEach(function () {
    document.body.removeChild(parent);
  });

  it('should watch for added childNodes', function (done) {
    watch(parent, function (added, removed) {
      expect(added.length).to.equal(1);
      expect(removed.length).to.equal(0);
      done();
    });

    parent.appendChild(child);
  });

  it('should watch for removed childNodes', function (done) {
    parent.appendChild(child);

    watch(parent, function (added, removed) {
      expect(added.length).to.equal(0);
      expect(removed.length).to.equal(1);
      done();
    });

    parent.removeChild(child);
  });

  it('should only watch immediate childNodes by default', function (done) {
    parent.appendChild(child);
    child.appendChild(descendant);

    watch(parent, function () {
      done('watcher triggered');
    });

    child.removeChild(descendant);
    setTimeout(done, 100);
  });

  it('should watch descendants if { subtree: true }', function (done) {
    parent.appendChild(child);
    child.appendChild(descendant);

    watch(parent, function (added, removed) {
      expect(added.length).to.equal(0);
      expect(removed.length).to.equal(1);
      done();
    }, {
      subtree: true
    });

    child.removeChild(descendant);
  });
});
<|endoftext|>


<commit_before>/* Copyright 2017 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
  bytesToString,
  createPromiseCapability,
  createValidAbsoluteUrl,
  encodeToXmlString,
  escapeString,
  getModificationDate,
  isArrayBuffer,
  isBool,
  isNum,
  isSameOrigin,
  isString,
  removeNullCharacters,
  string32,
  stringToBytes,
  stringToPDFString,
} from "../../src/shared/util.js";

describe("util", function () {
  describe("bytesToString", function () {
    it("handles non-array arguments", function () {
      expect(function () {
        bytesToString(null);
      }).toThrow(new Error("Invalid argument for bytesToString"));
    });

    it("handles array arguments with a length not exceeding the maximum", function () {
      expect(bytesToString(new Uint8Array([]))).toEqual("");
      expect(bytesToString(new Uint8Array([102, 111, 111]))).toEqual("foo");
    });

    it("handles array arguments with a length exceeding the maximum", function () {
      const length = 10000; // Larger than MAX_ARGUMENT_COUNT = 8192.

      // Create an array with `length` 'a' character codes.
      const bytes = new Uint8Array(length);
      for (let i = 0; i < length; i++) {
        bytes[i] = "a".charCodeAt(0);
      }

      // Create a string with `length` 'a' characters. We need an array of size
      // `length + 1` since `join` puts the argument between the array elements.
      const string = Array(length + 1).join("a");

      expect(bytesToString(bytes)).toEqual(string);
    });
  });

  describe("isArrayBuffer", function () {
    it("handles array buffer values", function () {
      expect(isArrayBuffer(new ArrayBuffer(0))).toEqual(true);
      expect(isArrayBuffer(new Uint8Array(0))).toEqual(true);
    });

    it("handles non-array buffer values", function () {
      expect(isArrayBuffer("true")).toEqual(false);
      expect(isArrayBuffer(1)).toEqual(false);
      expect(isArrayBuffer(null)).toEqual(false);
      expect(isArrayBuffer(undefined)).toEqual(false);
    });
  });

  describe("isBool", function () {
    it("handles boolean values", function () {
      expect(isBool(true)).toEqual(true);
      expect(isBool(false)).toEqual(true);
    });

    it("handles non-boolean values", function () {
      expect(isBool("true")).toEqual(false);
      expect(isBool("false")).toEqual(false);
      expect(isBool(1)).toEqual(false);
      expect(isBool(0)).toEqual(false);
      expect(isBool(null)).toEqual(false);
      expect(isBool(undefined)).toEqual(false);
    });
  });

  describe("isNum", function () {
    it("handles numeric values", function () {
      expect(isNum(1)).toEqual(true);
      expect(isNum(0)).toEqual(true);
      expect(isNum(-1)).toEqual(true);
      expect(isNum(1000000000000000000)).toEqual(true);
      expect(isNum(12.34)).toEqual(true);
    });

    it("handles non-numeric values", function () {
      expect(isNum("true")).toEqual(false);
      expect(isNum(true)).toEqual(false);
      expect(isNum(null)).toEqual(false);
      expect(isNum(undefined)).toEqual(false);
    });
  });

  describe("isString", function () {
    it("handles string values", function () {
      expect(isString("foo")).toEqual(true);
      expect(isString("")).toEqual(true);
    });

    it("handles non-string values", function () {
      expect(isString(true)).toEqual(false);
      expect(isString(1)).toEqual(false);
      expect(isString(null)).toEqual(false);
      expect(isString(undefined)).toEqual(false);
    });
  });

  describe("string32", function () {
    it("converts unsigned 32-bit integers to strings", function () {
      expect(string32(0x74727565)).toEqual("true");
      expect(string32(0x74797031)).toEqual("typ1");
      expect(string32(0x4f54544f)).toEqual("OTTO");
    });
  });

  describe("stringToBytes", function () {
    it("handles non-string arguments", function () {
      expect(function () {
        stringToBytes(null);
      }).toThrow(new Error("Invalid argument for stringToBytes"));
    });

    it("handles string arguments", function () {
      expect(stringToBytes("")).toEqual(new Uint8Array([]));
      expect(stringToBytes("foo")).toEqual(new Uint8Array([102, 111, 111]));
    });
  });

  describe("stringToPDFString", function () {
    it("handles ISO Latin 1 strings", function () {
      const str = "\x8Dstring\x8E";
      expect(stringToPDFString(str)).toEqual("\u201Cstring\u201D");
    });

    it("handles UTF-16 big-endian strings", function () {
      const str = "\xFE\xFF\x00\x73\x00\x74\x00\x72\x00\x69\x00\x6E\x00\x67";
      expect(stringToPDFString(str)).toEqual("string");
    });

    it("handles UTF-16 little-endian strings", function () {
      const str = "\xFF\xFE\x73\x00\x74\x00\x72\x00\x69\x00\x6E\x00\x67\x00";
      expect(stringToPDFString(str)).toEqual("string");
    });

    it("handles empty strings", function () {
      // ISO Latin 1
      const str1 = "";
      expect(stringToPDFString(str1)).toEqual("");

      // UTF-16BE
      const str2 = "\xFE\xFF";
      expect(stringToPDFString(str2)).toEqual("");

      // UTF-16LE
      const str3 = "\xFF\xFE";
      expect(stringToPDFString(str3)).toEqual("");
    });
  });

  describe("removeNullCharacters", function () {
    it("should not modify string without null characters", function () {
      const str = "string without null chars";
      expect(removeNullCharacters(str)).toEqual("string without null chars");
    });

    it("should modify string with null characters", function () {
      const str = "string\x00With\x00Null\x00Chars";
      expect(removeNullCharacters(str)).toEqual("stringWithNullChars");
    });
  });

  describe("ReadableStream", function () {
    it("should return an Object", function () {
      const readable = new ReadableStream();
      expect(typeof readable).toEqual("object");
    });

    it("should have property getReader", function () {
      const readable = new ReadableStream();
      expect(typeof readable.getReader).toEqual("function");
    });
  });

  describe("URL", function () {
    it("should return an Object", function () {
      const url = new URL("https://example.com");
      expect(typeof url).toEqual("object");
    });

    it("should have property `href`", function () {
      const url = new URL("https://example.com");
      expect(typeof url.href).toEqual("string");
    });
  });

  describe("isSameOrigin", function () {
    it("handles invalid base URLs", function () {
      // The base URL is not valid.
      expect(isSameOrigin("/foo", "/bar")).toEqual(false);

      // The base URL has no origin.
      expect(isSameOrigin("blob:foo", "/bar")).toEqual(false);
    });

    it("correctly checks if the origin of both URLs matches", function () {
      expect(
        isSameOrigin(
          "https://www.mozilla.org/foo",
          "https://www.mozilla.org/bar"
        )
      ).toEqual(true);
      expect(
        isSameOrigin(
          "https://www.mozilla.org/foo",
          "https://www.example.com/bar"
        )
      ).toEqual(false);
    });
  });

  describe("createValidAbsoluteUrl", function () {
    it("handles invalid URLs", function () {
      expect(createValidAbsoluteUrl(undefined, undefined)).toEqual(null);
      expect(createValidAbsoluteUrl(null, null)).toEqual(null);
      expect(createValidAbsoluteUrl("/foo", "/bar")).toEqual(null);
    });

    it("handles URLs that do not use an allowed protocol", function () {
      expect(createValidAbsoluteUrl("magnet:?foo", null)).toEqual(null);
    });

    it("correctly creates a valid URL for allowed protocols", function () {
      // `http` protocol
      expect(
        createValidAbsoluteUrl("http://www.mozilla.org/foo", null)
      ).toEqual(new URL("http://www.mozilla.org/foo"));
      expect(createValidAbsoluteUrl("/foo", "http://www.mozilla.org")).toEqual(
        new URL("http://www.mozilla.org/foo")
      );

      // `https` protocol
      expect(
        createValidAbsoluteUrl("https://www.mozilla.org/foo", null)
      ).toEqual(new URL("https://www.mozilla.org/foo"));
      expect(createValidAbsoluteUrl("/foo", "https://www.mozilla.org")).toEqual(
        new URL("https://www.mozilla.org/foo")
      );

      // `ftp` protocol
      expect(createValidAbsoluteUrl("ftp://www.mozilla.org/foo", null)).toEqual(
        new URL("ftp://www.mozilla.org/foo")
      );
      expect(createValidAbsoluteUrl("/foo", "ftp://www.mozilla.org")).toEqual(
        new URL("ftp://www.mozilla.org/foo")
      );

      // `mailto` protocol (base URLs have no meaning and should yield `null`)
      expect(createValidAbsoluteUrl("mailto:foo@bar.baz", null)).toEqual(
        new URL("mailto:foo@bar.baz")
      );
      expect(createValidAbsoluteUrl("/foo", "mailto:foo@bar.baz")).toEqual(
        null
      );

      // `tel` protocol (base URLs have no meaning and should yield `null`)
      expect(createValidAbsoluteUrl("tel:+0123456789", null)).toEqual(
        new URL("tel:+0123456789")
      );
      expect(createValidAbsoluteUrl("/foo", "tel:0123456789")).toEqual(null);
    });
  });

  describe("createPromiseCapability", function () {
    it("should resolve with correct data", function (done) {
      const promiseCapability = createPromiseCapability();
      expect(promiseCapability.settled).toEqual(false);

      promiseCapability.resolve({ test: "abc" });

      promiseCapability.promise.then(function (data) {
        expect(promiseCapability.settled).toEqual(true);

        expect(data).toEqual({ test: "abc" });
        done();
      }, done.fail);
    });

    it("should reject with correct reason", function (done) {
      const promiseCapability = createPromiseCapability();
      expect(promiseCapability.settled).toEqual(false);

      promiseCapability.reject(new Error("reason"));

      promiseCapability.promise.then(done.fail, function (reason) {
        expect(promiseCapability.settled).toEqual(true);

        expect(reason instanceof Error).toEqual(true);
        expect(reason.message).toEqual("reason");
        done();
      });
    });
  });

  describe("escapeString", function () {
    it("should escape (, ), \n, \r and \\", function () {
      expect(escapeString("((a\\a))\n(b(b\\b)\rb)")).toEqual(
        "\\(\\(a\\\\a\\)\\)\\n\\(b\\(b\\\\b\\)\\rb\\)"
      );
    });
  });

  describe("getModificationDate", function () {
    it("should get a correctly formatted date", function () {
      const date = new Date(Date.UTC(3141, 5, 9, 2, 6, 53));
      expect(getModificationDate(date)).toEqual("31410609020653");
    });
  });

  describe("encodeToXmlString", function () {
    it("should get a correctly encoded string with some entities", function () {
      const str = "\"\u0397ell😂' & <W😂rld>";
      expect(encodeToXmlString(str)).toEqual(
        ""Ηell😂' & <W😂rld>"
      );
    });

    it("should get a correctly encoded basic ascii string", function () {
      const str = "hello world";
      expect(encodeToXmlString(str)).toEqual(str);
    });
  });
});
<commit_msg>Update the description of the test-case used in the `escapeString` unit-test<commit_after>/* Copyright 2017 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
  bytesToString,
  createPromiseCapability,
  createValidAbsoluteUrl,
  encodeToXmlString,
  escapeString,
  getModificationDate,
  isArrayBuffer,
  isBool,
  isNum,
  isSameOrigin,
  isString,
  removeNullCharacters,
  string32,
  stringToBytes,
  stringToPDFString,
} from "../../src/shared/util.js";

describe("util", function () {
  describe("bytesToString", function () {
    it("handles non-array arguments", function () {
      expect(function () {
        bytesToString(null);
      }).toThrow(new Error("Invalid argument for bytesToString"));
    });

    it("handles array arguments with a length not exceeding the maximum", function () {
      expect(bytesToString(new Uint8Array([]))).toEqual("");
      expect(bytesToString(new Uint8Array([102, 111, 111]))).toEqual("foo");
    });

    it("handles array arguments with a length exceeding the maximum", function () {
      const length = 10000; // Larger than MAX_ARGUMENT_COUNT = 8192.

      // Create an array with `length` 'a' character codes.
      const bytes = new Uint8Array(length);
      for (let i = 0; i < length; i++) {
        bytes[i] = "a".charCodeAt(0);
      }

      // Create a string with `length` 'a' characters. We need an array of size
      // `length + 1` since `join` puts the argument between the array elements.
      const string = Array(length + 1).join("a");

      expect(bytesToString(bytes)).toEqual(string);
    });
  });

  describe("isArrayBuffer", function () {
    it("handles array buffer values", function () {
      expect(isArrayBuffer(new ArrayBuffer(0))).toEqual(true);
      expect(isArrayBuffer(new Uint8Array(0))).toEqual(true);
    });

    it("handles non-array buffer values", function () {
      expect(isArrayBuffer("true")).toEqual(false);
      expect(isArrayBuffer(1)).toEqual(false);
      expect(isArrayBuffer(null)).toEqual(false);
      expect(isArrayBuffer(undefined)).toEqual(false);
    });
  });

  describe("isBool", function () {
    it("handles boolean values", function () {
      expect(isBool(true)).toEqual(true);
      expect(isBool(false)).toEqual(true);
    });

    it("handles non-boolean values", function () {
      expect(isBool("true")).toEqual(false);
      expect(isBool("false")).toEqual(false);
      expect(isBool(1)).toEqual(false);
      expect(isBool(0)).toEqual(false);
      expect(isBool(null)).toEqual(false);
      expect(isBool(undefined)).toEqual(false);
    });
  });

  describe("isNum", function () {
    it("handles numeric values", function () {
      expect(isNum(1)).toEqual(true);
      expect(isNum(0)).toEqual(true);
      expect(isNum(-1)).toEqual(true);
      expect(isNum(1000000000000000000)).toEqual(true);
      expect(isNum(12.34)).toEqual(true);
    });

    it("handles non-numeric values", function () {
      expect(isNum("true")).toEqual(false);
      expect(isNum(true)).toEqual(false);
      expect(isNum(null)).toEqual(false);
      expect(isNum(undefined)).toEqual(false);
    });
  });

  describe("isString", function () {
    it("handles string values", function () {
      expect(isString("foo")).toEqual(true);
      expect(isString("")).toEqual(true);
    });

    it("handles non-string values", function () {
      expect(isString(true)).toEqual(false);
      expect(isString(1)).toEqual(false);
      expect(isString(null)).toEqual(false);
      expect(isString(undefined)).toEqual(false);
    });
  });

  describe("string32", function () {
    it("converts unsigned 32-bit integers to strings", function () {
      expect(string32(0x74727565)).toEqual("true");
      expect(string32(0x74797031)).toEqual("typ1");
      expect(string32(0x4f54544f)).toEqual("OTTO");
    });
  });

  describe("stringToBytes", function () {
    it("handles non-string arguments", function () {
      expect(function () {
        stringToBytes(null);
      }).toThrow(new Error("Invalid argument for stringToBytes"));
    });

    it("handles string arguments", function () {
      expect(stringToBytes("")).toEqual(new Uint8Array([]));
      expect(stringToBytes("foo")).toEqual(new Uint8Array([102, 111, 111]));
    });
  });

  describe("stringToPDFString", function () {
    it("handles ISO Latin 1 strings", function () {
      const str = "\x8Dstring\x8E";
      expect(stringToPDFString(str)).toEqual("\u201Cstring\u201D");
    });

    it("handles UTF-16 big-endian strings", function () {
      const str = "\xFE\xFF\x00\x73\x00\x74\x00\x72\x00\x69\x00\x6E\x00\x67";
      expect(stringToPDFString(str)).toEqual("string");
    });

    it("handles UTF-16 little-endian strings", function () {
      const str = "\xFF\xFE\x73\x00\x74\x00\x72\x00\x69\x00\x6E\x00\x67\x00";
      expect(stringToPDFString(str)).toEqual("string");
    });

    it("handles empty strings", function () {
      // ISO Latin 1
      const str1 = "";
      expect(stringToPDFString(str1)).toEqual("");

      // UTF-16BE
      const str2 = "\xFE\xFF";
      expect(stringToPDFString(str2)).toEqual("");

      // UTF-16LE
      const str3 = "\xFF\xFE";
      expect(stringToPDFString(str3)).toEqual("");
    });
  });

  describe("removeNullCharacters", function () {
    it("should not modify string without null characters", function () {
      const str = "string without null chars";
      expect(removeNullCharacters(str)).toEqual("string without null chars");
    });

    it("should modify string with null characters", function () {
      const str = "string\x00With\x00Null\x00Chars";
      expect(removeNullCharacters(str)).toEqual("stringWithNullChars");
    });
  });

  describe("ReadableStream", function () {
    it("should return an Object", function () {
      const readable = new ReadableStream();
      expect(typeof readable).toEqual("object");
    });

    it("should have property getReader", function () {
      const readable = new ReadableStream();
      expect(typeof readable.getReader).toEqual("function");
    });
  });

  describe("URL", function () {
    it("should return an Object", function () {
      const url = new URL("https://example.com");
      expect(typeof url).toEqual("object");
    });

    it("should have property `href`", function () {
      const url = new URL("https://example.com");
      expect(typeof url.href).toEqual("string");
    });
  });

  describe("isSameOrigin", function () {
    it("handles invalid base URLs", function () {
      // The base URL is not valid.
      expect(isSameOrigin("/foo", "/bar")).toEqual(false);

      // The base URL has no origin.
      expect(isSameOrigin("blob:foo", "/bar")).toEqual(false);
    });

    it("correctly checks if the origin of both URLs matches", function () {
      expect(
        isSameOrigin(
          "https://www.mozilla.org/foo",
          "https://www.mozilla.org/bar"
        )
      ).toEqual(true);
      expect(
        isSameOrigin(
          "https://www.mozilla.org/foo",
          "https://www.example.com/bar"
        )
      ).toEqual(false);
    });
  });

  describe("createValidAbsoluteUrl", function () {
    it("handles invalid URLs", function () {
      expect(createValidAbsoluteUrl(undefined, undefined)).toEqual(null);
      expect(createValidAbsoluteUrl(null, null)).toEqual(null);
      expect(createValidAbsoluteUrl("/foo", "/bar")).toEqual(null);
    });

    it("handles URLs that do not use an allowed protocol", function () {
      expect(createValidAbsoluteUrl("magnet:?foo", null)).toEqual(null);
    });

    it("correctly creates a valid URL for allowed protocols", function () {
      // `http` protocol
      expect(
        createValidAbsoluteUrl("http://www.mozilla.org/foo", null)
      ).toEqual(new URL("http://www.mozilla.org/foo"));
      expect(createValidAbsoluteUrl("/foo", "http://www.mozilla.org")).toEqual(
        new URL("http://www.mozilla.org/foo")
      );

      // `https` protocol
      expect(
        createValidAbsoluteUrl("https://www.mozilla.org/foo", null)
      ).toEqual(new URL("https://www.mozilla.org/foo"));
      expect(createValidAbsoluteUrl("/foo", "https://www.mozilla.org")).toEqual(
        new URL("https://www.mozilla.org/foo")
      );

      // `ftp` protocol
      expect(createValidAbsoluteUrl("ftp://www.mozilla.org/foo", null)).toEqual(
        new URL("ftp://www.mozilla.org/foo")
      );
      expect(createValidAbsoluteUrl("/foo", "ftp://www.mozilla.org")).toEqual(
        new URL("ftp://www.mozilla.org/foo")
      );

      // `mailto` protocol (base URLs have no meaning and should yield `null`)
      expect(createValidAbsoluteUrl("mailto:foo@bar.baz", null)).toEqual(
        new URL("mailto:foo@bar.baz")
      );
      expect(createValidAbsoluteUrl("/foo", "mailto:foo@bar.baz")).toEqual(
        null
      );

      // `tel` protocol (base URLs have no meaning and should yield `null`)
      expect(createValidAbsoluteUrl("tel:+0123456789", null)).toEqual(
        new URL("tel:+0123456789")
      );
      expect(createValidAbsoluteUrl("/foo", "tel:0123456789")).toEqual(null);
    });
  });

  describe("createPromiseCapability", function () {
    it("should resolve with correct data", function (done) {
      const promiseCapability = createPromiseCapability();
      expect(promiseCapability.settled).toEqual(false);

      promiseCapability.resolve({ test: "abc" });

      promiseCapability.promise.then(function (data) {
        expect(promiseCapability.settled).toEqual(true);

        expect(data).toEqual({ test: "abc" });
        done();
      }, done.fail);
    });

    it("should reject with correct reason", function (done) {
      const promiseCapability = createPromiseCapability();
      expect(promiseCapability.settled).toEqual(false);

      promiseCapability.reject(new Error("reason"));

      promiseCapability.promise.then(done.fail, function (reason) {
        expect(promiseCapability.settled).toEqual(true);

        expect(reason instanceof Error).toEqual(true);
        expect(reason.message).toEqual("reason");
        done();
      });
    });
  });

  describe("escapeString", function () {
    it("should escape (, ), \\n, \\r, and \\", function () {
      expect(escapeString("((a\\a))\n(b(b\\b)\rb)")).toEqual(
        "\\(\\(a\\\\a\\)\\)\\n\\(b\\(b\\\\b\\)\\rb\\)"
      );
    });
  });

  describe("getModificationDate", function () {
    it("should get a correctly formatted date", function () {
      const date = new Date(Date.UTC(3141, 5, 9, 2, 6, 53));
      expect(getModificationDate(date)).toEqual("31410609020653");
    });
  });

  describe("encodeToXmlString", function () {
    it("should get a correctly encoded string with some entities", function () {
      const str = "\"\u0397ell😂' & <W😂rld>";
      expect(encodeToXmlString(str)).toEqual(
        ""Ηell😂' & <W😂rld>"
      );
    });

    it("should get a correctly encoded basic ascii string", function () {
      const str = "hello world";
      expect(encodeToXmlString(str)).toEqual(str);
    });
  });
});
<|endoftext|>