fix: Join and normalize paths consistently.

This commit is contained in:
Ruben Verborgh
2021-01-04 12:45:16 +01:00
committed by Joachim Van Herwegen
parent ee072b038a
commit f454b781ff
13 changed files with 120 additions and 62 deletions

View File

@@ -1,8 +1,7 @@
import { mkdirSync } from 'fs';
import { join } from 'path';
import * as Path from 'path';
import { Loader } from 'componentsjs';
import * as rimraf from 'rimraf';
import { joinFilePath, toSystemFilePath } from '../../src/util/PathUtil';
export const BASE = 'http://test.com';
@@ -12,17 +11,17 @@ export const BASE = 'http://test.com';
export const instantiateFromConfig = async(componentUrl: string, configFile: string,
variables?: Record<string, any>): Promise<any> => {
// Initialize the Components.js loader
const mainModulePath = Path.join(__dirname, '../../');
const mainModulePath = joinFilePath(__dirname, '../../');
const loader = new Loader({ mainModulePath });
await loader.registerAvailableModuleResources();
// Instantiate the component from the config
const configPath = Path.join(__dirname, 'config', configFile);
const configPath = toSystemFilePath(joinFilePath(__dirname, 'config', configFile));
return loader.instantiateFromUrl(componentUrl, configPath, undefined, { variables });
};
export const getTestFolder = (name: string): string =>
join(__dirname, '../tmp', name);
joinFilePath(__dirname, '../tmp', name);
export const createFolder = (folder: string): void => {
mkdirSync(folder, { recursive: true });

View File

@@ -1,9 +1,9 @@
import { createReadStream } from 'fs';
import { join } from 'path';
import type { HttpHandler, Initializer, ResourceStore } from '../../src/';
import { RepresentationMetadata } from '../../src/ldp/representation/RepresentationMetadata';
import { guardStream } from '../../src/util/GuardedStream';
import { CONTENT_TYPE, LDP } from '../../src/util/Vocabularies';
import {
CONTENT_TYPE, LDP,
RepresentationMetadata, guardStream, joinFilePath,
} from '../../src/';
import { AclHelper, ResourceHelper } from '../util/TestHelpers';
import { BASE, getTestFolder, createFolder, removeFolder, instantiateFromConfig } from './Config';
@@ -58,7 +58,7 @@ describe.each(stores)('An LDP handler with auth using %s', (name, { storeUrn, se
// Write test resource
await store.setRepresentation({ path: `${BASE}/permanent.txt` }, {
binary: true,
data: guardStream(createReadStream(join(__dirname, '../assets/permanent.txt'))),
data: guardStream(createReadStream(joinFilePath(__dirname, '../assets/permanent.txt'))),
metadata: new RepresentationMetadata({ [CONTENT_TYPE]: 'text/plain' }),
});
});

View File

@@ -1,7 +1,7 @@
import type { Server } from 'http';
import { join } from 'path';
import fetch from 'cross-fetch';
import type { HttpServerFactory } from '../../src/server/HttpServerFactory';
import { joinFilePath } from '../../src/util/PathUtil';
import { readableToString } from '../../src/util/StreamUtil';
import { instantiateFromConfig } from './Config';
@@ -17,7 +17,7 @@ describe('A server with a pod handler', (): void => {
'urn:solid-server:default:ServerFactory', 'server-without-auth.json', {
'urn:solid-server:default:variable:port': port,
'urn:solid-server:default:variable:baseUrl': baseUrl,
'urn:solid-server:default:variable:podTemplateFolder': join(__dirname, '../assets/templates'),
'urn:solid-server:default:variable:podTemplateFolder': joinFilePath(__dirname, '../assets/templates'),
},
) as HttpServerFactory;
server = factory.startServer(port);

View File

@@ -1,7 +1,7 @@
import * as path from 'path';
import { Loader } from 'componentsjs';
import { CliRunner } from '../../../src/init/CliRunner';
import type { Initializer } from '../../../src/init/Initializer';
import { joinFilePath, toSystemFilePath } from '../../../src/util/PathUtil';
const initializer: jest.Mocked<Initializer> = {
handleSafe: jest.fn(),
@@ -34,12 +34,12 @@ describe('CliRunner', (): void => {
expect(Loader).toHaveBeenCalledTimes(1);
expect(Loader).toHaveBeenCalledWith({
mainModulePath: path.join(__dirname, '../../../'),
mainModulePath: toSystemFilePath(joinFilePath(__dirname, '../../../')),
});
expect(loader.instantiateFromUrl).toHaveBeenCalledTimes(1);
expect(loader.instantiateFromUrl).toHaveBeenCalledWith(
'urn:solid-server:default:Initializer',
path.join(__dirname, '/../../../config/config-default.json'),
toSystemFilePath(joinFilePath(__dirname, '/../../../config/config-default.json')),
undefined,
{
variables: {
@@ -48,7 +48,7 @@ describe('CliRunner', (): void => {
'urn:solid-server:default:variable:rootFilePath': '/var/cwd/',
'urn:solid-server:default:variable:sparqlEndpoint': undefined,
'urn:solid-server:default:variable:loggingLevel': 'info',
'urn:solid-server:default:variable:podTemplateFolder': path.join(__dirname, '../../../templates'),
'urn:solid-server:default:variable:podTemplateFolder': joinFilePath(__dirname, '../../../templates'),
},
},
);
@@ -77,18 +77,18 @@ describe('CliRunner', (): void => {
expect(Loader).toHaveBeenCalledTimes(1);
expect(Loader).toHaveBeenCalledWith({
mainModulePath: '/var/cwd/module/path',
mainModulePath: toSystemFilePath('/var/cwd/module/path'),
scanGlobal: true,
});
expect(loader.instantiateFromUrl).toHaveBeenCalledWith(
'urn:solid-server:default:Initializer',
'/var/cwd/myconfig.json',
toSystemFilePath('/var/cwd/myconfig.json'),
undefined,
{
variables: {
'urn:solid-server:default:variable:baseUrl': 'http://pod.example/',
'urn:solid-server:default:variable:loggingLevel': 'debug',
'urn:solid-server:default:variable:podTemplateFolder': 'templates',
'urn:solid-server:default:variable:podTemplateFolder': '/var/cwd/templates',
'urn:solid-server:default:variable:port': 4000,
'urn:solid-server:default:variable:rootFilePath': '/var/cwd/root',
'urn:solid-server:default:variable:sparqlEndpoint': 'http://localhost:5000/sparql',
@@ -116,18 +116,18 @@ describe('CliRunner', (): void => {
expect(Loader).toHaveBeenCalledTimes(1);
expect(Loader).toHaveBeenCalledWith({
mainModulePath: '/var/cwd/module/path',
mainModulePath: toSystemFilePath('/var/cwd/module/path'),
scanGlobal: true,
});
expect(loader.instantiateFromUrl).toHaveBeenCalledWith(
'urn:solid-server:default:Initializer',
'/var/cwd/myconfig.json',
toSystemFilePath('/var/cwd/myconfig.json'),
undefined,
{
variables: {
'urn:solid-server:default:variable:baseUrl': 'http://pod.example/',
'urn:solid-server:default:variable:loggingLevel': 'debug',
'urn:solid-server:default:variable:podTemplateFolder': 'templates',
'urn:solid-server:default:variable:podTemplateFolder': '/var/cwd/templates',
'urn:solid-server:default:variable:port': 4000,
'urn:solid-server:default:variable:rootFilePath': '/var/cwd/root',
'urn:solid-server:default:variable:sparqlEndpoint': 'http://localhost:5000/sparql',

View File

@@ -1,11 +1,41 @@
import { sep } from 'path';
import {
decodeUriPathComponents,
encodeUriPathComponents,
ensureTrailingSlash,
joinFilePath,
normalizeFilePath,
toCanonicalUriPath,
toSystemFilePath,
} from '../../../src/util/PathUtil';
describe('PathUtil', (): void => {
describe('normalizeFilePath', (): void => {
it('normalizes POSIX paths.', async(): Promise<void> => {
expect(normalizeFilePath('/foo/bar/../baz')).toEqual('/foo/baz');
});
it('normalizes Windows paths.', async(): Promise<void> => {
expect(normalizeFilePath('c:\\foo\\bar\\..\\baz')).toEqual('c:/foo/baz');
});
});
describe('joinFilePath', (): void => {
it('joins POSIX paths.', async(): Promise<void> => {
expect(joinFilePath('/foo/bar/', '..', '/baz')).toEqual('/foo/baz');
});
it('joins Windows paths.', async(): Promise<void> => {
expect(joinFilePath('c:\\foo\\bar\\', '..', '/baz')).toEqual(`c:/foo/baz`);
});
});
describe('toSystemFilePath', (): void => {
it('converts a POSIX path to an OS-specific path.', async(): Promise<void> => {
expect(toSystemFilePath('c:/foo/bar/')).toEqual(`c:${sep}foo${sep}bar${sep}`);
});
});
describe('#ensureTrailingSlash', (): void => {
it('makes sure there is always exactly 1 slash.', async(): Promise<void> => {
expect(ensureTrailingSlash('http://test.com')).toEqual('http://test.com/');

View File

@@ -1,13 +1,12 @@
import { EventEmitter } from 'events';
import { promises as fs } from 'fs';
import type { IncomingHttpHeaders } from 'http';
import { join } from 'path';
import { Readable } from 'stream';
import * as url from 'url';
import type { MockResponse } from 'node-mocks-http';
import { createResponse } from 'node-mocks-http';
import type { ResourceStore, PermissionSet, HttpHandler, HttpRequest } from '../../src/';
import { guardedStreamFrom, RepresentationMetadata, ensureTrailingSlash } from '../../src/';
import { guardedStreamFrom, RepresentationMetadata, joinFilePath, ensureTrailingSlash } from '../../src/';
import { CONTENT_TYPE } from '../../src/util/Vocabularies';
import { performRequest } from './Util';
@@ -109,7 +108,7 @@ export class ResourceHelper {
public async createResource(fileLocation: string, slug: string, contentType: string, mayFail = false):
Promise<MockResponse<any>> {
const fileData = await fs.readFile(
join(__dirname, fileLocation),
joinFilePath(__dirname, fileLocation),
);
const response: MockResponse<any> = await this.performRequestWithBody(
@@ -131,7 +130,7 @@ export class ResourceHelper {
public async replaceResource(fileLocation: string, requestUrl: string, contentType: string):
Promise<MockResponse<any>> {
const fileData = await fs.readFile(
join(__dirname, fileLocation),
joinFilePath(__dirname, fileLocation),
);
const putUrl = new URL(requestUrl);