<commit_before>'use strict';

var assert = require('assert');
var async = require('async');

var Analysis = require('../../lib/analysis');

var testConfig = require('../test-config');
var QueryRunner = require('../../lib/postgresql/query-runner');

describe('filters', function() {

    var queryRunner;

    before(function() {
        queryRunner = new QueryRunner(testConfig.db);
    });

    function getRows(query, callback) {
        queryRunner.run(query, function(err, result) {
            assert.ok(!err, err);
            assert.ok(result);
            var rows = result.rows;
            assert.ok(Array.isArray(rows));

            return callback(null, rows);
        });
    }

    var QUERY_ATM_MACHINES = 'select * from atm_machines';
    var BANKS_ALL = ['BBVA', 'Santander', 'Santander', 'Santander', 'BBVA', 'ING'];
    var BANKS_BBVA = BANKS_ALL.filter(function(bank) {return bank === 'BBVA'; });

    function filteredNodeDefinition(node, filters) {
        var clonedNode = JSON.parse(JSON.stringify(node));
        clonedNode.params.filters = filters;
        return clonedNode;
    }

    var sourceAnalysisDefinition = {
        type: 'source',
        params: {
            query: QUERY_ATM_MACHINES
        }
    };

    it('should return all banks', function(done) {
        Analysis.create(testConfig, sourceAnalysisDefinition, function(err, analysis) {
            assert.ok(!err, err);

            getRows(analysis.getQuery(), function(err, rows) {
                assert.ok(!err, err);

                var banks = rows.map(function(row) {
                    return row.bank;
                });

                assert.deepEqual(banks, BANKS_ALL);

                done();
            });

        });
    });

    it('should return just BBVA banks as they are filtered', function(done) {
        var filteredSource = filteredNodeDefinition(sourceAnalysisDefinition, {
            bank_category: {
                type: 'category',
                column: 'bank',
                params: {
                    accept: ['BBVA']
                }
            }
        });
        Analysis.create(testConfig, filteredSource, function(err, analysis) {
            assert.ok(!err, err);

            getRows(analysis.getQuery(), function(err, rows) {
                assert.ok(!err, err);

                var banks = rows.map(function(row) {
                    return row.bank;
                });

                assert.deepEqual(banks, BANKS_BBVA);

                done();
            });
        });
    });

    it('should return all banks as we are skipping the category filter', function(done) {
        var filteredSource = filteredNodeDefinition(sourceAnalysisDefinition, {
            bank_category: {
                type: 'category',
                column: 'bank',
                params: {
                    accept: ['BBVA']
                }
            }
        });
        Analysis.create(testConfig, filteredSource, function(err, analysis) {
            assert.ok(!err, err);

            getRows(analysis.getRoot().getQuery({bank_category: false}), function(err, rows) {
                assert.ok(!err, err);

                var banks = rows.map(function(row) {
                    return row.bank;
                });

                assert.deepEqual(banks, BANKS_ALL);

                done();
            });
        });
    });

    it('should filter dependant analyses based on filters', function(done) {
        var filteredSource = filteredNodeDefinition(sourceAnalysisDefinition, {
            bank_category: {
                type: 'category',
                column: 'bank',
                params: {
                    accept: ['BBVA']
                }
            }
        });

        var tradeAreaAnalysisDefinition = {
            type: 'buffer',
            params: {
                source: filteredSource,
                radio: 5000
            }
        };

        Analysis.create(testConfig, tradeAreaAnalysisDefinition, function(err, analysis) {
            assert.ok(!err, err);

            getRows(analysis.getRoot().getQuery(), function(err, rows) {
                assert.ok(!err, err);

                var banks = rows.map(function(row) {
                    return row.bank;
                });

                assert.deepEqual(banks, BANKS_BBVA);

                done();
            });
        });
    });

    describe('node-id', function() {
        function create(definition, callback) {
            Analysis.create(testConfig, definition, callback);
        }

        it('should have different id when filter is applied', function(done) {
            var filteredSource = filteredNodeDefinition(sourceAnalysisDefinition, {
                bank_category: {
                    type: 'category',
                    column: 'bank',
                    params: {
                        accept: ['BBVA']
                    }
                }
            });

            async.map([sourceAnalysisDefinition, filteredSource], create, function(err, results) {
                assert.ok(!err, err);

                assert.equal(results.length, 2);
                assert.notEqual(results[0].id(), results[1].id());
                assert.notEqual(results[0].getQuery(), results[1].getQuery());

                done();
            });
        });

    });

});
<commit_msg>Stub batch client<commit_after>'use strict';

var assert = require('assert');
var async = require('async');

var Analysis = require('../../lib/analysis');

var testConfig = require('../test-config');
var BatchClient = require('../../lib/postgresql/batch-client');
var QueryRunner = require('../../lib/postgresql/query-runner');

describe('filters', function() {

    var queryRunner;
    var enqueueFn;
    var enqueueCalled;

    before(function() {
        queryRunner = new QueryRunner(testConfig.db);
        enqueueFn = BatchClient.prototype.enqueue;
        enqueueCalled = 0;
        BatchClient.prototype.enqueue = function(query, callback) {
            enqueueCalled += 1;
            return callback(null, {status: 'ok'});
        };
    });
    after(function() {
        assert.ok(enqueueCalled > 0);
        BatchClient.prototype.enqueue = enqueueFn;
    });

    function getRows(query, callback) {
        queryRunner.run(query, function(err, result) {
            assert.ok(!err, err);
            assert.ok(result);
            var rows = result.rows;
            assert.ok(Array.isArray(rows));

            return callback(null, rows);
        });
    }

    var QUERY_ATM_MACHINES = 'select * from atm_machines';
    var BANKS_ALL = ['BBVA', 'Santander', 'Santander', 'Santander', 'BBVA', 'ING'];
    var BANKS_BBVA = BANKS_ALL.filter(function(bank) {return bank === 'BBVA'; });

    function filteredNodeDefinition(node, filters) {
        var clonedNode = JSON.parse(JSON.stringify(node));
        clonedNode.params.filters = filters;
        return clonedNode;
    }

    var sourceAnalysisDefinition = {
        type: 'source',
        params: {
            query: QUERY_ATM_MACHINES
        }
    };

    it('should return all banks', function(done) {
        Analysis.create(testConfig, sourceAnalysisDefinition, function(err, analysis) {
            assert.ok(!err, err);

            getRows(analysis.getQuery(), function(err, rows) {
                assert.ok(!err, err);

                var banks = rows.map(function(row) {
                    return row.bank;
                });

                assert.deepEqual(banks, BANKS_ALL);

                done();
            });

        });
    });

    it('should return just BBVA banks as they are filtered', function(done) {
        var filteredSource = filteredNodeDefinition(sourceAnalysisDefinition, {
            bank_category: {
                type: 'category',
                column: 'bank',
                params: {
                    accept: ['BBVA']
                }
            }
        });
        Analysis.create(testConfig, filteredSource, function(err, analysis) {
            assert.ok(!err, err);

            getRows(analysis.getQuery(), function(err, rows) {
                assert.ok(!err, err);

                var banks = rows.map(function(row) {
                    return row.bank;
                });

                assert.deepEqual(banks, BANKS_BBVA);

                done();
            });
        });
    });

    it('should return all banks as we are skipping the category filter', function(done) {
        var filteredSource = filteredNodeDefinition(sourceAnalysisDefinition, {
            bank_category: {
                type: 'category',
                column: 'bank',
                params: {
                    accept: ['BBVA']
                }
            }
        });
        Analysis.create(testConfig, filteredSource, function(err, analysis) {
            assert.ok(!err, err);

            getRows(analysis.getRoot().getQuery({bank_category: false}), function(err, rows) {
                assert.ok(!err, err);

                var banks = rows.map(function(row) {
                    return row.bank;
                });

                assert.deepEqual(banks, BANKS_ALL);

                done();
            });
        });
    });

    it('should filter dependant analyses based on filters', function(done) {
        var filteredSource = filteredNodeDefinition(sourceAnalysisDefinition, {
            bank_category: {
                type: 'category',
                column: 'bank',
                params: {
                    accept: ['BBVA']
                }
            }
        });

        var tradeAreaAnalysisDefinition = {
            type: 'buffer',
            params: {
                source: filteredSource,
                radio: 5000
            }
        };

        Analysis.create(testConfig, tradeAreaAnalysisDefinition, function(err, analysis) {
            assert.ok(!err, err);

            getRows(analysis.getRoot().getQuery(), function(err, rows) {
                assert.ok(!err, err);

                var banks = rows.map(function(row) {
                    return row.bank;
                });

                assert.deepEqual(banks, BANKS_BBVA);

                done();
            });
        });
    });

    describe('node-id', function() {
        function create(definition, callback) {
            Analysis.create(testConfig, definition, callback);
        }

        it('should have different id when filter is applied', function(done) {
            var filteredSource = filteredNodeDefinition(sourceAnalysisDefinition, {
                bank_category: {
                    type: 'category',
                    column: 'bank',
                    params: {
                        accept: ['BBVA']
                    }
                }
            });

            async.map([sourceAnalysisDefinition, filteredSource], create, function(err, results) {
                assert.ok(!err, err);

                assert.equal(results.length, 2);
                assert.notEqual(results[0].id(), results[1].id());
                assert.notEqual(results[0].getQuery(), results[1].getQuery());

                done();
            });
        });

    });

});
<|endoftext|>


<commit_before>const fs = require('fs');
const path = require('path');
const nock = require('nock');
const axios = require('axios');
// Requiring our app implementation
const Approvals = require('../../approvals/app');
const { Probot, ProbotOctokit } = require('probot');
// Requiring our fixtures
const payload = require('./fixtures/pull_request.edited');
const checkRunSuccess = require('./fixtures/check_run.success');
const checkRunNoApprovals = require('./fixtures/check_run.no_approvals');
const checkRunApprovalMissing = require('./fixtures/check_run.approval_missing');

// Configure Axios to use Node adapter (@see https://github.com/nock/nock#axios)
axios.defaults.adapter = require('axios/lib/adapters/http');

const privateKey = fs.readFileSync(
  path.join(__dirname, 'fixtures/mock-cert.pem'),
  'utf-8'
);

