// Copyright 2026 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 { describeWithEnvironment } from '../../testing/EnvironmentHelpers.js';
import * as AiAssistance from './ai_assistance.js';
describeWithEnvironment('AiOrigins', () => {
    describe('isOpaqueOrigin', () => {
        it('identifies opaque origins', () => {
            assert.isTrue(AiAssistance.AiOrigins.isOpaqueOrigin('null'));
            assert.isTrue(AiAssistance.AiOrigins.isOpaqueOrigin('data:'));
            assert.isTrue(AiAssistance.AiOrigins.isOpaqueOrigin('about://'));
            assert.isTrue(AiAssistance.AiOrigins.isOpaqueOrigin('about:srcdoc'));
            assert.isTrue(AiAssistance.AiOrigins.isOpaqueOrigin('detached'));
            assert.isTrue(AiAssistance.AiOrigins.isOpaqueOrigin('detached:123'));
            assert.isFalse(AiAssistance.AiOrigins.isOpaqueOrigin('https://google.com'));
        });
    });
    describe('extractContextOrigin', () => {
        it('extracts origin from URLs', () => {
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('https://google.com/path'), 'https://google.com');
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('null'), 'null');
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('data:'), 'data:');
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('about:blank'), 'about:blank');
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('detached'), 'detached');
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('trace-1-10'), 'trace-1-10');
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('invalid-url'), '');
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('blob:null/123'), 'null');
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('blob:https://google.com/123'), 'https://google.com');
        });
        it('extracts origin from URLs with long paths, queries and hashes', () => {
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('https://google.com/some/long/path/to/file.html?query=1&other=2#hash'), 'https://google.com');
        });
        it('extracts origin from URLs with subdomains', () => {
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('https://subdomain.google.com/path'), 'https://subdomain.google.com');
        });
        it('returns null (opaque) for malformed file:// URLs', () => {
            const malformedFile = AiAssistance.AiOrigins.extractContextOrigin('file://invalid path with spaces');
            assert.strictEqual(malformedFile, 'null');
            assert.isTrue(AiAssistance.AiOrigins.isOpaqueOrigin(malformedFile));
        });
        it('handles uppercase schemes for file and blob URLs', () => {
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('FILE:///path/to/file.js'), 'file:///path/to/file.js');
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('BLOB:null/123'), 'null');
        });
        it('preserves host in file:// URLs (UNC paths)', () => {
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('file://servera/path/to/file.js'), 'file://servera/path/to/file.js');
            assert.strictEqual(AiAssistance.AiOrigins.extractContextOrigin('file:///path/to/file.js'), 'file:///path/to/file.js');
        });
    });
    describe('areOriginsEquivalent', () => {
        it('returns true for identical non-opaque origins', () => {
            assert.isTrue(AiAssistance.AiOrigins.areOriginsEquivalent('https://a.com', 'https://a.com'));
        });
        it('returns false for different non-opaque origins', () => {
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent('https://a.com', 'https://b.com'));
        });
        it('never says opaque origins are equivalent even if they are the same string', () => {
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent('data:', 'data:'));
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent('null', 'null'));
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent('about:blank', 'about:blank'));
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent('detached', 'detached'));
        });
        it('returns false if one origin is opaque', () => {
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent('https://a.com', 'null'));
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent('null', 'https://a.com'));
        });
        it('handles blob:null URLs correctly', () => {
            const origin1 = AiAssistance.AiOrigins.extractContextOrigin('blob:null/1');
            const origin2 = AiAssistance.AiOrigins.extractContextOrigin('blob:null/2');
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent(origin1, origin2));
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent(origin1, origin1));
        });
        it('handles blob URLs with valid origins correctly', () => {
            const origin1 = AiAssistance.AiOrigins.extractContextOrigin('blob:https://google.com/1');
            const origin2 = AiAssistance.AiOrigins.extractContextOrigin('blob:https://google.com/2');
            const originDifferent = AiAssistance.AiOrigins.extractContextOrigin('blob:https://example.com/2');
            assert.isTrue(AiAssistance.AiOrigins.areOriginsEquivalent(origin1, origin2));
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent(origin1, originDifferent));
        });
        it('asserts different file paths are not equivalent (fails on current vulnerability)', () => {
            const originA = AiAssistance.AiOrigins.extractContextOrigin('file:///path/to/a.txt');
            const originB = AiAssistance.AiOrigins.extractContextOrigin('file:///path/to/b.txt');
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent(originA, originB), 'Different file paths should not be equivalent');
        });
        it('asserts opaque blob URLs are opaque and not equivalent (fails on current vulnerability)', () => {
            const blobNullOrigin1 = AiAssistance.AiOrigins.extractContextOrigin('blob:null/1');
            const blobNullOrigin2 = AiAssistance.AiOrigins.extractContextOrigin('blob:null/2');
            assert.isTrue(AiAssistance.AiOrigins.isOpaqueOrigin(blobNullOrigin1), 'blob:null should be opaque');
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent(blobNullOrigin1, blobNullOrigin2), 'blob:null origins should not be equivalent');
            const blobAboutBlank = AiAssistance.AiOrigins.extractContextOrigin('blob:about:blank');
            assert.isTrue(AiAssistance.AiOrigins.isOpaqueOrigin(blobAboutBlank), 'blob:about:blank should be opaque');
            const blobData = AiAssistance.AiOrigins.extractContextOrigin('blob:data:text/html,test');
            assert.isTrue(AiAssistance.AiOrigins.isOpaqueOrigin(blobData), 'blob:data should be opaque');
        });
        it('asserts undefined:// and other invalid origins are opaque (fails on current vulnerability)', () => {
            const undefinedOrigin = AiAssistance.AiOrigins.extractContextOrigin('undefined://');
            assert.isTrue(AiAssistance.AiOrigins.isOpaqueOrigin(undefinedOrigin), 'undefined:// should be opaque');
            const emptyOrigin = AiAssistance.AiOrigins.extractContextOrigin('://');
            assert.isTrue(AiAssistance.AiOrigins.isOpaqueOrigin(emptyOrigin), 'empty scheme should be opaque');
        });
        it('asserts different FILE:// paths are not equivalent', () => {
            const originA = AiAssistance.AiOrigins.extractContextOrigin('FILE:///path/to/a.txt');
            const originB = AiAssistance.AiOrigins.extractContextOrigin('FILE:///path/to/b.txt');
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent(originA, originB), 'Different FILE:// paths should not be equivalent');
        });
        it('asserts file:// URLs with different hosts are not equivalent', () => {
            const originA = AiAssistance.AiOrigins.extractContextOrigin('file://serverA/path/to/file.txt');
            const originB = AiAssistance.AiOrigins.extractContextOrigin('file://serverB/path/to/file.txt');
            assert.isFalse(AiAssistance.AiOrigins.areOriginsEquivalent(originA, originB), 'Different hosts should not be equivalent');
        });
    });
    describe('canResourceContentsBeReadForTrace', () => {
        it('returns true if origins are equivalent', () => {
            assert.isTrue(AiAssistance.AiOrigins.canResourceContentsBeReadForTrace('https://a.com/script.js', 'https://a.com'));
        });
        it('returns false if origins are different', () => {
            assert.isFalse(AiAssistance.AiOrigins.canResourceContentsBeReadForTrace('https://b.com/script.js', 'https://a.com'));
        });
        it('blocks opaque target origins even with matching allowedOrigin', () => {
            assert.isFalse(AiAssistance.AiOrigins.canResourceContentsBeReadForTrace('data:text/javascript,console.log()', 'https://a.com'));
        });
        it('blocks opaque allowedOrigin', () => {
            assert.isFalse(AiAssistance.AiOrigins.canResourceContentsBeReadForTrace('https://a.com/script.js', 'data:'));
            assert.isFalse(AiAssistance.AiOrigins.canResourceContentsBeReadForTrace('https://a.com/script.js', 'null'));
        });
        it('blocks local files for fresh recordings even if same-origin', () => {
            assert.isFalse(AiAssistance.AiOrigins.canResourceContentsBeReadForTrace('file:///etc/passwd', 'file://'));
            assert.isFalse(AiAssistance.AiOrigins.canResourceContentsBeReadForTrace('file:///tmp/index.html', 'file://'));
        });
    });
});
//# sourceMappingURL=AiOrigins.test.js.map