Timeline: repair oldest/newest metrics if we fetch nothing

This commit is contained in:
Scott Nonnenberg 2020-12-04 12:41:40 -08:00 committed by GitHub
parent 56ae4a41eb
commit 6832b8acca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 579 additions and 173 deletions

View file

@ -0,0 +1,53 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import * as sinon from 'sinon';
import { LatestQueue } from '../../util/LatestQueue';
describe('LatestQueue', () => {
it('if the queue is empty, new tasks are started immediately', done => {
new LatestQueue().add(async () => {
done();
});
});
it('only enqueues the latest operation', done => {
const queue = new LatestQueue();
const spy = sinon.spy();
let openFirstTaskGate: undefined | (() => void);
const firstTaskGate = new Promise(resolve => {
openFirstTaskGate = resolve;
});
if (!openFirstTaskGate) {
throw new Error('Test is misconfigured; cannot grab inner resolve');
}
queue.add(async () => {
await firstTaskGate;
spy('first');
});
queue.add(async () => {
spy('second');
});
queue.add(async () => {
spy('third');
});
sinon.assert.notCalled(spy);
openFirstTaskGate();
queue.onceEmpty(() => {
sinon.assert.calledTwice(spy);
sinon.assert.calledWith(spy, 'first');
sinon.assert.calledWith(spy, 'third');
done();
});
});
});

View file

@ -0,0 +1,32 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { combineNames } from '../../util/combineNames';
describe('combineNames', () => {
it('returns undefined if no names provided', () => {
assert.strictEqual(combineNames('', ''), undefined);
});
it('returns first name only if family name not provided', () => {
assert.strictEqual(combineNames('Alice'), 'Alice');
});
it('returns returns combined names', () => {
assert.strictEqual(combineNames('Alice', 'Jones'), 'Alice Jones');
});
it('returns given name first if names in Chinese', () => {
assert.strictEqual(combineNames('振宁', '杨'), '杨振宁');
});
it('returns given name first if names in Japanese', () => {
assert.strictEqual(combineNames('泰夫', '木田'), '木田泰夫');
});
it('returns given name first if names in Korean', () => {
assert.strictEqual(combineNames('채원', '도윤'), '도윤채원');
});
});

View file

@ -0,0 +1,60 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import * as fs from 'fs';
import * as path from 'path';
import { assert } from 'chai';
import { getAnimatedPngDataIfExists } from '../../util/getAnimatedPngDataIfExists';
describe('getAnimatedPngDataIfExists', () => {
const fixture = (filename: string): Promise<Buffer> => {
const fixturePath = path.join(
__dirname,
'..',
'..',
'..',
'fixtures',
filename
);
return fs.promises.readFile(fixturePath);
};
it('returns null for empty buffers', () => {
assert.isNull(getAnimatedPngDataIfExists(Buffer.alloc(0)));
});
it('returns null for non-PNG files', async () => {
await Promise.all(
[
'kitten-1-64-64.jpg',
'512x515-thumbs-up-lincoln.webp',
'giphy-GVNvOUpeYmI7e.gif',
'pixabay-Soap-Bubble-7141.mp4',
'lorem-ipsum.txt',
].map(async filename => {
assert.isNull(getAnimatedPngDataIfExists(await fixture(filename)));
})
);
});
it('returns null for non-animated PNG files', async () => {
assert.isNull(
getAnimatedPngDataIfExists(await fixture('20x200-yellow.png'))
);
});
it('returns data for animated PNG files', async () => {
assert.deepEqual(
getAnimatedPngDataIfExists(
await fixture('Animated_PNG_example_bouncing_beach_ball.png')
),
{ numPlays: Infinity }
);
assert.deepEqual(
getAnimatedPngDataIfExists(await fixture('apng_with_2_plays.png')),
{ numPlays: 2 }
);
});
});

View file

