Add tests and comments and PR co-author credit

Co-Authored-By: Anton Mikaskin <garrakombo@gmail.com>
Co-Authored-By: vnguyen42
This commit is contained in:
Ben Irvin 2023-04-18 17:09:47 +02:00
parent d6965e562c
commit d11699c79b
3 changed files with 131 additions and 12 deletions

View File

@ -2,9 +2,10 @@ import { Readable } from 'stream';
import type { ILocalFileSourceProviderOptions } from '..';
import { createLocalFileSourceProvider } from '..';
import { isFilePathInDirname, isPathEquivalent, unknownPathToPosix } from '../utils';
describe('Stream assets', () => {
test('returns a stream', () => {
describe('File source provider', () => {
test('returns assets stream', () => {
const options: ILocalFileSourceProviderOptions = {
file: {
path: './test-file',
@ -21,4 +22,108 @@ describe('Stream assets', () => {
expect(stream instanceof Readable).toBeTruthy();
});
describe('utils', () => {
const unknownConversionCases = [
['some/path/on/posix', 'some/path/on/posix'],
['some/path/on/posix/', 'some/path/on/posix/'],
['some/path/on/posix.jpg', 'some/path/on/posix.jpg'],
['file.jpg', 'file.jpg'],
['noextension', 'noextension'],
['some\\windows\\filename.jpg', 'some/windows/filename.jpg'],
['some\\windows\\noendingslash', 'some/windows/noendingslash'],
['some\\windows\\endingslash\\', 'some/windows/endingslash/'],
];
test.each(unknownConversionCases)('unknownPathToPosix: %p -> %p', (input, expected) => {
expect(unknownPathToPosix(input)).toEqual(expected);
});
const isFilePathInDirnameCases: [string, string, boolean][] = [
// posix paths
['some/path/on/posix', 'some/path/on/posix/file.jpg', true],
['some/path/on/posix/', 'some/path/on/posix/file.jpg', true],
['./some/path/on/posix', 'some/path/on/posix/file.jpg', true],
['some/path/on/posix/', './some/path/on/posix/file.jpg', true],
['some/path/on/posix/', 'some/path/on/posix/', false], // invalid; second method should include a filename
['some/path/on/posix', 'some/path/on/posix', false], // 'posix' in second case should be interpreted as a filename
['', 'file.jpg', true],
['', './file.jpg', true],
['./', './file.jpg', true],
['noextension', 'noextension', false], // second case is a file
['noextension', './noextension/file.jpg', true],
['./noextension', './noextension/file.jpg', true],
['./noextension', 'noextension/file.jpg', true],
['noextension', 'noextension/noextension', true],
// win32 paths
['some/path/on/win32', 'some\\path\\on\\win32\\file.jpg', true],
['some/path/on/win32/', 'some\\path\\on\\win32\\file.jpg', true],
['some/path/on/win32/', 'some\\path\\on\\win32\\', false], // invalid; second method should include a filename
['some/path/on/win32', 'some\\path\\on\\win32', false], // 'win32' in second case should be interpreted as a filename
['', 'file.jpg', true],
['', '.\\file.jpg', true],
['./', '.\\file.jpg', true],
['noextension', 'noextension', false], // second case is a file
['noextension', '.\\noextension\\file.jpg', true],
['./noextension', '.\\noextension\\file.jpg', true],
['./noextension', 'noextension\\file.jpg', true],
['noextension', 'noextension\\noextension', true],
];
test.each(isFilePathInDirnameCases)(
'isFilePathInDirname: %p : %p -> %p',
(inputA, inputB, expected) => {
expect(isFilePathInDirname(inputA, inputB)).toEqual(expected);
}
);
const isPathEquivalentCases: [string, string, boolean][] = [
// POSITIVES
// root level
['file.jpg', 'file.jpg', true],
['file.jpg', '.\\file.jpg', true],
['file.jpg', './file.jpg', true],
// cwd root level (posix)
['./file.jpg', 'file.jpg', true],
['./file.jpg', './file.jpg', true],
['./file.jpg', '.\\file.jpg', true],
// cwd root level (win32)
['.\\file.jpg', 'file.jpg', true],
['.\\file.jpg', './file.jpg', true],
['.\\file.jpg', '.\\file.jpg', true],
// directory with file (posix)
['one/two/file.jpg', 'one/two/file.jpg', true],
['one/two/file.jpg', './one/two/file.jpg', true],
['one/two/file.jpg', 'one\\two\\file.jpg', true],
['one/two/file.jpg', '.\\one\\two\\file.jpg', true],
// cwd with file (posix)
['./one/two/file.jpg', 'one/two/file.jpg', true],
['./one/two/file.jpg', './one/two/file.jpg', true],
['./one/two/file.jpg', 'one\\two\\file.jpg', true],
['./one/two/file.jpg', '.\\one\\two\\file.jpg', true],
// directory with file (win32)
['one\\two\\file.jpg', 'one/two/file.jpg', true],
['one\\two\\file.jpg', './one/two/file.jpg', true],
['one\\two\\file.jpg', '.\\one\\two\\file.jpg', true],
['one\\two\\file.jpg', 'one\\two\\file.jpg', true],
// cwd with file (win32)
['.\\one\\two\\file.jpg', 'one/two/file.jpg', true],
['.\\one\\two\\file.jpg', './one/two/file.jpg', true],
['.\\one\\two\\file.jpg', '.\\one\\two\\file.jpg', true],
['.\\one\\two\\file.jpg', 'one\\two\\file.jpg', true],
// NEGATIVES
['file.jpg', 'one/file.jpg', false],
['file.jpg', 'one\\file.jpg', false],
['file.jpg', '/file.jpg', false],
['file.jpg', '\\file.jpg', false],
['one/file.jpg', '\\one\\file.jpg', false],
['one/file.jpg', '/one/file.jpg', false],
['one/file.jpg', 'file.jpg', false],
];
test.each(isPathEquivalentCases)(
'isPathEquivalent: %p : %p -> %p',
(inputA, inputB, expected) => {
expect(isPathEquivalent(inputA, inputB)).toEqual(expected);
}
);
});
});

View File

@ -15,7 +15,7 @@ import type { IAsset, IMetadata, ISourceProvider, ProviderType } from '../../../
import { createDecryptionCipher } from '../../../utils/encryption';
import { collect } from '../../../utils/stream';
import { ProviderInitializationError, ProviderTransferError } from '../../../errors/providers';
import { isDirPathEquivalent, isPathEquivalent, unknownPathToPosix } from './utils';
import { isFilePathInDirname, isPathEquivalent, unknownPathToPosix } from './utils';
type StreamItemArray = Parameters<typeof chain>[0];
@ -143,7 +143,7 @@ class LocalFileSourceProvider implements ISourceProvider {
if (entry.type !== 'File') {
return false;
}
return isDirPathEquivalent('assets/uploads', filePath);
return isFilePathInDirname('assets/uploads', filePath);
},
onentry(entry) {
// TODO: Check if we need to handle win32 paths here for the assets
@ -203,7 +203,7 @@ class LocalFileSourceProvider implements ISourceProvider {
return false;
}
return isDirPathEquivalent(directory, filePath);
return isFilePathInDirname(directory, filePath);
},
async onentry(entry) {

View File

@ -12,23 +12,37 @@ import path from 'path';
*
* */
// Check if the directory of a given filePath (which can be either posix or win32) resolves to the same as the given posix-format path posixDirName
// We must be able to assume the first argument is a path, otherwise path.dirname will interpret a path without any slashes as the filename
export const isDirPathEquivalent = (posixDirName: string, filePath: string) => {
/**
* Check if the directory of a given filePath (which can be either posix or win32) resolves to the same as the given posix-format path posixDirName
* We must be able to assume the first argument is a path to a directory and the second is a path to a file, otherwise path.dirname will interpret a path without any slashes as the filename
*
* @param {string} posixDirName A posix path pointing to a directory
* @param {string} filePath an unknown filesystem path pointing to a file
* @returns {boolean} is the file located in the given directory
*/
export const isFilePathInDirname = (posixDirName: string, filePath: string) => {
const normalizedDir = path.posix.dirname(unknownPathToPosix(filePath));
return isPathEquivalent(posixDirName, normalizedDir);
};
// Check if two paths that can be either in posix or win32 format resolves to the same file
export const isPathEquivalent = (fileA: string, fileB: string) => {
/**
* Check if two paths that can be either in posix or win32 format resolves to the same file
*
* @param {string} pathA a path that may be either win32 or posix
* @param {string} pathB a path that may be either win32 or posix
*
* @returns {boolean} do paths point to the same place
*/
export const isPathEquivalent = (pathA: string, pathB: string) => {
// Check if paths appear to be win32 or posix, and if win32 convert to posix
const normalizedPathA = unknownPathToPosix(fileA);
const normalizedPathB = unknownPathToPosix(fileB);
const normalizedPathA = path.posix.normalize(unknownPathToPosix(pathA));
const normalizedPathB = path.posix.normalize(unknownPathToPosix(pathB));
return !path.posix.relative(normalizedPathB, normalizedPathA).length;
};
/**
* Convert an unknown format path (win32 or posix) to a posix path
*
* @param {string} filePath a path that may be either win32 or posix
*