diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..abe3d0cc --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,233 @@ +name: ci + +on: + push: + branches: + - master + pull_request: + branches: + - master + +permissions: + contents: read + +# Cancel in progress workflows +# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run +concurrency: + group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + cancel-in-progress: true + +jobs: + performance: + name: Run performance test + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Setup Node.js 22 + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Install dependencies + run: npm install + + - name: Run performance test + run: npm run test:performance + + test: + name: Run tests + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + node-version: + - "0.10" + - "0.12" + - "4" + - "5" + - "6" + - "7" + - "8" + - "9" + - "10" + - "11" + - "12" + - "13" + - "14" + - "15" + - "16" + - "17" + - "18" + - "19" + - "20" + - "21" + - "22" + - "23" + - "24" + # Use supported versions of our testing tools under older versions of Node + # Install npm in some specific cases where we need to + include: + - node-version: "0.10" + npm-i: "mocha@3.5.3 nyc@10.3.2 supertest@2.0.0" + # Npm isn't being installed on windows w/ setup-node for + # 0.10 and 0.12, which will end up choking when npm uses es6 + npm-version: "npm@2.15.1" + npm-rm: 'iconv' + + - node-version: "0.12" + npm-i: "mocha@3.5.3 nyc@10.3.2" + npm-version: "npm@2.15.11" + npm-rm: 'iconv' + + - node-version: "4" + npm-i: "mocha@5.2.0 nyc@11.9.0" + npm-rm: 'iconv' + + - node-version: "5" + npm-i: "mocha@5.2.0 nyc@11.9.0" + # fixes https://github.com/npm/cli/issues/681 + npm-version: "npm@3.10.10" + npm-rm: 'iconv' + + - node-version: "6" + npm-i: "mocha@6.2.2 nyc@14.1.1" + npm-rm: 'iconv' + + - node-version: "7" + npm-i: "mocha@6.2.2 nyc@14.1.1" + npm-rm: 'iconv' + + - node-version: "8" + npm-i: "mocha@7.2.0 nyc@14.1.1" + npm-rm: 'iconv' + + - node-version: "9" + npm-i: "mocha@7.2.0 nyc@14.1.1" + npm-rm: 'iconv' + + - node-version: "10" + npm-i: "mocha@8.4.0" + npm-rm: 'iconv' + + - node-version: "11" + npm-i: "mocha@8.4.0" + npm-rm: 'iconv' + + - node-version: "12" + npm-i: "mocha@9.2.2" + npm-rm: 'iconv' + + - node-version: "13" + npm-i: "mocha@9.2.2" + npm-rm: 'iconv' + + - node-version: "14" + npm-rm: 'iconv' + + - node-version: "15" + npm-rm: 'iconv' + + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Npm version fixes + if: ${{matrix.npm-version != ''}} + run: npm install -g ${{ matrix.npm-version }} + + - name: Configure npm loglevel + run: | + npm config set loglevel error + shell: bash + + - name: Remove npm module(s) ${{ matrix.npm-rm }} + run: npm rm --silent --save-dev ${{ matrix.npm-rm }} + if: matrix.npm-rm != '' + + - name: Install Node version specific dev deps + if: ${{ matrix.npm-i != '' }} + run: npm install --save-dev ${{ matrix.npm-i }} + + - name: Install dependencies + run: npm install + + - name: Output Node and NPM versions + run: | + echo "Node.js version: $(node -v)" + echo "NPM version: $(npm -v)" + + - name: Run tests + shell: bash + run: npm run test:ci + + - name: Upload code coverage + uses: actions/upload-artifact@v4 + with: + name: coverage-node-${{ matrix.node-version }}-${{ matrix.os }} + path: ./coverage/lcov.info + retention-days: 1 + + coverage: + needs: test + runs-on: ubuntu-latest + permissions: + contents: read + checks: write + steps: + - uses: actions/checkout@v4 + + - name: Install lcov + shell: bash + run: sudo apt-get -y install lcov + + - name: Collect coverage reports + uses: actions/download-artifact@v4 + with: + path: ./coverage + pattern: coverage-node-* + + - name: Merge coverage reports + shell: bash + run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./lcov.info + + - name: Upload coverage report + uses: coverallsapp/github-action@v2 + with: + file: ./lcov.info + + test_webpack: + name: Run tests webpack + strategy: + fail-fast: false + matrix: + node-version: ["12", "*"] + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Webpack test + shell: bash + run: | + npm run test:webpack \ No newline at end of file diff --git a/.github/workflows/iojs.yml b/.github/workflows/iojs.yml new file mode 100644 index 00000000..26968f69 --- /dev/null +++ b/.github/workflows/iojs.yml @@ -0,0 +1,72 @@ +name: iojs-ci + +on: + push: + branches: + - master + pull_request: + branches: + - master + +concurrency: + group: "${{ github.workflow }} iojs ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" + cancel-in-progress: true + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: ["1.8", "2.5", "3.3"] + include: + - node-version: "1.8" + npm-i: "mocha@3.5.3 nyc@10.3.2" + npm-rm: 'iconv' + - node-version: "2.5" + npm-i: "mocha@3.5.3 nyc@10.3.2" + npm-rm: 'iconv' + - node-version: "3.3" + npm-i: "mocha@3.5.3 nyc@10.3.2" + npm-rm: 'iconv' + + steps: + - uses: actions/checkout@v4 + + - name: Install iojs ${{ matrix.node-version }} + shell: bash -eo pipefail -l {0} + run: | + nvm install --default ${{ matrix.node-version }} + dirname "$(nvm which ${{ matrix.node-version }})" >> "$GITHUB_PATH" + + - name: Configure npm + run: | + npm config set loglevel error + npm config set shrinkwrap false + - name: Remove npm module(s) ${{ matrix.npm-rm }} + run: npm rm --silent --save-dev ${{ matrix.npm-rm }} + if: matrix.npm-rm != '' + + - name: Install npm module(s) ${{ matrix.npm-i }} + run: npm install --save-dev ${{ matrix.npm-i }} + if: matrix.npm-i != '' + + - name: Remove non-test dependencies + run: npm rm --silent --save-dev connect-redis + + - name: Install Node.js dependencies + run: npm install + + - name: List environment + id: list_env + shell: bash + run: | + echo "node@$(node -v)" + echo "npm@$(npm -v)" + npm -s ls ||: + (npm -s ls --depth=0 ||:) | awk -F'[ @]' 'NR>1 && $2 { print $2 "=" $3 }' >> "$GITHUB_OUTPUT" + + - name: Run tests + shell: bash + run: npm run test + diff --git a/.gitignore b/.gitignore index 1f9dccef..218b009c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ package-lock.json /coverage /benchmarks/node_envs /generation/source-data + +.nyc_output \ No newline at end of file diff --git a/.npmignore b/.npmignore index b540d031..12fca491 100644 --- a/.npmignore +++ b/.npmignore @@ -6,4 +6,4 @@ wiki coverage .github .idea -.travis.yml +performance \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 670a4b3b..00000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: node_js -node_js: - - "0.10" - - "0.11" - - "0.12" - - "iojs" - - "4" - - "6" - - "8" - - "10" - - "12" - - "node" - -jobs: - include: - - name: webpack - node_js: "12" - install: cd test/webpack; npm install - script: npm test \ No newline at end of file diff --git a/package.json b/package.json index d351115a..b29b1136 100644 --- a/package.json +++ b/package.json @@ -22,18 +22,22 @@ "node": ">=0.10.0" }, "scripts": { - "coverage": "c8 _mocha --grep .", - "test": "mocha --reporter spec --grep ." + "test": "mocha --reporter spec --check-leaks --grep .", + "test:ci": "nyc --exclude test --reporter=lcovonly --reporter=text npm test", + "test:cov": "nyc --exclude test --reporter=html --reporter=text npm test", + "test:performance": "node performance/index.js", + "test:tap": "mocha --reporter tap --check-leaks --grep .", + "test:webpack": "npm pack && mv iconv-lite-*.tgz test/webpack/iconv-lite.tgz && cd test/webpack && npm install && npm run test && rm iconv-lite.tgz" }, "browser": { "stream": false }, "devDependencies": { "async": "^3.2.0", - "c8": "^7.2.0", "errto": "^0.2.1", "iconv": "^2.3.5", - "mocha": "^3.5.3", + "mocha": "^6.2.2", + "nyc": "^14.1.1", "request": "^2.88.2", "semver": "^6.3.0", "unorm": "^1.6.0" diff --git a/test/performance.js b/performance/index.js similarity index 95% rename from test/performance.js rename to performance/index.js index 1a5bcf4d..4e5f541b 100644 --- a/test/performance.js +++ b/performance/index.js @@ -1,9 +1,5 @@ - -if (module.parent) // Skip this file from testing. - return; - var iconv = require('iconv'); -var iconv_lite = require("../"); +var iconv_lite = require("../lib"); var encoding = process.argv[2] || "windows-1251"; var convertTimes = 10000; @@ -30,6 +26,7 @@ var converter = new iconv.Iconv("utf8", encoding); for (var i = 0; i < convertTimes; i++) { var b = converter.convert(str); } + var duration = Date.now() - start; var mbs = convertTimes*b.length/duration/1024; diff --git a/test/big5-test.js b/test/big5-test.js index 1ca9dd91..a6c241f2 100644 --- a/test/big5-test.js +++ b/test/big5-test.js @@ -21,6 +21,11 @@ describe("Big5 tests", function() { }); it("Big5 file read decoded,compare with iconv result", function() { + try { + require('iconv'); + } catch (_e) { + this.skip(); + } var contentBuffer = Buffer.from('PEhUTUw+DQo8SEVBRD4gICAgDQoJPFRJVExFPiBtZXRhILzQxdKquqjPpc6hR6SkpOW69K22IDwvVElUTEU+DQoJPG1ldGEgSFRUUC1FUVVJVj0iQ29udGVudC1UeXBlIiBDT05URU5UPSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9YmlnNSI+DQo8L0hFQUQ+DQo8Qk9EWT4NCg0Ks2+sT6RArdPBY8XppKSk5br0rbahSTxicj4NCihUaGlzIHBhZ2UgdXNlcyBiaWc1IGNoYXJhY3RlciBzZXQuKTxicj4NCmNoYXJzZXQ9YmlnNQ0KDQo8L0JPRFk+DQo8L0hUTUw+', 'base64'); var str = iconv.decode(contentBuffer, "big5"); var iconvc = new (require('iconv').Iconv)('big5','utf8'); diff --git a/test/dbcs-test.js b/test/dbcs-test.js index 3eadfb5c..cb8e0e20 100644 --- a/test/dbcs-test.js +++ b/test/dbcs-test.js @@ -1,8 +1,7 @@ var fs = require('fs'), assert = require('assert'), Buffer = require('safer-buffer').Buffer, - iconv = require(__dirname+'/../'), - Iconv = require('iconv').Iconv; + iconv = require(__dirname+'/../'); // Make all valid input combinations for a given encoding and call fn with it. @@ -156,11 +155,19 @@ iconv.encode('', 'utf8'); // Load all encodings. describe("Full DBCS encoding tests", function() { this.timeout(10000); // These tests are pretty slow. + var Iconv; + try { + Iconv = require('iconv').Iconv; + } catch (_e) {} for (var enc in iconv.encodings) { if (iconv.encodings[enc].type === '_dbcs') (function(enc) { // Create tests for this encoding. it("Decode DBCS encoding '" + enc + "'", function() { + if (!Iconv) { + this.skip() // Skip if Iconv is available + } + var iconvChgs = iconvChanges[enc] || {}; var iconvCannotDecodeChars = iconvCannotDecode[enc] || {}; var converter = new Iconv(aliases[enc] || enc, "utf-8"); @@ -203,6 +210,10 @@ describe("Full DBCS encoding tests", function() { }); it("Encode DBCS encoding '" + enc + "'", function() { + if (!Iconv) { + this.skip() // Skip if Iconv is available + } + var iconvChgs = iconvChanges[enc] || {}; var iconvCannotDecodeChars = iconvCannotDecode[enc] || {}; var converter = new Iconv("utf-8", aliases[enc] || enc); diff --git a/test/gbk-test.js b/test/gbk-test.js index 224b896d..3ecc0784 100644 --- a/test/gbk-test.js +++ b/test/gbk-test.js @@ -18,6 +18,11 @@ describe("GBK tests", function() { }); it("GBK file read decoded,compare with iconv result", function() { + try { + require('iconv'); + } catch (_e){ + this.skip(); + } var contentBuffer = fs.readFileSync(__dirname+"/gbkFile.txt"); var str = iconv.decode(contentBuffer, "GBK"); var iconvc = new (require('iconv').Iconv)('GBK','utf8'); diff --git a/test/sbcs-test.js b/test/sbcs-test.js index 46f419be..c70e19cd 100644 --- a/test/sbcs-test.js +++ b/test/sbcs-test.js @@ -1,8 +1,7 @@ var assert = require('assert'), unorm = require('unorm'), Buffer = require('safer-buffer').Buffer, - iconv = require(__dirname+'/../'), - Iconv = require('iconv').Iconv; + iconv = require(__dirname+'/../'); function convertWithDefault(converter, buf, def) { var res = converter.convert(buf); @@ -54,12 +53,18 @@ var sbcsEncodingTests = {}; describe("Full SBCS encoding tests", function() { this.timeout(10000); + var Iconv; + try { + Iconv = require('iconv').Iconv; + } catch (_e) {} + for (var enc in iconv.encodings) if (iconv.encodings[enc].type === '_sbcs') (function(enc) { var iconvName = iconvAlias(enc), testEncName = enc + ((enc !== iconvName) ? " (" + iconvName + ")" : ""); it("Decode SBCS encoding " + testEncName, function() { + if (!Iconv) this.skip(); try { var conv = new Iconv(iconvName, "utf-8//IGNORE"); } catch (e) { diff --git a/test/utf32-test.js b/test/utf32-test.js index 6da093e5..377620ba 100644 --- a/test/utf32-test.js +++ b/test/utf32-test.js @@ -1,7 +1,6 @@ var assert = require('assert'), Buffer = require('safer-buffer').Buffer, - iconv = require(__dirname+'/../'), - Iconv = require('iconv').Iconv; + iconv = require(__dirname+'/../'); var testStr = '1aя中文☃💩', testStr2 = '❝Stray high \uD977😱 and low\uDDDD☔ surrogate values.❞', @@ -47,6 +46,12 @@ for (var i = 0; i <= 0x10F7FF; ++i) { } describe('UTF-32LE codec', function() { + var Iconv; + + try { + Iconv = require('iconv').Iconv; + } catch (_e) {} + it('encodes basic strings correctly', function() { assert.equal(iconv.encode(testStr, 'UTF32-LE').toString('hex'), utf32leBuf.toString('hex')); }); @@ -69,6 +74,11 @@ describe('UTF-32LE codec', function() { }); it('handles encoding all valid codepoints', function() { + if (!Iconv) { + this.skip(); + } + + assert.deepEqual(iconv.encode(allCharsStr, 'utf-32le'), allCharsLEBuf); var nodeIconv = new Iconv('UTF-8', 'UTF-32LE'); var nodeBuf = nodeIconv.convert(allCharsStr); @@ -76,6 +86,10 @@ describe('UTF-32LE codec', function() { }); it('handles decoding all valid codepoints', function() { + if (!Iconv) { + this.skip(); + } + assert.equal(iconv.decode(allCharsLEBuf, 'utf-32le'), allCharsStr); var nodeIconv = new Iconv('UTF-32LE', 'UTF-8'); var nodeStr = nodeIconv.convert(allCharsLEBuf).toString('utf8'); @@ -84,6 +98,12 @@ describe('UTF-32LE codec', function() { }); describe('UTF-32BE codec', function() { + var Iconv; + + try { + Iconv = require('iconv').Iconv; + } catch (_e) {} + it('encodes basic strings correctly', function() { assert.equal(iconv.encode(testStr, 'UTF32-BE').toString('hex'), utf32beBuf.toString('hex')); }); @@ -106,6 +126,11 @@ describe('UTF-32BE codec', function() { }); it('handles encoding all valid codepoints', function() { + if (!Iconv) { + this.skip(); + } + + assert.deepEqual(iconv.encode(allCharsStr, 'utf-32be'), allCharsBEBuf); var nodeIconv = new Iconv('UTF-8', 'UTF-32BE'); var nodeBuf = nodeIconv.convert(allCharsStr); @@ -113,6 +138,11 @@ describe('UTF-32BE codec', function() { }); it('handles decoding all valid codepoints', function() { + if (!Iconv) { + this.skip(); + } + + assert.equal(iconv.decode(allCharsBEBuf, 'utf-32be'), allCharsStr); var nodeIconv = new Iconv('UTF-32BE', 'UTF-8'); var nodeStr = nodeIconv.convert(allCharsBEBuf).toString('utf8'); diff --git a/test/webpack/karma.conf.js b/test/webpack/karma.conf.js index 7bfab3bf..3cad7a89 100644 --- a/test/webpack/karma.conf.js +++ b/test/webpack/karma.conf.js @@ -65,7 +65,14 @@ module.exports = function(config) { // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['ChromeHeadless'], + browsers: ['ChromeHeadless', 'ChromeHeadlessCI'], + + customLaunchers: { + ChromeHeadlessCI: { + base: 'ChromeHeadless', + flags: ['--no-sandbox'] + } + }, // Continuous Integration mode diff --git a/test/webpack/package.json b/test/webpack/package.json index ef01f4f7..89391622 100644 --- a/test/webpack/package.json +++ b/test/webpack/package.json @@ -5,9 +5,7 @@ "scripts": { "!note1": "NOTE: We do `npm pack` of the main iconv-lite package followed by installing it to create a copy of the package (not symlink).", "!note2": "This is needed because webpack4/watchpack1.7 crashes when trying to enumerate circular symlink.", - "preinstall": "mv $(npm pack -pq ../../) iconv-lite.tgz", - "postinstall": "rm iconv-lite.tgz", - "test": "karma start" + "test": "karma start --browsers ChromeHeadlessCI" }, "devDependencies": { "karma": "^5.0.9",