<commit_before>var path = require('path');
var fs = require('fs');
// var assert = require('assert');
var chai = require('chai');
chai.use(require('chai-string'));
// var expect = require('chai').expect;
var _ = require('lodash');

var assert = chai.assert;

var File = require('../lib/file');
var Formatter = require('../lib/formatter');
var Logger = require('../lib/logger');

var sub = require('../lib/base').sub;

describe('Formatter', function () {

	it(
		'should return the proper formatter for a file',
		function() {
			var customFormatGetter = Formatter.create(
				{
					id: 'customFormatGetter',
					extensions: '*.foo'
				}
			);

			var formatter = Formatter.get('path/to/file.foo');

			assert.equal(formatter.constructor, customFormatGetter);
		}
	);

	it(
		'should not return an unregistered formatter',
		function() {
			var formatter = Formatter.get('path/to/file.missing');

			assert.equal(formatter, null);
		}
	);

});

describe('Formatter Base', function () {

	it(
		'should accept a custom logger',
		function() {
			var formatter = new Formatter('path/to/file', new Logger.Logger());

			assert.isTrue(formatter.logger instanceof Logger.Logger);
		}
	);

	it(
		'should return a formatted string from base .format',
		function() {
			var formatter = new Formatter('path/to/file', new Logger.Logger());

			assert.equal(formatter.format('foo'), 'foo');
		}
	);

	it(
		'should execute init method',
		function() {
			var msg;
			var expectedMsg = 'init was called';

			var customFormatter = Formatter.create(
				{
					id: 'initCustomFormatter',
					extensions: '*.txt',
					prototype: {
						init: function(){
							msg = expectedMsg;
						}
					}
				}
			);

			new customFormatter('path/to/file');

			assert.equal(msg, expectedMsg);
		}
	);

});

describe('Formatter.create', function () {

	it(
		'should throw an error when called without arguments',
		function() {
			var msg;

			try {
				Formatter.create();
			}
			catch (e) {
				msg = e.message;
			}

			assert.equal(msg, 'You must pass an object to Formatter.create');
		}
	);

	it(
		'should throw an error when called without an id property',
		function() {
			var msg;

			try {
				Formatter.create({});
			}
			catch (e) {
				msg = e.message;
			}

			assert.equal(msg, 'You must give this formatter an id with the id property');
		}
	);

	it(
		'should throw an error when called without a duplicate id property',
		function() {
			var msg;

			var testFormatterId = 'TestFormatter';

			Formatter.create(
				{
					id: testFormatterId,
					extensions: '*.js'
				}
			);

			try {
				Formatter.create(
					{
						id: testFormatterId,
						extensions: '*.js'
					}
				);
			}
			catch (e) {
				msg = e.message;
			}

			assert.equal(msg, sub('The id: "{0}" is already taken', testFormatterId));
		}
	);

	it(
		'should throw an error when called without extensions',
		function() {
			var msg;

			var expectedErrorMsg = 'The extensions property must be a string, and must be glob expression';

			try {
				Formatter.create(
					{
						id: 'FooExtTest1'
					}
				);
			}
			catch (e) {
				msg = e.message;
			}

			assert.equal(msg, expectedErrorMsg);

			msg = undefined;

			try {
				Formatter.create(
					{
						id: 'FooExtTest2',
						extensions: ''
					}
				);
			}
			catch (e) {
				msg = e.message;
			}

			assert.equal(msg, expectedErrorMsg);
		}
	);

	it(
		'should use a custom constructor',
		function() {
			var msg;
			var expectedMsg = 'constructor was called';

			var fooCustom1 = Formatter.create(
				{
					constructor: function() {
						msg = expectedMsg;
					},
					id: 'FooCustom1',
					extensions: '*.js',
				}
			);

			new fooCustom1();

			assert.equal(msg, expectedMsg);
		}
	);

});<commit_msg>Expanding test coverage of formatter<commit_after>var path = require('path');
var fs = require('fs');
// var assert = require('assert');
var chai = require('chai');
chai.use(require('chai-string'));
// var expect = require('chai').expect;
var _ = require('lodash');

var assert = chai.assert;

var File = require('../lib/file');
var Formatter = require('../lib/formatter');
var Logger = require('../lib/logger');

var sub = require('../lib/base').sub;

describe('Formatter', function () {

	it(
		'should return the proper formatter for a file',
		function() {
			var customFormatGetter = Formatter.create(
				{
					id: 'customFormatGetter',
					extensions: '*.foo'
				}
			);

			var formatter = Formatter.get('path/to/file.foo');

			assert.equal(formatter.constructor, customFormatGetter);
		}
	);

	it(
		'should not return an unregistered formatter',
		function() {
			var formatter = Formatter.get('path/to/file.missing');

			assert.equal(formatter, null);
		}
	);

});

describe('Formatter Base', function () {

	it(
		'should accept a custom logger',
		function() {
			var formatter = new Formatter('path/to/file', new Logger.Logger());

			assert.isTrue(formatter.logger instanceof Logger.Logger);
		}
	);

	it(
		'should return a formatted string from base .format',
		function() {
			var formatter = new Formatter('path/to/file', new Logger.Logger());

			assert.equal(formatter.format('foo'), 'foo');
		}
	);

	it(
		'should execute init method',
		function() {
			var msg;
			var expectedMsg = 'init was called';

			var customFormatter = Formatter.create(
				{
					id: 'initCustomFormatter',
					extensions: '*.txt',
					prototype: {
						init: function(){
							msg = expectedMsg;
						}
					}
				}
			);

			new customFormatter('path/to/file');

			assert.equal(msg, expectedMsg);
		}
	);

	it(
		'should register an empty file path as <input>',
		function() {
			var msg;
			var expectedMsg = 'init was called';

			var customFormatter = new Formatter('');

			assert.equal(customFormatter.file, '<input>');
		}
	);

});

describe('Formatter.create', function () {

	it(
		'should throw an error when called without arguments',
		function() {
			var msg;

			try {
				Formatter.create();
			}
			catch (e) {
				msg = e.message;
			}

			assert.equal(msg, 'You must pass an object to Formatter.create');
		}
	);

	it(
		'should throw an error when called without an id property',
		function() {
			var msg;

			try {
				Formatter.create({});
			}
			catch (e) {
				msg = e.message;
			}

			assert.equal(msg, 'You must give this formatter an id with the id property');
		}
	);

	it(
		'should throw an error when called without a duplicate id property',
		function() {
			var msg;

			var testFormatterId = 'TestFormatter';

			Formatter.create(
				{
					id: testFormatterId,
					extensions: '*.js'
				}
			);

			try {
				Formatter.create(
					{
						id: testFormatterId,
						extensions: '*.js'
					}
				);
			}
			catch (e) {
				msg = e.message;
			}

			assert.equal(msg, sub('The id: "{0}" is already taken', testFormatterId));
		}
	);

	it(
		'should throw an error when called without extensions',
		function() {
			var msg;

			var expectedErrorMsg = 'The extensions property must be a string, and must be glob expression';

			try {
				Formatter.create(
					{
						id: 'FooExtTest1'
					}
				);
			}
			catch (e) {
				msg = e.message;
			}

			assert.equal(msg, expectedErrorMsg);

			msg = undefined;

			try {
				Formatter.create(
					{
						id: 'FooExtTest2',
						extensions: ''
					}
				);
			}
			catch (e) {
				msg = e.message;
			}

			assert.equal(msg, expectedErrorMsg);
		}
	);

	it(
		'should use a custom constructor',
		function() {
			var msg;
			var expectedMsg = 'constructor was called';

			var fooCustom1 = Formatter.create(
				{
					constructor: function() {
						msg = expectedMsg;
					},
					id: 'FooCustom1',
					extensions: '*.js',
				}
			);

			new fooCustom1();

			assert.equal(msg, expectedMsg);
		}
	);

});<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

const TEST_ICON = "chrome://branding/content/icon64.png";

