Merge pull request #82 from Azure/daschult/URL

Add and URLBuilder and tests
This commit is contained in:
Dan Schulte 2018-05-11 13:04:11 -07:00 коммит произвёл GitHub
Родитель b421f944c0 7f4422dd17
Коммит 0182b97925
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 1305 добавлений и 1 удалений

Просмотреть файл

@ -28,6 +28,7 @@ import {
promiseToCallback, promiseToServiceCallback, isValidUuid,
applyMixins, isNode, stringifyXML, prepareXMLRootList, isDuration
} from "./util/utils";
import { URLBuilder, URLQuery } from "./url";
// Credentials
import { TokenCredentials } from "./credentials/tokenCredentials";
@ -43,5 +44,6 @@ export {
BasicAuthenticationCredentials, ApiKeyCredentials, ApiKeyCredentialOptions, ServiceClientCredentials, BaseRequestPolicy, logPolicy, ServiceClientOptions, exponentialRetryPolicy,
systemErrorRetryPolicy, signingPolicy, msRestUserAgentPolicy, stripRequest, stripResponse, delay, executePromisesSequentially,
generateUuid, isValidUuid, encodeUri, RestError, RequestOptionsBase, RequestPolicy, ServiceCallback, promiseToCallback,
promiseToServiceCallback, isStream, redirectPolicy, applyMixins, isNode, stringifyXML, prepareXMLRootList, isDuration
promiseToServiceCallback, isStream, redirectPolicy, applyMixins, isNode, stringifyXML, prepareXMLRootList, isDuration,
URLBuilder, URLQuery
};

512
lib/url.ts Normal file
Просмотреть файл