@ -0,0 +1,50 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { getOwn } from '../../util/getOwn';
describe('getOwn', () => {
class Person {
public birthYear: number;
constructor(birthYear: number) {
this.birthYear = birthYear;
}
getAge() {
return new Date().getFullYear() - this.birthYear;
}
}
it('returns undefined when asking for a non-existent property', () => {
const obj: Record<string, number> = { bar: 123 };
assert.isUndefined(getOwn(obj, 'foo'));
});
it('returns undefined when asking for a non-own property', () => {
const obj: Record<string, number> = { bar: 123 };
assert.isUndefined(getOwn(obj, 'hasOwnProperty'));
const person = new Person(1880);
assert.isUndefined(getOwn(person, 'getAge'));
});
it('returns own properties', () => {
const obj: Record<string, number> = { foo: 123 };
assert.strictEqual(getOwn(obj, 'foo'), 123);
const person = new Person(1880);
assert.strictEqual(getOwn(person, 'birthYear'), 1880);
});
it('works even if `hasOwnProperty` has been overridden for the object', () => {
const obj: Record<string, unknown> = {
foo: 123,
hasOwnProperty: () => true,
};
assert.strictEqual(getOwn(obj, 'foo'), 123);
assert.isUndefined(getOwn(obj, 'bar'));
});
});

View file

@ -0,0 +1,45 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { expect } from 'chai';
import { getTextWithMentions } from '../../util/getTextWithMentions';
describe('getTextWithMentions', () => {
describe('given mention replacements', () => {
it('replaces them', () => {
const bodyRanges = [
{
length: 1,
mentionUuid: 'abcdef',
replacementText: 'fred',
start: 4,
},
];
const text = "Hey \uFFFC, I'm here";
expect(getTextWithMentions(bodyRanges, text)).to.eql(
"Hey @fred, I'm here"
);
});
it('sorts them to go from back to front', () => {
const bodyRanges = [
{
length: 1,
mentionUuid: 'blarg',
replacementText: 'jerry',
start: 0,
},
{
length: 1,
mentionUuid: 'abcdef',
replacementText: 'fred',
start: 7,
},
];
const text = "\uFFFC says \uFFFC, I'm here";
expect(getTextWithMentions(bodyRanges, text)).to.eql(
"@jerry says @fred, I'm here"
);
});
});
});

View file

@ -0,0 +1,37 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import * as sinon from 'sinon';
import { getUserAgent } from '../../util/getUserAgent';
describe('getUserAgent', () => {
beforeEach(function beforeEach() {
this.sandbox = sinon.createSandbox();
});
afterEach(function afterEach() {
this.sandbox.restore();
});
it('returns the right User-Agent on Windows', function test() {
this.sandbox.stub(process, 'platform').get(() => 'win32');
assert.strictEqual(getUserAgent('1.2.3'), 'Signal-Desktop/1.2.3 Windows');
});
it('returns the right User-Agent on macOS', function test() {
this.sandbox.stub(process, 'platform').get(() => 'darwin');
assert.strictEqual(getUserAgent('1.2.3'), 'Signal-Desktop/1.2.3 macOS');
});
it('returns the right User-Agent on Linux', function test() {
this.sandbox.stub(process, 'platform').get(() => 'linux');
assert.strictEqual(getUserAgent('1.2.3'), 'Signal-Desktop/1.2.3 Linux');
});
it('omits the platform on unsupported platforms', function test() {
this.sandbox.stub(process, 'platform').get(() => 'freebsd');
assert.strictEqual(getUserAgent('1.2.3'), 'Signal-Desktop/1.2.3');
});
});

View file

@ -0,0 +1,51 @@
// Copyright 2018-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { isFileDangerous } from '../../util/isFileDangerous';
describe('isFileDangerous', () => {
it('returns false for images', () => {
assert.strictEqual(isFileDangerous('dog.gif'), false);
assert.strictEqual(isFileDangerous('cat.jpg'), false);
});
it('returns false for documents', () => {
assert.strictEqual(isFileDangerous('resume.docx'), false);
assert.strictEqual(isFileDangerous('price_list.pdf'), false);
});
it('returns true for executable files', () => {
assert.strictEqual(isFileDangerous('run.exe'), true);
assert.strictEqual(isFileDangerous('install.pif'), true);
});
it('returns true for Microsoft settings files', () => {
assert.strictEqual(isFileDangerous('downl.SettingContent-ms'), true);
});
it('returns false for non-dangerous files that end in ".", which can happen on Windows', () => {
assert.strictEqual(isFileDangerous('dog.png.'), false);
assert.strictEqual(isFileDangerous('resume.docx.'), false);
});
it('returns true for dangerous files that end in ".", which can happen on Windows', () => {
assert.strictEqual(isFileDangerous('run.exe.'), true);
assert.strictEqual(isFileDangerous('install.pif.'), true);
});
it('returns false for empty filename', () => {
assert.strictEqual(isFileDangerous(''), false);
});
it('returns false for exe at various parts of filename', () => {
assert.strictEqual(isFileDangerous('.exemanifesto.txt'), false);
assert.strictEqual(isFileDangerous('runexe'), false);
assert.strictEqual(isFileDangerous('run_exe'), false);
});
it('returns true for upper-case EXE', () => {
assert.strictEqual(isFileDangerous('run.EXE'), true);
});
});

