X-Git-Url: https://git.squeep.com/?a=blobdiff_plain;f=test%2Flib%2Frfc8288-web-linking.js;fp=test%2Flib%2Frfc8288-web-linking.js;h=6bdc1884cf5f5f1ab1a93b049b530b5fce1d23d9;hb=3436c07c25324507228f3d538d345ea35751c623;hp=0000000000000000000000000000000000000000;hpb=b36198e0a3d21413d75a501ffd52f0fb20188a31;p=squeep-web-linking
diff --git a/test/lib/rfc8288-web-linking.js b/test/lib/rfc8288-web-linking.js
new file mode 100644
index 0000000..6bdc188
--- /dev/null
+++ b/test/lib/rfc8288-web-linking.js
@@ -0,0 +1,275 @@
+/* eslint-env mocha */
+'use strict';
+
+const assert = require('assert');
+
+describe('RFC 8288 Header parser', function () {
+ const { parse, SyntaxError: PEGSyntaxError } = require('../../lib/rfc8288-web-linking');
+
+ function checkParser(linkHeader, expectedResult) {
+ const result = parse(linkHeader.replace(/\r?\n|\r/gm, ''));
+ assert.deepStrictEqual(result, expectedResult);
+ }
+
+ describe('§3.3 Relation Type', function () {
+ it('Must ignore occurrences after the first', function () {
+ const linkHeader = [
+ ';',
+ 'rel="start"; rel="ignore"; foo',
+ ].join('\n');
+ const expectedResult = [
+ {
+ target: 'http://example.org/',
+ attributes: [
+ {
+ extended: false,
+ name: 'rel',
+ value: 'start',
+ },
+ {
+ extended: false,
+ name: 'foo',
+ value: null,
+ },
+ ],
+ },
+ ];
+ checkParser(linkHeader, expectedResult);
+ });
+ });
+
+ describe('§3.5 Link Header Field Examples', function () {
+ it('a', function () {
+ const linkHeader = [
+ '; rel="previous";',
+ 'title="previous chapter"',
+ ].join('\n');
+ const expectedResult = [
+ {
+ target: 'http://example.com/TheBook/chapter2',
+ attributes: [
+ {
+ extended: false,
+ name: 'rel',
+ value: 'previous',
+ },
+ {
+ extended: false,
+ name: 'title',
+ value: 'previous chapter',
+ },
+ ],
+ },
+ ];
+ checkParser(linkHeader, expectedResult);
+ });
+ it('b', function () {
+ const linkHeader = '>; rel="http://example.net/foo"';
+ const expectedResult = [
+ {
+ target: '/',
+ attributes: [
+ {
+ extended: false,
+ name: 'rel',
+ value: 'http://example.net/foo',
+ },
+ ],
+ },
+ ];
+ checkParser(linkHeader, expectedResult);
+ });
+ it('c', function () {
+ const linkHeader = '; rel="copyright"; anchor="#foo"';
+ const expectedResult = [
+ {
+ target: '/terms',
+ attributes: [
+ {
+ extended: false,
+ name: 'rel',
+ value: 'copyright',
+ },
+ {
+ extended: false,
+ name: 'anchor',
+ value: '#foo',
+ },
+ ],
+ },
+ ];
+ checkParser(linkHeader, expectedResult);
+ });
+ it('d', function () {
+ const linkHeader = [
+ ';',
+ 'rel="previous"; title*=UTF-8\'de\'letztes%20Kapitel,',
+ ';',
+ 'rel="next"; title*=UTF-8\'de\'n%c3%a4chstes%20Kapitel',
+ ].join('\n');
+ const expectedResult = [
+ {
+ target: '/TheBook/chapter2',
+ attributes: [
+ {
+ extended: false,
+ name: 'rel',
+ value: 'previous',
+ },
+ {
+ extended: true,
+ name: 'title*',
+ value: 'UTF-8\'de\'letztes%20Kapitel',
+ },
+ ],
+ },
+ {
+ target: '/TheBook/chapter4',
+ attributes: [
+ {
+ extended: false,
+ name: 'rel',
+ value: 'next',
+ },
+ {
+ extended: true,
+ name: 'title*',
+ value: 'UTF-8\'de\'n%c3%a4chstes%20Kapitel',
+ },
+ ],
+ },
+ ];
+ checkParser(linkHeader, expectedResult);
+ });
+ it('e', function () {
+ const linkHeader = [
+ ';',
+ 'rel="start http://example.net/relation/other"',
+ ].join('\n');
+ const expectedResult = [
+ {
+ target: 'http://example.org/',
+ attributes: [
+ {
+ extended: false,
+ name: 'rel',
+ value: 'start http://example.net/relation/other',
+ },
+ ],
+ },
+ ];
+ checkParser(linkHeader, expectedResult);
+ });
+ it('f', function () {
+ const linkHeader = [
+ '; rel="start",',
+ ' ; rel="index"',
+ ].join('\n');
+ const expectedResult = [
+ {
+ target: 'https://example.org/',
+ attributes: [
+ {
+ extended: false,
+ name: 'rel',
+ value: 'start',
+ },
+ ],
+ },
+ {
+ target: 'https://example.org/index',
+ attributes: [
+ {
+ extended: false,
+ name: 'rel',
+ value: 'index',
+ },
+ ],
+ },
+ ];
+ checkParser(linkHeader, expectedResult);
+ });
+ }); // §3.5 Link Header Field Examples
+
+ describe('Unusual Cases', function () {
+ it('handles uris with semicolons', function () {
+ const linkHeader = [
+ '; rel="self";',
+ ].join('\n');
+ const expectedResult = [
+ {
+ target: 'http://example.com/strange;url;indeed',
+ attributes: [
+ {
+ extended: false,
+ name: 'rel',
+ value: 'self',
+ },
+ ],
+ },
+ ];
+ checkParser(linkHeader, expectedResult);
+ });
+ it('handles value-less attributes', function () {
+ const linkHeader = [
+ '>; special; rel="special";',
+ ].join('\n');
+ const expectedResult = [
+ {
+ target: '/',
+ attributes: [
+ {
+ extended: false,
+ name: 'special',
+ value: null,
+ },
+ {
+ extended: false,
+ name: 'rel',
+ value: 'special',
+ },
+ ],
+ },
+ ];
+ checkParser(linkHeader, expectedResult);
+ });
+ }); // Unusual Cases
+
+ describe('Extended Values', function () {
+ it('decodes extended value', function () {
+ const extendedValue = 'UTF-8\'\'%c2%a3%20and%20%e2%82%ac%20rates';
+ const expectedResult = {
+ encoding: 'UTF-8',
+ language: null,
+ value: '£ and ⬠rates',
+ };
+ const result = parse(extendedValue, { startRule: 'extendedValue' });
+ assert.deepStrictEqual(result, expectedResult);
+ });
+ }); // Extended Values
+
+ describe('Failures', function () {
+ it('does not parse invalid header', function () {
+ const linkHeader = 'not a link header';
+ const expectedResult = [];
+ try {
+ checkParser(linkHeader, expectedResult);
+ assert.fail('unexpected success');
+ } catch (e) {
+ assert.strictEqual(e.name, 'SyntaxError');
+ }
+ });
+ it('does not parse partial invalid header', function () {
+ const linkHeader = '; rel="valid", not a link header';
+ const expectedResult = [];
+ try {
+ checkParser(linkHeader, expectedResult);
+ assert.fail('unexpected success');
+ } catch (e) {
+ assert(e instanceof PEGSyntaxError);
+ assert.strictEqual(e.name, 'SyntaxError');
+ }
+ });
+ }); // Failures
+
+});
\ No newline at end of file