mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 18:10:18 +05:30
Normalize line endings and remove rpm from Linux build targets
- Normalize line endings across all files - Remove rpm target from Linux build (requires rpmbuild) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+121
-121
@@ -1,121 +1,121 @@
|
||||
/**
|
||||
* Tests for Preload Script Security
|
||||
* Verifies that the IPC bridge is properly configured
|
||||
*/
|
||||
|
||||
describe('Preload Security', () => {
|
||||
describe('Allowed Channels', () => {
|
||||
const EXPECTED_SEND_CHANNELS = [
|
||||
'save-file',
|
||||
'save-current-file',
|
||||
'set-current-file',
|
||||
'save-recent-files',
|
||||
'clear-recent-files',
|
||||
'renderer-ready',
|
||||
'get-theme',
|
||||
'do-print',
|
||||
'export-with-options',
|
||||
'export-spreadsheet',
|
||||
'batch-convert',
|
||||
'select-folder',
|
||||
'universal-convert',
|
||||
'universal-convert-batch',
|
||||
'get-header-footer-settings',
|
||||
'save-header-footer-settings',
|
||||
'browse-header-footer-logo',
|
||||
'save-header-footer-logo',
|
||||
'clear-header-footer-logo',
|
||||
'get-page-settings',
|
||||
'update-page-settings',
|
||||
'set-custom-start-page',
|
||||
'process-pdf-operation',
|
||||
'get-pdf-page-count',
|
||||
'select-pdf-folder'
|
||||
];
|
||||
|
||||
const EXPECTED_RECEIVE_CHANNELS = [
|
||||
'file-new',
|
||||
'file-opened',
|
||||
'file-save',
|
||||
'get-content-for-save',
|
||||
'get-content-for-spreadsheet',
|
||||
'recent-files-cleared',
|
||||
'toggle-preview',
|
||||
'toggle-find',
|
||||
'theme-changed',
|
||||
'theme-data',
|
||||
'undo',
|
||||
'redo',
|
||||
'adjust-font-size',
|
||||
'print-preview',
|
||||
'print-preview-styled',
|
||||
'show-export-dialog',
|
||||
'show-batch-dialog',
|
||||
'show-universal-converter-dialog',
|
||||
'show-table-generator',
|
||||
'show-pdf-editor-dialog',
|
||||
'conversion-status',
|
||||
'conversion-complete',
|
||||
'batch-progress',
|
||||
'folder-selected',
|
||||
'pdf-folder-selected',
|
||||
'header-footer-settings-data',
|
||||
'header-footer-logo-selected',
|
||||
'header-footer-logo-saved',
|
||||
'page-settings-data',
|
||||
'pdf-page-count',
|
||||
'pdf-operation-complete',
|
||||
'pdf-operation-error'
|
||||
];
|
||||
|
||||
test('should define all expected send channels', () => {
|
||||
// This test documents expected channels
|
||||
expect(EXPECTED_SEND_CHANNELS.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('should define all expected receive channels', () => {
|
||||
// This test documents expected channels
|
||||
expect(EXPECTED_RECEIVE_CHANNELS.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('electronAPI Interface', () => {
|
||||
test('should expose send method', () => {
|
||||
expect(window.electronAPI.send).toBeDefined();
|
||||
expect(typeof window.electronAPI.send).toBe('function');
|
||||
});
|
||||
|
||||
test('should expose on method', () => {
|
||||
expect(window.electronAPI.on).toBeDefined();
|
||||
expect(typeof window.electronAPI.on).toBe('function');
|
||||
});
|
||||
|
||||
test('should expose once method', () => {
|
||||
expect(window.electronAPI.once).toBeDefined();
|
||||
expect(typeof window.electronAPI.once).toBe('function');
|
||||
});
|
||||
|
||||
test('should expose invoke method', () => {
|
||||
expect(window.electronAPI.invoke).toBeDefined();
|
||||
expect(typeof window.electronAPI.invoke).toBe('function');
|
||||
});
|
||||
|
||||
test('should expose file convenience methods', () => {
|
||||
expect(window.electronAPI.file).toBeDefined();
|
||||
expect(window.electronAPI.file.save).toBeDefined();
|
||||
expect(window.electronAPI.file.saveCurrent).toBeDefined();
|
||||
expect(window.electronAPI.file.setCurrent).toBeDefined();
|
||||
});
|
||||
|
||||
test('should expose theme convenience methods', () => {
|
||||
expect(window.electronAPI.theme).toBeDefined();
|
||||
expect(window.electronAPI.theme.get).toBeDefined();
|
||||
});
|
||||
|
||||
test('should expose pdf convenience methods', () => {
|
||||
expect(window.electronAPI.pdf).toBeDefined();
|
||||
expect(window.electronAPI.pdf.processOperation).toBeDefined();
|
||||
expect(window.electronAPI.pdf.getPageCount).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
/**
|
||||
* Tests for Preload Script Security
|
||||
* Verifies that the IPC bridge is properly configured
|
||||
*/
|
||||
|
||||
describe('Preload Security', () => {
|
||||
describe('Allowed Channels', () => {
|
||||
const EXPECTED_SEND_CHANNELS = [
|
||||
'save-file',
|
||||
'save-current-file',
|
||||
'set-current-file',
|
||||
'save-recent-files',
|
||||
'clear-recent-files',
|
||||
'renderer-ready',
|
||||
'get-theme',
|
||||
'do-print',
|
||||
'export-with-options',
|
||||
'export-spreadsheet',
|
||||
'batch-convert',
|
||||
'select-folder',
|
||||
'universal-convert',
|
||||
'universal-convert-batch',
|
||||
'get-header-footer-settings',
|
||||
'save-header-footer-settings',
|
||||
'browse-header-footer-logo',
|
||||
'save-header-footer-logo',
|
||||
'clear-header-footer-logo',
|
||||
'get-page-settings',
|
||||
'update-page-settings',
|
||||
'set-custom-start-page',
|
||||
'process-pdf-operation',
|
||||
'get-pdf-page-count',
|
||||
'select-pdf-folder'
|
||||
];
|
||||
|
||||
const EXPECTED_RECEIVE_CHANNELS = [
|
||||
'file-new',
|
||||
'file-opened',
|
||||
'file-save',
|
||||
'get-content-for-save',
|
||||
'get-content-for-spreadsheet',
|
||||
'recent-files-cleared',
|
||||
'toggle-preview',
|
||||
'toggle-find',
|
||||
'theme-changed',
|
||||
'theme-data',
|
||||
'undo',
|
||||
'redo',
|
||||
'adjust-font-size',
|
||||
'print-preview',
|
||||
'print-preview-styled',
|
||||
'show-export-dialog',
|
||||
'show-batch-dialog',
|
||||
'show-universal-converter-dialog',
|
||||
'show-table-generator',
|
||||
'show-pdf-editor-dialog',
|
||||
'conversion-status',
|
||||
'conversion-complete',
|
||||
'batch-progress',
|
||||
'folder-selected',
|
||||
'pdf-folder-selected',
|
||||
'header-footer-settings-data',
|
||||
'header-footer-logo-selected',
|
||||
'header-footer-logo-saved',
|
||||
'page-settings-data',
|
||||
'pdf-page-count',
|
||||
'pdf-operation-complete',
|
||||
'pdf-operation-error'
|
||||
];
|
||||
|
||||
test('should define all expected send channels', () => {
|
||||
// This test documents expected channels
|
||||
expect(EXPECTED_SEND_CHANNELS.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('should define all expected receive channels', () => {
|
||||
// This test documents expected channels
|
||||
expect(EXPECTED_RECEIVE_CHANNELS.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('electronAPI Interface', () => {
|
||||
test('should expose send method', () => {
|
||||
expect(window.electronAPI.send).toBeDefined();
|
||||
expect(typeof window.electronAPI.send).toBe('function');
|
||||
});
|
||||
|
||||
test('should expose on method', () => {
|
||||
expect(window.electronAPI.on).toBeDefined();
|
||||
expect(typeof window.electronAPI.on).toBe('function');
|
||||
});
|
||||
|
||||
test('should expose once method', () => {
|
||||
expect(window.electronAPI.once).toBeDefined();
|
||||
expect(typeof window.electronAPI.once).toBe('function');
|
||||
});
|
||||
|
||||
test('should expose invoke method', () => {
|
||||
expect(window.electronAPI.invoke).toBeDefined();
|
||||
expect(typeof window.electronAPI.invoke).toBe('function');
|
||||
});
|
||||
|
||||
test('should expose file convenience methods', () => {
|
||||
expect(window.electronAPI.file).toBeDefined();
|
||||
expect(window.electronAPI.file.save).toBeDefined();
|
||||
expect(window.electronAPI.file.saveCurrent).toBeDefined();
|
||||
expect(window.electronAPI.file.setCurrent).toBeDefined();
|
||||
});
|
||||
|
||||
test('should expose theme convenience methods', () => {
|
||||
expect(window.electronAPI.theme).toBeDefined();
|
||||
expect(window.electronAPI.theme.get).toBeDefined();
|
||||
});
|
||||
|
||||
test('should expose pdf convenience methods', () => {
|
||||
expect(window.electronAPI.pdf).toBeDefined();
|
||||
expect(window.electronAPI.pdf.processOperation).toBeDefined();
|
||||
expect(window.electronAPI.pdf.getPageCount).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+100
-100
@@ -1,100 +1,100 @@
|
||||
/**
|
||||
* Jest Test Setup
|
||||
* Provides mocks and utilities for PanConverter tests
|
||||
*/
|
||||
|
||||
// Mock window.electronAPI for renderer tests
|
||||
global.window = global.window || {};
|
||||
global.window.electronAPI = {
|
||||
send: jest.fn(),
|
||||
on: jest.fn(() => jest.fn()), // Returns cleanup function
|
||||
once: jest.fn(),
|
||||
invoke: jest.fn(() => Promise.resolve(null)),
|
||||
removeAllListeners: jest.fn(),
|
||||
file: {
|
||||
save: jest.fn(),
|
||||
saveCurrent: jest.fn(),
|
||||
setCurrent: jest.fn(),
|
||||
saveRecent: jest.fn(),
|
||||
clearRecent: jest.fn(),
|
||||
rendererReady: jest.fn()
|
||||
},
|
||||
theme: {
|
||||
get: jest.fn()
|
||||
},
|
||||
print: {
|
||||
doPrint: jest.fn()
|
||||
},
|
||||
export: {
|
||||
withOptions: jest.fn(),
|
||||
spreadsheet: jest.fn()
|
||||
},
|
||||
batch: {
|
||||
convert: jest.fn(),
|
||||
selectFolder: jest.fn()
|
||||
},
|
||||
converter: {
|
||||
convert: jest.fn(),
|
||||
convertBatch: jest.fn()
|
||||
},
|
||||
headerFooter: {
|
||||
getSettings: jest.fn(),
|
||||
saveSettings: jest.fn(),
|
||||
browseLogo: jest.fn(),
|
||||
saveLogo: jest.fn(),
|
||||
clearLogo: jest.fn()
|
||||
},
|
||||
page: {
|
||||
getSettings: jest.fn(),
|
||||
updateSettings: jest.fn(),
|
||||
setCustomStartPage: jest.fn()
|
||||
},
|
||||
pdf: {
|
||||
processOperation: jest.fn(),
|
||||
getPageCount: jest.fn(),
|
||||
selectFolder: jest.fn()
|
||||
}
|
||||
};
|
||||
|
||||
// Mock marked library
|
||||
global.window.marked = {
|
||||
parse: jest.fn((text) => `<p>${text}</p>`),
|
||||
setOptions: jest.fn()
|
||||
};
|
||||
|
||||
// Mock DOMPurify
|
||||
global.window.DOMPurify = {
|
||||
sanitize: jest.fn((html) => html)
|
||||
};
|
||||
|
||||
// Mock highlight.js
|
||||
global.window.hljs = {
|
||||
highlight: jest.fn((code, options) => ({ value: code })),
|
||||
highlightAuto: jest.fn((code) => ({ value: code })),
|
||||
getLanguage: jest.fn(() => true)
|
||||
};
|
||||
|
||||
// Mock localStorage
|
||||
const localStorageMock = {
|
||||
getItem: jest.fn(),
|
||||
setItem: jest.fn(),
|
||||
removeItem: jest.fn(),
|
||||
clear: jest.fn()
|
||||
};
|
||||
global.localStorage = localStorageMock;
|
||||
|
||||
// Console spy to catch unintended console logs in tests
|
||||
const originalConsoleError = console.error;
|
||||
console.error = (...args) => {
|
||||
// Allow certain expected errors
|
||||
const message = args[0]?.toString() || '';
|
||||
if (message.includes('Warning:') || message.includes('React')) {
|
||||
return;
|
||||
}
|
||||
originalConsoleError.apply(console, args);
|
||||
};
|
||||
|
||||
// Cleanup after each test
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
/**
|
||||
* Jest Test Setup
|
||||
* Provides mocks and utilities for PanConverter tests
|
||||
*/
|
||||
|
||||
// Mock window.electronAPI for renderer tests
|
||||
global.window = global.window || {};
|
||||
global.window.electronAPI = {
|
||||
send: jest.fn(),
|
||||
on: jest.fn(() => jest.fn()), // Returns cleanup function
|
||||
once: jest.fn(),
|
||||
invoke: jest.fn(() => Promise.resolve(null)),
|
||||
removeAllListeners: jest.fn(),
|
||||
file: {
|
||||
save: jest.fn(),
|
||||
saveCurrent: jest.fn(),
|
||||
setCurrent: jest.fn(),
|
||||
saveRecent: jest.fn(),
|
||||
clearRecent: jest.fn(),
|
||||
rendererReady: jest.fn()
|
||||
},
|
||||
theme: {
|
||||
get: jest.fn()
|
||||
},
|
||||
print: {
|
||||
doPrint: jest.fn()
|
||||
},
|
||||
export: {
|
||||
withOptions: jest.fn(),
|
||||
spreadsheet: jest.fn()
|
||||
},
|
||||
batch: {
|
||||
convert: jest.fn(),
|
||||
selectFolder: jest.fn()
|
||||
},
|
||||
converter: {
|
||||
convert: jest.fn(),
|
||||
convertBatch: jest.fn()
|
||||
},
|
||||
headerFooter: {
|
||||
getSettings: jest.fn(),
|
||||
saveSettings: jest.fn(),
|
||||
browseLogo: jest.fn(),
|
||||
saveLogo: jest.fn(),
|
||||
clearLogo: jest.fn()
|
||||
},
|
||||
page: {
|
||||
getSettings: jest.fn(),
|
||||
updateSettings: jest.fn(),
|
||||
setCustomStartPage: jest.fn()
|
||||
},
|
||||
pdf: {
|
||||
processOperation: jest.fn(),
|
||||
getPageCount: jest.fn(),
|
||||
selectFolder: jest.fn()
|
||||
}
|
||||
};
|
||||
|
||||
// Mock marked library
|
||||
global.window.marked = {
|
||||
parse: jest.fn((text) => `<p>${text}</p>`),
|
||||
setOptions: jest.fn()
|
||||
};
|
||||
|
||||
// Mock DOMPurify
|
||||
global.window.DOMPurify = {
|
||||
sanitize: jest.fn((html) => html)
|
||||
};
|
||||
|
||||
// Mock highlight.js
|
||||
global.window.hljs = {
|
||||
highlight: jest.fn((code, options) => ({ value: code })),
|
||||
highlightAuto: jest.fn((code) => ({ value: code })),
|
||||
getLanguage: jest.fn(() => true)
|
||||
};
|
||||
|
||||
// Mock localStorage
|
||||
const localStorageMock = {
|
||||
getItem: jest.fn(),
|
||||
setItem: jest.fn(),
|
||||
removeItem: jest.fn(),
|
||||
clear: jest.fn()
|
||||
};
|
||||
global.localStorage = localStorageMock;
|
||||
|
||||
// Console spy to catch unintended console logs in tests
|
||||
const originalConsoleError = console.error;
|
||||
console.error = (...args) => {
|
||||
// Allow certain expected errors
|
||||
const message = args[0]?.toString() || '';
|
||||
if (message.includes('Warning:') || message.includes('React')) {
|
||||
return;
|
||||
}
|
||||
originalConsoleError.apply(console, args);
|
||||
};
|
||||
|
||||
// Cleanup after each test
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
+137
-137
@@ -1,137 +1,137 @@
|
||||
/**
|
||||
* Tests for Utility Functions
|
||||
* Tests helper functions that can be extracted and tested
|
||||
*/
|
||||
|
||||
describe('Utility Functions', () => {
|
||||
describe('parseCommand', () => {
|
||||
// This function parses command strings into command and args
|
||||
function parseCommand(cmdString) {
|
||||
const parts = [];
|
||||
let current = '';
|
||||
let inQuotes = false;
|
||||
let quoteChar = '';
|
||||
|
||||
for (let i = 0; i < cmdString.length; i++) {
|
||||
const char = cmdString[i];
|
||||
if ((char === '"' || char === "'") && !inQuotes) {
|
||||
inQuotes = true;
|
||||
quoteChar = char;
|
||||
} else if (char === quoteChar && inQuotes) {
|
||||
inQuotes = false;
|
||||
quoteChar = '';
|
||||
} else if (char === ' ' && !inQuotes) {
|
||||
if (current) {
|
||||
parts.push(current);
|
||||
current = '';
|
||||
}
|
||||
} else {
|
||||
current += char;
|
||||
}
|
||||
}
|
||||
if (current) {
|
||||
parts.push(current);
|
||||
}
|
||||
|
||||
return {
|
||||
command: parts[0],
|
||||
args: parts.slice(1)
|
||||
};
|
||||
}
|
||||
|
||||
test('should parse simple command', () => {
|
||||
const result = parseCommand('pandoc input.md -o output.pdf');
|
||||
expect(result.command).toBe('pandoc');
|
||||
expect(result.args).toEqual(['input.md', '-o', 'output.pdf']);
|
||||
});
|
||||
|
||||
test('should handle double-quoted paths', () => {
|
||||
const result = parseCommand('pandoc "C:/path with spaces/file.md" -o output.pdf');
|
||||
expect(result.command).toBe('pandoc');
|
||||
expect(result.args).toEqual(['C:/path with spaces/file.md', '-o', 'output.pdf']);
|
||||
});
|
||||
|
||||
test('should handle single-quoted paths', () => {
|
||||
const result = parseCommand("pandoc 'file name.md' -o output.pdf");
|
||||
expect(result.command).toBe('pandoc');
|
||||
expect(result.args).toEqual(['file name.md', '-o', 'output.pdf']);
|
||||
});
|
||||
|
||||
test('should handle multiple options', () => {
|
||||
const result = parseCommand('pandoc input.md --pdf-engine=xelatex -V geometry:margin=1in -o output.pdf');
|
||||
expect(result.command).toBe('pandoc');
|
||||
expect(result.args).toContain('--pdf-engine=xelatex');
|
||||
expect(result.args).toContain('-V');
|
||||
});
|
||||
|
||||
test('should handle empty command', () => {
|
||||
const result = parseCommand('');
|
||||
expect(result.command).toBeUndefined();
|
||||
expect(result.args).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hexToRgb', () => {
|
||||
// This function converts hex colors to RGB
|
||||
function hexToRgb(hex) {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result ? {
|
||||
r: parseInt(result[1], 16) / 255,
|
||||
g: parseInt(result[2], 16) / 255,
|
||||
b: parseInt(result[3], 16) / 255
|
||||
} : null;
|
||||
}
|
||||
|
||||
test('should convert black hex to RGB', () => {
|
||||
const result = hexToRgb('#000000');
|
||||
expect(result).toEqual({ r: 0, g: 0, b: 0 });
|
||||
});
|
||||
|
||||
test('should convert white hex to RGB', () => {
|
||||
const result = hexToRgb('#ffffff');
|
||||
expect(result).toEqual({ r: 1, g: 1, b: 1 });
|
||||
});
|
||||
|
||||
test('should convert red hex to RGB', () => {
|
||||
const result = hexToRgb('#ff0000');
|
||||
expect(result.r).toBeCloseTo(1);
|
||||
expect(result.g).toBeCloseTo(0);
|
||||
expect(result.b).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
test('should handle hex without hash', () => {
|
||||
const result = hexToRgb('00ff00');
|
||||
expect(result.r).toBeCloseTo(0);
|
||||
expect(result.g).toBeCloseTo(1);
|
||||
expect(result.b).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
test('should return null for invalid hex', () => {
|
||||
expect(hexToRgb('invalid')).toBeNull();
|
||||
expect(hexToRgb('#xyz')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('File Path Utilities', () => {
|
||||
test('should extract file extension', () => {
|
||||
const getExtension = (filepath) => {
|
||||
const match = filepath.match(/\.([^/.]+)$/);
|
||||
return match ? match[1].toLowerCase() : '';
|
||||
};
|
||||
|
||||
expect(getExtension('file.md')).toBe('md');
|
||||
expect(getExtension('document.PDF')).toBe('pdf');
|
||||
expect(getExtension('path/to/file.docx')).toBe('docx');
|
||||
expect(getExtension('noextension')).toBe('');
|
||||
});
|
||||
|
||||
test('should replace file extension', () => {
|
||||
const replaceExtension = (filepath, newExt) => {
|
||||
return filepath.replace(/\.[^/.]+$/, `.${newExt}`);
|
||||
};
|
||||
|
||||
expect(replaceExtension('file.md', 'pdf')).toBe('file.pdf');
|
||||
expect(replaceExtension('path/to/doc.docx', 'html')).toBe('path/to/doc.html');
|
||||
});
|
||||
});
|
||||
});
|
||||
/**
|
||||
* Tests for Utility Functions
|
||||
* Tests helper functions that can be extracted and tested
|
||||
*/
|
||||
|
||||
describe('Utility Functions', () => {
|
||||
describe('parseCommand', () => {
|
||||
// This function parses command strings into command and args
|
||||
function parseCommand(cmdString) {
|
||||
const parts = [];
|
||||
let current = '';
|
||||
let inQuotes = false;
|
||||
let quoteChar = '';
|
||||
|
||||
for (let i = 0; i < cmdString.length; i++) {
|
||||
const char = cmdString[i];
|
||||
if ((char === '"' || char === "'") && !inQuotes) {
|
||||
inQuotes = true;
|
||||
quoteChar = char;
|
||||
} else if (char === quoteChar && inQuotes) {
|
||||
inQuotes = false;
|
||||
quoteChar = '';
|
||||
} else if (char === ' ' && !inQuotes) {
|
||||
if (current) {
|
||||
parts.push(current);
|
||||
current = '';
|
||||
}
|
||||
} else {
|
||||
current += char;
|
||||
}
|
||||
}
|
||||
if (current) {
|
||||
parts.push(current);
|
||||
}
|
||||
|
||||
return {
|
||||
command: parts[0],
|
||||
args: parts.slice(1)
|
||||
};
|
||||
}
|
||||
|
||||
test('should parse simple command', () => {
|
||||
const result = parseCommand('pandoc input.md -o output.pdf');
|
||||
expect(result.command).toBe('pandoc');
|
||||
expect(result.args).toEqual(['input.md', '-o', 'output.pdf']);
|
||||
});
|
||||
|
||||
test('should handle double-quoted paths', () => {
|
||||
const result = parseCommand('pandoc "C:/path with spaces/file.md" -o output.pdf');
|
||||
expect(result.command).toBe('pandoc');
|
||||
expect(result.args).toEqual(['C:/path with spaces/file.md', '-o', 'output.pdf']);
|
||||
});
|
||||
|
||||
test('should handle single-quoted paths', () => {
|
||||
const result = parseCommand("pandoc 'file name.md' -o output.pdf");
|
||||
expect(result.command).toBe('pandoc');
|
||||
expect(result.args).toEqual(['file name.md', '-o', 'output.pdf']);
|
||||
});
|
||||
|
||||
test('should handle multiple options', () => {
|
||||
const result = parseCommand('pandoc input.md --pdf-engine=xelatex -V geometry:margin=1in -o output.pdf');
|
||||
expect(result.command).toBe('pandoc');
|
||||
expect(result.args).toContain('--pdf-engine=xelatex');
|
||||
expect(result.args).toContain('-V');
|
||||
});
|
||||
|
||||
test('should handle empty command', () => {
|
||||
const result = parseCommand('');
|
||||
expect(result.command).toBeUndefined();
|
||||
expect(result.args).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hexToRgb', () => {
|
||||
// This function converts hex colors to RGB
|
||||
function hexToRgb(hex) {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result ? {
|
||||
r: parseInt(result[1], 16) / 255,
|
||||
g: parseInt(result[2], 16) / 255,
|
||||
b: parseInt(result[3], 16) / 255
|
||||
} : null;
|
||||
}
|
||||
|
||||
test('should convert black hex to RGB', () => {
|
||||
const result = hexToRgb('#000000');
|
||||
expect(result).toEqual({ r: 0, g: 0, b: 0 });
|
||||
});
|
||||
|
||||
test('should convert white hex to RGB', () => {
|
||||
const result = hexToRgb('#ffffff');
|
||||
expect(result).toEqual({ r: 1, g: 1, b: 1 });
|
||||
});
|
||||
|
||||
test('should convert red hex to RGB', () => {
|
||||
const result = hexToRgb('#ff0000');
|
||||
expect(result.r).toBeCloseTo(1);
|
||||
expect(result.g).toBeCloseTo(0);
|
||||
expect(result.b).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
test('should handle hex without hash', () => {
|
||||
const result = hexToRgb('00ff00');
|
||||
expect(result.r).toBeCloseTo(0);
|
||||
expect(result.g).toBeCloseTo(1);
|
||||
expect(result.b).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
test('should return null for invalid hex', () => {
|
||||
expect(hexToRgb('invalid')).toBeNull();
|
||||
expect(hexToRgb('#xyz')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('File Path Utilities', () => {
|
||||
test('should extract file extension', () => {
|
||||
const getExtension = (filepath) => {
|
||||
const match = filepath.match(/\.([^/.]+)$/);
|
||||
return match ? match[1].toLowerCase() : '';
|
||||
};
|
||||
|
||||
expect(getExtension('file.md')).toBe('md');
|
||||
expect(getExtension('document.PDF')).toBe('pdf');
|
||||
expect(getExtension('path/to/file.docx')).toBe('docx');
|
||||
expect(getExtension('noextension')).toBe('');
|
||||
});
|
||||
|
||||
test('should replace file extension', () => {
|
||||
const replaceExtension = (filepath, newExt) => {
|
||||
return filepath.replace(/\.[^/.]+$/, `.${newExt}`);
|
||||
};
|
||||
|
||||
expect(replaceExtension('file.md', 'pdf')).toBe('file.pdf');
|
||||
expect(replaceExtension('path/to/doc.docx', 'html')).toBe('path/to/doc.html');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user