// Copyright 2023 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 * as Trace from '../../models/trace/trace.js';
import * as TraceBounds from '../../services/trace_bounds/trace_bounds.js';
import * as TimelineComponents from './components/components.js';
function nestedBreadcrumbs() {
    const initialTraceWindow = {
        min: Trace.Types.Timing.Micro(1000),
        max: Trace.Types.Timing.Micro(10000),
        range: Trace.Types.Timing.Micro(9000),
    };
    const traceWindow1 = {
        min: Trace.Types.Timing.Micro(3000),
        max: Trace.Types.Timing.Micro(9000),
        range: Trace.Types.Timing.Micro(6000),
    };
    const traceWindow2 = {
        min: Trace.Types.Timing.Micro(4000),
        max: Trace.Types.Timing.Micro(6000),
        range: Trace.Types.Timing.Micro(2000),
    };
    const breadcrumb2 = {
        window: traceWindow2,
        child: null,
    };
    const breadcrumb1 = {
        window: traceWindow1,
        child: breadcrumb2,
    };
    const initialBreadcrumb = {
        window: initialTraceWindow,
        child: breadcrumb1,
    };
    return {
        initialBreadcrumb,
        breadcrumb1,
        breadcrumb2,
    };
}
describe('Timeline breadcrumbs', () => {
    it('can create breadcrumbs', () => {
        const { initialBreadcrumb, breadcrumb1, breadcrumb2 } = nestedBreadcrumbs();
        TraceBounds.TraceBounds.BoundsManager.instance({ forceNew: true }).resetWithNewBounds(initialBreadcrumb.window);
        const crumbs = new TimelineComponents.Breadcrumbs.Breadcrumbs(initialBreadcrumb.window);
        crumbs.add(breadcrumb1.window);
        crumbs.add(breadcrumb2.window);
        assert.deepEqual(TimelineComponents.Breadcrumbs.flattenBreadcrumbs(initialBreadcrumb), [initialBreadcrumb, breadcrumb1, breadcrumb2]);
        assert.deepEqual(crumbs.activeBreadcrumb, breadcrumb2);
    });
    it('can activate breadcrumbs', () => {
        const { initialBreadcrumb, breadcrumb1, breadcrumb2 } = nestedBreadcrumbs();
        TraceBounds.TraceBounds.BoundsManager.instance({ forceNew: true }).resetWithNewBounds(initialBreadcrumb.window);
        const crumbs = new TimelineComponents.Breadcrumbs.Breadcrumbs(initialBreadcrumb.window);
        crumbs.add(breadcrumb1.window);
        crumbs.add(breadcrumb2.window);
        // Last added breadcrumb should be active
        assert.deepEqual(crumbs.activeBreadcrumb, breadcrumb2);
        // Make sure breadcrumb 1 can be actived
        crumbs.setActiveBreadcrumb(breadcrumb1, {
            removeChildBreadcrumbs: false,
            updateVisibleWindow: true,
        });
        assert.deepEqual(crumbs.activeBreadcrumb, breadcrumb1);
        // Make sure initial breadcrumb can be actived
        crumbs.setActiveBreadcrumb(initialBreadcrumb, {
            removeChildBreadcrumbs: false,
            updateVisibleWindow: true,
        });
        assert.deepEqual(crumbs.activeBreadcrumb, initialBreadcrumb);
        // No breadcrumb were removed
        assert.deepEqual(TimelineComponents.Breadcrumbs.flattenBreadcrumbs(initialBreadcrumb), [initialBreadcrumb, breadcrumb1, breadcrumb2]);
    });
    it('can overwrite child breadcrumbs when a new one is added', () => {
        const { initialBreadcrumb, breadcrumb1, breadcrumb2 } = nestedBreadcrumbs();
        TraceBounds.TraceBounds.BoundsManager.instance({ forceNew: true }).resetWithNewBounds(initialBreadcrumb.window);
        const crumbs = new TimelineComponents.Breadcrumbs.Breadcrumbs(initialBreadcrumb.window);
        crumbs.add(breadcrumb1.window);
        crumbs.add(breadcrumb2.window);
        // Last added breadcrumb should be active
        assert.deepEqual(crumbs.activeBreadcrumb, breadcrumb2);
        // Currently, breadcrumbs structure is:
        // initialBreadcrumb -> breadcrumb1 -> breadcrumb2(activated)
        assert.deepEqual(TimelineComponents.Breadcrumbs.flattenBreadcrumbs(initialBreadcrumb), [initialBreadcrumb, breadcrumb1, breadcrumb2]);
        // In this test we want to check if the children of the activated breadcrumb will be overwrritten if a new one is added
        // Make the initial breadcrumb active:
        // initialBreadcrumb(activated) -> breadcrumb1 -> breadcrumb2
        crumbs.setActiveBreadcrumb(initialBreadcrumb, {
            removeChildBreadcrumbs: false,
            updateVisibleWindow: true,
        });
        assert.deepEqual(crumbs.activeBreadcrumb, initialBreadcrumb);
        // Add a new breadcrumb
        const traceWindow4 = {
            min: Trace.Types.Timing.Micro(2000),
            max: Trace.Types.Timing.Micro(5000),
            range: Trace.Types.Timing.Micro(3000),
        };
        const breadcrumb4 = {
            window: traceWindow4,
            child: null,
        };
        crumbs.add(traceWindow4);
        // Breadcrumbs should look like this:
        // initialBreadcrumb -> breadcrumb4
        assert.deepEqual(TimelineComponents.Breadcrumbs.flattenBreadcrumbs(initialBreadcrumb), [initialBreadcrumb, breadcrumb4]);
        assert.deepEqual(crumbs.activeBreadcrumb, breadcrumb4);
    });
    it('can remove breadcrumbs', () => {
        const { initialBreadcrumb, breadcrumb1, breadcrumb2 } = nestedBreadcrumbs();
        TraceBounds.TraceBounds.BoundsManager.instance({ forceNew: true }).resetWithNewBounds(initialBreadcrumb.window);
        const crumbs = new TimelineComponents.Breadcrumbs.Breadcrumbs(initialBreadcrumb.window);
        crumbs.add(breadcrumb1.window);
        crumbs.add(breadcrumb2.window);
        assert.deepEqual(TimelineComponents.Breadcrumbs.flattenBreadcrumbs(initialBreadcrumb), [initialBreadcrumb, breadcrumb1, breadcrumb2]);
        assert.deepEqual(crumbs.activeBreadcrumb, breadcrumb2);
        crumbs.setActiveBreadcrumb(breadcrumb1, {
            removeChildBreadcrumbs: true,
            updateVisibleWindow: true,
        });
        assert.deepEqual(TimelineComponents.Breadcrumbs.flattenBreadcrumbs(initialBreadcrumb), [initialBreadcrumb, breadcrumb1]);
        assert.deepEqual(crumbs.activeBreadcrumb, breadcrumb1);
    });
    it('can not create a breadcrumb equal to the parent breadcrumb', () => {
        const { initialBreadcrumb } = nestedBreadcrumbs();
        assert.throws(() => {
            TraceBounds.TraceBounds.BoundsManager.instance({ forceNew: true }).resetWithNewBounds(initialBreadcrumb.window);
            const crumbs = new TimelineComponents.Breadcrumbs.Breadcrumbs(initialBreadcrumb.window);
            const equalTraceWindow = {
                min: initialBreadcrumb.window.min,
                max: initialBreadcrumb.window.max,
                range: initialBreadcrumb.window.range,
            };
            crumbs.add(equalTraceWindow);
        }, 'Can not add a breadcrumb that is equal to or is outside of the parent breadcrumb TimeWindow');
    });
    it('can create breadcrumbs with equal start or end as the parent breadcrumb', () => {
        const initialTraceWindow = {
            min: Trace.Types.Timing.Micro(1000),
            max: Trace.Types.Timing.Micro(10000),
            range: Trace.Types.Timing.Micro(9000),
        };
        TraceBounds.TraceBounds.BoundsManager.instance({ forceNew: true }).resetWithNewBounds(initialTraceWindow);
        const crumbs = new TimelineComponents.Breadcrumbs.Breadcrumbs(initialTraceWindow);
        const traceWindow1 = {
            min: Trace.Types.Timing.Micro(1000),
            max: Trace.Types.Timing.Micro(9000),
            range: Trace.Types.Timing.Micro(8000),
        };
        const traceWindow2 = {
            min: Trace.Types.Timing.Micro(3000),
            max: Trace.Types.Timing.Micro(9000),
            range: Trace.Types.Timing.Micro(6000),
        };
        crumbs.add(traceWindow1);
        crumbs.add(traceWindow2);
        const breadcrumb2 = {
            window: traceWindow2,
            child: null,
        };
        const breadcrumb1 = {
            window: traceWindow1,
            child: breadcrumb2,
        };
        const initialBreadcrumb = {
            window: initialTraceWindow,
            child: breadcrumb1,
        };
        assert.deepEqual(TimelineComponents.Breadcrumbs.flattenBreadcrumbs(initialBreadcrumb), [initialBreadcrumb, breadcrumb1, breadcrumb2]);
        assert.deepEqual(crumbs.activeBreadcrumb, breadcrumb2);
    });
    it('correctly sets the last breadrumb and trace bound window when a new initial breadcrumb is provided', () => {
        const { initialBreadcrumb, breadcrumb1, breadcrumb2 } = nestedBreadcrumbs();
        TraceBounds.TraceBounds.BoundsManager.instance({ forceNew: true }).resetWithNewBounds(initialBreadcrumb.window);
        const crumbs = new TimelineComponents.Breadcrumbs.Breadcrumbs(initialBreadcrumb.window);
        crumbs.setInitialBreadcrumbFromLoadedModifications(initialBreadcrumb);
        assert.deepEqual(TimelineComponents.Breadcrumbs.flattenBreadcrumbs(initialBreadcrumb), [initialBreadcrumb, breadcrumb1, breadcrumb2]);
        assert.deepEqual(crumbs.activeBreadcrumb, breadcrumb2);
        // Make sure the trace bounds were correctly set to the last breadcrumb bounds
        assert.deepEqual(TraceBounds.TraceBounds.BoundsManager.instance().state()?.micro.minimapTraceBounds, breadcrumb2.window);
        // Make sure the TimelineVisibleWindow was correctly set to the last breadcrumb bounds
        assert.deepEqual(TraceBounds.TraceBounds.BoundsManager.instance().state()?.micro.minimapTraceBounds, breadcrumb2.window);
    });
    it('it will not update the trace window when activating a breadcrumb if the option is set to false', () => {
        const { initialBreadcrumb, breadcrumb1, breadcrumb2 } = nestedBreadcrumbs();
        TraceBounds.TraceBounds.BoundsManager.instance({ forceNew: true }).resetWithNewBounds(initialBreadcrumb.window);
        const crumbs = new TimelineComponents.Breadcrumbs.Breadcrumbs(initialBreadcrumb.window);
        crumbs.setInitialBreadcrumbFromLoadedModifications(initialBreadcrumb);
        // Make sure the trace bounds were correctly set to the last breadcrumb bounds
        assert.deepEqual(TraceBounds.TraceBounds.BoundsManager.instance().state()?.micro.minimapTraceBounds, breadcrumb2.window);
        // Now activate breadcrumb1, but tell it not to update the bounds
        crumbs.setActiveBreadcrumb(breadcrumb1, { removeChildBreadcrumbs: false, updateVisibleWindow: false });
        // The visible window is still breadcrumb2.
        assert.deepEqual(TraceBounds.TraceBounds.BoundsManager.instance().state()?.micro.timelineTraceWindow, breadcrumb2.window);
        // Now activate breadcrumb1, but ask it to update the bounds this time
        crumbs.setActiveBreadcrumb(breadcrumb1, { removeChildBreadcrumbs: false, updateVisibleWindow: true });
        // Now the window has changed.
        assert.deepEqual(TraceBounds.TraceBounds.BoundsManager.instance().state()?.micro.timelineTraceWindow, breadcrumb1.window);
    });
});
//# sourceMappingURL=Breadcrumbs.test.js.map