From 061458468bc39f5f67db93bd6a6b0881a3d59c6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 18:11:23 +0000 Subject: [PATCH 1/5] build(deps-dev): bump tsd from 0.30.7 to 0.31.0 (#151) Bumps [tsd](https://github.com/tsdjs/tsd) from 0.30.7 to 0.31.0. - [Release notes](https://github.com/tsdjs/tsd/releases) - [Commits](https://github.com/tsdjs/tsd/compare/v0.30.7...v0.31.0) --- updated-dependencies: - dependency-name: tsd dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 83693ac..f0d9336 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "standard": "^17.0.0", "tap": "^16.3.8", "tinybench": "^2.5.1", - "tsd": "^0.30.0", + "tsd": "^0.31.0", "typescript": "^5.0.2" }, "keywords": [ From e62384c9623ff9e7a72f5aca6817ca85fc10e31e Mon Sep 17 00:00:00 2001 From: Giovanni Bucci Date: Thu, 2 May 2024 13:33:51 +0200 Subject: [PATCH 2/5] More automated tests (#152) * started writing a couple of automated tests to chip in, working towards the 100% test coverage goal * added a couple more tests and eslint fixes * added all the cases for the basename * better test description * added the plan for the subtest too in the dicer-write.test.js * PR review: removed the t.end() in dicer-write.test.js --------- Co-authored-by: Giovanni Bucci --- test/basename.test.js | 28 ++++++++++++++++++++++++++++ test/busboy-emit.test.js | 17 +++++++++++++++++ test/dicer-write.test.js | 19 +++++++++++++++++++ test/multipart-constructor.test.js | 16 ++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 test/basename.test.js create mode 100644 test/busboy-emit.test.js create mode 100644 test/dicer-write.test.js create mode 100644 test/multipart-constructor.test.js diff --git a/test/basename.test.js b/test/basename.test.js new file mode 100644 index 0000000..0fb4a69 --- /dev/null +++ b/test/basename.test.js @@ -0,0 +1,28 @@ +'use strict' + +const { test } = require('tap') +const basename = require('../lib/utils/basename') + +test('basename', (t) => { + const testCases = [ + { description: 'returns an empty string if the path is not a string', path: {}, expected: '' }, + { description: 'returns an empty string if the path includes a \' and the char after is a .', path: 'path\\.', expected: '' }, + { description: 'returns an empty string if the path includes a / and the char after is a .', path: 'path/.', expected: '' }, + { description: 'returns an empty string if the path includes a \' and the chars after are a ..', path: 'path\\..', expected: '' }, + { description: 'returns an empty string if the path includes a / and the chars after are a ..', path: 'path/..', expected: '' }, + { description: 'returns the path if the path includes a \' and the rest is anything other than dots', path: 'path\\subpath', expected: 'subpath' }, + { description: 'returns the path if the path includes a / and the rest is anything other than dots', path: 'path/subpath', expected: 'subpath' }, + { description: 'returns an empty string if the path is a .', path: '.', expected: '' }, + { description: 'returns an empty string if the path is a ..', path: '..', expected: '' }, + { description: 'returns the path if the path is anything other than dots', path: 'subpath', expected: 'subpath' } + ] + + t.plan(testCases.length) + + testCases.forEach((testCase, index) => { + t.test(testCase.description, t => { + t.plan(1) + t.equal(basename(testCase.path), testCase.expected, `Test case ${index + 1}`) + }) + }) +}) diff --git a/test/busboy-emit.test.js b/test/busboy-emit.test.js new file mode 100644 index 0000000..1e539ab --- /dev/null +++ b/test/busboy-emit.test.js @@ -0,0 +1,17 @@ +'use strict' + +const Busboy = require('../lib/main') +const { test } = require('tap') + +test('busboy, emit', t => { + t.plan(1) + + t.test('returns undefined when the event is called a second time and the busboy was already finished', t => { + const busboy = new Busboy({ headers: { 'content-type': 'application/x-www-form-urlencoded' } }) + busboy._finished = true + busboy.emit('finish') + + t.equal(busboy.emit('finish'), undefined) + t.end() + }) +}) diff --git a/test/dicer-write.test.js b/test/dicer-write.test.js new file mode 100644 index 0000000..f270fa3 --- /dev/null +++ b/test/dicer-write.test.js @@ -0,0 +1,19 @@ +'use strict' + +const { test } = require('tap') +const { Dicer } = require('../lib/main') + +test('dicer _write method', t => { + t.plan(1) + + t.test('calls the callback cb() when headerFirst is set and all the data have been written', t => { + t.plan(1) + const dicer = new Dicer({ headerFirst: true }) + + dicer._write(Buffer.from('Content-Type: text/plain'), null, () => { + dicer._write(Buffer.from('Content-Type: text/plain'), null, () => { + t.pass('write method called') + }) + }) + }) +}) diff --git a/test/multipart-constructor.test.js b/test/multipart-constructor.test.js new file mode 100644 index 0000000..87aaad1 --- /dev/null +++ b/test/multipart-constructor.test.js @@ -0,0 +1,16 @@ +'use strict' + +const Multipart = require('../lib/types/multipart') +const Busboy = require('../lib/main') +const { test } = require('tap') + +test('multipart constructor', t => { + t.plan(1) + + t.test('throws if the boundary is not a string', t => { + const busboy = new Busboy({ headers: { 'content-type': 'application/x-www-form-urlencoded' } }) + + t.throws(() => new Multipart(busboy, { boundary: 123 }), new Error('Multipart: Boundary not found')) + t.end() + }) +}) From 808053272797326d83926c36a19a60cb0a551806 Mon Sep 17 00:00:00 2001 From: Matteo Gesmundo <46707463+Gesma94@users.noreply.github.com> Date: Wed, 22 May 2024 00:51:06 +0200 Subject: [PATCH 3/5] Improve test coverage (#153) * test: 100% branch coverage in `parseParam.js` * test: 100% branch coverage in `Decoder.js` * test: improve branch coverage in `urlencode.js` * test: 100% test coverage in `sbmh.js` * test: 100% branch coverage in `main.js` * chore: fix linting --- test/decoder.test.js | 5 +++ test/parse-params.test.js | 10 +++++ test/streamsearch.test.js | 36 ++++++++++++++++- test/types-urlencoded.test.js | 75 +++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 1 deletion(-) diff --git a/test/decoder.test.js b/test/decoder.test.js index fa4ce69..bc8795d 100644 --- a/test/decoder.test.js +++ b/test/decoder.test.js @@ -16,6 +16,11 @@ test('Decoder', t => { expected: 'Hello world', what: 'One full encoded byte' }, + { + source: ['%20Hello World'], + expected: ' Hello World', + what: 'Start with full encoded byte' + }, { source: ['Hello%20world%21'], expected: 'Hello world!', diff --git a/test/parse-params.test.js b/test/parse-params.test.js index eea4768..3b6bc98 100644 --- a/test/parse-params.test.js +++ b/test/parse-params.test.js @@ -51,6 +51,11 @@ test('parse-params', t => { expected: ['text/plain', ['greeting', 'hello "world"']], what: 'Quotes within quoted' }, + { + source: 'text/plain; greeting="hello \\\\world\\\\"', + expected: ['text/plain', ['greeting', 'hello \\world\\']], + what: 'Escape within quoted' + }, { source: 'text/plain; encoding=""', expected: ['text/plain', ['encoding', '']], @@ -86,6 +91,11 @@ test('parse-params', t => { expected: ['text/plain', ['filename', '£ rates'], ['altfilename', 'foobarbaz']], what: 'Mixed regular and extended parameters (RFC 5987)' }, + { + source: "text/plain; filename*=iso-8859-1'en';", + expected: ['text/plain', ['filename', '']], + what: 'Mixed regular and extended parameters (RFC 5987) with separator' + }, { source: "text/plain; filename=\"foobarbaz\"; altfilename*=iso-8859-1'en'%A3%20rates", expected: ['text/plain', ['filename', 'foobarbaz'], ['altfilename', '£ rates']], diff --git a/test/streamsearch.test.js b/test/streamsearch.test.js index 968c7de..bc9f01c 100644 --- a/test/streamsearch.test.js +++ b/test/streamsearch.test.js @@ -4,7 +4,7 @@ const { test } = require('tap') const Streamsearch = require('../deps/streamsearch/sbmh') test('streamsearch', t => { - t.plan(17) + t.plan(18) t.test('should throw an error if the needle is not a String or Buffer', t => { t.plan(1) @@ -335,6 +335,40 @@ test('streamsearch', t => { s.push(chunks[3]) }) + t.test('should process four chunks with repeted starting overflowing needle', t => { + t.plan(13) + + const expected = [ + [false, Buffer.from('\n\n\0'), 0, 1], + [true, undefined, undefined, undefined], + [false, Buffer.from('\r\nhello'), 1, 7] + ] + const needle = '\n\n\r' + const s = new Streamsearch(needle) + const chunks = [ + Buffer.from('\n'), + Buffer.from('\n'), + Buffer.from('\n'), + Buffer.from('\r\nhello') + ] + let i = 0 + s.on('info', (isMatched, data, start, end) => { + t.strictSame(isMatched, expected[i][0]) + t.strictSame(data, expected[i][1]) + t.strictSame(start, expected[i][2]) + t.strictSame(end, expected[i][3]) + i++ + if (i >= 3) { + t.pass() + } + }) + + s.push(chunks[0]) + s.push(chunks[1]) + s.push(chunks[2]) + s.push(chunks[3]) + }) + t.test('should process four chunks with a potentially overflowing needle', t => { t.plan(17) diff --git a/test/types-urlencoded.test.js b/test/types-urlencoded.test.js index 73cc286..7673aef 100644 --- a/test/types-urlencoded.test.js +++ b/test/types-urlencoded.test.js @@ -27,6 +27,13 @@ const tests = [ what: 'Unassigned and assigned value', plan: 5 }, + { + source: ['foo&baz=bla'], + expected: [['foo', '', false, false]], + what: 'Unassigned and assigned value with limit', + limits: { fields: 1 }, + plan: 4 + }, { source: ['foo=bar&baz'], expected: [['foo', 'bar', false, false], @@ -80,6 +87,13 @@ const tests = [ what: 'Two assigned values, one with encoded bytes', plan: 5 }, + { + source: ['foo=bar&baz=bla', 'foo=bar'], + expected: [], + what: 'Exceeded limits', + limits: { fields: 0 }, + plan: 3 + }, { source: ['foo=bar&baz=bla'], expected: [], @@ -110,6 +124,22 @@ const tests = [ limits: { fieldNameSize: 2 }, plan: 5 }, + { + source: ['f%20=bar&baz=bla'], + expected: [['f ', 'bar', false, false], + ['ba', 'bla', true, false]], + what: 'Limits: truncated field name with encoded bytes', + limits: { fieldNameSize: 2 }, + plan: 5 + }, + { + source: ['foo=b%20&baz=bla'], + expected: [['foo', 'b ', false, false], + ['baz', 'bl', false, true]], + what: 'Limits: truncated field value with encoded bytes', + limits: { fieldSize: 2 }, + plan: 5 + }, { source: ['foo=bar&baz=bla'], expected: [['foo', 'ba', false, true], @@ -208,3 +238,48 @@ tests.forEach((v) => { busboy.end() }) }) + +test('Call parser end twice', t => { + t.plan(1) + + let finishes = 0 + const busboy = new Busboy({ + headers: { + 'content-type': 'application/x-www-form-urlencoded; charset=utf-8' + } + }) + + busboy.on('finish', function () { + t.ok(++finishes === 1, 'finish emitted') + }) + + busboy.write(Buffer.from('Hello world', 'utf8'), EMPTY_FN) + + busboy._parser.end() + busboy._parser.end() +}) + +test('Call emit finish twice', t => { + t.plan(2) + + let fields = 0 + let finishes = 0 + + const busboy = new Busboy({ + headers: { + 'content-type': 'application/x-www-form-urlencoded; charset=utf-8' + } + }) + busboy.on('field', function () { + t.ok(++fields === 1, 'field emitted') + }) + + busboy.on('finish', function () { + t.ok(++finishes === 1, 'finish emitted') + }) + + busboy.write(Buffer.from('Hello world', 'utf8'), EMPTY_FN) + + busboy.emit('finish') + busboy.emit('finish') +}) From 94b0dd866d1da3c1b8f90f7bb3b189c99fc4f328 Mon Sep 17 00:00:00 2001 From: Cristian Barlutiu Date: Fri, 22 Mar 2024 11:43:51 +0100 Subject: [PATCH 4/5] Update for Fastify v5 (#150) * upgrade for fastify 5 * Fixed typo * removed engine field --- .github/workflows/ci.yml | 2 +- .taprc | 5 ++--- package.json | 15 ++++++--------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index babd56d..444baa7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,6 @@ on: jobs: test: - uses: fastify/workflows/.github/workflows/plugins-ci.yml@v3 + uses: fastify/workflows/.github/workflows/plugins-ci.yml@v4.1.0 with: license-check: true diff --git a/.taprc b/.taprc index 30a802b..4e0cdc0 100644 --- a/.taprc +++ b/.taprc @@ -1,4 +1,3 @@ +disable-coverage: true files: - - test/**/*.test.js - -coverage: false \ No newline at end of file + - test/**/*.test.js \ No newline at end of file diff --git a/package.json b/package.json index f0d9336..387c687 100644 --- a/package.json +++ b/package.json @@ -32,19 +32,16 @@ "test:coverage": "nyc npm run test", "test": "npm run test:mocha" }, - "engines": { - "node": ">=14" - }, "devDependencies": { - "@types/node": "^20.1.0", - "busboy": "^1.0.0", + "@types/node": "^20.11.30", + "busboy": "^1.6.0", "photofinish": "^1.8.0", "snazzy": "^9.0.0", - "standard": "^17.0.0", - "tap": "^16.3.8", - "tinybench": "^2.5.1", + "standard": "^17.1.0", + "tap": "^18.7.1", + "tinybench": "^2.6.0", "tsd": "^0.31.0", - "typescript": "^5.0.2" + "typescript": "^5.4.3" }, "keywords": [ "uploads", From 16f52a351c5b889a328acda993c97b02d7693e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCrg=C3=BCn=20Day=C4=B1o=C4=9Flu?= Date: Sun, 7 Jul 2024 11:39:02 +0300 Subject: [PATCH 5/5] workflows:pin node versions to lts (#154) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * pin node versions to lts * Update .github/workflows/ci.yml Signed-off-by: Gürgün Dayıoğlu * Update .github/workflows/ci.yml Signed-off-by: Gürgün Dayıoğlu * Update .github/workflows/ci.yml Signed-off-by: Gürgün Dayıoğlu --------- Signed-off-by: Gürgün Dayıoğlu --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 444baa7..cc453ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,7 @@ on: jobs: test: - uses: fastify/workflows/.github/workflows/plugins-ci.yml@v4.1.0 + uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5.0.0 with: license-check: true + node-versions: '["20", "22"]'