igniteui-angular-sovn
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
287 lines (235 loc) • 10.9 kB
text/typescript
import { strFromU8 } from 'fflate';
import { ExcelFileTypes } from './excel-enums';
import { ZipFiles } from './zip-helper.spec';
export class ZipWrapper {
private _zip: Object;
private _filesAndFolders: string[];
private _files: Map<string, Uint8Array>;
private _filesContent: IFileContent[] = [];
private _hasValues = true;
constructor(currentZip: Object) {
this._zip = currentZip;
this._files = new Map<string, Uint8Array>();
this._filesAndFolders = [];
this.createFilesAndFolders(this._zip, '');
this._hasValues = this._filesAndFolders.length > ZipFiles.templatesNames.length;
this._filesContent = [];
}
/* Asserts the zip contains the files it should contain. */
public verifyStructure(isHGrid = false, message = '') {
let result = ObjectComparer.AreEqual(this.templateFilesAndFolders, ZipFiles.templatesNames);
const template = isHGrid ? ZipFiles.hGridDataFilesAndFoldersNames : ZipFiles.dataFilesAndFoldersNames;
result = (this.hasValues) ?
result && ObjectComparer.AreEqual(this.dataFilesAndFolders, template) :
result && this._filesAndFolders.length === ZipFiles.templatesNames.length;
expect(result).toBe(true, message + ' Unexpected zip structure!');
}
/* Verifies the contents of all template files and asserts the result.
Optionally, a message can be passed in, which, if specified, will be shown in the beginning of the comparison result. */
public async verifyTemplateFilesContent(message = '', hasDates = false) {
ZipFiles.hasDates = hasDates;
let result;
const msg = (message !== '') ? message + '\r\n' : '';
await this.readTemplateFiles().then(() => {
result = this.compareFiles(this.templateFilesContent, undefined);
expect(result.areEqual).toBe(true, msg + result.differences);
});
}
/* Verifies the contents of all data files and asserts the result.
Optionally, a message can be passed in, which, if specified, will be shown in the beginning of the comparison result. */
public async verifyDataFilesContent(expectedData: IFileContent[], message = '', isHGrid = false) {
let result;
const msg = (message !== '') ? message + '\r\n' : '';
await this.readDataFiles().then(() => {
result = this.compareFiles(this.dataFilesContent, expectedData, isHGrid);
expect(result.areEqual).toBe(true, msg + result.differences);
});
}
private createFilesAndFolders(obj: Object, prefix: string) {
Object.keys(obj).forEach((key) => {
if (ArrayBuffer.isView(obj[key])) {
this._files.set(`${prefix}${key}`, obj[key]);
this._filesAndFolders.push(`${prefix}${key}`);
} else {
const newPrefix = `${prefix}${key}/`;
this._filesAndFolders.push(newPrefix);
this.createFilesAndFolders(obj[key], newPrefix);
}
});
}
public get templateFilesAndFolders(): string[] {
return this._filesAndFolders.filter((name) => ZipFiles.templatesNames.indexOf(name) !== -1);
}
public get dataFilesAndFolders(): string[] {
return this._filesAndFolders.filter((name) => ZipFiles.dataFilesAndFoldersNames.indexOf(name) !== -1);
}
public get dataFilesOnly(): string[] {
return this.getFiles(this.dataFilesAndFolders);
}
public get templateFilesOnly(): string[] {
return this.getFiles(this.templateFilesAndFolders);
}
public get hasValues() {
return this._hasValues;
}
private getFiles(collection: string[]) {
return collection.filter((f) => f.endsWith('/') === false);
}
/* Reads all files and stores their contents in this._filesContent. */
private readFiles(files: string[]) {
// const self = this;
this._filesContent = [];
for (const file of files) {
const content = strFromU8(this._files.get(file));
this._filesContent.push({
fileName: file,
fileContent: content
});
}
}
private async readDataFiles() {
await this.readFiles(this.dataFilesOnly);
}
private async readTemplateFiles() {
const actualTemplates = (this.hasValues) ? this.templateFilesOnly.filter((f) =>
f !== ZipFiles.templatesNames[11]) : this.templateFilesOnly;
await this.readFiles(actualTemplates);
}
public get templateFilesContent(): IFileContent[] {
const actualTemplates = (this.hasValues) ? this.templateFilesOnly.filter((f) =>
f !== ZipFiles.templatesNames[11]) : this.templateFilesOnly;
return this._filesContent.filter((c) => actualTemplates.indexOf(c.fileName) > -1);
}
public get dataFilesContent(): IFileContent[] {
return this._filesContent.filter((c) => this.dataFilesOnly.indexOf(c.fileName) > -1);
}
/* Formats the result of two files comparison by displaying both the actual and expected content. */
private formatDifferences(differences, fileName, actualContent, expectedContent): string {
differences = `${differences}
------------------ ${fileName} ------------------
=================== Actual content ======================
${actualContent}
=================== Expected content ====================
${expectedContent}`;
return differences;
}
/* Compares the content of two files based on the provided file type and expected value data. */
private compareFilesContent(currentContent: string, fileType: ExcelFileTypes, fileData: string, isHGrid) {
let result = true;
let differences = '';
const expectedFile = ZipFiles.createExpectedXML(fileType, fileData, this.hasValues, isHGrid);
const expectedContent = expectedFile.content;
result = ObjectComparer.AreEqualXmls(currentContent, expectedContent);
if (!result) {
differences = this.formatDifferences(differences, expectedFile.name, currentContent, expectedContent);
}
return { areEqual: result, differences };
}
private compareContent(currentFile: IFileContent, expectedData: string, isHGrid) {
let result = true;
let differences = '';
const fileType = this.getFileTypeByName(currentFile.fileName);
if (fileType !== undefined) {
const comparisonResult = this.compareFilesContent(currentFile.fileContent, fileType, expectedData, isHGrid);
result = comparisonResult.areEqual;
if (!result) {
differences = comparisonResult.differences;
}
}
return { areEqual: result, differences };
}
/* Compares the contents of the provided files to their expected values. */
private compareFiles(actualFilesContent: IFileContent[], expectedFilesData: IFileContent[], isHGrid = false) {
let result = true;
let differences = '';
for (const current of actualFilesContent) {
const index = (expectedFilesData !== undefined) ? expectedFilesData.findIndex((f) => f.fileName === current.fileName) : -1;
const excelData = (index > -1 && expectedFilesData[index] !== undefined) ? expectedFilesData[index].fileContent : '';
const comparisonResult = this.compareContent(current, excelData, isHGrid);
result = result && comparisonResult.areEqual;
if (!comparisonResult.areEqual) {
differences = differences + comparisonResult.differences;
}
}
return { areEqual: result, differences };
}
/* Returns file's name based on its type. */
private getFileNameByType(type: ExcelFileTypes) {
const file = ZipFiles.files.find((f) => f.type === type);
return (file !== undefined) ? file.name : '';
}
/* Returns file's type based on its name. */
private getFileTypeByName(name: string) {
const file = ZipFiles.files.find((f) => f.name === name);
return (file !== undefined) ? file.type : undefined;
}
}
export interface IFileContent {
fileName: string;
fileContent: string;
}
export class ObjectComparer {
public static AreEqual(actual, template): boolean {
if (!ObjectComparer.compareTypesAndLength(actual, template)) {
return false;
}
let result = true;
// Compare properties
if (Object.prototype.toString.call(actual) === '[object Array]') {
for (let i = 0; i < actual.length; i++) {
result = (result && actual[i] === template[i]);
}
} else {
for (const key in actual) {
if (actual.hasOwnProperty(key)) {
// Compare the item
}
}
}
return result;
}
public static AreSimilar(actual, template): boolean {
if (!ObjectComparer.compareTypesAndLength(actual, template)) {
return false;
}
let result = true;
// Compare properties
if (Object.prototype.toString.call(actual) === '[object Array]') {
// eslint-disable-next-line @typescript-eslint/prefer-for-of
for (let i = 0; i < actual.length; i++) {
result = (result && template.indexof(actual[i]) >= 0);
}
} else {
for (const key in actual) {
if (actual.hasOwnProperty(key)) {
// Compare the item
}
}
}
return result;
}
public static AreEqualXmls(actualXML: string, expectedXML: string) {
const regex = /(\r\n|\n|\r|\t|\s+)/g;
// /(\r\n|\n|\r|\t)/g;
const actual = actualXML.replace(regex, '');
const expected = expectedXML.replace(regex, '');
return actual === expected;
}
protected static compareTypesAndLength(actual, template): boolean {
const actualType = Object.prototype.toString.call(actual);
const templateType = Object.prototype.toString.call(template);
if (actualType !== templateType) {
return false;
}
// If items are not an object or array, return false
if (['[object Array]', '[object Object]'].indexOf(actualType) < 0) {
return false;
}
const actualLength = actualType === '[object Array]' ? actual.length : Object.keys(actual).length;
const templateLength = templateType === '[object Array]' ? template.length : Object.keys(template).length;
if (actualLength !== templateLength) {
return false;
}
return true;
}
}