const MESSAGES = () => ([
  {
    "id": "SIMPLE_TEST_1",
    "template": "simple_snippet",
    "content": {
      "icon": TEST_ICON,
      "text": "<syncLink>Sync it, link it, take it with you</syncLink>. All this and more with a Firefox Account.",
      "links": {"syncLink": {"url": "https://www.mozilla.org/en-US/firefox/accounts"}},
      "block_button_text": "Block",
    },
  },
  {
    "id": "SIMPLE_TEST_TALL",
    "template": "simple_snippet",
    "content": {
      "icon": TEST_ICON,
      "text": "<syncLink>Sync it, link it, take it with you</syncLink>. All this and more with a Firefox Account.",
      "links": {"syncLink": {"url": "https://www.mozilla.org/en-US/firefox/accounts"}},
      "button_label": "Get one now!",
      "button_url": "https://www.mozilla.org/en-US/firefox/accounts",
      "block_button_text": "Block",
      "tall": true,
    },
  },
  {
    "id": "SIMPLE_TEST_BUTTON_URL_1",
    "template": "simple_snippet",
    "content": {
      "icon": TEST_ICON,
      "button_label": "Get one now!",
      "button_url": "https://www.mozilla.org/en-US/firefox/accounts",
      "text": "Sync it, link it, take it with you. All this and more with a Firefox Account.",
      "block_button_text": "Block",
    },
  },
  {
    "id": "SIMPLE_WITH_TITLE_TEST_1",
    "template": "simple_snippet",
    "content": {
      "icon": TEST_ICON,
      "title": "Ready to sync?",
      "text": "Get connected with a <syncLink>Firefox account</syncLink>.",
      "links": {"syncLink": {"url": "https://www.mozilla.org/en-US/firefox/accounts"}},
      "block_button_text": "Block",
    },
  },
  {
    "id": "NEWSLETTER_TEST_1",
    "template": "newsletter_snippet",
    "content": {
      "scene1_icon": TEST_ICON,
      "scene1_title": "Be a part of a movement.",
      "scene1_title_icon": "",
      "scene1_text": "Internet shutdowns, hackers, harassment – the health of the internet is on the line. Sign up and Mozilla will keep you updated on how you can help.",
      "scene1_button_label": "Continue",
      "scene1_button_color": "#712b00",
      "scene1_button_background_color": "#ff9400",
      "scene2_dismiss_button_text": "Dismiss",
      "scene2_text": "Sign up for the Mozilla newsletter and we will keep you updated on how you can help.",
      "scene2_privacy_html": "I'm okay with Mozilla handling my info as explained in this <privacyLink>Privacy Notice</privacyLink>.",
      "scene2_button_label": "Sign Me up",
      "scene2_email_placeholder_text": "Your email here",
      "form_action": "https://basket.mozilla.org/subscribe.json",
      "success_text": "Check your inbox for the confirmation!",
      "error_text": "Error!",
      "hidden_inputs": {
        "fmt": "H",
        "lang": "en-US",
        "newsletters": "mozilla-foundation",
      },
      "links": {"privacyLink": {"url": "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894"}},
    },
  },
  {
    "id": "FXA_SNIPPET_TEST_1",
    "template": "fxa_signup_snippet",
    "content": {
      "scene1_icon": TEST_ICON,
      "scene1_button_label": "Get connected with sync!",
      "scene1_button_color": "#712b00",
      "scene1_button_background_color": "#ff9400",

      "scene1_text": "Connect to Firefox by securely syncing passwords, bookmarks, and open tabs.",
      "scene1_title": "Browser better.",
      "scene1_title_icon": "",

      "scene2_text": "Connect to your Firefox account to securely sync passwords, bookmarks, and open tabs.",
      "scene2_title": "Title 123",
      "scene2_email_placeholder_text": "Your email",
      "scene2_button_label": "Continue",
      "scene2_dismiss_button_text": "Dismiss",
      "form_action": "https://basket.mozilla.org/subscribe.json",
    },
  },
  {
    id: "SNIPPETS_SEND_TO_DEVICE_TEST",
    template: "send_to_device_snippet",
    content: {
      include_sms: true,
      locale: "en-CA",
      country: "us",
      message_id_sms: "ff-mobilesn-download",
      message_id_email: "download-firefox-mobile",

      scene1_button_background_color: "#6200a4",
      scene1_button_color: "#FFFFFF",
      scene1_button_label: "Install now",
      scene1_icon: TEST_ICON,
      scene1_text: "Browse without compromise with Firefox Mobile.",
      scene1_title: "Full-featured. Customizable. Lightning fast",
      scene1_title_icon: "",

      scene2_button_label: "Send",
      scene2_disclaimer_html: "The intended recipient of the email must have consented. <privacyLink>Learn more.</privacyLink>",
      scene2_dismiss_button_text: "Dismiss",
      scene2_icon: TEST_ICON,
      scene2_input_placeholder: "Your email address or phone number",
      scene2_text: "Send Firefox to your phone and take a powerful independent browser with you.",
      scene2_title: "",

      error_text: "Oops, there was a problem.",
      success_title: "Your download link was sent.",
      success_text: "Check your device for the email message!",
      links: {"privacyLink": {"url": "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894"}},
    },
  },
  {
    "id": "EOY_TEST_1",
    "template": "eoy_snippet",
    "content": {
      "highlight_color": "#f05",
      "selected_button": "donation_amount_first",
      "icon": TEST_ICON,
      "button_label": "Donate",
      "monthly_checkbox_label_text": "Make my donation monthly",
      "currency_code": "usd",
      "donation_amount_first": 50,
      "donation_amount_second": 25,
      "donation_amount_third": 10,
      "donation_amount_fourth": 5,
      "donation_form_url": "https://donate.mozilla.org",
      "text": "Big corporations want to restrict how we access the web. Fake news is making it harder for us to find the truth. Online bullies are silencing inspired voices. The not-for-profit Mozilla Foundation fights for a healthy internet with programs like our Tech Policy Fellowships and Internet Health Report; will you donate today?",
    },
  },
  {
    "id": "EOY_BOLD_TEST_1",
    "template": "eoy_snippet",
    "content": {
      "icon": TEST_ICON,
      "selected_button": "donation_amount_second",
      "button_label": "Donate",
      "monthly_checkbox_label_text": "Make my donation monthly",
      "currency_code": "usd",
      "donation_amount_first": 50,
      "donation_amount_second": 25,
      "donation_amount_third": 10,
      "donation_amount_fourth": 5,
      "donation_form_url": "https://donate.mozilla.org",
      "text": "Big corporations want to restrict how we access the web. Fake news is making it harder for us to find the truth. Online bullies are silencing inspired voices. The not-for-profit Mozilla Foundation fights for a healthy internet with programs like our Tech Policy Fellowships and Internet Health Report; will you donate today?",
      "test": "bold",
    },
  },
  {
    "id": "EOY_TAKEOVER_TEST_1",
    "template": "eoy_snippet",
    "content": {
      "icon": TEST_ICON,
      "button_label": "Donate",
      "monthly_checkbox_label_text": "Make my donation monthly",
      "currency_code": "usd",
      "donation_amount_first": 50,
      "donation_amount_second": 25,
      "donation_amount_third": 10,
      "donation_amount_fourth": 5,
      "donation_form_url": "https://donate.mozilla.org",
      "text": "Big corporations want to restrict how we access the web. Fake news is making it harder for us to find the truth. Online bullies are silencing inspired voices. The not-for-profit Mozilla Foundation fights for a healthy internet with programs like our Tech Policy Fellowships and Internet Health Report; will you donate today?",
      "test": "takeover",
    },
  },
]);

const SnippetsTestMessageProvider = {
  getMessages() {
    return MESSAGES()
      // Ensures we never actually show test except when triggered by debug tools
      .map(message => ({...message, targeting: `providerCohorts.snippets_local_testing == "SHOW_TEST"`}));
  },
};
this.SnippetsTestMessageProvider = SnippetsTestMessageProvider;

const EXPORTED_SYMBOLS = ["SnippetsTestMessageProvider"];
<commit_msg>Bug 1505406 - Add more test data for manual QA<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

const TEST_ICON = "chrome://branding/content/icon64.png";

