// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { assert } from 'chai';
import sinon from 'sinon';
import * as SDK from '../../core/sdk/sdk.js';
import * as Bindings from '../../models/bindings/bindings.js';
import * as Workspace from '../../models/workspace/workspace.js';
import { createTarget } from '../../testing/EnvironmentHelpers.js';
import { describeWithMockConnection } from '../../testing/MockConnection.js';
import * as SourceMapScopes from './source_map_scopes.js';
describeWithMockConnection('ScopeChainModel', () => {
    let clock;
    let stubPluginManager;
    beforeEach(() => {
        clock = sinon.useFakeTimers();
        const workspace = Workspace.Workspace.WorkspaceImpl.instance();
        const targetManager = SDK.TargetManager.TargetManager.instance();
        const resourceMapping = new Bindings.ResourceMapping.ResourceMapping(targetManager, workspace);
        const ignoreListManager = Workspace.IgnoreListManager.IgnoreListManager.instance({ forceNew: true });
        const debuggerWorkspaceBinding = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance({
            forceNew: true,
            resourceMapping,
            targetManager,
            ignoreListManager,
            workspace,
        });
        stubPluginManager = sinon.createStubInstance(Bindings.DebuggerLanguagePlugins.DebuggerLanguagePluginManager, { resolveScopeChain: Promise.resolve(null) });
        sinon.stub(debuggerWorkspaceBinding, 'pluginManager').value(stubPluginManager);
    });
    afterEach(() => {
        clock.restore();
    });
    it('emits an event after it was constructed with the scope chain', async () => {
        const target = createTarget();
        const debuggerModel = target.model(SDK.DebuggerModel.DebuggerModel);
        const fakeFrame = sinon.createStubInstance(SDK.DebuggerModel.CallFrame);
        fakeFrame.debuggerModel = debuggerModel;
        // @ts-expect-error readonly for test.
        fakeFrame.script = sinon.createStubInstance(SDK.Script.Script, { isWasm: false });
        fakeFrame.scopeChain.returns([]);
        const scopeChainModel = new SourceMapScopes.ScopeChainModel.ScopeChainModel(fakeFrame);
        const listenerStub = sinon.stub();
        scopeChainModel.addEventListener("ScopeChainUpdated" /* SourceMapScopes.ScopeChainModel.Events.SCOPE_CHAIN_UPDATED */, listenerStub);
        await clock.tickAsync(10);
        sinon.assert.calledOnce(listenerStub);
    });
    it('does not emit an event after it was disposed even with an update still in-flight', async () => {
        // Stub out the pluginManagers `resolveScopeChain` with a promise that we control.
        const { promise, resolve } = Promise.withResolvers();
        stubPluginManager.resolveScopeChain.returns(promise);
        const target = createTarget();
        const debuggerModel = target.model(SDK.DebuggerModel.DebuggerModel);
        const fakeFrame = sinon.createStubInstance(SDK.DebuggerModel.CallFrame);
        fakeFrame.debuggerModel = debuggerModel;
        // @ts-expect-error readonly for test.
        fakeFrame.script = sinon.createStubInstance(SDK.Script.Script, { isWasm: false });
        fakeFrame.scopeChain.returns([]);
        const scopeChainModel = new SourceMapScopes.ScopeChainModel.ScopeChainModel(fakeFrame);
        const listenerStub = sinon.stub();
        scopeChainModel.addEventListener("ScopeChainUpdated" /* SourceMapScopes.ScopeChainModel.Events.SCOPE_CHAIN_UPDATED */, listenerStub);
        await clock.tickAsync(10);
        sinon.assert.calledOnce(stubPluginManager.resolveScopeChain);
        assert.isFalse(listenerStub.calledOnce);
        scopeChainModel.dispose();
        resolve(null);
        await clock.tickAsync(10);
        assert.isFalse(listenerStub.calledOnce);
    });
});
//# sourceMappingURL=ScopeChainModel.test.js.map