Adrià Vilanova Martínez | f19ea43 | 2024-01-23 20:20:52 +0100 | [diff] [blame] | 1 | // Copyright 2019 The Chromium Authors |
Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | import {assert} from 'chai'; |
| 6 | import {arrayDifference, setHasAny, capitalizeFirst, hasPrefix, objectToMap, |
| 7 | objectValuesForKeys, equalsIgnoreCase, immutableSplice, userIsMember, |
Adrià Vilanova Martínez | f19ea43 | 2024-01-23 20:20:52 +0100 | [diff] [blame] | 8 | urlWithNewParams, createObjectComparisonFunc, generateProjectIssueURL} from './helpers.js'; |
Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 9 | |
| 10 | describe('arrayDifference', () => { |
| 11 | it('empty array stays empty', () => { |
| 12 | assert.deepEqual(arrayDifference([], []), []); |
| 13 | assert.deepEqual(arrayDifference([], undefined), []); |
| 14 | assert.deepEqual(arrayDifference([], ['a']), []); |
| 15 | }); |
| 16 | |
| 17 | it('subtracting empty array does nothing', () => { |
| 18 | assert.deepEqual(arrayDifference(['a'], []), ['a']); |
| 19 | assert.deepEqual(arrayDifference([1, 2, 3], []), [1, 2, 3]); |
| 20 | assert.deepEqual(arrayDifference([1, 2, 'test'], []), [1, 2, 'test']); |
| 21 | assert.deepEqual(arrayDifference([1, 2, 'test'], undefined), |
| 22 | [1, 2, 'test']); |
| 23 | }); |
| 24 | |
| 25 | it('subtracts elements from array', () => { |
| 26 | assert.deepEqual(arrayDifference(['a', 'b', 'c'], ['b', 'c']), ['a']); |
| 27 | assert.deepEqual(arrayDifference(['a', 'b', 'c'], ['a']), ['b', 'c']); |
| 28 | assert.deepEqual(arrayDifference(['a', 'b', 'c'], ['b']), ['a', 'c']); |
| 29 | assert.deepEqual(arrayDifference([1, 2, 3], [2]), [1, 3]); |
| 30 | }); |
| 31 | |
| 32 | it('does not subtract missing elements from array', () => { |
| 33 | assert.deepEqual(arrayDifference(['a', 'b', 'c'], ['d']), ['a', 'b', 'c']); |
| 34 | assert.deepEqual(arrayDifference([1, 2, 3], [5]), [1, 2, 3]); |
| 35 | assert.deepEqual(arrayDifference([1, 2, 3], [-1, 2]), [1, 3]); |
| 36 | }); |
| 37 | |
| 38 | it('custom equals function', () => { |
| 39 | assert.deepEqual(arrayDifference(['a', 'b'], ['A']), ['a', 'b']); |
| 40 | assert.deepEqual(arrayDifference(['a', 'b'], ['A'], equalsIgnoreCase), |
| 41 | ['b']); |
| 42 | }); |
| 43 | }); |
| 44 | |
| 45 | describe('setHasAny', () => { |
| 46 | it('empty set never has any values', () => { |
| 47 | assert.isFalse(setHasAny(new Set(), [])); |
| 48 | assert.isFalse(setHasAny(new Set(), ['test'])); |
| 49 | assert.isFalse(setHasAny(new Set(), ['nope', 'yup', 'no'])); |
| 50 | }); |
| 51 | |
| 52 | it('false when no values found', () => { |
| 53 | assert.isFalse(setHasAny(new Set(['hello', 'world']), [])); |
| 54 | assert.isFalse(setHasAny(new Set(['hello', 'world']), ['wor'])); |
| 55 | assert.isFalse(setHasAny(new Set(['test']), ['other', 'values'])); |
| 56 | assert.isFalse(setHasAny(new Set([1, 2, 3]), [4, 5, 6])); |
| 57 | }); |
| 58 | |
| 59 | it('true when values found', () => { |
| 60 | assert.isTrue(setHasAny(new Set(['hello', 'world']), ['world'])); |
| 61 | assert.isTrue(setHasAny(new Set([1, 2, 3]), [3, 4, 5])); |
| 62 | assert.isTrue(setHasAny(new Set([1, 2, 3]), [1, 3])); |
| 63 | }); |
| 64 | }); |
| 65 | |
| 66 | describe('capitalizeFirst', () => { |
| 67 | it('empty string', () => { |
| 68 | assert.equal(capitalizeFirst(''), ''); |
| 69 | }); |
| 70 | |
| 71 | it('ignores non-letters', () => { |
| 72 | assert.equal(capitalizeFirst('8fcsdf'), '8fcsdf'); |
| 73 | }); |
| 74 | |
| 75 | it('preserves existing caps', () => { |
| 76 | assert.equal(capitalizeFirst('HELLO world'), 'HELLO world'); |
| 77 | }); |
| 78 | |
| 79 | it('capitalizes lowercase', () => { |
| 80 | assert.equal(capitalizeFirst('hello world'), 'Hello world'); |
| 81 | }); |
| 82 | }); |
| 83 | |
| 84 | describe('hasPrefix', () => { |
| 85 | it('only true when has prefix', () => { |
| 86 | assert.isFalse(hasPrefix('teststring', 'test-')); |
| 87 | assert.isFalse(hasPrefix('stringtest-', 'test-')); |
| 88 | assert.isFalse(hasPrefix('^test-$', 'test-')); |
| 89 | assert.isTrue(hasPrefix('test-', 'test-')); |
| 90 | assert.isTrue(hasPrefix('test-fsdfsdf', 'test-')); |
| 91 | }); |
| 92 | |
| 93 | it('ignores case when checking prefix', () => { |
| 94 | assert.isTrue(hasPrefix('TEST-string', 'test-')); |
| 95 | assert.isTrue(hasPrefix('test-string', 'test-')); |
| 96 | assert.isTrue(hasPrefix('tEsT-string', 'test-')); |
| 97 | }); |
| 98 | }); |
| 99 | |
| 100 | describe('objectToMap', () => { |
| 101 | it('converts Object to Map with the same keys', () => { |
| 102 | assert.deepEqual(objectToMap({}), new Map()); |
| 103 | assert.deepEqual(objectToMap({test: 'value'}), |
| 104 | new Map([['test', 'value']])); |
| 105 | assert.deepEqual(objectToMap({['weird:key']: 'value', |
| 106 | ['what is this key']: 'v2'}), new Map([['weird:key', 'value'], |
| 107 | ['what is this key', 'v2']])); |
| 108 | }); |
| 109 | }); |
| 110 | |
| 111 | describe('objectValuesForKeys', () => { |
| 112 | it('no values when no matching keys', () => { |
| 113 | assert.deepEqual(objectValuesForKeys({}, []), []); |
| 114 | assert.deepEqual(objectValuesForKeys({}, []), []); |
| 115 | assert.deepEqual(objectValuesForKeys({key: 'value'}, []), []); |
| 116 | }); |
| 117 | |
| 118 | it('returns values when keys match', () => { |
| 119 | assert.deepEqual(objectValuesForKeys({a: 1, b: 2, c: 3}, ['a', 'b']), |
| 120 | [1, 2]); |
| 121 | assert.deepEqual(objectValuesForKeys({a: 1, b: 2, c: 3}, ['b', 'c']), |
| 122 | [2, 3]); |
| 123 | assert.deepEqual(objectValuesForKeys({['weird:key']: {nested: 'obj'}}, |
| 124 | ['weird:key']), [{nested: 'obj'}]); |
| 125 | }); |
| 126 | |
| 127 | it('sets non-matching keys to undefined', () => { |
| 128 | assert.deepEqual(objectValuesForKeys({a: 1, b: 2, c: 3}, ['c', 'd', 'e']), |
| 129 | [3, undefined, undefined]); |
| 130 | assert.deepEqual(objectValuesForKeys({a: 1, b: 2, c: 3}, [1, 2, 3]), |
| 131 | [undefined, undefined, undefined]); |
| 132 | }); |
| 133 | }); |
| 134 | |
| 135 | describe('equalsIgnoreCase', () => { |
| 136 | it('matches same case strings', () => { |
| 137 | assert.isTrue(equalsIgnoreCase('', '')); |
| 138 | assert.isTrue(equalsIgnoreCase('HelloWorld', 'HelloWorld')); |
| 139 | assert.isTrue(equalsIgnoreCase('hmm', 'hmm')); |
| 140 | assert.isTrue(equalsIgnoreCase('TEST', 'TEST')); |
| 141 | }); |
| 142 | |
| 143 | it('matches different case strings', () => { |
| 144 | assert.isTrue(equalsIgnoreCase('a', 'A')); |
| 145 | assert.isTrue(equalsIgnoreCase('HelloWorld', 'helloworld')); |
| 146 | assert.isTrue(equalsIgnoreCase('hmm', 'HMM')); |
| 147 | assert.isTrue(equalsIgnoreCase('TEST', 'teSt')); |
| 148 | }); |
| 149 | |
| 150 | it('does not match different strings', () => { |
| 151 | assert.isFalse(equalsIgnoreCase('hello', 'hello ')); |
| 152 | assert.isFalse(equalsIgnoreCase('superstring', 'string')); |
| 153 | assert.isFalse(equalsIgnoreCase('aaa', 'aa')); |
| 154 | }); |
| 155 | }); |
| 156 | |
| 157 | describe('immutableSplice', () => { |
| 158 | it('does not edit original array', () => { |
| 159 | const arr = ['apples', 'pears', 'oranges']; |
| 160 | |
| 161 | assert.deepEqual(immutableSplice(arr, 1, 1), |
| 162 | ['apples', 'oranges']); |
| 163 | |
| 164 | assert.deepEqual(arr, ['apples', 'pears', 'oranges']); |
| 165 | }); |
| 166 | |
| 167 | it('removes multiple items', () => { |
| 168 | const arr = [1, 2, 3, 4, 5, 6]; |
| 169 | |
| 170 | assert.deepEqual(immutableSplice(arr, 1, 0), [1, 2, 3, 4, 5, 6]); |
| 171 | assert.deepEqual(immutableSplice(arr, 1, 4), [1, 6]); |
| 172 | assert.deepEqual(immutableSplice(arr, 0, 6), []); |
| 173 | }); |
| 174 | |
| 175 | it('adds items', () => { |
| 176 | const arr = [1, 2, 3]; |
| 177 | |
| 178 | assert.deepEqual(immutableSplice(arr, 1, 1, 4, 5, 6), [1, 4, 5, 6, 3]); |
| 179 | assert.deepEqual(immutableSplice(arr, 2, 1, 4, 5, 6), [1, 2, 4, 5, 6]); |
| 180 | assert.deepEqual(immutableSplice(arr, 0, 0, -3, -2, -1, 0), |
| 181 | [-3, -2, -1, 0, 1, 2, 3]); |
| 182 | }); |
| 183 | }); |
| 184 | |
| 185 | describe('urlWithNewParams', () => { |
| 186 | it('empty', () => { |
| 187 | assert.equal(urlWithNewParams(), ''); |
| 188 | assert.equal(urlWithNewParams(''), ''); |
| 189 | assert.equal(urlWithNewParams('', {}), ''); |
| 190 | assert.equal(urlWithNewParams('', {}, {}), ''); |
| 191 | assert.equal(urlWithNewParams('', {}, {}, []), ''); |
| 192 | }); |
| 193 | |
| 194 | it('preserves existing URL without changes', () => { |
| 195 | assert.equal(urlWithNewParams('/p/chromium/issues/list'), |
| 196 | '/p/chromium/issues/list'); |
| 197 | assert.equal(urlWithNewParams('/p/chromium/issues/list', {q: 'owner:me'}), |
| 198 | '/p/chromium/issues/list?q=owner%3Ame'); |
| 199 | assert.equal( |
| 200 | urlWithNewParams('/p/chromium/issues/list', {q: 'owner:me', can: '1'}), |
| 201 | '/p/chromium/issues/list?q=owner%3Ame&can=1'); |
| 202 | }); |
| 203 | |
| 204 | it('adds new params', () => { |
| 205 | assert.equal( |
| 206 | urlWithNewParams('/p/chromium/issues/list', {}, {q: 'owner:me'}), |
| 207 | '/p/chromium/issues/list?q=owner%3Ame'); |
| 208 | assert.equal( |
| 209 | urlWithNewParams('/p/chromium/issues/list', |
| 210 | {can: '1'}, {q: 'owner:me'}), |
| 211 | '/p/chromium/issues/list?can=1&q=owner%3Ame'); |
| 212 | |
| 213 | // Override existing params. |
| 214 | assert.equal( |
| 215 | urlWithNewParams('/p/chromium/issues/list', |
| 216 | {can: '1', q: 'owner:me'}, {q: 'test'}), |
| 217 | '/p/chromium/issues/list?can=1&q=test'); |
| 218 | }); |
| 219 | |
| 220 | it('clears existing params', () => { |
| 221 | assert.equal( |
| 222 | urlWithNewParams('/p/chromium/issues/list', {q: 'owner:me'}, {}, ['q']), |
| 223 | '/p/chromium/issues/list'); |
| 224 | assert.equal( |
| 225 | urlWithNewParams('/p/chromium/issues/list', |
| 226 | {can: '1'}, {q: 'owner:me'}, ['can']), |
| 227 | '/p/chromium/issues/list?q=owner%3Ame'); |
| 228 | assert.equal( |
| 229 | urlWithNewParams('/p/chromium/issues/list', {q: 'owner:me'}, {can: '2'}, |
| 230 | ['q', 'can', 'fakeparam']), |
| 231 | '/p/chromium/issues/list'); |
| 232 | }); |
| 233 | }); |
| 234 | |
| 235 | describe('userIsMember', () => { |
| 236 | it('false when no user', () => { |
| 237 | assert.isFalse(userIsMember(undefined)); |
| 238 | assert.isFalse(userIsMember({})); |
| 239 | assert.isFalse(userIsMember({}, 'chromium', |
| 240 | new Map([['123', {ownerOf: ['chromium']}]]))); |
| 241 | }); |
| 242 | |
| 243 | it('true when user is member of project', () => { |
| 244 | assert.isTrue(userIsMember({userId: '123'}, 'chromium', |
| 245 | new Map([['123', {contributorTo: ['chromium']}]]))); |
| 246 | |
| 247 | assert.isTrue(userIsMember({userId: '123'}, 'chromium', |
| 248 | new Map([['123', {ownerOf: ['chromium']}]]))); |
| 249 | |
| 250 | assert.isTrue(userIsMember({userId: '123'}, 'chromium', |
| 251 | new Map([['123', {memberOf: ['chromium']}]]))); |
| 252 | }); |
| 253 | |
| 254 | it('true when user is member of multiple projects', () => { |
| 255 | assert.isTrue(userIsMember({userId: '123'}, 'chromium', new Map([ |
| 256 | ['123', {contributorTo: ['test', 'chromium', 'fakeproject']}], |
| 257 | ]))); |
| 258 | |
| 259 | assert.isTrue(userIsMember({userId: '123'}, 'chromium', new Map([ |
| 260 | ['123', {ownerOf: ['test', 'chromium', 'fakeproject']}], |
| 261 | ]))); |
| 262 | |
| 263 | assert.isTrue(userIsMember({userId: '123'}, 'chromium', new Map([ |
| 264 | ['123', {memberOf: ['test', 'chromium', 'fakeproject']}], |
| 265 | ]))); |
| 266 | }); |
| 267 | |
| 268 | it('false when user is member of different project', () => { |
| 269 | assert.isFalse(userIsMember({userId: '123'}, 'chromium', new Map([ |
| 270 | ['123', {contributorTo: ['test', 'fakeproject']}], |
| 271 | ]))); |
| 272 | |
| 273 | assert.isFalse(userIsMember({userId: '123'}, 'chromium', new Map([ |
| 274 | ['123', {ownerOf: ['test', 'fakeproject']}], |
| 275 | ]))); |
| 276 | |
| 277 | assert.isFalse(userIsMember({userId: '123'}, 'chromium', new Map([ |
| 278 | ['123', {memberOf: ['test', 'fakeproject']}], |
| 279 | ]))); |
| 280 | }); |
| 281 | |
| 282 | it('false when no project data for user', () => { |
| 283 | assert.isFalse(userIsMember({userId: '123'}, 'chromium')); |
| 284 | assert.isFalse(userIsMember({userId: '123'}, 'chromium', new Map())); |
| 285 | assert.isFalse(userIsMember({userId: '123'}, 'chromium', new Map([ |
| 286 | ['543', {ownerOf: ['chromium']}], |
| 287 | ]))); |
| 288 | }); |
| 289 | }); |
| 290 | |
| 291 | describe('createObjectComparisonFunc', () => { |
| 292 | it('returns a function', () => { |
| 293 | const result = createObjectComparisonFunc(new Set()); |
| 294 | assert.instanceOf(result, Function); |
| 295 | }); |
| 296 | |
| 297 | describe('returned function', () => { |
| 298 | it('returns false if both inputs are undefined', () => { |
| 299 | const comparableProps = new Set(['a', 'b', 'c']); |
| 300 | const func = createObjectComparisonFunc(comparableProps); |
| 301 | const result = func(undefined, undefined); |
| 302 | |
| 303 | assert.isFalse(result); |
| 304 | }); |
| 305 | |
| 306 | it('returns true if only one inputs is undefined', () => { |
| 307 | const comparableProps = new Set(['a', 'b', 'c']); |
| 308 | const func = createObjectComparisonFunc(comparableProps); |
| 309 | const result = func({}, undefined); |
| 310 | |
| 311 | assert.isTrue(result); |
| 312 | }); |
| 313 | |
| 314 | it('returns false if both inputs are null', () => { |
| 315 | const comparableProps = new Set(['a', 'b', 'c']); |
| 316 | const func = createObjectComparisonFunc(comparableProps); |
| 317 | const result = func(null, null); |
| 318 | |
| 319 | assert.isFalse(result); |
| 320 | }); |
| 321 | |
| 322 | it('returns true if only one inputs is null', () => { |
| 323 | const comparableProps = new Set(['a', 'b', 'c']); |
| 324 | const func = createObjectComparisonFunc(comparableProps); |
| 325 | const result = func({}, null); |
| 326 | |
| 327 | assert.isTrue(result); |
| 328 | }); |
| 329 | |
| 330 | it('returns true if any comparable property is different', () => { |
| 331 | const comparableProps = new Set(['a', 'b', 'c']); |
| 332 | const func = createObjectComparisonFunc(comparableProps); |
| 333 | const a = {a: 1, b: 2, c: 3}; |
| 334 | const b = {a: 1, b: 2, c: '3'}; |
| 335 | const result = func(a, b); |
| 336 | |
| 337 | assert.isTrue(result); |
| 338 | }); |
| 339 | |
| 340 | it('returns false if all comparable properties are the same', () => { |
| 341 | const comparableProps = new Set(['a', 'b', 'c']); |
| 342 | const func = createObjectComparisonFunc(comparableProps); |
| 343 | const a = {a: 1, b: 2, c: 3}; |
| 344 | const b = {a: 1, b: 2, c: 3}; |
| 345 | const result = func(a, b); |
| 346 | |
| 347 | assert.isFalse(result); |
| 348 | }); |
| 349 | |
| 350 | it('ignores non-comparable properties', () => { |
| 351 | const comparableProps = new Set(['a', 'b', 'c']); |
| 352 | const func = createObjectComparisonFunc(comparableProps); |
| 353 | const a = {a: 1, b: 2, c: 3, d: 4}; |
| 354 | const b = {a: 1, b: 2, c: 3, d: 'not four', e: 'exists'}; |
| 355 | const result = func(a, b); |
| 356 | |
| 357 | assert.isFalse(result); |
| 358 | }); |
| 359 | }); |
| 360 | }); |
Adrià Vilanova Martínez | f19ea43 | 2024-01-23 20:20:52 +0100 | [diff] [blame] | 361 | |
| 362 | describe('generateProjectIssueURL', () => { |
| 363 | it('no redirect required and no param', () => { |
| 364 | assert.equal(generateProjectIssueURL('project', '/list'), '/p/project/issues/list'); |
| 365 | }); |
| 366 | |
| 367 | it('no redirect required and with param', () => { |
| 368 | assert.equal(generateProjectIssueURL('project', '/detail', {'id': 123}), '/p/project/issues/detail?id=123'); |
| 369 | }); |
| 370 | |
| 371 | //TODO(crbug.com/monorail/12029): add more unit test. |
| 372 | }); |