Merge "Fix template problems with gr-search-bar"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
index c8b3901..f418cfa 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
@@ -23,7 +23,7 @@
lineNumberToNumber,
} from '../gr-diff/gr-diff-utils';
-const tokenMatcher = new RegExp(/[a-zA-Z0-9_-]+/g);
+const tokenMatcher = new RegExp(/[\w]+/g);
/** CSS class for all tokens. */
const CSS_TOKEN = 'token';
diff --git a/polygerrit-ui/app/utils/async-util_test.js b/polygerrit-ui/app/utils/async-util_test.js
deleted file mode 100644
index df29e97..0000000
--- a/polygerrit-ui/app/utils/async-util_test.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../test/common-test-setup-karma.js';
-import {asyncForeach} from './async-util.js';
-
-suite('async-util tests', () => {
- test('loops over each item', () => {
- const fn = sinon.stub().returns(Promise.resolve());
- return asyncForeach([1, 2, 3], fn)
- .then(() => {
- assert.isTrue(fn.calledThrice);
- assert.equal(fn.getCall(0).args[0], 1);
- assert.equal(fn.getCall(1).args[0], 2);
- assert.equal(fn.getCall(2).args[0], 3);
- });
- });
-
- test('halts on stop condition', () => {
- const stub = sinon.stub();
- const fn = (e, stop) => {
- stub(e);
- stop();
- return Promise.resolve();
- };
- return asyncForeach([1, 2, 3], fn)
- .then(() => {
- assert.isTrue(stub.calledOnce);
- assert.equal(stub.lastCall.args[0], 1);
- });
- });
-});
diff --git a/polygerrit-ui/app/utils/async-util_test.ts b/polygerrit-ui/app/utils/async-util_test.ts
new file mode 100644
index 0000000..5c8f610
--- /dev/null
+++ b/polygerrit-ui/app/utils/async-util_test.ts
@@ -0,0 +1,46 @@
+/**
+ * @license
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '../test/common-test-setup-karma';
+import {asyncForeach} from './async-util';
+
+suite('async-util tests', () => {
+ test('loops over each item', async () => {
+ const fn = sinon.stub().resolves();
+
+ await asyncForeach([1, 2, 3], fn);
+
+ assert.isTrue(fn.calledThrice);
+ assert.equal(fn.firstCall.firstArg, 1);
+ assert.equal(fn.secondCall.firstArg, 2);
+ assert.equal(fn.thirdCall.firstArg, 3);
+ });
+
+ test('halts on stop condition', async () => {
+ const stub = sinon.stub();
+ const fn = (item: number, stopCallback: () => void) => {
+ stub(item);
+ stopCallback();
+ return Promise.resolve();
+ };
+
+ await asyncForeach([1, 2, 3], fn);
+
+ assert.isTrue(stub.calledOnce);
+ assert.equal(stub.lastCall.firstArg, 1);
+ });
+});
diff --git a/polygerrit-ui/app/utils/date-util_test.js b/polygerrit-ui/app/utils/date-util_test.js
deleted file mode 100644
index 96d5bc1..0000000
--- a/polygerrit-ui/app/utils/date-util_test.js
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import '../test/common-test-setup-karma.js';
-import {isValidDate, parseDate, fromNow, isWithinDay, isWithinHalfYear, formatDate, wasYesterday} from './date-util.js';
-
-suite('date-util tests', () => {
- suite('parseDate', () => {
- test('parseDate server date', () => {
- const parsed = parseDate('2015-09-15 20:34:00.000000000');
- assert.equal('2015-09-15T20:34:00.000Z', parsed.toISOString());
- });
- });
-
- suite('isValidDate', () => {
- test('date is valid', () => {
- assert.isTrue(isValidDate(new Date()));
- });
- test('broken date is invalid', () => {
- assert.isFalse(isValidDate(new Date('xxx')));
- });
- });
-
- suite('fromNow', () => {
- test('test all variants', () => {
- const fakeNow = new Date('May 08 2020 12:00:00');
- sinon.useFakeTimers(fakeNow.getTime());
- assert.equal('just now', fromNow(new Date('May 08 2020 11:59:30')));
- assert.equal('1 minute ago', fromNow(new Date('May 08 2020 11:59:00')));
- assert.equal('5 minutes ago', fromNow(new Date('May 08 2020 11:55:00')));
- assert.equal('1 hour ago', fromNow(new Date('May 08 2020 11:00:00')));
- assert.equal(
- '1 hour 5 min ago', fromNow(new Date('May 08 2020 10:55:00')));
- assert.equal('3 hours ago', fromNow(new Date('May 08 2020 9:00:00')));
- assert.equal('1 day ago', fromNow(new Date('May 07 2020 12:00:00')));
- assert.equal('1 day 2 hr ago', fromNow(new Date('May 07 2020 10:00:00')));
- assert.equal('3 days ago', fromNow(new Date('May 05 2020 12:00:00')));
- assert.equal('1 month ago', fromNow(new Date('Apr 05 2020 12:00:00')));
- assert.equal('2 months ago', fromNow(new Date('Mar 05 2020 12:00:00')));
- assert.equal('1 year ago', fromNow(new Date('May 05 2019 12:00:00')));
- assert.equal('10 years ago', fromNow(new Date('May 05 2010 12:00:00')));
- });
- test('rounding error', () => {
- const fakeNow = new Date('May 08 2020 12:00:00');
- sinon.useFakeTimers(fakeNow.getTime());
- assert.equal('2 hours ago', fromNow(new Date('May 08 2020 9:30:00')));
- });
- });
-
- suite('isWithinDay', () => {
- test('basics works', () => {
- assert.isTrue(isWithinDay(new Date('May 08 2020 12:00:00'),
- new Date('May 08 2020 02:00:00')));
- assert.isFalse(isWithinDay(new Date('May 08 2020 12:00:00'),
- new Date('May 07 2020 12:00:00')));
- });
- });
-
- suite('wasYesterday', () => {
- test('less 24 hours', () => {
- assert.isFalse(wasYesterday(new Date('May 08 2020 12:00:00'),
- new Date('May 08 2020 02:00:00')));
- assert.isTrue(wasYesterday(new Date('May 08 2020 12:00:00'),
- new Date('May 07 2020 12:00:00')));
- });
- test('more 24 hours', () => {
- assert.isTrue(wasYesterday(new Date('May 08 2020 12:00:00'),
- new Date('May 07 2020 2:00:00')));
- assert.isFalse(wasYesterday(new Date('May 08 2020 12:00:00'),
- new Date('May 06 2020 14:00:00')));
- });
- });
-
- suite('isWithinHalfYear', () => {
- test('basics works', () => {
- assert.isTrue(isWithinHalfYear(new Date('May 08 2020 12:00:00'),
- new Date('Feb 08 2020 12:00:00')));
- assert.isFalse(isWithinHalfYear(new Date('May 08 2020 12:00:00'),
- new Date('Nov 07 2019 12:00:00')));
- });
- });
-
- suite('formatDate', () => {
- test('works for standard format', () => {
- const stdFormat = 'MMM DD, YYYY';
- assert.equal('May 08, 2020',
- formatDate(new Date('May 08 2020 12:00:00'), stdFormat));
- assert.equal('Feb 28, 2020',
- formatDate(new Date('Feb 28 2020 12:00:00'), stdFormat));
-
- const time24Format = 'HH:mm:ss';
- assert.equal('Feb 28, 2020 12:01:12',
- formatDate(new Date('Feb 28 2020 12:01:12'), stdFormat + ' '
- + time24Format));
- });
- test('works for euro format', () => {
- const euroFormat = 'DD.MM.YYYY';
- assert.equal('01.12.2019',
- formatDate(new Date('Dec 01 2019 12:00:00'), euroFormat));
- assert.equal('20.01.2002',
- formatDate(new Date('Jan 20 2002 12:00:00'), euroFormat));
-
- const time24Format = 'HH:mm:ss';
- assert.equal('28.02.2020 00:01:12',
- formatDate(new Date('Feb 28 2020 00:01:12'), euroFormat + ' '
- + time24Format));
- });
- test('works for iso format', () => {
- const isoFormat = 'YYYY-MM-DD';
- assert.equal('2015-01-01',
- formatDate(new Date('Jan 01 2015 12:00:00'), isoFormat));
- assert.equal('2013-07-03',
- formatDate(new Date('Jul 03 2013 12:00:00'), isoFormat));
-
- const timeFormat = 'h:mm:ss A';
- assert.equal('2013-07-03 5:00:00 AM',
- formatDate(new Date('Jul 03 2013 05:00:00'), isoFormat + ' '
- + timeFormat));
- assert.equal('2013-07-03 5:00:00 PM',
- formatDate(new Date('Jul 03 2013 17:00:00'), isoFormat + ' '
- + timeFormat));
- });
- test('h:mm:ss A shows correctly midnight and midday', () => {
- const timeFormat = 'h:mm A';
- assert.equal('12:14 PM',
- formatDate(new Date('Jul 03 2013 12:14:00'), timeFormat));
- assert.equal('12:15 AM',
- formatDate(new Date('Jul 03 2013 00:15:00'), timeFormat));
- });
- });
-});
diff --git a/polygerrit-ui/app/utils/date-util_test.ts b/polygerrit-ui/app/utils/date-util_test.ts
new file mode 100644
index 0000000..f17ced3
--- /dev/null
+++ b/polygerrit-ui/app/utils/date-util_test.ts
@@ -0,0 +1,219 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {Timestamp} from '../types/common';
+import '../test/common-test-setup-karma';
+import {
+ isValidDate,
+ parseDate,
+ fromNow,
+ isWithinDay,
+ isWithinHalfYear,
+ formatDate,
+ wasYesterday,
+} from './date-util';
+
+suite('date-util tests', () => {
+ suite('parseDate', () => {
+ test('parseDate server date', () => {
+ const parsed = parseDate('2015-09-15 20:34:00.000000000' as Timestamp);
+ assert.equal('2015-09-15T20:34:00.000Z', parsed.toISOString());
+ });
+ });
+
+ suite('isValidDate', () => {
+ test('date is valid', () => {
+ assert.isTrue(isValidDate(new Date()));
+ });
+ test('broken date is invalid', () => {
+ assert.isFalse(isValidDate(new Date('xxx')));
+ });
+ });
+
+ suite('fromNow', () => {
+ test('test all variants', () => {
+ const fakeNow = new Date('May 08 2020 12:00:00');
+ sinon.useFakeTimers(fakeNow.getTime());
+ assert.equal('just now', fromNow(new Date('May 08 2020 11:59:30')));
+ assert.equal('1 minute ago', fromNow(new Date('May 08 2020 11:59:00')));
+ assert.equal('5 minutes ago', fromNow(new Date('May 08 2020 11:55:00')));
+ assert.equal('1 hour ago', fromNow(new Date('May 08 2020 11:00:00')));
+ assert.equal(
+ '1 hour 5 min ago',
+ fromNow(new Date('May 08 2020 10:55:00'))
+ );
+ assert.equal('3 hours ago', fromNow(new Date('May 08 2020 9:00:00')));
+ assert.equal('1 day ago', fromNow(new Date('May 07 2020 12:00:00')));
+ assert.equal('1 day 2 hr ago', fromNow(new Date('May 07 2020 10:00:00')));
+ assert.equal('3 days ago', fromNow(new Date('May 05 2020 12:00:00')));
+ assert.equal('1 month ago', fromNow(new Date('Apr 05 2020 12:00:00')));
+ assert.equal('2 months ago', fromNow(new Date('Mar 05 2020 12:00:00')));
+ assert.equal('1 year ago', fromNow(new Date('May 05 2019 12:00:00')));
+ assert.equal('10 years ago', fromNow(new Date('May 05 2010 12:00:00')));
+ });
+ test('rounding error', () => {
+ const fakeNow = new Date('May 08 2020 12:00:00');
+ sinon.useFakeTimers(fakeNow.getTime());
+ assert.equal('2 hours ago', fromNow(new Date('May 08 2020 9:30:00')));
+ });
+ });
+
+ suite('isWithinDay', () => {
+ test('basics works', () => {
+ assert.isTrue(
+ isWithinDay(
+ new Date('May 08 2020 12:00:00'),
+ new Date('May 08 2020 02:00:00')
+ )
+ );
+ assert.isFalse(
+ isWithinDay(
+ new Date('May 08 2020 12:00:00'),
+ new Date('May 07 2020 12:00:00')
+ )
+ );
+ });
+ });
+
+ suite('wasYesterday', () => {
+ test('less 24 hours', () => {
+ assert.isFalse(
+ wasYesterday(
+ new Date('May 08 2020 12:00:00'),
+ new Date('May 08 2020 02:00:00')
+ )
+ );
+ assert.isTrue(
+ wasYesterday(
+ new Date('May 08 2020 12:00:00'),
+ new Date('May 07 2020 12:00:00')
+ )
+ );
+ });
+ test('more 24 hours', () => {
+ assert.isTrue(
+ wasYesterday(
+ new Date('May 08 2020 12:00:00'),
+ new Date('May 07 2020 2:00:00')
+ )
+ );
+ assert.isFalse(
+ wasYesterday(
+ new Date('May 08 2020 12:00:00'),
+ new Date('May 06 2020 14:00:00')
+ )
+ );
+ });
+ });
+
+ suite('isWithinHalfYear', () => {
+ test('basics works', () => {
+ assert.isTrue(
+ isWithinHalfYear(
+ new Date('May 08 2020 12:00:00'),
+ new Date('Feb 08 2020 12:00:00')
+ )
+ );
+ assert.isFalse(
+ isWithinHalfYear(
+ new Date('May 08 2020 12:00:00'),
+ new Date('Nov 07 2019 12:00:00')
+ )
+ );
+ });
+ });
+
+ suite('formatDate', () => {
+ test('works for standard format', () => {
+ const stdFormat = 'MMM DD, YYYY';
+ assert.equal(
+ 'May 08, 2020',
+ formatDate(new Date('May 08 2020 12:00:00'), stdFormat)
+ );
+ assert.equal(
+ 'Feb 28, 2020',
+ formatDate(new Date('Feb 28 2020 12:00:00'), stdFormat)
+ );
+
+ const time24Format = 'HH:mm:ss';
+ assert.equal(
+ 'Feb 28, 2020 12:01:12',
+ formatDate(
+ new Date('Feb 28 2020 12:01:12'),
+ stdFormat + ' ' + time24Format
+ )
+ );
+ });
+ test('works for euro format', () => {
+ const euroFormat = 'DD.MM.YYYY';
+ assert.equal(
+ '01.12.2019',
+ formatDate(new Date('Dec 01 2019 12:00:00'), euroFormat)
+ );
+ assert.equal(
+ '20.01.2002',
+ formatDate(new Date('Jan 20 2002 12:00:00'), euroFormat)
+ );
+
+ const time24Format = 'HH:mm:ss';
+ assert.equal(
+ '28.02.2020 00:01:12',
+ formatDate(
+ new Date('Feb 28 2020 00:01:12'),
+ euroFormat + ' ' + time24Format
+ )
+ );
+ });
+ test('works for iso format', () => {
+ const isoFormat = 'YYYY-MM-DD';
+ assert.equal(
+ '2015-01-01',
+ formatDate(new Date('Jan 01 2015 12:00:00'), isoFormat)
+ );
+ assert.equal(
+ '2013-07-03',
+ formatDate(new Date('Jul 03 2013 12:00:00'), isoFormat)
+ );
+
+ const timeFormat = 'h:mm:ss A';
+ assert.equal(
+ '2013-07-03 5:00:00 AM',
+ formatDate(
+ new Date('Jul 03 2013 05:00:00'),
+ isoFormat + ' ' + timeFormat
+ )
+ );
+ assert.equal(
+ '2013-07-03 5:00:00 PM',
+ formatDate(
+ new Date('Jul 03 2013 17:00:00'),
+ isoFormat + ' ' + timeFormat
+ )
+ );
+ });
+ test('h:mm:ss A shows correctly midnight and midday', () => {
+ const timeFormat = 'h:mm A';
+ assert.equal(
+ '12:14 PM',
+ formatDate(new Date('Jul 03 2013 12:14:00'), timeFormat)
+ );
+ assert.equal(
+ '12:15 AM',
+ formatDate(new Date('Jul 03 2013 00:15:00'), timeFormat)
+ );
+ });
+ });
+});
diff --git a/polygerrit-ui/app/utils/display-name-util_test.js b/polygerrit-ui/app/utils/display-name-util_test.js
deleted file mode 100644
index 9bb68dc..0000000
--- a/polygerrit-ui/app/utils/display-name-util_test.js
+++ /dev/null
@@ -1,200 +0,0 @@
-/**
- * @license
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../test/common-test-setup-karma.js';
-import {getDisplayName, getUserName, getGroupDisplayName, getAccountDisplayName, _testOnly_accountEmail} from './display-name-util.js';
-
-suite('display-name-utils tests', () => {
- // eslint-disable-next-line no-unused-vars
- const config = {
- user: {
- anonymous_coward_name: 'Anonymous Coward',
- },
- };
-
- test('getDisplayName name only', () => {
- const account = {
- name: 'test-name',
- };
- assert.equal(getDisplayName(config, account),
- 'test-name');
- });
-
- test('getDisplayName prefer displayName', () => {
- const account = {
- name: 'test-name',
- display_name: 'better-name',
- };
- assert.equal(getDisplayName(config, account),
- 'better-name');
- });
-
- test('getDisplayName prefer username default', () => {
- const account = {
- name: 'test-name',
- username: 'user-name',
- };
- const config = {
- accounts: {
- default_display_name: 'USERNAME',
- },
- };
- assert.equal(getDisplayName(config, account),
- 'user-name');
- });
-
- test('getDisplayName firstNameOnly', () => {
- const account = {
- name: 'firstname lastname',
- };
- assert.equal(getDisplayName(config, account, true), 'firstname');
- });
-
- test('getDisplayName prefer first name default', () => {
- const account = {
- name: 'firstname lastname',
- };
- const config = {
- accounts: {
- default_display_name: 'FIRST_NAME',
- },
- };
- assert.equal(getDisplayName(config, account),
- 'firstname');
- });
-
- test('getDisplayName ignore leading whitespace for first name', () => {
- const account = {
- name: ' firstname lastname',
- };
- const config = {
- accounts: {
- default_display_name: 'FIRST_NAME',
- },
- };
- assert.equal(getDisplayName(config, account),
- 'firstname');
- });
-
- test('getDisplayName full name default', () => {
- const account = {
- name: 'firstname lastname',
- };
- const config = {
- accounts: {
- default_display_name: 'FULL_NAME',
- },
- };
- assert.equal(getDisplayName(config, account),
- 'firstname lastname');
- });
-
- test('getDisplayName name only', () => {
- const account = {
- name: 'test-name',
- };
- assert.deepEqual(getUserName(config, account),
- 'test-name');
- });
-
- test('getUserName username only', () => {
- const account = {
- username: 'test-user',
- };
- assert.deepEqual(getUserName(config, account),
- 'test-user');
- });
-
- test('getUserName email only', () => {
- const account = {
- email: 'test-user@test-url.com',
- };
- assert.deepEqual(getUserName(config, account),
- 'test-user@test-url.com');
- });
-
- test('getUserName returns not Anonymous Coward as the anon name', () => {
- assert.deepEqual(getUserName(config, null),
- 'Anonymous');
- });
-
- test('getUserName for the config returning the anon name', () => {
- const config = {
- user: {
- anonymous_coward_name: 'Test Anon',
- },
- };
- assert.deepEqual(getUserName(config, null),
- 'Test Anon');
- });
-
- test('getAccountDisplayName - account with name only', () => {
- assert.equal(
- getAccountDisplayName(config,
- {name: 'Some user name'}),
- 'Some user name');
- });
-
- test('getAccountDisplayName - account with email only', () => {
- assert.equal(
- getAccountDisplayName(config,
- {email: 'my@example.com'}),
- 'my@example.com <my@example.com>');
- });
-
- test('getAccountDisplayName - account with name and status', () => {
- assert.equal(
- getAccountDisplayName(config, {
- name: 'Some name',
- status: 'OOO',
- }),
- 'Some name (OOO)');
- });
-
- test('getAccountDisplayName - account with name and email', () => {
- assert.equal(
- getAccountDisplayName(config, {
- name: 'Some name',
- email: 'my@example.com',
- }),
- 'Some name <my@example.com>');
- });
-
- test('getAccountDisplayName - account with name, email and status', () => {
- assert.equal(
- getAccountDisplayName(config, {
- name: 'Some name',
- email: 'my@example.com',
- status: 'OOO',
- }),
- 'Some name <my@example.com> (OOO)');
- });
-
- test('getGroupDisplayName', () => {
- assert.equal(
- getGroupDisplayName({name: 'Some user name'}),
- 'Some user name (group)');
- });
-
- test('_accountEmail', () => {
- assert.equal(
- _testOnly_accountEmail('email@gerritreview.com'),
- '<email@gerritreview.com>');
- assert.equal(_testOnly_accountEmail(undefined), '');
- });
-});
-
diff --git a/polygerrit-ui/app/utils/display-name-util_test.ts b/polygerrit-ui/app/utils/display-name-util_test.ts
new file mode 100644
index 0000000..e6d4704
--- /dev/null
+++ b/polygerrit-ui/app/utils/display-name-util_test.ts
@@ -0,0 +1,225 @@
+/**
+ * @license
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {
+ AccountInfo,
+ DefaultDisplayNameConfig,
+ EmailAddress,
+ GroupName,
+ ServerInfo,
+} from '../api/rest-api';
+import '../test/common-test-setup-karma';
+import {
+ getDisplayName,
+ getUserName,
+ getGroupDisplayName,
+ getAccountDisplayName,
+ _testOnly_accountEmail,
+} from './display-name-util';
+import {
+ createAccountsConfig,
+ createGroupInfo,
+ createServerInfo,
+} from '../test/test-data-generators';
+
+suite('display-name-utils tests', () => {
+ const config: ServerInfo = {
+ ...createServerInfo(),
+ user: {
+ anonymous_coward_name: 'Anonymous Coward',
+ },
+ };
+
+ test('getDisplayName name only', () => {
+ const account = {
+ name: 'test-name',
+ };
+ assert.equal(getDisplayName(config, account), 'test-name');
+ });
+
+ test('getDisplayName prefer displayName', () => {
+ const account = {
+ name: 'test-name',
+ display_name: 'better-name',
+ };
+ assert.equal(getDisplayName(config, account), 'better-name');
+ });
+
+ test('getDisplayName prefer username default', () => {
+ const account = {
+ name: 'test-name',
+ username: 'user-name',
+ };
+ const config: ServerInfo = {
+ ...createServerInfo(),
+ accounts: {
+ ...createAccountsConfig(),
+ default_display_name: DefaultDisplayNameConfig.USERNAME,
+ },
+ };
+ assert.equal(getDisplayName(config, account), 'user-name');
+ });
+
+ test('getDisplayName firstNameOnly', () => {
+ const account = {
+ name: 'firstname lastname',
+ };
+ assert.equal(getDisplayName(config, account, true), 'firstname');
+ });
+
+ test('getDisplayName prefer first name default', () => {
+ const account = {
+ name: 'firstname lastname',
+ };
+ const config: ServerInfo = {
+ ...createServerInfo(),
+ accounts: {
+ ...createAccountsConfig(),
+ default_display_name: DefaultDisplayNameConfig.FIRST_NAME,
+ },
+ };
+ assert.equal(getDisplayName(config, account), 'firstname');
+ });
+
+ test('getDisplayName ignore leading whitespace for first name', () => {
+ const account = {
+ name: ' firstname lastname',
+ };
+ const config: ServerInfo = {
+ ...createServerInfo(),
+ accounts: {
+ ...createAccountsConfig(),
+ default_display_name: DefaultDisplayNameConfig.FIRST_NAME,
+ },
+ };
+ assert.equal(getDisplayName(config, account), 'firstname');
+ });
+
+ test('getDisplayName full name default', () => {
+ const account = {
+ name: 'firstname lastname',
+ };
+ const config: ServerInfo = {
+ ...createServerInfo(),
+ accounts: {
+ ...createAccountsConfig(),
+ default_display_name: DefaultDisplayNameConfig.FULL_NAME,
+ },
+ };
+ assert.equal(getDisplayName(config, account), 'firstname lastname');
+ });
+
+ test('getDisplayName name only', () => {
+ const account = {
+ name: 'test-name',
+ };
+ assert.deepEqual(getUserName(config, account), 'test-name');
+ });
+
+ test('getUserName username only', () => {
+ const account = {
+ username: 'test-user',
+ };
+ assert.deepEqual(getUserName(config, account), 'test-user');
+ });
+
+ test('getUserName email only', () => {
+ const account: AccountInfo = {
+ email: 'test-user@test-url.com' as EmailAddress,
+ };
+ assert.deepEqual(getUserName(config, account), 'test-user@test-url.com');
+ });
+
+ test('getUserName returns not Anonymous Coward as the anon name', () => {
+ assert.deepEqual(getUserName(config, undefined), 'Anonymous');
+ });
+
+ test('getUserName for the config returning the anon name', () => {
+ const config: ServerInfo = {
+ ...createServerInfo(),
+ user: {
+ anonymous_coward_name: 'Test Anon',
+ },
+ };
+ assert.deepEqual(getUserName(config, undefined), 'Test Anon');
+ });
+
+ test('getAccountDisplayName - account with name only', () => {
+ assert.equal(
+ getAccountDisplayName(config, {name: 'Some user name'}),
+ 'Some user name'
+ );
+ });
+
+ test('getAccountDisplayName - account with email only', () => {
+ assert.equal(
+ getAccountDisplayName(config, {
+ email: 'my@example.com' as EmailAddress,
+ }),
+ 'my@example.com <my@example.com>'
+ );
+ });
+
+ test('getAccountDisplayName - account with name and status', () => {
+ assert.equal(
+ getAccountDisplayName(config, {
+ name: 'Some name',
+ status: 'OOO',
+ }),
+ 'Some name (OOO)'
+ );
+ });
+
+ test('getAccountDisplayName - account with name and email', () => {
+ assert.equal(
+ getAccountDisplayName(config, {
+ name: 'Some name',
+ email: 'my@example.com' as EmailAddress,
+ }),
+ 'Some name <my@example.com>'
+ );
+ });
+
+ test('getAccountDisplayName - account with name, email and status', () => {
+ assert.equal(
+ getAccountDisplayName(config, {
+ name: 'Some name',
+ email: 'my@example.com' as EmailAddress,
+ status: 'OOO',
+ }),
+ 'Some name <my@example.com> (OOO)'
+ );
+ });
+
+ test('getGroupDisplayName', () => {
+ assert.equal(
+ getGroupDisplayName({
+ ...createGroupInfo(),
+ name: 'Some user name' as GroupName,
+ }),
+ 'Some user name (group)'
+ );
+ });
+
+ test('_accountEmail', () => {
+ assert.equal(
+ _testOnly_accountEmail('email@gerritreview.com'),
+ '<email@gerritreview.com>'
+ );
+ assert.equal(_testOnly_accountEmail(undefined), '');
+ });
+});
diff --git a/polygerrit-ui/app/utils/path-list-util_test.js b/polygerrit-ui/app/utils/path-list-util_test.js
deleted file mode 100644
index 4d06344..0000000
--- a/polygerrit-ui/app/utils/path-list-util_test.js
+++ /dev/null
@@ -1,161 +0,0 @@
-/**
- * @license
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../test/common-test-setup-karma.js';
-import {SpecialFilePath} from '../constants/constants.js';
-import {
- addUnmodifiedFiles,
- computeDisplayPath,
- isMagicPath,
- specialFilePathCompare, truncatePath,
-} from './path-list-util.js';
-
-suite('path-list-utl tests', () => {
- test('special sort', () => {
- const testFiles = [
- '/a.h',
- '/MERGE_LIST',
- '/a.cpp',
- '/COMMIT_MSG',
- '/asdasd',
- '/mrPeanutbutter.py',
- ];
- assert.deepEqual(
- testFiles.sort(specialFilePathCompare),
- [
- '/COMMIT_MSG',
- '/MERGE_LIST',
- '/a.h',
- '/a.cpp',
- '/asdasd',
- '/mrPeanutbutter.py',
- ]);
- });
-
- test('special file path sorting', () => {
- assert.deepEqual(
- ['.b', '/COMMIT_MSG', '.a', 'file'].sort(
- specialFilePathCompare),
- ['/COMMIT_MSG', '.a', '.b', 'file']);
-
- assert.deepEqual(
- ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.h'].sort(
- specialFilePathCompare),
- ['/COMMIT_MSG', '.b', 'foo/bar/baz.h', 'foo/bar/baz.cc']);
-
- assert.deepEqual(
- ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.hpp'].sort(
- specialFilePathCompare),
- ['/COMMIT_MSG', '.b', 'foo/bar/baz.hpp', 'foo/bar/baz.cc']);
-
- assert.deepEqual(
- ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.hxx'].sort(
- specialFilePathCompare),
- ['/COMMIT_MSG', '.b', 'foo/bar/baz.hxx', 'foo/bar/baz.cc']);
-
- assert.deepEqual(
- ['foo/bar.h', 'foo/bar.hxx', 'foo/bar.hpp'].sort(
- specialFilePathCompare),
- ['foo/bar.h', 'foo/bar.hpp', 'foo/bar.hxx']);
-
- // Regression test for Issue 4448.
- assert.deepEqual(
- [
- 'minidump/minidump_memory_writer.cc',
- 'minidump/minidump_memory_writer.h',
- 'minidump/minidump_thread_writer.cc',
- 'minidump/minidump_thread_writer.h',
- ].sort(specialFilePathCompare),
- [
- 'minidump/minidump_memory_writer.h',
- 'minidump/minidump_memory_writer.cc',
- 'minidump/minidump_thread_writer.h',
- 'minidump/minidump_thread_writer.cc',
- ]);
-
- // Regression test for Issue 4545.
- assert.deepEqual(
- [
- 'task_test.go',
- 'task.go',
- ].sort(specialFilePathCompare),
- [
- 'task.go',
- 'task_test.go',
- ]);
- });
-
- test('file display name', () => {
- assert.equal(computeDisplayPath('/foo/bar/baz'), '/foo/bar/baz');
- assert.equal(computeDisplayPath('/foobarbaz'), '/foobarbaz');
- assert.equal(computeDisplayPath('/COMMIT_MSG'), 'Commit message');
- assert.equal(computeDisplayPath('/MERGE_LIST'), 'Merge list');
- });
-
- test('isMagicPath', () => {
- assert.isFalse(isMagicPath(undefined));
- assert.isFalse(isMagicPath('/foo.cc'));
- assert.isTrue(isMagicPath('/COMMIT_MSG'));
- assert.isTrue(isMagicPath('/MERGE_LIST'));
- });
-
- test('patchset level comments are hidden', () => {
- const commentedPaths = {
- [SpecialFilePath.PATCHSET_LEVEL_COMMENTS]: true,
- 'file1.txt': true,
- };
-
- const files = {'file2.txt': {status: 'M'}};
- addUnmodifiedFiles(files, commentedPaths);
- assert.equal(files['file1.txt'].status, 'U');
- assert.equal(files['file2.txt'].status, 'M');
- assert.isFalse(files.hasOwnProperty(
- SpecialFilePath.PATCHSET_LEVEL_COMMENTS));
- });
-
- test('truncatePath with long path should add ellipsis', () => {
- let path = 'level1/level2/level3/level4/file.js';
- let shortenedPath = truncatePath(path);
- // The expected path is truncated with an ellipsis.
- const expectedPath = '\u2026/file.js';
- assert.equal(shortenedPath, expectedPath);
-
- path = 'level2/file.js';
- shortenedPath = truncatePath(path);
- assert.equal(shortenedPath, expectedPath);
- });
-
- test('truncatePath with opt_threshold', () => {
- let path = 'level1/level2/level3/level4/file.js';
- let shortenedPath = truncatePath(path, 2);
- // The expected path is truncated with an ellipsis.
- const expectedPath = '\u2026/level4/file.js';
- assert.equal(shortenedPath, expectedPath);
-
- path = 'level2/file.js';
- shortenedPath = truncatePath(path, 2);
- assert.equal(shortenedPath, path);
- });
-
- test('truncatePath with short path should not add ellipsis', () => {
- const path = 'file.js';
- const expectedPath = 'file.js';
- const shortenedPath = truncatePath(path);
- assert.equal(shortenedPath, expectedPath);
- });
-});
-
diff --git a/polygerrit-ui/app/utils/path-list-util_test.ts b/polygerrit-ui/app/utils/path-list-util_test.ts
new file mode 100644
index 0000000..79b5f09
--- /dev/null
+++ b/polygerrit-ui/app/utils/path-list-util_test.ts
@@ -0,0 +1,170 @@
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '../test/common-test-setup-karma';
+import {FileInfoStatus, SpecialFilePath} from '../constants/constants';
+import {
+ addUnmodifiedFiles,
+ computeDisplayPath,
+ isMagicPath,
+ specialFilePathCompare,
+ truncatePath,
+} from './path-list-util';
+import {FileInfo} from '../api/rest-api';
+import {hasOwnProperty} from './common-util';
+
+suite('path-list-utl tests', () => {
+ test('special sort', () => {
+ const testFiles = [
+ '/a.h',
+ '/MERGE_LIST',
+ '/a.cpp',
+ '/COMMIT_MSG',
+ '/asdasd',
+ '/mrPeanutbutter.py',
+ ];
+ assert.deepEqual(testFiles.sort(specialFilePathCompare), [
+ '/COMMIT_MSG',
+ '/MERGE_LIST',
+ '/a.h',
+ '/a.cpp',
+ '/asdasd',
+ '/mrPeanutbutter.py',
+ ]);
+ });
+
+ test('special file path sorting', () => {
+ assert.deepEqual(
+ ['.b', '/COMMIT_MSG', '.a', 'file'].sort(specialFilePathCompare),
+ ['/COMMIT_MSG', '.a', '.b', 'file']
+ );
+
+ assert.deepEqual(
+ ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.h'].sort(
+ specialFilePathCompare
+ ),
+ ['/COMMIT_MSG', '.b', 'foo/bar/baz.h', 'foo/bar/baz.cc']
+ );
+
+ assert.deepEqual(
+ ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.hpp'].sort(
+ specialFilePathCompare
+ ),
+ ['/COMMIT_MSG', '.b', 'foo/bar/baz.hpp', 'foo/bar/baz.cc']
+ );
+
+ assert.deepEqual(
+ ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.hxx'].sort(
+ specialFilePathCompare
+ ),
+ ['/COMMIT_MSG', '.b', 'foo/bar/baz.hxx', 'foo/bar/baz.cc']
+ );
+
+ assert.deepEqual(
+ ['foo/bar.h', 'foo/bar.hxx', 'foo/bar.hpp'].sort(specialFilePathCompare),
+ ['foo/bar.h', 'foo/bar.hpp', 'foo/bar.hxx']
+ );
+
+ // Regression test for Issue 4448.
+ assert.deepEqual(
+ [
+ 'minidump/minidump_memory_writer.cc',
+ 'minidump/minidump_memory_writer.h',
+ 'minidump/minidump_thread_writer.cc',
+ 'minidump/minidump_thread_writer.h',
+ ].sort(specialFilePathCompare),
+ [
+ 'minidump/minidump_memory_writer.h',
+ 'minidump/minidump_memory_writer.cc',
+ 'minidump/minidump_thread_writer.h',
+ 'minidump/minidump_thread_writer.cc',
+ ]
+ );
+
+ // Regression test for Issue 4545.
+ assert.deepEqual(['task_test.go', 'task.go'].sort(specialFilePathCompare), [
+ 'task.go',
+ 'task_test.go',
+ ]);
+ });
+
+ test('file display name', () => {
+ assert.equal(computeDisplayPath('/foo/bar/baz'), '/foo/bar/baz');
+ assert.equal(computeDisplayPath('/foobarbaz'), '/foobarbaz');
+ assert.equal(computeDisplayPath('/COMMIT_MSG'), 'Commit message');
+ assert.equal(computeDisplayPath('/MERGE_LIST'), 'Merge list');
+ });
+
+ test('isMagicPath', () => {
+ assert.isFalse(isMagicPath(undefined));
+ assert.isFalse(isMagicPath('/foo.cc'));
+ assert.isTrue(isMagicPath('/COMMIT_MSG'));
+ assert.isTrue(isMagicPath('/MERGE_LIST'));
+ });
+
+ test('patchset level comments are hidden', () => {
+ const commentedPaths = {
+ [SpecialFilePath.PATCHSET_LEVEL_COMMENTS]: true,
+ 'file1.txt': true,
+ };
+
+ const files: {[filename: string]: FileInfo} = {
+ 'file2.txt': {
+ status: FileInfoStatus.REWRITTEN,
+ size_delta: 10,
+ size: 10,
+ },
+ };
+ addUnmodifiedFiles(files, commentedPaths);
+ assert.equal(files['file1.txt'].status, FileInfoStatus.UNMODIFIED);
+ assert.equal(files['file2.txt'].status, FileInfoStatus.REWRITTEN);
+ assert.isFalse(
+ hasOwnProperty(files, SpecialFilePath.PATCHSET_LEVEL_COMMENTS)
+ );
+ });
+
+ test('truncatePath with long path should add ellipsis', () => {
+ let path = 'level1/level2/level3/level4/file.js';
+ let shortenedPath = truncatePath(path);
+ // The expected path is truncated with an ellipsis.
+ const expectedPath = '\u2026/file.js';
+ assert.equal(shortenedPath, expectedPath);
+
+ path = 'level2/file.js';
+ shortenedPath = truncatePath(path);
+ assert.equal(shortenedPath, expectedPath);
+ });
+
+ test('truncatePath with opt_threshold', () => {
+ let path = 'level1/level2/level3/level4/file.js';
+ let shortenedPath = truncatePath(path, 2);
+ // The expected path is truncated with an ellipsis.
+ const expectedPath = '\u2026/level4/file.js';
+ assert.equal(shortenedPath, expectedPath);
+
+ path = 'level2/file.js';
+ shortenedPath = truncatePath(path, 2);
+ assert.equal(shortenedPath, path);
+ });
+
+ test('truncatePath with short path should not add ellipsis', () => {
+ const path = 'file.js';
+ const expectedPath = 'file.js';
+ const shortenedPath = truncatePath(path);
+ assert.equal(shortenedPath, expectedPath);
+ });
+});
diff --git a/polygerrit-ui/app/utils/url-util_test.js b/polygerrit-ui/app/utils/url-util_test.ts
similarity index 66%
rename from polygerrit-ui/app/utils/url-util_test.js
rename to polygerrit-ui/app/utils/url-util_test.ts
index 5cd4bb4..63dc81d 100644
--- a/polygerrit-ui/app/utils/url-util_test.js
+++ b/polygerrit-ui/app/utils/url-util_test.ts
@@ -15,7 +15,9 @@
* limitations under the License.
*/
-import '../test/common-test-setup-karma.js';
+import {ServerInfo} from '../api/rest-api';
+import '../test/common-test-setup-karma';
+import {createGerritInfo, createServerInfo} from '../test/test-data-generators';
import {
getBaseUrl,
getDocsBaseUrl,
@@ -25,11 +27,13 @@
toPath,
toPathname,
toSearchParams,
-} from './url-util.js';
+} from './url-util';
+import {appContext} from '../services/app-context';
+import {stubRestApi} from '../test/test-utils';
suite('url-util tests', () => {
suite('getBaseUrl tests', () => {
- let originalCanonicalPath;
+ let originalCanonicalPath: string | undefined;
suiteSetup(() => {
originalCanonicalPath = window.CANONICAL_PATH;
@@ -51,43 +55,50 @@
});
test('null config', async () => {
- const mockRestApi = {
- probePath: sinon.stub().returns(Promise.resolve(true)),
- };
- const docsBaseUrl = await getDocsBaseUrl(null, mockRestApi);
- assert.isTrue(
- mockRestApi.probePath.calledWith('/Documentation/index.html'));
+ const probePathMock = stubRestApi('probePath').resolves(true);
+ const docsBaseUrl = await getDocsBaseUrl(
+ undefined,
+ appContext.restApiService
+ );
+ assert.isTrue(probePathMock.calledWith('/Documentation/index.html'));
assert.equal(docsBaseUrl, '/Documentation');
});
test('no doc config', async () => {
- const mockRestApi = {
- probePath: sinon.stub().returns(Promise.resolve(true)),
+ const probePathMock = stubRestApi('probePath').resolves(true);
+ const config: ServerInfo = {
+ ...createServerInfo(),
+ gerrit: createGerritInfo(),
};
- const config = {gerrit: {}};
- const docsBaseUrl = await getDocsBaseUrl(config, mockRestApi);
- assert.isTrue(
- mockRestApi.probePath.calledWith('/Documentation/index.html'));
+ const docsBaseUrl = await getDocsBaseUrl(
+ config,
+ appContext.restApiService
+ );
+ assert.isTrue(probePathMock.calledWith('/Documentation/index.html'));
assert.equal(docsBaseUrl, '/Documentation');
});
test('has doc config', async () => {
- const mockRestApi = {
- probePath: sinon.stub().returns(Promise.resolve(true)),
+ const probePathMock = stubRestApi('probePath').resolves(true);
+ const config: ServerInfo = {
+ ...createServerInfo(),
+ gerrit: {...createGerritInfo(), doc_url: 'foobar'},
};
- const config = {gerrit: {doc_url: 'foobar'}};
- const docsBaseUrl = await getDocsBaseUrl(config, mockRestApi);
- assert.isFalse(mockRestApi.probePath.called);
+ const docsBaseUrl = await getDocsBaseUrl(
+ config,
+ appContext.restApiService
+ );
+ assert.isFalse(probePathMock.called);
assert.equal(docsBaseUrl, 'foobar');
});
test('no probe', async () => {
- const mockRestApi = {
- probePath: sinon.stub().returns(Promise.resolve(false)),
- };
- const docsBaseUrl = await getDocsBaseUrl(null, mockRestApi);
- assert.isTrue(
- mockRestApi.probePath.calledWith('/Documentation/index.html'));
+ const probePathMock = stubRestApi('probePath').resolves(false);
+ const docsBaseUrl = await getDocsBaseUrl(
+ undefined,
+ appContext.restApiService
+ );
+ assert.isTrue(probePathMock.calledWith('/Documentation/index.html'));
assert.isNotOk(docsBaseUrl);
});
});
@@ -144,7 +155,9 @@
assert.equal(toPath('asdf', params), 'asdf');
params.set('qwer', 'zxcv');
assert.equal(toPath('asdf', params), 'asdf?qwer=zxcv');
- assert.equal(toPath(toPathname('asdf?qwer=zxcv'),
- toSearchParams('asdf?qwer=zxcv')), 'asdf?qwer=zxcv');
+ assert.equal(
+ toPath(toPathname('asdf?qwer=zxcv'), toSearchParams('asdf?qwer=zxcv')),
+ 'asdf?qwer=zxcv'
+ );
});
});