View file

@ -0,0 +1,22 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { isMuted } from '../../util/isMuted';
describe('isMuted', () => {
it('returns false if passed undefined', () => {
assert.isFalse(isMuted(undefined));
});
it('returns false if passed a date in the past', () => {
assert.isFalse(isMuted(0));
assert.isFalse(isMuted(Date.now() - 123));
});
it('returns false if passed a date in the future', () => {
assert.isTrue(isMuted(Date.now() + 123));
assert.isTrue(isMuted(Date.now() + 123456));
});
});

View file

@ -0,0 +1,45 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { isPathInside } from '../../util/isPathInside';
describe('isPathInside', () => {
it('returns false if the child path is not inside the parent path', () => {
assert.isFalse(isPathInside('x', 'a/b'));
assert.isFalse(isPathInside('a/b', '/a/b'));
assert.isFalse(isPathInside('/a/b', 'a/b'));
assert.isFalse(isPathInside('/x', '/a/b'));
assert.isFalse(isPathInside('/x/y', '/a/b'));
assert.isFalse(isPathInside('/a/x', '/a/b'));
assert.isFalse(isPathInside('/a/bad', '/a/b'));
assert.isFalse(isPathInside('/a/x', '/a/b'));
assert.isFalse(isPathInside('/a/b', '/a/b'));
assert.isFalse(isPathInside('/a/b/c/..', '/a/b'));
assert.isFalse(isPathInside('/', '/'));
assert.isFalse(isPathInside('/x/..', '/'));
if (process.platform === 'win32') {
assert.isFalse(isPathInside('C:\\a\\x\\y', 'C:\\a\\b'));
assert.isFalse(isPathInside('D:\\a\\b\\c', 'C:\\a\\b'));
}
});
it('returns true if the child path is inside the parent path', () => {
assert.isTrue(isPathInside('a/b/c', 'a/b'));
assert.isTrue(isPathInside('a/b/c/d', 'a/b'));
assert.isTrue(isPathInside('/a/b/c', '/a/b'));
assert.isTrue(isPathInside('/a/b/c', '/a/b/'));
assert.isTrue(isPathInside('/a/b/c/', '/a/b'));
assert.isTrue(isPathInside('/a/b/c/', '/a/b/'));
assert.isTrue(isPathInside('/a/b/c/d', '/a/b'));
assert.isTrue(isPathInside('/a/b/c/d/..', '/a/b'));
assert.isTrue(isPathInside('/x/y/z/z/y', '/'));
assert.isTrue(isPathInside('x/y/z/z/y', '/'));
if (process.platform === 'win32') {
assert.isTrue(isPathInside('C:\\a\\b\\c', 'C:\\a\\b'));
}
});
});

View file

@ -0,0 +1,16 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { nonRenderedRemoteParticipant } from '../../../util/ringrtc/nonRenderedRemoteParticipant';
describe('nonRenderedRemoteParticipant', () => {
it('returns a video request object a width and height of 0', () => {
assert.deepEqual(nonRenderedRemoteParticipant({ demuxId: 123 }), {
demuxId: 123,
width: 0,
height: 0,
});
});
});

View file