const MESSAGES = () => ([
  {
    "id": "SIMPLE_TEST_1",
    "template": "simple_snippet",
    "content": {
      "icon": TEST_ICON,
      "text": "<syncLink>Sync it, link it, take it with you</syncLink>. All this and more with a Firefox Account.",
      "links": {"syncLink": {"url": "https://www.mozilla.org/en-US/firefox/accounts"}},
      "block_button_text": "Block",
    },
  },
  {
    "id": "SIMPLE_TEST_TALL",
    "template": "simple_snippet",
    "content": {
      "icon": TEST_ICON,
      "text": "<syncLink>Sync it, link it, take it with you</syncLink>. All this and more with a Firefox Account.",
      "links": {"syncLink": {"url": "https://www.mozilla.org/en-US/firefox/accounts"}},
      "button_label": "Get one now!",
      "button_url": "https://www.mozilla.org/en-US/firefox/accounts",
      "block_button_text": "Block",
      "tall": true,
    },
  },
  {
    "id": "SIMPLE_TEST_BUTTON_URL_1",
    "template": "simple_snippet",
    "content": {
      "icon": TEST_ICON,
      "button_label": "Get one now!",
      "button_url": "https://www.mozilla.org/en-US/firefox/accounts",
      "text": "Sync it, link it, take it with you. All this and more with a Firefox Account.",
      "block_button_text": "Block",
    },
  },
  {
    "id": "SIMPLE_WITH_TITLE_TEST_1",
    "template": "simple_snippet",
    "content": {
      "icon": TEST_ICON,
      "title": "Ready to sync?",
      "text": "Get connected with a <syncLink>Firefox account</syncLink>.",
      "links": {"syncLink": {"url": "https://www.mozilla.org/en-US/firefox/accounts"}},
      "block_button_text": "Block",
    },
  },
  {
    "id": "NEWSLETTER_TEST_DEFAULTS",
    "template": "newsletter_snippet",
    "content": {
      "scene1_icon": TEST_ICON,
      "scene1_title": "Be a part of a movement.",
      "scene1_title_icon": "",
      "scene1_text": "Internet shutdowns, hackers, harassment – the health of the internet is on the line. Sign up and Mozilla will keep you updated on how you can help.",
      "scene1_button_label": "Continue",
      "scene1_button_color": "#712b00",
      "scene1_button_background_color": "#ff9400",
      "scene2_title": "Let's do this!",
      "scene2_dismiss_button_text": "Dismiss",
      "scene2_text": "Sign up for the Mozilla newsletter and we will keep you updated on how you can help.",
      "scene2_privacy_html": "I'm okay with Mozilla handling my info as explained in this <privacyLink>Privacy Notice</privacyLink>.",
      "scene2_newsletter": "mozilla-foundation",
      "form_action": "https://basket.mozilla.org/subscribe.json",
      "success_text": "Check your inbox for the confirmation!",
      "error_text": "Error!",
      "links": {"privacyLink": {"url": "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894"}},
    },
  },
  {
    "id": "NEWSLETTER_TEST_1",
    "template": "newsletter_snippet",
    "content": {
      "scene1_icon": TEST_ICON,
      "scene1_title": "Be a part of a movement.",
      "scene1_title_icon": "",
      "scene1_text": "Internet shutdowns, hackers, harassment – the health of the internet is on the line. Sign up and Mozilla will keep you updated on how you can help.",
      "scene1_button_label": "Continue",
      "scene1_button_color": "#712b00",
      "scene1_button_background_color": "#ff9400",
      "scene2_title": "Let's do this!",
      "locale": "en-CA",
      "scene2_dismiss_button_text": "Dismiss",
      "scene2_text": "Sign up for the Mozilla newsletter and we will keep you updated on how you can help.",
      "scene2_privacy_html": "I'm okay with Mozilla handling my info as explained in this <privacyLink>Privacy Notice</privacyLink>.",
      "scene2_button_label": "Sign Me up",
      "scene2_email_placeholder_text": "Your email here",
      "scene2_newsletter": "mozilla-foundation",
      "form_action": "https://basket.mozilla.org/subscribe.json",
      "success_text": "Check your inbox for the confirmation!",
      "error_text": "Error!",
      "links": {"privacyLink": {"url": "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894"}},
    },
  },
  {
    "id": "FXA_SNIPPET_TEST_1",
    "template": "fxa_signup_snippet",
    "content": {
      "scene1_icon": TEST_ICON,
      "scene1_button_label": "Get connected with sync!",
      "scene1_button_color": "#712b00",
      "scene1_button_background_color": "#ff9400",

      "scene1_text": "Connect to Firefox by securely syncing passwords, bookmarks, and open tabs.",
      "scene1_title": "Browser better.",
      "scene1_title_icon": "",

      "scene2_text": "Connect to your Firefox account to securely sync passwords, bookmarks, and open tabs.",
      "scene2_title": "Title 123",
      "scene2_email_placeholder_text": "Your email",
      "scene2_button_label": "Continue",
      "scene2_dismiss_button_text": "Dismiss",
      "form_action": "https://basket.mozilla.org/subscribe.json",
    },
  },
  {
    id: "SNIPPETS_SEND_TO_DEVICE_TEST",
    template: "send_to_device_snippet",
    content: {
      include_sms: true,
      locale: "en-CA",
      country: "us",
      message_id_sms: "ff-mobilesn-download",
      message_id_email: "download-firefox-mobile",

      scene1_button_background_color: "#6200a4",
      scene1_button_color: "#FFFFFF",
      scene1_button_label: "Install now",
      scene1_icon: TEST_ICON,
      scene1_text: "Browse without compromise with Firefox Mobile.",
      scene1_title: "Full-featured. Customizable. Lightning fast",
      scene1_title_icon: "",

      scene2_button_label: "Send",
      scene2_disclaimer_html: "The intended recipient of the email must have consented. <privacyLink>Learn more.</privacyLink>",
      scene2_dismiss_button_text: "Dismiss",
      scene2_icon: TEST_ICON,
      scene2_input_placeholder: "Your email address or phone number",
      scene2_text: "Send Firefox to your phone and take a powerful independent browser with you.",
      scene2_title: "Let's do this!",

      error_text: "Oops, there was a problem.",
      success_title: "Your download link was sent.",
      success_text: "Check your device for the email message!",
      links: {"privacyLink": {"url": "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894"}},
    },
  },
  {
    "id": "EOY_TEST_1",
    "template": "eoy_snippet",
    "content": {
      "highlight_color": "#f05",
      "selected_button": "donation_amount_first",
      "icon": TEST_ICON,
      "button_label": "Donate",
      "monthly_checkbox_label_text": "Make my donation monthly",
      "currency_code": "usd",
      "donation_amount_first": 50,
      "donation_amount_second": 25,
      "donation_amount_third": 10,
      "donation_amount_fourth": 5,
      "donation_form_url": "https://donate.mozilla.org",
      "text": "Big corporations want to restrict how we access the web. Fake news is making it harder for us to find the truth. Online bullies are silencing inspired voices. The not-for-profit Mozilla Foundation fights for a healthy internet with programs like our Tech Policy Fellowships and Internet Health Report; will you donate today?",
    },
  },
  {
    "id": "EOY_BOLD_TEST_1",
    "template": "eoy_snippet",
    "content": {
      "icon": TEST_ICON,
      "selected_button": "donation_amount_second",
      "button_label": "Donate",
      "monthly_checkbox_label_text": "Make my donation monthly",
      "currency_code": "usd",
      "donation_amount_first": 50,
      "donation_amount_second": 25,
      "donation_amount_third": 10,
      "donation_amount_fourth": 5,
      "donation_form_url": "https://donate.mozilla.org",
      "text": "Big corporations want to restrict how we access the web. Fake news is making it harder for us to find the truth. Online bullies are silencing inspired voices. The not-for-profit Mozilla Foundation fights for a healthy internet with programs like our Tech Policy Fellowships and Internet Health Report; will you donate today?",
      "test": "bold",
    },
  },
  {
    "id": "EOY_TAKEOVER_TEST_1",
    "template": "eoy_snippet",
    "content": {
      "icon": TEST_ICON,
      "button_label": "Donate",
      "monthly_checkbox_label_text": "Make my donation monthly",
      "currency_code": "usd",
      "donation_amount_first": 50,
      "donation_amount_second": 25,
      "donation_amount_third": 10,
      "donation_amount_fourth": 5,
      "donation_form_url": "https://donate.mozilla.org",
      "text": "Big corporations want to restrict how we access the web. Fake news is making it harder for us to find the truth. Online bullies are silencing inspired voices. The not-for-profit Mozilla Foundation fights for a healthy internet with programs like our Tech Policy Fellowships and Internet Health Report; will you donate today?",
      "test": "takeover",
    },
  },
]);

const SnippetsTestMessageProvider = {
  getMessages() {
    return MESSAGES()
      // Ensures we never actually show test except when triggered by debug tools
      .map(message => ({...message, targeting: `providerCohorts.snippets_local_testing == "SHOW_TEST"`}));
  },
};
this.SnippetsTestMessageProvider = SnippetsTestMessageProvider;

const EXPORTED_SYMBOLS = ["SnippetsTestMessageProvider"];
<|endoftext|>


<commit_before>var path = require('path')

var o = require('atom').o(module);
var oo = require('atom').oo(module);
var _o = require('bond')._o(module);
var _ = require('underscore');

/*******************************************************************************
 * @class StaticDocumentationGenerator
 */