describe('Approvals', () => {
  let probot;
  let mock;

  const opts = {
    'Content-Type': 'application/json',
  };

  beforeEach(() => {
    nock.disableNetConnect();

    // Mock Github requests
    nock('https://raw.githubusercontent.com')
      .get('/devnook/developer.chrome.com/main/.github/chrome-devrel-bot.json')
      .replyWithFile(200, __dirname + '/fixtures/config.json')

    mock = nock('https://api.github.com')
      .post('/app/installations/24733797/access_tokens')
      .reply(200, {
        token: 'test',
        permissions: {
          checks: 'write',
        },
      })
      // Mock files request
      .get('/repos/devnook/developer.chrome.com/pulls/6/files', )
      .replyWithFile(200, __dirname + '/fixtures/files.json', {
        'Content-Type': 'application/json',
      });

    probot = new Probot({
      appId: 123,
      privateKey,
      // disable request throttling and retries for testing
      Octokit: ProbotOctokit.defaults({
        retry: { enabled: false },
        throttle: { enabled: false },
      }),
    });
    // Load our app into probot
    probot.load(Approvals);
  });

  test('Creates a SUCCESS check for approved PR', async () => {
    mock
      // Mock reviews request
      .get('/repos/devnook/developer.chrome.com/pulls/6/reviews', )
      .replyWithFile(200, __dirname + '/fixtures/reviews_approved.json', opts)
      // Expected request
      .post('/repos/devnook/developer.chrome.com/check-runs', (body) => {
        body.started_at = '2018-10-05T17:35:21.594Z';
        expect(body).toMatchObject(checkRunSuccess);
        return true;
      })
      .reply(200);

    // Receive a webhook event
    await probot.receive({ name: 'pull_request', payload });
    expect(mock.pendingMocks()).toStrictEqual([]);
  });

  test('Creates a FAILURE check for a rejected PR', async () => {
    mock
      // Mock reviews request
      .get('/repos/devnook/developer.chrome.com/pulls/6/reviews', )
      .replyWithFile(200, __dirname + '/fixtures/reviews_rejected.json', opts)
      // Expected request
      .post('/repos/devnook/developer.chrome.com/check-runs', (body) => {
        body.started_at = '2018-10-05T17:35:21.594Z';
        expect(body).toMatchObject(checkRunNoApprovals);
        return true;
      })
      .reply(200);

    // Receive a webhook event
    await probot.receive({ name: 'pull_request', payload });
    expect(mock.pendingMocks()).toStrictEqual([]);
  });

  test('Creates a FAILURE check for a missing content approval', async () => {
    mock
      // Mock reviews request
      .get('/repos/devnook/developer.chrome.com/pulls/6/reviews', )
      .replyWithFile(200, __dirname + '/fixtures/reviews_approved_rejected.json', opts)
      // Expected request
      .post('/repos/devnook/developer.chrome.com/check-runs', (body) => {
        body.started_at = '2018-10-05T17:35:21.594Z';
        expect(body).toMatchObject(checkRunApprovalMissing);
        return true;
      })
      .reply(200);

    // Receive a webhook event
    await probot.receive({ name: 'pull_request', payload });
    expect(mock.pendingMocks()).toStrictEqual([]);
  });

  test('Creates a FAILURE check for a an unreviewed PR', async () => {
    mock
      // Mock reviews request
      .get('/repos/devnook/developer.chrome.com/pulls/6/reviews', )
      .replyWithFile(200, __dirname + '/fixtures/reviews_empty.json', opts)
      // Expected request
      .post('/repos/devnook/developer.chrome.com/check-runs', (body) => {
        body.started_at = '2018-10-05T17:35:21.594Z';
        expect(body).toMatchObject(checkRunNoApprovals);
        return true;
      })
      .reply(200);

    // Receive a webhook event
    await probot.receive({ name: 'pull_request', payload });
    expect(mock.pendingMocks()).toStrictEqual([]);
  });

  afterEach(() => {
    nock.cleanAll();
    nock.enableNetConnect();
  });
});
<commit_msg>Add licence<commit_after>/*
 * Copyright 2022 Google LLC
 *
 * 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
 *
 *     https://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.
 */
const fs = require('fs');
const path = require('path');
const nock = require('nock');
const axios = require('axios');
// Requiring our app implementation
const Approvals = require('../../approvals/app');
const { Probot, ProbotOctokit } = require('probot');
// Requiring our fixtures
const payload = require('./fixtures/pull_request.edited');
const checkRunSuccess = require('./fixtures/check_run.success');
const checkRunNoApprovals = require('./fixtures/check_run.no_approvals');
const checkRunApprovalMissing = require('./fixtures/check_run.approval_missing');

// Configure Axios to use Node adapter (@see https://github.com/nock/nock#axios)
axios.defaults.adapter = require('axios/lib/adapters/http');

const privateKey = fs.readFileSync(
  path.join(__dirname, 'fixtures/mock-cert.pem'),
  'utf-8'
);

describe('Approvals', () => {
  let probot;
  let mock;

  const opts = {
    'Content-Type': 'application/json',
  };

  beforeEach(() => {
    nock.disableNetConnect();

    // Mock Github requests
    nock('https://raw.githubusercontent.com')
      .get('/devnook/developer.chrome.com/main/.github/chrome-devrel-bot.json')
      .replyWithFile(200, __dirname + '/fixtures/config.json')

    mock = nock('https://api.github.com')
      .post('/app/installations/24733797/access_tokens')
      .reply(200, {
        token: 'test',
        permissions: {
          checks: 'write',
        },
      })
      // Mock files request
      .get('/repos/devnook/developer.chrome.com/pulls/6/files', )
      .replyWithFile(200, __dirname + '/fixtures/files.json', {
        'Content-Type': 'application/json',
      });

    probot = new Probot({
      appId: 123,
      privateKey,
      // disable request throttling and retries for testing
      Octokit: ProbotOctokit.defaults({
        retry: { enabled: false },
        throttle: { enabled: false },
      }),
    });
    // Load our app into probot
    probot.load(Approvals);
  });

  test('Creates a SUCCESS check for approved PR', async () => {
    mock
      // Mock reviews request
      .get('/repos/devnook/developer.chrome.com/pulls/6/reviews', )
      .replyWithFile(200, __dirname + '/fixtures/reviews_approved.json', opts)
      // Expected request
      .post('/repos/devnook/developer.chrome.com/check-runs', (body) => {
        body.started_at = '2018-10-05T17:35:21.594Z';
        expect(body).toMatchObject(checkRunSuccess);
        return true;
      })
      .reply(200);

    // Receive a webhook event
    await probot.receive({ name: 'pull_request', payload });
    expect(mock.pendingMocks()).toStrictEqual([]);
  });

  test('Creates a FAILURE check for a rejected PR', async () => {
    mock
      // Mock reviews request
      .get('/repos/devnook/developer.chrome.com/pulls/6/reviews', )
      .replyWithFile(200, __dirname + '/fixtures/reviews_rejected.json', opts)
      // Expected request
      .post('/repos/devnook/developer.chrome.com/check-runs', (body) => {
        body.started_at = '2018-10-05T17:35:21.594Z';
        expect(body).toMatchObject(checkRunNoApprovals);
        return true;
      })
      .reply(200);

    // Receive a webhook event
    await probot.receive({ name: 'pull_request', payload });
    expect(mock.pendingMocks()).toStrictEqual([]);
  });

  test('Creates a FAILURE check for a missing content approval', async () => {
    mock
      // Mock reviews request
      .get('/repos/devnook/developer.chrome.com/pulls/6/reviews', )
      .replyWithFile(200, __dirname + '/fixtures/reviews_approved_rejected.json', opts)
      // Expected request
      .post('/repos/devnook/developer.chrome.com/check-runs', (body) => {
        body.started_at = '2018-10-05T17:35:21.594Z';
        expect(body).toMatchObject(checkRunApprovalMissing);
        return true;
      })
      .reply(200);

    // Receive a webhook event
    await probot.receive({ name: 'pull_request', payload });
    expect(mock.pendingMocks()).toStrictEqual([]);
  });

  test('Creates a FAILURE check for a an unreviewed PR', async () => {
    mock
      // Mock reviews request
      .get('/repos/devnook/developer.chrome.com/pulls/6/reviews', )
      .replyWithFile(200, __dirname + '/fixtures/reviews_empty.json', opts)
      // Expected request
      .post('/repos/devnook/developer.chrome.com/check-runs', (body) => {
        body.started_at = '2018-10-05T17:35:21.594Z';
        expect(body).toMatchObject(checkRunNoApprovals);
        return true;
      })
      .reply(200);

    // Receive a webhook event
    await probot.receive({ name: 'pull_request', payload });
    expect(mock.pendingMocks()).toStrictEqual([]);
  });

  afterEach(() => {
    nock.cleanAll();
    nock.enableNetConnect();
  });
});
<|endoftext|>


<commit_before>import { setupRerender } from 'preact/test-utils';
import { createElement as h, render, Component, Fragment, hydrate } from '../../src/index';
import { setupScratch, teardown } from '../_util/helpers';
import { div, span, input as inputStr } from '../_util/dom';
/* eslint-disable react/jsx-boolean-value */