@ -0,0 +1,74 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { normalizeGroupCallTimestamp } from '../../../util/ringrtc/normalizeGroupCallTimestamp';
describe('normalizeGroupCallTimestamp', () => {
it('returns undefined if passed NaN', () => {
assert.isUndefined(normalizeGroupCallTimestamp(NaN));
});
it('returns undefined if passed 0', () => {
assert.isUndefined(normalizeGroupCallTimestamp(0));
assert.isUndefined(normalizeGroupCallTimestamp(-0));
});
it('returns undefined if passed a negative number', () => {
assert.isUndefined(normalizeGroupCallTimestamp(-1));
assert.isUndefined(normalizeGroupCallTimestamp(-123));
});
it('returns undefined if passed a string that cannot be parsed as a number', () => {
assert.isUndefined(normalizeGroupCallTimestamp(''));
assert.isUndefined(normalizeGroupCallTimestamp('uhhh'));
});
it('returns undefined if passed a BigInt of 0', () => {
assert.isUndefined(normalizeGroupCallTimestamp(BigInt(0)));
});
it('returns undefined if passed a negative BigInt', () => {
assert.isUndefined(normalizeGroupCallTimestamp(BigInt(-1)));
assert.isUndefined(normalizeGroupCallTimestamp(BigInt(-123)));
});
it('returns undefined if passed a non-parseable type', () => {
[
undefined,
null,
{},
[],
[123],
Symbol('123'),
{ [Symbol.toPrimitive]: () => 123 },
// eslint-disable-next-line no-new-wrappers
new Number(123),
].forEach(value => {
assert.isUndefined(normalizeGroupCallTimestamp(value));
});
});
it('returns positive numbers passed in', () => {
assert.strictEqual(normalizeGroupCallTimestamp(1), 1);
assert.strictEqual(normalizeGroupCallTimestamp(123), 123);
});
it('parses strings as numbers', () => {
assert.strictEqual(normalizeGroupCallTimestamp('1'), 1);
assert.strictEqual(normalizeGroupCallTimestamp('123'), 123);
});
it('only parses the first 15 characters of a string', () => {
assert.strictEqual(
normalizeGroupCallTimestamp('12345678901234567890123456789'),
123456789012345
);
});
it('converts positive BigInts to numbers', () => {
assert.strictEqual(normalizeGroupCallTimestamp(BigInt(1)), 1);
assert.strictEqual(normalizeGroupCallTimestamp(BigInt(123)), 123);
});
});

View file

