blob: 43e4f8500347deb3835e6d347d50096829bf7d93 [file] [log] [blame]
Sean Condon83fc39f2018-04-19 18:56:13 +01001/*
2 * Copyright 2014-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16import { TestBed, inject } from '@angular/core/testing';
17
Sean Condon2aa86092018-07-16 09:04:05 +010018import { LogService } from '../../log.service';
19import { ConsoleLoggerService } from '../../consolelogger.service';
20import { FnService } from '../../fw/util/fn.service';
Sean Condon49e15be2018-05-16 16:58:29 +010021import { ActivatedRoute, Params } from '@angular/router';
22import { of } from 'rxjs';
Sean Condonfd6d11b2018-06-02 20:29:49 +010023import * as d3 from 'd3';
Sean Condon49e15be2018-05-16 16:58:29 +010024
25class MockActivatedRoute extends ActivatedRoute {
26 constructor(params: Params) {
27 super();
28 this.queryParams = of(params);
29 }
30}
Sean Condon83fc39f2018-04-19 18:56:13 +010031
32/**
33 * ONOS GUI -- Util -- General Purpose Functions - Unit Tests
34 */
35describe('FnService', () => {
Sean Condon49e15be2018-05-16 16:58:29 +010036 let ar: ActivatedRoute;
Sean Condonfd6d11b2018-06-02 20:29:49 +010037 let fs: FnService;
38 let mockWindow: Window;
39 let logServiceSpy: jasmine.SpyObj<LogService>;
40
41 const someFunction = () => {};
42 const someArray = [1, 2, 3];
43 const someObject = { foo: 'bar'};
44 const someNumber = 42;
45 const someString = 'xyyzy';
46 const someDate = new Date();
47 const stringArray = ['foo', 'bar'];
Sean Condon83fc39f2018-04-19 18:56:13 +010048
Sean Condon49e15be2018-05-16 16:58:29 +010049 beforeEach(() => {
Sean Condonfd6d11b2018-06-02 20:29:49 +010050 const logSpy = jasmine.createSpyObj('LogService', ['debug', 'warn']);
Sean Condon49e15be2018-05-16 16:58:29 +010051 ar = new MockActivatedRoute({'debug': 'TestService'});
Sean Condonfd6d11b2018-06-02 20:29:49 +010052 mockWindow = <any>{
53 innerWidth: 400,
54 innerHeight: 200,
55 navigator: {
56 userAgent: 'defaultUA'
57 }
58 };
59
Sean Condon49e15be2018-05-16 16:58:29 +010060
61 TestBed.configureTestingModule({
62 providers: [FnService,
Sean Condonfd6d11b2018-06-02 20:29:49 +010063 { provide: LogService, useValue: logSpy },
Sean Condon49e15be2018-05-16 16:58:29 +010064 { provide: ActivatedRoute, useValue: ar },
Sean Condona00bf382018-06-23 07:54:01 +010065 { provide: 'Window', useFactory: (() => mockWindow ) }
Sean Condon49e15be2018-05-16 16:58:29 +010066 ]
67 });
Sean Condonfd6d11b2018-06-02 20:29:49 +010068
69 fs = TestBed.get(FnService);
70 logServiceSpy = TestBed.get(LogService);
Sean Condon49e15be2018-05-16 16:58:29 +010071 });
72
Sean Condonfd6d11b2018-06-02 20:29:49 +010073 it('should be created', () => {
74 expect(fs).toBeTruthy();
75 });
76
77 // === Tests for isF()
78 it('isF(): null for undefined', () => {
79 expect(fs.isF(undefined)).toBeNull();
80 });
81
82 it('isF(): null for null', () => {
83 expect(fs.isF(null)).toBeNull();
84 });
85 it('isF(): the reference for function', () => {
86 expect(fs.isF(someFunction)).toBe(someFunction);
87 });
88 it('isF(): null for string', () => {
89 expect(fs.isF(someString)).toBeNull();
90 });
91 it('isF(): null for number', () => {
92 expect(fs.isF(someNumber)).toBeNull();
93 });
94 it('isF(): null for Date', () => {
95 expect(fs.isF(someDate)).toBeNull();
96 });
97 it('isF(): null for array', () => {
98 expect(fs.isF(someArray)).toBeNull();
99 });
100 it('isF(): null for object', () => {
101 expect(fs.isF(someObject)).toBeNull();
102 });
103
104 // === Tests for isA()
105 it('isA(): null for undefined', () => {
106 expect(fs.isA(undefined)).toBeNull();
107 });
108 it('isA(): null for null', () => {
109 expect(fs.isA(null)).toBeNull();
110 });
111 it('isA(): null for function', () => {
112 expect(fs.isA(someFunction)).toBeNull();
113 });
114 it('isA(): null for string', () => {
115 expect(fs.isA(someString)).toBeNull();
116 });
117 it('isA(): null for number', () => {
118 expect(fs.isA(someNumber)).toBeNull();
119 });
120 it('isA(): null for Date', () => {
121 expect(fs.isA(someDate)).toBeNull();
122 });
123 it('isA(): the reference for array', () => {
124 expect(fs.isA(someArray)).toBe(someArray);
125 });
126 it('isA(): null for object', () => {
127 expect(fs.isA(someObject)).toBeNull();
128 });
129
130 // === Tests for isS()
131 it('isS(): null for undefined', () => {
132 expect(fs.isS(undefined)).toBeNull();
133 });
134 it('isS(): null for null', () => {
135 expect(fs.isS(null)).toBeNull();
136 });
137 it('isS(): null for function', () => {
138 expect(fs.isS(someFunction)).toBeNull();
139 });
140 it('isS(): the reference for string', () => {
141 expect(fs.isS(someString)).toBe(someString);
142 });
143 it('isS(): null for number', () => {
144 expect(fs.isS(someNumber)).toBeNull();
145 });
146 it('isS(): null for Date', () => {
147 expect(fs.isS(someDate)).toBeNull();
148 });
149 it('isS(): null for array', () => {
150 expect(fs.isS(someArray)).toBeNull();
151 });
152 it('isS(): null for object', () => {
153 expect(fs.isS(someObject)).toBeNull();
154 });
155
156 // === Tests for isO()
157 it('isO(): null for undefined', () => {
158 expect(fs.isO(undefined)).toBeNull();
159 });
160 it('isO(): null for null', () => {
161 expect(fs.isO(null)).toBeNull();
162 });
163 it('isO(): null for function', () => {
164 expect(fs.isO(someFunction)).toBeNull();
165 });
166 it('isO(): null for string', () => {
167 expect(fs.isO(someString)).toBeNull();
168 });
169 it('isO(): null for number', () => {
170 expect(fs.isO(someNumber)).toBeNull();
171 });
172 it('isO(): null for Date', () => {
173 expect(fs.isO(someDate)).toBeNull();
174 });
175 it('isO(): null for array', () => {
176 expect(fs.isO(someArray)).toBeNull();
177 });
178 it('isO(): the reference for object', () => {
179 expect(fs.isO(someObject)).toBe(someObject);
180 });
181
182
183 // === Tests for contains()
184 it('contains(): false for non-array', () => {
185 expect(fs.contains(null, 1)).toBeFalsy();
186 });
187 it('contains(): true for contained item', () => {
188 expect(fs.contains(someArray, 1)).toBeTruthy();
189 expect(fs.contains(stringArray, 'bar')).toBeTruthy();
190 });
191 it('contains(): false for non-contained item', () => {
192 expect(fs.contains(someArray, 109)).toBeFalsy();
193 expect(fs.contains(stringArray, 'zonko')).toBeFalsy();
194 });
195
196 // === Tests for areFunctions()
197 it('areFunctions(): true for empty-array', () => {
198 expect(fs.areFunctions({}, [])).toBeTruthy();
199 });
200 it('areFunctions(): true for some api', () => {
201 expect(fs.areFunctions({
202 a: () => {},
203 b: () => {}
204 }, ['b', 'a'])).toBeTruthy();
205 });
206 it('areFunctions(): false for some other api', () => {
207 expect(fs.areFunctions({
208 a: () => {},
209 b: 'not-a-function'
210 }, ['b', 'a'])).toBeFalsy();
211 });
212 it('areFunctions(): extraneous stuff NOT ignored', () => {
213 expect(fs.areFunctions({
214 a: () => {},
215 b: () => {},
216 c: 1,
217 d: 'foo'
218 }, ['a', 'b'])).toBeFalsy();
219 });
220 it('areFunctions(): extraneous stuff ignored (alternate fn)', () => {
221 expect(fs.areFunctionsNonStrict({
222 a: () => {},
223 b: () => {},
224 c: 1,
225 d: 'foo'
226 }, ['a', 'b'])).toBeTruthy();
227 });
228
229 // == use the now-tested areFunctions() on our own api:
230 it('should define api functions', () => {
231 expect(fs.areFunctions(fs, [
232 'isF', 'isA', 'isS', 'isO', 'contains',
233 'areFunctions', 'areFunctionsNonStrict', 'windowSize',
234 'isMobile', 'isChrome', 'isChromeHeadless', 'isSafari',
235 'isFirefox', 'parseDebugFlags',
236 'debugOn', 'debug', 'find', 'inArray', 'removeFromArray',
237 'isEmptyObject', 'cap', 'noPx', 'noPxStyle', 'endsWith',
Sean Condon2bd11b72018-06-15 08:00:48 +0100238 'inEvilList', 'analyze', 'sanitize', 'sameObjProps', 'containsObj'
Sean Condonfd6d11b2018-06-02 20:29:49 +0100239// 'find', 'inArray', 'removeFromArray', 'isEmptyObject', 'sameObjProps', 'containsObj', 'cap',
240// 'eecode', 'noPx', 'noPxStyle', 'endsWith', 'addToTrie', 'removeFromTrie', 'trieLookup',
241// 'classNames', 'extend', 'sanitize'
242 ])).toBeTruthy();
243 });
244
245
246 // === Tests for windowSize()
247 it('windowSize(): adjust height', () => {
248 const dim = fs.windowSize(50);
249 expect(dim.width).toEqual(400);
250 expect(dim.height).toEqual(150);
251 });
252
253 it('windowSize(): adjust width', () => {
254 const dim = fs.windowSize(0, 50);
255 expect(dim.width).toEqual(350);
256 expect(dim.height).toEqual(200);
257 });
258
259 it('windowSize(): adjust width and height', () => {
260 const dim = fs.windowSize(101, 201);
261 expect(dim.width).toEqual(199);
262 expect(dim.height).toEqual(99);
263 });
264
265 // === Tests for isMobile()
266 const uaMap = {
267 chrome: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) ' +
268 'AppleWebKit/537.36 (KHTML, like Gecko) ' +
269 'Chrome/41.0.2272.89 Safari/537.36',
270
271 iPad: 'Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) ' +
272 'AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 ' +
273 'Mobile/11A465 Safari/9537.53',
274
275 iPhone: 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) ' +
276 'AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 ' +
277 'Mobile/11A465 Safari/9537.53'
278 };
279
280 function setUa(key) {
281 const str = uaMap[key];
282 expect(str).toBeTruthy();
283 (<any>mockWindow.navigator).userAgent = str;
284 }
285
286 it('isMobile(): should be false for Chrome on Mac OS X', () => {
287 setUa('chrome');
288 expect(fs.isMobile()).toBe(false);
289 });
290 it('isMobile(): should be true for Safari on iPad', () => {
291 setUa('iPad');
292 expect(fs.isMobile()).toBe(true);
293 });
294 it('isMobile(): should be true for Safari on iPhone', () => {
295 setUa('iPhone');
296 expect(fs.isMobile()).toBe(true);
297 });
298
299 // === Tests for find()
300 const dataset = [
301 { id: 'foo', name: 'Furby'},
302 { id: 'bar', name: 'Barbi'},
303 { id: 'baz', name: 'Basil'},
304 { id: 'goo', name: 'Gabby'},
305 { id: 'zoo', name: 'Zevvv'}
306 ];
307
308 it('should not find ooo', () => {
309 expect(fs.find('ooo', dataset)).toEqual(-1);
310 });
311 it('should find foo', () => {
312 expect(fs.find('foo', dataset)).toEqual(0);
313 });
314 it('should find zoo', () => {
315 expect(fs.find('zoo', dataset)).toEqual(4);
316 });
317
318 it('should not find Simon', () => {
319 expect(fs.find('Simon', dataset, 'name')).toEqual(-1);
320 });
321 it('should find Furby', () => {
322 expect(fs.find('Furby', dataset, 'name')).toEqual(0);
323 });
324 it('should find Zevvv', () => {
325 expect(fs.find('Zevvv', dataset, 'name')).toEqual(4);
326 });
327
328
329 // === Tests for inArray()
330 const objRef = { x: 1, y: 2 };
331 const array = [1, 3.14, 'hey', objRef, 'there', true];
332 const array2 = ['b', 'a', 'd', 'a', 's', 's'];
333
334 it('should not find HOO', () => {
335 expect(fs.inArray('HOO', array)).toEqual(-1);
336 });
337 it('should find 1', () => {
338 expect(fs.inArray(1, array)).toEqual(0);
339 });
340 it('should find pi', () => {
341 expect(fs.inArray(3.14, array)).toEqual(1);
342 });
343 it('should find hey', () => {
344 expect(fs.inArray('hey', array)).toEqual(2);
345 });
346 it('should find the object', () => {
347 expect(fs.inArray(objRef, array)).toEqual(3);
348 });
349 it('should find there', () => {
350 expect(fs.inArray('there', array)).toEqual(4);
351 });
352 it('should find true', () => {
353 expect(fs.inArray(true, array)).toEqual(5);
354 });
355
356 it('should find the first occurrence A', () => {
357 expect(fs.inArray('a', array2)).toEqual(1);
358 });
359 it('should find the first occurrence S', () => {
360 expect(fs.inArray('s', array2)).toEqual(4);
361 });
362 it('should not find X', () => {
363 expect(fs.inArray('x', array2)).toEqual(-1);
364 });
365
366 // === Tests for removeFromArray()
367 it('should keep the array the same, for non-match', () => {
368 const array1 = [1, 2, 3];
369 expect(fs.removeFromArray(4, array1)).toBe(false);
370 expect(array1).toEqual([1, 2, 3]);
371 });
372 it('should remove a value', () => {
373 const array1a = [1, 2, 3];
374 expect(fs.removeFromArray(2, array1a)).toBe(true);
375 expect(array1a).toEqual([1, 3]);
376 });
377 it('should remove the first occurrence', () => {
378 const array1b = ['x', 'y', 'z', 'z', 'y'];
379 expect(fs.removeFromArray('y', array1b)).toBe(true);
380 expect(array1b).toEqual(['x', 'z', 'z', 'y']);
381 expect(fs.removeFromArray('x', array1b)).toBe(true);
382 expect(array1b).toEqual(['z', 'z', 'y']);
383 });
384
385 // === Tests for isEmptyObject()
386 it('should return true if an object is empty', () => {
387 expect(fs.isEmptyObject({})).toBe(true);
388 });
389 it('should return false if an object is not empty', () => {
390 expect(fs.isEmptyObject({foo: 'bar'})).toBe(false);
391 });
392
393 // === Tests for cap()
394 it('should ignore non-alpha', () => {
395 expect(fs.cap('123')).toEqual('123');
396 });
397 it('should capitalize first char', () => {
398 expect(fs.cap('Foo')).toEqual('Foo');
399 expect(fs.cap('foo')).toEqual('Foo');
400 expect(fs.cap('foo bar')).toEqual('Foo bar');
401 expect(fs.cap('FOO BAR')).toEqual('Foo bar');
402 expect(fs.cap('foo Bar')).toEqual('Foo bar');
403 });
404
405 // === Tests for noPx()
406 it('should return the value without px suffix', () => {
407 expect(fs.noPx('10px')).toBe(10);
408 expect(fs.noPx('500px')).toBe(500);
409 expect(fs.noPx('-80px')).toBe(-80);
410 });
411
412 // === Tests for noPxStyle()
413 it('should give a style\'s property without px suffix', () => {
414 const d3Elem = d3.select('body')
415 .append('div')
416 .attr('id', 'fooElem')
417 .style('width', '500px')
418 .style('height', '200px')
419 .style('font-size', '12px');
420 expect(fs.noPxStyle(d3Elem, 'width')).toBe(500);
421 expect(fs.noPxStyle(d3Elem, 'height')).toBe(200);
422 expect(fs.noPxStyle(d3Elem, 'font-size')).toBe(12);
423 d3.select('#fooElem').remove();
424 });
425
426 // === Tests for endsWith()
427 it('should return true if string ends with foo', () => {
428 expect(fs.endsWith('barfoo', 'foo')).toBe(true);
429 });
430
431 it('should return false if string doesnt end with foo', () => {
432 expect(fs.endsWith('barfood', 'foo')).toBe(false);
433 });
434
435 // === Tests for sanitize()
436 it('should return foo', () => {
437 expect(fs.sanitize('foo')).toEqual('foo');
438 });
439 it('should retain < b > tags', () => {
440 const str = 'foo <b>bar</b> baz';
441 expect(fs.sanitize(str)).toEqual(str);
442 });
443 it('should retain < i > tags', () => {
444 const str = 'foo <i>bar</i> baz';
445 expect(fs.sanitize(str)).toEqual(str);
446 });
447 it('should retain < p > tags', () => {
448 const str = 'foo <p>bar</p> baz';
449 expect(fs.sanitize(str)).toEqual(str);
450 });
451 it('should retain < em > tags', () => {
452 const str = 'foo <em>bar</em> baz';
453 expect(fs.sanitize(str)).toEqual(str);
454 });
455 it('should retain < strong > tags', () => {
456 const str = 'foo <strong>bar</strong> baz';
457 expect(fs.sanitize(str)).toEqual(str);
458 });
459
460 it('should reject < a > tags', () => {
461 expect(fs.sanitize('test <a href="hah">something</a> this'))
462 .toEqual('test something this');
463 });
464
465 it('should log a warning for < script > tags', () => {
466 expect(fs.sanitize('<script>alert("foo");</script>'))
467 .toEqual('');
468 expect(logServiceSpy.warn).toHaveBeenCalledWith(
469 'Unsanitary HTML input -- <script> detected!'
470 );
471 });
472 it('should log a warning for < style > tags', () => {
473 expect(fs.sanitize('<style> h1 {color:red;} </style>'))
474 .toEqual('');
475 expect(logServiceSpy.warn).toHaveBeenCalledWith(
476 'Unsanitary HTML input -- <style> detected!'
477 );
478 });
479
480 it('should log a warning for < iframe > tags', () => {
481 expect(fs.sanitize('Foo<iframe><body><h1>fake</h1></body></iframe>Bar'))
482 .toEqual('FooBar');
483 expect(logServiceSpy.warn).toHaveBeenCalledWith(
484 'Unsanitary HTML input -- <iframe> detected!'
485 );
486 });
487
488 it('should completely strip < script >, remove < a >, retain < i >', () => {
489 expect(fs.sanitize('Hey <i>this</i> is <script>alert("foo");</script> <a href="meh">cool</a>'))
490 .toEqual('Hey <i>this</i> is cool');
491 });
Sean Condon83fc39f2018-04-19 18:56:13 +0100492});