/** @jsx h */
describe('focus', () => {

	/** @type {HTMLDivElement} */
	let scratch;

	/** @type {() => void} */
	let rerender;

	const List = ({ children }) =>
{children}
;
	const ListItem = ({ children }) => {children};
	const Input = () => <input type="text" />;

	function focusInput() {
		if (!scratch) return;

		const input = scratch.querySelector('input');
		input.value = 'a word';
		input.focus();
		input.setSelectionRange(2, 5);

		expect(document.activeElement).to.equal(input);

		return input;
	}

	/**
	 * Validate an input tag has maintained focus
	 * @param {HTMLInputElement} input The input to validate
	 * @param {string} [message] Message to show if the activeElement is not
	 * eqaul to the `input` parameter
	 */
	function validateFocus(input, message) {
		// Check `nodeName` first to make cli output less spammy
		expect(document.activeElement.nodeName).to.equal(input.nodeName, message);
		expect(document.activeElement).to.equal(input, message);
		expect(input.selectionStart).to.equal(2);
		expect(input.selectionEnd).to.equal(5);

	}

	beforeEach(() => {
		scratch = setupScratch();
		rerender = setupRerender();
	});

	afterEach(() => {
		teardown(scratch);
	});

	it.skip('should maintain focus when swapping elements', () => {
		render((
			<List>
				<Input />
				<ListItem>fooo</ListItem>
			</List>
		), scratch);

		const input = focusInput();

		render((
			<List>
				<ListItem>fooo</ListItem>
				<Input />
			</List>
		), scratch);
		validateFocus(input);
	});

	it('should maintain focus when moving the input around', () => {
		function App({ showFirst, showLast }) {
			return (
				<List>
					{ showFirst ? <ListItem>1</ListItem> : null }
					<Input />
					{ showLast ? <ListItem>2</ListItem> : null }
				</List>
			);
		}

		render(<App showFirst={true} showLast={true} />, scratch);

		let input = focusInput();
		render(<App showFirst={false} showLast={true} />, scratch);
		validateFocus(input, 'move from middle to beginning');

		input = focusInput();
		render(<App showFirst={true} showLast={true} />, scratch);
		validateFocus(input, 'move from beginning to middle');

		input = focusInput();
		render(<App showFirst={true} showLast={false} />, scratch);
		validateFocus(input, 'move from middle to end');

		input = focusInput();
		render(<App showFirst={true} showLast={true} />, scratch);
		validateFocus(input, 'move from end to middle');
	});

	it('should maintain focus when adding children around input', () => {
		render((
			<List>
				<Input />
			</List>
		), scratch);

		let input = focusInput();

		render((
			<List>
				<ListItem>1</ListItem>
				<Input />
			</List>
		), scratch);
		validateFocus(input, 'insert sibling before');

		input = focusInput();

		render((
			<List>
				<ListItem>1</ListItem>
				<Input />
				<ListItem>2</ListItem>
			</List>
		), scratch);
		validateFocus(input, 'insert sibling after');

		input = focusInput();

		render((
			<List>
				<ListItem>1</ListItem>
				<Input />
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
			</List>
		), scratch);
		validateFocus(input, 'insert sibling after again');

		input = focusInput();

		render((
			<List>
				<ListItem>0</ListItem>
				<ListItem>1</ListItem>
				<Input />
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
			</List>
		), scratch);
		validateFocus(input, 'insert sibling before again');
	});

	it('should maintain focus when removing elements around input', () => {
		render((
			<List>
				<ListItem>0</ListItem>
				<ListItem>1</ListItem>
				<Input />
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
			</List>
		), scratch);

		let input = focusInput();

		render((
			<List>
				<ListItem>1</ListItem>
				<Input />
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
			</List>
		), scratch);
		validateFocus(input, 'remove sibling before');

		input = focusInput();

		render((
			<List>
				<ListItem>1</ListItem>
				<Input />
				<ListItem>2</ListItem>
			</List>
		), scratch);
		validateFocus(input, 'remove sibling after');

		input = focusInput();

		render((
			<List>
				<ListItem>1</ListItem>
				<Input />
			</List>
		), scratch);
		validateFocus(input, 'remove sibling after 2');

		input = focusInput();

		render((
			<List>
				<Input />
			</List>
		), scratch);
		validateFocus(input, 'remove sibling before 2');
	});

	it('should maintain focus when hydrating', () => {
		const html = div([
			span('1'),
			span('2'),
			span('3'),
			inputStr()
		].join(''));

		scratch.innerHTML = html;
		const input = focusInput();

		hydrate((
			<List>
				<ListItem>1</ListItem>
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
				<Input />
			</List>
		), scratch);

		expect(scratch.innerHTML).to.equal(html);
		validateFocus(input);
	});

	it('should keep focus in Fragments', () => {

		/** @type {HTMLInputElement} */
		let input;

		/** @type {() => void} */
		let updateState;

		class App extends Component {
			constructor() {
				super();
				this.state = { active: false };
				updateState = () => this.setState(prev => ({ active: !prev.active }));
			}

			render() {
				return (

Heading

						{!this.state.active ? (
							<Fragment>
								foobar
								<Fragment>
									Hello World

yo

								</Fragment>
								<input type="text" ref={i => input = i} />
							</Fragment>
						) : (
							<Fragment>
								<Fragment>
									Hello World

yo

								</Fragment>
								foobar
								<input type="text" ref={i => input = i} />
							</Fragment>
						)}

				);
			}
		}

		render(<App />, scratch);

		input.focus();
		updateState();

		expect(document.activeElement).to.equal(input, 'Before rerender');
		rerender();

		expect(document.activeElement).to.equal(input, 'After rerender');
	});

	it('should keep text selection', () => {

		/** @type {HTMLInputElement} */
		let input;

		/** @type {() => void} */
		let updateState;

		class App extends Component {
			constructor() {
				super();
				this.state = { active: false };
				updateState = () => this.setState(prev => ({ active: !prev.active }));
			}

			render() {
				return (

Heading

						{!this.state.active ? (
							<Fragment>
								foobar
								<Fragment>
									Hello World

yo

								</Fragment>
								<input type="text" ref={i => input = i} value="foobar" />
							</Fragment>
						) : (
							<Fragment>
								<Fragment>
									Hello World

yo

								</Fragment>
								foobar
								<input type="text" ref={i => input = i} value="foobar" />
							</Fragment>
						)}

				);
			}
		}

		render(<App />, scratch);

		input.focus();
		input.setSelectionRange(2, 5);
		updateState();

		expect(document.activeElement).to.equal(input, 'Before rerender');
		rerender();

		expect(input.selectionStart).to.equal(2);
		expect(input.selectionEnd).to.equal(5);
		expect(document.activeElement).to.equal(input, 'After rerender');
	});
});
<commit_msg>tests: bigger focus test<commit_after>import { setupRerender } from 'preact/test-utils';
import { createElement as h, render, Component, Fragment, hydrate } from '../../src/index';
import { setupScratch, teardown } from '../_util/helpers';
import { div, span, input as inputStr } from '../_util/dom';
/* eslint-disable react/jsx-boolean-value */

/** @jsx h */
describe('focus', () => {

	/** @type {HTMLDivElement} */
	let scratch;

	/** @type {() => void} */
	let rerender;

	const List = ({ children }) =>
{children}
;
	const ListItem = ({ children }) => {children};
	const Input = ({ i }) => <input id={`input-${i}`} type="text" />;

	function focusInput() {
		if (!scratch) return;

		const input = scratch.querySelector('input');
		input.value = 'a word';
		input.focus();
		input.setSelectionRange(2, 5);

		expect(document.activeElement).to.equal(input);

		return input;
	}

	function focusInputById() {
		if (!scratch) return;

		const input = scratch.querySelector('#input-0');
		input.value = 'a word';
		input.focus();
		input.setSelectionRange(2, 5);

		expect(document.activeElement).to.equal(input);

		return input;
	}

	/**
	 * Validate an input tag has maintained focus
	 * @param {HTMLInputElement} input The input to validate
	 * @param {string} [message] Message to show if the activeElement is not
	 * eqaul to the `input` parameter
	 */
	function validateFocus(input, message) {
		// Check `nodeName` first to make cli output less spammy
		expect(document.activeElement.nodeName).to.equal(input.nodeName, message);
		expect(document.activeElement).to.equal(input, message);
		expect(input.selectionStart).to.equal(2);
		expect(input.selectionEnd).to.equal(5);

	}

	beforeEach(() => {
		scratch = setupScratch();
		rerender = setupRerender();
	});

	afterEach(() => {
		teardown(scratch);
	});

	it.skip('should maintain focus when swapping elements', () => {
		render((
			<List>
				<Input />
				<ListItem>fooo</ListItem>
			</List>
		), scratch);

		const input = focusInput();

		render((
			<List>
				<ListItem>fooo</ListItem>
				<Input />
			</List>
		), scratch);
		validateFocus(input);
	});

	it('should maintain focus when moving the input around', () => {
		function App({ showFirst, showLast }) {
			return (
				<List>
					{ showFirst ? <ListItem>1</ListItem> : null }
					<Input />
					{ showLast ? <ListItem>2</ListItem> : null }
				</List>
			);
		}

		render(<App showFirst={true} showLast={true} />, scratch);

		let input = focusInput();
		render(<App showFirst={false} showLast={true} />, scratch);
		validateFocus(input, 'move from middle to beginning');

		input = focusInput();
		render(<App showFirst={true} showLast={true} />, scratch);
		validateFocus(input, 'move from beginning to middle');

		input = focusInput();
		render(<App showFirst={true} showLast={false} />, scratch);
		validateFocus(input, 'move from middle to end');

		input = focusInput();
		render(<App showFirst={true} showLast={true} />, scratch);
		validateFocus(input, 'move from end to middle');
	});

	it('should maintain focus when adding children around input', () => {
		render((
			<List>
				<Input />
			</List>
		), scratch);

		let input = focusInput();

		render((
			<List>
				<ListItem>1</ListItem>
				<Input />
			</List>
		), scratch);
		validateFocus(input, 'insert sibling before');

		input = focusInput();

		render((
			<List>
				<ListItem>1</ListItem>
				<Input />
				<ListItem>2</ListItem>
			</List>
		), scratch);
		validateFocus(input, 'insert sibling after');

		input = focusInput();

		render((
			<List>
				<ListItem>1</ListItem>
				<Input />
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
			</List>
		), scratch);
		validateFocus(input, 'insert sibling after again');

		input = focusInput();

		render((
			<List>
				<ListItem>0</ListItem>
				<ListItem>1</ListItem>
				<Input />
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
			</List>
		), scratch);
		validateFocus(input, 'insert sibling before again');
	});

	it('should maintain focus when removing elements around input', () => {
		render((
			<List>
				<ListItem>0</ListItem>
				<ListItem>1</ListItem>
				<Input />
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
			</List>
		), scratch);

		let input = focusInput();

		render((
			<List>
				<ListItem>1</ListItem>
				<Input />
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
			</List>
		), scratch);
		validateFocus(input, 'remove sibling before');

		input = focusInput();

		render((
			<List>
				<ListItem>1</ListItem>
				<Input />
				<ListItem>2</ListItem>
			</List>
		), scratch);
		validateFocus(input, 'remove sibling after');

		input = focusInput();

		render((
			<List>
				<ListItem>1</ListItem>
				<Input />
			</List>
		), scratch);
		validateFocus(input, 'remove sibling after 2');

		input = focusInput();

		render((
			<List>
				<Input />
			</List>
		), scratch);
		validateFocus(input, 'remove sibling before 2');
	});

	it.only('should maintain focus when adding input next to the current input', () => {
		render((
			<List>
				<Input i={0} />
			</List>
		), scratch);

		let input = focusInputById();

		render((
			<List>
				<Input i={1} />
				<Input i={0} />
			</List>
		), scratch);
		validateFocus(input, 'add input before');

		input = focusInputById();

		render((
			<List>
				<Input i={1} />
				<Input i={0} />
				<Input i={2} />
			</List>
		), scratch);
		validateFocus(input, 'add input after');

		input = focusInputById();

		render((
			<List>
				<Input i={3} />
				<Input i={1} />
				<Input i={0} />
				<Input i={2} />
			</List>
		), scratch);
		validateFocus(input, 'add input first place');

		input = focusInputById();

		render((
			<List>
				<Input i={3} />
				<Input i={1} />
				<Input i={4} />
				<Input i={0} />
				<Input i={2} />
			</List>
		), scratch);
		validateFocus(input, 'add input before');
	});

	it('should maintain focus when hydrating', () => {
		const html = div([
			span('1'),
			span('2'),
			span('3'),
			inputStr()
		].join(''));

		scratch.innerHTML = html;
		const input = focusInput();

		hydrate((
			<List>
				<ListItem>1</ListItem>
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
				<Input />
			</List>
		), scratch);

		expect(scratch.innerHTML).to.equal(html);
		validateFocus(input);
	});

	it('should keep focus in Fragments', () => {

		/** @type {HTMLInputElement} */
		let input;

		/** @type {() => void} */
		let updateState;

		class App extends Component {
			constructor() {
				super();
				this.state = { active: false };
				updateState = () => this.setState(prev => ({ active: !prev.active }));
			}

			render() {
				return (

Heading

						{!this.state.active ? (
							<Fragment>
								foobar
								<Fragment>
									Hello World

yo

								</Fragment>
								<input type="text" ref={i => input = i} />
							</Fragment>
						) : (
							<Fragment>
								<Fragment>
									Hello World

yo

								</Fragment>
								foobar
								<input type="text" ref={i => input = i} />
							</Fragment>
						)}

				);
			}
		}

		render(<App />, scratch);

		input.focus();
		updateState();

		expect(document.activeElement).to.equal(input, 'Before rerender');
		rerender();

		expect(document.activeElement).to.equal(input, 'After rerender');
	});

	it('should keep text selection', () => {

		/** @type {HTMLInputElement} */
		let input;

		/** @type {() => void} */
		let updateState;

		class App extends Component {
			constructor() {
				super();
				this.state = { active: false };
				updateState = () => this.setState(prev => ({ active: !prev.active }));
			}

			render() {
				return (

Heading

						{!this.state.active ? (
							<Fragment>
								foobar
								<Fragment>
									Hello World

yo

								</Fragment>
								<input type="text" ref={i => input = i} value="foobar" />
							</Fragment>
						) : (
							<Fragment>
								<Fragment>
									Hello World

yo

								</Fragment>
								foobar
								<input type="text" ref={i => input = i} value="foobar" />
							</Fragment>
						)}

				);
			}
		}

		render(<App />, scratch);

		input.focus();
		input.setSelectionRange(2, 5);
		updateState();

		expect(document.activeElement).to.equal(input, 'Before rerender');
		rerender();

		expect(input.selectionStart).to.equal(2);
		expect(input.selectionEnd).to.equal(5);
		expect(document.activeElement).to.equal(input, 'After rerender');
	});
});
<|endoftext|>