var StaticDocumentationGenerator = oo({
  /**********************************************************************
   * _C
   */
  _C: function(objectserver) {
    if (objectserver) {
      this._objectserver = objectserver
    }
    else {
      this._objectserver = null
    }
  },

  /**********************************************************************
   * generate api docs
   *
   * @abstract
   * @throws Error
   */
  generateDocs: function(docsPath, singlePage) {
    throw new Error('not implemented')
  },

  /**********************************************************************
   * build api descriptor object to be used by static docs plugins
   *
   * @param {object} options
   * @param {...} options.
   * @returns {object} the descriptor for the api
   */
  _generateDescriptor: function() {
    var self = this

    return {
      version: '1.0.0', // XXX ?
      title: self._objectserver.serviceName || 'ObjectServer',

      description: self._objectserver.description,
      longDescription: null,

      // headers, query, path, body
      parameters: self._generateParameterDescriptors(self._objectserver.parameters),

      // XXX: not implemented
      securityModel: null,

      // XXX: should probably pull these from the object server
      schemes: ['http'],
      consumes: ['application/json'],
      produces: ['application/json'],

      // this should be a flattened list of endpoints
      endpoints : self._generateEndpointDescriptors()
    }
  },

  /**********************************************************************
   * flattens and sorts endpoint tree in objectserver (potentially too
   * much nesting otherwise).
   *
   * @returns {array}
   */
  _generateEndpointDescriptors: function() {
    var self = this

    var endpoints = new Array()

    var flatten = function(eps, topLevel, parentPath) {
      for (var _path in eps) {
        var absPath = path.join(parentPath, _path)
        endpoints.push({
          path: absPath,
          topLevel: topLevel,
          endpoint: eps[_path]
        })
        if (eps[_path].endpoints) {
          flatten(eps[_path].endpoints, false, absPath)
        }
      }
    }

    flatten(self._objectserver.endpoints, true, '/')

    var methods = _o('./Endpoint').prototype.ALL_METHODS

    for (var i = 0; i < endpoints.length; i++) {
      var operations = methods.map(function(m) {
          if (endpoints[i].endpoint[m] &&
              (m != "options" || self._objectserver.generateOptionsMethodsInDocs)) {
            return self._generateOperationDescriptor(m, endpoints[i].endpoint[m])
          }
          return undefined
        }).filter(function(e) {
          return e ? true : false;
        })

      if (operations.length == 0) {
        continue
      }

      endpoints[i] = {
        path: endpoints[i].path,
        description: endpoints[i].description,
        topLevel: endpoints[i].topLevel,
        parameters: self._generateParameterDescriptors(endpoints[i].endpoint.parameters),
        allowUnauthenticated: endpoints[i].allowUnauthenticated,
        responseSchema: endpoints[i].responseSchema,
        operations: operations
      }
    }

    endpoints.sort(function(e1, e2) {
      if (e1.path < e2.path) {
        return -1
      }
      if (e1 > e2) {
        return 1
      }
      return 0
    })

    return endpoints
  },

  /**********************************************************************
   *
   *
   * @param {object} operation
   * @returns {array}
   */
  _generateOperationDescriptor: function(method, operation) {
    var self = this

    var allParameters = operation.getAllParameters()
    var inheritedParameters = _.keys(allParameters).reduce(function(obj, e) {
          if (! (e in operation.parameters)) {
            obj[e] = allParameters[e]
          }
          return obj
        }, {})

    // XXX: description is not currently a property of "Operation"

    return {
      method: method.toUpperCase(),
      description: operation.description,
      parameters: self._generateParameterDescriptors(operation.parameters, inheritedParameters),
      responseSchema: operation.responseSchema,
      errorResponses: operation.errorResponses

      // XXX: examples request/response
    }
  },

  /**********************************************************************
   * _generateParameterDescriptors
   *
   * @param {object} parameters
   * @param {object} inheritedParameters
   * @returns {object}
   */
  _generateParameterDescriptors: function(parameters, inheritedParameters) {
    var _parameters = {
      'path': [],
      'query': [],
      'body': [],
      'header':[]
    }
    var descriptor = function(parameter, inherited) {
      return {
          name: parameter.name,
          description: parameter.description,
          location: parameter.location,
          schema: parameter.schema,
          required: parameter.required,
          default: parameter.default,
          inherited: inherited,
      }
    }
    if (typeof inheritedParameters != "undefined") {
      for (var parameter in inheritedParameters) {
        _parameters[inheritedParameters[parameter].location].push(
          descriptor(inheritedParameters[parameter], true))
      }
    }
    for (var parameter in parameters) {
      _parameters[parameters[parameter].location].push(descriptor(parameters[parameter], false))
    }
    for (var location in _parameters) {
      if (_parameters[location].length == 0) {
        delete _parameters[location]
      }
    }
    return _parameters
  }

})

/*******************************************************************************
 * Map of doc types to generator classes.
 *
 * @protected
 * @memberof StaticDocumentationGenerator
 * @static
 */
StaticDocumentationGenerator._registeredTypes = {}

/*******************************************************************************
 * Register a generator class for a specific type.
 *
 * @function registerType
 * @memberof StaticDocumentationGenerator
 * @static
 *
 * @param {string} docType
 * @param {class} cls
 */
StaticDocumentationGenerator.registerType = function(docType, cls) {
  if (typeof docType != 'string') {
    throw new TypeError('docType does not appear to be a string')
  }
  // XXX: how do we check that this is a class (constructor) versus a function?
  if (typeof cls != 'function') {
    throw new TypeError('cls does not appear to be a class')
  }
  StaticDocumentationGenerator._registeredTypes[docType] = cls
}

/*******************************************************************************
 * Create a generator for a particular doc type.
 *
 * @function createGenerator
 * @memberof StaticDocumentationGenerator
 * @static
 *
 * @param {string} docType
 * @returns {StaticDocumentationGenerator}
 */
StaticDocumentationGenerator.createGenerator = function(docType, objectserver) {
  if (!docType in StaticDocumentationGenerator._registeredTypes) {
    throw new Error('no handler registered for ' + docType)
  }
  return new StaticDocumentationGenerator._registeredTypes[docType](objectserver)
}

module.exports = StaticDocumentationGenerator

// register doc generator "plugins"
// XXX: can we avoid including these
require('./GHMDGenerator.js')
<commit_msg>fix bad require<commit_after>var path = require('path')

var o = require('atom').o(module);
var oo = require('atom').oo(module);
var _o = require('bond')._o(module);
var _ = require('lodash');

/*******************************************************************************
 * @class StaticDocumentationGenerator
 */
var StaticDocumentationGenerator = oo({
  /**********************************************************************
   * _C
   */
  _C: function(objectserver) {
    if (objectserver) {
      this._objectserver = objectserver
    }
    else {
      this._objectserver = null
    }
  },

  /**********************************************************************
   * generate api docs
   *
   * @abstract
   * @throws Error
   */
  generateDocs: function(docsPath, singlePage) {
    throw new Error('not implemented')
  },

  /**********************************************************************
   * build api descriptor object to be used by static docs plugins
   *
   * @param {object} options
   * @param {...} options.
   * @returns {object} the descriptor for the api
   */
  _generateDescriptor: function() {
    var self = this

    return {
      version: '1.0.0', // XXX ?
      title: self._objectserver.serviceName || 'ObjectServer',

      description: self._objectserver.description,
      longDescription: null,

      // headers, query, path, body
      parameters: self._generateParameterDescriptors(self._objectserver.parameters),

      // XXX: not implemented
      securityModel: null,

      // XXX: should probably pull these from the object server
      schemes: ['http'],
      consumes: ['application/json'],
      produces: ['application/json'],

      // this should be a flattened list of endpoints
      endpoints : self._generateEndpointDescriptors()
    }
  },

  /**********************************************************************
   * flattens and sorts endpoint tree in objectserver (potentially too
   * much nesting otherwise).
   *
   * @returns {array}
   */
  _generateEndpointDescriptors: function() {
    var self = this

    var endpoints = new Array()

    var flatten = function(eps, topLevel, parentPath) {
      for (var _path in eps) {
        var absPath = path.join(parentPath, _path)
        endpoints.push({
          path: absPath,
          topLevel: topLevel,
          endpoint: eps[_path]
        })
        if (eps[_path].endpoints) {
          flatten(eps[_path].endpoints, false, absPath)
        }
      }
    }

    flatten(self._objectserver.endpoints, true, '/')

    var methods = _o('./Endpoint').prototype.ALL_METHODS

    for (var i = 0; i < endpoints.length; i++) {
      var operations = methods.map(function(m) {
          if (endpoints[i].endpoint[m] &&
              (m != "options" || self._objectserver.generateOptionsMethodsInDocs)) {
            return self._generateOperationDescriptor(m, endpoints[i].endpoint[m])
          }
          return undefined
        }).filter(function(e) {
          return e ? true : false;
        })

      if (operations.length == 0) {
        continue
      }

      endpoints[i] = {
        path: endpoints[i].path,
        description: endpoints[i].description,
        topLevel: endpoints[i].topLevel,
        parameters: self._generateParameterDescriptors(endpoints[i].endpoint.parameters),
        allowUnauthenticated: endpoints[i].allowUnauthenticated,
        responseSchema: endpoints[i].responseSchema,
        operations: operations
      }
    }

    endpoints.sort(function(e1, e2) {
      if (e1.path < e2.path) {
        return -1
      }
      if (e1 > e2) {
        return 1
      }
      return 0
    })

    return endpoints
  },

  /**********************************************************************
   *
   *
   * @param {object} operation
   * @returns {array}
   */
  _generateOperationDescriptor: function(method, operation) {
    var self = this

    var allParameters = operation.getAllParameters()
    var inheritedParameters = _.keys(allParameters).reduce(function(obj, e) {
          if (! (e in operation.parameters)) {
            obj[e] = allParameters[e]
          }
          return obj
        }, {})

    // XXX: description is not currently a property of "Operation"

    return {
      method: method.toUpperCase(),
      description: operation.description,
      parameters: self._generateParameterDescriptors(operation.parameters, inheritedParameters),
      responseSchema: operation.responseSchema,
      errorResponses: operation.errorResponses

      // XXX: examples request/response
    }
  },

  /**********************************************************************
   * _generateParameterDescriptors
   *
   * @param {object} parameters
   * @param {object} inheritedParameters
   * @returns {object}
   */
  _generateParameterDescriptors: function(parameters, inheritedParameters) {
    var _parameters = {
      'path': [],
      'query': [],
      'body': [],
      'header':[]
    }
    var descriptor = function(parameter, inherited) {
      return {
          name: parameter.name,
          description: parameter.description,
          location: parameter.location,
          schema: parameter.schema,
          required: parameter.required,
          default: parameter.default,
          inherited: inherited,
      }
    }
    if (typeof inheritedParameters != "undefined") {
      for (var parameter in inheritedParameters) {
        _parameters[inheritedParameters[parameter].location].push(
          descriptor(inheritedParameters[parameter], true))
      }
    }
    for (var parameter in parameters) {
      _parameters[parameters[parameter].location].push(descriptor(parameters[parameter], false))
    }
    for (var location in _parameters) {
      if (_parameters[location].length == 0) {
        delete _parameters[location]
      }
    }
    return _parameters
  }

})

/*******************************************************************************
 * Map of doc types to generator classes.
 *
 * @protected
 * @memberof StaticDocumentationGenerator
 * @static
 */
StaticDocumentationGenerator._registeredTypes = {}

/*******************************************************************************
 * Register a generator class for a specific type.
 *
 * @function registerType
 * @memberof StaticDocumentationGenerator
 * @static
 *
 * @param {string} docType
 * @param {class} cls
 */