@ -0,0 +1,512 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
export interface URLQuery {
[queryParameterName: string]: string;
}
/**
* A class that handles creating, modifying, and parsing URLs.
*/
export class URLBuilder {
private _scheme: string | undefined;
private _host: string | undefined;
private _port: string | undefined;
private _path: string | undefined;
private _query: URLQuery = {};
/**
* Set the scheme/protocol for this URL. If the provided scheme contains other parts of a URL
* (such as a host, port, path, or query), those parts will be added to this URL as well.
*/
public setScheme(scheme: string): void {
if (!scheme) {
this._scheme = undefined;
} else {
this.set(scheme, URLTokenizerState.SCHEME);
}
}
/**
* Get the scheme that has been set in this URL.
*/
public getScheme(): string | undefined {
return this._scheme;
}
/**
* Set the host for this URL. If the provided host contains other parts of a URL (such as a
* port, path, or query), those parts will be added to this URL as well.
*/
public setHost(host: string): void {
if (!host) {
this._host = undefined;
} else {
this.set(host, URLTokenizerState.SCHEME_OR_HOST);
}
}
/**
* Get the host that has been set in this URL.
*/
public getHost(): string | undefined {
return this._host;
}
/**
* Set the port for this URL. If the provided port contains other parts of a URL (such as a
* path or query), those parts will be added to this URL as well.
*/
public setPort(port: number | string | undefined): void {
if (port == undefined || port === "") {
this._port = undefined;
} else {
this.set(port.toString(), URLTokenizerState.PORT);
}
}
/**
* Get the port that has been set in this URL.
*/
public getPort(): string | undefined {
return this._port;
}
/**
* Set the path for this URL. If the provided path contains a query, then it will be added to
* this URL as well.
*/
public setPath(path: string | undefined): void {
if (!path) {
this._path = undefined;
} else {
if (path.indexOf("://") !== -1) {
this.set(path, URLTokenizerState.SCHEME);
} else {
this.set(path, URLTokenizerState.PATH);
}
}
}
/**
* Get the path that has been set in this URL.
*/
public getPath(): string | undefined {
return this._path;
}
/**
* Set the query parameter in this URL with the provided queryParameterName to be the provided
* queryParameterEncodedValue.
*/
public setQueryParameter(queryParameterName: string, queryParameterEncodedValue: string): void {
if (queryParameterName) {
this._query[queryParameterName] = queryParameterEncodedValue;
}
}
/**
* Set the query in this URL.
*/
public setQuery(query: string | URLQuery | undefined): void {
if (!query) {
this._query = {};
} else if (typeof query !== "string") {
this._query = query;
} else {
this.set(query, URLTokenizerState.QUERY);
}
}
/**
* Set the parts of this URL by parsing the provided text using the provided startState.
*/
private set(text: string, startState: URLTokenizerState): void {
const tokenizer = new URLTokenizer(text, startState);
while (tokenizer.next()) {
const token: URLToken | undefined = tokenizer.current();
if (token) {
switch (token.type) {
case URLTokenType.SCHEME:
this._scheme = token.text || undefined;
break;
case URLTokenType.HOST:
this._host = token.text || undefined;
break;
case URLTokenType.PORT:
this._port = token.text || undefined;
break;
case URLTokenType.PATH:
const tokenPath: string | undefined = token.text || undefined;
if (!this._path || this._path === "/" || tokenPath !== "/") {
this._path = tokenPath;
}
break;
case URLTokenType.QUERY:
let queryString: string | undefined = token.text;
if (queryString) {
if (queryString.startsWith("?")) {
queryString = queryString.substring(1);
}
for (const queryParameterString of queryString.split("&")) {
const queryParameterParts: string[] = queryParameterString.split("=");
if (queryParameterParts.length === 2) {
this.setQueryParameter(queryParameterParts[0], queryParameterParts[1]);
} else {
throw new Error("Malformed query parameter: " + queryParameterString);
}
}
}
break;
default:
throw new Error(`Unrecognized URLTokenType: ${token.type}`);
}
}
}
}
public toString(): string {
let result = "";
if (this._scheme) {
result += `${this._scheme}://`;
}
if (this._host) {
result += this._host;
}
if (this._port) {
result += `:${this._port}`;
}
if (this._path) {
if (!this._path.startsWith("/")) {
result += "/";
}
result += this._path;
}
if (this._query) {
let queryString = "";
for (const queryParameterName in this._query) {
if (queryString) {
queryString += "&";
}
queryString += `${queryParameterName}=${this._query[queryParameterName]}`;
}
if (queryString) {
result += `?${queryString}`;
}
}
return result;
}
public static parse(text: string): URLBuilder {
const result = new URLBuilder();
result.set(text, URLTokenizerState.SCHEME_OR_HOST);
return result;
}
}
export const enum URLTokenizerState {
SCHEME,
SCHEME_OR_HOST,
HOST,
PORT,
PATH,
QUERY,
DONE,
}
export const enum URLTokenType {
SCHEME,
HOST,
PORT,
PATH,
QUERY
}
export class URLToken {
public constructor(public readonly text: string, public readonly type: URLTokenType) {
}
public static scheme(text: string): URLToken {
return new URLToken(text, URLTokenType.SCHEME);
}
public static host(text: string): URLToken {
return new URLToken(text, URLTokenType.HOST);
}
public static port(text: string): URLToken {
return new URLToken(text, URLTokenType.PORT);
}
public static path(text: string): URLToken {
return new URLToken(text, URLTokenType.PATH);
}
public static query(text: string): URLToken {
return new URLToken(text, URLTokenType.QUERY);
}
}
/**
* Get whether or not the provided character (single character string) is an alphanumeric (letter or
* digit) character.
*/
export function isAlphaNumericCharacter(character: string): boolean {
const characterCode: number = character.charCodeAt(0);
return (48 /* '0' */ <= characterCode && characterCode <= 57 /* '9' */) ||
(65 /* 'A' */ <= characterCode && characterCode <= 90 /* 'Z' */) ||
(97 /* 'a' */ <= characterCode && characterCode <= 122 /* 'z' */);
}
/**
* A class that tokenizes URL strings.
*/
export class URLTokenizer {
private readonly _textLength: number;
private _currentState: URLTokenizerState;
private _currentIndex: number;
private _currentToken: URLToken | undefined;
public constructor(private readonly _text: string, state?: URLTokenizerState) {
this._textLength = _text ? _text.length : 0;
this._currentState = state != undefined ? state : URLTokenizerState.SCHEME_OR_HOST;
this._currentIndex = 0;
}
/**
* Whether or not this URLTokenizer has a current character.
*/
private hasCurrentCharacter(): boolean {
return this._currentIndex < this._textLength;
}
/**
* Get the character in the text string at the current index.
*/
private getCurrentCharacter(): string {
return this._text[this._currentIndex];
}
/**
* Advance to the character in text that is "step" characters ahead. If no step value is provided,
* then step will default to 1.
*/
private nextCharacter(step?: number): void {
if (this.hasCurrentCharacter) {
if (!step) {
step = 1;
}
this._currentIndex += step;
}
}
/**
* Starting with the current character, peek "charactersToPeek" number of characters ahead in this
* Tokenizer's stream of characters.
*/
private peekCharacters(charactersToPeek: number): string {
let endIndex: number = this._currentIndex + charactersToPeek;
if (this._textLength < endIndex) {
endIndex = this._textLength;
}
return this._text.substring(this._currentIndex, endIndex);
}
/**
* Read characters from this Tokenizer until the end of the stream or until the provided condition
* is false when provided the current character.
*/
private readWhile(condition: (character: string) => boolean): string {
let result = "";
while (this.hasCurrentCharacter()) {
const currentCharacter: string = this.getCurrentCharacter();
if (!condition(currentCharacter)) {
break;
} else {
result += currentCharacter;
this.nextCharacter();
}
}
return result;
}
/**
* Read characters from this Tokenizer until a non-alphanumeric character or the end of the
* character stream is reached.
*/
private readWhileLetterOrDigit(): string {
return this.readWhile((character: string) => isAlphaNumericCharacter(character));
}
/**
* Read characters from this Tokenizer until one of the provided terminating characters is read or
* the end of the character stream is reached.
*/
private readUntilCharacter(...terminatingCharacters: string[]): string {
return this.readWhile((character: string) => terminatingCharacters.indexOf(character) === -1);
}
/**
* Read the remaining characters from this Tokenizer's character stream.
*/
private readRemaining(): string {
let result = "";
if (this._currentIndex < this._textLength) {
result = this._text.substring(this._currentIndex);
this._currentIndex = this._textLength;
}
return result;
}
/**
* Get the current URLToken this URLTokenizer is pointing at, or undefined if the URLTokenizer
* hasn't started or has finished tokenizing.
*/
public current(): URLToken | undefined {
return this._currentToken;
}
/**
* Advance to the next URLToken and return whether or not a URLToken was found.
*/
public next(): boolean {
if (!this.hasCurrentCharacter()) {
this._currentToken = undefined;
} else {
switch (this._currentState) {
case URLTokenizerState.SCHEME:
this.nextScheme();
break;
case URLTokenizerState.SCHEME_OR_HOST:
this.nextSchemeOrHost();
break;
case URLTokenizerState.HOST:
this.nextHost();
break;
case URLTokenizerState.PORT:
this.nextPort();
break;
case URLTokenizerState.PATH:
this.nextPath();
break;
case URLTokenizerState.QUERY:
this.nextQuery();
break;
default:
throw new Error(`Unrecognized URLTokenizerState: ${this._currentState}`);
}
}
return !!this._currentToken;
}
private nextScheme(): void {
const scheme: string = this.readWhileLetterOrDigit();
this._currentToken = URLToken.scheme(scheme);
if (!this.hasCurrentCharacter()) {
this._currentState = URLTokenizerState.DONE;
} else {
this._currentState = URLTokenizerState.HOST;
}
}
private nextSchemeOrHost(): void {
const schemeOrHost: string = this.readUntilCharacter(":", "/", "?");
if (!this.hasCurrentCharacter()) {
this._currentToken = URLToken.host(schemeOrHost);
this._currentState = URLTokenizerState.DONE;
} else if (this.getCurrentCharacter() === ":") {
if (this.peekCharacters(3) === "://") {
this._currentToken = URLToken.scheme(schemeOrHost);
this._currentState = URLTokenizerState.HOST;
} else {
this._currentToken = URLToken.host(schemeOrHost);
this._currentState = URLTokenizerState.PORT;
}
} else {
this._currentToken = URLToken.host(schemeOrHost);
if (this.getCurrentCharacter() === "/") {
this._currentState = URLTokenizerState.PATH;
} else {
this._currentState = URLTokenizerState.QUERY;
}
}
}
private nextHost(): void {
if (this.peekCharacters(3) === "://") {
this.nextCharacter(3);
}
const host: string = this.readUntilCharacter(":", "/", "?");
this._currentToken = URLToken.host(host);
if (!this.hasCurrentCharacter()) {
this._currentState = URLTokenizerState.DONE;
} else if (this.getCurrentCharacter() === ":") {
this._currentState = URLTokenizerState.PORT;
} else if (this.getCurrentCharacter() === "/") {
this._currentState = URLTokenizerState.PATH;
} else {
this._currentState = URLTokenizerState.QUERY;
}
}
private nextPort(): void {
if (this.getCurrentCharacter() === ":") {
this.nextCharacter();
}
const port: string = this.readUntilCharacter("/", "?");
this._currentToken = URLToken.port(port);
if (!this.hasCurrentCharacter()) {
this._currentState = URLTokenizerState.DONE;
} else if (this.getCurrentCharacter() === "/") {
this._currentState = URLTokenizerState.PATH;
} else {
this._currentState = URLTokenizerState.QUERY;
}
}
private nextPath(): void {
const path: string = this.readUntilCharacter("?");
this._currentToken = URLToken.path(path);
if (!this.hasCurrentCharacter()) {
this._currentState = URLTokenizerState.DONE;
} else {
this._currentState = URLTokenizerState.QUERY;
}
}
private nextQuery(): void {
if (this.getCurrentCharacter() === "?") {
this.nextCharacter();
}
const query: string = this.readRemaining();
this._currentToken = URLToken.query(query);
this._currentState = URLTokenizerState.DONE;
}
}