<commit_before>import {createSpecBuilderClass, createConnectionBuilderClass, createUnionBuilderClass} from './base';
import {nextID} from '../id-sequence';

import {RepositoryBuilder} from './repository';
import {UserBuilder} from './user';
import {ReactionGroupBuilder} from './reaction-group';
import {
  CommitBuilder,
  CommitCommentThreadBuilder,
  CrossReferencedEventBuilder,
  HeadRefForcePushedEventBuilder,
  IssueCommentBuilder,
  MergedEventBuilder,
} from './timeline';

const PullRequestTimelineItemBuilder = createUnionBuilderClass('PullRequestTimelineItem', {
  beCommit: CommitBuilder,
  beCommitCommentThread: CommitCommentThreadBuilder,
  beCrossReferencedEvent: CrossReferencedEventBuilder,
  beHeadRefForcePushedEvent: HeadRefForcePushedEventBuilder,
  beIssueComment: IssueCommentBuilder,
  beMergedEvent: MergedEventBuilder,
  default: 'beIssueComment',
});

export const CommentBuilder = createSpecBuilderClass('PullRequestReviewComment', {
  __typename: {default: 'PullRequestReviewComment'},
  id: {default: nextID},
  path: {default: 'first.txt'},
  position: {default: 0, nullable: true},
  diffHunk: {default: '@ -1,4 +1,5 @@'},
  author: {linked: UserBuilder},
  reactionGroups: {linked: ReactionGroupBuilder, plural: true, singularName: 'reactionGroup'},
  url: {default: 'https://github.com/atom/github/pull/1829/files#r242224689'},
  createdAt: {default: '2018-12-27T17:51:17Z'},
  bodyHTML: {default: 'Lorem ipsum dolor sit amet, te urbanitas appellantur est.'},
  replyTo: {default: null, nullable: true},
  isMinimized: {default: false},
  minimizedReason: {default: null, nullable: true},
  state: {default: 'SUBMITTED'},
  viewerCanReact: {default: true},
  viewerCanMinimize: {default: true},
}, 'Node & Comment & Deletable & Updatable & UpdatableComment & Reactable & RepositoryNode');

export const CommentConnectionBuilder = createConnectionBuilderClass('PullRequestReviewComment', CommentBuilder);

export const ReviewThreadBuilder = createSpecBuilderClass('PullRequestReviewThread', {
  __typename: {default: 'PullRequestReviewThread'},
  id: {default: nextID},
  isResolved: {default: false},
  viewerCanResolve: {default: f => !f.isResolved},
  viewerCanUnresolve: {default: f => !!f.isResolved},
  resolvedBy: {linked: UserBuilder},
  comments: {linked: CommentConnectionBuilder},
}, 'Node');

