/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import { marked } from 'marked';
import { processImports, validateImportPath } from './memoryImportProcessor.js';
import { debugLogger } from './debugLogger.js';
// Helper function to create platform-agnostic test paths
function testPath(...segments) {
    // Start with the first segment as is (might be an absolute path on Windows)
    let result = segments[0];
    // Join remaining segments with the platform-specific separator
    for (let i = 1; i < segments.length; i++) {
        if (segments[i].startsWith('/') || segments[i].startsWith('\\')) {
            // If segment starts with a separator, remove the trailing separator from the result
            result = path.normalize(result.replace(/[\\/]+$/, '') + segments[i]);
        }
        else {
            // Otherwise join with the platform separator
            result = path.join(result, segments[i]);
        }
    }
    return path.normalize(result);
}
vi.mock('fs/promises');
const mockedFs = vi.mocked(fs);
// Helper functions using marked for parsing and validation
const parseMarkdown = (content) => marked.lexer(content);
const findMarkdownComments = (content) => {
    const tokens = parseMarkdown(content);
    const comments = [];
    function walkTokens(tokenList) {
        for (const token of tokenList) {
            const t = token;
            if (t.type === 'html' && t.raw.includes('<!--')) {
                comments.push(t.raw.trim());
            }
            if (t.tokens) {
                walkTokens(t.tokens);
            }
        }
    }
    walkTokens(tokens);
    return comments;
};
const findCodeBlocks = (content) => {
    const tokens = parseMarkdown(content);
    const codeBlocks = [];
    function walkTokens(tokenList) {
        for (const token of tokenList) {
            const t = token;
            if (t.type === 'code') {
                codeBlocks.push({
                    type: 'code_block',
                    content: t.text,
                });
            }
            else if (t.type === 'codespan') {
                codeBlocks.push({
                    type: 'inline_code',
                    content: t.text,
                });
            }
            if (t.tokens) {
                walkTokens(t.tokens);
            }
        }
    }
    walkTokens(tokens);
    return codeBlocks;
};
describe('memoryImportProcessor', () => {
    beforeEach(() => {
        vi.clearAllMocks();
        // Mock console methods
        vi.spyOn(debugLogger, 'warn').mockImplementation(() => { });
        vi.spyOn(debugLogger, 'error').mockImplementation(() => { });
        vi.spyOn(debugLogger, 'debug').mockImplementation(() => { });
    });
    afterEach(() => {
        vi.resetAllMocks();
    });
    describe('processImports', () => {
        it('should process basic md file imports', async () => {
            const content = 'Some content @./test.md more content';
            const basePath = testPath('test', 'path');
            const importedContent = '# Imported Content\nThis is imported.';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile.mockResolvedValue(importedContent);
            const result = await processImports(content, basePath, true);
            // Use marked to find HTML comments (import markers)
            const comments = findMarkdownComments(result.content);
            expect(comments.some((c) => c.includes('Imported from: ./test.md'))).toBe(true);
            expect(comments.some((c) => c.includes('End of import from: ./test.md'))).toBe(true);
            // Verify the imported content is present
            expect(result.content).toContain(importedContent);
            // Verify the markdown structure is valid
            const tokens = parseMarkdown(result.content);
            expect(tokens).toBeDefined();
            expect(tokens.length).toBeGreaterThan(0);
            expect(mockedFs.readFile).toHaveBeenCalledWith(path.resolve(basePath, './test.md'), 'utf-8');
        });
        it('should import non-md files just like md files', async () => {
            const content = 'Some content @./instructions.txt more content';
            const basePath = testPath('test', 'path');
            const importedContent = '# Instructions\nThis is a text file with markdown.';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile.mockResolvedValue(importedContent);
            const result = await processImports(content, basePath, true);
            // Use marked to find import comments
            const comments = findMarkdownComments(result.content);
            expect(comments.some((c) => c.includes('Imported from: ./instructions.txt'))).toBe(true);
            expect(comments.some((c) => c.includes('End of import from: ./instructions.txt'))).toBe(true);
            // Use marked to parse and validate the imported content structure
            const tokens = parseMarkdown(result.content);
            // Find headers in the parsed content
            const headers = tokens.filter((token) => token.type === 'heading');
            expect(headers.some((h) => h.text === 'Instructions')).toBe(true);
            // Verify the imported content is present
            expect(result.content).toContain(importedContent);
            expect(debugLogger.warn).not.toHaveBeenCalled();
            expect(mockedFs.readFile).toHaveBeenCalledWith(path.resolve(basePath, './instructions.txt'), 'utf-8');
        });
        it('should handle circular imports', async () => {
            const content = 'Content @./circular.md more content';
            const basePath = testPath('test', 'path');
            const circularContent = 'Circular @./main.md content';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile.mockResolvedValue(circularContent);
            // Set up the import state to simulate we're already processing main.md
            const importState = {
                processedFiles: new Set(),
                maxDepth: 10,
                currentDepth: 0,
                currentFile: testPath('test', 'path', 'main.md'), // Simulate we're processing main.md
            };
            const result = await processImports(content, basePath, true, importState);
            // The circular import should be detected when processing the nested import
            expect(result.content).toContain('<!-- File already processed: ./main.md -->');
        });
        it('should handle file not found errors', async () => {
            const content = 'Content @./nonexistent.md more content';
            const basePath = testPath('test', 'path');
            mockedFs.access.mockRejectedValue(new Error('File not found'));
            const result = await processImports(content, basePath, true);
            expect(result.content).toContain('<!-- Import failed: ./nonexistent.md - File not found -->');
            expect(debugLogger.error).toHaveBeenCalledWith('[ERROR] [ImportProcessor]', 'Failed to import ./nonexistent.md: File not found');
        });
        it('should respect max depth limit', async () => {
            const content = 'Content @./deep.md more content';
            const basePath = testPath('test', 'path');
            const deepContent = 'Deep @./deeper.md content';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile.mockResolvedValue(deepContent);
            const importState = {
                processedFiles: new Set(),
                maxDepth: 1,
                currentDepth: 1,
            };
            const result = await processImports(content, basePath, true, importState);
            expect(debugLogger.warn).toHaveBeenCalledWith('[WARN] [ImportProcessor]', 'Maximum import depth (1) reached. Stopping import processing.');
            expect(result.content).toBe(content);
        });
        it('should handle nested imports recursively', async () => {
            const content = 'Main @./nested.md content';
            const basePath = testPath('test', 'path');
            const nestedContent = 'Nested @./inner.md content';
            const innerContent = 'Inner content';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile
                .mockResolvedValueOnce(nestedContent)
                .mockResolvedValueOnce(innerContent);
            const result = await processImports(content, basePath, true);
            expect(result.content).toContain('<!-- Imported from: ./nested.md -->');
            expect(result.content).toContain('<!-- Imported from: ./inner.md -->');
            expect(result.content).toContain(innerContent);
        });
        it('should handle absolute paths in imports', async () => {
            const content = 'Content @/absolute/path/file.md more content';
            const basePath = testPath('test', 'path');
            const importedContent = 'Absolute path content';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile.mockResolvedValue(importedContent);
            const result = await processImports(content, basePath, true);
            expect(result.content).toContain('<!-- Import failed: /absolute/path/file.md - Path traversal attempt -->');
        });
        it('should handle multiple imports in same content', async () => {
            const content = 'Start @./first.md middle @./second.md end';
            const basePath = testPath('test', 'path');
            const firstContent = 'First content';
            const secondContent = 'Second content';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile
                .mockResolvedValueOnce(firstContent)
                .mockResolvedValueOnce(secondContent);
            const result = await processImports(content, basePath, true);
            expect(result.content).toContain('<!-- Imported from: ./first.md -->');
            expect(result.content).toContain('<!-- Imported from: ./second.md -->');
            expect(result.content).toContain(firstContent);
            expect(result.content).toContain(secondContent);
        });
        it('should ignore imports inside code blocks', async () => {
            const content = [
                'Normal content @./should-import.md',
                '```',
                'code block with @./should-not-import.md',
                '```',
                'More content @./should-import2.md',
            ].join('\n');
            const projectRoot = testPath('test', 'project');
            const basePath = testPath(projectRoot, 'src');
            const importedContent1 = 'Imported 1';
            const importedContent2 = 'Imported 2';
            // Only the imports outside code blocks should be processed
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile
                .mockResolvedValueOnce(importedContent1)
                .mockResolvedValueOnce(importedContent2);
            const result = await processImports(content, basePath, true, undefined, projectRoot);
            // Use marked to verify imported content is present
            expect(result.content).toContain(importedContent1);
            expect(result.content).toContain(importedContent2);
            // Use marked to find code blocks and verify the import wasn't processed
            const codeBlocks = findCodeBlocks(result.content);
            const hasUnprocessedImport = codeBlocks.some((block) => block.content.includes('@./should-not-import.md'));
            expect(hasUnprocessedImport).toBe(true);
            // Verify no import comment was created for the code block import
            const comments = findMarkdownComments(result.content);
            expect(comments.some((c) => c.includes('should-not-import.md'))).toBe(false);
        });
        it('should ignore imports inside inline code', async () => {
            const content = [
                'Normal content @./should-import.md',
                '`code with import @./should-not-import.md`',
                'More content @./should-import2.md',
            ].join('\n');
            const projectRoot = testPath('test', 'project');
            const basePath = testPath(projectRoot, 'src');
            const importedContent1 = 'Imported 1';
            const importedContent2 = 'Imported 2';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile
                .mockResolvedValueOnce(importedContent1)
                .mockResolvedValueOnce(importedContent2);
            const result = await processImports(content, basePath, true, undefined, projectRoot);
            // Verify imported content is present
            expect(result.content).toContain(importedContent1);
            expect(result.content).toContain(importedContent2);
            // Use marked to find inline code spans
            const codeBlocks = findCodeBlocks(result.content);
            const inlineCodeSpans = codeBlocks.filter((block) => block.type === 'inline_code');
            // Verify the inline code span still contains the unprocessed import
            expect(inlineCodeSpans.some((span) => span.content.includes('@./should-not-import.md'))).toBe(true);
            // Verify no import comments were created for inline code imports
            const comments = findMarkdownComments(result.content);
            expect(comments.some((c) => c.includes('should-not-import.md'))).toBe(false);
        });
        it('should handle nested tokens and non-unique content correctly', async () => {
            // This test verifies the robust findCodeRegions implementation
            // that recursively walks the token tree and handles non-unique content
            const content = [
                'Normal content @./should-import.md',
                'Paragraph with `inline code @./should-not-import.md` and more text.',
                'Another paragraph with the same `inline code @./should-not-import.md` text.',
                'More content @./should-import2.md',
            ].join('\n');
            const projectRoot = testPath('test', 'project');
            const basePath = testPath(projectRoot, 'src');
            const importedContent1 = 'Imported 1';
            const importedContent2 = 'Imported 2';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile
                .mockResolvedValueOnce(importedContent1)
                .mockResolvedValueOnce(importedContent2);
            const result = await processImports(content, basePath, true, undefined, projectRoot);
            // Should process imports outside code regions
            expect(result.content).toContain(importedContent1);
            expect(result.content).toContain(importedContent2);
            // Should preserve imports inside inline code (both occurrences)
            expect(result.content).toContain('`inline code @./should-not-import.md`');
            // Should not have processed the imports inside code regions
            expect(result.content).not.toContain('<!-- Imported from: ./should-not-import.md -->');
        });
        it('should not process imports in repeated inline code blocks', async () => {
            const content = '`@noimport` and `@noimport`';
            const projectRoot = testPath('test', 'project');
            const basePath = testPath(projectRoot, 'src');
            const result = await processImports(content, basePath, true, undefined, projectRoot);
            expect(result.content).toBe(content);
        });
        it('should not import when @ is inside an inline code block', async () => {
            const content = 'We should not ` @import` when the symbol is inside an inline code string.';
            const testRootDir = testPath('test', 'project');
            const result = await processImports(content, testRootDir);
            expect(result.content).toBe(content);
            expect(result.importTree.imports).toBeUndefined();
        });
        it('should allow imports from parent and subdirectories within project root', async () => {
            const content = 'Parent import: @../parent.md Subdir import: @./components/sub.md';
            const projectRoot = testPath('test', 'project');
            const basePath = testPath(projectRoot, 'src');
            const importedParent = 'Parent file content';
            const importedSub = 'Subdir file content';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile
                .mockResolvedValueOnce(importedParent)
                .mockResolvedValueOnce(importedSub);
            const result = await processImports(content, basePath, true, undefined, projectRoot);
            expect(result.content).toContain(importedParent);
            expect(result.content).toContain(importedSub);
        });
        it('should reject imports outside project root', async () => {
            const content = 'Outside import: @../../../etc/passwd';
            const projectRoot = testPath('test', 'project');
            const basePath = testPath(projectRoot, 'src');
            const result = await processImports(content, basePath, true, undefined, projectRoot);
            expect(result.content).toContain('<!-- Import failed: ../../../etc/passwd - Path traversal attempt -->');
        });
        it('should build import tree structure', async () => {
            const content = 'Main content @./nested.md @./simple.md';
            const projectRoot = testPath('test', 'project');
            const basePath = testPath(projectRoot, 'src');
            const nestedContent = 'Nested @./inner.md content';
            const simpleContent = 'Simple content';
            const innerContent = 'Inner content';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile
                .mockResolvedValueOnce(nestedContent)
                .mockResolvedValueOnce(simpleContent)
                .mockResolvedValueOnce(innerContent);
            const result = await processImports(content, basePath, true);
            // Use marked to find and validate import comments
            const comments = findMarkdownComments(result.content);
            const importComments = comments.filter((c) => c.includes('Imported from:'));
            expect(importComments.some((c) => c.includes('./nested.md'))).toBe(true);
            expect(importComments.some((c) => c.includes('./simple.md'))).toBe(true);
            expect(importComments.some((c) => c.includes('./inner.md'))).toBe(true);
            // Use marked to validate the markdown structure is well-formed
            const tokens = parseMarkdown(result.content);
            expect(tokens).toBeDefined();
            expect(tokens.length).toBeGreaterThan(0);
            // Verify the content contains expected text using marked parsing
            const textContent = tokens
                .filter((token) => token.type === 'paragraph')
                .map((token) => token.raw)
                .join(' ');
            expect(textContent).toContain('Main content');
            expect(textContent).toContain('Nested');
            expect(textContent).toContain('Simple content');
            expect(textContent).toContain('Inner content');
            // Verify import tree structure
            expect(result.importTree.path).toBe('unknown'); // No currentFile set in test
            expect(result.importTree.imports).toHaveLength(2);
            // First import: nested.md
            // Check that the paths match using includes to handle potential absolute/relative differences
            const expectedNestedPath = testPath(projectRoot, 'src', 'nested.md');
            expect(result.importTree.imports[0].path).toContain(expectedNestedPath);
            expect(result.importTree.imports[0].imports).toHaveLength(1);
            const expectedInnerPath = testPath(projectRoot, 'src', 'inner.md');
            expect(result.importTree.imports[0].imports[0].path).toContain(expectedInnerPath);
            expect(result.importTree.imports[0].imports[0].imports).toBeUndefined();
            // Second import: simple.md
            const expectedSimplePath = testPath(projectRoot, 'src', 'simple.md');
            expect(result.importTree.imports[1].path).toContain(expectedSimplePath);
            expect(result.importTree.imports[1].imports).toBeUndefined();
        });
        it('should produce flat output in Claude-style with unique files in order', async () => {
            const content = 'Main @./nested.md content @./simple.md';
            const projectRoot = testPath('test', 'project');
            const basePath = testPath(projectRoot, 'src');
            const nestedContent = 'Nested @./inner.md content';
            const simpleContent = 'Simple content';
            const innerContent = 'Inner content';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile
                .mockResolvedValueOnce(nestedContent)
                .mockResolvedValueOnce(simpleContent)
                .mockResolvedValueOnce(innerContent);
            const result = await processImports(content, basePath, true, undefined, projectRoot, 'flat');
            // Use marked to parse the output and validate structure
            const tokens = parseMarkdown(result.content);
            expect(tokens).toBeDefined();
            // Find all file markers using marked parsing
            const fileMarkers = [];
            const endMarkers = [];
            function walkTokens(tokenList) {
                for (const token of tokenList) {
                    const t = token;
                    if (t.type === 'paragraph' && t.raw.includes('--- File:')) {
                        const match = t.raw.match(/--- File: (.+?) ---/);
                        if (match) {
                            // Normalize the path before adding to fileMarkers
                            fileMarkers.push(path.normalize(match[1]));
                        }
                    }
                    if (t.type === 'paragraph' && t.raw.includes('--- End of File:')) {
                        const match = t.raw.match(/--- End of File: (.+?) ---/);
                        if (match) {
                            // Normalize the path before adding to endMarkers
                            endMarkers.push(path.normalize(match[1]));
                        }
                    }
                    if (t.tokens) {
                        walkTokens(t.tokens);
                    }
                }
            }
            walkTokens(tokens);
            // Verify all expected files are present
            const expectedFiles = ['nested.md', 'simple.md', 'inner.md'];
            // Check that each expected file is present in the content
            expectedFiles.forEach((file) => {
                expect(result.content).toContain(file);
            });
            // Verify content is present
            expect(result.content).toContain('Main @./nested.md content @./simple.md');
            expect(result.content).toContain('Nested @./inner.md content');
            expect(result.content).toContain('Simple content');
            expect(result.content).toContain('Inner content');
            // Verify end markers exist
            expect(endMarkers.length).toBeGreaterThan(0);
        });
        it('should not duplicate files in flat output if imported multiple times', async () => {
            const content = 'Main @./dup.md again @./dup.md';
            const projectRoot = testPath('test', 'project');
            const basePath = testPath(projectRoot, 'src');
            const dupContent = 'Duplicated content';
            // Reset mocks
            mockedFs.access.mockReset();
            mockedFs.readFile.mockReset();
            // Set up mocks
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile.mockResolvedValue(dupContent);
            const result = await processImports(content, basePath, true, // followImports
            undefined, // allowedPaths
            projectRoot, 'flat');
            // Verify readFile was called only once for dup.md
            expect(mockedFs.readFile).toHaveBeenCalledTimes(1);
            // Check that the content contains the file content only once
            const contentStr = result.content;
            const firstIndex = contentStr.indexOf('Duplicated content');
            const lastIndex = contentStr.lastIndexOf('Duplicated content');
            expect(firstIndex).toBeGreaterThan(-1); // Content should exist
            expect(firstIndex).toBe(lastIndex); // Should only appear once
        });
        it('should handle nested imports in flat output', async () => {
            const content = 'Root @./a.md';
            const projectRoot = testPath('test', 'project');
            const basePath = testPath(projectRoot, 'src');
            const aContent = 'A @./b.md';
            const bContent = 'B content';
            mockedFs.access.mockResolvedValue(undefined);
            mockedFs.readFile
                .mockResolvedValueOnce(aContent)
                .mockResolvedValueOnce(bContent);
            const result = await processImports(content, basePath, true, undefined, projectRoot, 'flat');
            // Verify all files are present by checking for their basenames
            expect(result.content).toContain('a.md');
            expect(result.content).toContain('b.md');
            // Verify content is in the correct order
            const contentStr = result.content;
            const aIndex = contentStr.indexOf('a.md');
            const bIndex = contentStr.indexOf('b.md');
            const rootIndex = contentStr.indexOf('Root @./a.md');
            expect(rootIndex).toBeLessThan(aIndex);
            expect(aIndex).toBeLessThan(bIndex);
            // Verify content is present
            expect(result.content).toContain('Root @./a.md');
            expect(result.content).toContain('A @./b.md');
            expect(result.content).toContain('B content');
        });
    });
    describe('validateImportPath', () => {
        it('should reject URLs', () => {
            const basePath = testPath('base');
            const allowedPath = testPath('allowed');
            expect(validateImportPath('https://example.com/file.md', basePath, [
                allowedPath,
            ])).toBe(false);
            expect(validateImportPath('http://example.com/file.md', basePath, [
                allowedPath,
            ])).toBe(false);
            expect(validateImportPath('file:///path/to/file.md', basePath, [allowedPath])).toBe(false);
        });
        it('should allow paths within allowed directories', () => {
            const basePath = path.resolve(testPath('base'));
            const allowedPath = path.resolve(testPath('allowed'));
            // Test relative paths - resolve them against basePath
            const relativePath = './file.md';
            path.resolve(basePath, relativePath);
            expect(validateImportPath(relativePath, basePath, [basePath])).toBe(true);
            // Test parent directory access (should be allowed if parent is in allowed paths)
            const parentPath = path.dirname(basePath);
            if (parentPath !== basePath) {
                // Only test if parent is different
                const parentRelativePath = '../file.md';
                path.resolve(basePath, parentRelativePath);
                expect(validateImportPath(parentRelativePath, basePath, [parentPath])).toBe(true);
                path.resolve(basePath, 'sub');
                const resultSub = validateImportPath('sub', basePath, [basePath]);
                expect(resultSub).toBe(true);
            }
            // Test allowed path access - use a file within the allowed directory
            const allowedSubPath = 'nested';
            const allowedFilePath = path.join(allowedPath, allowedSubPath, 'file.md');
            expect(validateImportPath(allowedFilePath, basePath, [allowedPath])).toBe(true);
        });
        it('should reject paths outside allowed directories', () => {
            const basePath = path.resolve(testPath('base'));
            const allowedPath = path.resolve(testPath('allowed'));
            const forbiddenPath = path.resolve(testPath('forbidden'));
            // Forbidden path should be blocked
            expect(validateImportPath(forbiddenPath, basePath, [allowedPath])).toBe(false);
            // Relative path to forbidden directory should be blocked
            const relativeToForbidden = path.relative(basePath, path.join(forbiddenPath, 'file.md'));
            expect(validateImportPath(relativeToForbidden, basePath, [allowedPath])).toBe(false);
            // Path that tries to escape the base directory should be blocked
            const escapingPath = path.join('..', '..', 'sensitive', 'file.md');
            expect(validateImportPath(escapingPath, basePath, [basePath])).toBe(false);
        });
        it('should handle multiple allowed directories', () => {
            const basePath = path.resolve(testPath('base'));
            const allowed1 = path.resolve(testPath('allowed1'));
            const allowed2 = path.resolve(testPath('allowed2'));
            // File not in any allowed path
            const otherPath = path.resolve(testPath('other', 'file.md'));
            expect(validateImportPath(otherPath, basePath, [allowed1, allowed2])).toBe(false);
            // File in first allowed path
            const file1 = path.join(allowed1, 'nested', 'file.md');
            expect(validateImportPath(file1, basePath, [allowed1, allowed2])).toBe(true);
            // File in second allowed path
            const file2 = path.join(allowed2, 'nested', 'file.md');
            expect(validateImportPath(file2, basePath, [allowed1, allowed2])).toBe(true);
            // Test with relative path to allowed directory
            const relativeToAllowed1 = path.relative(basePath, file1);
            expect(validateImportPath(relativeToAllowed1, basePath, [allowed1, allowed2])).toBe(true);
        });
        it('should handle relative paths correctly', () => {
            const basePath = path.resolve(testPath('base'));
            const parentPath = path.resolve(testPath('parent'));
            // Current directory file access
            expect(validateImportPath('file.md', basePath, [basePath])).toBe(true);
            // Explicit current directory file access
            expect(validateImportPath('./file.md', basePath, [basePath])).toBe(true);
            // Parent directory access - should be blocked unless parent is in allowed paths
            const parentFile = path.join(parentPath, 'file.md');
            const relativeToParent = path.relative(basePath, parentFile);
            expect(validateImportPath(relativeToParent, basePath, [basePath])).toBe(false);
            // Parent directory access when parent is in allowed paths
            expect(validateImportPath(relativeToParent, basePath, [basePath, parentPath])).toBe(true);
            // Nested relative path
            const nestedPath = path.join('nested', 'sub', 'file.md');
            expect(validateImportPath(nestedPath, basePath, [basePath])).toBe(true);
        });
        it('should handle absolute paths correctly', () => {
            const basePath = path.resolve(testPath('base'));
            const allowedPath = path.resolve(testPath('allowed'));
            const forbiddenPath = path.resolve(testPath('forbidden'));
            // Allowed path should work - file directly in allowed directory
            const allowedFilePath = path.join(allowedPath, 'file.md');
            expect(validateImportPath(allowedFilePath, basePath, [allowedPath])).toBe(true);
            // Allowed path should work - file in subdirectory of allowed directory
            const allowedNestedPath = path.join(allowedPath, 'nested', 'file.md');
            expect(validateImportPath(allowedNestedPath, basePath, [allowedPath])).toBe(true);
            // Forbidden path should be blocked
            const forbiddenFilePath = path.join(forbiddenPath, 'file.md');
            expect(validateImportPath(forbiddenFilePath, basePath, [allowedPath])).toBe(false);
            // Relative path to allowed directory should work
            const relativeToAllowed = path.relative(basePath, allowedFilePath);
            expect(validateImportPath(relativeToAllowed, basePath, [allowedPath])).toBe(true);
            // Path that resolves to the same file but via different relative segments
            const dotPath = path.join('.', '..', path.basename(allowedPath), 'file.md');
            expect(validateImportPath(dotPath, basePath, [allowedPath])).toBe(true);
        });
    });
});
//# sourceMappingURL=memoryImportProcessor.test.js.map