You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@annotator.apache.org by ge...@apache.org on 2020/04/03 11:53:19 UTC
[incubator-annotator] 04/09: Test fragment-identifier against spec
examples
This is an automated email from the ASF dual-hosted git repository.
gerben pushed a commit to branch fragment-tests
in repository https://gitbox.apache.org/repos/asf/incubator-annotator.git
commit 531d5e75d0ec61a4bdf095c96b73633c7fda80cd
Author: Gerben <ge...@treora.com>
AuthorDate: Thu Apr 2 21:46:25 2020 +0200
Test fragment-identifier against spec examples
Derived from earlier work: https://github.com/Treora/selector-state-frags/blob/51fe53df390301f768b6e876a670d12d1249b2b1/test/test.js
---
packages/fragment-identifier/test/index.js | 55 +++++++
.../fragment-identifier/test/spec-examples.json | 180 +++++++++++++++++++++
2 files changed, 235 insertions(+)
diff --git a/packages/fragment-identifier/test/index.js b/packages/fragment-identifier/test/index.js
new file mode 100644
index 0000000..761de0d
--- /dev/null
+++ b/packages/fragment-identifier/test/index.js
@@ -0,0 +1,55 @@
+/**
+ * @license
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { parse, stringify } from '../src';
+
+// Test examples from the spec: https://www.w3.org/TR/2017/NOTE-selectors-states-20170223/#json-examples-converted-to-fragment-identifiers
+import specExamplesRaw from './spec-examples.json';
+
+// The JSON file has the full examples; pull out the parts we need.
+const specExamples = Object.fromEntries(Object.entries(specExamplesRaw).map(
+ ([name, { uri, obj: { selector, state } }]) =>
+ [name, { fragId: uri.split('#')[1], selector, state }]
+));
+
+describe('stringify', () => {
+ // Test examples in the spec, ignoring their URI encoding
+ for (const [name, example] of Object.entries(specExamples)) {
+ it(`should properly stringify (disregarding URI-encoding): '${name}'`, () => {
+ const result = stringify(example.selector || example.state);
+ assert.equal(
+ decodeURIComponent(result),
+ decodeURIComponent(example.fragId)
+ );
+ });
+ }
+});
+
+describe('parse', () => {
+ for (const [name, example] of Object.entries(specExamples)) {
+ it(`should properly parse: ${name}`, () => {
+ const expected = (example.selector !== undefined)
+ ? { selector: example.selector }
+ : { state: example.state };
+ const result = parse(example.fragId);
+ assert.deepEqual(result, expected);
+ });
+ }
+});
diff --git a/packages/fragment-identifier/test/spec-examples.json b/packages/fragment-identifier/test/spec-examples.json
new file mode 100644
index 0000000..832e02b
--- /dev/null
+++ b/packages/fragment-identifier/test/spec-examples.json
@@ -0,0 +1,180 @@
+{
+ "Example 2 <=> 16: Fragment selector": {
+ "uri": "http://example.org/video1#selector(type=FragmentSelector,conformsTo=http://www.w3.org/TR/media-frags/,value=t%3D30%2C60)",
+ "obj": {
+ "source": "http://example.org/video1",
+ "selector": {
+ "type": "FragmentSelector",
+ "conformsTo": "http://www.w3.org/TR/media-frags/",
+ "value": "t=30,60"
+ }
+ }
+ },
+
+ "Example 3 <=> 17: CSS selector": {
+ "uri": "http://example.org/page1.html#selector(type=CssSelector,value=%23elemid%20>%20.elemclass%20+%20p)",
+ "obj": {
+ "source": "http://example.org/page1.html",
+ "selector": {
+ "type": "CssSelector",
+ "value": "#elemid > .elemclass + p"
+ }
+ }
+ },
+
+ "Example 4 <=> 18: XPath selector": {
+ "uri": "http://example.org/page1.html#selector(type=XPathSelector,value=/html/body/p[2]/table/tr[2]/td[3]/span)",
+ "obj": {
+ "source": "http://example.org/page1.html",
+ "selector": {
+ "type": "XPathSelector",
+ "value": "/html/body/p[2]/table/tr[2]/td[3]/span"
+ }
+ }
+ },
+
+ "Example 5 <=> 19: TextQuote selector": {
+ "uri": "http://example.org/page1#selector(type=TextQuoteSelector,exact=annotation,prefix=this%20is%20an%20,suffix=%20that%20has%20some)",
+ "obj": {
+ "source": "http://example.org/page1",
+ "selector": {
+ "type": "TextQuoteSelector",
+ "exact": "annotation",
+ "prefix": "this is an ",
+ "suffix": " that has some"
+ }
+ }
+ },
+
+ "Example 6 <=> 20: TextPosition selector": {
+ "uri": "http://example.org/ebook1#selector(type=TextPositionSelector,start=412,end=795)",
+ "obj": {
+ "source": "http://example.org/ebook1",
+ "selector": {
+ "type": "TextPositionSelector",
+ "start": 412,
+ "end": 795
+ }
+ }
+ },
+
+ "Example 7 <=> 21: Data position selector": {
+ "uri": "http://example.org/diskimg1#selector(type=DataPositionSelector,start=4096,end=4104)",
+ "obj": {
+ "source": "http://example.org/diskimg1",
+ "selector": {
+ "type": "DataPositionSelector",
+ "start": 4096,
+ "end": 4104
+ }
+ }
+ },
+
+ "Example 8 <=> 22: SVG selector; external SVG": {
+ "uri": "http://example.org/map1#selector(type=SvgSelector,id=http://example.org/svg1)",
+ "obj": {
+ "source": "http://example.org/map1",
+ "selector": {
+ "type": "SvgSelector",
+ "id": "http://example.org/svg1"
+ }
+ }
+ },
+
+ "Example 9 <=> 23: SVG selector; embedded SVG": {
+ "uri": "http://example.org/map1#selector(type=SvgSelector,value=<svg:svg>%20...%20</svg:svg>)",
+ "obj": {
+ "source": "http://example.org/map1",
+ "selector": {
+ "type": "SvgSelector",
+ "value": "<svg:svg> ... </svg:svg>"
+ }
+ }
+ },
+
+ "Example 10 <=> 24: Range selector": {
+ "uri": "http://example.org/page1.html#selector(type=RangeSelector,startSelector=selector(type=XPathSelector,value=//table[1]/tr[1]/td[2]),endSelector=selector(type=XPathSelector,value=//table[1]/tr[1]/td[4]))",
+ "obj": {
+ "source": "http://example.org/page1.html",
+ "selector": {
+ "type": "RangeSelector",
+ "startSelector": {
+ "type": "XPathSelector",
+ "value": "//table[1]/tr[1]/td[2]"
+ },
+ "endSelector": {
+ "type": "XPathSelector",
+ "value": "//table[1]/tr[1]/td[4]"
+ }
+ }
+ }
+ },
+
+ "Example 11 <=> 25: Selector refinement": {
+ "uri": "http://example.org/page1#selector(type=FragmentSelector,value=para5,refinedBy=selector(type=TextQuoteSelector,exact=Selected%20Text,prefix=text%20before%20the%20,suffix=%20and%20text%20after%20it))",
+ "obj": {
+ "source": "http://example.org/page1",
+ "selector": {
+ "type": "FragmentSelector",
+ "value": "para5",
+ "refinedBy": {
+ "type": "TextQuoteSelector",
+ "exact": "Selected Text",
+ "prefix": "text before the ",
+ "suffix": " and text after it"
+ }
+ }
+ }
+ },
+
+ "Example 13 <=> 26: Time state": {
+ "uri": "http://example.org/page1#state(type=TimeState,cached=http://archive.example.org/copy1,sourceDate=2015-07-20T13:30:00Z)",
+ "obj": {
+ "source": "http://example.org/page1",
+ "state": {
+ "type": "TimeState",
+ "cached": "http://archive.example.org/copy1",
+ "sourceDate": "2015-07-20T13:30:00Z"
+ }
+ }
+ },
+
+ "Example 14 <=> 27: HTTP request state": {
+ "uri": "http://example.org/resource1#state(type=HttpRequestState,value=Accept:%20application/pdf)",
+ "obj": {
+ "source": "http://example.org/resource1",
+ "state": {
+ "type": "HttpRequestState",
+ "value": "Accept: application/pdf"
+ }
+ }
+ },
+
+ "Example 15 <=> 28: Refinement of states": {
+ "uri": "http://example.org/ebook1#state(type=TimeState,sourceDate=2016-02-01T12:05:23Z,refinedBy=state(type=HttpRequestState,value=Accept:%20application/epub+zip))",
+ "obj": {
+ "source": "http://example.org/ebook1",
+ "state": {
+ "type": "TimeState",
+ "sourceDate": "2016-02-01T12:05:23Z",
+ "refinedBy": {
+ "type": "HttpRequestState",
+ "value": "Accept: application/epub+zip"
+ }
+ }
+ }
+ },
+
+ "Example 29: Serializing IRI to URL (and vice versa)": {
+ "uri": "http://jp.example.org/page1#selector(type=TextQuoteSelector,exact=%E3%83%9A%E3%83%B3%E3%82%92,prefix=%E7%A7%81%E3%81%AF%E3%80%81,suffix=%E6%8C%81%E3%81%A3%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99)",
+ "obj": {
+ "source": "http://jp.example.org/page1",
+ "selector": {
+ "type": "TextQuoteSelector",
+ "exact": "ペンを",
+ "prefix": "私は、",
+ "suffix": "持っています"
+ }
+ }
+ }
+}