export const ReviewBuilder = createSpecBuilderClass('PullRequestReview', {
  __typename: {default: 'PullRequestReview'},
  id: {default: nextID},
  submittedAt: {default: '2018-12-28T20:40:55Z'},
  bodyHTML: {default: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit'},
  state: {default: 'COMMENTED'},
  author: {linked: UserBuilder},
  comments: {linked: CommentConnectionBuilder},
  reactionGroups: {linked: ReactionGroupBuilder, plural: true, singularName: 'reactionGroup'},
}, 'Node & Comment & Deletable & Updatable & UpdatableComment & Reactable & RepositoryNode');

export const CommitConnectionBuilder = createConnectionBuilderClass('PullRequestCommit', CommentBuilder);

export const PullRequestCommitBuilder = createSpecBuilderClass('PullRequestCommit', {
  id: {default: nextID},
  commit: {linked: CommitBuilder},
}, 'Node & UniformResourceLocatable');

export const PullRequestBuilder = createSpecBuilderClass('PullRequest', {
  id: {default: nextID},
  __typename: {default: 'PullRequest'},
  number: {default: 123},
  title: {default: 'the title'},
  baseRefName: {default: 'base-ref'},
  headRefName: {default: 'head-ref'},
  isCrossRepository: {default: false},
  changedFiles: {default: 5},
  state: {default: 'OPEN'},
  bodyHTML: {default: '', nullable: true},
  createdAt: {default: '2019-01-01T10:00:00Z'},
  countedCommits: {linked: CommitConnectionBuilder},
  url: {default: f => {
    const ownerLogin = (f.repository && f.repository.owner && f.repository.owner.login) || 'aaa';
    const repoName = (f.repository && f.repository.name) || 'bbb';
    const number = f.number || 1;
    return `https://github.com/${ownerLogin}/${repoName}/pull/${number}`;
  }},
  author: {linked: UserBuilder},
  repository: {linked: RepositoryBuilder},
  headRepository: {linked: RepositoryBuilder, nullable: true},
  headRepositoryOwner: {linked: UserBuilder},
  commits: {linked: createConnectionBuilderClass('PullRequestCommit', PullRequestCommitBuilder)},
  recentCommits: {linked: createConnectionBuilderClass('PullRequestCommit', PullRequestCommitBuilder)},
  reviews: {linked: createConnectionBuilderClass('ReviewConnection', ReviewBuilder)},
  reviewThreads: {linked: createConnectionBuilderClass('ReviewThreadConnection', ReviewThreadBuilder)},
  timeline: {linked: createConnectionBuilderClass('PullRequestTimeline', PullRequestTimelineItemBuilder)},
  reactionGroups: {linked: ReactionGroupBuilder, plural: true, singularName: 'reactionGroup'},
  viewerCanReact: {default: true},
},
'Node & Assignable & Closable & Comment & Updatable & UpdatableComment & Labelable & Lockable & Reactable & ' +
'RepositoryNode & Subscribable & UniformResourceLocatable',
);

export function reviewThreadBuilder(...nodes) {
  return ReviewThreadBuilder.onFragmentQuery(nodes);
}

export function pullRequestBuilder(...nodes) {
  return PullRequestBuilder.onFragmentQuery(nodes);
}
<commit_msg>Add builder fields for ReviewsController tests<commit_after>import {createSpecBuilderClass, createConnectionBuilderClass, createUnionBuilderClass} from './base';
import {nextID} from '../id-sequence';

import {RepositoryBuilder} from './repository';
import {UserBuilder} from './user';
import {ReactionGroupBuilder} from './reaction-group';
import {
  CommitBuilder,
  CommitCommentThreadBuilder,
  CrossReferencedEventBuilder,
  HeadRefForcePushedEventBuilder,
  IssueCommentBuilder,
  MergedEventBuilder,
} from './timeline';

const PullRequestTimelineItemBuilder = createUnionBuilderClass('PullRequestTimelineItem', {
  beCommit: CommitBuilder,
  beCommitCommentThread: CommitCommentThreadBuilder,
  beCrossReferencedEvent: CrossReferencedEventBuilder,
  beHeadRefForcePushedEvent: HeadRefForcePushedEventBuilder,
  beIssueComment: IssueCommentBuilder,
  beMergedEvent: MergedEventBuilder,
  default: 'beIssueComment',
});

export const CommentBuilder = createSpecBuilderClass('PullRequestReviewComment', {
  __typename: {default: 'PullRequestReviewComment'},
  id: {default: nextID},
  path: {default: 'first.txt'},
  position: {default: 0, nullable: true},
  diffHunk: {default: '@ -1,4 +1,5 @@'},
  author: {linked: UserBuilder},
  reactionGroups: {linked: ReactionGroupBuilder, plural: true, singularName: 'reactionGroup'},
  url: {default: 'https://github.com/atom/github/pull/1829/files#r242224689'},
  createdAt: {default: '2018-12-27T17:51:17Z'},
  bodyHTML: {default: 'Lorem ipsum dolor sit amet, te urbanitas appellantur est.'},
  replyTo: {default: null, nullable: true},
  isMinimized: {default: false},
  minimizedReason: {default: null, nullable: true},
  state: {default: 'SUBMITTED'},
  viewerCanReact: {default: true},
  viewerCanMinimize: {default: true},
}, 'Node & Comment & Deletable & Updatable & UpdatableComment & Reactable & RepositoryNode');

export const CommentConnectionBuilder = createConnectionBuilderClass('PullRequestReviewComment', CommentBuilder);

export const ReviewThreadBuilder = createSpecBuilderClass('PullRequestReviewThread', {
  __typename: {default: 'PullRequestReviewThread'},
  id: {default: nextID},
  isResolved: {default: false},
  viewerCanResolve: {default: f => !f.isResolved},
  viewerCanUnresolve: {default: f => !!f.isResolved},
  resolvedBy: {linked: UserBuilder},
  comments: {linked: CommentConnectionBuilder},
}, 'Node');

export const ReviewBuilder = createSpecBuilderClass('PullRequestReview', {
  __typename: {default: 'PullRequestReview'},
  id: {default: nextID},
  submittedAt: {default: '2018-12-28T20:40:55Z'},
  bodyHTML: {default: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit'},
  state: {default: 'COMMENTED'},
  author: {linked: UserBuilder},
  comments: {linked: CommentConnectionBuilder},
  viewerCanReact: {default: true},
  reactionGroups: {linked: ReactionGroupBuilder, plural: true, singularName: 'reactionGroup'},
}, 'Node & Comment & Deletable & Updatable & UpdatableComment & Reactable & RepositoryNode');

export const CommitConnectionBuilder = createConnectionBuilderClass('PullRequestCommit', CommentBuilder);

export const PullRequestCommitBuilder = createSpecBuilderClass('PullRequestCommit', {
  id: {default: nextID},
  commit: {linked: CommitBuilder},
}, 'Node & UniformResourceLocatable');

export const PullRequestBuilder = createSpecBuilderClass('PullRequest', {
  id: {default: nextID},
  __typename: {default: 'PullRequest'},
  number: {default: 123},
  title: {default: 'the title'},
  baseRefName: {default: 'base-ref'},
  headRefName: {default: 'head-ref'},
  headRefOid: {default: '0000000000000000000000000000000000000000'},
  isCrossRepository: {default: false},
  changedFiles: {default: 5},
  state: {default: 'OPEN'},
  bodyHTML: {default: '', nullable: true},
  createdAt: {default: '2019-01-01T10:00:00Z'},
  countedCommits: {linked: CommitConnectionBuilder},
  url: {default: f => {
    const ownerLogin = (f.repository && f.repository.owner && f.repository.owner.login) || 'aaa';
    const repoName = (f.repository && f.repository.name) || 'bbb';
    const number = f.number || 1;
    return `https://github.com/${ownerLogin}/${repoName}/pull/${number}`;
  }},
  author: {linked: UserBuilder},
  repository: {linked: RepositoryBuilder},
  headRepository: {linked: RepositoryBuilder, nullable: true},
  headRepositoryOwner: {linked: UserBuilder},
  commits: {linked: createConnectionBuilderClass('PullRequestCommit', PullRequestCommitBuilder)},
  recentCommits: {linked: createConnectionBuilderClass('PullRequestCommit', PullRequestCommitBuilder)},
  reviews: {linked: createConnectionBuilderClass('ReviewConnection', ReviewBuilder)},
  reviewThreads: {linked: createConnectionBuilderClass('ReviewThreadConnection', ReviewThreadBuilder)},
  timeline: {linked: createConnectionBuilderClass('PullRequestTimeline', PullRequestTimelineItemBuilder)},
  reactionGroups: {linked: ReactionGroupBuilder, plural: true, singularName: 'reactionGroup'},
  viewerCanReact: {default: true},
},
'Node & Assignable & Closable & Comment & Updatable & UpdatableComment & Labelable & Lockable & Reactable & ' +
'RepositoryNode & Subscribable & UniformResourceLocatable',
);

export function reviewThreadBuilder(...nodes) {
  return ReviewThreadBuilder.onFragmentQuery(nodes);
}

export function pullRequestBuilder(...nodes) {
  return PullRequestBuilder.onFragmentQuery(nodes);
}
<|endoftext|>


<commit_before>'use strict';

let expect         = require('chai').expect;
let createComputer = require('../src/calc').createComputer;

describe('createComputer', () => {

    context('general', () => {

        it('should return a function', () => {

            let compute = createComputer({ a: 1, b: 1 }, 'a + b');
            expect(typeof compute).to.equal('function');

        });
    });

    context('addition', () => {

        it('should compute a + b', () => {

            let compute = createComputer({ a: 1, b: 1 }, 'a + b');
            expect(compute()).to.equal(2);

        });

        it('should compute a + b after a change to a', () => {

            let obj = { a: 1, b: 1 };
            let compute = createComputer(obj, 'a + b');
            expect(compute()).to.equal(2);

            obj.a = 2;
            expect(compute()).to.equal(3);

        });

        it('should compute a + b after a change to b', () => {

            let obj = { a: 1, b: 1 };
            let compute = createComputer(obj, 'a + b');
            expect(compute()).to.equal(2);

            obj.b = 2;
            expect(compute()).to.equal(3);

        });

        it('should compute a + b after a change to a and b', () => {

            let obj = { a: 1, b: 1 };
            let compute = createComputer(obj, 'a + b');
            expect(compute()).to.equal(2);

            obj.a = 2;
            obj.b = 2;
            expect(compute()).to.equal(4);

        });
    });

    context('subtraction', () => {

        it('should compute a - b', () => {

            let compute = createComputer({ a: 1, b: 1 }, 'a - b');
            expect(compute()).to.equal(0);

        });

        it('should compute a - b after a change to a', () => {

            let obj = { a: 1, b: 1 };
            let compute = createComputer(obj, 'a - b');
            expect(compute()).to.equal(0);

            obj.a = 2;
            expect(compute()).to.equal(1);

        });

        it('should compute a - b after a change to b', () => {

            let obj = { a: 1, b: 1 };
            let compute = createComputer(obj, 'a - b');
            expect(compute()).to.equal(0);

            obj.b = 2;
            expect(compute()).to.equal(-1);

        });

        it('should compute a - b after a change to a and b', () => {

            let obj = { a: 1, b: 1 };
            let compute = createComputer(obj, 'a - b');
            expect(compute()).to.equal(0);

            obj.a = 3;
            obj.b = 2;
            expect(compute()).to.equal(1);

        });

    });

    context('multiplication', () => {

        it('should compute a * b', () => {

            let compute = createComputer({ a: 2, b: 3 }, 'a * b');
            expect(compute()).to.equal(6);

        });

        it('should compute a * b after a change to a', () => {

            let obj = { a: 2, b: 3 };
            let compute = createComputer(obj, 'a * b');
            expect(compute()).to.equal(6);

            obj.a = 1;
            expect(compute()).to.equal(3);

        });

        it('should compute a * b after a change to b', () => {

            let obj = { a: 2, b: 3 };
            let compute = createComputer(obj, 'a * b');
            expect(compute()).to.equal(6);

            obj.b = 2;
            expect(compute()).to.equal(4);

        });

        it('should compute a * b after a change to a and b', () => {

            let obj = { a: 2, b: 3 };
            let compute = createComputer(obj, 'a * b');
            expect(compute()).to.equal(6);

            obj.a = 1;
            obj.b = 5;
            expect(compute()).to.equal(5);

        });

    });

    context('division', () => {

        it('should compute a / b', () => {

            let compute = createComputer({ a: 6, b: 3 }, 'a / b');
            expect(compute()).to.equal(2);

        });

        it('should compute a / b after a change to a', () => {

            let obj = { a: 6, b: 3 };
            let compute = createComputer(obj, 'a / b');
            expect(compute()).to.equal(2);

            obj.a = 9;
            expect(compute()).to.equal(3);

        });

        it('should compute a / b after a change to b', () => {

            let obj = { a: 6, b: 3 };
            let compute = createComputer(obj, 'a / b');
            expect(compute()).to.equal(2);

            obj.b = 2;
            expect(compute()).to.equal(3);

        });

        it('should compute a / b after a change to a and b', () => {

            let obj = { a: 6, b: 3 };
            let compute = createComputer(obj, 'a / b');
            expect(compute()).to.equal(2);

            obj.a = 10;
            obj.b = 5;
            expect(compute()).to.equal(2);

        });

    });

    context('modulo', () => {

        it('should compute a % b', () => {

            let compute = createComputer({ a: 6, b: 3 }, 'a % b');
            expect(compute()).to.equal(0);

        });

        it('should compute a % b after a change to a', () => {

            let obj = { a: 6, b: 3 };
            let compute = createComputer(obj, 'a % b');
            expect(compute()).to.equal(0);

            obj.a = 8;
            expect(compute()).to.equal(2);

        });

        it('should compute a % b after a change to b', () => {

            let obj = { a: 6, b: 3 };
            let compute = createComputer(obj, 'a % b');
            expect(compute()).to.equal(0);

            obj.b = 5;
            expect(compute()).to.equal(1);

        });

        it('should compute a % b after a change to a and b', () => {

            let obj = { a: 6, b: 3 };
            let compute = createComputer(obj, 'a % b');
            expect(compute()).to.equal(0);

            obj.a = 11;
            obj.b = 5;
            expect(compute()).to.equal(1);

        });

    });

});<commit_msg>Remove redundant computer tests.<commit_after>'use strict';

let expect         = require('chai').expect;
let createComputer = require('../src/calc').createComputer;

describe('createComputer', () => {

    context('general', () => {

        it('should return a function', () => {

            let compute = createComputer({ a: 1, b: 1 }, 'a + b');
            expect(typeof compute).to.equal('function');

        });
    });

    context('addition', () => {

        it('should compute a + b', () => {

            let compute = createComputer({ a: 1, b: 1 }, 'a + b');
            expect(compute()).to.equal(2);

        });

        it('should compute a + b after a change to a', () => {

            let obj = { a: 1, b: 1 };
            let compute = createComputer(obj, 'a + b');

            obj.a = 2;
            expect(compute()).to.equal(3);

        });

        it('should compute a + b after a change to b', () => {

            let obj = { a: 1, b: 1 };
            let compute = createComputer(obj, 'a + b');

            obj.b = 2;
            expect(compute()).to.equal(3);

        });

        it('should compute a + b after a change to a and b', () => {

            let obj = { a: 1, b: 1 };
            let compute = createComputer(obj, 'a + b');

            obj.a = 2;
            obj.b = 2;
            expect(compute()).to.equal(4);

        });
    });

    context('subtraction', () => {

        it('should compute a - b', () => {

            let compute = createComputer({ a: 1, b: 1 }, 'a - b');
            expect(compute()).to.equal(0);

        });

        it('should compute a - b after a change to a', () => {

            let obj = { a: 1, b: 1 };
            let compute = createComputer(obj, 'a - b');

            obj.a = 2;
            expect(compute()).to.equal(1);

        });

        it('should compute a - b after a change to b', () => {

            let obj = { a: 1, b: 1 };
            let compute = createComputer(obj, 'a - b');

            obj.b = 2;
            expect(compute()).to.equal(-1);

        });

        it('should compute a - b after a change to a and b', () => {

            let obj = { a: 1, b: 1 };
            let compute = createComputer(obj, 'a - b');

            obj.a = 3;
            obj.b = 2;
            expect(compute()).to.equal(1);

        });

    });

    context('multiplication', () => {

        it('should compute a * b', () => {

            let compute = createComputer({ a: 2, b: 3 }, 'a * b');
            expect(compute()).to.equal(6);

        });

        it('should compute a * b after a change to a', () => {

            let obj = { a: 2, b: 3 };
            let compute = createComputer(obj, 'a * b');

            obj.a = 1;
            expect(compute()).to.equal(3);

        });

        it('should compute a * b after a change to b', () => {

            let obj = { a: 2, b: 3 };
            let compute = createComputer(obj, 'a * b');

            obj.b = 2;
            expect(compute()).to.equal(4);

        });

        it('should compute a * b after a change to a and b', () => {

            let obj = { a: 2, b: 3 };
            let compute = createComputer(obj, 'a * b');

            obj.a = 1;
            obj.b = 5;
            expect(compute()).to.equal(5);

        });

    });

    context('division', () => {

        it('should compute a / b', () => {

            let compute = createComputer({ a: 6, b: 3 }, 'a / b');
            expect(compute()).to.equal(2);

        });

        it('should compute a / b after a change to a', () => {

            let obj = { a: 6, b: 3 };
            let compute = createComputer(obj, 'a / b');

            obj.a = 9;
            expect(compute()).to.equal(3);

        });

        it('should compute a / b after a change to b', () => {

            let obj = { a: 6, b: 3 };
            let compute = createComputer(obj, 'a / b');

            obj.b = 2;
            expect(compute()).to.equal(3);

        });

        it('should compute a / b after a change to a and b', () => {

            let obj = { a: 6, b: 3 };
            let compute = createComputer(obj, 'a / b');

            obj.a = 10;
            obj.b = 5;
            expect(compute()).to.equal(2);

        });

    });

    context('modulo', () => {

        it('should compute a % b', () => {

            let compute = createComputer({ a: 6, b: 3 }, 'a % b');
            expect(compute()).to.equal(0);

        });

        it('should compute a % b after a change to a', () => {

            let obj = { a: 6, b: 3 };
            let compute = createComputer(obj, 'a % b');

            obj.a = 8;
            expect(compute()).to.equal(2);

        });

        it('should compute a % b after a change to b', () => {

            let obj = { a: 6, b: 3 };
            let compute = createComputer(obj, 'a % b');

            obj.b = 5;
            expect(compute()).to.equal(1);

        });

        it('should compute a % b after a change to a and b', () => {

            let obj = { a: 6, b: 3 };
            let compute = createComputer(obj, 'a % b');

            obj.a = 11;
            obj.b = 5;
            expect(compute()).to.equal(1);

        });

    });

});<|endoftext|>


<commit_before>/* global describe, it, before, after */
"use strict";
const InstanceManager = require("../../InstanceManager.js");
const expect = require("chai").expect;
const arangojs = require("arangojs");
const rp = require("request-promise");

describe("Move shards", function() {
  let instanceManager = InstanceManager.create();
  let db;
  let servers = [];
  before(function() {
    return instanceManager
      .startCluster(1, 2, 3)
      .then(() => {
        db = arangojs({
          url: instanceManager.getEndpointUrl(),
          databaseName: "_system"
        });
        return db
          .collection("testcollection")
          .create({ shards: 1, replicationFactor: 2 });
      })
      .then(() => {
        return rp({
          url:
            instanceManager.getEndpointUrl() +
            "/_db/_system/_admin/aardvark/cluster/DBServers",
          json: true
        });
      })
      .then(_servers => {
        servers = _servers;
      });
  });
  after(function() {
    return instanceManager.cleanup();
  });

  it("should allow moving shards while writing", function() {
    let stopMoving = false;

    let moveShards = function() {
      if (moveShards.stop) {
        return Promise.resolve();
      }

      let waitShardMoved = function(newLeader, numServers, num) {
        if (num > 10000) {
          return Promise.reject(
            new Error(
              "Shard did not come into sync after " +
                num +
                " tries. " +
                newLeader
            )
          );
        }
        return rp({
          url:
            instanceManager.getEndpointUrl() +
            "/_db/_system/_admin/cluster/shardDistribution",
          json: true
        })
          .then(shardDistribution => {
            let currentShards =
              shardDistribution.results.testcollection.Current;
            let shardKey = Object.keys(currentShards)[0];
            // upon leader resign this might be undefined
            let currentServers = [];
            if (currentShards[shardKey].leader) {
              currentServers.push(currentShards[shardKey].leader);
            }

            let plannedShards = shardDistribution.results.testcollection.Plan;
            let plannedServers = [];
            if (plannedShards[shardKey].leader) {
              plannedServers.push(plannedShards[shardKey].leader);
            }
            return [
              plannedServers.concat(plannedShards[shardKey].followers),
              currentServers.concat(currentShards[shardKey].followers)
            ];
          })
          .then(result => {
            let planned = result[0];
            let current = result[1];

            return (
              current.length == numServers &&
              current.length == planned.length &&
              current[0] === newLeader &&
              current.every((server, index) => planned[index] == server)
            );
          })
          .then(finished => {
            if (!finished) {
              return new Promise((resolve, reject) => {
                setTimeout(resolve, 100);
              }).then(() => {
                return waitShardMoved(newLeader, numServers, num + 1);
              });
            }
          });
      };

      return rp({
        url:
          instanceManager.getEndpointUrl() +
          "/_db/_system/_admin/cluster/shardDistribution",
        json: true
      })
        .then(shardDistribution => {
          let shards = shardDistribution.results.testcollection.Plan;
          let shardKey = Object.keys(shards)[0];
          let is = [shards[shardKey].leader].concat(shards[shardKey].followers);
          let freeServer = servers.filter(
            server => is.indexOf(server.name) == -1
          )[0];

          if (freeServer === undefined) {
            throw new Error(
              "Don't have a free server! Servers: " +
                JSON.stringify(servers) +
                ", current: " +
                JSON.stringify(is)
            );
          }
          let should = is.slice();
          should[0] = freeServer.name;
          let move = {
            collection: "testcollection",
            database: "_system",
            shard: shardKey,
            fromServer: servers.filter(
              server => server.name == shards[shardKey].leader
            )[0].id,
            toServer: freeServer.id
          };
          return rp({
            url:
              instanceManager.getEndpointUrl() +
              "/_db/_system/_admin/cluster/moveShard",
            json: true,
            body: move,
            method: "POST"
          }).then(() => {
            return should;
          });
        })
        .then(should => {
          return waitShardMoved(should[0], should.length, 1);
        })
        .then(() => {
          return moveShards();
        });
    };

    let insertDocuments = function() {
      return [...Array(10000).keys()].reduce((promise, key) => {
        return promise.then(() => {
          return db.collection("testcollection").save({ hallooo: key });
        });
      }, Promise.resolve());
    };

    let movePromise = moveShards();

    return insertDocuments()
      .then(() => {
        console.log("Done inserting 10000 docs.");
        moveShards.stop = true;
        return movePromise;
      })
      .then(() => {
        console.log("movePromise resolved");
        return db.collection("testcollection").count();
      })
      .then(count => {
        return db.collection("testcollection").all();
      })
      .then(cursor => {
        return cursor.all();
      })
      .then(all => {
        all = all.map(doc => doc.hallooo);
        all.sort((a, b) => {
          if (a < b) {
            return -1;
          } else if (a > b) {
            return 1;
          } else {
            return 0;
          }
        });

        let errorMsg = "";
        if (all.length !== 10000) {
          for (let i = 0; i < all.length; ++i) {
            if (all[i] !== i) {
              errorMsg +=
                "At position " +
                i +
                " we got " +
                all[i] +
                " instead of " +
                i +
                "\n";
            }
          }
        }
        expect(all, errorMsg).to.have.lengthOf(10000);
      });
  });
});
<commit_msg>Improve error message (#9)<commit_after>/* global describe, it, before, after */
"use strict";
const InstanceManager = require("../../InstanceManager.js");
const expect = require("chai").expect;
const arangojs = require("arangojs");
const rp = require("request-promise");
const _ = require("lodash");

describe("Move shards", function() {
  let instanceManager = InstanceManager.create();
  let db;
  let servers = [];
  before(function() {
    return instanceManager
      .startCluster(1, 2, 3)
      .then(() => {
        db = arangojs({
          url: instanceManager.getEndpointUrl(),
          databaseName: "_system"
        });
        return db
          .collection("testcollection")
          .create({ shards: 1, replicationFactor: 2 });
      })
      .then(() => {
        return rp({
          url:
            instanceManager.getEndpointUrl() +
            "/_db/_system/_admin/aardvark/cluster/DBServers",
          json: true
        });
      })
      .then(_servers => {
        servers = _servers;
      });
  });
  after(function() {
    return instanceManager.cleanup();
  });

  it("should allow moving shards while writing", function() {
    let stopMoving = false;

    let moveShards = function() {
      if (moveShards.stop) {
        return Promise.resolve();
      }

      let waitShardMoved = function(newLeader, numServers, num) {
        if (num > 10000) {
          return Promise.reject(
            new Error(
              "Shard did not come into sync after " +
                num +
                " tries. " +
                newLeader
            )
          );
        }
        return rp({
          url:
            instanceManager.getEndpointUrl() +
            "/_db/_system/_admin/cluster/shardDistribution",
          json: true
        })
          .then(shardDistribution => {
            let currentShards =
              shardDistribution.results.testcollection.Current;
            let shardKey = Object.keys(currentShards)[0];
            // upon leader resign this might be undefined
            let currentServers = [];
            if (currentShards[shardKey].leader) {
              currentServers.push(currentShards[shardKey].leader);
            }

            let plannedShards = shardDistribution.results.testcollection.Plan;
            let plannedServers = [];
            if (plannedShards[shardKey].leader) {
              plannedServers.push(plannedShards[shardKey].leader);
            }
            return [
              plannedServers.concat(plannedShards[shardKey].followers),
              currentServers.concat(currentShards[shardKey].followers)
            ];
          })
          .then(result => {
            let planned = result[0];
            let current = result[1];

            return (
              current.length == numServers &&
              current.length == planned.length &&
              current[0] === newLeader &&
              current.every((server, index) => planned[index] == server)
            );
          })
          .then(finished => {
            if (!finished) {
              return new Promise((resolve, reject) => {
                setTimeout(resolve, 100);
              }).then(() => {
                return waitShardMoved(newLeader, numServers, num + 1);
              });
            }
          });
      };

      return rp({
        url:
          instanceManager.getEndpointUrl() +
          "/_db/_system/_admin/cluster/shardDistribution",
        json: true
      })
        .then(shardDistribution => {
          let shards = shardDistribution.results.testcollection.Plan;
          let shardKey = Object.keys(shards)[0];
          let is = [shards[shardKey].leader].concat(shards[shardKey].followers);
          let freeServer = servers.filter(
            server => is.indexOf(server.name) == -1
          )[0];

          if (freeServer === undefined) {
            throw new Error(
              "Don't have a free server! Servers: " +
                JSON.stringify(servers) +
                ", current: " +
                JSON.stringify(is)
            );
          }
          let should = is.slice();
          should[0] = freeServer.name;
          let move = {
            collection: "testcollection",
            database: "_system",
            shard: shardKey,
            fromServer: servers.filter(
              server => server.name == shards[shardKey].leader
            )[0].id,
            toServer: freeServer.id
          };
          return rp({
            url:
              instanceManager.getEndpointUrl() +
              "/_db/_system/_admin/cluster/moveShard",
            json: true,
            body: move,
            method: "POST"
          }).then(() => {
            return should;
          });
        })
        .then(should => {
          return waitShardMoved(should[0], should.length, 1);
        })
        .then(() => {
          return moveShards();
        });
    };

    let insertDocuments = function() {
      return [...Array(10000).keys()].reduce((promise, key) => {
        return promise.then(() => {
          return db.collection("testcollection").save({ hallooo: key });
        });
      }, Promise.resolve());
    };

    let movePromise = moveShards();

    return insertDocuments()
      .then(() => {
        console.log("Done inserting 10000 docs.");
        moveShards.stop = true;
        return movePromise;
      })
      .then(() => {
        console.log("movePromise resolved");
        return db.collection("testcollection").count();
      })
      .then(count => {
        return db.collection("testcollection").all();
      })
      .then(cursor => {
        return cursor.all();
      })
      .then(all => {
        all = new Set(all.map(doc => doc.hallooo));

        let errorMsg = "";
        if (all.size !== 10000) {
          for (let i = 0; i < 10000; ++i) {
            if (!all.has(i)) {
              errorMsg += `Document ${i} missing!\n`;
            }
          }
          // If you get the following error message, most probably something is
          // wrong in the test code.
          for (const i of all) {
            if (!_.inRange(i, 0, 10000)) {
              errorMsg += `Unexpected document ${i}!\n`;
            }
          }
        }
        expect(all.size, errorMsg).to.equal(10000);
      });
  });
});
<|endoftext|>


<commit_before>define(["Tone/component/Envelope", "helper/Basic", "helper/Offline", "Test"],
function (Envelope, Basic, Offline, Test) {
	describe("Envelope", function(){

		Basic(Envelope);

		context("Envelope", function(){

			it("has an output connections", function(){
				var env = new Envelope();
				env.connect(Test);
				env.dispose();
			});

			it ("can get and set values an Objects", function(){
				var env = new Envelope();
				var values = {
					"attack" : 0,
					"decay" : 0.5,
					"sustain" : 1,
					"release" : "4n"
				};
				env.set(values);
				expect(env.get()).to.contain.keys(Object.keys(values));
				env.dispose();
			});

			it ("passes no signal before being triggered", function(done){
				var env;
				var offline = new Offline(0.1);
				offline.before(function(dest){
					env = new Envelope().connect(dest);
				});
				offline.test(function(sample){
					expect(sample).to.be.closeTo(0, 0.001);
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("passes signal once triggered", function(done){
				var env;
				var offline = new Offline(0.2);
				offline.before(function(dest){
					env = new Envelope().connect(dest);
					env.triggerAttack(0.1);
				});
				offline.test(function(sample, time){
					if (time <= 0.1){
						expect(sample).to.be.closeTo(0, 0.001);
					} else {
						expect(sample).to.be.above(0);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("can take parameters as both an object and as arguments", function(){
				var env0 = new Envelope({
					"attack" : 0,
					"decay" : 0.5,
					"sustain" : 1
				});
				expect(env0.attack).to.equal(0);
				expect(env0.decay).to.equal(0.5);
				expect(env0.sustain).to.equal(1);
				env0.dispose();
				var env1 = new Envelope(0.1, 0.2, 0.3);
				expect(env1.attack).to.equal(0.1);
				expect(env1.decay).to.equal(0.2);
				expect(env1.sustain).to.equal(0.3);
				env1.dispose();
			});

			it("can set attack to exponential or linear", function(){
				var env = new Envelope(0.01, 0.01, 0.5, 0.3);
				env.attackCurve = "exponential";
				expect(env.attackCurve).to.equal("exponential");
				env.triggerAttack();
				env.dispose();
				//and can be linear
				var env2 = new Envelope(0.01, 0.01, 0.5, 0.3);
				env2.attackCurve = "linear";
				expect(env2.attackCurve).to.equal("linear");
				env2.triggerAttack();
				//and test a non-curve
				expect(function(){
					env2.attackCurve = "other";
				}).to.throw(Error);
				env2.dispose();
			});

			it("can set release to exponential or linear", function(){
				var env = new Envelope(0.01, 0.01, 0.5, 0.3);
				env.releaseCurve = "exponential";
				expect(env.releaseCurve).to.equal("exponential");
				env.triggerRelease();
				env.dispose();
				//and can be linear
				var env2 = new Envelope(0.01, 0.01, 0.5, 0.3);
				env2.releaseCurve = "linear";
				expect(env2.releaseCurve).to.equal("linear");
				env2.triggerRelease();
				//and test a non-curve
				expect(function(){
					env2.releaseCurve = "other";
				}).to.throw(Error);
				env2.dispose();
			});

			it ("correctly schedules an exponential attack", function(done){
				var env;
				var offline = new Offline(0.7);
				offline.before(function(dest){
					env = new Envelope(0.01, 0.4, 0.5, 0.1);
					env.attackCurve = "exponential";
					env.connect(dest);
					env.triggerAttack(0);
				});
				offline.test(function(sample, time){
					if (time < env.attack){
						expect(sample).to.be.within(0, 1);
					} else if (time < env.attack + env.decay){
						expect(sample).to.be.within(env.sustain, 1);
					} else {
						expect(sample).to.be.closeTo(env.sustain, 0.01);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("correctly schedules an exponential attack", function(done){
				var env;
				var offline = new Offline(0.7);
				offline.before(function(dest){
					env = new Envelope(0.3, 0.001, 0.5, 0.1);
					env.attackCurve = "exponential";
					env.connect(dest);
					env.triggerAttack(0);
				});
				offline.test(function(sample, time){
					if (time < env.attack){
						expect(sample).to.be.within(0, 1);
					} else if (time < env.attack + env.decay){
						expect(sample).to.be.within(env.sustain, 1);
					} else {
						expect(sample).to.be.closeTo(env.sustain, 0.01);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("can schedule a very short attack", function(done){
				var env;
				var offline = new Offline(0.2);
				offline.before(function(dest){
					env = new Envelope(0.001, 0.001, 0);
					env.connect(dest);
					env.triggerAttack(0);
				});
				offline.test(function(sample, time){
					if (time < env.attack){
						expect(sample).to.be.within(0, 1);
					} else if (time < env.attack + env.decay){
						expect(sample).to.be.within(0, 1);
					} else {
						expect(sample).to.be.below(0.02);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("correctly schedule a release", function(done){
				var releaseTime = 0.2;
				var env;
				var offline = new Offline(0.7);
				offline.before(function(dest){
					env = new Envelope(0.001, 0.001, 0.5, 0.3);
					env.connect(dest);
					env.triggerAttack(0);
					env.triggerRelease(releaseTime);
				});
				offline.test(function(sample, time){
					if (time > env.attack + env.decay && time < env.attack + env.decay + releaseTime){
						expect(sample).to.be.below(env.sustain + 0.01);
					} else if (time > 0.5){
						//silent
						expect(sample).to.be.below(0.01);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("correctly schedule an attack release envelope", function(done){
				var env;
				var releaseTime = 0.4;
				var offline = new Offline(0.8);
				offline.before(function(dest){
					env = new Envelope(0.08, 0.2, 0.1, 0.2);
					env.connect(dest);
					env.triggerAttack(0);
					env.triggerRelease(releaseTime);
				});
				offline.test(function(sample, time){
					if (time < env.attack){
						expect(sample).to.be.within(0, 1);
					} else if (time < env.attack + env.decay){
						expect(sample).to.be.within(env.sustain, 1);
					} else if (time < releaseTime){
						expect(sample).to.be.closeTo(env.sustain, 0.1);
					} else if (time < releaseTime + env.release){
						expect(sample).to.be.within(0, env.sustain + 0.01);
					} else {
						//silent
						expect(sample).to.be.below(0.01);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("can schedule a combined AttackRelease", function(done){
				var env;
				var duration = 0.4;
				var offline = new Offline(0.7);
				offline.before(function(dest){
					env = new Envelope(0.1, 0.2, 0.35, 0.1);
					env.connect(dest);
					env.triggerAttackRelease(duration, 0);
				});
				offline.test(function(sample, time){
					if (time < env.attack){
						expect(sample).to.be.within(0, 1);
					} else if (time < env.attack + env.decay){
						expect(sample).to.be.within(env.sustain - 0.001, 1);
					} else if (time < duration){
						expect(sample).to.be.closeTo(env.sustain, 0.1);
					} else if (time < duration + env.release){
						expect(sample).to.be.within(0, env.sustain + 0.01);
					} else {
						expect(sample).to.be.below(0.01);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("can schedule a combined AttackRelease with velocity", function(done){
				var env;
				var duration = 0.4;
				var velocity = 0.4;
				var offline = new Offline(0.8);
				offline.before(function(dest){
					env = new Envelope(0.1, 0.2, 0.35, 0.1);
					env.connect(dest);
					env.triggerAttackRelease(duration, 0, velocity);
				});
				offline.test(function(sample, time){
					if (time < env.attack){
						expect(sample).to.be.within(0, velocity + 0.01);
					} else if (time < env.attack + env.decay){
						expect(sample).to.be.within(env.sustain * velocity - 0.01, velocity + 0.01);
					} else if (time < duration){
						expect(sample).to.be.closeTo(env.sustain * velocity, 0.1);
					} else if (time < duration + env.release){
						expect(sample).to.be.within(0, env.sustain * velocity + 0.01);
					} else {
						expect(sample).to.be.below(0.01);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("can schedule multiple envelopes", function(done){
				var env;
				var offline = new Offline(1);
				offline.before(function(dest){
					env = new Envelope(0.1, 0.2, 0);
					env.connect(dest);
					env.triggerAttack(0);
					env.triggerAttack(0.5);
				});
				offline.test(function(sample, time){
					if (time > 0 && time < 0.3){
						expect(sample).to.be.above(0);
					} else if (time <= 0.5){
						expect(sample).to.be.below(0.02);
					} else if (time <= 0.8){
						expect(sample).to.be.above(0);
					} else {
						expect(sample).to.be.below(0.02);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("reports its current envelope value (.value)", function(done){
				var env = new Envelope(0.1, 0.2, 1).noGC();
				expect(env.value).to.be.closeTo(0, 0.01);
				env.triggerAttack();
				setTimeout(function(){
					expect(env.value).to.be.closeTo(1, 0.01);
					env.dispose();
					done();
				}, 200);
			});
		});
	});
});<commit_msg>testing that envelope is silent while not triggered<commit_after>define(["Tone/component/Envelope", "helper/Basic", "helper/Offline", "Test"],
function (Envelope, Basic, Offline, Test) {
	describe("Envelope", function(){

		Basic(Envelope);

		context("Envelope", function(){

			it("has an output connections", function(){
				var env = new Envelope();
				env.connect(Test);
				env.dispose();
			});

			it ("can get and set values an Objects", function(){
				var env = new Envelope();
				var values = {
					"attack" : 0,
					"decay" : 0.5,
					"sustain" : 1,
					"release" : "4n"
				};
				env.set(values);
				expect(env.get()).to.contain.keys(Object.keys(values));
				env.dispose();
			});

			it ("passes no signal before being triggered", function(done){
				var env;
				var offline = new Offline(0.1);
				offline.before(function(dest){
					env = new Envelope().connect(dest);
				});
				offline.test(function(sample){
					expect(sample).to.be.closeTo(0, 0.001);
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("passes signal once triggered", function(done){
				var env;
				var offline = new Offline(0.2);
				offline.before(function(dest){
					env = new Envelope().connect(dest);
					env.triggerAttack(0.1);
				});
				offline.test(function(sample, time){
					if (time <= 0.1){
						expect(sample).to.be.closeTo(0, 0.001);
					} else {
						expect(sample).to.be.above(0);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("can take parameters as both an object and as arguments", function(){
				var env0 = new Envelope({
					"attack" : 0,
					"decay" : 0.5,
					"sustain" : 1
				});
				expect(env0.attack).to.equal(0);
				expect(env0.decay).to.equal(0.5);
				expect(env0.sustain).to.equal(1);
				env0.dispose();
				var env1 = new Envelope(0.1, 0.2, 0.3);
				expect(env1.attack).to.equal(0.1);
				expect(env1.decay).to.equal(0.2);
				expect(env1.sustain).to.equal(0.3);
				env1.dispose();
			});

			it("can set attack to exponential or linear", function(){
				var env = new Envelope(0.01, 0.01, 0.5, 0.3);
				env.attackCurve = "exponential";
				expect(env.attackCurve).to.equal("exponential");
				env.triggerAttack();
				env.dispose();
				//and can be linear
				var env2 = new Envelope(0.01, 0.01, 0.5, 0.3);
				env2.attackCurve = "linear";
				expect(env2.attackCurve).to.equal("linear");
				env2.triggerAttack();
				//and test a non-curve
				expect(function(){
					env2.attackCurve = "other";
				}).to.throw(Error);
				env2.dispose();
			});

			it("can set release to exponential or linear", function(){
				var env = new Envelope(0.01, 0.01, 0.5, 0.3);
				env.releaseCurve = "exponential";
				expect(env.releaseCurve).to.equal("exponential");
				env.triggerRelease();
				env.dispose();
				//and can be linear
				var env2 = new Envelope(0.01, 0.01, 0.5, 0.3);
				env2.releaseCurve = "linear";
				expect(env2.releaseCurve).to.equal("linear");
				env2.triggerRelease();
				//and test a non-curve
				expect(function(){
					env2.releaseCurve = "other";
				}).to.throw(Error);
				env2.dispose();
			});

			it ("correctly schedules an exponential attack", function(done){
				var env;
				var offline = new Offline(0.7);
				offline.before(function(dest){
					env = new Envelope(0.01, 0.4, 0.5, 0.1);
					env.attackCurve = "exponential";
					env.connect(dest);
					env.triggerAttack(0);
				});
				offline.test(function(sample, time){
					if (time < env.attack){
						expect(sample).to.be.within(0, 1);
					} else if (time < env.attack + env.decay){
						expect(sample).to.be.within(env.sustain, 1);
					} else {
						expect(sample).to.be.closeTo(env.sustain, 0.01);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("correctly schedules a linear release", function(done){
				var env;
				var offline = new Offline(0.4);
				offline.before(function(dest){
					env = new Envelope(0.1, 0.01, 1, 0.1);
					env.releaseCurve = "linear";
					env.connect(dest);
					env.triggerAttackRelease(0.2, 0);
				});
				offline.test(function(sample, time){
					if (time > 0.2 && time <= 0.3){
						var target = 1 - (time - 0.2) * 10;
						expect(sample).to.be.closeTo(target, 0.01);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("can schedule a very short attack", function(done){
				var env;
				var offline = new Offline(0.2);
				offline.before(function(dest){
					env = new Envelope(0.001, 0.001, 0);
					env.connect(dest);
					env.triggerAttack(0);
				});
				offline.test(function(sample, time){
					if (time < env.attack){
						expect(sample).to.be.within(0, 1);
					} else if (time < env.attack + env.decay){
						expect(sample).to.be.within(0, 1);
					} else {
						expect(sample).to.be.below(0.02);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("correctly schedule a release", function(done){
				var releaseTime = 0.2;
				var env;
				var offline = new Offline(0.7);
				offline.before(function(dest){
					env = new Envelope(0.001, 0.001, 0.5, 0.3);
					env.connect(dest);
					env.triggerAttack(0);
					env.triggerRelease(releaseTime);
				});
				offline.test(function(sample, time){
					if (time > env.attack + env.decay && time < env.attack + env.decay + releaseTime){
						expect(sample).to.be.below(env.sustain + 0.01);
					} else if (time > 0.5){
						//silent
						expect(sample).to.be.below(0.01);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("is silent before and after triggering", function(done){
				var releaseTime = 0.2;
				var attackTime = 0.1;
				var env;
				var offline = new Offline(0.7);
				offline.before(function(dest){
					env = new Envelope(0.001, 0.001, 0.5, 0.01);
					env.connect(dest);
					env.triggerAttack(attackTime);
					env.triggerRelease(releaseTime);
				});
				offline.test(function(sample, time){
					if (time < attackTime){
						expect(sample).to.equal(0);
					} else if (time > env.attack + env.decay + releaseTime + env.release){
						expect(sample).to.equal(0);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("correctly schedule an attack release envelope", function(done){
				var env;
				var releaseTime = 0.4;
				var offline = new Offline(0.8);
				offline.before(function(dest){
					env = new Envelope(0.08, 0.2, 0.1, 0.2);
					env.connect(dest);
					env.triggerAttack(0);
					env.triggerRelease(releaseTime);
				});
				offline.test(function(sample, time){
					if (time < env.attack){
						expect(sample).to.be.within(0, 1);
					} else if (time < env.attack + env.decay){
						expect(sample).to.be.within(env.sustain, 1);
					} else if (time < releaseTime){
						expect(sample).to.be.closeTo(env.sustain, 0.1);
					} else if (time < releaseTime + env.release){
						expect(sample).to.be.within(0, env.sustain + 0.01);
					} else {
						//silent
						expect(sample).to.be.below(0.01);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("can schedule a combined AttackRelease", function(done){
				var env;
				var duration = 0.4;
				var offline = new Offline(0.7);
				offline.before(function(dest){
					env = new Envelope(0.1, 0.2, 0.35, 0.1);
					env.connect(dest);
					env.triggerAttackRelease(duration, 0);
				});
				offline.test(function(sample, time){
					if (time < env.attack){
						expect(sample).to.be.within(0, 1);
					} else if (time < env.attack + env.decay){
						expect(sample).to.be.within(env.sustain - 0.001, 1);
					} else if (time < duration){
						expect(sample).to.be.closeTo(env.sustain, 0.1);
					} else if (time < duration + env.release){
						expect(sample).to.be.within(0, env.sustain + 0.01);
					} else {
						expect(sample).to.be.below(0.01);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("can schedule a combined AttackRelease with velocity", function(done){
				var env;
				var duration = 0.4;
				var velocity = 0.4;
				var offline = new Offline(0.8);
				offline.before(function(dest){
					env = new Envelope(0.1, 0.2, 0.35, 0.1);
					env.connect(dest);
					env.triggerAttackRelease(duration, 0, velocity);
				});
				offline.test(function(sample, time){
					if (time < env.attack){
						expect(sample).to.be.within(0, velocity + 0.01);
					} else if (time < env.attack + env.decay){
						expect(sample).to.be.within(env.sustain * velocity - 0.01, velocity + 0.01);
					} else if (time < duration){
						expect(sample).to.be.closeTo(env.sustain * velocity, 0.1);
					} else if (time < duration + env.release){
						expect(sample).to.be.within(0, env.sustain * velocity + 0.01);
					} else {
						expect(sample).to.be.below(0.01);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("can schedule multiple envelopes", function(done){
				var env;
				var offline = new Offline(1);
				offline.before(function(dest){
					env = new Envelope(0.1, 0.2, 0);
					env.connect(dest);
					env.triggerAttack(0);
					env.triggerAttack(0.5);
				});
				offline.test(function(sample, time){
					if (time > 0 && time < 0.3){
						expect(sample).to.be.above(0);
					} else if (time <= 0.5){
						expect(sample).to.be.below(0.02);
					} else if (time <= 0.8){
						expect(sample).to.be.above(0);
					} else {
						expect(sample).to.be.below(0.02);
					}
				});
				offline.after(function(){
					env.dispose();
					done();
				});
				offline.run();
			});

			it ("reports its current envelope value (.value)", function(done){
				var env = new Envelope(0.1, 0.2, 1).noGC();
				expect(env.value).to.be.closeTo(0, 0.01);
				env.triggerAttack();
				setTimeout(function(){
					expect(env.value).to.be.closeTo(1, 0.01);
					env.dispose();
					done();
				}, 200);
			});
		});
	});
});<|endoftext|>