StaticDocumentationGenerator.registerType = function(docType, cls) {
  if (typeof docType != 'string') {
    throw new TypeError('docType does not appear to be a string')
  }
  // XXX: how do we check that this is a class (constructor) versus a function?
  if (typeof cls != 'function') {
    throw new TypeError('cls does not appear to be a class')
  }
  StaticDocumentationGenerator._registeredTypes[docType] = cls
}

/*******************************************************************************
 * Create a generator for a particular doc type.
 *
 * @function createGenerator
 * @memberof StaticDocumentationGenerator
 * @static
 *
 * @param {string} docType
 * @returns {StaticDocumentationGenerator}
 */
StaticDocumentationGenerator.createGenerator = function(docType, objectserver) {
  if (!docType in StaticDocumentationGenerator._registeredTypes) {
    throw new Error('no handler registered for ' + docType)
  }
  return new StaticDocumentationGenerator._registeredTypes[docType](objectserver)
}

module.exports = StaticDocumentationGenerator

// register doc generator "plugins"
// XXX: can we avoid including these
require('./GHMDGenerator.js')
<|endoftext|>


<commit_before>var Frequency = require('../lib/frequency');

/*
  ======== A Handy Little Nodeunit Reference ========
  https://github.com/caolan/nodeunit

  Test methods:
    test.expect(numAssertions)
    test.done()
  Test assertions:
    test.ok(value, [message])
    test.equal(actual, expected, [message])
    test.notEqual(actual, expected, [message])
    test.deepEqual(actual, expected, [message])
    test.notDeepEqual(actual, expected, [message])
    test.strictEqual(actual, expected, [message])
    test.notStrictEqual(actual, expected, [message])
    test.throws(block, [error], [message])
    test.doesNotThrow(block, [error], [message])
    test.ifError(value)
*/

module.exports = {
  'on': function (test) {
    var f = new Frequency(),
      tmp = f.on('hour', 10);

    test.deepEqual(f, tmp, 'on should return frequency object');
    test.equal(typeof f.rules, 'array', 'on should create rules property');

    f.on('day', 6).on('hour', 10);

    test.equal(f.rules.length, 2, 'rules should be chainable');

    test.done();
  },
  'next': function (test) {
    var f = new Frequency();

    f.on('hour', 10);

    test.equal(f.next(new Date(2013, 8, 2)), new Date(2013, 8, 2, 10, 0, 0), 'next should return next instance');

    test.done();
  },
  'between': function (test) {
    var f = new Frequency(),
      start = new Date(2013, 8, 2),
      end = new Date(2013, 8, 9);

    f.on('hour', 10);

    test.equal(f.between(start, end).length, 7, 'between should return an array of dates');

    test.done();
  }
};
<commit_msg>improved tests<commit_after>var Frequency = require('../lib/frequency');

/*
  ======== A Handy Little Nodeunit Reference ========
  https://github.com/caolan/nodeunit

  Test methods:
    test.expect(numAssertions)
    test.done()
  Test assertions:
    test.ok(value, [message])
    test.equal(actual, expected, [message])
    test.notEqual(actual, expected, [message])
    test.deepEqual(actual, expected, [message])
    test.notDeepEqual(actual, expected, [message])
    test.strictEqual(actual, expected, [message])
    test.notStrictEqual(actual, expected, [message])
    test.throws(block, [error], [message])
    test.doesNotThrow(block, [error], [message])
    test.ifError(value)
*/

module.exports = {
  'on': function (test) {
    var f = new Frequency(),
      tmp = f.on('hour', 10);

    test.deepEqual(f, tmp, 'on should be chainable');

    test.done();
  },
  'next': function (test) {
    var f = new Frequency(),
      start = new Date(2013, 8, 2);

    test.equal(f.next(start), new Date(2013, 8, 2, 0, 0, 1), 'default frequency should be 1 second');

    f.on('hour', 10); // each day at 10:00:00
    test.equal(f.next(start), new Date(2013, 8, 2, 10, 0, 0), 'next should return next instance of frequency');

    f.on('hour', 0); // each day at 00:00:00
    test.equal(f.next(start), start, 'next should include passed date as instance');

    f.on('hour', 10, 'month'); // each 10th hour of the month
    test.equal(f.next(start), new Date(2013, 9, 1, 10, 0, 0), 'scope change should return correct instance');

    f.on('hour', 10).on('day', 2); // each Wednesday at 10:00:00
    test.equal(f.next(start), new Date(2013, 9, 4, 10, 0, 0), 'multiple rules should return correct instance');

    test.done();
  },
  'between': function (test) {
    var f = new Frequency(),
      start = new Date(2013, 8, 2),
      end = new Date(2013, 8, 9);

    f.on('hour', 10); // each day at 10:00:00

    test.equal(f.between(start, end).length, 7, 'between should return an array of dates');

    test.done();
  }
};
<|endoftext|>


<commit_before>

var God = require('..');
var numCPUs = require('os').cpus().length;
var fs = require('fs');
var path = require('path');

describe('God', function() {
  it('should have right properties', function() {
    God.should.have.property('prepare');
    God.should.have.property('getProcesses');
    God.should.have.property('getMonitorData');
    God.should.have.property('getFormatedProcesses');
    God.should.have.property('checkProcess');
    God.should.have.property('stopAll');
    God.should.have.property('stopProcessId');
  });

  describe('One process', function() {
    var proc;

    after(function(done) {
      God.stopAll(done);
    });

    it('should fork one process', function(done) {
      God.prepare({
	pm_exec_path : path.resolve(process.cwd(), 'test/fixtures/echo.js'),
	pm_err_log_path : path.resolve(process.cwd(), 'test/echoErr.log'),
	pm_out_log_path : path.resolve(process.cwd(), 'test/echoLog.log'),
	pm_pid_file : path.resolve(process.cwd(), 'test/echopid')
      }, function(err, proce) {
	proc = proce;
	proc.status.should.be.equal('online');
	God.getFormatedProcesses().length.should.equal(1);
	done();
      });
    });

    it('should stop process and no more present', function(done) {
      proc.status.should.be.equal('online');
      God.checkProcess(proc.process.pid).should.be.true;
      God.stopProcess(proc, function() {
	God.getFormatedProcesses().length.should.equal(0);
	God.checkProcess(proc.process.pid).should.be.false;
	proc.status.should.be.equal('stopped');
	done()
      });
    });

    // Process stopped are not anymore cached in db
    it.skip('should start the process', function(done) {
      God.startProcess(proc, function(err, proc) {
        God.checkProcess(proc.process.pid).should.be.true;
	proc.status.should.be.equal('online');
	God.getFormatedProcesses().length.should.equal(1);
	done();
      });
    });
  });

  describe('Multi launching', function() {
    it('should launch multiple processes depending on CPUs available', function(done) {
      God.prepare({
        pm_exec_path    : path.resolve(process.cwd(), 'test/fixtures/echo.js'),
        pm_err_log_path : path.resolve(process.cwd(), 'test/errLog.log'),
        pm_out_log_path : path.resolve(process.cwd(), 'test/outLog.log'),
        pm_pid_path     : path.resolve(process.cwd(), 'test/child'),
        instances       : 3
      }, function(err, procs) {
	God.getFormatedProcesses().length.should.equal(3);
        procs.length.should.equal(3);
        God.stopAll(done);
      });
    });

    it('should start maximum processes depending on CPU numbers', function(done) {
      God.prepare({
        pm_exec_path    : path.resolve(process.cwd(), 'test/fixtures/echo.js'),
        pm_err_log_path : path.resolve(process.cwd(), 'test/errLog.log'),
        pm_out_log_path : path.resolve(process.cwd(), 'test/outLog.log'),
        pm_pid_path     : path.resolve(process.cwd(), 'test/child'),
        instances       : 'max'
      }, function(err, procs) {
	God.getFormatedProcesses().length.should.equal(numCPUs);
        procs.length.should.equal(numCPUs);
        God.stopAll(done);
      });
    });

    it('should handle arguments', function(done) {
      God.prepare({
        pm_exec_path    : path.resolve(process.cwd(), 'test/fixtures/args.js'),
        pm_err_log_path : path.resolve(process.cwd(), 'test/errLog.log'),
        pm_out_log_path : path.resolve(process.cwd(), 'test/outLog.log'),
        pm_pid_path     : path.resolve(process.cwd(), 'test/child'),
        args            : '-d -a',
        instances       : '1'
      }, function(err, procs) {
        setTimeout(function() {
          God.getFormatedProcesses()[0].opts.restart_time.should.eql(0);
          God.stopAll(done);
        }, 400);
      });
    });

  });

});
<commit_msg>travis & 34 cpus<commit_after>

var God = require('..');
var numCPUs = require('os').cpus().length;
var fs = require('fs');
var path = require('path');