@ -0,0 +1,176 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import Sinon from 'sinon';
import { LoggerType } from '../../types/Logging';
import { isSgnlHref, parseSgnlHref } from '../../util/sgnlHref';
function shouldNeverBeCalled() {
assert.fail('This should never be called');
}
const explodingLogger: LoggerType = {
fatal: shouldNeverBeCalled,
error: shouldNeverBeCalled,
warn: shouldNeverBeCalled,
info: shouldNeverBeCalled,
debug: shouldNeverBeCalled,
trace: shouldNeverBeCalled,
};
describe('sgnlHref', () => {
describe('isSgnlHref', () => {
it('returns false for non-strings', () => {
const logger = {
...explodingLogger,
warn: Sinon.spy(),
};
const castToString = (value: unknown): string => value as string;
assert.isFalse(isSgnlHref(castToString(undefined), logger));
assert.isFalse(isSgnlHref(castToString(null), logger));
assert.isFalse(isSgnlHref(castToString(123), logger));
Sinon.assert.calledThrice(logger.warn);
});
it('returns false for invalid URLs', () => {
assert.isFalse(isSgnlHref('', explodingLogger));
assert.isFalse(isSgnlHref('sgnl', explodingLogger));
assert.isFalse(isSgnlHref('sgnl://::', explodingLogger));
});
it('returns false if the protocol is not "sgnl:"', () => {
assert.isFalse(isSgnlHref('https://example', explodingLogger));
assert.isFalse(
isSgnlHref(
'https://signal.art/addstickers/?pack_id=abc',
explodingLogger
)
);
assert.isFalse(isSgnlHref('signal://example', explodingLogger));
});
it('returns true if the protocol is "sgnl:"', () => {
assert.isTrue(isSgnlHref('sgnl://', explodingLogger));
assert.isTrue(isSgnlHref('sgnl://example', explodingLogger));
assert.isTrue(isSgnlHref('sgnl://example.com', explodingLogger));
assert.isTrue(isSgnlHref('SGNL://example', explodingLogger));
assert.isTrue(isSgnlHref('sgnl://example?foo=bar', explodingLogger));
assert.isTrue(isSgnlHref('sgnl://example/', explodingLogger));
assert.isTrue(isSgnlHref('sgnl://example#', explodingLogger));
assert.isTrue(isSgnlHref('sgnl:foo', explodingLogger));
assert.isTrue(isSgnlHref('sgnl://user:pass@example', explodingLogger));
assert.isTrue(isSgnlHref('sgnl://example.com:1234', explodingLogger));
assert.isTrue(
isSgnlHref('sgnl://example.com/extra/path/data', explodingLogger)
);
assert.isTrue(
isSgnlHref('sgnl://example/?foo=bar#hash', explodingLogger)
);
});
it('accepts URL objects', () => {
const invalid = new URL('https://example.com');
assert.isFalse(isSgnlHref(invalid, explodingLogger));
const valid = new URL('sgnl://example');
assert.isTrue(isSgnlHref(valid, explodingLogger));
});
});
describe('parseSgnlHref', () => {
it('returns a null command for invalid URLs', () => {
['', 'sgnl', 'https://example/?foo=bar'].forEach(href => {
assert.deepEqual(parseSgnlHref(href, explodingLogger), {
command: null,
args: new Map<never, never>(),
});
});
});
it('parses the command for URLs with no arguments', () => {
[
'sgnl://foo',
'sgnl://foo/',
'sgnl://foo?',
'SGNL://foo?',
'sgnl://user:pass@foo',
'sgnl://foo/path/data#hash-data',
].forEach(href => {
assert.deepEqual(parseSgnlHref(href, explodingLogger), {
command: 'foo',
args: new Map<string, string>(),
});
});
});
it("parses a command's arguments", () => {
assert.deepEqual(
parseSgnlHref(
'sgnl://Foo?bar=baz&qux=Quux&num=123&empty=&encoded=hello%20world',
explodingLogger
),
{
command: 'Foo',
args: new Map([
['bar', 'baz'],
['qux', 'Quux'],
['num', '123'],
['empty', ''],
['encoded', 'hello world'],
]),
}
);
});
it('treats the port as part of the command', () => {
assert.propertyVal(
parseSgnlHref('sgnl://foo:1234', explodingLogger),
'command',
'foo:1234'
);
});
it('ignores duplicate query parameters', () => {
assert.deepPropertyVal(
parseSgnlHref('sgnl://x?foo=bar&foo=totally-ignored', explodingLogger),
'args',
new Map([['foo', 'bar']])
);
});
it('ignores other parts of the URL', () => {
[
'sgnl://foo?bar=baz',
'sgnl://foo/?bar=baz',
'sgnl://foo/lots/of/path?bar=baz',
'sgnl://foo?bar=baz#hash',
'sgnl://user:pass@foo?bar=baz',
].forEach(href => {
assert.deepEqual(parseSgnlHref(href, explodingLogger), {
command: 'foo',
args: new Map([['bar', 'baz']]),
});
});
});
it("doesn't do anything fancy with arrays or objects in the query string", () => {
// The `qs` module does things like this, which we don't want.
assert.deepPropertyVal(
parseSgnlHref('sgnl://x?foo[]=bar&foo[]=baz', explodingLogger),
'args',
new Map([['foo[]', 'bar']])
);
assert.deepPropertyVal(
parseSgnlHref('sgnl://x?foo[bar][baz]=foobarbaz', explodingLogger),
'args',
new Map([['foo[bar][baz]', 'foobarbaz']])
);
});
});
});

View file

@ -0,0 +1,36 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { useFakeTimers } from 'sinon';
import { sleep } from '../../util/sleep';
describe('sleep', () => {
beforeEach(function beforeEach() {
// This isn't a hook.
// eslint-disable-next-line react-hooks/rules-of-hooks
this.clock = useFakeTimers();
});
afterEach(function afterEach() {
this.clock.restore();
});
it('returns a promise that resolves after the specified number of milliseconds', async function test() {
let isDone = false;
(async () => {
await sleep(123);
isDone = true;
})();
assert.isFalse(isDone);
await this.clock.tickAsync(100);
assert.isFalse(isDone);
await this.clock.tickAsync(25);
assert.isTrue(isDone);
});
});

View file

