text: // Copyright 2017 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.
  
  // Flags: --allow-natives-syntax
  
  let {session, contextGroup, Protocol} =
    InspectorTest.start('Checks Runtime.queryObjects');
  
  InspectorTest.runAsyncTestSuite([
    async function testClass() {
      let contextGroup = new InspectorTest.ContextGroup();
      let session = contextGroup.connect();
      let Protocol = session.Protocol;
  
      InspectorTest.log('Declare class Foo & store its constructor.');
      await Protocol.Runtime.evaluate({
        expression: 'class Foo{constructor(){}};'
      });
      let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
        expression: 'Foo.prototype'
      });
  
      for (let i = 0; i < 2; ++i) {
        InspectorTest.log('Create object with class Foo.');
        Protocol.Runtime.evaluate({expression: 'new Foo()'});
        await queryObjects(session, objectId, 'Foo');
      }
  
      session.disconnect();
    },
  
    async function testDerivedNewClass() {
      let contextGroup = new InspectorTest.ContextGroup();
      let session = contextGroup.connect();
      let Protocol = session.Protocol;
  
      InspectorTest.log('Declare class Foo & store its constructor.');
      Protocol.Runtime.evaluate({expression: 'class Foo{};'});
      let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
        expression: 'Foo.prototype'
      });
      let fooConstructorId = objectId;
  
      InspectorTest.log('Declare class Boo extends Foo & store its constructor.');
      Protocol.Runtime.evaluate({expression: 'class Boo extends Foo{};'});
      ({result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
        expression: 'Boo.prototype'
      }));
      let booConstructorId = objectId;
  
      await queryObjects(session, fooConstructorId, 'Foo');
      await queryObjects(session, booConstructorId, 'Boo');
  
      InspectorTest.log('Create object with class Foo');
      Protocol.Runtime.evaluate({expression: 'new Foo()'});
      await queryObjects(session, fooConstructorId, 'Foo');
  
      InspectorTest.log('Create object with class Boo');
      Protocol.Runtime.evaluate({expression: 'new Boo()'});
      await queryObjects(session, fooConstructorId, 'Foo');
      await queryObjects(session, booConstructorId, 'Boo');
  
      session.disconnect();
    },
  
    async function testNewFunction() {
      let contextGroup = new InspectorTest.ContextGroup();
      let session = contextGroup.connect();
      let Protocol = session.Protocol;
  
      InspectorTest.log('Declare Foo & store it.');
      Protocol.Runtime.evaluate({expression: 'function Foo(){}'});
      let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
        expression: 'Foo.prototype'
      });
  
      for (let i = 0; i < 2; ++i) {
        InspectorTest.log('Create object using Foo.');
        Protocol.Runtime.evaluate({expression: 'new Foo()'});
        await queryObjects(session, objectId, 'Foo');
      }
      session.disconnect();
    },
  
    async function testNonInspectable() {
      let contextGroup = new InspectorTest.ContextGroup();
      let session = contextGroup.connect();
      let Protocol = session.Protocol;
  
      InspectorTest.log('Declare Foo & store it.');
      Protocol.Runtime.evaluate({expression: 'function Foo(){}'});
      let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
        expression: 'Foo.prototype'
      });
  
      InspectorTest.log('Create object using Foo.');
      Protocol.Runtime.evaluate({expression: 'a = new Foo()'});
      await queryObjects(session, objectId, 'Foo');
      InspectorTest.log('Mark object as not inspectable.')
      Protocol.Runtime.evaluate({expression: 'inspector.markObjectAsNotInspectable(a)'});
      await queryObjects(session, objectId, 'Foo');
      session.disconnect();
    },
  
    async function testObjectCreate() {
      let contextGroup = new InspectorTest.ContextGroup();
      let session = contextGroup.connect();
      let Protocol = session.Protocol;
  
      InspectorTest.log('Declare Object p & store it.');
      let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
        expression: 'p = {a:1}'
      });
      for (let i = 0; i < 2; ++i) {
        InspectorTest.log('Create object using Object.create(p).');
        Protocol.Runtime.evaluate({expression: 'Object.create(p)'});
        await queryObjects(session, objectId, 'p');
      }
      session.disconnect();
    },
  
    async function testQueryObjectsWithFeedbackVector() {
      let contextGroup = new InspectorTest.ContextGroup();
      let session = contextGroup.connect();
      let Protocol = session.Protocol;
  
      let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
        expression: 'Object.prototype',
      });
      let countBefore = await countObjects(session, objectId);
      await Protocol.Runtime.evaluate({
        returnByValue: true,
        expression: `
          global.dummyFunction = () => {
            [42];
            {foo: 'bar'};
            [1,2,3];
          }
          %EnsureFeedbackVectorForFunction(dummyFunction);
          dummyFunction();
        `
      });
      let countAfter = await countObjects(session, objectId);
      // Difference should be 1 since |dummyFunction| is retained.
      InspectorTest.log('Before/After difference: ' + (countAfter - countBefore));
      session.disconnect();
    },
  
    async function testWithObjectGroup() {
      let contextGroup = new InspectorTest.ContextGroup();
      let session = contextGroup.connect();
      let Protocol = session.Protocol;
      let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
        expression: 'Array.prototype'
      });
  
      let initialArrayCount;
      const N = 3;
      InspectorTest.log(`Query for Array.prototype ${N} times`);
      for (let i = 0; i < N; ++i) {
        const {result:{objects}} = await Protocol.Runtime.queryObjects({
          prototypeObjectId: objectId,
          objectGroup: 'console'
        });
        logCountSinceInitial(objects.description);
      }
  
      await Protocol.Runtime.releaseObjectGroup({objectGroup: 'console'});
      InspectorTest.log('\nReleased object group.');
  
      const {result:{objects}} = await Protocol.Runtime.queryObjects({
        prototypeObjectId: objectId,
        objectGroup: 'console'
      });
      logCountSinceInitial(objects.description);
      session.disconnect();
  
      function logCountSinceInitial(description) {
        const count = parseInt(/Array\((\d+)\)/.exec(description)[1]);
        if (typeof initialArrayCount === 'undefined')
          initialArrayCount = count;
        InspectorTest.logMessage(`Results since initial: ${count - initialArrayCount}`);
      }
    },
  ]);
  
  const constructorsNameFunction = `
  function() {
    return this.map(o => o.constructor.name + ',' + typeof o).sort();
  }`;
  
  async function queryObjects(sesion, prototypeObjectId, name) {
    let {result:{objects}} = await sesion.Protocol.Runtime.queryObjects({
      prototypeObjectId
    });
    InspectorTest.log(`Query objects with ${name} prototype.`);
    let {result:{result:{value}}} = await sesion.Protocol.Runtime.callFunctionOn({
      objectId: objects.objectId,
      functionDeclaration: constructorsNameFunction,
      returnByValue: true
    });
    InspectorTest.log('Dump each object constructor name.');
    InspectorTest.logMessage(value);
  }
  
  async function countObjects(session, prototypeObjectId) {
    let {result:{objects}} = await session.Protocol.Runtime.queryObjects({
      prototypeObjectId
    });
    let {result:{result:{value}}} = await session.Protocol.Runtime.callFunctionOn({
      objectId: objects.objectId,
      functionDeclaration: `function() { return this.length; }`,
      returnByValue: true
    });
    await session.Protocol.Runtime.releaseObject({
      objectId: objects.objectId,
    });
    return value;
  }
  