describe('God', function() {
  it('should have right properties', function() {
    God.should.have.property('prepare');
    God.should.have.property('getProcesses');
    God.should.have.property('getMonitorData');
    God.should.have.property('getFormatedProcesses');
    God.should.have.property('checkProcess');
    God.should.have.property('stopAll');
    God.should.have.property('stopProcessId');
  });

  describe('One process', function() {
    var proc;

    after(function(done) {
      God.stopAll(done);
    });

    it('should fork one process', function(done) {
      God.prepare({
	pm_exec_path : path.resolve(process.cwd(), 'test/fixtures/echo.js'),
	pm_err_log_path : path.resolve(process.cwd(), 'test/echoErr.log'),
	pm_out_log_path : path.resolve(process.cwd(), 'test/echoLog.log'),
	pm_pid_file : path.resolve(process.cwd(), 'test/echopid')
      }, function(err, proce) {
	proc = proce;
	proc.status.should.be.equal('online');
	God.getFormatedProcesses().length.should.equal(1);
	done();
      });
    });

    it('should stop process and no more present', function(done) {
      proc.status.should.be.equal('online');
      God.checkProcess(proc.process.pid).should.be.true;
      God.stopProcess(proc, function() {
	God.getFormatedProcesses().length.should.equal(0);
	God.checkProcess(proc.process.pid).should.be.false;
	proc.status.should.be.equal('stopped');
	done()
      });
    });

    // Process stopped are not anymore cached in db
    it.skip('should start the process', function(done) {
      God.startProcess(proc, function(err, proc) {
        God.checkProcess(proc.process.pid).should.be.true;
	proc.status.should.be.equal('online');
	God.getFormatedProcesses().length.should.equal(1);
	done();
      });
    });
  });

  describe('Multi launching', function() {
    it('should launch multiple processes depending on CPUs available', function(done) {
      God.prepare({
        pm_exec_path    : path.resolve(process.cwd(), 'test/fixtures/echo.js'),
        pm_err_log_path : path.resolve(process.cwd(), 'test/errLog.log'),
        pm_out_log_path : path.resolve(process.cwd(), 'test/outLog.log'),
        pm_pid_path     : path.resolve(process.cwd(), 'test/child'),
        instances       : 3
      }, function(err, procs) {
	God.getFormatedProcesses().length.should.equal(3);
        procs.length.should.equal(3);
        God.stopAll(done);
      });
    });

    it('should start maximum processes depending on CPU numbers', function(done) {
      God.prepare({
        pm_exec_path    : path.resolve(process.cwd(), 'test/fixtures/echo.js'),
        pm_err_log_path : path.resolve(process.cwd(), 'test/errLog.log'),
        pm_out_log_path : path.resolve(process.cwd(), 'test/outLog.log'),
        pm_pid_path     : path.resolve(process.cwd(), 'test/child'),
        instances       : 10
      }, function(err, procs) {
	God.getFormatedProcesses().length.should.equal(10);
        procs.length.should.equal(10);
        God.stopAll(done);
      });
    });

    it('should handle arguments', function(done) {
      God.prepare({
        pm_exec_path    : path.resolve(process.cwd(), 'test/fixtures/args.js'),
        pm_err_log_path : path.resolve(process.cwd(), 'test/errLog.log'),
        pm_out_log_path : path.resolve(process.cwd(), 'test/outLog.log'),
        pm_pid_path     : path.resolve(process.cwd(), 'test/child'),
        args            : '-d -a',
        instances       : '1'
      }, function(err, procs) {
        setTimeout(function() {
          God.getFormatedProcesses()[0].opts.restart_time.should.eql(0);
          God.stopAll(done);
        }, 400);
      });
    });

  });

});
<|endoftext|>


<commit_before>// GET /db/{db}/groups/{id}
// Groups / List all group members
//
// Alpha @ 0.1.23
//
// `200 OK`,
// [Read-only](/docs/#/concept/read-only.md),
// [Paginated](/docs/#/concept/paginated.md).
//
// Returns all the contacts in the specified group, in arbitrary order.
// Supports `limit` and `offset` pagination.
//
// ### Response format
//     { "list": [ <shortcontact>, ... ],
//       "count": <int> }
// - `list` is a list of contacts on the requested page, in
//   [short format](/docs/#/contact/short-contact.js)
// - `count` is the total number of contacts in the group.

TODO("The response has valid return code and content type.", function(next) {
    Assert.fail();
});

// # Examples
//
// ### Example request
//     GET /db/0SNQc00211H/groups/0SNQe0032JZ?limit=3&offset=213
//
// ### Example response
//     200 OK
//     Content-Type: application/json
//
//     { "list" : [
//       { "id" : "0SNQe00311H",
//         "name" : "test@runorg.com",
//         "gender" : null,
//         "pic" : "https://www.gravatar.com/avatar/1ed54d253636f5b33eff32c2d5573f70" },
//       { "id" : "0SNQg00511H",
//         "name" : "vnicollet@runorg.com",
//         "gender" : null,
//         "pic" : "https://www.gravatar.com/avatar/5a31b00f649489a9a24d3dc3e8b28060"} ],
//       "count" : 215 }

TODO("Returns correct number of contacts in count.", function(next) {
    Assert.fail();
});

TODO("Returns data for all contacts.", function(next) {
    Assert.fail();
});

// # Errors
//
// ## Returns `404 Not Found`
// - ... if database `{db}` does not exist

TODO("Returns 404 when database does not exist.", function(next) {
    Assert.fail();
});

// - ... if group `{id}` does not exist in database `{db}`

TODO("Returns 404 when group does not exist.", function(next) {
    Assert.fail();
});

// ## Returns `401 Unauthorized`
// - ... if the provided token does not grant access to all contacts,
//   or no token was provided

TODO("Returns 401 when token is not valid.", function(next) {
    Assert.fail();
});

// # Access restrictions
//
// Currently, anyone can list all members of a group with a token for the corresponding database.
// This is subject to change in future versions.
<commit_msg>Update old tests for GET /groups/{id}<commit_after>// GET /db/{db}/groups/{id}
// Groups / List all group members
//
// Alpha @ 0.1.23
//
// `200 OK`,
// [Read-only](/docs/#/concept/read-only.md),
// [Paginated](/docs/#/concept/paginated.md).
//
// Returns all the [people](/docs/#/person.md) in the specified group, in
// arbitrary order. Supports `limit` and `offset` pagination.
//
// ### Response format
//     { "list": [ <person>, ... ],
//       "count": <int> }
// - `list` is a list of contacts on the requested page, in
//   [short format](/docs/#/person/short.js)
// - `count` is the total number of members in the group.

TEST("The response has valid return code and content type.", function(Query) {

    var db = Query.mkdb();
    var auth = Query.auth(db);
    var id = Query.post(["db/",db,"/groups"],{},auth).id();
    return Query.get(["db/",db,"/groups/",id],auth)
	.assertStatus(200).assertIsJson();

});

// # Examples
//
// ### Example request
//     GET /db/0SNQc00211H/groups/0SNQe0032JZ?limit=3&offset=213
//
// ### Example response
//     200 OK
//     Content-Type: application/json
//
//     { "list" : [
//       { "id" : "0SNQe00311H",
//         "label" : "George Sand",
//         "gender" : "f",
//         "pic" : "https://www.gravatar.com/avatar/1ed54d253636f5b33eff32c2d5573f70" },
//       { "id" : "0SNQg00511H",
//         "label" : "Victor Hugo",
//         "gender" : "m",
//         "pic" : "https://www.gravatar.com/avatar/5a31b00f649489a9a24d3dc3e8b28061"} ],
//       "count" : 215 }

TEST("Returns correct number of contacts in count.", function(Query) {

    var db = Query.mkdb();
    var auth = Query.auth(db);
    var other = Query.auth(db,true,"test+2@runorg.com");

    return $.when(auth,other).then(function() {
	var count = Query.get(["db/",db,"/groups/admin?limit=1"],auth).then(function(d) { return d.count; });
	return Assert.areEqual(2,count);
    });

});

TEST("Returns data for all contacts.", function(Query) {

    var db = Query.mkdb();
    var auth = Query.auth(db);
    var other = Query.auth(db,true,"test+2@runorg.com");

    return $.when(auth,other).then(function() {

	var list = Query.get(["db/",db,"/groups/admin"],auth).then(function(d) { return d.list; });
	var expected = [{
	    "id" : other.id,
	    "label" : "test+2@runorg.com",
	    "gender" : null,
	    "pic" : "https://www.gravatar.com/avatar/fcf1ec969e2da183f88f5a6dca0c1d65?d=identicon"
	}, {
	    "id" : auth.id,
	    "label" : "test@runorg.com",
	    "gender" : null,
	    "pic" : "https://www.gravatar.com/avatar/1ed54d253636f5b33eff32c2d5573f70?d=identicon"
	}];

	return Assert.areEqual(expected,list);
    });

});

// # Errors
//
// ## Returns `401 Unauthorized`
// - ... if the provided token does not allow acting as `{as}`.

TEST("Returns 401 when token is not valid.", function(Query) {
    var db = Query.mkdb();
    return Query.get(["db/",db,"/groups/admin"],{id:"01234567890",token:"01234567890"})
	.assertStatus(401);
});

//
// ## Returns `403 Forbidden`
// - ... if `{as}` does not have **list** access to the group.

TEST("Returns 403 when no 'list' access.", function(Query) {
    var db = Query.mkdb();
    var auth = Query.auth(db);
    var id = Query.post(["db/",db,"/groups"],{"audience":{"view":"anyone"}},auth).id();
    var peon = Query.auth(db, false, "peon@runorg.com");
    return Query.get(["db/",db,"/groups/admin"])
	.assertStatus(403);
});

