Previous function name `debugMatch` was not consistent with other match functions. PR Close #39233
		
			
				
	
	
		
			114 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
 | 
						|
/**
 | 
						|
 * @license
 | 
						|
 * Copyright Google LLC All Rights Reserved.
 | 
						|
 *
 | 
						|
 * Use of this source code is governed by an MIT-style license that can be
 | 
						|
 * found in the LICENSE file at https://angular.io/license
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
/** Template string function that can be used to strip indentation from a given string literal. */
 | 
						|
export function dedent(strings: TemplateStringsArray, ...values: any[]) {
 | 
						|
  let joinedString = '';
 | 
						|
  for (let i = 0; i < values.length; i++) {
 | 
						|
    joinedString += `${strings[i]}${values[i]}`;
 | 
						|
  }
 | 
						|
  joinedString += strings[strings.length - 1];
 | 
						|
  const lines = joinedString.split('\n');
 | 
						|
  while (isBlank(lines[0])) {
 | 
						|
    lines.shift();
 | 
						|
  }
 | 
						|
  while (isBlank(lines[lines.length - 1])) {
 | 
						|
    lines.pop();
 | 
						|
  }
 | 
						|
  let minWhitespacePrefix = lines.reduce(
 | 
						|
      (min, line) => Math.min(min, numOfWhiteSpaceLeadingChars(line)), Number.MAX_SAFE_INTEGER);
 | 
						|
  return lines.map((line) => line.substring(minWhitespacePrefix)).join('\n');
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Tests to see if the line is blank.
 | 
						|
 *
 | 
						|
 * A blank line is such which contains only whitespace.
 | 
						|
 * @param text string to test for blank-ness.
 | 
						|
 */
 | 
						|
function isBlank(text: string): boolean {
 | 
						|
  return /^\s*$/.test(text);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns number of whitespace leading characters.
 | 
						|
 *
 | 
						|
 * @param text
 | 
						|
 */
 | 
						|
function numOfWhiteSpaceLeadingChars(text: string): number {
 | 
						|
  return text.match(/^\s*/)![0].length;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Jasmine AsymmetricMatcher which can be used to assert `.debug` properties.
 | 
						|
 *
 | 
						|
 * ```
 | 
						|
 * expect(obj).toEqual({
 | 
						|
 *   create: matchDebug('someValue')
 | 
						|
 * })
 | 
						|
 * ```
 | 
						|
 *
 | 
						|
 * In the above example it will assert that `obj.create.debug === 'someValue'`.
 | 
						|
 *
 | 
						|
 * @param expected Expected value.
 | 
						|
 */
 | 
						|
export function matchDebug<T>(expected: T): any {
 | 
						|
  const matcher = function() {};
 | 
						|
  let actual: any = matchDebug;
 | 
						|
 | 
						|
  matcher.asymmetricMatch = function(objectWithDebug: any) {
 | 
						|
    return jasmine.matchersUtil.equals(actual = objectWithDebug.debug, expected);
 | 
						|
  };
 | 
						|
  matcher.jasmineToString = function() {
 | 
						|
    if (actual === matchDebug) {
 | 
						|
      // `asymmetricMatch` never got called hence no error to display
 | 
						|
      return '';
 | 
						|
    }
 | 
						|
    return buildFailureMessage(actual, expected);
 | 
						|
  };
 | 
						|
  return matcher;
 | 
						|
}
 | 
						|
 | 
						|
export function buildFailureMessage(actual: any, expected: any): string {
 | 
						|
  const diffs: string[] = [];
 | 
						|
  listPropertyDifferences(diffs, '', actual, expected, 5);
 | 
						|
  return '\n  ' + diffs.join('\n  ');
 | 
						|
}
 | 
						|
 | 
						|
function listPropertyDifferences(
 | 
						|
    diffs: string[], path: string, actual: any, expected: any, depth: number) {
 | 
						|
  if (actual === expected) return;
 | 
						|
  if (typeof actual !== typeof expected) {
 | 
						|
    diffs.push(`${path}: Expected ${jasmine.pp(actual)} to be ${jasmine.pp(expected)}`);
 | 
						|
  } else if (depth && Array.isArray(expected)) {
 | 
						|
    if (!Array.isArray(actual)) {
 | 
						|
      diffs.push(`${path}: Expected ${jasmine.pp(expected)} but was ${jasmine.pp(actual)}`);
 | 
						|
    } else {
 | 
						|
      const maxLength = Math.max(actual.length, expected.length);
 | 
						|
      listPropertyDifferences(diffs, path + '.length', expected.length, actual.length, depth - 1);
 | 
						|
      for (let i = 0; i < maxLength; i++) {
 | 
						|
        const actualItem = actual[i];
 | 
						|
        const expectedItem = expected[i];
 | 
						|
        listPropertyDifferences(diffs, path + '[' + i + ']', actualItem, expectedItem, depth - 1);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else if (
 | 
						|
      depth && expected && typeof expected === 'object' && actual && typeof actual === 'object') {
 | 
						|
    new Set(Object.keys(expected).concat(Object.keys(actual))).forEach((key) => {
 | 
						|
      const actualItem = actual[key];
 | 
						|
      const expectedItem = expected[key];
 | 
						|
      listPropertyDifferences(diffs, path + '.' + key, actualItem, expectedItem, depth - 1);
 | 
						|
    });
 | 
						|
  } else {
 | 
						|
    diffs.push(`${path}: Expected ${jasmine.pp(actual)} to be ${jasmine.pp(expected)}`);
 | 
						|
  }
 | 
						|
}
 |