'use strict';

import UserDefinition from '../UserDefinition';
import { buildConstant, buildPointwiseUnary, buildPointwiseBinary, buildSink } from '../nativeDefinitionHelpers';

describe('runtime', () => {
  test('user defined identity function', () => {
    const def = new UserDefinition(null, {
      inputs: [
        {tempo: 'step'},
      ],
      output: {tempo: 'step'},
    });

    def.addConnection(def.definitionInputs[0], def.definitionOutput);

    const outputCallback = jest.fn();
    const act = def.activate(outputCallback);

    expect(outputCallback).not.toBeCalled();

    act.evaluate([{value: 123, changed: true}]);

    expect(outputCallback.mock.calls).toEqual([[123]]);
    outputCallback.mockClear();

    act.evaluate([{value: 456, changed: true}]);

    expect(outputCallback.mock.calls).toEqual([[456]]);
  });

  test('user defined identity function, adding connection after activation', () => {
    const def = new UserDefinition(null, {
      inputs: [
        {tempo: 'step'},
      ],
      output: {tempo: 'step'},
    });

    const outputCallback = jest.fn();
    const act = def.activate(outputCallback);

    expect(outputCallback).not.toBeCalled();

    act.evaluate([{value: 123, changed: true}]);

    // NOTE: Since connection hasn't been made, output will still be undefined
    // TODO: We might change expectation to be that outputCallback is called with undefined value
    expect(outputCallback).not.toBeCalled();
    outputCallback.mockClear();

    def.addConnection(def.definitionInputs[0], def.definitionOutput);

    expect(outputCallback.mock.calls).toEqual([[123]]);
    outputCallback.mockClear();

    act.evaluate([{value: 456, changed: true}]);

    expect(outputCallback.mock.calls).toEqual([[456]]);
  });

  test('constant connected to definition out', () => {
    const def = new UserDefinition(null, {
      inputs: [],
      output: {tempo: 'step'},
    });

    const constDef = buildConstant(123);

    const constApp = def.addNativeApplication(constDef);

    def.addConnection(constApp.output, def.definitionOutput);

    const outputCallback = jest.fn();
    const act = def.activate(outputCallback);

    expect(outputCallback).not.toBeCalled();

    act.evaluate();

    expect(outputCallback.mock.calls).toEqual([[123]]);
  });

  test('adding two constants into sink output', () => {
    const const2Def = buildConstant(2);
    const const3Def = buildConstant(3);

    const mockAdd = jest.fn((a, b) => a + b);
    const addDef = buildPointwiseBinary(mockAdd);

    const mockSink = jest.fn();
    const sinkDef = buildSink(mockSink);

    const def = new UserDefinition();
    const const2App = def.addNativeApplication(const2Def);
    const const3App = def.addNativeApplication(const3Def);
    const addApp = def.addNativeApplication(addDef);
    const sinkApp = def.addNativeApplication(sinkDef);

    def.addConnection(const2App.output, addApp.inputs[0]);
    def.addConnection(const3App.output, addApp.inputs[1]);
    def.addConnection(addApp.output, sinkApp.inputs[0]);

    expect(mockAdd).not.toBeCalled();
    expect(mockSink).not.toBeCalled();

    const outputCallback = jest.fn();
    const act = def.activate(outputCallback);

    // Nothing should have been called yet since we haven't done first evaluate()
    expect(outputCallback).not.toBeCalled();
    expect(mockAdd).not.toBeCalled();
    expect(mockSink).not.toBeCalled();

    act.evaluate();

    expect(outputCallback).not.toBeCalled();
    expect(mockAdd.mock.calls.length).toBe(1);
    expect(mockSink.mock.calls).toEqual([[5]]);
  });
});

@@ -3579,13 +3579,1265 @@
 );%0A  %7D);
+%0A%0A  test('removing connection via disconnectPort from either end', () =%3E %7B%0A    const constDef = buildConstant(123);%0A%0A    const mockSink = jest.fn();%0A    const sinkDef = buildSink(mockSink);%0A%0A    const def = new UserDefinition();%0A    const constApp = def.addNativeApplication(constDef);%0A    const sinkApp = def.addNativeApplication(sinkDef);%0A    const act = def.activate();%0A%0A    expect(mockSink).not.toBeCalled(); // sanity check%0A%0A    act.evaluate();%0A    // Since there is no connection and we did initial eval, sink will get eval'd with undefined%0A    expect(mockSink.mock.calls).toEqual(%5B%5Bundefined%5D%5D);%0A    mockSink.mockClear();%0A%0A    def.addConnection(constApp.output, sinkApp.inputs%5B0%5D);%0A%0A    expect(mockSink.mock.calls).toEqual(%5B%5B123%5D%5D);%0A    mockSink.mockClear();%0A%0A    // disconnect from output end%0A    def.disconnectPort(constApp.output);%0A%0A    expect(mockSink.mock.calls).toEqual(%5B%5Bundefined%5D%5D);%0A    mockSink.mockClear();%0A%0A    // re-add connection%0A    def.addConnection(constApp.output, sinkApp.inputs%5B0%5D);%0A%0A    expect(mockSink.mock.calls).toEqual(%5B%5B123%5D%5D);%0A    mockSink.mockClear();%0A%0A    // disconnect from input end%0A    def.disconnectPort(sinkApp.inputs%5B0%5D);%0A%0A    expect(mockSink.mock.calls).toEqual(%5B%5Bundefined%5D%5D);%0A    mockSink.mockClear();%0A  %7D);
 %0A%7D);%0A

Add basic test of adding/removing connections