//
// ## Returns `404 Not Found`
// - ... if database `{db}` does not exist

TEST("Returns 404 when database does not exist.", function(Query) {
    return Query.get(["db/00000000000/groups/admin"]).assertStatus(404);
});

// - ... if group `{id}` does not exist in database `{db}`
TEST("Returns 404 when group does not exist.", function(Query) {
    var db = Query.mkdb();
    var auth = Query.auth(db);
    return Query.get(["db/",db,"/groups/00000000000"],auth).assertStatus(404);
});

// - ... if `{as}` does not have at least **view** access to the
//   group, to ensure [absence equivalence](/docs/#/concept/absence-equivalence.md)

TEST("Returns 404 when no 'view' access.", function(Query) {
    var db = Query.mkdb();
    // Create admin to auto-create admin group
    return Query.auth(db).id.then(function() {
	var peon = Query.auth(db,false,"peon@runorg.com");
	return Query.get(["db/",db,"/groups/admin"],peon).assertStatus(404);
    });
});

// # Access restrictions
//
// An [access level](/docs/#/group/audience.js) of **list** is
// required to view the members of a group.<|endoftext|>


<commit_before>import { expect } from 'chai';
import sinon from 'sinon';
import hibp from '../src';
import './mockAxios';
import {
  BAD_REQUEST,
  FORBIDDEN,
  TOO_MANY_REQUESTS,
} from '../src/responses';
import {
  UNKNOWN,
  ERR,
  INVALID_HEADER,
  RATE_LIMITED,
  UNEXPECTED,
  ACCOUNT_BREACHED,
  ACCOUNT_CLEAN,
  BREACH_FOUND,
  BREACH_NOT_FOUND,
  EMAIL_PASTED,
  EMAIL_CLEAN,
  EMAIL_INVALID,
  OPTS_DOM,
  OPTS_TRUNC,
  OPTS_DOM_TRUNC,
  RESPONSE_OBJ,
  RESPONSE_ARY,
  RESPONSE_CLEAN,
} from './testData';

describe('hibp', () => {
  describe('_fetchFromApi (request failure)', () => {
    let failboat;

    before(() => {
      failboat = hibp._axios.interceptors.request.use(() => {
        throw ERR;
      });
    });

    after(() => {
      hibp._axios.interceptors.request.eject(failboat);
    });

    it('should re-throw request setup errors', () => {
      const handler = sinon.spy();
      const errorHandler = sinon.spy();
      return hibp.dataClasses()
        .then(handler)
        .catch(errorHandler)
        .then(() => {
          expect(handler.called).to.be.false;
          expect(errorHandler.calledOnce).to.be.true;
          const err = errorHandler.getCall(0).args[0];
          expect(err).to.equal(ERR);
        });
    });
  });

  describe('_fetchFromApi (invalid account format)', () => {
    it('should throw an Error with "Bad Request" status text', () => {
      const handler = sinon.spy();
      const errorHandler = sinon.spy();
      return hibp.breachedAccount(EMAIL_INVALID)
        .then(handler)
        .catch(errorHandler)
        .then(() => {
          expect(handler.called).to.be.false;
          expect(errorHandler.calledOnce).to.be.true;
          const err = errorHandler.getCall(0).args[0];
          expect(err.message).to.match(new RegExp(BAD_REQUEST.statusText));
        });
    });
  });

  describe('_fetchFromApi (invalid request header)', () => {
    it('should throw an Error with "Forbidden" status text', () => {
      const handler = sinon.spy();
      const errorHandler = sinon.spy();
      return hibp.breachedAccount(INVALID_HEADER)
        .then(handler)
        .catch(errorHandler)
        .then(() => {
          expect(handler.called).to.be.false;
          expect(errorHandler.calledOnce).to.be.true;
          const err = errorHandler.getCall(0).args[0];
          expect(err.message).to.match(new RegExp(FORBIDDEN.statusText));
        });
    });
  });

  describe('_fetchFromApi (rate limited)', () => {
    it('should throw an Error with "Too Many Requests" response data', () => {
      const handler = sinon.spy();
      const errorHandler = sinon.spy();
      return hibp.breachedAccount(RATE_LIMITED)
        .then(handler)
        .catch(errorHandler)
        .then(() => {
          expect(handler.called).to.be.false;
          expect(errorHandler.calledOnce).to.be.true;
          const err = errorHandler.getCall(0).args[0];
          expect(err.message).to.match(new RegExp(TOO_MANY_REQUESTS.response));
        });
    });
  });

  describe('_fetchFromApi (unexpected HTTP error)', () => {
    it('should throw an Error with the response status text', () => {
      const handler = sinon.spy();
      const errorHandler = sinon.spy();
      return hibp.breachedAccount(UNEXPECTED)
        .then(handler)
        .catch(errorHandler)
        .then(() => {
          expect(handler.called).to.be.false;
          expect(errorHandler.calledOnce).to.be.true;
          const err = errorHandler.getCall(0).args[0];
          expect(err.message).to.match(new RegExp(UNKNOWN.statusText));
        });
    });
  });

  describe('breachedAccount (breached account, no parameters)', () => {
    it('should resolve with an object', () => {
      const handler = sinon.spy();
      return hibp.breachedAccount(ACCOUNT_BREACHED)
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_OBJ);
        });
    });
  });

  describe('breachedAccount (breached account, with truncateResults)', () => {
    it('should resolve with an object', () => {
      const handler = sinon.spy();
      return hibp.breachedAccount(ACCOUNT_BREACHED, OPTS_TRUNC)
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_OBJ);
        });
    });
  });

  describe('breachedAccount (breached account, with domain)', () => {
    it('should resolve with an object', () => {
      const handler = sinon.spy();
      return hibp.breachedAccount(ACCOUNT_BREACHED, OPTS_DOM)
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_OBJ);
        });
    });
  });

  describe('breachedAccount (breached account, with domain and ' +
    'truncateResults)', () => {
    it('should resolve with an object', () => {
      const handler = sinon.spy();
      return hibp.breachedAccount(ACCOUNT_BREACHED, OPTS_DOM_TRUNC)
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_OBJ);
        });
    });
  });

  describe('breachedAccount (clean account, no parameters)', () => {
    it('should resolve with null', () => {
      const handler = sinon.spy();
      return hibp.breachedAccount(ACCOUNT_CLEAN)
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_CLEAN);
        });
    });
  });

  describe('breachedAccount (clean account, with truncateResults)', () => {
    it('should resolve with null', () => {
      const handler = sinon.spy();
      return hibp.breachedAccount(ACCOUNT_CLEAN, OPTS_TRUNC)
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_CLEAN);
        });
    });
  });

  describe('breachedAccount (clean account, with domain)', () => {
    it('should resolve with null', () => {
      const handler = sinon.spy();
      return hibp.breachedAccount(ACCOUNT_CLEAN, OPTS_DOM)
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_CLEAN);
        });
    });
  });

  describe('breachedAccount (clean account, with domain and truncateResults)',
    () => {
      it('should resolve with null', () => {
        const handler = sinon.spy();
        return hibp.breachedAccount(ACCOUNT_CLEAN, OPTS_DOM_TRUNC)
          .then(handler)
          .then(() => {
            expect(handler.calledOnce).to.be.true;
            expect(handler.getCall(0).args[0]).to.equal(RESPONSE_CLEAN);
          });
      });
    });

  describe('breaches (no parameters)', () => {
    it('should resolve with an array', () => {
      const handler = sinon.spy();
      return hibp.breaches()
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_ARY);
        });
    });
  });

  describe('breaches (with domain)', () => {
    it('should resolve with an array', () => {
      const handler = sinon.spy();
      return hibp.breaches(OPTS_DOM)
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_ARY);
        });
    });
  });

  describe('breach (found)', () => {
    it('should resolve with an object', () => {
      const handler = sinon.spy();
      return hibp.breach(BREACH_FOUND)
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_OBJ);
        });
    });
  });

  describe('breach (not found)', () => {
    it('should resolve with null', () => {
      const handler = sinon.spy();
      return hibp.breach(BREACH_NOT_FOUND)
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_CLEAN);
        });
    });
  });

  describe('dataClasses', () => {
    it('should resolve with an array', () => {
      const handler = sinon.spy();
      return hibp.dataClasses()
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_ARY);
        });
    });
  });

  describe('pasteAccount (pasted email)', () => {
    it('should resolve with an array', () => {
      const handler = sinon.spy();
      return hibp.pasteAccount(EMAIL_PASTED)
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_ARY);
        });
    });
  });

  describe('pasteAccount (clean email)', () => {
    it('should resolve with null', () => {
      const handler = sinon.spy();
      return hibp.pasteAccount(EMAIL_CLEAN)
        .then(handler)
        .then(() => {
          expect(handler.calledOnce).to.be.true;
          expect(handler.getCall(0).args[0]).to.equal(RESPONSE_CLEAN);
        });
    });
  });
});
<commit_msg>Share spies and refactor syntax in tests<commit_after>import { expect } from 'chai';
import sinon from 'sinon';
import hibp from '../src';
import './mockAxios';
import {
  BAD_REQUEST,
  FORBIDDEN,
  TOO_MANY_REQUESTS,
} from '../src/responses';
import {
  UNKNOWN,
  ERR,
  INVALID_HEADER,
  RATE_LIMITED,
  UNEXPECTED,
  ACCOUNT_BREACHED,
  ACCOUNT_CLEAN,
  BREACH_FOUND,
  BREACH_NOT_FOUND,
  EMAIL_PASTED,
  EMAIL_CLEAN,
  EMAIL_INVALID,
  OPTS_DOM,
  OPTS_TRUNC,
  OPTS_DOM_TRUNC,
  RESPONSE_OBJ,
  RESPONSE_ARY,
  RESPONSE_CLEAN,
} from './testData';