@ -0,0 +1,95 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import * as fs from 'fs';
import * as path from 'path';
import { assert } from 'chai';
import {
IMAGE_BMP,
IMAGE_GIF,
IMAGE_ICO,
IMAGE_JPEG,
IMAGE_PNG,
IMAGE_WEBP,
} from '../../types/MIME';
import { sniffImageMimeType } from '../../util/sniffImageMimeType';
describe('sniffImageMimeType', () => {
const fixture = (filename: string): Promise<Buffer> => {
const fixturePath = path.join(
__dirname,
'..',
'..',
'..',
'fixtures',
filename
);
return fs.promises.readFile(fixturePath);
};
it('returns undefined for empty buffers', () => {
assert.isUndefined(sniffImageMimeType(new Uint8Array()));
});
it('returns undefined for non-image files', async () => {
await Promise.all(
['pixabay-Soap-Bubble-7141.mp4', 'lorem-ipsum.txt'].map(
async filename => {
assert.isUndefined(sniffImageMimeType(await fixture(filename)));
}
)
);
});
it('sniffs ICO files', async () => {
assert.strictEqual(
sniffImageMimeType(await fixture('kitten-1-64-64.ico')),
IMAGE_ICO
);
});
it('sniffs BMP files', async () => {
assert.strictEqual(sniffImageMimeType(await fixture('2x2.bmp')), IMAGE_BMP);
});
it('sniffs GIF files', async () => {
assert.strictEqual(
sniffImageMimeType(await fixture('giphy-GVNvOUpeYmI7e.gif')),
IMAGE_GIF
);
});
it('sniffs WEBP files', async () => {
assert.strictEqual(
sniffImageMimeType(await fixture('512x515-thumbs-up-lincoln.webp')),
IMAGE_WEBP
);
});
it('sniffs PNG files', async () => {
await Promise.all(
[
'freepngs-2cd43b_bed7d1327e88454487397574d87b64dc_mv2.png',
'Animated_PNG_example_bouncing_beach_ball.png',
].map(async filename => {
assert.strictEqual(
sniffImageMimeType(await fixture(filename)),
IMAGE_PNG
);
})
);
});
it('sniffs JPEG files', async () => {
assert.strictEqual(
sniffImageMimeType(await fixture('kitten-1-64-64.jpg')),
IMAGE_JPEG
);
});
it('handles ArrayBuffers', async () => {
const arrayBuffer = (await fixture('kitten-1-64-64.jpg')).buffer;
assert.strictEqual(sniffImageMimeType(arrayBuffer), IMAGE_JPEG);
});
});

View file

@ -0,0 +1,67 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import * as path from 'path';
import * as os from 'os';
import * as fs from 'fs';
import * as fse from 'fs-extra';
import * as Sinon from 'sinon';
import { assertRejects } from '../helpers';
import { writeWindowsZoneIdentifier } from '../../util/windowsZoneIdentifier';
describe('writeWindowsZoneIdentifier', () => {
before(function thisNeeded() {
if (process.platform !== 'win32') {
this.skip();
}
});
beforeEach(async function thisNeeded() {
this.sandbox = Sinon.createSandbox();
this.tmpdir = await fs.promises.mkdtemp(
path.join(os.tmpdir(), 'signal-test-')
);
});
afterEach(async function thisNeeded() {
this.sandbox.restore();
await fse.remove(this.tmpdir);
});
it('writes zone transfer ID 3 (internet) to the Zone.Identifier file', async function thisNeeded() {
const file = path.join(this.tmpdir, 'file.txt');
await fse.outputFile(file, 'hello');
await writeWindowsZoneIdentifier(file);
assert.strictEqual(
await fs.promises.readFile(`${file}:Zone.Identifier`, 'utf8'),
'[ZoneTransfer]\r\nZoneId=3'
);
});
it('fails if there is an existing Zone.Identifier file', async function thisNeeded() {
const file = path.join(this.tmpdir, 'file.txt');
await fse.outputFile(file, 'hello');
await fs.promises.writeFile(`${file}:Zone.Identifier`, '# already here');
await assertRejects(() => writeWindowsZoneIdentifier(file));
});
it('fails if the original file does not exist', async function thisNeeded() {
const file = path.join(this.tmpdir, 'file-never-created.txt');
await assertRejects(() => writeWindowsZoneIdentifier(file));
});
it('fails if not on Windows', async function thisNeeded() {
this.sandbox.stub(process, 'platform').get(() => 'darwin');
const file = path.join(this.tmpdir, 'file.txt');
await fse.outputFile(file, 'hello');
await assertRejects(() => writeWindowsZoneIdentifier(file));
});
});