216 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			216 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | /** | ||
|  |  * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
|  |  * | ||
|  |  * This source code is licensed under the MIT license found in the | ||
|  |  * LICENSE file in the root directory of this source tree. | ||
|  |  */ | ||
|  | 
 | ||
|  | import util from 'util'; | ||
|  | 
 | ||
|  | const chalk = require('chalk'); | ||
|  | const React = require('react'); | ||
|  | const ReactTestRenderer = require('react-test-renderer'); | ||
|  | const leftPad = require('left-pad'); | ||
|  | const prettyFormat = require('../build'); | ||
|  | const ReactTestComponent = require('../build/plugins/ReactTestComponent'); | ||
|  | const worldGeoJson = require('./world.geo.json'); | ||
|  | 
 | ||
|  | const NANOSECONDS = 1000000000; | ||
|  | let TIMES_TO_RUN = 100000; | ||
|  | 
 | ||
|  | function testCase(name, fn) { | ||
|  |   let result, error, time, total; | ||
|  | 
 | ||
|  |   try { | ||
|  |     result = fn(); | ||
|  |   } catch (err) { | ||
|  |     error = err; | ||
|  |   } | ||
|  | 
 | ||
|  |   if (!error) { | ||
|  |     const start = process.hrtime(); | ||
|  | 
 | ||
|  |     for (let i = 0; i < TIMES_TO_RUN; i++) { | ||
|  |       fn(); | ||
|  |     } | ||
|  | 
 | ||
|  |     const diff = process.hrtime(start); | ||
|  | 
 | ||
|  |     total = diff[0] * 1e9 + diff[1]; | ||
|  |     time = Math.round(total / TIMES_TO_RUN); | ||
|  |   } | ||
|  | 
 | ||
|  |   return { | ||
|  |     error, | ||
|  |     name, | ||
|  |     result, | ||
|  |     time, | ||
|  |     total, | ||
|  |   }; | ||
|  | } | ||
|  | 
 | ||