describe('hibp', () => {
  const successHandler = sinon.spy();
  const errorHandler = sinon.spy();

  afterEach(() => {
    successHandler.reset();
    errorHandler.reset();
  });

  describe('_fetchFromApi (request failure)', () => {
    let failboat;

    before(() => {
      failboat = hibp._axios.interceptors.request.use(() => {
        throw ERR;
      });
    });

    after(() => {
      hibp._axios.interceptors.request.eject(failboat);
    });

    it('should re-throw request setup errors', () => (
      hibp.dataClasses()
        .then(successHandler)
        .catch(errorHandler)
        .then(() => {
          expect(successHandler.called).to.be.false;
          expect(errorHandler.calledOnce).to.be.true;
          const err = errorHandler.getCall(0).args[0];
          expect(err).to.equal(ERR);
        })
    ));
  });

  describe('_fetchFromApi (invalid account format)', () => {
    it('should throw an Error with "Bad Request" status text', () => (
      hibp.breachedAccount(EMAIL_INVALID)
        .then(successHandler)
        .catch(errorHandler)
        .then(() => {
          expect(successHandler.called).to.be.false;
          expect(errorHandler.calledOnce).to.be.true;
          const err = errorHandler.getCall(0).args[0];
          expect(err.message).to.match(new RegExp(BAD_REQUEST.statusText));
        })
    ));
  });

  describe('_fetchFromApi (invalid request header)', () => {
    it('should throw an Error with "Forbidden" status text', () => (
      hibp.breachedAccount(INVALID_HEADER)
        .then(successHandler)
        .catch(errorHandler)
        .then(() => {
          expect(successHandler.called).to.be.false;
          expect(errorHandler.calledOnce).to.be.true;
          const err = errorHandler.getCall(0).args[0];
          expect(err.message).to.match(new RegExp(FORBIDDEN.statusText));
        })
    ));
  });

  describe('_fetchFromApi (rate limited)', () => {
    it('should throw an Error with "Too Many Requests" response data', () => (
      hibp.breachedAccount(RATE_LIMITED)
        .then(successHandler)
        .catch(errorHandler)
        .then(() => {
          expect(successHandler.called).to.be.false;
          expect(errorHandler.calledOnce).to.be.true;
          const err = errorHandler.getCall(0).args[0];
          expect(err.message).to.match(new RegExp(TOO_MANY_REQUESTS.response));
        })
    ));
  });

  describe('_fetchFromApi (unexpected HTTP error)', () => {
    it('should throw an Error with the response status text', () => (
      hibp.breachedAccount(UNEXPECTED)
        .then(successHandler)
        .catch(errorHandler)
        .then(() => {
          expect(successHandler.called).to.be.false;
          expect(errorHandler.calledOnce).to.be.true;
          const err = errorHandler.getCall(0).args[0];
          expect(err.message).to.match(new RegExp(UNKNOWN.statusText));
        })
    ));
  });

  describe('breachedAccount (breached account, no parameters)', () => {
    it('should resolve with an object', () => (
      hibp.breachedAccount(ACCOUNT_BREACHED)
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_OBJ);
        })
    ));
  });

  describe('breachedAccount (breached account, with truncateResults)', () => {
    it('should resolve with an object', () => (
      hibp.breachedAccount(ACCOUNT_BREACHED, OPTS_TRUNC)
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_OBJ);
        })
    ));
  });

  describe('breachedAccount (breached account, with domain)', () => {
    it('should resolve with an object', () => (
      hibp.breachedAccount(ACCOUNT_BREACHED, OPTS_DOM)
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_OBJ);
        })
    ));
  });

  describe('breachedAccount (breached account, with domain and ' +
    'truncateResults)', () => {
    it('should resolve with an object', () => (
      hibp.breachedAccount(ACCOUNT_BREACHED, OPTS_DOM_TRUNC)
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_OBJ);
        })
    ));
  });

  describe('breachedAccount (clean account, no parameters)', () => {
    it('should resolve with null', () => (
      hibp.breachedAccount(ACCOUNT_CLEAN)
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_CLEAN);
        })
    ));
  });

  describe('breachedAccount (clean account, with truncateResults)', () => {
    it('should resolve with null', () => (
      hibp.breachedAccount(ACCOUNT_CLEAN, OPTS_TRUNC)
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_CLEAN);
        })
    ));
  });

  describe('breachedAccount (clean account, with domain)', () => {
    it('should resolve with null', () => (
      hibp.breachedAccount(ACCOUNT_CLEAN, OPTS_DOM)
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_CLEAN);
        })
    ));
  });

  describe('breachedAccount (clean account, with domain and truncateResults)',
    () => {
      it('should resolve with null', () => (
        hibp.breachedAccount(ACCOUNT_CLEAN, OPTS_DOM_TRUNC)
          .then(successHandler)
          .then(() => {
            expect(successHandler.calledOnce).to.be.true;
            expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_CLEAN);
          })
      ));
    });

  describe('breaches (no parameters)', () => {
    it('should resolve with an array', () => (
      hibp.breaches()
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_ARY);
        })
    ));
  });

  describe('breaches (with domain)', () => {
    it('should resolve with an array', () => (
      hibp.breaches(OPTS_DOM)
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_ARY);
        })
    ));
  });

  describe('breach (found)', () => {
    it('should resolve with an object', () => (
      hibp.breach(BREACH_FOUND)
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_OBJ);
        })
    ));
  });

  describe('breach (not found)', () => {
    it('should resolve with null', () => (
      hibp.breach(BREACH_NOT_FOUND)
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_CLEAN);
        })
    ));
  });

  describe('dataClasses', () => {
    it('should resolve with an array', () => (
      hibp.dataClasses()
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_ARY);
        })
    ));
  });

  describe('pasteAccount (pasted email)', () => {
    it('should resolve with an array', () => (
      hibp.pasteAccount(EMAIL_PASTED)
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_ARY);
        })
    ));
  });

  describe('pasteAccount (clean email)', () => {
    it('should resolve with null', () => (
      hibp.pasteAccount(EMAIL_CLEAN)
        .then(successHandler)
        .then(() => {
          expect(successHandler.calledOnce).to.be.true;
          expect(successHandler.getCall(0).args[0]).to.equal(RESPONSE_CLEAN);
        })
    ));
  });
});
<|endoftext|>


<commit_before>/*
 *	Copyright 2016 Victorien Elvinger
 *
 *	This program is free software: you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation, either version 3 of the License, or
 * 	(at your option) any later version.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import test from "ava"
import Identifier from "../lib/identifier.js"
import IdFactory from "../lib/idfactory.js"

test("two-contiguous-bases", (t) => {
    const replicaNumber = 1
    const clock = 5
    const id1 = new Identifier([], 1)
    const id2 = new Identifier([], 4)
    const newBase = IdFactory.createBetweenPosition(id1, id2,
        replicaNumber, clock)
    const newId = new Identifier(newBase, 0)

    t.is(id1.compareTo(newId), -1, "id1 < newId")
    t.is(newId.compareTo(id2), -1, "newId < id2")
    t.is(newBase[0], 2)
})

test("prefix-preservation", (t) => {
    const replicaNumber = 1
    const clock = 5
    const prefix = [-42, 1, 8]
    const id1 = new Identifier(prefix, 1)
    const id2 = new Identifier(prefix, 4)
    const newBase = IdFactory.createBetweenPosition(id1, id2,
        replicaNumber, clock)

    t.true(prefix.length <= newBase.length)
    t.deepEqual(prefix, newBase.slice(0, prefix.length))
})

<commit_msg>test(idfactory): weaken more two-contiguous-bases test<commit_after>/*
 *	Copyright 2016 Victorien Elvinger
 *
 *	This program is free software: you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation, either version 3 of the License, or
 * 	(at your option) any later version.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import test from "ava"
import Identifier from "../lib/identifier.js"
import IdFactory from "../lib/idfactory.js"

test("two-contiguous-bases", (t) => {
    const replicaNumber = 1
    const clock = 5
    const id1 = new Identifier([], 1)
    const id2 = new Identifier([], 4)
    const newBase = IdFactory.createBetweenPosition(id1, id2,
        replicaNumber, clock)
    const newId = new Identifier(newBase, 0)

    t.is(id1.compareTo(newId), -1, "id1 < newId")
    t.is(newId.compareTo(id2), -1, "newId < id2")
})

test("prefix-preservation", (t) => {
    const replicaNumber = 1
    const clock = 5
    const prefix = [-42, 1, 8]
    const id1 = new Identifier(prefix, 1)
    const id2 = new Identifier(prefix, 4)
    const newBase = IdFactory.createBetweenPosition(id1, id2,
        replicaNumber, clock)

    t.true(prefix.length <= newBase.length)
    t.deepEqual(prefix, newBase.slice(0, prefix.length))
})

<|endoftext|>