790
test/shared/urlTests.ts Normal file
Просмотреть файл

@ -0,0 +1,790 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import * as assert from "assert";
import { URLTokenizer, URLToken, URLBuilder } from "../../lib/url";
describe("URLBuilder", () => {
describe("setScheme()", () => {
it(`to ""`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("");
assert.strictEqual(urlBuilder.getScheme(), undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`to "http"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http");
assert.strictEqual(urlBuilder.getScheme(), "http");
assert.strictEqual(urlBuilder.toString(), "http://");
});
it(`to "http://"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http://");
assert.strictEqual(urlBuilder.getScheme(), "http");
assert.strictEqual(urlBuilder.getHost(), undefined);
assert.strictEqual(urlBuilder.toString(), "http://");
});
it(`to "http://www.example.com"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http://www.example.com");
assert.strictEqual(urlBuilder.getScheme(), "http");
assert.strictEqual(urlBuilder.getHost(), "www.example.com");
assert.strictEqual(urlBuilder.toString(), "http://www.example.com");
});
it(`to "http://www.exa mple.com"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http://www.exa mple.com");
assert.strictEqual(urlBuilder.getScheme(), "http");
assert.strictEqual(urlBuilder.getHost(), "www.exa mple.com");
assert.strictEqual(urlBuilder.toString(), "http://www.exa mple.com");
});
it(`from "http" to ""`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http");
urlBuilder.setScheme("");
assert.strictEqual(urlBuilder.getScheme(), undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`from "http" to "https"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http");
urlBuilder.setScheme("https");
assert.strictEqual(urlBuilder.getScheme(), "https");
assert.strictEqual(urlBuilder.toString(), "https://");
});
it(`to "http" and setHost() to "www.example.com" and setQueryParameter() to "A=B"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http");
urlBuilder.setHost("www.example.com");
urlBuilder.setQueryParameter("A", "B");
assert.strictEqual("http://www.example.com?A=B", urlBuilder.toString());
});
it(`to "http" and setHost() to "www.example.com" and setQueryParameter() to "App les=B"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http");
urlBuilder.setHost("www.example.com");
urlBuilder.setQueryParameter("App les", "B");
assert.strictEqual("http://www.example.com?App les=B", urlBuilder.toString());
});
it(`to "http" and setHost() to "www.example.com" and setQueryParameter() to "App+les=B"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http");
urlBuilder.setHost("www.example.com");
urlBuilder.setQueryParameter("App+les", "B");
assert.strictEqual("http://www.example.com?App+les=B", urlBuilder.toString());
});
it(`to "http" and setHost() to "www.example.com" and setQueryParameter() to "App%20les=B"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http");
urlBuilder.setHost("www.example.com");
urlBuilder.setQueryParameter("App%20les", "B");
assert.strictEqual("http://www.example.com?App%20les=B", urlBuilder.toString());
});
it(`to "http" and setHost() to "www.example.com" and setQueryParameter() to "Apples=Go od"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http");
urlBuilder.setHost("www.example.com");
urlBuilder.setQueryParameter("Apples", "Go od");
assert.strictEqual("http://www.example.com?Apples=Go od", urlBuilder.toString());
});
it(`to "http" and setHost() to "www.example.com" and setQueryParameter() to "Apples=Go+od"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http");
urlBuilder.setHost("www.example.com");
urlBuilder.setQueryParameter("Apples", "Go+od");
assert.strictEqual("http://www.example.com?Apples=Go+od", urlBuilder.toString());
});
it(`to "http" and setHost() to "www.example.com" and setQueryParameter() to "Apples=Go%20od"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http");
urlBuilder.setHost("www.example.com");
urlBuilder.setQueryParameter("Apples", "Go%20od");
assert.strictEqual("http://www.example.com?Apples=Go%20od", urlBuilder.toString());
});
it(`to "http" and setHost() to "www.example.com" and setQueryParameter() to "A=B&C=D"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http");
urlBuilder.setHost("www.example.com");
urlBuilder.setQueryParameter("A", "B");
urlBuilder.setQueryParameter("C", "D");
assert.strictEqual(urlBuilder.toString(), "http://www.example.com?A=B&C=D");
});
it(`to "http" and setHost() to "www.example.com" and setQueryParameter() to "A=B&C=D" and setPath() to "index.html"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("http");
urlBuilder.setHost("www.example.com");
urlBuilder.setQueryParameter("A", "B");
urlBuilder.setQueryParameter("C", "D");
urlBuilder.setPath("index.html");
assert.strictEqual(urlBuilder.toString(), "http://www.example.com/index.html?A=B&C=D");
});
it(`to "https" and setHost() to "www.example.com" and setPath() to "http://www.othersite.com"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("https");
urlBuilder.setHost("www.example.com");
urlBuilder.setPath("http://www.othersite.com");
assert.strictEqual(urlBuilder.getScheme(), "http");
assert.strictEqual(urlBuilder.getHost(), "www.othersite.com");
assert.strictEqual(urlBuilder.getPath(), undefined);
assert.strictEqual(urlBuilder.toString(), "http://www.othersite.com");
});
it(`to "https" and setHost() to "www.example.com" and setPath() to "mypath?thing=stuff"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("https");
urlBuilder.setHost("www.example.com");
urlBuilder.setPath("mypath?thing=stuff");
urlBuilder.setQueryParameter("otherthing", "otherstuff");
assert.strictEqual(urlBuilder.getScheme(), "https");
assert.strictEqual(urlBuilder.getHost(), "www.example.com");
assert.strictEqual(urlBuilder.getPath(), "mypath");
assert.strictEqual(urlBuilder.toString(), "https://www.example.com/mypath?thing=stuff&otherthing=otherstuff");
});
it(`to "https" and setHost() to "www.example.com" and setPath() to "http://www.othersite.com/mypath?thing=stuff" and setQueryParameter() to "otherthing=otherstuff"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setScheme("https");
urlBuilder.setHost("www.example.com");
urlBuilder.setPath("http://www.othersite.com/mypath?thing=stuff");
urlBuilder.setQueryParameter("otherthing", "otherstuff");
assert.strictEqual(urlBuilder.getScheme(), "http");
assert.strictEqual(urlBuilder.getPath(), "/mypath");
assert.strictEqual(urlBuilder.toString(), "http://www.othersite.com/mypath?thing=stuff&otherthing=otherstuff");
});
});
describe("setHost()", () => {
it(`to ""`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("");
assert.strictEqual(urlBuilder.getHost(), undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`to "://www.example.com"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("://www.example.com");
assert.strictEqual(urlBuilder.getScheme(), undefined);
assert.strictEqual(urlBuilder.getHost(), "www.example.com");
assert.strictEqual(urlBuilder.toString(), "www.example.com");
});
it(`to "https://www.example.com"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("https://www.example.com");
assert.strictEqual(urlBuilder.getScheme(), "https");
assert.strictEqual(urlBuilder.getHost(), "www.example.com");
assert.strictEqual(urlBuilder.toString(), "https://www.example.com");
});
it(`to "www.example.com:"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com:");
assert.strictEqual(urlBuilder.getHost(), "www.example.com");
assert.strictEqual(urlBuilder.getPort(), undefined);
assert.strictEqual(urlBuilder.toString(), "www.example.com");
});
it(`to "www.example.com:1234"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com:1234");
assert.strictEqual(urlBuilder.getHost(), "www.example.com");
assert.strictEqual(urlBuilder.getPort(), "1234");
assert.strictEqual(urlBuilder.toString(), "www.example.com:1234");
});
it(`to "www.example.com/"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com/");
assert.strictEqual(urlBuilder.getHost(), "www.example.com");
assert.strictEqual(urlBuilder.getPath(), "/");
assert.strictEqual(urlBuilder.toString(), "www.example.com/");
});
it(`to "www.example.com/index.html"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com/index.html");
assert.strictEqual(urlBuilder.getHost(), "www.example.com");
assert.strictEqual(urlBuilder.getPath(), "/index.html");
assert.strictEqual(urlBuilder.toString(), "www.example.com/index.html");
});
it(`to "www.example.com?"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com?");
assert.strictEqual(urlBuilder.getHost(), "www.example.com");
assert.strictEqual(urlBuilder.toString(), "www.example.com");
});
it(`to "www.example.com?a=b"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com?a=b");
assert.strictEqual(urlBuilder.getHost(), "www.example.com");
assert.strictEqual(urlBuilder.toString(), "www.example.com?a=b");
});
it(`to "www.examp le.com"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.examp le.com");
assert.strictEqual(urlBuilder.getHost(), "www.examp le.com");
assert.strictEqual(urlBuilder.toString(), "www.examp le.com");
});
it(`from "www.example.com" to ""`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com");
urlBuilder.setHost("");
assert.strictEqual(urlBuilder.getHost(), undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`from "www.example.com" to "www.bing.com"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com");
urlBuilder.setHost("www.bing.com");
assert.strictEqual(urlBuilder.getHost(), "www.bing.com");
assert.strictEqual(urlBuilder.toString(), "www.bing.com");
});
it(`to "www.example.com" and setPath() to "my/path"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com");
urlBuilder.setPath("my/path");
assert.strictEqual(urlBuilder.toString(), "www.example.com/my/path");
});
it(`to "www.example.com" and setPath() to "/my/path"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com");
urlBuilder.setPath("/my/path");
assert.strictEqual(urlBuilder.toString(), "www.example.com/my/path");
});
it(`to "www.example.com/" and setPath() to "my/path"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com/");
urlBuilder.setPath("my/path");
assert.strictEqual(urlBuilder.toString(), "www.example.com/my/path");
});
it(`to "www.example.com/" and setPath() to "/my/path"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com/");
urlBuilder.setPath("/my/path");
assert.strictEqual(urlBuilder.toString(), "www.example.com/my/path");
});
it(`to "www.example.com" and setPath() to "my path"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com/");
urlBuilder.setPath("my path");
assert.strictEqual(urlBuilder.toString(), "www.example.com/my path");
});
it(`to "www.example.com" and setPath() to "my+path"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com/");
urlBuilder.setPath("my+path");
assert.strictEqual(urlBuilder.toString(), "www.example.com/my+path");
});
it(`to "www.example.com" and setPath() to "my%20path"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setHost("www.example.com/");
urlBuilder.setPath("my%20path");
assert.strictEqual(urlBuilder.toString(), "www.example.com/my%20path");
});
});
describe("setPort()", () => {
it(`to undefined`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPort(undefined);
assert.strictEqual(urlBuilder.getPort(), undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`to ""`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPort("");
assert.strictEqual(urlBuilder.getPort(), undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`to 50`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPort(50);
assert.strictEqual(urlBuilder.getPort(), "50");
assert.strictEqual(urlBuilder.toString(), ":50");
});
it(`to "50"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPort("50");
assert.strictEqual(urlBuilder.getPort(), "50");
assert.strictEqual(urlBuilder.toString(), ":50");
});
it(`to "50/"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPort("50/");
assert.strictEqual(urlBuilder.getPort(), "50");
assert.strictEqual(urlBuilder.getPath(), "/");
assert.strictEqual(urlBuilder.toString(), ":50/");
});
it(`to "50/index.html"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPort("50/index.html");
assert.strictEqual(urlBuilder.getPort(), "50");
assert.strictEqual(urlBuilder.getPath(), "/index.html");
assert.strictEqual(urlBuilder.toString(), ":50/index.html");
});
it(`to "50?"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPort("50?");
assert.strictEqual(urlBuilder.getPort(), "50");
assert.strictEqual(urlBuilder.toString(), ":50");
});
it(`to "50?a=b&c=d"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPort("50?a=b&c=d");
assert.strictEqual(urlBuilder.getPort(), "50");
assert.strictEqual(urlBuilder.toString(), ":50?a=b&c=d");
});
it(`from 8080 to undefined`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPort(8080);
urlBuilder.setPort(undefined);
assert.strictEqual(urlBuilder.getPort(), undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`from 8080 to ""`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPort(8080);
urlBuilder.setPort("");
assert.strictEqual(urlBuilder.getPort(), undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`from 8080 to 123`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPort(8080);
urlBuilder.setPort(123);
assert.strictEqual(urlBuilder.getPort(), "123");
assert.strictEqual(urlBuilder.toString(), ":123");
});
it(`from 8080 to "123"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPort(8080);
urlBuilder.setPort("123");
assert.strictEqual(urlBuilder.getPort(), "123");
assert.strictEqual(urlBuilder.toString(), ":123");
});
});
describe("setPath()", () => {
it(`to undefined`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPath(undefined);
assert.strictEqual(urlBuilder.getPath(), undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`to ""`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPath("");
assert.strictEqual(urlBuilder.getPath(), undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`to "/"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPath("/");
assert.strictEqual(urlBuilder.getPath(), "/");
assert.strictEqual(urlBuilder.toString(), "/");
});
it(`to "test/path.html"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPath("test/path.html");
assert.strictEqual(urlBuilder.getPath(), "test/path.html");
assert.strictEqual(urlBuilder.toString(), "/test/path.html");
});
it(`from "/" to undefined`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPath("/");
urlBuilder.setPath(undefined);
assert.strictEqual(urlBuilder.getPath(), undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`from "/" to ""`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPath("/");
urlBuilder.setPath("");
assert.strictEqual(urlBuilder.getPath(), undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`from "/" to "/"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPath("/");
urlBuilder.setPath("/");
assert.strictEqual(urlBuilder.getPath(), "/");
assert.strictEqual(urlBuilder.toString(), "/");
});
it(`from "/" to "test/path.html"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setPath("/");
urlBuilder.setPath("test/path.html");
assert.strictEqual(urlBuilder.getPath(), "test/path.html");
assert.strictEqual(urlBuilder.toString(), "/test/path.html");
});
});
describe("setQuery()", () => {
it(`to undefined`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setQuery(undefined);
assert.strictEqual(urlBuilder.toString(), "");
});
it(`to ""`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setQuery("");
assert.strictEqual(urlBuilder.toString(), "");
});
it(`to "?"`, () => {
const urlBuilder = new URLBuilder();
urlBuilder.setQuery("?");
assert.strictEqual(urlBuilder.toString(), "");
});
});
describe("parse()", () => {
it(`with ""`, () => {
assert.strictEqual(URLBuilder.parse("").toString(), "");
});
it(`with "www.bing.com"`, () => {
assert.strictEqual(URLBuilder.parse("www.bing.com").toString(), "www.bing.com");
});
it(`with "www.bing.com:8080"`, () => {
assert.strictEqual(URLBuilder.parse("www.bing.com:8080").toString(), "www.bing.com:8080");
});
it(`with "ftp://www.bing.com:8080"`, () => {
assert.strictEqual(URLBuilder.parse("ftp://www.bing.com:8080").toString(), "ftp://www.bing.com:8080");
});
it(`with "www.bing.com/my/path"`, () => {
assert.strictEqual(URLBuilder.parse("www.bing.com/my/path").toString(), "www.bing.com/my/path");
});
it(`with "ftp://www.bing.com/my/path"`, () => {
assert.strictEqual(URLBuilder.parse("ftp://www.bing.com/my/path").toString(), "ftp://www.bing.com/my/path");
});
it(`with "www.bing.com:1234/my/path"`, () => {
assert.strictEqual(URLBuilder.parse("www.bing.com:1234/my/path").toString(), "www.bing.com:1234/my/path");
});
it(`with "ftp://www.bing.com:1234/my/path"`, () => {
assert.strictEqual(URLBuilder.parse("ftp://www.bing.com:1234/my/path").toString(), "ftp://www.bing.com:1234/my/path");
});
it(`with "www.bing.com?a=1"`, () => {
assert.strictEqual(URLBuilder.parse("www.bing.com?a=1").toString(), "www.bing.com?a=1");
});
it(`with "https://www.bing.com?a=1"`, () => {
assert.strictEqual(URLBuilder.parse("https://www.bing.com?a=1").toString(), "https://www.bing.com?a=1");
});
it(`with "www.bing.com:123?a=1"`, () => {
assert.strictEqual(URLBuilder.parse("www.bing.com:123?a=1").toString(), "www.bing.com:123?a=1");
});
it(`with "https://www.bing.com:987?a=1"`, () => {
assert.strictEqual(URLBuilder.parse("https://www.bing.com:987?a=1").toString(), "https://www.bing.com:987?a=1");
});
it(`with "www.bing.com/folder/index.html?a=1"`, () => {
assert.strictEqual(URLBuilder.parse("www.bing.com/folder/index.html?a=1").toString(), "www.bing.com/folder/index.html?a=1");
});
it(`with "https://www.bing.com/image.gif?a=1"`, () => {
assert.strictEqual(URLBuilder.parse("https://www.bing.com/image.gif?a=1").toString(), "https://www.bing.com/image.gif?a=1");
});
it(`with "www.bing.com:123/index.html?a=1"`, () => {
assert.strictEqual(URLBuilder.parse("www.bing.com:123/index.html?a=1").toString(), "www.bing.com:123/index.html?a=1");
});
it(`with "https://www.bing.com:987/my/path/again?a=1"`, () => {
assert.strictEqual(URLBuilder.parse("https://www.bing.com:987/my/path/again?a=1").toString(), "https://www.bing.com:987/my/path/again?a=1");
});
it(`with "www.bing.com?a=1&b=2"`, () => {
assert.strictEqual(URLBuilder.parse("www.bing.com?a=1&b=2").toString(), "www.bing.com?a=1&b=2");
});
it(`with "https://www.bing.com?a=1&b=2"`, () => {
assert.strictEqual(URLBuilder.parse("https://www.bing.com?a=1&b=2").toString(), "https://www.bing.com?a=1&b=2");
});
it(`with "www.bing.com:123?a=1&b=2"`, () => {
assert.strictEqual(URLBuilder.parse("www.bing.com:123?a=1&b=2").toString(), "www.bing.com:123?a=1&b=2");
});
it(`with "https://www.bing.com:987?a=1&b=2"`, () => {
assert.strictEqual(URLBuilder.parse("https://www.bing.com:987?a=1&b=2").toString(), "https://www.bing.com:987?a=1&b=2");
});
it(`with "www.bing.com/folder/index.html?a=1&b=2"`, () => {
assert.strictEqual(URLBuilder.parse("www.bing.com/folder/index.html?a=1&b=2").toString(), "www.bing.com/folder/index.html?a=1&b=2");
});
it(`with "https://www.bing.com/image.gif?a=1&b=2"`, () => {
assert.strictEqual(URLBuilder.parse("https://www.bing.com/image.gif?a=1&b=2").toString(), "https://www.bing.com/image.gif?a=1&b=2");
});
it(`with "www.bing.com:123/index.html?a=1&b=2"`, () => {
assert.strictEqual(URLBuilder.parse("www.bing.com:123/index.html?a=1&b=2").toString(), "www.bing.com:123/index.html?a=1&b=2");
});
it(`with "https://www.bing.com:987/my/path/again?a=1&b=2"`, () => {
assert.strictEqual(URLBuilder.parse("https://www.bing.com:987/my/path/again?a=1&b=2").toString(), "https://www.bing.com:987/my/path/again?a=1&b=2");
});
it(`with "https://www.bing.com/my:/path"`, () => {
assert.strictEqual(URLBuilder.parse("https://www.bing.com/my:/path").toString(), "https://www.bing.com/my:/path");
});
});
});
describe("URLTokenizer", () => {
it("should not have a current token when first created", () => {
const tokenizer = new URLTokenizer("http://www.bing.com");
assert.strictEqual(tokenizer.current(), undefined);
});
describe("next()", () => {
function nextTest(text: string, expectedURLTokens: URLToken[]): void {
const tokenizer = new URLTokenizer(text);
if (expectedURLTokens) {
for (let i = 0; i < expectedURLTokens.length; ++i) {
assert.strictEqual(tokenizer.next(), true, `Expected to find ${expectedURLTokens.length} URLTokens, but found ${i} instead.`);
assert.deepEqual(tokenizer.current(), expectedURLTokens[i], `Expected the ${i + 1} URLToken to be ${JSON.stringify(expectedURLTokens[i])}, but found ${JSON.stringify(tokenizer.current())} instead.`);
}
}
assert.strictEqual(tokenizer.next(), false, `Only expected to find ${(expectedURLTokens ? expectedURLTokens.length : 0)} URL token(s).`);
assert.strictEqual(tokenizer.current(), undefined, `After reading all of the URLTokens, expected the current value to be undefined.`);
}
it(`with ""`, () => {
nextTest("", []);
});
it(`with "http"`, () => {
nextTest("http", [
URLToken.host("http")
]);
});
it(`with "http:"`, () => {
nextTest("http:", [
URLToken.host("http"),
URLToken.port("")
]);
});
it(`with "http:/"`, () => {
nextTest("http:/", [
URLToken.host("http"),
URLToken.port(""),
URLToken.path("/")
]);
});
it(`with "http://"`, () => {
nextTest("http://", [
URLToken.scheme("http"),
URLToken.host("")
]);
});
it(`with "https://www.example.com"`, () => {
nextTest("https://www.example.com", [
URLToken.scheme("https"),
URLToken.host("www.example.com")
]);
});
it(`with "https://www.example.com:"`, () => {
nextTest("https://www.example.com:", [
URLToken.scheme("https"),
URLToken.host("www.example.com"),
URLToken.port("")
]);
});
it(`with "https://www.example.com:8080"`, () => {
nextTest("https://www.example.com:8080", [
URLToken.scheme("https"),
URLToken.host("www.example.com"),
URLToken.port("8080")
]);
});
it(`with "ftp://www.bing.com:123/"`, () => {
nextTest("ftp://www.bing.com:123/", [
URLToken.scheme("ftp"),
URLToken.host("www.bing.com"),
URLToken.port("123"),
URLToken.path("/")
]);
});
it(`with "ftp://www.bing.com:123/a/b/c.txt"`, () => {
nextTest("ftp://www.bing.com:123/a/b/c.txt", [
URLToken.scheme("ftp"),
URLToken.host("www.bing.com"),
URLToken.port("123"),
URLToken.path("/a/b/c.txt")
]);
});
it(`with "ftp://www.bing.com:123?"`, () => {
nextTest("ftp://www.bing.com:123?", [
URLToken.scheme("ftp"),
URLToken.host("www.bing.com"),
URLToken.port("123"),
URLToken.query("")
]);
});
it(`with "ftp://www.bing.com:123?a=b&c=d"`, () => {
nextTest("ftp://www.bing.com:123?a=b&c=d", [
URLToken.scheme("ftp"),
URLToken.host("www.bing.com"),
URLToken.port("123"),
URLToken.query("a=b&c=d")
]);
});
it(`with "https://www.example.com/"`, () => {
nextTest("https://www.example.com/", [
URLToken.scheme("https"),
URLToken.host("www.example.com"),
URLToken.path("/")
]);
});
it(`with "https://www.example.com/index.html"`, () => {
nextTest("https://www.example.com/index.html", [
URLToken.scheme("https"),
URLToken.host("www.example.com"),
URLToken.path("/index.html")
]);
});
it(`with "https://www.example.com/index.html?"`, () => {
nextTest("https://www.example.com/index.html?", [
URLToken.scheme("https"),
URLToken.host("www.example.com"),
URLToken.path("/index.html"),
URLToken.query("")
]);
});
it(`with "https://www.example.com/index.html?"`, () => {
nextTest("https://www.example.com/index.html?", [
URLToken.scheme("https"),
URLToken.host("www.example.com"),
URLToken.path("/index.html"),
URLToken.query("")
]);
});
it(`with "https://www.example.com/index.html?alpha=beta"`, () => {
nextTest("https://www.example.com/index.html?alpha=beta", [
URLToken.scheme("https"),
URLToken.host("www.example.com"),
URLToken.path("/index.html"),
URLToken.query("alpha=beta")
]);
});
it(`with "https://www.example.com?"`, () => {
nextTest("https://www.example.com?", [
URLToken.scheme("https"),
URLToken.host("www.example.com"),
URLToken.query("")
]);
});
it(`with "https://www.example.com?a=b"`, () => {
nextTest("https://www.example.com?a=b", [
URLToken.scheme("https"),
URLToken.host("www.example.com"),
URLToken.query("a=b")
]);
});
it(`with "www.test.com/"`, () => {
nextTest("www.test.com/", [
URLToken.host("www.test.com"),
URLToken.path("/")
]);
});
it(`with "www.test.com?"`, () => {
nextTest("www.test.com?", [
URLToken.host("www.test.com"),
URLToken.query("")
]);
});
it(`with "folder/index.html"`, () => {
nextTest("folder/index.html", [
URLToken.host("folder"),
URLToken.path("/index.html")
]);
});
it(`with "/folder/index.html"`, () => {
nextTest("/folder/index.html", [
URLToken.host(""),
URLToken.path("/folder/index.html")
]);
});
});
});