// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

let { session, contextGroup, Protocol } = InspectorTest.start(
  "Test static private class methods"
);

const script = `
function run() {
  class A {
    static test() {
      debugger;
    }
    static #field = 2;
    #instanceMethod() { }  // should not show up
    get #instanceAccessor() { return this.#field; }  // should not show up
    set #instanceAccessor(val) { this.#field = val; }  // should not show up

    static set #writeOnly(val) { this.#field = val; }
    static get #readOnly() { return this.#field; }
    static get #accessor() { return this.#field; }
    static set #accessor(val) { this.#field = val; }
    static #inc() { return ++A.#accessor; }
  };
  A.test();

  class B extends A {
    static get #accessor() { return 'subclassAccessor'; }
    static #subclassMethod() { return B.#accessor; }
    static test() {
      debugger;
    }
  }

  B.test();
}`;

contextGroup.addScript(script);

InspectorTest.runAsyncTestSuite([
  async function testScopesPaused() {
    Protocol.Debugger.enable();

    // Do not await here, instead oncePaused should be awaited.
    Protocol.Runtime.evaluate({ expression: 'run()' });

    InspectorTest.log('privateProperties on the base class');
    let {
      params: { callFrames }
    } = await Protocol.Debugger.oncePaused(); // inside A.test()
    let frame = callFrames[0];
    let { result } = await Protocol.Runtime.getProperties({
      objectId: frame.this.objectId
    });
    InspectorTest.logMessage(result.privateProperties);

    InspectorTest.log('Evaluating A.#inc();');
    ({ result } = await Protocol.Debugger.evaluateOnCallFrame({
      expression: 'A.#inc();',
      callFrameId: callFrames[0].callFrameId
    }));
    InspectorTest.logObject(result);

    InspectorTest.log('Evaluating this.#inc();');
    ({ result } = await Protocol.Debugger.evaluateOnCallFrame({
      expression: 'this.#inc();',
      callFrameId: callFrames[0].callFrameId
    }));
    InspectorTest.logObject(result);

    InspectorTest.log('Evaluating ++this.#accessor;');
    ({ result } = await Protocol.Debugger.evaluateOnCallFrame({
      expression: '++this.#accessor;',
      callFrameId: callFrames[0].callFrameId
    }));
    InspectorTest.logObject(result);

    InspectorTest.log('Evaluating this.#readOnly;');
    ({ result } = await Protocol.Debugger.evaluateOnCallFrame({
      expression: 'this.#readOnly;',
      callFrameId: callFrames[0].callFrameId
    }));
    InspectorTest.logObject(result);

    InspectorTest.log('Evaluating this.#writeOnly = 0; this.#field;');
    ({ result } = await Protocol.Debugger.evaluateOnCallFrame({
      expression: 'this.#writeOnly = 0; this.#field;',
      callFrameId: callFrames[0].callFrameId
    }));
    InspectorTest.logObject(result);

    Protocol.Debugger.resume();
    ({ params: { callFrames } } = await Protocol.Debugger.oncePaused());  // B.test();
    frame = callFrames[0];

    InspectorTest.log('privateProperties on the subclass');
    ({ result } = await Protocol.Runtime.getProperties({
      objectId: frame.this.objectId
    }));
    InspectorTest.logMessage(result.privateProperties);

    InspectorTest.log('Evaluating this.#inc(); from the base class');
    ({ result } = await Protocol.Debugger.evaluateOnCallFrame({
      expression: 'this.#inc();',
      callFrameId: callFrames[0].callFrameId
    }));
    InspectorTest.logMessage(result);

    InspectorTest.log('Evaluating this.#subclassMethod();');
    ({ result } = await Protocol.Debugger.evaluateOnCallFrame({
      expression: 'this.#subclassMethod();',
      callFrameId: callFrames[0].callFrameId
    }));
    InspectorTest.logMessage(result);

    Protocol.Debugger.resume();
    Protocol.Debugger.disable();
  }
]);
