test: moved to vitest from mocha/chai

damn vitest is so good
This commit is contained in:
alina 🌸 2023-11-09 00:20:43 +03:00
parent 1abf35e30c
commit 96a443f8d3
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
90 changed files with 1344 additions and 1859 deletions

View file

@ -226,7 +226,7 @@ module.exports = {
},
},
{
files: ['**/scripts/**', '*.spec.ts', 'packages/create-*/**', '**/build.config.cjs'],
files: ['**/scripts/**', '*.test.ts', 'packages/create-*/**', '**/build.config.cjs'],
rules: {
'no-console': 'off',
'no-restricted-imports': 'off',

View file

@ -34,7 +34,7 @@ jobs:
run: pnpm run lint:ci
- name: 'Circular dependencies'
run: pnpm run lint:dpdm
- run: pnpm run test:all:ci
- run: pnpm run test
e2e:
runs-on: ubuntu-latest
needs: test

View file

@ -1,3 +0,0 @@
{
"node-option": ["experimental-specifier-resolution=node", "loader=ts-node/esm"]
}

View file

@ -8,8 +8,9 @@
"scripts": {
"prepare": "husky install",
"postinstall": "node scripts/validate-deps-versions.mjs",
"test:all": "pnpm run -r --parallel test",
"test:all:ci": "pnpm run -r test",
"test": "vitest run && pnpm run -r test",
"test:dev": "vitest watch",
"test:coverage": "vitest run --coverage",
"lint": "eslint .",
"lint:ci": "NODE_OPTIONS=\"--max_old_space_size=8192\" eslint --config .eslintrc.ci.js .",
"lint:tsc": "pnpm -r --parallel exec tsc --build",
@ -27,15 +28,11 @@
"devDependencies": {
"@commitlint/cli": "^17.6.5",
"@commitlint/config-conventional": "^17.6.5",
"@types/chai": "4.3.5",
"@types/chai-spies": "^1.0.4",
"@types/mocha": "10.0.1",
"@types/node-forge": "1.3.2",
"@types/ws": "8.5.4",
"@typescript-eslint/eslint-plugin": "6.4.0",
"@typescript-eslint/parser": "6.4.0",
"chai": "4.3.7",
"chai-spies": "^1.0.0",
"@vitest/coverage-v8": "^0.34.6",
"dotenv-flow": "3.2.0",
"dpdm": "^3.14.0",
"eslint": "8.47.0",
@ -47,15 +44,15 @@
"glob": "10.2.6",
"husky": "^8.0.3",
"lint-staged": "^13.2.2",
"mocha": "10.2.0",
"node-forge": "1.3.1",
"nyc": "15.1.0",
"prettier": "3.0.3",
"rimraf": "5.0.1",
"semver": "7.5.1",
"ts-node": "10.9.1",
"tsconfig-paths": "^4.2.0",
"typedoc": "0.25.3",
"typescript": "5.0.4"
"typescript": "5.0.4",
"vite": "^4.5.0",
"vitest": "^0.34.6"
}
}

View file

@ -8,8 +8,6 @@
"main": "src/index.ts",
"type": "module",
"scripts": {
"test": "mocha \"tests/**/*.spec.ts\"",
"docs": "typedoc",
"build": "pnpm run -w build-package client",
"gen-client": "node ./scripts/generate-client.cjs",
"gen-updates": "node ./scripts/generate-updates.cjs"

View file

@ -1,19 +1,22 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { hexDecodeToBuffer, utf8EncodeToBuffer } from '@mtcute/core/utils.js'
import { isProbablyPlainText } from '../src/utils/file-utils.js'
import { isProbablyPlainText } from './file-utils.js'
describe('isProbablyPlainText', () => {
it('should return true for buffers only containing printable ascii', () => {
expect(isProbablyPlainText(utf8EncodeToBuffer('hello this is some ascii text'))).to.be.true
expect(isProbablyPlainText(utf8EncodeToBuffer('hello this is some ascii text\nwith unix new lines'))).to.be.true
expect(isProbablyPlainText(utf8EncodeToBuffer('hello this is some ascii text\r\nwith windows new lines'))).to.be.true
expect(isProbablyPlainText(utf8EncodeToBuffer('hello this is some ascii text\n\twith unix new lines and tabs'))).to.be
expect(isProbablyPlainText(utf8EncodeToBuffer('hello this is some ascii text\r\nwith windows new lines'))).to.be
.true
expect(isProbablyPlainText(utf8EncodeToBuffer('hello this is some ascii text\r\n\twith windows new lines and tabs')))
expect(isProbablyPlainText(utf8EncodeToBuffer('hello this is some ascii text\n\twith unix new lines and tabs')))
.to.be.true
expect(
isProbablyPlainText(
utf8EncodeToBuffer('hello this is some ascii text\r\n\twith windows new lines and tabs'),
),
).to.be.true
})
it('should return false for buffers containing some binary data', () => {

View file

@ -1,7 +1,6 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { memoizeGetters } from '../src/utils/memoize.js'
import { memoizeGetters } from './memoize.js'
describe('memoizeGetters', () => {
it('should memoize getters', () => {

View file

@ -1,8 +1,7 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { Readable } from 'node:stream'
import { describe, expect, it } from 'vitest'
import { createChunkedReader, nodeReadableToWeb } from '../src/utils/stream-utils.js'
import { createChunkedReader, nodeReadableToWeb } from './stream-utils.js'
describe('createChunkedReader', () => {
it('should correctly handle chunks smaller than chunkSize', async () => {

View file

@ -1,9 +0,0 @@
{
"extends": "../../../tsconfig.json",
"include": [
".",
],
"references": [
{ "path": "../" },
]
}

View file

@ -8,7 +8,6 @@
"main": "src/index.ts",
"type": "module",
"scripts": {
"test": "mocha \"tests/**/*.spec.ts\"",
"build": "pnpm run -w build-package core"
},
"browser": {

View file

@ -1,15 +1,11 @@
/* eslint-disable no-restricted-globals */
import chai, { expect } from 'chai'
import spies from 'chai-spies'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { TlReaderMap } from '@mtcute/tl-runtime'
import { AuthKey } from '../src/network/auth-key.js'
import { NodeCryptoProvider } from '../src/utils/crypto/node.js'
import { LogManager } from '../src/utils/index.js'
chai.use(spies)
import { NodeCryptoProvider } from '../utils/crypto/node.js'
import { LogManager } from '../utils/index.js'
import { AuthKey } from './auth-key.js'
const authKey = Buffer.alloc(
2048 / 8,

View file

@ -0,0 +1,79 @@
import { describe, expect, it } from 'vitest'
import { hexDecodeToBuffer, hexEncode } from '@mtcute/tl-runtime'
import { IntermediatePacketCodec, TransportError } from '../../index.js'
describe('IntermediatePacketCodec', () => {
it('should return correct tag', () => {
expect(hexEncode(new IntermediatePacketCodec().tag())).eq('eeeeeeee')
})
it('should correctly parse immediate framing', () =>
new Promise<void>((done) => {
const codec = new IntermediatePacketCodec()
codec.on('packet', (data: Uint8Array) => {
expect([...data]).eql([5, 1, 2, 3, 4])
done()
})
codec.feed(hexDecodeToBuffer('050000000501020304'))
}))
it('should correctly parse incomplete framing', () =>
new Promise<void>((done) => {
const codec = new IntermediatePacketCodec()
codec.on('packet', (data: Uint8Array) => {
expect([...data]).eql([5, 1, 2, 3, 4])
done()
})
codec.feed(hexDecodeToBuffer('050000000501'))
codec.feed(hexDecodeToBuffer('020304'))
}))
it('should correctly parse multiple streamed packets', () =>
new Promise<void>((done) => {
const codec = new IntermediatePacketCodec()
let number = 0
codec.on('packet', (data: Uint8Array) => {
if (number === 0) {
expect([...data]).eql([5, 1, 2, 3, 4])
number = 1
} else {
expect([...data]).eql([3, 1, 2, 3, 1])
done()
}
})
codec.feed(hexDecodeToBuffer('050000000501'))
codec.feed(hexDecodeToBuffer('020304050000'))
codec.feed(hexDecodeToBuffer('000301020301'))
}))
it('should correctly parse transport errors', () =>
new Promise<void>((done) => {
const codec = new IntermediatePacketCodec()
codec.on('error', (err: TransportError) => {
expect(err).to.have.instanceOf(TransportError)
expect(err.code).eq(404)
done()
})
codec.feed(hexDecodeToBuffer('040000006cfeffff'))
}))
it('should reset when called reset()', () =>
new Promise<void>((done) => {
const codec = new IntermediatePacketCodec()
codec.on('packet', (data: Uint8Array) => {
expect([...data]).eql([1, 2, 3, 4, 5])
done()
})
codec.feed(hexDecodeToBuffer('ff0000001234567812345678'))
codec.reset()
codec.feed(hexDecodeToBuffer('050000000102030405'))
}))
})

View file

@ -1,9 +1,8 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { hexDecodeToBuffer } from '@mtcute/tl-runtime'
import { bigIntToBuffer, bufferToBigInt } from '../src/utils/index.js'
import { bigIntToBuffer, bufferToBigInt } from './index.js'
describe('bigIntToBuffer', () => {
it('should handle writing to BE', () => {

View file

@ -1,10 +1,9 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { hexEncode, utf8Decode, utf8EncodeToBuffer } from '@mtcute/tl-runtime'
import { buffersEqual, bufferToReversed, cloneBuffer, concatBuffers, randomBytes } from '../src/utils/buffer-utils.js'
import { xorBuffer, xorBufferInPlace } from '../src/utils/crypto/utils.js'
import { buffersEqual, bufferToReversed, cloneBuffer, concatBuffers, randomBytes } from './buffer-utils.js'
import { xorBuffer, xorBufferInPlace } from './crypto/utils.js'
describe('buffersEqual', () => {
it('should return true for equal buffers', () => {

View file

@ -1,15 +1,11 @@
import { expect } from 'chai'
import * as crypto from 'crypto'
import { describe, it } from 'mocha'
import { beforeAll, expect, it } from 'vitest'
import { hexDecodeToBuffer, hexEncode, utf8EncodeToBuffer } from '@mtcute/tl-runtime'
import { NodeCryptoProvider } from '../src/utils/crypto/node.js'
import { WebCryptoProvider } from '../src/utils/crypto/web.js'
import { ICryptoProvider } from '../src/utils/index.js'
import { ICryptoProvider } from './abstract.js'
export function testCryptoProvider(c: ICryptoProvider): void {
before(() => c.initialize?.())
beforeAll(() => c.initialize?.())
it('should calculate sha1', () => {
expect(hexEncode(c.sha1(utf8EncodeToBuffer('')))).to.eq('da39a3ee5e6b4b0d3255bfef95601890afd80709')
@ -98,23 +94,3 @@ export function testCryptoProvider(c: ICryptoProvider): void {
).to.eq('99706487a1cde613bc6de0b6f24b1c7aa448c8b9c3403e3467a8cad89340f53b')
})
}
describe('NodeCryptoProvider', () => {
if (typeof process === 'undefined') {
console.warn('Skipping NodeCryptoProvider tests')
return
}
testCryptoProvider(new NodeCryptoProvider())
})
describe('WebCryptoProvider', () => {
if (typeof crypto.subtle === 'undefined') {
console.warn('Skipping WebCryptoProvider tests')
return
}
testCryptoProvider(new WebCryptoProvider({ subtle: crypto.subtle }))
})

View file

@ -0,0 +1,24 @@
import { describe, expect, it } from 'vitest'
import { hexDecodeToBuffer, hexEncode } from '@mtcute/tl-runtime'
import { factorizePQSync } from './factorization.js'
describe(
'prime factorization',
function () {
it('should decompose PQ to prime factors P and Q', () => {
const testFactorization = (pq: string, p: string, q: string) => {
const [p1, q1] = factorizePQSync(hexDecodeToBuffer(pq))
expect(hexEncode(p1)).eq(p.toLowerCase())
expect(hexEncode(q1)).eq(q.toLowerCase())
}
// from samples at https://core.telegram.org/mtproto/samples-auth_key
testFactorization('17ED48941A08F981', '494C553B', '53911073')
// random example
testFactorization('14fcab4dfc861f45', '494c5c99', '494c778d')
})
},
{ timeout: 10000 },
) // since PQ factorization relies on RNG, it may take a while (or may not!)

View file

@ -1,8 +1,7 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { NodeCryptoProvider } from '../src/utils/crypto/node.js'
import { parsePublicKey } from '../src/utils/index.js'
import { parsePublicKey } from '../index.js'
import { NodeCryptoProvider } from './node.js'
const crypto = new NodeCryptoProvider()

View file

@ -0,0 +1,139 @@
import { describe, expect, it } from 'vitest'
import { millerRabin } from './miller-rabin.js'
describe(
'miller-rabin test',
function () {
const testMillerRabin = (n: number | string | bigint, isPrime: boolean) => {
expect(millerRabin(BigInt(n))).eq(isPrime)
}
it('should correctly label small primes as probable primes', () => {
const smallOddPrimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
for (const prime of smallOddPrimes) {
testMillerRabin(prime, true)
}
})
it('should correctly label small odd composite numbers as composite', () => {
const smallOddPrimes = [9, 15, 21, 25, 27, 33, 35]
for (const prime of smallOddPrimes) {
testMillerRabin(prime, false)
}
})
// primes are generated using `openssl prime -generate -bits <bits>`
it('should work for 512-bit numbers', () => {
testMillerRabin(
'8411445470921866378538628788380866906358949375899610911537071281076627385046125382763689993349183284546479522400013151510610266158235924343045768103605519',
true,
)
testMillerRabin(
'11167561990563990242158096122232207092938761092751537312016255867850441858086589598418467012717458858604863547175649456433632887622140170743409535470973399',
true,
)
testMillerRabin(
'11006717791910450367418249787526506184731090161438431250022510598653874155081488487035840577645711578911087148186160668569071839053453201592321650008610329',
true,
)
testMillerRabin(
'12224330340162812215033324917156282302617911690617664923428569636370785775561435789211091021550357876767050350997458404009005800772805534351607294516706177',
true,
)
// above numbers but -2 (not prime)
testMillerRabin(
'8411445470921866378538628788380866906358949375899610911537071281076627385046125382763689993349183284546479522400013151510610266158235924343045768103605517',
false,
)
testMillerRabin(
'11167561990563990242158096122232207092938761092751537312016255867850441858086589598418467012717458858604863547175649456433632887622140170743409535470973397',
false,
)
testMillerRabin(
'11006717791910450367418249787526506184731090161438431250022510598653874155081488487035840577645711578911087148186160668569071839053453201592321650008610327',
false,
)
testMillerRabin(
'12224330340162812215033324917156282302617911690617664923428569636370785775561435789211091021550357876767050350997458404009005800772805534351607294516706175',
false,
)
})
it('should work for 1024-bit numbers', () => {
testMillerRabin(
'94163180970530844245052892199633535954736903357996153321496979115367320260897793334681106861766748541439161886270777106456088209508872459550450259737267142959061663564218457086654112219462515165219295402175541003899136060178102898376369981338103600856012709228116661479275753497725541132207243717937379815409',
true,
)
testMillerRabin(
'97324962433497727515811278760066576725849776656602017497363465683978397629803148191267105308901733336070351381654371470561376353774017284623969415330564867697353080030917333974193741719718950105404732792050882127213356260415251087867407489400712288570880407613514781891914135956778687719588061176455381937003',
true,
)
testMillerRabin(
'92511311413226091818378551616231701579277597795073142338527410334932345968554993390789667936819230228388142960299649466238701015865565141753710450319875546944139442823075990348978746055937500467483161699883905850192191164043687791185635729923497381849380102040768674652775240505782671289535260164547714030567',
true,
)
testMillerRabin(
'98801756216479639848708157708947504990501845258427605711852570166662700681215707617225664134994147912417941920327932092748574265476658124536672887141144222716123085451749764522435906007567360583062117498919471220566974634924384147341592903939264267901029640119196259026154529723870788246284629644039137378253',
true,
)
// above numbers but -2 (not prime)
testMillerRabin(
'94163180970530844245052892199633535954736903357996153321496979115367320260897793334681106861766748541439161886270777106456088209508872459550450259737267142959061663564218457086654112219462515165219295402175541003899136060178102898376369981338103600856012709228116661479275753497725541132207243717937379815407',
false,
)
testMillerRabin(
'97324962433497727515811278760066576725849776656602017497363465683978397629803148191267105308901733336070351381654371470561376353774017284623969415330564867697353080030917333974193741719718950105404732792050882127213356260415251087867407489400712288570880407613514781891914135956778687719588061176455381937001',
false,
)
testMillerRabin(
'92511311413226091818378551616231701579277597795073142338527410334932345968554993390789667936819230228388142960299649466238701015865565141753710450319875546944139442823075990348978746055937500467483161699883905850192191164043687791185635729923497381849380102040768674652775240505782671289535260164547714030565',
false,
)
testMillerRabin(
'98801756216479639848708157708947504990501845258427605711852570166662700681215707617225664134994147912417941920327932092748574265476658124536672887141144222716123085451749764522435906007567360583062117498919471220566974634924384147341592903939264267901029640119196259026154529723870788246284629644039137378251',
false,
)
})
it('should work for 2048-bit numbers', () => {
testMillerRabin(
'28608382334358769588283288249494859626901014972463291352091976543138105382282108662849885913053034513852843449409838151123568984617793641641937583673207501643041336002587032201383537626393235736734494131431069043382068545865505150651648610506542819001961332454611129372758714288168807328523359776577571626967649079147416191592855529888846889532625386469236278694936872628305052827422772792103722178298844645210242389265273407924858034431614414896134561928996888883994953322861399988094086562513898527391555490352156627307769278185444897960555995383228897584818577375695810423475039211516849716140051437120083274285367',
true,
)
testMillerRabin(
'30244022694659482453371920976249272809817388822378671144866806600284132009663832003348737406289715119965835410140834733465553787513841966120831322372642881643693711233087233983267648392814127424201572290931937482043046169402667397610783447368703776842799852222745601531140231486417855517072392416789672922529566643118973930252809010605519948446055538976582290902060054788109497630796585770940656002892943575479533099350429655210881833493066716819282707441553612603960556051122162329171373373251909387401572866056121964608595895425640834764028568120995397759283490218181167000161310959711677055741632674632758727382743',
true,
)
testMillerRabin(
'30560953105766401423987964658775999222308579908395527900931049506803845883459894704297458477118152899910620180302473409631442956208933061650967001020981432894530064472547770442696756724169958362395601360296775798187903794894866967342028337982275745956538015473621792510615113531964380246815875830970404687926061637030085629909804357717955251735074071072456074274947993921828878633638119117086342305530526661796817095624933200483138188878398983149622639425550360394901699701985050966685840649129419227936413574227792077082510807968104733387734970009620450108276446659342203263759999068046251645984039420643003580284779',
true,
)
// above numbers but -2 (not prime)
testMillerRabin(
'28608382334358769588283288249494859626901014972463291352091976543138105382282108662849885913053034513852843449409838151123568984617793641641937583673207501643041336002587032201383537626393235736734494131431069043382068545865505150651648610506542819001961332454611129372758714288168807328523359776577571626967649079147416191592855529888846889532625386469236278694936872628305052827422772792103722178298844645210242389265273407924858034431614414896134561928996888883994953322861399988094086562513898527391555490352156627307769278185444897960555995383228897584818577375695810423475039211516849716140051437120083274285365',
false,
)
testMillerRabin(
'30244022694659482453371920976249272809817388822378671144866806600284132009663832003348737406289715119965835410140834733465553787513841966120831322372642881643693711233087233983267648392814127424201572290931937482043046169402667397610783447368703776842799852222745601531140231486417855517072392416789672922529566643118973930252809010605519948446055538976582290902060054788109497630796585770940656002892943575479533099350429655210881833493066716819282707441553612603960556051122162329171373373251909387401572866056121964608595895425640834764028568120995397759283490218181167000161310959711677055741632674632758727382741',
false,
)
testMillerRabin(
'30560953105766401423987964658775999222308579908395527900931049506803845883459894704297458477118152899910620180302473409631442956208933061650967001020981432894530064472547770442696756724169958362395601360296775798187903794894866967342028337982275745956538015473621792510615113531964380246815875830970404687926061637030085629909804357717955251735074071072456074274947993921828878633638119117086342305530526661796817095624933200483138188878398983149622639425550360394901699701985050966685840649129419227936413574227792077082510807968104733387734970009620450108276446659342203263759999068046251645984039420643003580284777',
false,
)
// dh_prime used by telegram, as seen in https://core.telegram.org/mtproto/security_guidelines
const telegramDhPrime =
'C7 1C AE B9 C6 B1 C9 04 8E 6C 52 2F 70 F1 3F 73 98 0D 40 23 8E 3E 21 C1 49 34 D0 37 56 3D 93 0F 48 19 8A 0A A7 C1 40 58 22 94 93 D2 25 30 F4 DB FA 33 6F 6E 0A C9 25 13 95 43 AE D4 4C CE 7C 37 20 FD 51 F6 94 58 70 5A C6 8C D4 FE 6B 6B 13 AB DC 97 46 51 29 69 32 84 54 F1 8F AF 8C 59 5F 64 24 77 FE 96 BB 2A 94 1D 5B CD 1D 4A C8 CC 49 88 07 08 FA 9B 37 8E 3C 4F 3A 90 60 BE E6 7C F9 A4 A4 A6 95 81 10 51 90 7E 16 27 53 B5 6B 0F 6B 41 0D BA 74 D8 A8 4B 2A 14 B3 14 4E 0E F1 28 47 54 FD 17 ED 95 0D 59 65 B4 B9 DD 46 58 2D B1 17 8D 16 9C 6B C4 65 B0 D6 FF 9C A3 92 8F EF 5B 9A E4 E4 18 FC 15 E8 3E BE A0 F8 7F A9 FF 5E ED 70 05 0D ED 28 49 F4 7B F9 59 D9 56 85 0C E9 29 85 1F 0D 81 15 F6 35 B1 05 EE 2E 4E 15 D0 4B 24 54 BF 6F 4F AD F0 34 B1 04 03 11 9C D8 E3 B9 2F CC 5B'
testMillerRabin(BigInt('0x' + telegramDhPrime.replace(/ /g, '')), true)
})
},
{ timeout: 10000 },
) // since miller-rabin factorization relies on RNG, it may take a while (or may not!)

View file

@ -1,17 +1,8 @@
/* eslint-disable no-restricted-globals,@typescript-eslint/no-unsafe-assignment */
// for whatever reason eslint doesn't properly handle chai-spies typings
import chai, { expect } from 'chai'
import spies from 'chai-spies'
import { describe, it } from 'mocha'
/* eslint-disable no-restricted-globals */
import { describe, expect, it, vi } from 'vitest'
import {
createAesIgeForMessage,
createAesIgeForMessageOld,
generateKeyAndIvFromNonce,
} from '../src/utils/crypto/mtproto.js'
import { NodeCryptoProvider } from '../src/utils/crypto/node.js'
chai.use(spies)
import { createAesIgeForMessage, createAesIgeForMessageOld, generateKeyAndIvFromNonce } from './mtproto.js'
import { NodeCryptoProvider } from './node.js'
const authKey = Buffer.alloc(
2048 / 8,
@ -22,11 +13,11 @@ const messageKey = Buffer.from('25d701f2a29205526757825a99eb2d32')
describe('mtproto 2.0', () => {
it('should correctly derive message key and iv for client', () => {
const crypto = new NodeCryptoProvider()
const spy = chai.spy.on(crypto, 'createAesIge')
const spy = vi.spyOn(crypto, 'createAesIge')
createAesIgeForMessage(crypto, authKey, messageKey, true)
expect(spy).to.have.been.called.with.exactly(
expect(spy).toHaveBeenCalledWith(
Buffer.from('7acac59ab48cd370e478daf6c64545ab9f32d5c9197f25febe052110f61875ca', 'hex'),
Buffer.from('2746ccc19fc260c08f3d2696389f415392103dbcc3a8bf69da9394c3c3d95bd3', 'hex'),
)
@ -34,11 +25,11 @@ describe('mtproto 2.0', () => {
it('should correctly derive message key and iv for server', () => {
const crypto = new NodeCryptoProvider()
const spy = chai.spy.on(crypto, 'createAesIge')
const spy = vi.spyOn(crypto, 'createAesIge')
createAesIgeForMessage(crypto, authKey, messageKey, false)
expect(spy).to.have.been.called.with.exactly(
expect(spy).toHaveBeenCalledWith(
Buffer.from('c7cf179e7ebab144ba87de05415db4157d2fc66df4790b2fd405a6c8cbe4c0b3', 'hex'),
Buffer.from('0916a7bd9880eacd4eeb868577a4c6a50e76fca4ac5c1bcfbafe3b9f76ccd806', 'hex'),
)
@ -48,11 +39,11 @@ describe('mtproto 2.0', () => {
describe('mtproto 1.0', () => {
it('should correctly derive message key and iv for client', () => {
const crypto = new NodeCryptoProvider()
const spy = chai.spy.on(crypto, 'createAesIge')
const spy = vi.spyOn(crypto, 'createAesIge')
createAesIgeForMessageOld(crypto, authKey, messageKey, true)
expect(spy).to.have.been.called.with.exactly(
expect(spy).toHaveBeenCalledWith(
Buffer.from('aad61cb5b7be5e8435174d74665f8a978e85806d0970ad4958642ca49e3c8834', 'hex'),
Buffer.from('4065736fe6586e94aad9f024062f1b9988e8a44e2aff4e11aad61cb5b7be5e84', 'hex'),
)
@ -60,11 +51,11 @@ describe('mtproto 1.0', () => {
it('should correctly derive message key and iv for server', () => {
const crypto = new NodeCryptoProvider()
const spy = chai.spy.on(crypto, 'createAesIge')
const spy = vi.spyOn(crypto, 'createAesIge')
createAesIgeForMessageOld(crypto, authKey, messageKey, false)
expect(spy).to.have.been.called.with.exactly(
expect(spy).toHaveBeenCalledWith(
Buffer.from('d57682a17105e43b92bc5025ea80e88ef708240fc19450dfe072a8760f9534da', 'hex'),
Buffer.from('07addff7beeb7705ef3a9d5090bd73c992d57291bb8a7079d57682a17105e43b', 'hex'),
)

View file

@ -0,0 +1,14 @@
import { describe } from 'vitest'
import { testCryptoProvider } from './crypto.test-utils.js'
import { NodeCryptoProvider } from './node.js'
describe('NodeCryptoProvider', () => {
if (typeof process === 'undefined') {
console.warn('Skipping NodeCryptoProvider tests')
return
}
testCryptoProvider(new NodeCryptoProvider())
})

View file

@ -0,0 +1,20 @@
import { describe } from 'vitest'
import { testCryptoProvider } from './crypto.test-utils.js'
import { WebCryptoProvider } from './web.js'
describe('WebCryptoProvider', async () => {
let subtle = globalThis.crypto?.subtle
if (!subtle && typeof process !== 'undefined') {
subtle = await import('crypto').then((m) => m.subtle)
}
if (!subtle) {
console.warn('Skipping WebCryptoProvider tests (no crypto.subtle)')
return
}
testCryptoProvider(new WebCryptoProvider({ subtle }))
})

View file

@ -1,8 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { links } from '../../src/utils/links/index.js'
import { links } from './index.js'
describe('Deep links', function () {
describe('Bot start links', () => {

View file

@ -1,8 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { links } from '../../src/utils/links/index.js'
import { links } from './index.js'
describe('Deep links', function () {
describe('Chat invite links', () => {

View file

@ -1,8 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { links } from '../../src/utils/links/index.js'
import { links } from './index.js'
describe('Deep links', function () {
describe('Video chat links', () => {

View file

@ -1,8 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { links } from '../../src/utils/links/index.js'
import { links } from './index.js'
describe('Deep links', function () {
describe('MTProxy links', () => {

View file

@ -1,8 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { links } from '../../src/utils/links/index.js'
import { links } from './index.js'
describe('Deep links', function () {
describe('Public username links', () => {

View file

@ -1,7 +1,6 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { LruMap } from '../utils.js'
import { LruMap } from './lru-map.js'
describe('LruMap', () => {
it('Map backend', () => {

View file

@ -1,8 +1,7 @@
import { expect } from 'chai'
import Long from 'long'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { LruSet } from '../utils.js'
import { LruSet } from './lru-set.js'
describe('LruSet', () => {
describe('for strings', () => {

View file

@ -1,71 +0,0 @@
// import { expect } from 'chai'
// import { randomBytes } from 'crypto'
// import { describe, it } from 'mocha'
//
// import __tlReaderMap from '@mtcute/tl/binary/reader'
// import { TlBinaryReader } from '@mtcute/tl-runtime'
//
// import { createTestTelegramClient } from './utils.js'
//
// // eslint-disable-next-line @typescript-eslint/no-var-requires
// require('dotenv-flow').config()
//
// describe('fuzz : packet', async function () {
// this.timeout(45000)
//
// it('random packet', async () => {
// const client = createTestTelegramClient()
//
// await client.connect()
// await client.waitUntilUsable()
//
// let errors = 0
//
// const conn = client.primaryConnection
// // eslint-disable-next-line dot-notation
// const mtproto = conn['_session']
//
// for (let i = 0; i < 100; i++) {
// const payload = randomBytes(Math.round(Math.random() * 16) * 16)
//
// try {
// // eslint-disable-next-line dot-notation
// conn['_handleRawMessage'](
// mtproto.getMessageId().sub(1),
// 0,
// new TlBinaryReader(__tlReaderMap, payload),
// )
// } catch (e) {
// errors += 1
// }
// }
//
// // similar test, but this time only using object ids that do exist
// const objectIds = Object.keys(__tlReaderMap)
//
// for (let i = 0; i < 100; i++) {
// const payload = randomBytes(
// (Math.round(Math.random() * 16) + 1) * 16,
// )
// const objectId = parseInt(
// objectIds[Math.round(Math.random() * objectIds.length)],
// )
// payload.writeUInt32LE(objectId, 0)
//
// try {
// // eslint-disable-next-line dot-notation
// conn['_handleRawMessage'](
// mtproto.getMessageId().sub(1),
// 0,
// new TlBinaryReader(__tlReaderMap, payload),
// )
// } catch (e) {
// errors += 1
// }
// }
//
// await client.close()
//
// expect(errors).gt(0)
// })
// })

View file

@ -1,77 +0,0 @@
// import { expect } from 'chai'
// import { randomBytes } from 'crypto'
// import { describe, it } from 'mocha'
//
// import { sleep } from '../../src.js'
// import { createTestTelegramClient } from './utils.js'
//
// // eslint-disable-next-line @typescript-eslint/no-var-requires
// require('dotenv-flow').config()
//
// describe('fuzz : session', async function () {
// this.timeout(45000)
//
// it('random auth_key', async () => {
// const client = createTestTelegramClient()
//
// // random key
// const initKey = randomBytes(256)
// await client.storage.setAuthKeyFor(2, initKey)
//
// // client is supposed to handle this and generate a new key
//
// const errors: Error[] = []
//
// const errorHandler = (err: Error) => {
// errors.push(err)
// }
//
// client.onError(errorHandler)
//
// await client.connect()
//
// await sleep(10000)
//
// await client.close()
//
// expect(errors.length).eq(0)
//
// expect((await client.storage.getAuthKeyFor(2))?.toString('hex')).not.eq(
// initKey.toString('hex'),
// )
// })
//
// it('random auth_key for other dc', async () => {
// const client = createTestTelegramClient()
//
// // random key for dc1
// const initKey = randomBytes(256)
// await client.storage.setAuthKeyFor(1, initKey)
//
// // client is supposed to handle this and generate a new key
//
// const errors: Error[] = []
//
// const errorHandler = (err: Error) => {
// errors.push(err)
// }
//
// client.onError(errorHandler)
//
// await client.connect()
// await client.waitUntilUsable()
//
// const conn = await client.createAdditionalConnection(1)
// await conn.sendRpc({ _: 'help.getConfig' })
//
// await sleep(10000)
//
// await client.close()
//
// expect(errors.length).eq(0)
//
// expect((await client.storage.getAuthKeyFor(1))?.toString('hex')).not.eq(
// initKey.toString('hex'),
// )
// })
// })

View file

@ -1,127 +0,0 @@
// import { expect } from 'chai'
// import { randomBytes } from 'crypto'
// import { EventEmitter } from 'events'
// import { describe, it } from 'mocha'
//
// import {
// BaseTelegramClient,
// defaultDcs,
// ITelegramTransport,
// NodeCryptoProvider,
// sleep,
// tl,
// TransportState,
// } from '../../src.js'
//
// // eslint-disable-next-line @typescript-eslint/no-var-requires
// require('dotenv-flow').config()
//
// class RandomBytesTransport extends EventEmitter implements ITelegramTransport {
// dc: tl.RawDcOption
// interval?: NodeJS.Timeout
//
// close(): void {
// clearInterval(this.interval)
// this.emit('close')
// this.interval = undefined
// }
//
// connect(dc: tl.RawDcOption): void {
// this.dc = dc
//
// setTimeout(() => this.emit('ready'), 0)
//
// this.interval = setInterval(() => {
// this.emit('message', randomBytes(64))
// }, 100)
// }
//
// currentDc(): tl.RawDcOption | null {
// return this.dc
// }
//
// send(_data: Buffer): Promise<void> {
// return Promise.resolve()
// }
//
// state(): TransportState {
// return this.interval ? TransportState.Ready : TransportState.Idle
// }
// }
//
// describe('fuzz : transport', function () {
// this.timeout(30000)
//
// it('RandomBytesTransport (no auth)', async () => {
// const client = new BaseTelegramClient({
// crypto: () => new NodeCryptoProvider(),
// transport: () => new RandomBytesTransport(),
// apiId: 0,
// apiHash: '',
// defaultDc: defaultDcs.defaultTestDc,
// })
// client.log.level = 0
//
// const errors: Error[] = []
//
// client.onError((err) => {
// errors.push(err)
// })
//
// await client.connect()
// await sleep(15000)
// await client.close()
//
// expect(errors.length).gt(0)
// errors.forEach((err) => {
// expect(err.message).match(/unknown object id/i)
// })
// })
//
// it('RandomBytesTransport (with auth)', async () => {
// const client = new BaseTelegramClient({
// crypto: () => new NodeCryptoProvider(),
// transport: () => new RandomBytesTransport(),
// apiId: 0,
// apiHash: '',
// defaultDc: defaultDcs.defaultTestDc,
// })
// client.log.level = 0
//
// // random key just to make it think it already has one
// await client.storage.setAuthKeyFor(2, randomBytes(256))
//
// // in this case, there will be no actual errors, only
// // warnings like 'received message with unknown authKey'
// //
// // to test for that, we hook into `decryptMessage` and make
// // sure that it returns `null`
//
// await client.connect()
//
// let hadNonNull = false
//
// const decryptMessage =
// // eslint-disable-next-line dot-notation
// client.primaryConnection['_session'].decryptMessage
//
// // ехал any через any
// // видит any - any, any
// // сунул any any в any
// // any any any any
// // eslint-disable-next-line dot-notation
// ;(client.primaryConnection['_session'] as any).decryptMessage = (
// buf: any,
// cb: any,
// ) =>
// decryptMessage.call(this, buf, (...args: any[]) => {
// cb(...(args as any))
// hadNonNull = true
// })
//
// await sleep(15000)
// await client.close()
//
// expect(hadNonNull).false
// })
// })

View file

@ -1,17 +0,0 @@
// import { BaseTelegramClient, TcpTransport } from '../../src.js'
// import { NodeCryptoProvider } from '../../utils.js'
// export function createTestTelegramClient() {
// const tg = new BaseTelegramClient({
// // provided explicitly because mocha
// crypto: () => new NodeCryptoProvider(),
// transport: () => new TcpTransport(),
// // example values from tdlib
// apiId: 94575,
// apiHash: 'a3406de8d171bb422bb6ddf3bbd800e2',
// testMode: true,
// })
// tg.log.level = 0
// return tg
// }

View file

@ -1,138 +0,0 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { millerRabin } from '../src/utils/crypto/miller-rabin.js'
describe('miller-rabin test', function () {
this.timeout(10000) // since miller-rabin factorization relies on RNG, it may take a while (or may not!)
const testMillerRabin = (n: number | string | bigint, isPrime: boolean) => {
expect(millerRabin(BigInt(n))).eq(isPrime)
}
it('should correctly label small primes as probable primes', () => {
const smallOddPrimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
for (const prime of smallOddPrimes) {
testMillerRabin(prime, true)
}
})
it('should correctly label small odd composite numbers as composite', () => {
const smallOddPrimes = [9, 15, 21, 25, 27, 33, 35]
for (const prime of smallOddPrimes) {
testMillerRabin(prime, false)
}
})
// primes are generated using `openssl prime -generate -bits <bits>`
it('should work for 512-bit numbers', () => {
testMillerRabin(
'8411445470921866378538628788380866906358949375899610911537071281076627385046125382763689993349183284546479522400013151510610266158235924343045768103605519',
true,
)
testMillerRabin(
'11167561990563990242158096122232207092938761092751537312016255867850441858086589598418467012717458858604863547175649456433632887622140170743409535470973399',
true,
)
testMillerRabin(
'11006717791910450367418249787526506184731090161438431250022510598653874155081488487035840577645711578911087148186160668569071839053453201592321650008610329',
true,
)
testMillerRabin(
'12224330340162812215033324917156282302617911690617664923428569636370785775561435789211091021550357876767050350997458404009005800772805534351607294516706177',
true,
)
// above numbers but -2 (not prime)
testMillerRabin(
'8411445470921866378538628788380866906358949375899610911537071281076627385046125382763689993349183284546479522400013151510610266158235924343045768103605517',
false,
)
testMillerRabin(
'11167561990563990242158096122232207092938761092751537312016255867850441858086589598418467012717458858604863547175649456433632887622140170743409535470973397',
false,
)
testMillerRabin(
'11006717791910450367418249787526506184731090161438431250022510598653874155081488487035840577645711578911087148186160668569071839053453201592321650008610327',
false,
)
testMillerRabin(
'12224330340162812215033324917156282302617911690617664923428569636370785775561435789211091021550357876767050350997458404009005800772805534351607294516706175',
false,
)
})
it('should work for 1024-bit numbers', () => {
testMillerRabin(
'94163180970530844245052892199633535954736903357996153321496979115367320260897793334681106861766748541439161886270777106456088209508872459550450259737267142959061663564218457086654112219462515165219295402175541003899136060178102898376369981338103600856012709228116661479275753497725541132207243717937379815409',
true,
)
testMillerRabin(
'97324962433497727515811278760066576725849776656602017497363465683978397629803148191267105308901733336070351381654371470561376353774017284623969415330564867697353080030917333974193741719718950105404732792050882127213356260415251087867407489400712288570880407613514781891914135956778687719588061176455381937003',
true,
)
testMillerRabin(
'92511311413226091818378551616231701579277597795073142338527410334932345968554993390789667936819230228388142960299649466238701015865565141753710450319875546944139442823075990348978746055937500467483161699883905850192191164043687791185635729923497381849380102040768674652775240505782671289535260164547714030567',
true,
)
testMillerRabin(
'98801756216479639848708157708947504990501845258427605711852570166662700681215707617225664134994147912417941920327932092748574265476658124536672887141144222716123085451749764522435906007567360583062117498919471220566974634924384147341592903939264267901029640119196259026154529723870788246284629644039137378253',
true,
)
// above numbers but -2 (not prime)
testMillerRabin(
'94163180970530844245052892199633535954736903357996153321496979115367320260897793334681106861766748541439161886270777106456088209508872459550450259737267142959061663564218457086654112219462515165219295402175541003899136060178102898376369981338103600856012709228116661479275753497725541132207243717937379815407',
false,
)
testMillerRabin(
'97324962433497727515811278760066576725849776656602017497363465683978397629803148191267105308901733336070351381654371470561376353774017284623969415330564867697353080030917333974193741719718950105404732792050882127213356260415251087867407489400712288570880407613514781891914135956778687719588061176455381937001',
false,
)
testMillerRabin(
'92511311413226091818378551616231701579277597795073142338527410334932345968554993390789667936819230228388142960299649466238701015865565141753710450319875546944139442823075990348978746055937500467483161699883905850192191164043687791185635729923497381849380102040768674652775240505782671289535260164547714030565',
false,
)
testMillerRabin(
'98801756216479639848708157708947504990501845258427605711852570166662700681215707617225664134994147912417941920327932092748574265476658124536672887141144222716123085451749764522435906007567360583062117498919471220566974634924384147341592903939264267901029640119196259026154529723870788246284629644039137378251',
false,
)
})
it('should work for 2048-bit numbers', () => {
testMillerRabin(
'28608382334358769588283288249494859626901014972463291352091976543138105382282108662849885913053034513852843449409838151123568984617793641641937583673207501643041336002587032201383537626393235736734494131431069043382068545865505150651648610506542819001961332454611129372758714288168807328523359776577571626967649079147416191592855529888846889532625386469236278694936872628305052827422772792103722178298844645210242389265273407924858034431614414896134561928996888883994953322861399988094086562513898527391555490352156627307769278185444897960555995383228897584818577375695810423475039211516849716140051437120083274285367',
true,
)
testMillerRabin(
'30244022694659482453371920976249272809817388822378671144866806600284132009663832003348737406289715119965835410140834733465553787513841966120831322372642881643693711233087233983267648392814127424201572290931937482043046169402667397610783447368703776842799852222745601531140231486417855517072392416789672922529566643118973930252809010605519948446055538976582290902060054788109497630796585770940656002892943575479533099350429655210881833493066716819282707441553612603960556051122162329171373373251909387401572866056121964608595895425640834764028568120995397759283490218181167000161310959711677055741632674632758727382743',
true,
)
testMillerRabin(
'30560953105766401423987964658775999222308579908395527900931049506803845883459894704297458477118152899910620180302473409631442956208933061650967001020981432894530064472547770442696756724169958362395601360296775798187903794894866967342028337982275745956538015473621792510615113531964380246815875830970404687926061637030085629909804357717955251735074071072456074274947993921828878633638119117086342305530526661796817095624933200483138188878398983149622639425550360394901699701985050966685840649129419227936413574227792077082510807968104733387734970009620450108276446659342203263759999068046251645984039420643003580284779',
true,
)
// above numbers but -2 (not prime)
testMillerRabin(
'28608382334358769588283288249494859626901014972463291352091976543138105382282108662849885913053034513852843449409838151123568984617793641641937583673207501643041336002587032201383537626393235736734494131431069043382068545865505150651648610506542819001961332454611129372758714288168807328523359776577571626967649079147416191592855529888846889532625386469236278694936872628305052827422772792103722178298844645210242389265273407924858034431614414896134561928996888883994953322861399988094086562513898527391555490352156627307769278185444897960555995383228897584818577375695810423475039211516849716140051437120083274285365',
false,
)
testMillerRabin(
'30244022694659482453371920976249272809817388822378671144866806600284132009663832003348737406289715119965835410140834733465553787513841966120831322372642881643693711233087233983267648392814127424201572290931937482043046169402667397610783447368703776842799852222745601531140231486417855517072392416789672922529566643118973930252809010605519948446055538976582290902060054788109497630796585770940656002892943575479533099350429655210881833493066716819282707441553612603960556051122162329171373373251909387401572866056121964608595895425640834764028568120995397759283490218181167000161310959711677055741632674632758727382741',
false,
)
testMillerRabin(
'30560953105766401423987964658775999222308579908395527900931049506803845883459894704297458477118152899910620180302473409631442956208933061650967001020981432894530064472547770442696756724169958362395601360296775798187903794894866967342028337982275745956538015473621792510615113531964380246815875830970404687926061637030085629909804357717955251735074071072456074274947993921828878633638119117086342305530526661796817095624933200483138188878398983149622639425550360394901699701985050966685840649129419227936413574227792077082510807968104733387734970009620450108276446659342203263759999068046251645984039420643003580284777',
false,
)
// dh_prime used by telegram, as seen in https://core.telegram.org/mtproto/security_guidelines
const telegramDhPrime =
'C7 1C AE B9 C6 B1 C9 04 8E 6C 52 2F 70 F1 3F 73 98 0D 40 23 8E 3E 21 C1 49 34 D0 37 56 3D 93 0F 48 19 8A 0A A7 C1 40 58 22 94 93 D2 25 30 F4 DB FA 33 6F 6E 0A C9 25 13 95 43 AE D4 4C CE 7C 37 20 FD 51 F6 94 58 70 5A C6 8C D4 FE 6B 6B 13 AB DC 97 46 51 29 69 32 84 54 F1 8F AF 8C 59 5F 64 24 77 FE 96 BB 2A 94 1D 5B CD 1D 4A C8 CC 49 88 07 08 FA 9B 37 8E 3C 4F 3A 90 60 BE E6 7C F9 A4 A4 A6 95 81 10 51 90 7E 16 27 53 B5 6B 0F 6B 41 0D BA 74 D8 A8 4B 2A 14 B3 14 4E 0E F1 28 47 54 FD 17 ED 95 0D 59 65 B4 B9 DD 46 58 2D B1 17 8D 16 9C 6B C4 65 B0 D6 FF 9C A3 92 8F EF 5B 9A E4 E4 18 FC 15 E8 3E BE A0 F8 7F A9 FF 5E ED 70 05 0D ED 28 49 F4 7B F9 59 D9 56 85 0C E9 29 85 1F 0D 81 15 F6 35 B1 05 EE 2E 4E 15 D0 4B 24 54 BF 6F 4F AD F0 34 B1 04 03 11 9C D8 E3 B9 2F CC 5B'
testMillerRabin(BigInt('0x' + telegramDhPrime.replace(/ /g, '')), true)
})
})

View file

@ -1,23 +0,0 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { hexDecodeToBuffer, hexEncode } from '@mtcute/tl-runtime'
import { factorizePQSync } from '../src/utils/crypto/factorization.js'
describe('prime factorization', function () {
this.timeout(10000) // since PQ factorization relies on RNG, it may take a while (or may not!)
it('should decompose PQ to prime factors P and Q', () => {
const testFactorization = (pq: string, p: string, q: string) => {
const [p1, q1] = factorizePQSync(hexDecodeToBuffer(pq))
expect(hexEncode(p1)).eq(p.toLowerCase())
expect(hexEncode(q1)).eq(q.toLowerCase())
}
// from samples at https://core.telegram.org/mtproto/samples-auth_key
testFactorization('17ED48941A08F981', '494C553B', '53911073')
// random example
testFactorization('14fcab4dfc861f45', '494c5c99', '494c778d')
})
})

View file

@ -1,75 +0,0 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { hexDecodeToBuffer, hexEncode } from '@mtcute/tl-runtime'
import { IntermediatePacketCodec, TransportError } from '../../src/index.js'
describe('IntermediatePacketCodec', () => {
it('should return correct tag', () => {
expect(hexEncode(new IntermediatePacketCodec().tag())).eq('eeeeeeee')
})
it('should correctly parse immediate framing', (done) => {
const codec = new IntermediatePacketCodec()
codec.on('packet', (data: Uint8Array) => {
expect([...data]).eql([5, 1, 2, 3, 4])
done()
})
codec.feed(hexDecodeToBuffer('050000000501020304'))
})
it('should correctly parse incomplete framing', (done) => {
const codec = new IntermediatePacketCodec()
codec.on('packet', (data: Uint8Array) => {
expect([...data]).eql([5, 1, 2, 3, 4])
done()
})
codec.feed(hexDecodeToBuffer('050000000501'))
codec.feed(hexDecodeToBuffer('020304'))
})
it('should correctly parse multiple streamed packets', (done) => {
const codec = new IntermediatePacketCodec()
let number = 0
codec.on('packet', (data: Uint8Array) => {
if (number === 0) {
expect([...data]).eql([5, 1, 2, 3, 4])
number = 1
} else {
expect([...data]).eql([3, 1, 2, 3, 1])
done()
}
})
codec.feed(hexDecodeToBuffer('050000000501'))
codec.feed(hexDecodeToBuffer('020304050000'))
codec.feed(hexDecodeToBuffer('000301020301'))
})
it('should correctly parse transport errors', (done) => {
const codec = new IntermediatePacketCodec()
codec.on('error', (err: TransportError) => {
expect(err).to.have.instanceOf(TransportError)
expect(err.code).eq(404)
done()
})
codec.feed(hexDecodeToBuffer('040000006cfeffff'))
})
it('should reset when called reset()', (done) => {
const codec = new IntermediatePacketCodec()
codec.on('packet', (data: Uint8Array) => {
expect([...data]).eql([1, 2, 3, 4, 5])
done()
})
codec.feed(hexDecodeToBuffer('ff0000001234567812345678'))
codec.reset()
codec.feed(hexDecodeToBuffer('050000000102030405'))
})
})

View file

@ -1,9 +0,0 @@
{
"extends": "../../../tsconfig.json",
"include": [
".",
],
"references": [
{ "path": "../" },
]
}

View file

@ -14,9 +14,7 @@
"install": "node-gyp configure && node-gyp -j 16 build",
"rebuild:dev": "node-gyp configure --debug && node-gyp -j 16 rebuild --debug",
"rebuild": "node-gyp configure && node-gyp -j 16 rebuild",
"clean": "node-gyp clean",
"test": "mocha \"tests/**/*.spec.ts\"",
"docs": "typedoc"
"clean": "node-gyp clean"
},
"keepScripts": [
"install"

View file

@ -0,0 +1,9 @@
import { describe } from 'vitest'
// eslint-disable-next-line import/no-relative-packages
import { testCryptoProvider } from '../../core/src/utils/crypto/crypto.test-utils.js'
import { NodeNativeCryptoProvider } from './index.js'
describe('NodeNativeCryptoProvider', () => {
testCryptoProvider(new NodeNativeCryptoProvider())
})

View file

@ -1,9 +0,0 @@
import { describe } from 'mocha'
// eslint-disable-next-line import/no-relative-packages
import { testCryptoProvider } from '../../core/tests/crypto-providers.spec.js'
import { NodeNativeCryptoProvider } from '../src/index.js'
describe('NodeNativeCryptoProvider', () => {
testCryptoProvider(new NodeNativeCryptoProvider())
})

View file

@ -1,9 +0,0 @@
{
"extends": "../../../tsconfig.json",
"include": [
".",
],
"references": [
{ "path": "../" },
]
}

View file

@ -16,8 +16,6 @@
}
},
"scripts": {
"test": "mocha \"tests/**/*.spec.ts\"",
"docs": "typedoc",
"build": "pnpm run -w build-package dispatcher",
"gen-updates": "node ./scripts/generate.cjs"
},

View file

@ -1,5 +1,4 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { PeersIndex, TelegramClient } from '@mtcute/client'

View file

@ -8,8 +8,6 @@
"main": "src/index.ts",
"type": "module",
"scripts": {
"test": "mocha \"tests/**/*.spec.ts\"",
"docs": "typedoc",
"build": "pnpm run -w build-package file-id"
},
"distOnlyFields": {

View file

@ -1,11 +1,10 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { Long } from '@mtcute/core'
import { hexDecodeToBuffer } from '@mtcute/core/utils.js'
import { parseFileId } from '../src/index.js'
import { tdFileId as td } from '../src/types.js'
import { parseFileId } from './parse.js'
import { tdFileId as td } from './types.js'
// test file IDs are partially taken from https://github.com/luckydonald/telegram_file_id

View file

@ -1,7 +1,7 @@
import { expect } from 'chai'
import { describe } from 'mocha'
import { describe, expect, it } from 'vitest'
import { parseFileId, toUniqueFileId } from '../src/index.js'
import { parseFileId } from './parse.js'
import { toUniqueFileId } from './serialize-unique.js'
// test file IDs are partially taken from https://github.com/luckydonald/telegram_file_id

View file

@ -1,9 +1,8 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { hexDecodeToBuffer, hexEncode } from '@mtcute/core/utils.js'
import { telegramRleDecode, telegramRleEncode } from '../src/utils.js'
import { telegramRleDecode, telegramRleEncode } from './utils.js'
describe('telegramRleEncode', () => {
it('should not modify input if there are no \\x00', () => {

View file

@ -1,9 +0,0 @@
{
"extends": "../../../tsconfig.json",
"include": [
".",
],
"references": [
{ "path": "../" },
]
}

View file

@ -8,10 +8,7 @@
"main": "src/index.ts",
"type": "module",
"scripts": {
"test": "mocha \"tests/**/*.spec.ts\"",
"coverage": "nyc npm run test",
"build": "pnpm run -w build-package html-parser",
"docs": "typedoc"
"build": "pnpm run -w build-package html-parser"
},
"distOnlyFields": {
"exports": {

View file

@ -1,13 +1,12 @@
import { expect } from 'chai'
import Long from 'long'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { MessageEntity, TextWithEntities, tl } from '@mtcute/client'
// prettier has "html" special-cased which breaks the formatting
// this is not an issue when using normally, since we properly handle newlines/spaces,
// but here we want to test everything as it is
import { html as htm, HtmlUnparseOptions } from '../src/index.js'
import { html as htm, HtmlUnparseOptions } from './index.js'
const createEntity = <T extends tl.TypeMessageEntity['_']>(
type: T,

View file

@ -8,10 +8,7 @@
"main": "src/index.ts",
"type": "module",
"scripts": {
"test": "mocha \"tests/**/*.spec.ts\"",
"coverage": "nyc npm run test",
"build": "pnpm run -w build-package i18n",
"docs": "typedoc"
"build": "pnpm run -w build-package i18n"
},
"distOnlyFields": {
"exports": {

View file

@ -1,5 +1,4 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { Message, PeersIndex } from '@mtcute/client'
import { MessageContext } from '@mtcute/dispatcher'
@ -84,12 +83,15 @@ describe('i18n', () => {
})
it('should parse language from a message', () => {
const message = new MessageContext(null as never, new Message(
{ _: 'message', peerId: { _: 'peerUser', userId: 1 } } as never,
PeersIndex.from({
users: [{ _: 'user', id: 1, firstName: 'Пыня', langCode: 'ru' }],
}),
))
const message = new MessageContext(
null as never,
new Message(
{ _: 'message', peerId: { _: 'peerUser', userId: 1 } } as never,
PeersIndex.from({
users: [{ _: 'user', id: 1, firstName: 'Пыня', langCode: 'ru' }],
}),
),
)
expect(tr(message, 'direct')).to.equal('Привет')
})

View file

@ -8,10 +8,7 @@
"main": "src/index.ts",
"type": "module",
"scripts": {
"test": "mocha \"tests/**/*.spec.ts\"",
"coverage": "nyc npm run test",
"build": "pnpm run -w build-package markdown-parser",
"docs": "typedoc"
"build": "pnpm run -w build-package markdown-parser"
},
"distOnlyFields": {
"exports": {

View file

@ -1,11 +1,10 @@
import { expect } from 'chai'
import Long from 'long'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { MessageEntity, TextWithEntities, tl } from '@mtcute/client'
// md is special cased in prettier, we don't want that here
import { md as md_ } from '../src/index.js'
import { md as md_ } from './index.js'
const createEntity = <T extends tl.TypeMessageEntity['_']>(
type: T,

View file

@ -1,9 +0,0 @@
{
"extends": "../../../tsconfig.json",
"include": [
".",
],
"references": [
{ "path": "../" },
]
}

View file

@ -14,8 +14,8 @@ import {
tl,
TransportState,
} from '@mtcute/core'
import { buffersEqual } from '@mtcute/core/dist/esm/utils/index.js'
import { BaseTcpTransport } from '@mtcute/core/src/network/transports/tcp.js'
import { buffersEqual } from '@mtcute/core/utils.js'
import { FakeTlsPacketCodec, generateFakeTlsHeader } from './fake-tls.js'

View file

@ -8,8 +8,6 @@
"main": "src/index.ts",
"type": "module",
"scripts": {
"docs": "typedoc",
"test": "mocha \"tests/**/*.spec.ts\"",
"build": "pnpm run -w build-package test"
},
"dependencies": {

View file

@ -1,9 +1,8 @@
/* eslint-disable no-restricted-globals */
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { StubTelegramClient } from '../src/client.js'
import { createStub } from '../src/stub.js'
import { StubTelegramClient } from './client.js'
import { createStub } from './stub.js'
describe('client stub', () => {
it('should correctly intercept rpc calls', async () => {
@ -14,7 +13,7 @@ describe('client stub', () => {
await client.with(async () => {
const result = await client.call({ _: 'help.getConfig' })
expect(result).to.eql(stubConfig)
expect(result).toEqual(stubConfig)
})
})
@ -31,7 +30,7 @@ describe('client stub', () => {
await client.with(async () => {
await client.call({ _: 'help.getConfig' }).catch(() => {}) // ignore "client closed" error
expect(log).to.eql([
expect(log).toEqual([
'message ctor=dcf8f173', // msg_container
])
})

View file

@ -1,11 +1,10 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { BaseTelegramClient } from '@mtcute/core'
import { StubMemoryTelegramStorage } from '../src/storage.js'
import { createStub } from '../src/stub.js'
import { StubTelegramTransport } from '../src/transport.js'
import { StubMemoryTelegramStorage } from './storage.js'
import { createStub } from './stub.js'
import { StubTelegramTransport } from './transport.js'
describe('storage stub', () => {
it('should correctly intercept calls', async () => {
@ -43,6 +42,6 @@ describe('storage stub', () => {
await client.connect()
await client.call({ _: 'help.getConfig' }).catch(() => {}) // ignore "client closed" error
expect(log).to.eql(['load', 'save', 'destroy'])
expect(log).toEqual(['load', 'save', 'destroy'])
})
})

View file

@ -1,12 +1,11 @@
import { expect } from 'chai'
import Long from 'long'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { createStub } from '../src/index.js'
import { createStub } from './index.js'
describe('stub', () => {
it('should correctly generate simple stubs', () => {
expect(createStub('inputUser', { userId: 123 })).to.eql({
expect(createStub('inputUser', { userId: 123 })).toEqual({
_: 'inputUser',
userId: 123,
accessHash: Long.ZERO,
@ -14,7 +13,7 @@ describe('stub', () => {
})
it('should correctly generate stubs for optional fields', () => {
expect(createStub('updateChannelTooLong')).to.eql({
expect(createStub('updateChannelTooLong')).toEqual({
_: 'updateChannelTooLong',
channelId: 0,
pts: undefined,
@ -22,21 +21,21 @@ describe('stub', () => {
})
it('should correctly generate stubs for boolean flags', () => {
expect(createStub('account.finishTakeoutSession')).to.eql({
expect(createStub('account.finishTakeoutSession')).toEqual({
_: 'account.finishTakeoutSession',
success: false,
})
})
it('should correctly generate stubs for vectors', () => {
expect(createStub('messageActionChatAddUser')).to.eql({
expect(createStub('messageActionChatAddUser')).toEqual({
_: 'messageActionChatAddUser',
users: [],
})
})
it('should correctly generate stubs for nested types', () => {
expect(createStub('messageActionGroupCallScheduled', { scheduleDate: 123 })).to.eql({
expect(createStub('messageActionGroupCallScheduled', { scheduleDate: 123 })).toEqual({
_: 'messageActionGroupCallScheduled',
call: {
_: 'inputGroupCall',

View file

@ -1,10 +1,9 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { BaseTelegramClient } from '@mtcute/core'
import { createStub } from '../src/stub.js'
import { StubTelegramTransport } from '../src/transport.js'
import { createStub } from './stub.js'
import { StubTelegramTransport } from './transport.js'
describe('transport stub', () => {
it('should correctly intercept calls', async () => {
@ -22,9 +21,7 @@ describe('transport stub', () => {
new StubTelegramTransport({
onConnect: (dc, testMode) => {
log.push(`connect ${dc.ipAddress}:${dc.port} test=${testMode}`)
setTimeout(() => {
client.close().catch(() => {})
}, 10)
client.close().catch(() => {})
},
onMessage(msg) {
log.push(`message size=${msg.length}`)
@ -32,10 +29,9 @@ describe('transport stub', () => {
}),
})
await client.connect()
await new Promise((resolve) => client.once('closed', resolve))
await client.connect().catch(() => {}) // ignore "client closed" error
expect(log).to.eql([
expect(log).toEqual([
'message size=40', // req_pq_multi
'connect 1.2.3.4:1234 test=false',
])

View file

@ -7,7 +7,6 @@
"license": "MIT",
"type": "module",
"scripts": {
"test": "mocha \"tests/**/*.spec.ts\"",
"docs": "typedoc",
"build": "pnpm run -w build-package tl-runtime"
},

View file

@ -1,40 +1,39 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { base64Decode, base64DecodeToBuffer, base64Encode } from '../../src/encodings/base64.js'
import { base64Decode as base64DecodeWeb, base64Encode as base64EncodeWeb } from '../../src/encodings/base64.web.js'
import { base64Decode, base64DecodeToBuffer, base64Encode } from './base64.js'
import { base64Decode as base64DecodeWeb, base64Encode as base64EncodeWeb } from './base64.web.js'
describe('base64', () => {
it('should decode base64 string to existing buffer', () => {
const buf = new Uint8Array(4)
base64Decode(buf, 'AQIDBA==')
expect(buf).eql(new Uint8Array([1, 2, 3, 4]))
expect(buf).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should decode base64 string to new buffer', () => {
const buf = base64DecodeToBuffer('AQIDBA==')
expect(buf).eql(new Uint8Array([1, 2, 3, 4]))
expect(new Uint8Array(buf)).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should encode buffer to base64 string', () => {
const buf = new Uint8Array([1, 2, 3, 4])
expect(base64Encode(buf)).eq('AQIDBA==')
expect(base64Encode(buf)).toEqual('AQIDBA==')
})
it('should decode url-safe base64 string to existing buffer', () => {
const buf = new Uint8Array(4)
base64Decode(buf, 'AQIDBA', true)
expect(buf).eql(new Uint8Array([1, 2, 3, 4]))
expect(buf).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should decode url-safe base64 string to new buffer', () => {
const buf = base64DecodeToBuffer('AQIDBA', true)
expect(buf).eql(new Uint8Array([1, 2, 3, 4]))
expect(new Uint8Array(buf)).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should encode buffer to url-safe base64 string', () => {
const buf = new Uint8Array([1, 2, 3, 4])
expect(base64Encode(buf, true)).eq('AQIDBA')
expect(base64Encode(buf, true)).toEqual('AQIDBA')
})
})
@ -42,32 +41,32 @@ describe('base64.web', () => {
it('should decode base64 string to existing buffer', () => {
const buf = new Uint8Array(4)
base64DecodeWeb(buf, 'AQIDBA==')
expect(buf).eql(new Uint8Array([1, 2, 3, 4]))
expect(buf).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should decode base64 string to new buffer', () => {
const buf = base64DecodeToBuffer('AQIDBA==')
expect(buf).eql(new Uint8Array([1, 2, 3, 4]))
expect(new Uint8Array(buf)).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should encode buffer to base64 string', () => {
const buf = new Uint8Array([1, 2, 3, 4])
expect(base64EncodeWeb(buf)).eq('AQIDBA==')
expect(base64EncodeWeb(buf)).toEqual('AQIDBA==')
})
it('should decode url-safe base64 string to existing buffer', () => {
const buf = new Uint8Array(4)
base64DecodeWeb(buf, 'AQIDBA', true)
expect(buf).eql(new Uint8Array([1, 2, 3, 4]))
expect(buf).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should decode url-safe base64 string to new buffer', () => {
const buf = base64DecodeToBuffer('AQIDBA', true)
expect(buf).eql(new Uint8Array([1, 2, 3, 4]))
expect(new Uint8Array(buf)).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should encode buffer to url-safe base64 string', () => {
const buf = new Uint8Array([1, 2, 3, 4])
expect(base64EncodeWeb(buf, true)).eq('AQIDBA')
expect(base64EncodeWeb(buf, true)).toEqual('AQIDBA')
})
})

View file

@ -1,24 +1,27 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { hexDecode, hexDecodeToBuffer, hexEncode } from '../../src/encodings/hex.js'
import { hexDecode as hexDecodeWeb, hexDecodeToBuffer as hexDecodeToBufferWeb, hexEncode as hexEncodeWeb } from '../../src/encodings/hex.web.js'
import { hexDecode, hexDecodeToBuffer, hexEncode } from './hex.js'
import {
hexDecode as hexDecodeWeb,
hexDecodeToBuffer as hexDecodeToBufferWeb,
hexEncode as hexEncodeWeb,
} from './hex.web.js'
describe('hex', () => {
it('should decode hex string to existing buffer', () => {
const buf = new Uint8Array(4)
hexDecode(buf, '01020304')
expect(buf).eql(new Uint8Array([1, 2, 3, 4]))
expect(buf).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should decode hex string to new buffer', () => {
const buf = hexDecodeToBuffer('01020304')
expect(buf).eql(new Uint8Array([1, 2, 3, 4]))
expect(new Uint8Array(buf)).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should encode buffer to hex string', () => {
const buf = new Uint8Array([1, 2, 3, 4])
expect(hexEncode(buf)).eq('01020304')
expect(hexEncode(buf)).toEqual('01020304')
})
})
@ -26,16 +29,16 @@ describe('hex.web', () => {
it('should decode hex string to existing buffer', () => {
const buf = new Uint8Array(4)
hexDecodeWeb(buf, '01020304')
expect(buf).eql(new Uint8Array([1, 2, 3, 4]))
expect(buf).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should decode hex string to new buffer', () => {
const buf = hexDecodeToBufferWeb('01020304')
expect(buf).eql(new Uint8Array([1, 2, 3, 4]))
expect(buf).toEqual(new Uint8Array([1, 2, 3, 4]))
})
it('should encode buffer to hex string', () => {
const buf = new Uint8Array([1, 2, 3, 4])
expect(hexEncodeWeb(buf)).eq('01020304')
expect(hexEncodeWeb(buf)).toEqual('01020304')
})
})

View file

@ -1,13 +1,12 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { byteLengthUtf8, utf8Decode, utf8Encode, utf8EncodeToBuffer } from '../../src/encodings/utf8.js'
import { byteLengthUtf8, utf8Decode, utf8Encode, utf8EncodeToBuffer } from './utf8.js'
import {
byteLengthUtf8 as byteLengthUtf8Web,
utf8Decode as utf8DecodeWeb,
utf8Encode as utf8EncodeWeb,
utf8EncodeToBuffer as utf8EncodeToBufferWeb,
} from '../../src/encodings/utf8.web.js'
} from './utf8.web.js'
// since we use TextEncoder or native Buffer, we can skip testing the utf8 encoding itself
// we only need to test that the functions work as expected with offsets and lengths
@ -16,17 +15,17 @@ describe('utf8', () => {
it('should encode utf8 string into existing buffer', () => {
const buf = new Uint8Array(4)
utf8Encode(buf, 'abcd')
expect(buf).eql(new Uint8Array([97, 98, 99, 100]))
expect(buf).toEqual(new Uint8Array([97, 98, 99, 100]))
})
it('should encode utf8 string into new buffer', () => {
const buf = utf8EncodeToBuffer('abcd')
expect(buf).eql(new Uint8Array([97, 98, 99, 100]))
expect(new Uint8Array(buf)).toEqual(new Uint8Array([97, 98, 99, 100]))
})
it('should decode utf8 string from existing buffer', () => {
const buf = new Uint8Array([97, 98, 99, 100])
expect(utf8Decode(buf)).eq('abcd')
expect(utf8Decode(buf)).toEqual('abcd')
})
})
@ -34,33 +33,33 @@ describe('utf8.web', () => {
it('should encode utf8 string into existing buffer', () => {
const buf = new Uint8Array(4)
utf8EncodeWeb(buf, 'abcd')
expect(buf).eql(new Uint8Array([97, 98, 99, 100]))
expect(buf).toEqual(new Uint8Array([97, 98, 99, 100]))
})
it('should encode utf8 string into new buffer', () => {
const buf = utf8EncodeToBufferWeb('abcd')
expect(buf).eql(new Uint8Array([97, 98, 99, 100]))
expect(buf).toEqual(new Uint8Array([97, 98, 99, 100]))
})
it('should decode utf8 string from existing buffer', () => {
const buf = new Uint8Array([97, 98, 99, 100])
expect(utf8DecodeWeb(buf)).eq('abcd')
expect(utf8DecodeWeb(buf)).toEqual('abcd')
})
})
describe('byteLengthUtf8', () => {
it('should return byte length of utf8 string', () => {
expect(byteLengthUtf8('abcd')).eq(4)
expect(byteLengthUtf8('abcd')).toEqual(4)
})
it('should properly handle utf8 string with non-ascii characters', () => {
expect(byteLengthUtf8('абвг')).eq(8)
expect(byteLengthUtf8('🌸')).eq(4)
expect(byteLengthUtf8('абвг')).toEqual(8)
expect(byteLengthUtf8('🌸')).toEqual(4)
})
it('should work in web', () => {
expect(byteLengthUtf8Web('abcd')).eq(4)
expect(byteLengthUtf8Web('абвг')).eq(8)
expect(byteLengthUtf8Web('🌸')).eq(4)
expect(byteLengthUtf8Web('abcd')).toEqual(4)
expect(byteLengthUtf8Web('абвг')).toEqual(8)
expect(byteLengthUtf8Web('🌸')).toEqual(4)
})
})

View file

@ -1,90 +1,98 @@
// eslint-disable-next-line max-len
/* eslint-disable @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-argument */
import { expect } from 'chai'
import { randomBytes } from 'crypto'
import Long from 'long'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { hexDecodeToBuffer, hexEncode } from '../src/encodings/hex.js'
import { TlBinaryReader, TlReaderMap } from '../src/index.js'
import { hexDecodeToBuffer, hexEncode } from './encodings/hex.js'
import { TlBinaryReader, TlReaderMap } from './reader.js'
describe('TlBinaryReader', () => {
it('should read int32', () => {
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0, 0])).int()).eq(0)
expect(TlBinaryReader.manual(new Uint8Array([1, 0, 0, 0])).int()).eq(1)
expect(TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4])).int()).eq(67305985)
expect(TlBinaryReader.manual(new Uint8Array([0xff, 0xff, 0xff, 0xff])).int()).eq(-1)
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0, 0])).int()).toEqual(0)
expect(TlBinaryReader.manual(new Uint8Array([1, 0, 0, 0])).int()).toEqual(1)
expect(TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4])).int()).toEqual(67305985)
expect(TlBinaryReader.manual(new Uint8Array([0xff, 0xff, 0xff, 0xff])).int()).toEqual(-1)
})
it('should read uint32', () => {
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0, 0])).uint()).eq(0)
expect(TlBinaryReader.manual(new Uint8Array([1, 0, 0, 0])).uint()).eq(1)
expect(TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4])).uint()).eq(67305985)
expect(TlBinaryReader.manual(new Uint8Array([0xff, 0xff, 0xff, 0xff])).uint()).eq(4294967295)
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0, 0])).uint()).toEqual(0)
expect(TlBinaryReader.manual(new Uint8Array([1, 0, 0, 0])).uint()).toEqual(1)
expect(TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4])).uint()).toEqual(67305985)
expect(TlBinaryReader.manual(new Uint8Array([0xff, 0xff, 0xff, 0xff])).uint()).toEqual(4294967295)
})
it('should read int53', () => {
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0])).int53()).eq(0)
expect(TlBinaryReader.manual(new Uint8Array([1, 0, 0, 0, 0, 0, 0, 0])).int53()).eq(1)
expect(TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4, 0, 0, 0, 0])).int53()).eq(67305985)
expect(TlBinaryReader.manual(new Uint8Array([1, 0, 1, 0, 1, 0, 1, 0])).int53()).eq(281479271743489)
expect(TlBinaryReader.manual(new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])).int53()).eq(-1)
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0])).int53()).toEqual(0)
expect(TlBinaryReader.manual(new Uint8Array([1, 0, 0, 0, 0, 0, 0, 0])).int53()).toEqual(1)
expect(TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4, 0, 0, 0, 0])).int53()).toEqual(67305985)
expect(TlBinaryReader.manual(new Uint8Array([1, 0, 1, 0, 1, 0, 1, 0])).int53()).toEqual(281479271743489)
expect(TlBinaryReader.manual(new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])).int53()).toEqual(
-1,
)
})
it('should read long', () => {
expect(
TlBinaryReader.manual(new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])).long().toString(),
).eq('-1')
TlBinaryReader.manual(new Uint8Array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]))
.long()
.toString(),
).toEqual('-1')
expect(
TlBinaryReader.manual(new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78])).long().toString(),
).eq('8671175386481439762')
TlBinaryReader.manual(new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]))
.long()
.toString(),
).toEqual('8671175386481439762')
expect(
TlBinaryReader.manual(new Uint8Array([0x15, 0xc4, 0x15, 0xb5, 0xc4, 0x1c, 0x03, 0xa3])).long().toString(),
).eq('-6700480189419895787')
TlBinaryReader.manual(new Uint8Array([0x15, 0xc4, 0x15, 0xb5, 0xc4, 0x1c, 0x03, 0xa3]))
.long()
.toString(),
).toEqual('-6700480189419895787')
})
it('should read float', () => {
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0x80, 0x3f])).float()).closeTo(1, 0.001)
expect(TlBinaryReader.manual(new Uint8Array([0xb6, 0xf3, 0x9d, 0x3f])).float()).closeTo(1.234, 0.001)
expect(TlBinaryReader.manual(new Uint8Array([0xfa, 0x7e, 0x2a, 0x3f])).float()).closeTo(0.666, 0.001)
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0x80, 0x3f])).float()).toBeCloseTo(1, 0.001)
expect(TlBinaryReader.manual(new Uint8Array([0xb6, 0xf3, 0x9d, 0x3f])).float()).toBeCloseTo(1.234, 0.001)
expect(TlBinaryReader.manual(new Uint8Array([0xfa, 0x7e, 0x2a, 0x3f])).float()).toBeCloseTo(0.666, 0.001)
})
it('should read double', () => {
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0, 0, 0, 0, 0xf0, 0x3f])).double()).closeTo(1, 0.001)
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0, 0, 0, 0, 0x25, 0x40])).double()).closeTo(10.5, 0.001)
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0, 0, 0, 0, 0xf0, 0x3f])).double()).toBeCloseTo(1, 0.001)
expect(TlBinaryReader.manual(new Uint8Array([0, 0, 0, 0, 0, 0, 0x25, 0x40])).double()).toBeCloseTo(10.5, 0.001)
expect(
TlBinaryReader.manual(new Uint8Array([0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0x21, 0x40])).double(),
).closeTo(8.8, 0.001)
).toBeCloseTo(8.8, 0.001)
})
it('should read raw bytes', () => {
expect([...TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4])).raw(2)]).eql([1, 2])
expect([...TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4])).raw()]).eql([1, 2, 3, 4])
expect([...TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4])).raw(0)]).eql([])
expect([...TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4])).raw(2)]).toEqual([1, 2])
expect([...TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4])).raw()]).toEqual([1, 2, 3, 4])
expect([...TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4])).raw(0)]).toEqual([])
})
it('should move cursor', () => {
const reader = TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]))
reader.int()
expect(reader.pos).eq(4)
expect(reader.pos).toEqual(4)
reader.seek(-4)
expect(reader.pos).eq(0)
expect(reader.pos).toEqual(0)
expect(() => reader.seek(-1)).to.throw(RangeError)
expect(() => reader.seek(1000)).to.throw(RangeError)
expect(() => reader.seek(-1)).toThrow(RangeError)
expect(() => reader.seek(1000)).toThrow(RangeError)
reader.uint()
expect(reader.pos).eq(4)
expect(reader.pos).toEqual(4)
reader.seekTo(0)
expect(reader.pos).eq(0)
expect(reader.pos).toEqual(0)
expect(() => reader.seekTo(-1)).to.throw(RangeError)
expect(() => reader.seekTo(1000)).to.throw(RangeError)
expect(() => reader.seekTo(-1)).toThrow(RangeError)
expect(() => reader.seekTo(1000)).toThrow(RangeError)
const checkFunction = (fn: () => void, sz: number) => {
fn()
expect(reader.pos).eq(sz)
expect(reader.pos).toEqual(sz)
reader.seekTo(0)
}
@ -95,12 +103,12 @@ describe('TlBinaryReader', () => {
})
it('should read tg-encoded bytes', () => {
expect([...TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4])).bytes()]).eql([2])
expect([...TlBinaryReader.manual(new Uint8Array([1, 2, 3, 4])).bytes()]).toEqual([2])
const random250bytes = randomBytes(250)
let reader = TlBinaryReader.manual(new Uint8Array([250, ...random250bytes, 0, 0, 0, 0, 0]))
expect([...reader.bytes()]).eql([...random250bytes])
expect(reader.pos).eq(252)
expect([...reader.bytes()]).toEqual([...random250bytes])
expect(reader.pos).toEqual(252)
const random1000bytes = randomBytes(1000)
// eslint-disable-next-line no-restricted-globals
@ -109,8 +117,8 @@ describe('TlBinaryReader', () => {
buffer.writeIntLE(1000, 1, 3)
buffer.set(random1000bytes, 4)
reader = TlBinaryReader.manual(buffer)
expect([...reader.bytes()]).eql([...random1000bytes])
expect(reader.pos).eq(1004)
expect([...reader.bytes()]).toEqual([...random1000bytes])
expect(reader.pos).toEqual(1004)
})
const stubObjectsMap: TlReaderMap = {
@ -153,9 +161,9 @@ describe('TlBinaryReader', () => {
const reader = new TlBinaryReader(stubObjectsMap, buffer)
const deadBeef = reader.object()
expect(deadBeef).eql({ a: 1, b: 42 })
expect(deadBeef).toEqual({ a: 1, b: 42 })
const baadCode = reader.object()
expect(baadCode).eq(2)
expect(baadCode).toEqual(2)
})
it('should read tg-encoded vectors', () => {
@ -215,11 +223,11 @@ describe('TlBinaryReader', () => {
const reader = new TlBinaryReader(stubObjectsMap, buffer)
const vector = reader.vector()
expect(vector).eql([{ a: 1, b: 42 }, 2, { vec: [1, 2] }])
expect(vector).toEqual([{ a: 1, b: 42 }, 2, { vec: [1, 2] }])
reader.seekTo(0)
const vectorObj = reader.object()
expect(vector).eql(vectorObj)
expect(vector).toEqual(vectorObj)
})
describe('examples from documentation', () => {
@ -249,18 +257,18 @@ describe('TlBinaryReader', () => {
}
const r = new TlBinaryReader(map, hexDecodeToBuffer(input))
expect(r.long().toString()).eq('0') // authKeyId
expect(r.long().toString(16)).eq('51E57AC91E83C801'.toLowerCase()) // messageId
expect(r.uint()).eq(64) // messageLength
expect(r.long().toString()).toEqual('0') // authKeyId
expect(r.long().toString(16)).toEqual('51E57AC91E83C801'.toLowerCase()) // messageId
expect(r.uint()).toEqual(64) // messageLength
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const obj = r.object() as any
expect(obj._).eq('mt_resPQ')
expect(hexEncode(obj.nonce)).eq(hexEncode(expected.nonce))
expect(hexEncode(obj.serverNonce)).eq(hexEncode(expected.serverNonce))
expect(hexEncode(obj.pq)).eq(hexEncode(expected.pq))
expect(obj.serverPublicKeyFingerprints.length).eq(1)
expect(obj.serverPublicKeyFingerprints[0].toString(16)).eq(
expect(obj._).toEqual('mt_resPQ')
expect(hexEncode(obj.nonce)).toEqual(hexEncode(expected.nonce))
expect(hexEncode(obj.serverNonce)).toEqual(hexEncode(expected.serverNonce))
expect(hexEncode(obj.pq)).toEqual(hexEncode(expected.pq))
expect(obj.serverPublicKeyFingerprints.length).toEqual(1)
expect(obj.serverPublicKeyFingerprints[0].toString(16)).toEqual(
expected.serverPublicKeyFingerprints[0].toString(16),
)
})

View file

@ -1,76 +1,77 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
import { expect } from 'chai'
import { randomBytes } from 'crypto'
import Long from 'long'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { hexDecodeToBuffer, hexEncode } from '../src/encodings/hex.js'
import { TlBinaryWriter, TlSerializationCounter, TlWriterMap } from '../src/index.js'
import { TlBinaryWriter, TlSerializationCounter, TlWriterMap } from './writer.js'
describe('TlBinaryWriter', () => {
const testSingleMethod = (size: number, fn: (w: TlBinaryWriter) => void, map?: TlWriterMap): string => {
const w = TlBinaryWriter.alloc(map, size)
fn(w)
expect(w.pos).eq(size)
expect(w.pos).toEqual(size)
return hexEncode(w.uint8View)
}
it('should write int32', () => {
expect(testSingleMethod(4, (w) => w.int(0))).eq('00000000')
expect(testSingleMethod(4, (w) => w.int(1))).eq('01000000')
expect(testSingleMethod(4, (w) => w.int(67305985))).eq('01020304')
expect(testSingleMethod(4, (w) => w.int(-1))).eq('ffffffff')
expect(testSingleMethod(4, (w) => w.int(0))).toEqual('00000000')
expect(testSingleMethod(4, (w) => w.int(1))).toEqual('01000000')
expect(testSingleMethod(4, (w) => w.int(67305985))).toEqual('01020304')
expect(testSingleMethod(4, (w) => w.int(-1))).toEqual('ffffffff')
})
it('should write uint32', () => {
expect(testSingleMethod(4, (w) => w.uint(0))).eq('00000000')
expect(testSingleMethod(4, (w) => w.uint(1))).eq('01000000')
expect(testSingleMethod(4, (w) => w.uint(67305985))).eq('01020304')
expect(testSingleMethod(4, (w) => w.uint(4294967295))).eq('ffffffff')
expect(testSingleMethod(4, (w) => w.uint(0))).toEqual('00000000')
expect(testSingleMethod(4, (w) => w.uint(1))).toEqual('01000000')
expect(testSingleMethod(4, (w) => w.uint(67305985))).toEqual('01020304')
expect(testSingleMethod(4, (w) => w.uint(4294967295))).toEqual('ffffffff')
})
it('should write int53', () => {
expect(testSingleMethod(8, (w) => w.int53(0))).eq('0000000000000000')
expect(testSingleMethod(8, (w) => w.int53(1))).eq('0100000000000000')
expect(testSingleMethod(8, (w) => w.int53(67305985))).eq('0102030400000000')
expect(testSingleMethod(8, (w) => w.int53(281479271743489))).eq('0100010001000100')
expect(testSingleMethod(8, (w) => w.int53(-1))).eq('ffffffffffffffff')
expect(testSingleMethod(8, (w) => w.int53(0))).toEqual('0000000000000000')
expect(testSingleMethod(8, (w) => w.int53(1))).toEqual('0100000000000000')
expect(testSingleMethod(8, (w) => w.int53(67305985))).toEqual('0102030400000000')
expect(testSingleMethod(8, (w) => w.int53(281479271743489))).toEqual('0100010001000100')
expect(testSingleMethod(8, (w) => w.int53(-1))).toEqual('ffffffffffffffff')
})
it('should write long', () => {
expect(testSingleMethod(8, (w) => w.long(Long.NEG_ONE))).eq('ffffffffffffffff')
expect(testSingleMethod(8, (w) => w.long(Long.fromString('8671175386481439762')))).eq('1234567812345678')
expect(testSingleMethod(8, (w) => w.long(Long.fromString('-6700480189419895787')))).eq('15c415b5c41c03a3')
expect(testSingleMethod(8, (w) => w.long(Long.NEG_ONE))).toEqual('ffffffffffffffff')
expect(testSingleMethod(8, (w) => w.long(Long.fromString('8671175386481439762')))).toEqual('1234567812345678')
expect(testSingleMethod(8, (w) => w.long(Long.fromString('-6700480189419895787')))).toEqual('15c415b5c41c03a3')
})
it('should write float', () => {
expect(testSingleMethod(4, (w) => w.float(1))).eq('0000803f')
expect(testSingleMethod(4, (w) => w.float(1.234))).eq('b6f39d3f')
expect(testSingleMethod(4, (w) => w.float(0.666))).eq('fa7e2a3f')
expect(testSingleMethod(4, (w) => w.float(1))).toEqual('0000803f')
expect(testSingleMethod(4, (w) => w.float(1.234))).toEqual('b6f39d3f')
expect(testSingleMethod(4, (w) => w.float(0.666))).toEqual('fa7e2a3f')
})
it('should write double', () => {
expect(testSingleMethod(8, (w) => w.double(1))).eq('000000000000f03f')
expect(testSingleMethod(8, (w) => w.double(10.5))).eq('0000000000002540')
expect(testSingleMethod(8, (w) => w.double(8.8))).eq('9a99999999992140')
expect(testSingleMethod(8, (w) => w.double(1))).toEqual('000000000000f03f')
expect(testSingleMethod(8, (w) => w.double(10.5))).toEqual('0000000000002540')
expect(testSingleMethod(8, (w) => w.double(8.8))).toEqual('9a99999999992140')
})
it('should write raw bytes', () => {
expect(testSingleMethod(5, (w) => w.raw(new Uint8Array([4, 3, 5, 1, 1])))).eq('0403050101')
expect(testSingleMethod(5, (w) => w.raw(new Uint8Array([4, 3, 5, 1, 1])))).toEqual('0403050101')
})
it('should write tg-encoded boolean', () => {
expect(testSingleMethod(4, (w) => w.boolean(false))).eq('379779bc')
expect(testSingleMethod(4, (w) => w.boolean(true))).eq('b5757299')
expect(testSingleMethod(4, (w) => w.boolean(false))).toEqual('379779bc')
expect(testSingleMethod(4, (w) => w.boolean(true))).toEqual('b5757299')
})
it('should write tg-encoded bytes', () => {
expect(testSingleMethod(4, (w) => w.bytes(new Uint8Array([1, 2, 3])))).eq('03010203')
expect(testSingleMethod(8, (w) => w.bytes(new Uint8Array([1, 2, 3, 4])))).eq('0401020304000000')
expect(testSingleMethod(4, (w) => w.bytes(new Uint8Array([1, 2, 3])))).toEqual('03010203')
expect(testSingleMethod(8, (w) => w.bytes(new Uint8Array([1, 2, 3, 4])))).toEqual('0401020304000000')
const random250bytes = randomBytes(250)
expect(testSingleMethod(252, (w) => w.bytes(random250bytes))).eq('fa' + random250bytes.toString('hex') + '00')
expect(testSingleMethod(252, (w) => w.bytes(random250bytes))).toEqual(
'fa' + random250bytes.toString('hex') + '00',
)
const random1000bytes = randomBytes(1000)
// eslint-disable-next-line no-restricted-globals
@ -78,7 +79,7 @@ describe('TlBinaryWriter', () => {
buffer[0] = 254
buffer.writeIntLE(1000, 1, 3)
buffer.set(random1000bytes, 4)
expect(testSingleMethod(1004, (w) => w.bytes(random1000bytes))).eq(buffer.toString('hex'))
expect(testSingleMethod(1004, (w) => w.bytes(random1000bytes))).toEqual(buffer.toString('hex'))
})
const stubObjectsMap: TlWriterMap = {
@ -116,7 +117,7 @@ describe('TlBinaryWriter', () => {
const length =
TlSerializationCounter.countNeededBytes(stubObjectsMap, object1) +
TlSerializationCounter.countNeededBytes(stubObjectsMap, object2)
expect(length).eq(20)
expect(length).toEqual(20)
expect(
testSingleMethod(
@ -127,7 +128,7 @@ describe('TlBinaryWriter', () => {
},
stubObjectsMap,
),
).eq('efbeadde01000000addecefadec0adba02000000')
).toEqual('efbeadde01000000addecefadec0adba02000000')
})
it('should write tg-encoded vectors', () => {
@ -150,7 +151,7 @@ describe('TlBinaryWriter', () => {
TlSerializationCounter.countNeededBytes(stubObjectsMap, object2) +
TlSerializationCounter.countNeededBytes(stubObjectsMap, object3) +
8 // because technically in tl vector can't be top-level, but whatever :shrug:
expect(length).eq(48)
expect(length).toEqual(48)
expect(
testSingleMethod(
@ -160,7 +161,7 @@ describe('TlBinaryWriter', () => {
},
stubObjectsMap,
),
).eq('15c4b51c03000000efbeadde01000000addecefadec0adba020000003d0cbfbe15c4b51c020000000100000002000000')
).toEqual('15c4b51c03000000efbeadde01000000addecefadec0adba020000003d0cbfbe15c4b51c020000000100000002000000')
})
describe('examples from documentation', () => {
@ -193,7 +194,7 @@ describe('TlBinaryWriter', () => {
20 + // mtproto header
TlSerializationCounter.countNeededBytes(map, resPq)
expect(length).eq(expected.length / 2)
expect(length).toEqual(expected.length / 2)
expect(
testSingleMethod(
length,
@ -206,7 +207,7 @@ describe('TlBinaryWriter', () => {
},
map,
),
).eq(expected)
).toEqual(expected)
})
})
})

View file

@ -1,9 +0,0 @@
{
"extends": "../../../tsconfig.json",
"include": [
"."
],
"references": [
{ "path": "../" }
]
}

View file

@ -6,5 +6,5 @@
},
"include": [
"./src"
]
],
}

View file

@ -8,7 +8,6 @@
"main": "src/index.ts",
"type": "module",
"scripts": {
"test": "mocha \"tests/**/*.spec.ts\"",
"docs": "typedoc",
"build": "pnpm run -w build-package tl-utils"
},

View file

@ -1,12 +1,11 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { calculateStaticSizes } from '../src/calculator.js'
import { parseTlToEntries } from '../src/parse.js'
import { calculateStaticSizes } from './calculator.js'
import { parseTlToEntries } from './parse.js'
describe('calculateStaticSizes', () => {
const test = (tl: string, expected: object) => {
expect(calculateStaticSizes(parseTlToEntries(tl))).eql(expected)
expect(calculateStaticSizes(parseTlToEntries(tl))).toEqual(expected)
}
it('computes for constructors without parameters', () => {

View file

@ -1,12 +1,12 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { generateReaderCodeForTlEntry, parseTlToEntries } from '../../src/index.js'
import { parseTlToEntries } from '../parse.js'
import { generateReaderCodeForTlEntry } from './reader.js'
describe('generateReaderCodeForTlEntry', () => {
const test = (tl: string, ...js: string[]) => {
const entry = parseTlToEntries(tl).slice(-1)[0]
expect(generateReaderCodeForTlEntry(entry)).eq(`${entry.id}:function(r){${js.join('')}},`)
expect(generateReaderCodeForTlEntry(entry)).toEqual(`${entry.id}:function(r){${js.join('')}},`)
}
it('generates code for constructors without arguments', () => {
@ -163,7 +163,7 @@ describe('generateReaderCodeForTlEntry', () => {
it('generates code with raw flags for constructors with flags', () => {
const entry = parseTlToEntries('test flags:# flags2:# = Test;')[0]
expect(generateReaderCodeForTlEntry(entry, { includeFlags: true })).eq(
expect(generateReaderCodeForTlEntry(entry, { includeFlags: true })).toEqual(
`${entry.id}:function(r){${[
'var flags=r.uint(),',
'flags2=r.uint();',

View file

@ -1,17 +1,13 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import {
generateTypescriptDefinitionsForTlEntry,
generateTypescriptDefinitionsForTlSchema,
parseFullTlSchema,
parseTlToEntries,
} from '../../src/index.js'
import { parseTlToEntries } from '../parse.js'
import { parseFullTlSchema } from '../schema.js'
import { generateTypescriptDefinitionsForTlEntry, generateTypescriptDefinitionsForTlSchema } from './types.js'
describe('generateTypescriptDefinitionsForTlEntry', () => {
const test = (tl: string, ...ts: string[]) => {
const entry = parseTlToEntries(tl)[0]
expect(generateTypescriptDefinitionsForTlEntry(entry)).eq(ts.join('\n'))
expect(generateTypescriptDefinitionsForTlEntry(entry)).toEqual(ts.join('\n'))
}
it('replaces primitive types', () => {
@ -155,7 +151,7 @@ describe('generateTypescriptDefinitionsForTlEntry', () => {
it('generates code with raw flags for constructors with flags', () => {
const entry = parseTlToEntries('test flags:# flags2:# = Test;')[0]
expect(generateTypescriptDefinitionsForTlEntry(entry, undefined, undefined, true)).eq(
expect(generateTypescriptDefinitionsForTlEntry(entry, undefined, undefined, true)).toEqual(
['interface RawTest {', " _: 'test';", ' flags: number;', ' flags2: number;', '}'].join('\n'),
)
})
@ -176,8 +172,8 @@ describe('generateTypescriptDefinitionsForTlSchema', () => {
// skip prelude
codeJs = codeJs.substring(codeJs.indexOf('ns.LAYER = 0;') + 14, codeJs.length - 15)
expect(codeTs.trim()).eq(ts.join('\n'))
expect(codeJs.trim()).eq(js.join('\n'))
expect(codeTs.trim()).toEqual(ts.join('\n'))
expect(codeJs.trim()).toEqual(js.join('\n'))
}
it('writes simple schemas', () => {

View file

@ -1,12 +1,12 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { generateWriterCodeForTlEntries, generateWriterCodeForTlEntry, parseTlToEntries } from '../../src/index.js'
import { parseTlToEntries } from '../parse.js'
import { generateWriterCodeForTlEntries, generateWriterCodeForTlEntry } from './writer.js'
describe('generateWriterCodeForTlEntry', () => {
const test = (tl: string, ...js: string[]) => {
const entry = parseTlToEntries(tl).slice(-1)[0]
expect(generateWriterCodeForTlEntry(entry)).eq(
expect(generateWriterCodeForTlEntry(entry)).toEqual(
`'${entry.name}':function(w${entry.arguments.length ? ',v' : ''}){w.uint(${entry.id});${js.join('')}},`,
)
}
@ -136,7 +136,7 @@ describe('generateWriterCodeForTlEntry', () => {
'future_salts#ae500895 salts:vector<future_salt> current:future_salt = FutureSalts;',
)
expect(generateWriterCodeForTlEntries(entries, { includePrelude: false })).eq(
expect(generateWriterCodeForTlEntries(entries, { includePrelude: false })).toEqual(
`
var m={
'future_salt':function(w,v){w.uint(155834844);w.bytes(h(v,'salt'));},
@ -150,7 +150,7 @@ describe('generateWriterCodeForTlEntry', () => {
it('generates code with raw flags for constructors with flags', () => {
const entry = parseTlToEntries('test flags:# flags2:# = Test;')[0]
expect(generateWriterCodeForTlEntry(entry, { includeFlags: true })).eq(
expect(generateWriterCodeForTlEntry(entry, { includeFlags: true })).toEqual(
`'${entry.name}':function(w,v){${[
`w.uint(${entry.id});`,
'var flags=v.flags;',

View file

@ -1,7 +1,7 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { computeConstructorIdFromEntry, TlArgument, TlEntry } from '../src/index.js'
import { computeConstructorIdFromEntry } from './ctor-id.js'
import { TlArgument, TlEntry } from './index.js'
describe('computeConstructorIdFromEntry', () => {
const make = (name: string, type: string, ...args: string[]): TlEntry => ({
@ -31,7 +31,7 @@ describe('computeConstructorIdFromEntry', () => {
})
const test = (tl: TlEntry, expected: number) => {
expect(computeConstructorIdFromEntry(tl)).eq(expected)
expect(computeConstructorIdFromEntry(tl)).toEqual(expected)
}
it('computes for constructors without parameters', () => {

View file

@ -1,16 +1,15 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { generateTlEntriesDifference, generateTlSchemasDifference } from '../src/diff.js'
import { parseTlToEntries } from '../src/parse.js'
import { parseFullTlSchema } from '../src/schema.js'
import { TlEntryDiff, TlSchemaDiff } from '../src/types.js'
import { generateTlEntriesDifference, generateTlSchemasDifference } from './diff.js'
import { parseTlToEntries } from './parse.js'
import { parseFullTlSchema } from './schema.js'
import { TlEntryDiff, TlSchemaDiff } from './types.js'
describe('generateTlEntriesDifference', () => {
const test = (tl: string[], expected: TlEntryDiff) => {
const e = parseTlToEntries(tl.join('\n'))
const res = generateTlEntriesDifference(e[0], e[1])
expect(res).eql(expected)
expect(res).toEqual(expected)
}
it('shows id diff', () => {
@ -112,7 +111,7 @@ describe('generateTlSchemasDifference', () => {
if (!('classes' in expected)) delete res.classes
if (!('unions' in expected)) delete res.unions
expect(res).eql(expected)
expect(res).toEqual(expected)
}
it('shows added constructors', () => {

View file

@ -1,23 +1,18 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import {
mergeTlEntries,
mergeTlSchemas,
parseFullTlSchema,
parseTlToEntries,
writeTlEntriesToString,
writeTlEntryToString,
} from '../src/index.js'
import { mergeTlEntries, mergeTlSchemas } from './merge.js'
import { parseTlToEntries } from './parse.js'
import { parseFullTlSchema, writeTlEntriesToString } from './schema.js'
import { writeTlEntryToString } from './stringify.js'
describe('mergeTlEntries', () => {
const test = (tl: string, expected: string) => {
const res = mergeTlEntries(parseTlToEntries(tl))
if (typeof res === 'string') {
expect(res).eq(expected)
expect(res).toEqual(expected)
} else {
expect(writeTlEntryToString(res)).eq(expected)
expect(writeTlEntryToString(res)).toEqual(expected)
}
}
@ -83,7 +78,7 @@ describe('mergeTlSchemas', () => {
omitPrimitives: true,
tdlibComments: true,
}),
).eq(expected.join('\n'))
).toEqual(expected.join('\n'))
}
it('merges different constructors', async () => {

View file

@ -1,11 +1,11 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { parseTlToEntries, TlEntry } from '../src/index.js'
import { parseTlToEntries } from './parse.js'
import { TlEntry } from './types.js'
describe('tl parser', () => {
const test = (tl: string, expected: TlEntry[], params?: Parameters<typeof parseTlToEntries>[1]) => {
expect(parseTlToEntries(tl, params)).eql(expected)
expect(parseTlToEntries(tl, params)).toEqual(expected)
}
it('skips empty lines and comments', () => {
@ -317,10 +317,10 @@ account.getAccountTTL = AccountDaysTTL;
users.getUsers id:Vector<InputUser> = Vector<User>;
`,
)
expect(items[0].id).eq(0xda9b0d0d)
expect(items[1].id).eq(0x8c39793f)
expect(items[2].id).eq(0x8fc711d)
expect(items[3].id).eq(0xd91a548)
expect(items[0].id).toEqual(0xda9b0d0d)
expect(items[1].id).toEqual(0x8c39793f)
expect(items[2].id).toEqual(0x8fc711d)
expect(items[3].id).toEqual(0xd91a548)
})
it('parses preceding comments', () => {
@ -401,7 +401,7 @@ users.getUsers id:Vector<InputUser> = Vector<User>;
},
)
expect(orphaned).eql(['some comment idk', 'another comment but multiline', 'yet another at the end'])
expect(orphaned).toEqual(['some comment idk', 'another comment but multiline', 'yet another at the end'])
})
it('applies prefix to constructors', () => {

View file

@ -1,8 +1,7 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { writeTlEntriesToString } from '../src/schema.js'
import { TlEntry } from '../src/types.js'
import { writeTlEntriesToString } from './schema.js'
import { TlEntry } from './types.js'
describe('writeTlEntriesToString', () => {
const test = (entries: TlEntry[], params: Parameters<typeof writeTlEntriesToString>[1], ...expected: string[]) => {
@ -11,7 +10,7 @@ describe('writeTlEntriesToString', () => {
omitPrimitives: true,
...params,
}),
).eq(expected.join('\n'))
).toEqual(expected.join('\n'))
}
it('computes missing ids', () => {

View file

@ -1,8 +1,7 @@
import { expect } from 'chai'
import { describe, it } from 'mocha'
import { describe, expect, it } from 'vitest'
import { writeTlEntryToString } from '../src/stringify.js'
import { TlArgument, TlEntry } from '../src/types.js'
import { writeTlEntryToString } from './stringify.js'
import { TlArgument, TlEntry } from './types.js'
describe('writeTlEntryToString', () => {
const make = (name: string, type: string, ...args: string[]): TlEntry => ({
@ -32,7 +31,7 @@ describe('writeTlEntryToString', () => {
})
const test = (tl: TlEntry, expected: string) => {
expect(writeTlEntryToString(tl)).eq(expected)
expect(writeTlEntryToString(tl)).toEqual(expected)
}
it('writes constructors without parameters', () => {

View file

@ -1,9 +0,0 @@
{
"extends": "../../../tsconfig.json",
"include": [
"."
],
"references": [
{ "path": "../" }
]
}

View file

@ -8,7 +8,6 @@
"main": "src/index.ts",
"type": "module",
"scripts": {
"test": "mocha \"tests/**/*.spec.ts\"",
"docs": "typedoc",
"build": "pnpm run -w build-package wasm",
"build:wasm": "docker build --output=lib --target=binaries lib"

View file

@ -1,8 +1,8 @@
import { expect } from 'chai'
import { beforeAll, describe, expect, it } from 'vitest'
import { __getWasm, initAsync } from '../src/index.js'
before(async () => {
beforeAll(async () => {
await initAsync()
})
@ -16,6 +16,6 @@ describe('allocator', () => {
wasm.__free(ptr)
}
expect(wasm.memory.buffer.byteLength).to.equal(memUsage)
expect(wasm.memory.buffer.byteLength).toEqual(memUsage)
})
})

View file

@ -1,10 +1,9 @@
/* eslint-disable no-restricted-globals */
import { expect } from 'chai'
import { before, describe } from 'mocha'
import { beforeAll, describe, expect, it } from 'vitest'
import { __getWasm, createCtr256, ctr256, freeCtr256, initAsync } from '../src/index.js'
before(async () => {
beforeAll(async () => {
await initAsync()
})
@ -34,7 +33,7 @@ describe('aes-ctr', () => {
const res = ctr256(ctr, data)
freeCtr256(ctr)
expect(Buffer.from(res).toString('hex')).to.equal(dataEnc.toString('hex'))
expect(Buffer.from(res).toString('hex')).toEqual(dataEnc.toString('hex'))
})
it('should correctly decrypt', () => {
@ -42,7 +41,7 @@ describe('aes-ctr', () => {
const res = ctr256(ctr, dataEnc)
freeCtr256(ctr)
expect(Buffer.from(res).toString('hex')).to.equal(data.toString('hex'))
expect(Buffer.from(res).toString('hex')).toEqual(data.toString('hex'))
})
})
@ -60,9 +59,9 @@ describe('aes-ctr', () => {
freeCtr256(ctr)
expect(Buffer.from(res1).toString('hex')).to.equal(dataEnc1.toString('hex'))
expect(Buffer.from(res2).toString('hex')).to.equal(dataEnc2.toString('hex'))
expect(Buffer.from(res3).toString('hex')).to.equal(dataEnc3.toString('hex'))
expect(Buffer.from(res1).toString('hex')).toEqual(dataEnc1.toString('hex'))
expect(Buffer.from(res2).toString('hex')).toEqual(dataEnc2.toString('hex'))
expect(Buffer.from(res3).toString('hex')).toEqual(dataEnc3.toString('hex'))
})
it('should correctly decrypt', () => {
@ -73,9 +72,9 @@ describe('aes-ctr', () => {
freeCtr256(ctr)
expect(Buffer.from(res1).toString('hex')).to.equal(data.toString('hex'))
expect(Buffer.from(res2).toString('hex')).to.equal(data.toString('hex'))
expect(Buffer.from(res3).toString('hex')).to.equal(data.toString('hex'))
expect(Buffer.from(res1).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res2).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res3).toString('hex')).toEqual(data.toString('hex'))
})
})
@ -99,12 +98,12 @@ describe('aes-ctr', () => {
freeCtr256(ctr)
expect(Buffer.from(res1).toString('hex')).to.equal(dataEnc1.toString('hex'))
expect(Buffer.from(res2).toString('hex')).to.equal(dataEnc2.toString('hex'))
expect(Buffer.from(res3).toString('hex')).to.equal(dataEnc3.toString('hex'))
expect(Buffer.from(res4).toString('hex')).to.equal(dataEnc4.toString('hex'))
expect(Buffer.from(res5).toString('hex')).to.equal(dataEnc5.toString('hex'))
expect(Buffer.from(res6).toString('hex')).to.equal(dataEnc6.toString('hex'))
expect(Buffer.from(res1).toString('hex')).toEqual(dataEnc1.toString('hex'))
expect(Buffer.from(res2).toString('hex')).toEqual(dataEnc2.toString('hex'))
expect(Buffer.from(res3).toString('hex')).toEqual(dataEnc3.toString('hex'))
expect(Buffer.from(res4).toString('hex')).toEqual(dataEnc4.toString('hex'))
expect(Buffer.from(res5).toString('hex')).toEqual(dataEnc5.toString('hex'))
expect(Buffer.from(res6).toString('hex')).toEqual(dataEnc6.toString('hex'))
})
it('should correctly decrypt', () => {
@ -118,12 +117,12 @@ describe('aes-ctr', () => {
freeCtr256(ctr)
expect(Buffer.from(res1).toString('hex')).to.equal(data.toString('hex'))
expect(Buffer.from(res2).toString('hex')).to.equal(data.toString('hex'))
expect(Buffer.from(res3).toString('hex')).to.equal(data.toString('hex'))
expect(Buffer.from(res4).toString('hex')).to.equal(data.toString('hex'))
expect(Buffer.from(res5).toString('hex')).to.equal(data.toString('hex'))
expect(Buffer.from(res6).toString('hex')).to.equal(data.toString('hex'))
expect(Buffer.from(res1).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res2).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res3).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res4).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res5).toString('hex')).toEqual(data.toString('hex'))
expect(Buffer.from(res6).toString('hex')).toEqual(data.toString('hex'))
})
})
@ -144,6 +143,6 @@ describe('aes-ctr', () => {
freeCtr256(ctrDec)
}
expect(mem.byteLength).to.equal(memSize)
expect(mem.byteLength).toEqual(memSize)
})
})

View file

@ -1,11 +1,10 @@
/* eslint-disable no-restricted-globals */
import { expect } from 'chai'
import { before, describe } from 'mocha'
import { beforeAll, describe, expect, it } from 'vitest'
import { gzipSync } from 'zlib'
import { __getWasm, gunzip, initAsync } from '../src/index.js'
before(async () => {
beforeAll(async () => {
await initAsync()
})
@ -17,16 +16,16 @@ describe('gunzip', () => {
const inputPtr = wasm.__malloc(data.length)
new Uint8Array(wasm.memory.buffer).set(data, inputPtr)
expect(wasm.libdeflate_gzip_get_output_size(inputPtr, data.length)).to.equal(11)
expect(wasm.libdeflate_gzip_get_output_size(inputPtr, data.length)).toEqual(11)
})
it('should correctly inflate', () => {
const data = Array.from({ length: 1000 }, () => 'a').join('')
const res = gzipSync(Buffer.from(data))
expect(res).not.to.be.null
expect(res.length).to.be.lessThan(100)
expect(gunzip(res)).to.deep.equal(new Uint8Array(Buffer.from(data)))
expect(res).not.toBeNull()
expect(res.length).toBeLessThan(100)
expect(gunzip(res)).toEqual(new Uint8Array(Buffer.from(data)))
})
it('should not leak memory', () => {
@ -38,9 +37,9 @@ describe('gunzip', () => {
const res = gunzip(deflated)
expect(Buffer.from(res).toString()).to.equal(data)
expect(Buffer.from(res).toString()).toEqual(data)
}
expect(__getWasm().memory.buffer.byteLength).to.equal(memSize)
expect(__getWasm().memory.buffer.byteLength).toEqual(memSize)
})
})

View file

@ -1,10 +1,9 @@
/* eslint-disable no-restricted-globals */
import { expect } from 'chai'
import { before, describe } from 'mocha'
import { beforeAll, describe, expect, it } from 'vitest'
import { __getWasm, initAsync, sha1, sha256 } from '../src/index.js'
before(async () => {
beforeAll(async () => {
await initAsync()
})
@ -12,7 +11,7 @@ describe('sha256', () => {
it('should correctly calculate sha-256 hash', () => {
const hash = sha256(Buffer.from('abc'))
expect(Buffer.from(hash).toString('hex')).to.equal(
expect(Buffer.from(hash).toString('hex')).toEqual(
'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad',
)
})
@ -25,7 +24,7 @@ describe('sha256', () => {
sha256(Buffer.from('abc'))
}
expect(mem.byteLength).to.equal(memSize)
expect(mem.byteLength).toEqual(memSize)
})
})
@ -33,7 +32,7 @@ describe('sha1', () => {
it('should correctly calculate sha-1 hash', () => {
const hash = sha1(Buffer.from('abc'))
expect(Buffer.from(hash).toString('hex')).to.equal('a9993e364706816aba3e25717850c26c9cd0d89d')
expect(Buffer.from(hash).toString('hex')).toEqual('a9993e364706816aba3e25717850c26c9cd0d89d')
})
it('should not leak memory', () => {
@ -44,6 +43,6 @@ describe('sha1', () => {
sha1(Buffer.from('abc'))
}
expect(mem.byteLength).to.equal(memSize)
expect(mem.byteLength).toEqual(memSize)
})
})

View file

@ -1,10 +1,9 @@
/* eslint-disable no-restricted-globals */
import { expect } from 'chai'
import { before, describe } from 'mocha'
import { beforeAll, describe, expect, it } from 'vitest'
import { __getWasm, ige256Decrypt, ige256Encrypt, initAsync } from '../src/index.js'
before(async () => {
beforeAll(async () => {
await initAsync()
})
@ -18,13 +17,13 @@ describe('aes-ige', () => {
it('should correctly encrypt', () => {
const aes = ige256Encrypt(data, key, iv)
expect(Buffer.from(aes).toString('hex')).to.equal(dataEnc.toString('hex'))
expect(Buffer.from(aes).toString('hex')).toEqual(dataEnc.toString('hex'))
})
it('should correctly decrypt', () => {
const aes = ige256Decrypt(dataEnc, key, iv)
expect(Buffer.from(aes).toString('hex')).to.equal(data.toString('hex'))
expect(Buffer.from(aes).toString('hex')).toEqual(data.toString('hex'))
})
it('should not leak memory', () => {
@ -35,6 +34,6 @@ describe('aes-ige', () => {
ige256Decrypt(ige256Encrypt(data, key, iv), key, iv)
}
expect(mem.byteLength).to.equal(memSize)
expect(mem.byteLength).toEqual(memSize)
})
})

View file

@ -1,11 +1,10 @@
/* eslint-disable no-restricted-globals */
import { expect } from 'chai'
import { before, describe } from 'mocha'
import { beforeAll, describe, expect, it } from 'vitest'
import { inflateSync } from 'zlib'
import { __getWasm, deflateMaxSize, initAsync } from '../src/index.js'
before(async () => {
beforeAll(async () => {
await initAsync()
})
@ -13,23 +12,23 @@ describe('zlib deflate', () => {
it('should add zlib headers', () => {
const res = deflateMaxSize(Buffer.from('hello world'), 100)
expect(res).not.to.be.null
expect(res!.slice(0, 2)).to.deep.equal(Buffer.from([0x78, 0x9c]))
expect(res).not.toBeNull()
expect(res!.slice(0, 2)).toEqual(new Uint8Array([0x78, 0x9c]))
})
it('should return null if compressed data is larger than size', () => {
const res = deflateMaxSize(Buffer.from('hello world'), 1)
expect(res).to.be.null
expect(res).toBeNull()
})
it('should correctly deflate', () => {
const data = Array.from({ length: 1000 }, () => 'a').join('')
const res = deflateMaxSize(Buffer.from(data), 100)
expect(res).not.to.be.null
expect(res!.length).to.be.lessThan(100)
expect(inflateSync(res!)).to.deep.equal(Buffer.from(data))
expect(res).not.toBeNull()
expect(res!.length).toBeLessThan(100)
expect(inflateSync(res!)).toEqual(Buffer.from(data))
})
it('should not leak memory', () => {
@ -41,9 +40,9 @@ describe('zlib deflate', () => {
const res = inflateSync(deflated!)
expect(Buffer.from(res).toString()).to.equal(data)
expect(Buffer.from(res).toString()).toEqual(data)
}
expect(__getWasm().memory.buffer.byteLength).to.equal(memSize)
expect(__getWasm().memory.buffer.byteLength).toEqual(memSize)
})
})

File diff suppressed because it is too large Load diff

View file

@ -125,7 +125,23 @@ buildConfig.before()
if (buildConfig.buildTs) {
console.log('[i] Building typescript...')
exec('pnpm exec tsc --build', { cwd: packageDir, stdio: 'inherit' })
fs.cpSync(path.join(packageDir, 'tsconfig.json'), path.join(packageDir, 'tsconfig.backup.json'))
let tsconfig = fs.readFileSync(path.join(packageDir, 'tsconfig.backup.json'), 'utf-8')
// what the fuck
tsconfig = tsconfig.replace(
/("extends": "\.\.\/\.\.\/tsconfig\.json",)/,
'$1"exclude": ["**/*.{test,test-utils}.ts"],',
)
fs.writeFileSync(path.join(packageDir, 'tsconfig.json'), tsconfig)
try {
exec('pnpm exec tsc --build', { cwd: packageDir, stdio: 'inherit' })
} catch (e) {
fs.renameSync(path.join(packageDir, 'tsconfig.backup.json'), path.join(packageDir, 'tsconfig.json'))
throw e
}
if (buildConfig.buildCjs) {
console.log('[i] Building typescript (CJS)...')
@ -156,6 +172,8 @@ if (buildConfig.buildTs) {
if (error) throw error
}
fs.renameSync(path.join(packageDir, 'tsconfig.backup.json'), path.join(packageDir, 'tsconfig.json'))
console.log('[i] Post-processing...')
if (buildConfig.removeReferenceComments) {

15
vite.config.mts Normal file
View file

@ -0,0 +1,15 @@
/// <reference types="vitest" />
import { defineConfig } from 'vite'
export default defineConfig({
test: {
include: [
'packages/**/*.test.ts',
],
typecheck: {
include: [
'packages/**/*.test-d.ts',
],
}
},
})