utils.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /**
  2. * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. import utils from '/ckeditor5/core/utils.js';
  7. const getIteratorCount = utils.count;
  8. describe( 'utils', () => {
  9. describe( 'spy', () => {
  10. it( 'should not have `called` after creation', () => {
  11. let spy = utils.spy();
  12. expect( spy.called ).to.not.be.true();
  13. } );
  14. it( 'should register calls', () => {
  15. let fn1 = utils.spy();
  16. let fn2 = utils.spy();
  17. fn1();
  18. expect( fn1.called ).to.be.true();
  19. expect( fn2.called ).to.not.be.true();
  20. } );
  21. } );
  22. describe( 'uid', () => {
  23. it( 'should return different ids', () => {
  24. let id1 = utils.uid();
  25. let id2 = utils.uid();
  26. let id3 = utils.uid();
  27. expect( id1 ).to.be.a( 'number' );
  28. expect( id2 ).to.be.a( 'number' ).to.not.equal( id1 ).to.not.equal( id3 );
  29. expect( id3 ).to.be.a( 'number' ).to.not.equal( id1 ).to.not.equal( id2 );
  30. } );
  31. } );
  32. describe( 'isIterable', () => {
  33. it( 'should be true for string', () => {
  34. let string = 'foo';
  35. expect( utils.isIterable( string ) ).to.be.true;
  36. } );
  37. it( 'should be true for arrays', () => {
  38. let array = [ 1, 2, 3 ];
  39. expect( utils.isIterable( array ) ).to.be.true;
  40. } );
  41. it( 'should be true for iterable classes', () => {
  42. class IterableClass {
  43. constructor() {
  44. this.array = [ 1, 2, 3 ];
  45. }
  46. [ Symbol.iterator ]() {
  47. return this.array[ Symbol.iterator ]();
  48. }
  49. }
  50. let instance = new IterableClass();
  51. expect( utils.isIterable( instance ) ).to.be.true;
  52. } );
  53. it( 'should be false for not iterable objects', () => {
  54. let notIterable = { foo: 'bar' };
  55. expect( utils.isIterable( notIterable ) ).to.be.false;
  56. } );
  57. it( 'should be false for undefined', () => {
  58. expect( utils.isIterable() ).to.be.false;
  59. } );
  60. } );
  61. describe( 'compareArrays', () => {
  62. it( 'should return SAME flag, when arrays are same', () => {
  63. let a = [ 'abc', 0, 3 ];
  64. let b = [ 'abc', 0, 3 ];
  65. let result = utils.compareArrays( a, b );
  66. expect( result ).to.equal( 'SAME' );
  67. } );
  68. it( 'should return PREFIX flag, when all n elements of first array are same as n first elements of the second array', () => {
  69. let a = [ 'abc', 0 ];
  70. let b = [ 'abc', 0, 3 ];
  71. let result = utils.compareArrays( a, b );
  72. expect( result ).to.equal( 'PREFIX' );
  73. } );
  74. it( 'should return EXTENSION flag, when n first elements of first array are same as all elements of the second array', () => {
  75. let a = [ 'abc', 0, 3 ];
  76. let b = [ 'abc', 0 ];
  77. let result = utils.compareArrays( a, b );
  78. expect( result ).to.equal( 'EXTENSION' );
  79. } );
  80. it( 'should return index on which arrays differ, when arrays are not the same', () => {
  81. let a = [ 'abc', 0, 3 ];
  82. let b = [ 'abc', 1, 3 ];
  83. let result = utils.compareArrays( a, b );
  84. expect( result ).to.equal( 1 );
  85. } );
  86. } );
  87. describe( 'toMap', () => {
  88. it( 'should create map from object', () => {
  89. const map = utils.toMap( { foo: 1, bar: 2 } );
  90. expect( getIteratorCount( map ) ).to.equal( 2 );
  91. expect( map.get( 'foo' ) ).to.equal( 1 );
  92. expect( map.get( 'bar' ) ).to.equal( 2 );
  93. } );
  94. it( 'should create map from iterator', () => {
  95. const map = utils.toMap( [ [ 'foo', 1 ], [ 'bar', 2 ] ] );
  96. expect( getIteratorCount( map ) ).to.equal( 2 );
  97. expect( map.get( 'foo' ) ).to.equal( 1 );
  98. expect( map.get( 'bar' ) ).to.equal( 2 );
  99. } );
  100. it( 'should create map from another map', () => {
  101. const data = new Map( [ [ 'foo', 1 ], [ 'bar', 2 ] ] );
  102. const map = utils.toMap( data );
  103. expect( getIteratorCount( map ) ).to.equal( 2 );
  104. expect( map.get( 'foo' ) ).to.equal( 1 );
  105. expect( map.get( 'bar' ) ).to.equal( 2 );
  106. } );
  107. } );
  108. describe( 'mapsEqual', () => {
  109. it( 'should return true if maps have exactly same entries (order of adding does not matter)', () => {
  110. let mapA = new Map();
  111. let mapB = new Map();
  112. mapA.set( 'foo', 'bar' );
  113. mapA.set( 'abc', 'xyz' );
  114. mapB.set( 'abc', 'xyz' );
  115. mapB.set( 'foo', 'bar' );
  116. expect( utils.mapsEqual( mapA, mapB ) ).to.be.true;
  117. } );
  118. } );
  119. describe( 'nth', () => {
  120. it( 'should return 0th item', () => {
  121. expect( utils.nth( 0, getIterator() ) ).to.equal( 11 );
  122. } );
  123. it( 'should return the last item', () => {
  124. expect( utils.nth( 2, getIterator() ) ).to.equal( 33 );
  125. } );
  126. it( 'should return null if out of range (bottom)', () => {
  127. expect( utils.nth( -1, getIterator() ) ).to.be.null;
  128. } );
  129. it( 'should return null if out of range (top)', () => {
  130. expect( utils.nth( 3, getIterator() ) ).to.be.null;
  131. } );
  132. it( 'should return null if iterator is empty', () => {
  133. expect( utils.nth( 0, [] ) ).to.be.null;
  134. } );
  135. function *getIterator() {
  136. yield 11;
  137. yield 22;
  138. yield 33;
  139. }
  140. } );
  141. describe( 'mix', () => {
  142. const MixinA = {
  143. a() {
  144. return 'a';
  145. }
  146. };
  147. const MixinB = {
  148. b() {
  149. return 'b';
  150. }
  151. };
  152. it( 'mixes 2nd+ argument\'s properties into the first class', () => {
  153. class Foo {}
  154. utils.mix( Foo, MixinA, MixinB );
  155. expect( Foo ).to.not.have.property( 'a' );
  156. expect( Foo ).to.not.have.property( 'b' );
  157. const foo = new Foo();
  158. expect( foo.a() ).to.equal( 'a' );
  159. expect( foo.b() ).to.equal( 'b' );
  160. } );
  161. it( 'does not break the instanceof operator', () => {
  162. class Foo {}
  163. utils.mix( Foo, MixinA );
  164. let foo = new Foo();
  165. expect( foo ).to.be.instanceof( Foo );
  166. } );
  167. it( 'defines properties with the same descriptors as native classes', () => {
  168. class Foo {
  169. foo() {}
  170. }
  171. utils.mix( Foo, MixinA );
  172. const actualDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, 'a' );
  173. const expectedDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, 'foo' );
  174. expect( actualDescriptor ).to.have.property( 'writable', expectedDescriptor.writable );
  175. expect( actualDescriptor ).to.have.property( 'enumerable', expectedDescriptor.enumerable );
  176. expect( actualDescriptor ).to.have.property( 'configurable', expectedDescriptor.configurable );
  177. } );
  178. it( 'copies setters and getters (with descriptors as of native classes)', () => {
  179. class Foo {
  180. set foo( v ) {
  181. this._foo = v;
  182. }
  183. get foo() {}
  184. }
  185. const Mixin = {
  186. set a( v ) {
  187. this._a = v;
  188. },
  189. get a() {
  190. return this._a;
  191. }
  192. };
  193. utils.mix( Foo, Mixin );
  194. const actualDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, 'a' );
  195. const expectedDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, 'foo' );
  196. expect( actualDescriptor ).to.have.property( 'enumerable', expectedDescriptor.enumerable );
  197. expect( actualDescriptor ).to.have.property( 'configurable', expectedDescriptor.configurable );
  198. const foo = new Foo();
  199. foo.a = 1;
  200. expect( foo._a ).to.equal( 1 );
  201. foo._a = 2;
  202. expect( foo.a ).to.equal( 2 );
  203. } );
  204. it( 'copies symbols (with descriptors as of native classes)', () => {
  205. const symbolA = Symbol( 'a' );
  206. const symbolFoo = Symbol( 'foo' );
  207. // https://github.com/jscs-dev/node-jscs/issues/2078
  208. // jscs:disable disallowSpacesInFunction
  209. class Foo {
  210. [ symbolFoo ]() {
  211. return 'foo';
  212. }
  213. }
  214. const Mixin = {
  215. [ symbolA ]() {
  216. return 'a';
  217. }
  218. };
  219. // jscs:enable disallowSpacesInFunction
  220. utils.mix( Foo, Mixin );
  221. const actualDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, symbolA );
  222. const expectedDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, symbolFoo );
  223. expect( actualDescriptor ).to.have.property( 'writable', expectedDescriptor.writable );
  224. expect( actualDescriptor ).to.have.property( 'enumerable', expectedDescriptor.enumerable );
  225. expect( actualDescriptor ).to.have.property( 'configurable', expectedDescriptor.configurable );
  226. const foo = new Foo();
  227. expect( foo[ symbolA ]() ).to.equal( 'a' );
  228. } );
  229. it( 'does not copy already existing properties', () => {
  230. class Foo {
  231. a() {
  232. return 'foo';
  233. }
  234. }
  235. utils.mix( Foo, MixinA, MixinB );
  236. const foo = new Foo();
  237. expect( foo.a() ).to.equal( 'foo' );
  238. expect( foo.b() ).to.equal( 'b' );
  239. } );
  240. it( 'does not copy already existing properties - properties deep in the proto chain', () => {
  241. class Foo {
  242. a() {
  243. return 'foo';
  244. }
  245. }
  246. class Bar extends Foo {}
  247. utils.mix( Bar, MixinA, MixinB );
  248. const bar = new Bar();
  249. expect( bar.a() ).to.equal( 'foo' );
  250. expect( bar.b() ).to.equal( 'b' );
  251. } );
  252. } );
  253. describe( 'count', () => {
  254. it( 'should returns number of editable items', () => {
  255. const count = utils.count( [ 1, 2, 3, 4, 5 ] );
  256. expect( count ).to.equal( 5 );
  257. } );
  258. } );
  259. } );