|  | function test(name, value, ignoreResult, prettyFormatOpts) { | ||
|  |   const formatted = testCase('prettyFormat()  ', () => | ||
|  |     prettyFormat(value, prettyFormatOpts), | ||
|  |   ); | ||
|  | 
 | ||
|  |   const inspected = testCase('util.inspect()  ', () => | ||
|  |     util.inspect(value, { | ||
|  |       depth: null, | ||
|  |       showHidden: true, | ||
|  |     }), | ||
|  |   ); | ||
|  | 
 | ||
|  |   const stringified = testCase('JSON.stringify()', () => | ||
|  |     JSON.stringify(value, null, '  '), | ||
|  |   ); | ||
|  | 
 | ||
|  |   const results = [formatted, inspected, stringified].sort( | ||
|  |     (a, b) => a.time - b.time, | ||
|  |   ); | ||
|  | 
 | ||
|  |   const winner = results[0]; | ||
|  | 
 | ||
|  |   results.forEach((item, index) => { | ||
|  |     item.isWinner = index === 0; | ||
|  |     item.isLoser = index === results.length - 1; | ||
|  |   }); | ||
|  | 
 | ||
|  |   function log(current) { | ||
|  |     let message = current.name; | ||
|  | 
 | ||
|  |     if (current.time) { | ||
|  |       message += ' - ' + leftPad(current.time, 6) + 'ns'; | ||
|  |     } | ||
|  |     if (current.total) { | ||
|  |       message += | ||
|  |         ' - ' + | ||
|  |         current.total / NANOSECONDS + | ||
|  |         's total (' + | ||
|  |         TIMES_TO_RUN + | ||
|  |         ' runs)'; | ||
|  |     } | ||
|  |     if (current.error) { | ||
|  |       message += ' - Error: ' + current.error.message; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (!ignoreResult && current.result) { | ||
|  |       message += ' - ' + JSON.stringify(current.result); | ||
|  |     } | ||
|  | 
 | ||
|  |     message = ' ' + message + ' '; | ||
|  | 
 | ||
|  |     if (current.error) { | ||
|  |       message = chalk.dim(message); | ||
|  |     } | ||
|  | 
 | ||
|  |     const diff = current.time - winner.time; | ||
|  | 
 | ||
|  |     if (diff > winner.time * 0.85) { | ||
|  |       message = chalk.bgRed.black(message); | ||
|  |     } else if (diff > winner.time * 0.65) { | ||
|  |       message = chalk.bgYellow.black(message); | ||
|  |     } else if (!current.error) { | ||
|  |       message = chalk.bgGreen.black(message); | ||
|  |     } else { | ||
|  |       message = chalk.dim(message); | ||
|  |     } | ||
|  | 
 | ||
|  |     console.log('  ' + message); | ||
|  |   } | ||
|  | 
 | ||
|  |   console.log(name + ': '); | ||
|  |   results.forEach(log); | ||
|  |   console.log(); | ||
|  | } | ||
|  | 
 | ||
|  | function returnArguments() { | ||
|  |   return arguments; | ||
|  | } | ||
|  | 
 | ||
|  | test('empty arguments', returnArguments()); | ||
|  | test('arguments', returnArguments(1, 2, 3)); | ||
|  | test('an empty array', []); | ||
|  | test('an array with items', [1, 2, 3]); | ||
|  | test('a typed array', new Uint32Array(3)); | ||
|  | test('an array buffer', new ArrayBuffer(3)); | ||
|  | test('a nested array', [[1, 2, 3]]); | ||
|  | test('true', true); | ||
|  | test('false', false); | ||
|  | test('an error', new Error()); | ||
|  | test('a typed error with a message', new TypeError('message')); | ||
|  | /* eslint-disable no-new-func */ | ||
|  | test('a function constructor', new Function()); | ||
|  | /* eslint-enable no-new-func */ | ||
|  | test('an anonymous function', () => {}); | ||
|  | function named() {} | ||
|  | test('a named function', named); | ||
|  | test('Infinity', Infinity); | ||
|  | test('-Infinity', -Infinity); | ||
|  | test('an empty map', new Map()); | ||
|  | const mapWithValues = new Map(); | ||
|  | const mapWithNonStringKeys = new Map(); | ||
|  | mapWithValues.set('prop1', 'value1'); | ||
|  | mapWithValues.set('prop2', 'value2'); | ||
|  | mapWithNonStringKeys.set({prop: 'value'}, {prop: 'value'}); | ||
|  | test('a map with values', mapWithValues); | ||
|  | test('a map with non-string keys', mapWithNonStringKeys); | ||
|  | test('NaN', NaN); | ||
|  | test('null', null); | ||
|  | test('a number', 123); | ||
|  | test('a date', new Date(10e11)); | ||
|  | test('an empty object', {}); | ||
|  | test('an object with properties', {prop1: 'value1', prop2: 'value2'}); | ||
|  | const objectWithPropsAndSymbols = {prop: 'value1'}; | ||
|  | objectWithPropsAndSymbols[Symbol('symbol1')] = 'value2'; | ||
|  | objectWithPropsAndSymbols[Symbol('symbol2')] = 'value3'; | ||
|  | test('an object with properties and symbols', objectWithPropsAndSymbols); | ||
|  | test('an object with sorted properties', {a: 2, b: 1}); | ||
|  | test('regular expressions from constructors', new RegExp('regexp')); | ||
|  | test('regular expressions from literals', /regexp/gi); | ||
|  | test('an empty set', new Set()); | ||
|  | const setWithValues = new Set(); | ||
|  | setWithValues.add('value1'); | ||
|  | setWithValues.add('value2'); | ||
|  | test('a set with values', setWithValues); | ||
|  | test('a string', 'string'); | ||
|  | test('a symbol', Symbol('symbol')); | ||
|  | test('undefined', undefined); | ||
|  | test('a WeakMap', new WeakMap()); | ||
|  | test('a WeakSet', new WeakSet()); | ||
|  | test('deeply nested objects', {prop: {prop: {prop: 'value'}}}); | ||
|  | const circularReferences = {}; | ||
|  | circularReferences.prop = circularReferences; | ||
|  | test('circular references', circularReferences); | ||
|  | const parallelReferencesInner = {}; | ||
|  | const parallelReferences = { | ||
|  |   prop1: parallelReferencesInner, | ||
|  |   prop2: parallelReferencesInner, | ||
|  | }; | ||
|  | test('parallel references', parallelReferences); | ||
|  | test('able to customize indent', {prop: 'value'}); | ||
|  | const bigObj = {}; | ||
|  | for (let i = 0; i < 50; i++) { | ||
|  |   bigObj[i] = i; | ||
|  | } | ||
|  | test('big object', bigObj); | ||
|  | 
 | ||
|  | const element = React.createElement( | ||
|  |   'div', | ||
|  |   {onClick: () => {}, prop: {a: 1, b: 2}}, | ||
|  |   React.createElement('div', {prop: {a: 1, b: 2}}), | ||
|  |   React.createElement('div'), | ||
|  |   React.createElement( | ||
|  |     'div', | ||
|  |     {prop: {a: 1, b: 2}}, | ||
|  |     React.createElement('div', null, React.createElement('div')), | ||
|  |   ), | ||
|  | ); | ||
|  | 
 | ||
|  | test('react', ReactTestRenderer.create(element).toJSON(), false, { | ||
|  |   plugins: [ReactTestComponent], | ||
|  | }); | ||
|  | 
 | ||
|  | TIMES_TO_RUN = 100; | ||
|  | test('massive', worldGeoJson, true); |