@embedpdf/engine-core 3.0.0-next.12 → 3.0.0-next.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AbortError-8-9JAX1Y.js → AbortError-DwuHPK_I.js} +2 -2
- package/dist/{AbortError-8-9JAX1Y.js.map → AbortError-DwuHPK_I.js.map} +1 -1
- package/dist/{AbortError-CRSooKsk.cjs → AbortError-P0RU0Mgg.cjs} +4 -4
- package/dist/{AbortError-CRSooKsk.cjs.map → AbortError-P0RU0Mgg.cjs.map} +1 -1
- package/dist/{AnnotationListSnapshot-x6tKulNV.d.cts → AnnotationListSnapshot-D9R5n2Kf.d.cts} +1390 -176
- package/dist/{AnnotationListSnapshot-x6tKulNV.d.ts → AnnotationListSnapshot-D9R5n2Kf.d.ts} +1390 -176
- package/dist/{DocumentSecurityService-CK0pejAK.d.cts → DocumentSecurityService-CIx1MT0T.d.cts} +2 -2
- package/dist/{DocumentSecurityService-9MawYxP-.d.ts → DocumentSecurityService-Ca6EK3-3.d.ts} +2 -2
- package/dist/{Engine--0XF0UAK.d.cts → Engine-EWWHhEIi.d.ts} +179 -11
- package/dist/{Engine-Ds0ytbl6.d.ts → Engine-FNaAEjfb.d.cts} +179 -11
- package/dist/conformance.cjs +1441 -88
- package/dist/conformance.cjs.map +1 -1
- package/dist/conformance.d.cts +74 -3
- package/dist/conformance.d.ts +74 -3
- package/dist/conformance.js +1376 -25
- package/dist/conformance.js.map +1 -1
- package/dist/derive-BbsDk_Kz.cjs +880 -0
- package/dist/derive-BbsDk_Kz.cjs.map +1 -0
- package/dist/derive-DAFJolWu.js +647 -0
- package/dist/derive-DAFJolWu.js.map +1 -0
- package/dist/{PageInsertBlankInput-WKY0tr6S.js → format-Bbphf4zR.js} +95 -3
- package/dist/format-Bbphf4zR.js.map +1 -0
- package/dist/{PageInsertBlankInput-CzShuSJI.cjs → format-D_epWlob.cjs} +106 -2
- package/dist/format-D_epWlob.cjs.map +1 -0
- package/dist/index.cjs +137 -88
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -5
- package/dist/{resolver-D-jumvgM.cjs → resolver-CYVNV4hn.cjs} +216 -10
- package/dist/resolver-CYVNV4hn.cjs.map +1 -0
- package/dist/{resolver-CHG4waXL.js → resolver-inAVzsWt.js} +157 -11
- package/dist/resolver-inAVzsWt.js.map +1 -0
- package/dist/runtime.cjs +147 -98
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.cts +216 -5
- package/dist/runtime.d.ts +216 -5
- package/dist/runtime.js +6 -6
- package/dist/{schemas-DOyVEPk7.js → schemas-CFQGvWiu.js} +551 -5
- package/dist/schemas-CFQGvWiu.js.map +1 -0
- package/dist/{schemas-RChsAMWw.cjs → schemas-D0g6tKa9.cjs} +829 -25
- package/dist/schemas-D0g6tKa9.cjs.map +1 -0
- package/dist/{builders-8Hl1AYNU.cjs → viewport-BWeNHZmb.cjs} +1522 -117
- package/dist/viewport-BWeNHZmb.cjs.map +1 -0
- package/dist/{builders-DOjcKDWQ.js → viewport-CvMcadfQ.js} +1386 -89
- package/dist/viewport-CvMcadfQ.js.map +1 -0
- package/dist/wire.cjs +252 -13
- package/dist/wire.cjs.map +1 -1
- package/dist/wire.d.cts +3147 -5
- package/dist/wire.d.ts +3147 -5
- package/dist/wire.js +207 -14
- package/dist/wire.js.map +1 -1
- package/package.json +1 -1
- package/dist/PageInsertBlankInput-CzShuSJI.cjs.map +0 -1
- package/dist/PageInsertBlankInput-WKY0tr6S.js.map +0 -1
- package/dist/builders-8Hl1AYNU.cjs.map +0 -1
- package/dist/builders-DOjcKDWQ.js.map +0 -1
- package/dist/fold-BfyxxwS6.js +0 -334
- package/dist/fold-BfyxxwS6.js.map +0 -1
- package/dist/fold-C7I5GpBz.cjs +0 -447
- package/dist/fold-C7I5GpBz.cjs.map +0 -1
- package/dist/resolver-CHG4waXL.js.map +0 -1
- package/dist/resolver-D-jumvgM.cjs.map +0 -1
- package/dist/schemas-DOyVEPk7.js.map +0 -1
- package/dist/schemas-RChsAMWw.cjs.map +0 -1
package/dist/conformance.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const require_AbortError = require("./AbortError-
|
|
5
|
-
const require_schemas = require("./schemas-
|
|
2
|
+
const require_derive = require("./derive-BbsDk_Kz.cjs");
|
|
3
|
+
const require_format = require("./format-D_epWlob.cjs");
|
|
4
|
+
const require_AbortError = require("./AbortError-P0RU0Mgg.cjs");
|
|
5
|
+
const require_schemas = require("./schemas-D0g6tKa9.cjs");
|
|
6
6
|
//#region src/conformance/runMetadataConformance.ts
|
|
7
7
|
/**
|
|
8
8
|
* The conformance harness is transport-agnostic. It takes the test runner as
|
|
@@ -60,7 +60,7 @@ function runMetadataConformance(runner, opts) {
|
|
|
60
60
|
caught = err;
|
|
61
61
|
}
|
|
62
62
|
expect(caught).toBeTruthy();
|
|
63
|
-
expect(
|
|
63
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.DocNotOpen)).toBe(true);
|
|
64
64
|
});
|
|
65
65
|
test("update() sets standard + custom fields and a subsequent read observes them", async () => {
|
|
66
66
|
const doc = await openFixture$20(engine, opts);
|
|
@@ -104,7 +104,7 @@ function runMetadataConformance(runner, opts) {
|
|
|
104
104
|
caught = err;
|
|
105
105
|
}
|
|
106
106
|
expect(caught).toBeTruthy();
|
|
107
|
-
expect(
|
|
107
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.DocNotOpen)).toBe(true);
|
|
108
108
|
});
|
|
109
109
|
});
|
|
110
110
|
}
|
|
@@ -123,6 +123,270 @@ async function openFixture$20(engine, opts) {
|
|
|
123
123
|
});
|
|
124
124
|
}
|
|
125
125
|
//#endregion
|
|
126
|
+
//#region src/conformance/runMeasurementConformance.ts
|
|
127
|
+
/** Shared numerical, persistence and calibration contract for local and HTTP engines. */
|
|
128
|
+
function runMeasurementConformance(runner, opts) {
|
|
129
|
+
const { describe, test, beforeAll, afterAll, expect } = runner;
|
|
130
|
+
describe(`measurement conformance: ${opts.label}`, () => {
|
|
131
|
+
let engine;
|
|
132
|
+
beforeAll(async () => {
|
|
133
|
+
engine = await opts.makeEngine();
|
|
134
|
+
});
|
|
135
|
+
afterAll(async () => {
|
|
136
|
+
await engine?.destroy();
|
|
137
|
+
});
|
|
138
|
+
const open = async () => opts.openKind === "bytes" ? engine.open({
|
|
139
|
+
kind: "bytes",
|
|
140
|
+
id: opts.fixture.id,
|
|
141
|
+
bytes: await opts.fixture.bytes()
|
|
142
|
+
}) : engine.open({
|
|
143
|
+
kind: "id",
|
|
144
|
+
id: opts.fixture.cloudId ?? opts.fixture.id
|
|
145
|
+
});
|
|
146
|
+
const scale = require_derive.measureFromKnownLength(100, {
|
|
147
|
+
value: 3,
|
|
148
|
+
unit: "m"
|
|
149
|
+
});
|
|
150
|
+
const rect = {
|
|
151
|
+
left: 0,
|
|
152
|
+
bottom: 0,
|
|
153
|
+
right: 100,
|
|
154
|
+
top: 100
|
|
155
|
+
};
|
|
156
|
+
const vertices = [
|
|
157
|
+
{
|
|
158
|
+
x: 0,
|
|
159
|
+
y: 0
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
x: 100,
|
|
163
|
+
y: 0
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
x: 100,
|
|
167
|
+
y: 100
|
|
168
|
+
}
|
|
169
|
+
];
|
|
170
|
+
test("geometry derives contents while caption patches retain placement", async () => {
|
|
171
|
+
const doc = await open();
|
|
172
|
+
try {
|
|
173
|
+
const page = doc.page((await doc.pages.list()).pages[0].pageObjectNumber);
|
|
174
|
+
const created = (await page.annotations.create({
|
|
175
|
+
subtype: "line",
|
|
176
|
+
intent: "LineDimension",
|
|
177
|
+
rect,
|
|
178
|
+
measure: scale,
|
|
179
|
+
linePoints: {
|
|
180
|
+
start: vertices[0],
|
|
181
|
+
end: vertices[1]
|
|
182
|
+
},
|
|
183
|
+
caption: {
|
|
184
|
+
enabled: true,
|
|
185
|
+
offset: {
|
|
186
|
+
along: 10,
|
|
187
|
+
perpendicular: 20
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
})).created;
|
|
191
|
+
const inert = await page.annotations.update(created.ref, {
|
|
192
|
+
subtype: "line",
|
|
193
|
+
contents: "999 m"
|
|
194
|
+
});
|
|
195
|
+
expect(inert.updated.contents).toBe("3 m");
|
|
196
|
+
expect(inert.appearance).toEqual({
|
|
197
|
+
action: "preserved",
|
|
198
|
+
changed: false
|
|
199
|
+
});
|
|
200
|
+
const changed = await page.annotations.update(created.ref, {
|
|
201
|
+
subtype: "line",
|
|
202
|
+
linePoints: {
|
|
203
|
+
start: vertices[0],
|
|
204
|
+
end: {
|
|
205
|
+
x: 200,
|
|
206
|
+
y: 0
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
expect(changed.updated.contents).toBe("6 m");
|
|
211
|
+
expect(changed.appearance.changed).toBe(true);
|
|
212
|
+
const hidden = await page.annotations.update(created.ref, {
|
|
213
|
+
subtype: "line",
|
|
214
|
+
caption: { enabled: false }
|
|
215
|
+
});
|
|
216
|
+
expect(hidden.updated).toMatchObject({
|
|
217
|
+
contents: "6 m",
|
|
218
|
+
caption: {
|
|
219
|
+
enabled: false,
|
|
220
|
+
offset: {
|
|
221
|
+
along: 10,
|
|
222
|
+
perpendicular: 20
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
expect(hidden.appearance.changed).toBe(true);
|
|
227
|
+
const reset = await page.annotations.update(created.ref, {
|
|
228
|
+
subtype: "line",
|
|
229
|
+
caption: {
|
|
230
|
+
enabled: true,
|
|
231
|
+
offset: null
|
|
232
|
+
},
|
|
233
|
+
measure: null
|
|
234
|
+
});
|
|
235
|
+
expect(reset.updated.contents).toBe("6 m");
|
|
236
|
+
expect(reset.updated.subtype === "line" && reset.updated.caption?.offset === void 0).toBe(true);
|
|
237
|
+
expect(require_derive.measurementReadout(reset.updated)).toEqual({ unavailable: "no-measure" });
|
|
238
|
+
} finally {
|
|
239
|
+
await doc.close();
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
test("all three kinds derive labels, save, reopen and retain captions", async () => {
|
|
243
|
+
let doc = await open();
|
|
244
|
+
try {
|
|
245
|
+
const pon = (await doc.pages.list()).pages[0].pageObjectNumber;
|
|
246
|
+
const drafts = [
|
|
247
|
+
{
|
|
248
|
+
subtype: "line",
|
|
249
|
+
rect,
|
|
250
|
+
intent: "LineDimension",
|
|
251
|
+
measure: require_derive.measureFromKnownLength(1, {
|
|
252
|
+
value: 1.00000001,
|
|
253
|
+
unit: "m"
|
|
254
|
+
}),
|
|
255
|
+
contents: "wrong",
|
|
256
|
+
linePoints: {
|
|
257
|
+
start: vertices[0],
|
|
258
|
+
end: {
|
|
259
|
+
x: 3.4450000001,
|
|
260
|
+
y: 0
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
caption: {
|
|
264
|
+
enabled: true,
|
|
265
|
+
offset: {
|
|
266
|
+
along: 10,
|
|
267
|
+
perpendicular: 20
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
subtype: "polyline",
|
|
273
|
+
rect,
|
|
274
|
+
intent: "PolyLineDimension",
|
|
275
|
+
measure: scale,
|
|
276
|
+
contents: "wrong",
|
|
277
|
+
vertices,
|
|
278
|
+
caption: {
|
|
279
|
+
enabled: true,
|
|
280
|
+
center: {
|
|
281
|
+
x: 0,
|
|
282
|
+
y: 0
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
subtype: "polygon",
|
|
288
|
+
rect,
|
|
289
|
+
intent: "PolygonDimension",
|
|
290
|
+
measure: scale,
|
|
291
|
+
contents: "wrong",
|
|
292
|
+
vertices,
|
|
293
|
+
caption: {
|
|
294
|
+
enabled: true,
|
|
295
|
+
center: {
|
|
296
|
+
x: 50,
|
|
297
|
+
y: 30
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
];
|
|
302
|
+
const saved = [];
|
|
303
|
+
for (const draft of drafts) {
|
|
304
|
+
const preview = require_derive.measurementReadout(draft);
|
|
305
|
+
const a = (await doc.page(pon).annotations.create(draft)).created;
|
|
306
|
+
expect(a.contents).toBe("label" in preview ? preview.label : void 0);
|
|
307
|
+
saved.push(a);
|
|
308
|
+
}
|
|
309
|
+
const bytes = opts.openKind === "bytes" ? await doc.download() : void 0;
|
|
310
|
+
await doc.close();
|
|
311
|
+
doc = bytes ? await engine.open({
|
|
312
|
+
kind: "bytes",
|
|
313
|
+
id: `${opts.fixture.id}-saved`,
|
|
314
|
+
bytes
|
|
315
|
+
}) : await open();
|
|
316
|
+
const page = doc.page((await doc.pages.list()).pages[0].pageObjectNumber);
|
|
317
|
+
const list = (await page.annotations.list()).annotations;
|
|
318
|
+
for (const before of saved) {
|
|
319
|
+
const a = list.find((a) => require_derive.refKey(a.ref) === require_derive.refKey(before.ref));
|
|
320
|
+
expect(a.contents).toBe(before.contents);
|
|
321
|
+
if (a.subtype !== "line" && a.subtype !== "polygon" && a.subtype !== "polyline") throw new Error("Missing dimension");
|
|
322
|
+
expect(a.caption).toEqual("caption" in before ? before.caption : void 0);
|
|
323
|
+
const result = await page.annotations.update(a.ref, {
|
|
324
|
+
subtype: a.subtype,
|
|
325
|
+
color: {
|
|
326
|
+
r: 0,
|
|
327
|
+
g: 0,
|
|
328
|
+
b: 255
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
expect(result.updated.contents).toBe(before.contents);
|
|
332
|
+
}
|
|
333
|
+
} finally {
|
|
334
|
+
await doc.close();
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
test("calibration updates only viewports and emits one event per write", async () => {
|
|
338
|
+
const doc = await open();
|
|
339
|
+
try {
|
|
340
|
+
const pon = (await doc.pages.list()).pages[0].pageObjectNumber;
|
|
341
|
+
const page = doc.page(pon);
|
|
342
|
+
if (!page.measure) throw new Error("Measurement service is required");
|
|
343
|
+
const foreign = (await page.measure.viewports()).filter((v) => !v.owned);
|
|
344
|
+
const annotations = (await page.annotations.list()).annotations;
|
|
345
|
+
const events = [];
|
|
346
|
+
const off = doc.events.subscribe((event) => events.push(event));
|
|
347
|
+
try {
|
|
348
|
+
await page.measure.setScale(scale);
|
|
349
|
+
expect((await page.measure.viewports()).filter((v) => v.owned)).toHaveLength(1);
|
|
350
|
+
expect((await page.annotations.list()).annotations).toEqual(annotations);
|
|
351
|
+
await page.measure.setScale(null);
|
|
352
|
+
expect(await page.measure.viewports()).toEqual(foreign);
|
|
353
|
+
const changes = events.filter((e) => e.type === "page.viewportsChanged");
|
|
354
|
+
expect(changes).toHaveLength(2);
|
|
355
|
+
for (const event of changes) expect(event).toMatchObject({
|
|
356
|
+
pageObjectNumber: pon,
|
|
357
|
+
meta: { affectedPages: [] }
|
|
358
|
+
});
|
|
359
|
+
} finally {
|
|
360
|
+
off();
|
|
361
|
+
}
|
|
362
|
+
} finally {
|
|
363
|
+
await doc.close();
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
test("invalid and immediately aborted calibration leaves the previous scale intact", async () => {
|
|
367
|
+
const doc = await open();
|
|
368
|
+
try {
|
|
369
|
+
const page = doc.page((await doc.pages.list()).pages[0].pageObjectNumber);
|
|
370
|
+
await page.measure.setScale(scale);
|
|
371
|
+
const before = await page.measure.viewports();
|
|
372
|
+
await expect(page.measure.setScale({
|
|
373
|
+
...scale,
|
|
374
|
+
x: [{
|
|
375
|
+
unit: "m",
|
|
376
|
+
conversion: 0
|
|
377
|
+
}]
|
|
378
|
+
})).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
379
|
+
const pending = page.measure.setScale(null);
|
|
380
|
+
pending.abort("conformance");
|
|
381
|
+
await expect(pending).rejects.toBeInstanceOf(require_AbortError.AbortError);
|
|
382
|
+
expect(await page.measure.viewports()).toEqual(before);
|
|
383
|
+
} finally {
|
|
384
|
+
await doc.close();
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
//#endregion
|
|
126
390
|
//#region src/conformance/runAnnotationReadConformance.ts
|
|
127
391
|
function runAnnotationReadConformance(runner, opts) {
|
|
128
392
|
const { describe, test, beforeAll, afterAll, expect } = runner;
|
|
@@ -333,7 +597,7 @@ function runAnnotationReadConformance(runner, opts) {
|
|
|
333
597
|
caught = err;
|
|
334
598
|
}
|
|
335
599
|
expect(caught).toBeTruthy();
|
|
336
|
-
expect(
|
|
600
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.NotFound)).toBe(true);
|
|
337
601
|
} finally {
|
|
338
602
|
await doc.close();
|
|
339
603
|
}
|
|
@@ -389,7 +653,7 @@ function runActionsConformance(runner, opts) {
|
|
|
389
653
|
if (engine) await engine.destroy();
|
|
390
654
|
});
|
|
391
655
|
test("reads catalog additional actions and preserves /CO identity", async () => {
|
|
392
|
-
const doc = await open(engine, opts, opts.fixtures.document);
|
|
656
|
+
const doc = await open$1(engine, opts, opts.fixtures.document);
|
|
393
657
|
try {
|
|
394
658
|
expect(Boolean(doc.actions)).toBe(true);
|
|
395
659
|
const snapshot = await doc.actions.read();
|
|
@@ -410,7 +674,7 @@ function runActionsConformance(runner, opts) {
|
|
|
410
674
|
}
|
|
411
675
|
});
|
|
412
676
|
test("attaches page /AA to PageLayout", async () => {
|
|
413
|
-
const doc = await open(engine, opts, opts.fixtures.page);
|
|
677
|
+
const doc = await open$1(engine, opts, opts.fixtures.page);
|
|
414
678
|
try {
|
|
415
679
|
const pages = await doc.pages.list();
|
|
416
680
|
expect(pages.pages[0].actions?.open?.root?.type).toBe("goto-embedded");
|
|
@@ -422,7 +686,7 @@ function runActionsConformance(runner, opts) {
|
|
|
422
686
|
}
|
|
423
687
|
});
|
|
424
688
|
test("attaches activation actions to AnnotationBase, including links", async () => {
|
|
425
|
-
const doc = await open(engine, opts, opts.fixtures.annotation);
|
|
689
|
+
const doc = await open$1(engine, opts, opts.fixtures.annotation);
|
|
426
690
|
try {
|
|
427
691
|
const firstPage = (await doc.pages.list()).pages[0];
|
|
428
692
|
const snapshot = await doc.page(firstPage.pageObjectNumber).annotations.list();
|
|
@@ -439,7 +703,7 @@ function runActionsConformance(runner, opts) {
|
|
|
439
703
|
test("classifies a /S /JavaScript link target, script staying on base.actions", async () => {
|
|
440
704
|
const fixture = opts.fixtures.javascriptLink;
|
|
441
705
|
if (!fixture) return;
|
|
442
|
-
const doc = await open(engine, opts, fixture);
|
|
706
|
+
const doc = await open$1(engine, opts, fixture);
|
|
443
707
|
try {
|
|
444
708
|
const firstPage = (await doc.pages.list()).pages[0];
|
|
445
709
|
const link = (await doc.page(firstPage.pageObjectNumber).annotations.list()).annotations.find((annotation) => annotation.subtype === "link");
|
|
@@ -452,7 +716,7 @@ function runActionsConformance(runner, opts) {
|
|
|
452
716
|
}
|
|
453
717
|
});
|
|
454
718
|
test("keeps field actions separate from merged widget events", async () => {
|
|
455
|
-
const doc = await open(engine, opts, opts.fixtures.field);
|
|
719
|
+
const doc = await open$1(engine, opts, opts.fixtures.field);
|
|
456
720
|
try {
|
|
457
721
|
const form = await doc.forms.list();
|
|
458
722
|
expect(form.fields).toHaveLength(1);
|
|
@@ -466,7 +730,7 @@ function runActionsConformance(runner, opts) {
|
|
|
466
730
|
}
|
|
467
731
|
});
|
|
468
732
|
test("carries interpreter payloads on every executable node", async () => {
|
|
469
|
-
const doc = await open(engine, opts, opts.fixtures.payloads);
|
|
733
|
+
const doc = await open$1(engine, opts, opts.fixtures.payloads);
|
|
470
734
|
try {
|
|
471
735
|
const page = (await doc.pages.list()).pages[0];
|
|
472
736
|
const snapshot = await doc.page(page.pageObjectNumber).annotations.list();
|
|
@@ -627,7 +891,7 @@ function runActionsConformance(runner, opts) {
|
|
|
627
891
|
}
|
|
628
892
|
});
|
|
629
893
|
test("degrades unreadable payloads to unknown with payload-dropped", async () => {
|
|
630
|
-
const doc = await open(engine, opts, opts.fixtures.payloads);
|
|
894
|
+
const doc = await open$1(engine, opts, opts.fixtures.payloads);
|
|
631
895
|
try {
|
|
632
896
|
const page = (await doc.pages.list()).pages[0];
|
|
633
897
|
const snapshot = await doc.page(page.pageObjectNumber).annotations.list();
|
|
@@ -651,7 +915,7 @@ function runActionsConformance(runner, opts) {
|
|
|
651
915
|
}
|
|
652
916
|
});
|
|
653
917
|
test("reads a destination-form /OpenAction as openDestination", async () => {
|
|
654
|
-
const doc = await open(engine, opts, opts.fixtures.openDestination);
|
|
918
|
+
const doc = await open$1(engine, opts, opts.fixtures.openDestination);
|
|
655
919
|
try {
|
|
656
920
|
expect(Boolean(doc.actions)).toBe(true);
|
|
657
921
|
const snapshot = await doc.actions.read();
|
|
@@ -671,7 +935,7 @@ function runActionsConformance(runner, opts) {
|
|
|
671
935
|
});
|
|
672
936
|
});
|
|
673
937
|
}
|
|
674
|
-
async function open(engine, opts, fixture) {
|
|
938
|
+
async function open$1(engine, opts, fixture) {
|
|
675
939
|
if (opts.openKind === "bytes") return engine.open({
|
|
676
940
|
kind: "bytes",
|
|
677
941
|
id: fixture.id,
|
|
@@ -1519,6 +1783,287 @@ function runAnnotationMutationConformance(runner, opts) {
|
|
|
1519
1783
|
await doc.close();
|
|
1520
1784
|
}
|
|
1521
1785
|
});
|
|
1786
|
+
test("rich text: a plain draft reads back body-style paragraphs and a body from its font", async () => {
|
|
1787
|
+
const doc = await openFixture$18(engine, opts);
|
|
1788
|
+
try {
|
|
1789
|
+
const created = await doc.page(fix.pageObjectNumber).annotations.create({
|
|
1790
|
+
subtype: "free-text",
|
|
1791
|
+
intent: "free-text",
|
|
1792
|
+
contents: "Plain\rtext",
|
|
1793
|
+
rect: shapeRect,
|
|
1794
|
+
fontFamily: "helvetica-bold",
|
|
1795
|
+
fontSize: 18,
|
|
1796
|
+
textAlign: "center",
|
|
1797
|
+
color: {
|
|
1798
|
+
r: 0,
|
|
1799
|
+
g: 0,
|
|
1800
|
+
b: 0
|
|
1801
|
+
}
|
|
1802
|
+
});
|
|
1803
|
+
expect(created.created.subtype).toBe("free-text");
|
|
1804
|
+
if (created.created.subtype === "free-text") {
|
|
1805
|
+
const rich = created.created.richText;
|
|
1806
|
+
expect(created.created.fontFamily).toBe("helvetica-bold");
|
|
1807
|
+
expect(rich.body.family).toBe("Helvetica");
|
|
1808
|
+
expect(rich.body.weight).toBe(700);
|
|
1809
|
+
expect(rich.body.italic).toBe(false);
|
|
1810
|
+
expect(rich.body.size).toBe(18);
|
|
1811
|
+
expect(rich.body.align).toBe("center");
|
|
1812
|
+
expect(rich.paragraphs).toEqual([{ runs: [{ text: "Plain" }] }, { runs: [{ text: "text" }] }]);
|
|
1813
|
+
}
|
|
1814
|
+
} finally {
|
|
1815
|
+
await doc.close();
|
|
1816
|
+
}
|
|
1817
|
+
});
|
|
1818
|
+
test("rich text: a draft with runs round-trips the body, the runs and the plain projection", async () => {
|
|
1819
|
+
const doc = await openFixture$18(engine, opts);
|
|
1820
|
+
try {
|
|
1821
|
+
const page = doc.page(fix.pageObjectNumber);
|
|
1822
|
+
const created = await page.annotations.create({
|
|
1823
|
+
subtype: "free-text",
|
|
1824
|
+
intent: "free-text",
|
|
1825
|
+
rect: shapeRect,
|
|
1826
|
+
fontFamily: "helvetica",
|
|
1827
|
+
fontSize: 12,
|
|
1828
|
+
textAlign: "left",
|
|
1829
|
+
color: {
|
|
1830
|
+
r: 0,
|
|
1831
|
+
g: 0,
|
|
1832
|
+
b: 255
|
|
1833
|
+
},
|
|
1834
|
+
richText: {
|
|
1835
|
+
body: {
|
|
1836
|
+
family: "Helvetica",
|
|
1837
|
+
size: 18,
|
|
1838
|
+
color: "#102030"
|
|
1839
|
+
},
|
|
1840
|
+
paragraphs: [{ runs: [
|
|
1841
|
+
{ text: "Hello " },
|
|
1842
|
+
{
|
|
1843
|
+
text: "bold",
|
|
1844
|
+
style: { weight: 700 }
|
|
1845
|
+
},
|
|
1846
|
+
{
|
|
1847
|
+
text: " red",
|
|
1848
|
+
style: { color: "#FF0000" }
|
|
1849
|
+
}
|
|
1850
|
+
] }, {
|
|
1851
|
+
align: "center",
|
|
1852
|
+
runs: [{ text: "H" }, {
|
|
1853
|
+
text: "2",
|
|
1854
|
+
style: { script: "sub" }
|
|
1855
|
+
}]
|
|
1856
|
+
}]
|
|
1857
|
+
}
|
|
1858
|
+
});
|
|
1859
|
+
expect(require_schemas.AnnotationCreateResultSchema.safeParse(created).success).toBe(true);
|
|
1860
|
+
expect(created.created.subtype).toBe("free-text");
|
|
1861
|
+
if (created.created.subtype === "free-text") {
|
|
1862
|
+
const dto = created.created;
|
|
1863
|
+
expect(dto.contents).toBe("Hello bold red\rH2");
|
|
1864
|
+
expect(dto.fontFamily).toBe("helvetica");
|
|
1865
|
+
expect(dto.fontSize).toBe(18);
|
|
1866
|
+
expect(dto.color).toMatchObject({
|
|
1867
|
+
r: 0,
|
|
1868
|
+
g: 0,
|
|
1869
|
+
b: 255
|
|
1870
|
+
});
|
|
1871
|
+
expect(dto.richText.body.color).toBe("#102030");
|
|
1872
|
+
expect(dto.richText.paragraphs[0].runs).toEqual([
|
|
1873
|
+
{ text: "Hello " },
|
|
1874
|
+
{
|
|
1875
|
+
text: "bold",
|
|
1876
|
+
style: { weight: 700 }
|
|
1877
|
+
},
|
|
1878
|
+
{
|
|
1879
|
+
text: " red",
|
|
1880
|
+
style: { color: "#FF0000" }
|
|
1881
|
+
}
|
|
1882
|
+
]);
|
|
1883
|
+
expect(dto.richText.paragraphs[1].align).toBe("center");
|
|
1884
|
+
expect(dto.richText.paragraphs[1].runs[1]).toEqual({
|
|
1885
|
+
text: "2",
|
|
1886
|
+
style: { script: "sub" }
|
|
1887
|
+
});
|
|
1888
|
+
}
|
|
1889
|
+
const listed = (await page.annotations.list()).annotations.find((a) => a.index === created.created.index);
|
|
1890
|
+
expect(listed?.subtype).toBe("free-text");
|
|
1891
|
+
if (listed?.subtype === "free-text") expect(listed.richText.paragraphs[0].runs[1]).toEqual({
|
|
1892
|
+
text: "bold",
|
|
1893
|
+
style: { weight: 700 }
|
|
1894
|
+
});
|
|
1895
|
+
} finally {
|
|
1896
|
+
await doc.close();
|
|
1897
|
+
}
|
|
1898
|
+
});
|
|
1899
|
+
test("rich text: paragraphs-only patch keeps the body; contents-only rewrites body-style paragraphs", async () => {
|
|
1900
|
+
const doc = await openFixture$18(engine, opts);
|
|
1901
|
+
try {
|
|
1902
|
+
const page = doc.page(fix.pageObjectNumber);
|
|
1903
|
+
const ref = (await page.annotations.create({
|
|
1904
|
+
subtype: "free-text",
|
|
1905
|
+
intent: "free-text",
|
|
1906
|
+
rect: shapeRect,
|
|
1907
|
+
fontFamily: "helvetica",
|
|
1908
|
+
fontSize: 14,
|
|
1909
|
+
textAlign: "center",
|
|
1910
|
+
color: {
|
|
1911
|
+
r: 0,
|
|
1912
|
+
g: 0,
|
|
1913
|
+
b: 0
|
|
1914
|
+
},
|
|
1915
|
+
richText: {
|
|
1916
|
+
body: {
|
|
1917
|
+
family: "Helvetica",
|
|
1918
|
+
size: 14
|
|
1919
|
+
},
|
|
1920
|
+
paragraphs: [{ runs: [{ text: "a" }, {
|
|
1921
|
+
text: "b",
|
|
1922
|
+
style: { weight: 700 }
|
|
1923
|
+
}] }]
|
|
1924
|
+
}
|
|
1925
|
+
})).created.ref;
|
|
1926
|
+
const restyled = await page.annotations.update(ref, {
|
|
1927
|
+
subtype: "free-text",
|
|
1928
|
+
richText: { paragraphs: [{ runs: [{
|
|
1929
|
+
text: "ab",
|
|
1930
|
+
style: { italic: true }
|
|
1931
|
+
}, { text: "c" }] }] }
|
|
1932
|
+
});
|
|
1933
|
+
expect(require_schemas.AnnotationUpdateResultSchema.safeParse(restyled).success).toBe(true);
|
|
1934
|
+
expect(restyled.updated.subtype).toBe("free-text");
|
|
1935
|
+
if (restyled.updated.subtype === "free-text") {
|
|
1936
|
+
expect(restyled.updated.contents).toBe("abc");
|
|
1937
|
+
expect(restyled.updated.richText.body.size).toBe(14);
|
|
1938
|
+
expect(restyled.updated.richText.body.align).toBe("center");
|
|
1939
|
+
expect(restyled.updated.textAlign).toBe("center");
|
|
1940
|
+
expect(restyled.updated.richText.paragraphs[0].runs[0]).toEqual({
|
|
1941
|
+
text: "ab",
|
|
1942
|
+
style: { italic: true }
|
|
1943
|
+
});
|
|
1944
|
+
}
|
|
1945
|
+
const rewritten = await page.annotations.update(ref, {
|
|
1946
|
+
subtype: "free-text",
|
|
1947
|
+
contents: "one\rtwo"
|
|
1948
|
+
});
|
|
1949
|
+
expect(rewritten.updated.subtype).toBe("free-text");
|
|
1950
|
+
if (rewritten.updated.subtype === "free-text") {
|
|
1951
|
+
expect(rewritten.updated.contents).toBe("one\rtwo");
|
|
1952
|
+
expect(rewritten.updated.richText.paragraphs).toEqual([{ runs: [{ text: "one" }] }, { runs: [{ text: "two" }] }]);
|
|
1953
|
+
expect(rewritten.updated.richText.body.size).toBe(14);
|
|
1954
|
+
}
|
|
1955
|
+
expect(rewritten.meta.weakRefsInvalidated).toBe(false);
|
|
1956
|
+
} finally {
|
|
1957
|
+
await doc.close();
|
|
1958
|
+
}
|
|
1959
|
+
});
|
|
1960
|
+
test("rich text: fontSize / fontColor / fontFamily move the body while runs keep their deltas", async () => {
|
|
1961
|
+
const doc = await openFixture$18(engine, opts);
|
|
1962
|
+
try {
|
|
1963
|
+
const page = doc.page(fix.pageObjectNumber);
|
|
1964
|
+
const created = await page.annotations.create({
|
|
1965
|
+
subtype: "free-text",
|
|
1966
|
+
intent: "free-text",
|
|
1967
|
+
rect: shapeRect,
|
|
1968
|
+
fontFamily: "helvetica",
|
|
1969
|
+
fontSize: 14,
|
|
1970
|
+
textAlign: "left",
|
|
1971
|
+
color: {
|
|
1972
|
+
r: 0,
|
|
1973
|
+
g: 0,
|
|
1974
|
+
b: 0
|
|
1975
|
+
},
|
|
1976
|
+
richText: {
|
|
1977
|
+
body: {
|
|
1978
|
+
family: "Helvetica",
|
|
1979
|
+
size: 14
|
|
1980
|
+
},
|
|
1981
|
+
paragraphs: [{ runs: [{ text: "a" }, {
|
|
1982
|
+
text: "b",
|
|
1983
|
+
style: { size: 30 }
|
|
1984
|
+
}] }]
|
|
1985
|
+
}
|
|
1986
|
+
});
|
|
1987
|
+
const updated = await page.annotations.update(created.created.ref, {
|
|
1988
|
+
subtype: "free-text",
|
|
1989
|
+
fontSize: 20,
|
|
1990
|
+
fontColor: {
|
|
1991
|
+
r: 255,
|
|
1992
|
+
g: 0,
|
|
1993
|
+
b: 0
|
|
1994
|
+
},
|
|
1995
|
+
fontFamily: "times-bold"
|
|
1996
|
+
});
|
|
1997
|
+
expect(updated.updated.subtype).toBe("free-text");
|
|
1998
|
+
if (updated.updated.subtype === "free-text") {
|
|
1999
|
+
const dto = updated.updated;
|
|
2000
|
+
expect(dto.fontSize).toBe(20);
|
|
2001
|
+
expect(dto.fontFamily).toBe("times-bold");
|
|
2002
|
+
expect(dto.richText.body.size).toBe(20);
|
|
2003
|
+
expect(dto.richText.body.color).toBe("#FF0000");
|
|
2004
|
+
expect(dto.richText.body.family).toBe("Times");
|
|
2005
|
+
expect(dto.richText.body.weight).toBe(700);
|
|
2006
|
+
expect(dto.richText.paragraphs[0].runs[1]).toEqual({
|
|
2007
|
+
text: "b",
|
|
2008
|
+
style: { size: 30 }
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
} finally {
|
|
2012
|
+
await doc.close();
|
|
2013
|
+
}
|
|
2014
|
+
});
|
|
2015
|
+
test("rich text: contents and richText that disagree reject with InvalidArg; agreeing writes the runs", async () => {
|
|
2016
|
+
const doc = await openFixture$18(engine, opts);
|
|
2017
|
+
try {
|
|
2018
|
+
const page = doc.page(fix.pageObjectNumber);
|
|
2019
|
+
const created = await page.annotations.create({
|
|
2020
|
+
subtype: "free-text",
|
|
2021
|
+
intent: "free-text",
|
|
2022
|
+
contents: "x",
|
|
2023
|
+
rect: shapeRect,
|
|
2024
|
+
fontFamily: "helvetica",
|
|
2025
|
+
fontSize: 14,
|
|
2026
|
+
textAlign: "left",
|
|
2027
|
+
color: {
|
|
2028
|
+
r: 0,
|
|
2029
|
+
g: 0,
|
|
2030
|
+
b: 0
|
|
2031
|
+
}
|
|
2032
|
+
});
|
|
2033
|
+
const ref = created.created.ref;
|
|
2034
|
+
let caught;
|
|
2035
|
+
try {
|
|
2036
|
+
await page.annotations.update(ref, {
|
|
2037
|
+
subtype: "free-text",
|
|
2038
|
+
contents: "stale",
|
|
2039
|
+
richText: { paragraphs: [{ runs: [{ text: "fresh" }] }] }
|
|
2040
|
+
});
|
|
2041
|
+
} catch (err) {
|
|
2042
|
+
caught = err;
|
|
2043
|
+
}
|
|
2044
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
2045
|
+
const after = (await page.annotations.list()).annotations.find((a) => a.index === created.created.index);
|
|
2046
|
+
expect(after?.contents).toBe("x");
|
|
2047
|
+
const agreed = await page.annotations.update(ref, {
|
|
2048
|
+
subtype: "free-text",
|
|
2049
|
+
contents: "fresh",
|
|
2050
|
+
richText: { paragraphs: [{ runs: [{ text: "fr" }, {
|
|
2051
|
+
text: "esh",
|
|
2052
|
+
style: { weight: 700 }
|
|
2053
|
+
}] }] }
|
|
2054
|
+
});
|
|
2055
|
+
expect(agreed.updated.subtype).toBe("free-text");
|
|
2056
|
+
if (agreed.updated.subtype === "free-text") {
|
|
2057
|
+
expect(agreed.updated.contents).toBe("fresh");
|
|
2058
|
+
expect(agreed.updated.richText.paragraphs[0].runs[1]).toEqual({
|
|
2059
|
+
text: "esh",
|
|
2060
|
+
style: { weight: 700 }
|
|
2061
|
+
});
|
|
2062
|
+
}
|
|
2063
|
+
} finally {
|
|
2064
|
+
await doc.close();
|
|
2065
|
+
}
|
|
2066
|
+
});
|
|
1522
2067
|
test("create redact (area + text) round-trips label + colour fields", async () => {
|
|
1523
2068
|
const doc = await openFixture$18(engine, opts);
|
|
1524
2069
|
try {
|
|
@@ -2125,7 +2670,7 @@ function runAnnotationMutationConformance(runner, opts) {
|
|
|
2125
2670
|
} catch (err) {
|
|
2126
2671
|
caught = err;
|
|
2127
2672
|
}
|
|
2128
|
-
expect(
|
|
2673
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidReference)).toBe(true);
|
|
2129
2674
|
} finally {
|
|
2130
2675
|
await doc.close();
|
|
2131
2676
|
}
|
|
@@ -2271,7 +2816,7 @@ function runAnnotationMutationConformance(runner, opts) {
|
|
|
2271
2816
|
} finally {
|
|
2272
2817
|
await weakSession?.release();
|
|
2273
2818
|
}
|
|
2274
|
-
expect(
|
|
2819
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidReference)).toBe(true);
|
|
2275
2820
|
} finally {
|
|
2276
2821
|
await doc.close();
|
|
2277
2822
|
}
|
|
@@ -2295,7 +2840,7 @@ function runAnnotationMutationConformance(runner, opts) {
|
|
|
2295
2840
|
} finally {
|
|
2296
2841
|
await weakSession?.release();
|
|
2297
2842
|
}
|
|
2298
|
-
expect(
|
|
2843
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
2299
2844
|
} finally {
|
|
2300
2845
|
await doc.close();
|
|
2301
2846
|
}
|
|
@@ -2318,7 +2863,7 @@ function runAnnotationMutationConformance(runner, opts) {
|
|
|
2318
2863
|
} finally {
|
|
2319
2864
|
await weakSession?.release();
|
|
2320
2865
|
}
|
|
2321
|
-
expect(
|
|
2866
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
2322
2867
|
} finally {
|
|
2323
2868
|
await doc.close();
|
|
2324
2869
|
}
|
|
@@ -2734,7 +3279,7 @@ function runAnnotationMutationConformance(runner, opts) {
|
|
|
2734
3279
|
} catch (err) {
|
|
2735
3280
|
caught = err;
|
|
2736
3281
|
}
|
|
2737
|
-
expect(
|
|
3282
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
2738
3283
|
} finally {
|
|
2739
3284
|
await doc.close();
|
|
2740
3285
|
}
|
|
@@ -2787,7 +3332,7 @@ function runAnnotationMutationConformance(runner, opts) {
|
|
|
2787
3332
|
} catch (err) {
|
|
2788
3333
|
caught = err;
|
|
2789
3334
|
}
|
|
2790
|
-
expect(
|
|
3335
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
2791
3336
|
} finally {
|
|
2792
3337
|
await doc.close();
|
|
2793
3338
|
}
|
|
@@ -3034,7 +3579,7 @@ function runFormConformance(runner, opts) {
|
|
|
3034
3579
|
await expect(doc.forms.setValue(radioRef, {
|
|
3035
3580
|
type: "toggle",
|
|
3036
3581
|
state: null
|
|
3037
|
-
})).rejects.toMatchObject({ code:
|
|
3582
|
+
})).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
3038
3583
|
const check = await doc.forms.setValue({
|
|
3039
3584
|
kind: "fqn",
|
|
3040
3585
|
name: "opt_check"
|
|
@@ -3062,7 +3607,7 @@ function runFormConformance(runner, opts) {
|
|
|
3062
3607
|
}, {
|
|
3063
3608
|
type: "toggle",
|
|
3064
3609
|
state: "On"
|
|
3065
|
-
})).rejects.toMatchObject({ code:
|
|
3610
|
+
})).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
3066
3611
|
const field = await doc.forms.get({
|
|
3067
3612
|
kind: "fqn",
|
|
3068
3613
|
name: "maxlen_text"
|
|
@@ -3166,7 +3711,7 @@ function runFormConformance(runner, opts) {
|
|
|
3166
3711
|
}, {
|
|
3167
3712
|
type: "choice",
|
|
3168
3713
|
values: ["foo", "bar"]
|
|
3169
|
-
})).rejects.toMatchObject({ code:
|
|
3714
|
+
})).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
3170
3715
|
} finally {
|
|
3171
3716
|
await doc.close();
|
|
3172
3717
|
}
|
|
@@ -3236,7 +3781,7 @@ function runFormConformance(runner, opts) {
|
|
|
3236
3781
|
test("rejects garbage import payloads", async () => {
|
|
3237
3782
|
const doc = await open(opts.fixtures.toggleFields);
|
|
3238
3783
|
try {
|
|
3239
|
-
await expect(doc.forms.importData(new TextEncoder().encode("not a form payload"))).rejects.toMatchObject({ code:
|
|
3784
|
+
await expect(doc.forms.importData(new TextEncoder().encode("not a form payload"))).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
3240
3785
|
} finally {
|
|
3241
3786
|
await doc.close();
|
|
3242
3787
|
}
|
|
@@ -3343,7 +3888,7 @@ function runFormConformance(runner, opts) {
|
|
|
3343
3888
|
g: 247,
|
|
3344
3889
|
b: 219
|
|
3345
3890
|
});
|
|
3346
|
-
await expect(page.annotations.delete(widgetRef)).rejects.toMatchObject({ code:
|
|
3891
|
+
await expect(page.annotations.delete(widgetRef)).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
3347
3892
|
await doc.forms.detachWidget(field.field.ref, {
|
|
3348
3893
|
annotObjectNumber: widgetRef.annotObjectNumber,
|
|
3349
3894
|
pageObjectNumber: pon
|
|
@@ -3407,7 +3952,7 @@ function runFormConformance(runner, opts) {
|
|
|
3407
3952
|
await expect(doc.forms.updateField(created.field.ref, {
|
|
3408
3953
|
family: "radio",
|
|
3409
3954
|
name: "unison_radio"
|
|
3410
|
-
})).rejects.toMatchObject({ code:
|
|
3955
|
+
})).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
3411
3956
|
const before = await doc.page(pon).annotations.list();
|
|
3412
3957
|
const removed = await doc.forms.deleteField(created.field.ref);
|
|
3413
3958
|
expect(removed.removedWidgets.length).toBe(2);
|
|
@@ -3416,7 +3961,7 @@ function runFormConformance(runner, opts) {
|
|
|
3416
3961
|
await expect(doc.forms.get({
|
|
3417
3962
|
kind: "fqn",
|
|
3418
3963
|
name: "renamed_radio"
|
|
3419
|
-
})).rejects.toMatchObject({ code:
|
|
3964
|
+
})).rejects.toMatchObject({ code: require_format.EngineErrorCode.NotFound });
|
|
3420
3965
|
} finally {
|
|
3421
3966
|
await doc.close();
|
|
3422
3967
|
}
|
|
@@ -3427,7 +3972,7 @@ function runFormConformance(runner, opts) {
|
|
|
3427
3972
|
await expect(doc.forms.get({
|
|
3428
3973
|
kind: "fqn",
|
|
3429
3974
|
name: "no.such.field"
|
|
3430
|
-
})).rejects.toMatchObject({ code:
|
|
3975
|
+
})).rejects.toMatchObject({ code: require_format.EngineErrorCode.NotFound });
|
|
3431
3976
|
} finally {
|
|
3432
3977
|
await doc.close();
|
|
3433
3978
|
}
|
|
@@ -3720,7 +4265,7 @@ function runPageReorderConformance(runner, opts) {
|
|
|
3720
4265
|
} catch (err) {
|
|
3721
4266
|
caught = err;
|
|
3722
4267
|
}
|
|
3723
|
-
expect(
|
|
4268
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
3724
4269
|
} finally {
|
|
3725
4270
|
await doc.close();
|
|
3726
4271
|
}
|
|
@@ -3737,7 +4282,7 @@ function runPageReorderConformance(runner, opts) {
|
|
|
3737
4282
|
} catch (err) {
|
|
3738
4283
|
caught = err;
|
|
3739
4284
|
}
|
|
3740
|
-
expect(
|
|
4285
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
3741
4286
|
} finally {
|
|
3742
4287
|
await doc.close();
|
|
3743
4288
|
}
|
|
@@ -3755,7 +4300,7 @@ function runPageReorderConformance(runner, opts) {
|
|
|
3755
4300
|
} catch (err) {
|
|
3756
4301
|
caught = err;
|
|
3757
4302
|
}
|
|
3758
|
-
expect(
|
|
4303
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.NotFound) || require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
3759
4304
|
} finally {
|
|
3760
4305
|
await doc.close();
|
|
3761
4306
|
}
|
|
@@ -3930,7 +4475,7 @@ function runPageRotateConformance(runner, opts) {
|
|
|
3930
4475
|
} catch (err) {
|
|
3931
4476
|
caught = err;
|
|
3932
4477
|
}
|
|
3933
|
-
expect(
|
|
4478
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
3934
4479
|
} finally {
|
|
3935
4480
|
await doc.close();
|
|
3936
4481
|
}
|
|
@@ -3945,7 +4490,7 @@ function runPageRotateConformance(runner, opts) {
|
|
|
3945
4490
|
} catch (err) {
|
|
3946
4491
|
caught = err;
|
|
3947
4492
|
}
|
|
3948
|
-
expect(
|
|
4493
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
3949
4494
|
} finally {
|
|
3950
4495
|
await doc.close();
|
|
3951
4496
|
}
|
|
@@ -3963,7 +4508,7 @@ function runPageRotateConformance(runner, opts) {
|
|
|
3963
4508
|
} catch (err) {
|
|
3964
4509
|
caught = err;
|
|
3965
4510
|
}
|
|
3966
|
-
expect(
|
|
4511
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.NotFound) || require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
3967
4512
|
} finally {
|
|
3968
4513
|
await doc.close();
|
|
3969
4514
|
}
|
|
@@ -4077,7 +4622,7 @@ function runPageDeleteConformance(runner, opts) {
|
|
|
4077
4622
|
} catch (err) {
|
|
4078
4623
|
caught = err;
|
|
4079
4624
|
}
|
|
4080
|
-
expect(
|
|
4625
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.NotFound)).toBe(true);
|
|
4081
4626
|
} finally {
|
|
4082
4627
|
await doc.close();
|
|
4083
4628
|
}
|
|
@@ -4125,7 +4670,7 @@ function runPageDeleteConformance(runner, opts) {
|
|
|
4125
4670
|
} catch (err) {
|
|
4126
4671
|
caught = err;
|
|
4127
4672
|
}
|
|
4128
|
-
expect(
|
|
4673
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
4129
4674
|
} finally {
|
|
4130
4675
|
await doc.close();
|
|
4131
4676
|
}
|
|
@@ -4140,7 +4685,7 @@ function runPageDeleteConformance(runner, opts) {
|
|
|
4140
4685
|
} catch (err) {
|
|
4141
4686
|
caught = err;
|
|
4142
4687
|
}
|
|
4143
|
-
expect(
|
|
4688
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
4144
4689
|
} finally {
|
|
4145
4690
|
await doc.close();
|
|
4146
4691
|
}
|
|
@@ -4158,7 +4703,7 @@ function runPageDeleteConformance(runner, opts) {
|
|
|
4158
4703
|
} catch (err) {
|
|
4159
4704
|
caught = err;
|
|
4160
4705
|
}
|
|
4161
|
-
expect(
|
|
4706
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.NotFound) || require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
4162
4707
|
} finally {
|
|
4163
4708
|
await doc.close();
|
|
4164
4709
|
}
|
|
@@ -4317,7 +4862,7 @@ function runNamedPagesConformance(runner, opts) {
|
|
|
4317
4862
|
require_schemas.PageNameResultSchema.parse(removed);
|
|
4318
4863
|
expect(find(removed, "Draft=Concept")).toBe(void 0);
|
|
4319
4864
|
expect(removed.layout.pages.length).toBe(before.pages.length);
|
|
4320
|
-
await expect(doc.pages.removeName({ name: "Draft=Concept" })).rejects.toMatchObject({ code:
|
|
4865
|
+
await expect(doc.pages.removeName({ name: "Draft=Concept" })).rejects.toMatchObject({ code: require_format.EngineErrorCode.NotFound });
|
|
4321
4866
|
} finally {
|
|
4322
4867
|
await doc.close();
|
|
4323
4868
|
}
|
|
@@ -4330,7 +4875,7 @@ function runNamedPagesConformance(runner, opts) {
|
|
|
4330
4875
|
await expect(doc.pages.setName({
|
|
4331
4876
|
name: "",
|
|
4332
4877
|
pageObjectNumber: before.pages[0].pageObjectNumber
|
|
4333
|
-
})).rejects.toMatchObject({ code:
|
|
4878
|
+
})).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
4334
4879
|
let unknownPage = null;
|
|
4335
4880
|
try {
|
|
4336
4881
|
await doc.pages.setName({
|
|
@@ -4340,7 +4885,7 @@ function runNamedPagesConformance(runner, opts) {
|
|
|
4340
4885
|
} catch (error) {
|
|
4341
4886
|
unknownPage = error;
|
|
4342
4887
|
}
|
|
4343
|
-
expect(
|
|
4888
|
+
expect(require_derive.EngineError.is(unknownPage, require_format.EngineErrorCode.NotFound) || require_derive.EngineError.is(unknownPage, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
4344
4889
|
} finally {
|
|
4345
4890
|
await doc.close();
|
|
4346
4891
|
}
|
|
@@ -4496,7 +5041,7 @@ function runAnnotationFlattenConformance(runner, opts) {
|
|
|
4496
5041
|
const own = (await page0.annotations.create(square$1(20, 100))).created.ref;
|
|
4497
5042
|
const foreign = (await page1.annotations.create(square$1(20, 100))).created.ref;
|
|
4498
5043
|
const countBefore = (await page0.annotations.list()).annotations.length;
|
|
4499
|
-
await expect(page0.annotations.flatten([own, foreign])).rejects.toMatchObject({ code:
|
|
5044
|
+
await expect(page0.annotations.flatten([own, foreign])).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
4500
5045
|
expect((await page0.annotations.list()).annotations.length).toBe(countBefore);
|
|
4501
5046
|
} finally {
|
|
4502
5047
|
await doc.close();
|
|
@@ -4508,7 +5053,7 @@ function runAnnotationFlattenConformance(runner, opts) {
|
|
|
4508
5053
|
const pon = (await doc.pages.list()).pages[0].pageObjectNumber;
|
|
4509
5054
|
const page = doc.page(pon);
|
|
4510
5055
|
if (!page.annotations.flatten) return;
|
|
4511
|
-
await expect(page.annotations.flatten([])).rejects.toMatchObject({ code:
|
|
5056
|
+
await expect(page.annotations.flatten([])).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
4512
5057
|
let unknown = null;
|
|
4513
5058
|
try {
|
|
4514
5059
|
await page.annotations.flatten([{
|
|
@@ -4519,7 +5064,7 @@ function runAnnotationFlattenConformance(runner, opts) {
|
|
|
4519
5064
|
} catch (error) {
|
|
4520
5065
|
unknown = error;
|
|
4521
5066
|
}
|
|
4522
|
-
expect(
|
|
5067
|
+
expect(require_derive.EngineError.is(unknown, require_format.EngineErrorCode.NotFound) || require_derive.EngineError.is(unknown, require_format.EngineErrorCode.InvalidArg) || require_derive.EngineError.is(unknown, require_format.EngineErrorCode.InvalidReference)).toBe(true);
|
|
4523
5068
|
} finally {
|
|
4524
5069
|
await doc.close();
|
|
4525
5070
|
}
|
|
@@ -4623,12 +5168,12 @@ function runAnnotationAppearanceExportConformance(runner, opts) {
|
|
|
4623
5168
|
const layout = await doc.pages.list();
|
|
4624
5169
|
const page0 = doc.page(layout.pages[0].pageObjectNumber);
|
|
4625
5170
|
if (!page0.annotations.exportAppearance) return;
|
|
4626
|
-
await expect(page0.annotations.exportAppearance([])).rejects.toMatchObject({ code:
|
|
5171
|
+
await expect(page0.annotations.exportAppearance([])).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
4627
5172
|
if (layout.pages.length < 2) return;
|
|
4628
5173
|
const page1 = doc.page(layout.pages[1].pageObjectNumber);
|
|
4629
5174
|
const own = (await page0.annotations.create(square(20, 100))).created.ref;
|
|
4630
5175
|
const foreign = (await page1.annotations.create(square(20, 100))).created.ref;
|
|
4631
|
-
await expect(page0.annotations.exportAppearance([own, foreign])).rejects.toMatchObject({ code:
|
|
5176
|
+
await expect(page0.annotations.exportAppearance([own, foreign])).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
4632
5177
|
} finally {
|
|
4633
5178
|
await doc.close();
|
|
4634
5179
|
}
|
|
@@ -4687,7 +5232,7 @@ function runPageFlattenConformance(runner, opts) {
|
|
|
4687
5232
|
expect(noOp.meta).toBeNull();
|
|
4688
5233
|
expect(events).toHaveLength(1);
|
|
4689
5234
|
unsubscribe();
|
|
4690
|
-
await expect(doc.pages.flatten([pageObjectNumber, pageObjectNumber])).rejects.toMatchObject({ code:
|
|
5235
|
+
await expect(doc.pages.flatten([pageObjectNumber, pageObjectNumber])).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
4691
5236
|
} finally {
|
|
4692
5237
|
await doc.close();
|
|
4693
5238
|
}
|
|
@@ -4839,7 +5384,7 @@ function runRedactionApplyConformance(runner, opts) {
|
|
|
4839
5384
|
await expect(doc.redaction.apply({
|
|
4840
5385
|
kind: "pages",
|
|
4841
5386
|
pageObjectNumbers: [pageObjectNumber, pageObjectNumber]
|
|
4842
|
-
})).rejects.toMatchObject({ code:
|
|
5387
|
+
})).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
4843
5388
|
const notRedact = await page.annotations.create({
|
|
4844
5389
|
subtype: "highlight",
|
|
4845
5390
|
quadPoints: COLLATERAL_QUAD
|
|
@@ -4847,7 +5392,7 @@ function runRedactionApplyConformance(runner, opts) {
|
|
|
4847
5392
|
await expect(doc.redaction.apply({
|
|
4848
5393
|
kind: "annotations",
|
|
4849
5394
|
refs: [notRedact.created.ref]
|
|
4850
|
-
})).rejects.toMatchObject({ code:
|
|
5395
|
+
})).rejects.toMatchObject({ code: require_format.EngineErrorCode.InvalidArg });
|
|
4851
5396
|
} finally {
|
|
4852
5397
|
await doc.close();
|
|
4853
5398
|
}
|
|
@@ -4948,7 +5493,7 @@ function runPageExtractConformance(runner, opts) {
|
|
|
4948
5493
|
} catch (err) {
|
|
4949
5494
|
caught = err;
|
|
4950
5495
|
}
|
|
4951
|
-
expect(
|
|
5496
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
4952
5497
|
} finally {
|
|
4953
5498
|
await doc.close();
|
|
4954
5499
|
}
|
|
@@ -4963,7 +5508,7 @@ function runPageExtractConformance(runner, opts) {
|
|
|
4963
5508
|
} catch (err) {
|
|
4964
5509
|
caught = err;
|
|
4965
5510
|
}
|
|
4966
|
-
expect(
|
|
5511
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
4967
5512
|
} finally {
|
|
4968
5513
|
await doc.close();
|
|
4969
5514
|
}
|
|
@@ -4981,7 +5526,7 @@ function runPageExtractConformance(runner, opts) {
|
|
|
4981
5526
|
} catch (err) {
|
|
4982
5527
|
caught = err;
|
|
4983
5528
|
}
|
|
4984
|
-
expect(
|
|
5529
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.NotFound) || require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
4985
5530
|
} finally {
|
|
4986
5531
|
await doc.close();
|
|
4987
5532
|
}
|
|
@@ -5095,7 +5640,7 @@ function runAttachmentConformance(runner, opts) {
|
|
|
5095
5640
|
await expect(doc.attachments.download({
|
|
5096
5641
|
kind: "key",
|
|
5097
5642
|
key: "conformance-no-such-key.bin"
|
|
5098
|
-
})).rejects.toBeInstanceOf(
|
|
5643
|
+
})).rejects.toBeInstanceOf(require_derive.EngineError);
|
|
5099
5644
|
} finally {
|
|
5100
5645
|
await doc.close();
|
|
5101
5646
|
}
|
|
@@ -5131,7 +5676,7 @@ function runAttachmentConformance(runner, opts) {
|
|
|
5131
5676
|
await expect(doc.attachments.create({
|
|
5132
5677
|
data,
|
|
5133
5678
|
name: "0-conformance.bin"
|
|
5134
|
-
})).rejects.toBeInstanceOf(
|
|
5679
|
+
})).rejects.toBeInstanceOf(require_derive.EngineError);
|
|
5135
5680
|
const content = await doc.attachments.download({
|
|
5136
5681
|
kind: "key",
|
|
5137
5682
|
key: created.key
|
|
@@ -5151,7 +5696,7 @@ function runAttachmentConformance(runner, opts) {
|
|
|
5151
5696
|
await expect(doc.attachments.delete({
|
|
5152
5697
|
kind: "key",
|
|
5153
5698
|
key: created.key
|
|
5154
|
-
})).rejects.toBeInstanceOf(
|
|
5699
|
+
})).rejects.toBeInstanceOf(require_derive.EngineError);
|
|
5155
5700
|
} finally {
|
|
5156
5701
|
await doc.close();
|
|
5157
5702
|
}
|
|
@@ -5350,14 +5895,14 @@ function runPageInsertConformance(runner, opts) {
|
|
|
5350
5895
|
} catch (err) {
|
|
5351
5896
|
caught = err;
|
|
5352
5897
|
}
|
|
5353
|
-
expect(
|
|
5898
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
5354
5899
|
caught = void 0;
|
|
5355
5900
|
try {
|
|
5356
5901
|
await doc.pages.insert(new TextEncoder().encode("not a pdf at all"));
|
|
5357
5902
|
} catch (err) {
|
|
5358
5903
|
caught = err;
|
|
5359
5904
|
}
|
|
5360
|
-
expect(
|
|
5905
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.MalformedPdf)).toBe(true);
|
|
5361
5906
|
const list = await doc.pages.list();
|
|
5362
5907
|
expect(list.pageCount > 0).toBe(true);
|
|
5363
5908
|
} finally {
|
|
@@ -5375,7 +5920,7 @@ function runPageInsertConformance(runner, opts) {
|
|
|
5375
5920
|
} catch (err) {
|
|
5376
5921
|
caught = err;
|
|
5377
5922
|
}
|
|
5378
|
-
expect(
|
|
5923
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
5379
5924
|
} finally {
|
|
5380
5925
|
await doc.close();
|
|
5381
5926
|
}
|
|
@@ -5524,7 +6069,7 @@ function runPageInsertBlankConformance(runner, opts) {
|
|
|
5524
6069
|
} catch (err) {
|
|
5525
6070
|
caught = err;
|
|
5526
6071
|
}
|
|
5527
|
-
expect(
|
|
6072
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
5528
6073
|
}
|
|
5529
6074
|
const list = await doc.pages.list();
|
|
5530
6075
|
expect(list.pageCount).toBe(before.pageCount);
|
|
@@ -5957,7 +6502,7 @@ function runPageTextConformance(runner, opts) {
|
|
|
5957
6502
|
caught = err;
|
|
5958
6503
|
}
|
|
5959
6504
|
expect(caught).toBeTruthy();
|
|
5960
|
-
expect(
|
|
6505
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.NotFound)).toBe(true);
|
|
5961
6506
|
} finally {
|
|
5962
6507
|
await doc.close();
|
|
5963
6508
|
}
|
|
@@ -5983,7 +6528,7 @@ function runPageTextConformance(runner, opts) {
|
|
|
5983
6528
|
caught = err;
|
|
5984
6529
|
}
|
|
5985
6530
|
expect(caught).toBeTruthy();
|
|
5986
|
-
expect(
|
|
6531
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.DocNotOpen)).toBe(true);
|
|
5987
6532
|
});
|
|
5988
6533
|
});
|
|
5989
6534
|
}
|
|
@@ -6032,8 +6577,8 @@ function runTextDivergenceConformance(runner, opts) {
|
|
|
6032
6577
|
const doc = await openFixture$2(engine, opts);
|
|
6033
6578
|
try {
|
|
6034
6579
|
const snap = await doc.page(fixture.pageObjectNumber).text.read();
|
|
6035
|
-
expect(
|
|
6036
|
-
for (const s of fixture.slices ?? []) expect(
|
|
6580
|
+
expect(require_format.sliceTextByChars(snap, 0, snap.charCount)).toBe(snap.text);
|
|
6581
|
+
for (const s of fixture.slices ?? []) expect(require_format.sliceTextByChars(snap, s.from, s.to)).toBe(s.text);
|
|
6037
6582
|
} finally {
|
|
6038
6583
|
await doc.close();
|
|
6039
6584
|
}
|
|
@@ -6052,7 +6597,7 @@ function runTextDivergenceConformance(runner, opts) {
|
|
|
6052
6597
|
expect(hit.charCount).toBe(probe.charCount);
|
|
6053
6598
|
expect(hit.segments.length > 0).toBe(true);
|
|
6054
6599
|
const snap = await doc.page(fixture.pageObjectNumber).text.read();
|
|
6055
|
-
expect(
|
|
6600
|
+
expect(require_format.sliceTextByChars(snap, hit.charStart, hit.charStart + hit.charCount)).toBe(probe.matchedText);
|
|
6056
6601
|
} finally {
|
|
6057
6602
|
await doc.close();
|
|
6058
6603
|
}
|
|
@@ -6217,8 +6762,8 @@ function runPageGeometryOrientationConformance(runner, opts) {
|
|
|
6217
6762
|
const expectation = opts.fixture.expectation;
|
|
6218
6763
|
if (expectation.kind === "upright") {
|
|
6219
6764
|
for (const run of snapshot.runs) {
|
|
6220
|
-
expect(
|
|
6221
|
-
if (
|
|
6765
|
+
expect(require_derive.isRotatedGeometryRun(run)).toBe(false);
|
|
6766
|
+
if (require_derive.isRotatedGeometryRun(run)) continue;
|
|
6222
6767
|
for (const glyph of run.glyphs) {
|
|
6223
6768
|
expect("looseQuad" in glyph).toBe(false);
|
|
6224
6769
|
if (glyph.flags & FLAG_EMPTY) expect(glyph.looseBox).toEqual({
|
|
@@ -6233,8 +6778,8 @@ function runPageGeometryOrientationConformance(runner, opts) {
|
|
|
6233
6778
|
}
|
|
6234
6779
|
if (expectation.kind === "empty-only") {
|
|
6235
6780
|
for (const run of snapshot.runs) {
|
|
6236
|
-
expect(
|
|
6237
|
-
if (
|
|
6781
|
+
expect(require_derive.isRotatedGeometryRun(run)).toBe(false);
|
|
6782
|
+
if (require_derive.isRotatedGeometryRun(run)) continue;
|
|
6238
6783
|
for (const glyph of run.glyphs) {
|
|
6239
6784
|
expect(glyph.flags & FLAG_EMPTY).toBe(FLAG_EMPTY);
|
|
6240
6785
|
expect(glyph.looseBox).toEqual({
|
|
@@ -6247,7 +6792,7 @@ function runPageGeometryOrientationConformance(runner, opts) {
|
|
|
6247
6792
|
}
|
|
6248
6793
|
return;
|
|
6249
6794
|
}
|
|
6250
|
-
const rotatedRuns = snapshot.runs.filter(
|
|
6795
|
+
const rotatedRuns = snapshot.runs.filter(require_derive.isRotatedGeometryRun);
|
|
6251
6796
|
expect(rotatedRuns.length >= (expectation.minRotatedRuns ?? 1)).toBe(true);
|
|
6252
6797
|
for (const run of rotatedRuns) {
|
|
6253
6798
|
expect(expectation.rotations.some((angle) => angleClose(run.rotation, angle, ANGLE_TOLERANCE))).toBe(true);
|
|
@@ -6288,7 +6833,7 @@ function runPageGeometryOrientationConformance(runner, opts) {
|
|
|
6288
6833
|
const q = glyph.looseQuad;
|
|
6289
6834
|
expect(Math.abs(q.p2.x - q.p1.x - (q.p4.x - q.p3.x)) <= COORD_TOLERANCE).toBe(true);
|
|
6290
6835
|
expect(Math.abs(q.p2.y - q.p1.y - (q.p4.y - q.p3.y)) <= COORD_TOLERANCE).toBe(true);
|
|
6291
|
-
const bounds =
|
|
6836
|
+
const bounds = require_derive.pdfQuadBounds(q);
|
|
6292
6837
|
expect(bounds.left >= run.rect.left - COORD_TOLERANCE).toBe(true);
|
|
6293
6838
|
expect(bounds.right <= run.rect.right + COORD_TOLERANCE).toBe(true);
|
|
6294
6839
|
expect(bounds.bottom >= run.rect.bottom - COORD_TOLERANCE).toBe(true);
|
|
@@ -6405,7 +6950,7 @@ function runSearchConformance(runner, opts) {
|
|
|
6405
6950
|
expect(!!m.snippet).toBe(true);
|
|
6406
6951
|
const s = m.snippet;
|
|
6407
6952
|
const hit = s.text.slice(s.matchStart, s.matchStart + s.matchLength);
|
|
6408
|
-
expect(
|
|
6953
|
+
expect(require_derive.foldText(hit).folded).toBe(require_derive.foldText(fixture.presentLiteral).folded);
|
|
6409
6954
|
}
|
|
6410
6955
|
const rects = await collectAll(doc, {
|
|
6411
6956
|
query: { text: fixture.presentLiteral },
|
|
@@ -6476,7 +7021,7 @@ function runSearchConformance(runner, opts) {
|
|
|
6476
7021
|
} catch (err) {
|
|
6477
7022
|
caught = err;
|
|
6478
7023
|
}
|
|
6479
|
-
expect(
|
|
7024
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
6480
7025
|
} finally {
|
|
6481
7026
|
await doc.close();
|
|
6482
7027
|
}
|
|
@@ -6493,7 +7038,7 @@ function runSearchConformance(runner, opts) {
|
|
|
6493
7038
|
} catch (err) {
|
|
6494
7039
|
caught = err;
|
|
6495
7040
|
}
|
|
6496
|
-
expect(
|
|
7041
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
6497
7042
|
} finally {
|
|
6498
7043
|
await doc.close();
|
|
6499
7044
|
}
|
|
@@ -6536,20 +7081,42 @@ function runSearchConformance(runner, opts) {
|
|
|
6536
7081
|
await doc.close();
|
|
6537
7082
|
}
|
|
6538
7083
|
});
|
|
6539
|
-
test("
|
|
7084
|
+
test("ignoreWhitespace keeps every default hit and finds the space-free needle", async () => {
|
|
6540
7085
|
const doc = await openFixture(engine, opts);
|
|
6541
7086
|
try {
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
7087
|
+
const key = (m) => `${m.pageObjectNumber}:${m.charStart}:${m.charCount}`;
|
|
7088
|
+
const plain = await collectAll(doc, { query: { text: fixture.presentLiteral } });
|
|
7089
|
+
const relaxed = await collectAll(doc, { query: {
|
|
7090
|
+
text: fixture.presentLiteral,
|
|
7091
|
+
ignoreWhitespace: true
|
|
7092
|
+
} });
|
|
7093
|
+
const relaxedKeys = new Set(relaxed.matches.map(key));
|
|
7094
|
+
for (const m of plain.matches) expect(relaxedKeys.has(key(m))).toBe(true);
|
|
7095
|
+
const squashed = await collectAll(doc, { query: {
|
|
7096
|
+
text: fixture.presentLiteral.replace(/\s+/g, ""),
|
|
7097
|
+
ignoreWhitespace: true
|
|
7098
|
+
} });
|
|
7099
|
+
expect(squashed.matches.map(key)).toEqual(relaxed.matches.map(key));
|
|
7100
|
+
} finally {
|
|
7101
|
+
await doc.close();
|
|
7102
|
+
}
|
|
7103
|
+
});
|
|
7104
|
+
test("regex + matchDiacritics / ignoreWhitespace are rejected with InvalidArg", async () => {
|
|
7105
|
+
const doc = await openFixture(engine, opts);
|
|
7106
|
+
try {
|
|
7107
|
+
for (const flags of [{ matchDiacritics: true }, { ignoreWhitespace: true }]) {
|
|
7108
|
+
let caught;
|
|
7109
|
+
try {
|
|
7110
|
+
await doc.search.query({ query: {
|
|
7111
|
+
text: fixture.presentRegex,
|
|
7112
|
+
regex: true,
|
|
7113
|
+
...flags
|
|
7114
|
+
} });
|
|
7115
|
+
} catch (err) {
|
|
7116
|
+
caught = err;
|
|
7117
|
+
}
|
|
7118
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
6551
7119
|
}
|
|
6552
|
-
expect(require_fold.EngineError.is(caught, require_PageInsertBlankInput.EngineErrorCode.InvalidArg)).toBe(true);
|
|
6553
7120
|
} finally {
|
|
6554
7121
|
await doc.close();
|
|
6555
7122
|
}
|
|
@@ -6571,7 +7138,7 @@ function runSearchConformance(runner, opts) {
|
|
|
6571
7138
|
} catch (err) {
|
|
6572
7139
|
caught = err;
|
|
6573
7140
|
}
|
|
6574
|
-
expect(
|
|
7141
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.InvalidArg)).toBe(true);
|
|
6575
7142
|
}
|
|
6576
7143
|
} finally {
|
|
6577
7144
|
await doc.close();
|
|
@@ -6606,7 +7173,7 @@ function runSearchConformance(runner, opts) {
|
|
|
6606
7173
|
} catch (err) {
|
|
6607
7174
|
caught = err;
|
|
6608
7175
|
}
|
|
6609
|
-
expect(
|
|
7176
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.DocNotOpen)).toBe(true);
|
|
6610
7177
|
});
|
|
6611
7178
|
});
|
|
6612
7179
|
}
|
|
@@ -6675,6 +7242,790 @@ function diffAnnotation(i, a, b, errs) {
|
|
|
6675
7242
|
if (a.nm !== b.nm) errs.push(`annotations[${i}].nm mismatch: ${a.nm} vs ${b.nm}`);
|
|
6676
7243
|
}
|
|
6677
7244
|
//#endregion
|
|
7245
|
+
//#region src/conformance/runSignatureConformance.ts
|
|
7246
|
+
/**
|
|
7247
|
+
* Digital signatures, read side. The service is OPTIONAL on the contract
|
|
7248
|
+
* (`downloadLayer?` pattern) — the suite runs only where the engine
|
|
7249
|
+
* provides it.
|
|
7250
|
+
*
|
|
7251
|
+
* Invariants:
|
|
7252
|
+
* 1. Byte facts describe the LOADED bytes: a revision is a byte prefix,
|
|
7253
|
+
* a whole-revision signature seals exactly one, the digest over its
|
|
7254
|
+
* `/ByteRange` is what the file's bytes hash to, and an unsaved edit
|
|
7255
|
+
* changes none of it.
|
|
7256
|
+
* 2. Protection is derived from the signatures in the file and applied
|
|
7257
|
+
* as document-derived capabilities: a certification with permission 2
|
|
7258
|
+
* takes page assembly and annotation writes away, a FieldMDP freezes
|
|
7259
|
+
* the fields it names, a rewrite save is refused. Under
|
|
7260
|
+
* `signedDocumentPolicy: 'permit'` none of that applies and the
|
|
7261
|
+
* analysis is unchanged.
|
|
7262
|
+
* 3. The same answers come from a plain session and from a layer
|
|
7263
|
+
* session over the same bytes.
|
|
7264
|
+
*/
|
|
7265
|
+
function runSignatureConformance(runner, opts) {
|
|
7266
|
+
const { describe, test, beforeAll, afterAll, expect } = runner;
|
|
7267
|
+
describe(`signatures conformance: ${opts.label}`, () => {
|
|
7268
|
+
let engine;
|
|
7269
|
+
let permitEngine = null;
|
|
7270
|
+
let supported = false;
|
|
7271
|
+
beforeAll(async () => {
|
|
7272
|
+
engine = await opts.makeEngine();
|
|
7273
|
+
const probe = await open(engine, opts, opts.fixtures.unsignedForm);
|
|
7274
|
+
supported = probe.signatures !== void 0;
|
|
7275
|
+
await probe.close();
|
|
7276
|
+
if (supported && opts.makePermitEngine) permitEngine = await opts.makePermitEngine();
|
|
7277
|
+
});
|
|
7278
|
+
afterAll(async () => {
|
|
7279
|
+
if (permitEngine) await permitEngine.destroy();
|
|
7280
|
+
if (engine) await engine.destroy();
|
|
7281
|
+
});
|
|
7282
|
+
test("an unsigned form has no signatures and no protection; version() hashes the loaded bytes", async () => {
|
|
7283
|
+
if (!supported) return;
|
|
7284
|
+
const bytes = await opts.fixtures.unsignedForm.bytes();
|
|
7285
|
+
const doc = await open(engine, opts, opts.fixtures.unsignedForm);
|
|
7286
|
+
try {
|
|
7287
|
+
const snapshot = await doc.signatures.list();
|
|
7288
|
+
expect(snapshot.chainValid).toBe(true);
|
|
7289
|
+
expect(snapshot.signatures).toEqual([]);
|
|
7290
|
+
expect(snapshot.revisions.length >= 1).toBe(true);
|
|
7291
|
+
expect(snapshot.protection.judged).toBeNull();
|
|
7292
|
+
expect(snapshot.protection.enforced).toBeNull();
|
|
7293
|
+
expect(snapshot.protection.certification).toBeNull();
|
|
7294
|
+
expect(snapshot.protection.fieldLocks).toEqual([]);
|
|
7295
|
+
expect(doc.security.allows("doc.pages.assemble")).toBe(true);
|
|
7296
|
+
if (doc.version) {
|
|
7297
|
+
const version = await doc.version();
|
|
7298
|
+
expect(version.byteLength).toBe(bytes.byteLength);
|
|
7299
|
+
expect(version.sha256).toBe(await sha256Hex(bytes));
|
|
7300
|
+
}
|
|
7301
|
+
let caught;
|
|
7302
|
+
try {
|
|
7303
|
+
await doc.signatures.contents({
|
|
7304
|
+
kind: "fqn",
|
|
7305
|
+
name: "no-such-field"
|
|
7306
|
+
});
|
|
7307
|
+
} catch (err) {
|
|
7308
|
+
caught = err;
|
|
7309
|
+
}
|
|
7310
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.NotFound)).toBe(true);
|
|
7311
|
+
} finally {
|
|
7312
|
+
await doc.close();
|
|
7313
|
+
}
|
|
7314
|
+
});
|
|
7315
|
+
test("two approval signatures: revisions, coverage, digests, contents, revision bytes", async () => {
|
|
7316
|
+
if (!supported) return;
|
|
7317
|
+
const fixture = opts.fixtures.twoApprovals;
|
|
7318
|
+
const bytes = await fixture.bytes();
|
|
7319
|
+
const doc = await open(engine, opts, fixture);
|
|
7320
|
+
try {
|
|
7321
|
+
const snapshot = await doc.signatures.list();
|
|
7322
|
+
expect(snapshot.chainValid).toBe(true);
|
|
7323
|
+
expect(snapshot.revisions).toHaveLength(3);
|
|
7324
|
+
expect(snapshot.signatures).toHaveLength(2);
|
|
7325
|
+
expect(snapshot.revisions[2].end).toBe(bytes.byteLength);
|
|
7326
|
+
for (const [i, sig] of snapshot.signatures.entries()) {
|
|
7327
|
+
expect(sig.index).toBe(i);
|
|
7328
|
+
expect(sig.signed).toBe(true);
|
|
7329
|
+
expect(sig.kind).toBe("signature");
|
|
7330
|
+
expect(sig.field.kind).toBe("objectNumber");
|
|
7331
|
+
expect(sig.fieldName).toBe(fixture.fieldNames[i]);
|
|
7332
|
+
expect(sig.coverage).toBe("whole-revision");
|
|
7333
|
+
expect(sig.revisionIndex).toBe(i + 1);
|
|
7334
|
+
expect(snapshot.revisions[i + 1].signatureIndex).toBe(i);
|
|
7335
|
+
expect(sig.subFilter).toBe("ETSI.CAdES.detached");
|
|
7336
|
+
expect(typeof sig.signer.claimedTime).toBe("string");
|
|
7337
|
+
expect(sig.docMdp).toBeNull();
|
|
7338
|
+
expect(sig.catalogCertification).toBe(false);
|
|
7339
|
+
expect(sig.contentsSize > 0).toBe(true);
|
|
7340
|
+
expect(sig.byteRange[0]).toBe(0);
|
|
7341
|
+
expect(sig.byteRange[2] + sig.byteRange[3]).toBe(snapshot.revisions[i + 1].end);
|
|
7342
|
+
}
|
|
7343
|
+
expect(snapshot.protection.judged).toBe("annotate");
|
|
7344
|
+
expect(snapshot.protection.enforced).toBeNull();
|
|
7345
|
+
expect(snapshot.protection.certification).toBeNull();
|
|
7346
|
+
expect(snapshot.protection.fieldLocks).toEqual([]);
|
|
7347
|
+
const first = snapshot.signatures[0];
|
|
7348
|
+
const contents = await doc.signatures.contents(first.field);
|
|
7349
|
+
expect(contents.byteLength).toBe(first.contentsSize);
|
|
7350
|
+
expect(contents[0]).toBe(48);
|
|
7351
|
+
const [a, b, c, d] = first.byteRange;
|
|
7352
|
+
const sealed = await doc.signatures.revisionBytes(1);
|
|
7353
|
+
expect(sealed.byteLength).toBe(snapshot.revisions[1].end);
|
|
7354
|
+
expect(bytesEqual(sealed, bytes.subarray(0, sealed.byteLength))).toBe(true);
|
|
7355
|
+
const signedBytes = concat(sealed.subarray(a, a + b), sealed.subarray(c, c + d));
|
|
7356
|
+
const digest = await doc.signatures.digest(first.field, "sha256");
|
|
7357
|
+
expect(digest.byteLength).toBe(32);
|
|
7358
|
+
expect(toHex(digest)).toBe(await sha256Hex(signedBytes));
|
|
7359
|
+
expect((await doc.signatures.digest(first.field, "sha512")).byteLength).toBe(64);
|
|
7360
|
+
const byName = await doc.signatures.digest({
|
|
7361
|
+
kind: "fqn",
|
|
7362
|
+
name: first.fieldName
|
|
7363
|
+
}, "sha256");
|
|
7364
|
+
expect(toHex(byName)).toBe(toHex(digest));
|
|
7365
|
+
const text = (await doc.forms.list()).fields.find((f) => f.name === fixture.textField);
|
|
7366
|
+
expect(text).toBeTruthy();
|
|
7367
|
+
await doc.forms.setValue({
|
|
7368
|
+
kind: "objectNumber",
|
|
7369
|
+
fieldObjectNumber: text.fieldObjectNumber
|
|
7370
|
+
}, {
|
|
7371
|
+
type: "text",
|
|
7372
|
+
value: "unsaved"
|
|
7373
|
+
});
|
|
7374
|
+
const again = await doc.signatures.list();
|
|
7375
|
+
expect(again.revisions).toEqual(snapshot.revisions);
|
|
7376
|
+
expect(again.signatures.map((s) => [
|
|
7377
|
+
s.coverage,
|
|
7378
|
+
s.revisionIndex,
|
|
7379
|
+
s.byteRange
|
|
7380
|
+
])).toEqual(snapshot.signatures.map((s) => [
|
|
7381
|
+
s.coverage,
|
|
7382
|
+
s.revisionIndex,
|
|
7383
|
+
s.byteRange
|
|
7384
|
+
]));
|
|
7385
|
+
expect(toHex(await doc.signatures.digest(first.field, "sha256"))).toBe(toHex(digest));
|
|
7386
|
+
if (doc.version) expect((await doc.version()).sha256).toBe(await sha256Hex(bytes));
|
|
7387
|
+
} finally {
|
|
7388
|
+
await doc.close();
|
|
7389
|
+
}
|
|
7390
|
+
});
|
|
7391
|
+
test("a certification takes structural capabilities away; permit lifts it", async () => {
|
|
7392
|
+
if (!supported) return;
|
|
7393
|
+
const fixture = opts.fixtures.certified;
|
|
7394
|
+
const doc = await open(engine, opts, fixture);
|
|
7395
|
+
try {
|
|
7396
|
+
const snapshot = await doc.signatures.list();
|
|
7397
|
+
const signed = snapshot.signatures.filter((s) => s.signed);
|
|
7398
|
+
expect(signed).toHaveLength(1);
|
|
7399
|
+
const sig = signed[0];
|
|
7400
|
+
expect(sig.fieldName).toBe(fixture.fieldName);
|
|
7401
|
+
expect(sig.coverage).toBe("whole-revision");
|
|
7402
|
+
expect(sig.docMdp).toBe(2);
|
|
7403
|
+
expect(sig.catalogCertification).toBe(true);
|
|
7404
|
+
expect(snapshot.protection.judged).toBe("fill");
|
|
7405
|
+
expect(snapshot.protection.enforced).toBe("fill");
|
|
7406
|
+
expect(snapshot.protection.certification).toEqual({
|
|
7407
|
+
signatureIndex: sig.index,
|
|
7408
|
+
permission: 2
|
|
7409
|
+
});
|
|
7410
|
+
expect(doc.security.allows("doc.forms.read")).toBe(true);
|
|
7411
|
+
expect(doc.security.allows("doc.forms.fill")).toBe(true);
|
|
7412
|
+
expect(doc.security.allows("doc.annotate.modify")).toBe(false);
|
|
7413
|
+
expect(doc.security.allows("doc.pages.assemble")).toBe(false);
|
|
7414
|
+
expect(doc.security.allows("doc.redact")).toBe(false);
|
|
7415
|
+
const list = await doc.pages.list();
|
|
7416
|
+
let caught;
|
|
7417
|
+
try {
|
|
7418
|
+
await doc.pages.delete([list.pages[0].pageObjectNumber]);
|
|
7419
|
+
} catch (err) {
|
|
7420
|
+
caught = err;
|
|
7421
|
+
}
|
|
7422
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.ProtectedDocument)).toBe(true);
|
|
7423
|
+
caught = void 0;
|
|
7424
|
+
try {
|
|
7425
|
+
await doc.download({ mode: "rewrite" });
|
|
7426
|
+
} catch (err) {
|
|
7427
|
+
caught = err;
|
|
7428
|
+
}
|
|
7429
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.ProtectedDocument)).toBe(true);
|
|
7430
|
+
const saved = await doc.download();
|
|
7431
|
+
expect(saved.byteLength >= snapshot.revisions[1].end).toBe(true);
|
|
7432
|
+
} finally {
|
|
7433
|
+
await doc.close();
|
|
7434
|
+
}
|
|
7435
|
+
if (!permitEngine) return;
|
|
7436
|
+
const permitted = await open(permitEngine, opts, fixture);
|
|
7437
|
+
try {
|
|
7438
|
+
const snapshot = await permitted.signatures.list();
|
|
7439
|
+
expect(snapshot.protection.judged).toBe("fill");
|
|
7440
|
+
expect(snapshot.protection.enforced).toBe("fill");
|
|
7441
|
+
expect(permitted.security.allows("doc.pages.assemble")).toBe(true);
|
|
7442
|
+
const rewritten = await permitted.download({ mode: "rewrite" });
|
|
7443
|
+
expect(rewritten.byteLength > 0).toBe(true);
|
|
7444
|
+
} finally {
|
|
7445
|
+
await permitted.close();
|
|
7446
|
+
}
|
|
7447
|
+
});
|
|
7448
|
+
test("a FieldMDP freezes the fields it names; permit lifts it", async () => {
|
|
7449
|
+
if (!supported) return;
|
|
7450
|
+
const fixture = opts.fixtures.fieldMdp;
|
|
7451
|
+
const doc = await open(engine, opts, fixture);
|
|
7452
|
+
const lockedRef = {
|
|
7453
|
+
kind: "fqn",
|
|
7454
|
+
name: fixture.lockedField
|
|
7455
|
+
};
|
|
7456
|
+
try {
|
|
7457
|
+
const snapshot = await doc.signatures.list();
|
|
7458
|
+
const sig = snapshot.signatures[0];
|
|
7459
|
+
expect(sig.fieldName).toBe(fixture.fieldName);
|
|
7460
|
+
expect(sig.fieldMdp).toEqual({
|
|
7461
|
+
action: "include",
|
|
7462
|
+
fields: [fixture.lockedField]
|
|
7463
|
+
});
|
|
7464
|
+
expect(snapshot.protection.judged).toBe("annotate");
|
|
7465
|
+
expect(snapshot.protection.enforced).toBeNull();
|
|
7466
|
+
expect(snapshot.protection.fieldLocks[0]).toEqual({
|
|
7467
|
+
signatureIndex: 0,
|
|
7468
|
+
source: "fieldmdp",
|
|
7469
|
+
spec: {
|
|
7470
|
+
action: "include",
|
|
7471
|
+
fields: [fixture.lockedField]
|
|
7472
|
+
}
|
|
7473
|
+
});
|
|
7474
|
+
for (const lock of snapshot.protection.fieldLocks) {
|
|
7475
|
+
expect(lock.signatureIndex).toBe(0);
|
|
7476
|
+
expect(lock.spec).toEqual({
|
|
7477
|
+
action: "include",
|
|
7478
|
+
fields: [fixture.lockedField]
|
|
7479
|
+
});
|
|
7480
|
+
}
|
|
7481
|
+
expect(doc.security.allows("doc.forms.fill")).toBe(true);
|
|
7482
|
+
let caught;
|
|
7483
|
+
try {
|
|
7484
|
+
await doc.forms.setValue(lockedRef, {
|
|
7485
|
+
type: "text",
|
|
7486
|
+
value: "changed"
|
|
7487
|
+
});
|
|
7488
|
+
} catch (err) {
|
|
7489
|
+
caught = err;
|
|
7490
|
+
}
|
|
7491
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.ProtectedDocument)).toBe(true);
|
|
7492
|
+
const field = await doc.forms.get(lockedRef);
|
|
7493
|
+
expect(field.family).toBe("text");
|
|
7494
|
+
expect(field.value === "changed").toBe(false);
|
|
7495
|
+
} finally {
|
|
7496
|
+
await doc.close();
|
|
7497
|
+
}
|
|
7498
|
+
if (!permitEngine) return;
|
|
7499
|
+
const permitted = await open(permitEngine, opts, fixture);
|
|
7500
|
+
try {
|
|
7501
|
+
const result = await permitted.forms.setValue(lockedRef, {
|
|
7502
|
+
type: "text",
|
|
7503
|
+
value: "changed"
|
|
7504
|
+
});
|
|
7505
|
+
expect(result.field.name).toBe(fixture.lockedField);
|
|
7506
|
+
} finally {
|
|
7507
|
+
await permitted.close();
|
|
7508
|
+
}
|
|
7509
|
+
});
|
|
7510
|
+
test("well-formed ranges that seal no revision are partial, with no revision index", async () => {
|
|
7511
|
+
if (!supported) return;
|
|
7512
|
+
const doc = await open(engine, opts, opts.fixtures.partialChain);
|
|
7513
|
+
try {
|
|
7514
|
+
const snapshot = await doc.signatures.list();
|
|
7515
|
+
expect(snapshot.chainValid).toBe(true);
|
|
7516
|
+
expect(snapshot.revisions).toHaveLength(3);
|
|
7517
|
+
expect(snapshot.signatures).toHaveLength(2);
|
|
7518
|
+
for (const sig of snapshot.signatures) {
|
|
7519
|
+
expect(sig.signed).toBe(true);
|
|
7520
|
+
expect(sig.coverage).toBe("partial");
|
|
7521
|
+
expect(sig.revisionIndex).toBeNull();
|
|
7522
|
+
expect(sig.contentsSize).toBe(13);
|
|
7523
|
+
expect((await doc.signatures.contents(sig.field)).byteLength).toBe(13);
|
|
7524
|
+
expect((await doc.signatures.digest(sig.field, "sha256")).byteLength).toBe(32);
|
|
7525
|
+
}
|
|
7526
|
+
expect(snapshot.revisions.every((r) => r.signatureIndex === null)).toBe(true);
|
|
7527
|
+
expect(snapshot.protection.judged).toBe("annotate");
|
|
7528
|
+
expect(snapshot.protection.enforced).toBeNull();
|
|
7529
|
+
let caught;
|
|
7530
|
+
try {
|
|
7531
|
+
await doc.signatures.revisionBytes(3);
|
|
7532
|
+
} catch (err) {
|
|
7533
|
+
caught = err;
|
|
7534
|
+
}
|
|
7535
|
+
expect(require_derive.EngineError.is(caught, require_format.EngineErrorCode.NotFound)).toBe(true);
|
|
7536
|
+
} finally {
|
|
7537
|
+
await doc.close();
|
|
7538
|
+
}
|
|
7539
|
+
});
|
|
7540
|
+
if (opts.openKind !== "id") {
|
|
7541
|
+
runSigningTests(runner, opts, () => engine, () => supported);
|
|
7542
|
+
runAnalysisTests(runner, opts, () => engine, () => permitEngine, () => supported);
|
|
7543
|
+
}
|
|
7544
|
+
});
|
|
7545
|
+
}
|
|
7546
|
+
function runAnalysisTests(runner, opts, engineOf, permitEngineOf, supported) {
|
|
7547
|
+
const { test, expect } = runner;
|
|
7548
|
+
test("analyze: a form fill and a second signature after an approval are permitted", async () => {
|
|
7549
|
+
if (!supported()) return;
|
|
7550
|
+
const doc = await open(engineOf(), opts, opts.fixtures.twoApprovals);
|
|
7551
|
+
try {
|
|
7552
|
+
const analysis = await doc.signatures.analyze({ since: { signatureIndex: 0 } });
|
|
7553
|
+
expect(analysis.mode).toBe("authoritative");
|
|
7554
|
+
expect(analysis.basis.source).toBe("persisted");
|
|
7555
|
+
expect(analysis.since).toEqual({
|
|
7556
|
+
revisionIndex: 1,
|
|
7557
|
+
signatureIndex: 0
|
|
7558
|
+
});
|
|
7559
|
+
expect(analysis.until.revisionIndex).toBe(2);
|
|
7560
|
+
expect(analysis.steps).toHaveLength(1);
|
|
7561
|
+
const [step] = analysis.steps;
|
|
7562
|
+
expect(step.levelInForce).toBe("annotate");
|
|
7563
|
+
expect(step.verdict).toBe("permitted");
|
|
7564
|
+
expect(step.changes.length > 0).toBe(true);
|
|
7565
|
+
const rules = new Set(step.findings.filter((f) => f.verdict === "permitted").map((f) => f.rule));
|
|
7566
|
+
expect(rules.has("form-fill")).toBe(true);
|
|
7567
|
+
expect(rules.has("signature-added")).toBe(true);
|
|
7568
|
+
expect(step.findings.filter((f) => f.verdict === "forbidden")).toEqual([]);
|
|
7569
|
+
expect(analysis.verdict).toBe("permitted");
|
|
7570
|
+
const latest = await doc.signatures.analyze({ since: { signatureIndex: 1 } });
|
|
7571
|
+
expect(latest.steps).toHaveLength(0);
|
|
7572
|
+
expect(latest.verdict).toBe("unchanged");
|
|
7573
|
+
const historic = await doc.signatures.analyze({
|
|
7574
|
+
since: { revisionIndex: 0 },
|
|
7575
|
+
until: { revisionIndex: 1 }
|
|
7576
|
+
});
|
|
7577
|
+
expect(historic.steps).toHaveLength(1);
|
|
7578
|
+
expect(historic.verdict).toBe("permitted");
|
|
7579
|
+
} finally {
|
|
7580
|
+
await doc.close();
|
|
7581
|
+
}
|
|
7582
|
+
});
|
|
7583
|
+
test("analyze: the working copy is one more revision; a partial signature cannot anchor", async () => {
|
|
7584
|
+
if (!supported()) return;
|
|
7585
|
+
const fx = opts.fixtures.unsignedSigField;
|
|
7586
|
+
const doc = await open(engineOf(), opts, fx);
|
|
7587
|
+
try {
|
|
7588
|
+
const prepared = await doc.signatures.prepare({
|
|
7589
|
+
field: {
|
|
7590
|
+
kind: "fqn",
|
|
7591
|
+
name: fx.fieldName
|
|
7592
|
+
},
|
|
7593
|
+
certify: { permission: 2 }
|
|
7594
|
+
});
|
|
7595
|
+
await doc.signatures.complete({
|
|
7596
|
+
signingId: prepared.signingId,
|
|
7597
|
+
cms: FAKE_CMS,
|
|
7598
|
+
expectedVersion: prepared.expectedVersion
|
|
7599
|
+
});
|
|
7600
|
+
const clean = await doc.signatures.analyze({
|
|
7601
|
+
since: { signatureIndex: 0 },
|
|
7602
|
+
until: "working-copy"
|
|
7603
|
+
});
|
|
7604
|
+
expect(clean.steps).toHaveLength(0);
|
|
7605
|
+
expect(clean.verdict).toBe("unchanged");
|
|
7606
|
+
await doc.forms.setValue({
|
|
7607
|
+
kind: "fqn",
|
|
7608
|
+
name: fx.textField
|
|
7609
|
+
}, {
|
|
7610
|
+
type: "text",
|
|
7611
|
+
value: "draft"
|
|
7612
|
+
});
|
|
7613
|
+
const persisted = await doc.signatures.analyze({ since: { signatureIndex: 0 } });
|
|
7614
|
+
expect(persisted.steps).toHaveLength(0);
|
|
7615
|
+
const working = await doc.signatures.analyze({
|
|
7616
|
+
since: { signatureIndex: 0 },
|
|
7617
|
+
until: "working-copy"
|
|
7618
|
+
});
|
|
7619
|
+
expect(working.basis.source).toBe("working-copy");
|
|
7620
|
+
expect(working.steps).toHaveLength(1);
|
|
7621
|
+
expect(working.steps[0].levelInForce).toBe("fill");
|
|
7622
|
+
expect(working.verdict).toBe("permitted");
|
|
7623
|
+
expect(working.steps[0].findings.some((f) => f.rule === "form-fill" && f.verdict === "permitted")).toBe(true);
|
|
7624
|
+
} finally {
|
|
7625
|
+
await doc.close();
|
|
7626
|
+
}
|
|
7627
|
+
const partial = await open(engineOf(), opts, opts.fixtures.partialChain);
|
|
7628
|
+
try {
|
|
7629
|
+
expect(await caughtCode(() => partial.signatures.analyze({ since: { signatureIndex: 0 } }))).toBe(require_format.EngineErrorCode.InvalidArg);
|
|
7630
|
+
const byRevision = await partial.signatures.analyze({ since: { revisionIndex: 0 } });
|
|
7631
|
+
expect(byRevision.later.revisionCount).toBe(2);
|
|
7632
|
+
expect(byRevision.steps).toHaveLength(0);
|
|
7633
|
+
const inFull = await partial.signatures.analyze({
|
|
7634
|
+
since: { revisionIndex: 0 },
|
|
7635
|
+
detail: "full"
|
|
7636
|
+
});
|
|
7637
|
+
expect(inFull.steps).toHaveLength(2);
|
|
7638
|
+
expect(inFull.current.verdict).toBe(byRevision.current.verdict);
|
|
7639
|
+
} finally {
|
|
7640
|
+
await partial.close();
|
|
7641
|
+
}
|
|
7642
|
+
});
|
|
7643
|
+
test("analyze: a page edit under a certification and a locked field edit are forbidden", async () => {
|
|
7644
|
+
if (!supported()) return;
|
|
7645
|
+
const permit = permitEngineOf();
|
|
7646
|
+
if (!permit) return;
|
|
7647
|
+
const certified = await open(permit, opts, opts.fixtures.certified);
|
|
7648
|
+
let reopened = null;
|
|
7649
|
+
try {
|
|
7650
|
+
const list = await certified.pages.list();
|
|
7651
|
+
await certified.pages.rotate([list.pages[0].pageObjectNumber], 90);
|
|
7652
|
+
const working = await certified.signatures.analyze({
|
|
7653
|
+
since: { signatureIndex: 0 },
|
|
7654
|
+
until: "working-copy"
|
|
7655
|
+
});
|
|
7656
|
+
expect(working.verdict).toBe("forbidden");
|
|
7657
|
+
const bytes = await certified.download();
|
|
7658
|
+
reopened = await reopen(permit, opts, `${opts.fixtures.certified.id}-tampered`, bytes);
|
|
7659
|
+
const analysis = await reopened.signatures.analyze({ since: { signatureIndex: 0 } });
|
|
7660
|
+
expect(analysis.verdict).toBe("forbidden");
|
|
7661
|
+
expect(analysis.steps[0].findings.some((f) => f.verdict === "forbidden")).toBe(true);
|
|
7662
|
+
} finally {
|
|
7663
|
+
if (reopened) await reopened.close();
|
|
7664
|
+
await certified.close();
|
|
7665
|
+
}
|
|
7666
|
+
const locked = await open(permit, opts, opts.fixtures.fieldMdp);
|
|
7667
|
+
try {
|
|
7668
|
+
await locked.forms.setValue({
|
|
7669
|
+
kind: "fqn",
|
|
7670
|
+
name: opts.fixtures.fieldMdp.lockedField
|
|
7671
|
+
}, {
|
|
7672
|
+
type: "text",
|
|
7673
|
+
value: "tampered"
|
|
7674
|
+
});
|
|
7675
|
+
const working = await locked.signatures.analyze({
|
|
7676
|
+
since: { signatureIndex: 0 },
|
|
7677
|
+
until: "working-copy"
|
|
7678
|
+
});
|
|
7679
|
+
expect(working.verdict).toBe("forbidden");
|
|
7680
|
+
expect(working.steps[0].findings.some((f) => f.rule === "field-lock")).toBe(true);
|
|
7681
|
+
} finally {
|
|
7682
|
+
await locked.close();
|
|
7683
|
+
}
|
|
7684
|
+
});
|
|
7685
|
+
}
|
|
7686
|
+
/** A minimal DER SEQUENCE standing in for a CMS: the engine's job ends at the bytes. */
|
|
7687
|
+
const FAKE_CMS = new Uint8Array([
|
|
7688
|
+
48,
|
|
7689
|
+
6,
|
|
7690
|
+
2,
|
|
7691
|
+
1,
|
|
7692
|
+
1,
|
|
7693
|
+
2,
|
|
7694
|
+
1,
|
|
7695
|
+
2
|
|
7696
|
+
]);
|
|
7697
|
+
async function caughtCode(run) {
|
|
7698
|
+
try {
|
|
7699
|
+
await run();
|
|
7700
|
+
return null;
|
|
7701
|
+
} catch (err) {
|
|
7702
|
+
return err instanceof require_derive.EngineError ? err.code : "not-an-engine-error";
|
|
7703
|
+
}
|
|
7704
|
+
}
|
|
7705
|
+
function runSigningTests(runner, opts, engineOf, supported) {
|
|
7706
|
+
const { test, expect } = runner;
|
|
7707
|
+
const fx = () => opts.fixtures.unsignedSigField;
|
|
7708
|
+
const sigRef = () => ({
|
|
7709
|
+
kind: "fqn",
|
|
7710
|
+
name: fx().fieldName
|
|
7711
|
+
});
|
|
7712
|
+
const textRef = () => ({
|
|
7713
|
+
kind: "fqn",
|
|
7714
|
+
name: fx().textField
|
|
7715
|
+
});
|
|
7716
|
+
test("sign: prepare seals a candidate, complete installs it, download returns it verbatim", async () => {
|
|
7717
|
+
if (!supported()) return;
|
|
7718
|
+
const engine = engineOf();
|
|
7719
|
+
const doc = await open(engine, opts, fx());
|
|
7720
|
+
const events = [];
|
|
7721
|
+
const unsubscribe = doc.events.subscribe((event) => events.push(event.type));
|
|
7722
|
+
let reopened = null;
|
|
7723
|
+
try {
|
|
7724
|
+
const v0 = await doc.version();
|
|
7725
|
+
const before = await doc.signatures.list();
|
|
7726
|
+
expect(before.revisions).toHaveLength(1);
|
|
7727
|
+
expect(before.signatures).toHaveLength(1);
|
|
7728
|
+
expect(before.signatures[0].signed).toBe(false);
|
|
7729
|
+
expect(before.protection.judged).toBeNull();
|
|
7730
|
+
const prepared = await doc.signatures.prepare({
|
|
7731
|
+
field: sigRef(),
|
|
7732
|
+
subFilter: "ETSI.CAdES.detached",
|
|
7733
|
+
digest: "sha256",
|
|
7734
|
+
contentsSize: 1024,
|
|
7735
|
+
attribution: { reason: "conformance" }
|
|
7736
|
+
});
|
|
7737
|
+
expect(prepared.digest.byteLength).toBe(32);
|
|
7738
|
+
expect(prepared.algorithm).toBe("sha256");
|
|
7739
|
+
expect(prepared.subFilter).toBe("ETSI.CAdES.detached");
|
|
7740
|
+
expect(prepared.contentsSize).toBe(1024);
|
|
7741
|
+
expect(prepared.byteRange[0]).toBe(0);
|
|
7742
|
+
expect(prepared.byteRange[2] > prepared.byteRange[1]).toBe(true);
|
|
7743
|
+
expect(prepared.expectedVersion.baseSha256).toBe(v0.sha256);
|
|
7744
|
+
expect(await caughtCode(() => doc.signatures.prepare({ field: sigRef() }))).toBe(require_format.EngineErrorCode.SigningPending);
|
|
7745
|
+
expect(await caughtCode(() => doc.forms.setValue(textRef(), {
|
|
7746
|
+
type: "text",
|
|
7747
|
+
value: "x"
|
|
7748
|
+
}))).toBe(require_format.EngineErrorCode.SigningPending);
|
|
7749
|
+
const during = await doc.signatures.list();
|
|
7750
|
+
expect(during.signatures[0].signed).toBe(false);
|
|
7751
|
+
expect((await doc.version()).sha256).toBe(v0.sha256);
|
|
7752
|
+
expect(await caughtCode(() => doc.signatures.complete({
|
|
7753
|
+
signingId: prepared.signingId,
|
|
7754
|
+
cms: FAKE_CMS,
|
|
7755
|
+
expectedVersion: {
|
|
7756
|
+
baseSha256: prepared.expectedVersion.baseSha256,
|
|
7757
|
+
editsVersion: prepared.expectedVersion.editsVersion + 1
|
|
7758
|
+
}
|
|
7759
|
+
}))).toBe(require_format.EngineErrorCode.SigningVersionMismatch);
|
|
7760
|
+
const result = await doc.signatures.complete({
|
|
7761
|
+
signingId: prepared.signingId,
|
|
7762
|
+
cms: FAKE_CMS,
|
|
7763
|
+
expectedVersion: prepared.expectedVersion
|
|
7764
|
+
});
|
|
7765
|
+
expect(result.status).toBe("completed");
|
|
7766
|
+
expect(result.signature.signed).toBe(true);
|
|
7767
|
+
expect(result.signature.fieldName).toBe(fx().fieldName);
|
|
7768
|
+
expect(result.signature.coverage).toBe("whole-revision");
|
|
7769
|
+
expect(result.signature.revisionIndex).toBe(1);
|
|
7770
|
+
expect(result.signature.subFilter).toBe("ETSI.CAdES.detached");
|
|
7771
|
+
expect(result.signature.signer.reason).toBe("conformance");
|
|
7772
|
+
expect(result.signature.contentsSize).toBe(FAKE_CMS.byteLength);
|
|
7773
|
+
expect(result.previous).toEqual(prepared.expectedVersion);
|
|
7774
|
+
expect(result.version.sha256 === v0.sha256).toBe(false);
|
|
7775
|
+
expect(result.protection.judged).toBe("annotate");
|
|
7776
|
+
expect(result.protection.enforced).toBeNull();
|
|
7777
|
+
expect(result.meta.affectedPages.length >= 1).toBe(true);
|
|
7778
|
+
expect(await doc.version()).toEqual(result.version);
|
|
7779
|
+
const after = await doc.signatures.list();
|
|
7780
|
+
expect(after.revisions).toHaveLength(2);
|
|
7781
|
+
expect(after.signatures[0].signed).toBe(true);
|
|
7782
|
+
expect(after.signatures[0].revisionIndex).toBe(1);
|
|
7783
|
+
expect(after.revisions[1].signatureIndex).toBe(0);
|
|
7784
|
+
expect(toHex(await doc.signatures.digest(sigRef(), "sha256"))).toBe(toHex(prepared.digest));
|
|
7785
|
+
expect(bytesEqual(await doc.signatures.contents(sigRef()), FAKE_CMS)).toBe(true);
|
|
7786
|
+
const bytes = await doc.download();
|
|
7787
|
+
expect(bytes.byteLength).toBe(result.version.byteLength);
|
|
7788
|
+
expect(await sha256Hex(bytes)).toBe(result.version.sha256);
|
|
7789
|
+
reopened = await reopen(engine, opts, `${fx().id}-signed`, bytes);
|
|
7790
|
+
const fresh = await reopened.signatures.list();
|
|
7791
|
+
expect(fresh.revisions).toHaveLength(2);
|
|
7792
|
+
expect(fresh.signatures[0].coverage).toBe("whole-revision");
|
|
7793
|
+
expect(toHex(await reopened.signatures.digest(sigRef(), "sha256"))).toBe(toHex(prepared.digest));
|
|
7794
|
+
const replay = await doc.signatures.complete({
|
|
7795
|
+
signingId: prepared.signingId,
|
|
7796
|
+
cms: FAKE_CMS,
|
|
7797
|
+
expectedVersion: prepared.expectedVersion
|
|
7798
|
+
});
|
|
7799
|
+
expect(replay.status).toBe("already-completed");
|
|
7800
|
+
expect(replay.version).toEqual(result.version);
|
|
7801
|
+
expect((await doc.signatures.abort(prepared.signingId)).status).toBe("already-completed");
|
|
7802
|
+
expect((await doc.signatures.abort("never-prepared")).status).toBe("unknown");
|
|
7803
|
+
await doc.forms.setValue(textRef(), {
|
|
7804
|
+
type: "text",
|
|
7805
|
+
value: "after"
|
|
7806
|
+
});
|
|
7807
|
+
expect(await caughtCode(() => doc.signatures.prepare({ field: sigRef() }))).toBe(require_format.EngineErrorCode.SignatureRefused);
|
|
7808
|
+
expect(events.filter((t) => t === "signature.prepared")).toHaveLength(1);
|
|
7809
|
+
expect(events.filter((t) => t === "signature.completed")).toHaveLength(1);
|
|
7810
|
+
expect(events.filter((t) => t === "document.versioned")).toHaveLength(1);
|
|
7811
|
+
} finally {
|
|
7812
|
+
unsubscribe();
|
|
7813
|
+
if (reopened) await reopened.close();
|
|
7814
|
+
await doc.close();
|
|
7815
|
+
}
|
|
7816
|
+
});
|
|
7817
|
+
test("sign: unsaved edits are sealed in the signature's own revision (layer session)", async () => {
|
|
7818
|
+
if (!supported()) return;
|
|
7819
|
+
const doc = await open(engineOf(), opts, fx());
|
|
7820
|
+
try {
|
|
7821
|
+
await doc.forms.setValue(textRef(), {
|
|
7822
|
+
type: "text",
|
|
7823
|
+
value: "unsaved"
|
|
7824
|
+
});
|
|
7825
|
+
const prepared = await doc.signatures.prepare({ field: sigRef() });
|
|
7826
|
+
const result = await doc.signatures.complete({
|
|
7827
|
+
signingId: prepared.signingId,
|
|
7828
|
+
cms: FAKE_CMS,
|
|
7829
|
+
expectedVersion: prepared.expectedVersion
|
|
7830
|
+
});
|
|
7831
|
+
expect(result.signature.revisionIndex).toBe(1);
|
|
7832
|
+
const after = await doc.signatures.list();
|
|
7833
|
+
expect(after.revisions).toHaveLength(2);
|
|
7834
|
+
const text = await doc.forms.get(textRef());
|
|
7835
|
+
expect(text.value).toBe("unsaved");
|
|
7836
|
+
const bytes = await doc.download();
|
|
7837
|
+
expect(await sha256Hex(bytes)).toBe(result.version.sha256);
|
|
7838
|
+
} finally {
|
|
7839
|
+
await doc.close();
|
|
7840
|
+
}
|
|
7841
|
+
});
|
|
7842
|
+
test("sign: a certification protects the document from the moment it completes", async () => {
|
|
7843
|
+
if (!supported()) return;
|
|
7844
|
+
const doc = await open(engineOf(), opts, fx());
|
|
7845
|
+
try {
|
|
7846
|
+
expect(doc.security.allows("doc.pages.assemble")).toBe(true);
|
|
7847
|
+
const prepared = await doc.signatures.prepare({
|
|
7848
|
+
field: sigRef(),
|
|
7849
|
+
certify: { permission: 2 },
|
|
7850
|
+
subFilter: "adbe.pkcs7.detached"
|
|
7851
|
+
});
|
|
7852
|
+
const result = await doc.signatures.complete({
|
|
7853
|
+
signingId: prepared.signingId,
|
|
7854
|
+
cms: FAKE_CMS,
|
|
7855
|
+
expectedVersion: prepared.expectedVersion
|
|
7856
|
+
});
|
|
7857
|
+
expect(result.signature.docMdp).toBe(2);
|
|
7858
|
+
expect(result.signature.catalogCertification).toBe(true);
|
|
7859
|
+
expect(result.protection.judged).toBe("fill");
|
|
7860
|
+
expect(result.protection.enforced).toBe("fill");
|
|
7861
|
+
expect(result.protection.certification).toEqual({
|
|
7862
|
+
signatureIndex: result.signature.index,
|
|
7863
|
+
permission: 2
|
|
7864
|
+
});
|
|
7865
|
+
expect(doc.security.allows("doc.pages.assemble")).toBe(false);
|
|
7866
|
+
expect(doc.security.allows("doc.forms.fill")).toBe(true);
|
|
7867
|
+
const list = await doc.pages.list();
|
|
7868
|
+
expect(await caughtCode(() => doc.pages.delete([list.pages[0].pageObjectNumber]))).toBe(require_format.EngineErrorCode.ProtectedDocument);
|
|
7869
|
+
expect(await caughtCode(() => doc.download({ mode: "rewrite" }))).toBe(require_format.EngineErrorCode.ProtectedDocument);
|
|
7870
|
+
await doc.forms.setValue(textRef(), {
|
|
7871
|
+
type: "text",
|
|
7872
|
+
value: "filled"
|
|
7873
|
+
});
|
|
7874
|
+
const after = await doc.signatures.list();
|
|
7875
|
+
expect(after.signatures[0].coverage).toBe("whole-revision");
|
|
7876
|
+
} finally {
|
|
7877
|
+
await doc.close();
|
|
7878
|
+
}
|
|
7879
|
+
});
|
|
7880
|
+
test("sign: a lock freezes the named fields and is mirrored on the field", async () => {
|
|
7881
|
+
if (!supported()) return;
|
|
7882
|
+
const doc = await open(engineOf(), opts, fx());
|
|
7883
|
+
try {
|
|
7884
|
+
const prepared = await doc.signatures.prepare({
|
|
7885
|
+
field: sigRef(),
|
|
7886
|
+
lock: {
|
|
7887
|
+
action: "include",
|
|
7888
|
+
fields: [fx().textField]
|
|
7889
|
+
}
|
|
7890
|
+
});
|
|
7891
|
+
const result = await doc.signatures.complete({
|
|
7892
|
+
signingId: prepared.signingId,
|
|
7893
|
+
cms: FAKE_CMS,
|
|
7894
|
+
expectedVersion: prepared.expectedVersion
|
|
7895
|
+
});
|
|
7896
|
+
expect(result.signature.fieldMdp).toEqual({
|
|
7897
|
+
action: "include",
|
|
7898
|
+
fields: [fx().textField]
|
|
7899
|
+
});
|
|
7900
|
+
expect(result.signature.lock).toEqual({
|
|
7901
|
+
action: "include",
|
|
7902
|
+
fields: [fx().textField]
|
|
7903
|
+
});
|
|
7904
|
+
expect(result.protection.fieldLocks.length >= 1).toBe(true);
|
|
7905
|
+
expect(await caughtCode(() => doc.forms.setValue(textRef(), {
|
|
7906
|
+
type: "text",
|
|
7907
|
+
value: "nope"
|
|
7908
|
+
}))).toBe(require_format.EngineErrorCode.ProtectedDocument);
|
|
7909
|
+
} finally {
|
|
7910
|
+
await doc.close();
|
|
7911
|
+
}
|
|
7912
|
+
});
|
|
7913
|
+
test("sign: abort discards the candidate and lifts the fence", async () => {
|
|
7914
|
+
if (!supported()) return;
|
|
7915
|
+
const doc = await open(engineOf(), opts, fx());
|
|
7916
|
+
try {
|
|
7917
|
+
const v0 = await doc.version();
|
|
7918
|
+
const prepared = await doc.signatures.prepare({ field: sigRef() });
|
|
7919
|
+
expect((await doc.signatures.abort(prepared.signingId)).status).toBe("aborted");
|
|
7920
|
+
expect((await doc.signatures.list()).signatures[0].signed).toBe(false);
|
|
7921
|
+
expect((await doc.version()).sha256).toBe(v0.sha256);
|
|
7922
|
+
await doc.forms.setValue(textRef(), {
|
|
7923
|
+
type: "text",
|
|
7924
|
+
value: "free again"
|
|
7925
|
+
});
|
|
7926
|
+
expect(await caughtCode(() => doc.signatures.complete({
|
|
7927
|
+
signingId: prepared.signingId,
|
|
7928
|
+
cms: FAKE_CMS,
|
|
7929
|
+
expectedVersion: prepared.expectedVersion
|
|
7930
|
+
}))).toBe(require_format.EngineErrorCode.NotFound);
|
|
7931
|
+
} finally {
|
|
7932
|
+
await doc.close();
|
|
7933
|
+
}
|
|
7934
|
+
});
|
|
7935
|
+
test("sign: artwork from a PDF page lands on the widget", async () => {
|
|
7936
|
+
if (!supported()) return;
|
|
7937
|
+
const doc = await open(engineOf(), opts, fx());
|
|
7938
|
+
try {
|
|
7939
|
+
const artwork = await opts.fixtures.artwork.bytes();
|
|
7940
|
+
const prepared = await doc.signatures.prepare({
|
|
7941
|
+
field: sigRef(),
|
|
7942
|
+
appearance: {
|
|
7943
|
+
pdf: artwork,
|
|
7944
|
+
pageIndex: 0
|
|
7945
|
+
}
|
|
7946
|
+
});
|
|
7947
|
+
const result = await doc.signatures.complete({
|
|
7948
|
+
signingId: prepared.signingId,
|
|
7949
|
+
cms: FAKE_CMS,
|
|
7950
|
+
expectedVersion: prepared.expectedVersion
|
|
7951
|
+
});
|
|
7952
|
+
expect(result.signature.coverage).toBe("whole-revision");
|
|
7953
|
+
expect(result.signature.widget).toBeTruthy();
|
|
7954
|
+
const widget = (await doc.page(result.signature.widget.pageObjectNumber).annotations.list()).annotations.find((a) => a.ref.kind === "objectNumber" && a.ref.annotObjectNumber === result.signature.widget.annotObjectNumber);
|
|
7955
|
+
expect(widget).toBeTruthy();
|
|
7956
|
+
} finally {
|
|
7957
|
+
await doc.close();
|
|
7958
|
+
}
|
|
7959
|
+
});
|
|
7960
|
+
if (opts.openKind === "layerBytes") test("sign: a layer session keeps its kind, with an empty layer over the new base", async () => {
|
|
7961
|
+
if (!supported()) return;
|
|
7962
|
+
const doc = await open(engineOf(), opts, fx());
|
|
7963
|
+
try {
|
|
7964
|
+
const prepared = await doc.signatures.prepare({ field: sigRef() });
|
|
7965
|
+
const result = await doc.signatures.complete({
|
|
7966
|
+
signingId: prepared.signingId,
|
|
7967
|
+
cms: FAKE_CMS,
|
|
7968
|
+
expectedVersion: prepared.expectedVersion
|
|
7969
|
+
});
|
|
7970
|
+
const layer = await doc.downloadLayer();
|
|
7971
|
+
expect(layer.byteLength > 0).toBe(true);
|
|
7972
|
+
expect(await sha256Hex(await doc.download())).toBe(result.version.sha256);
|
|
7973
|
+
} finally {
|
|
7974
|
+
await doc.close();
|
|
7975
|
+
}
|
|
7976
|
+
});
|
|
7977
|
+
}
|
|
7978
|
+
async function reopen(engine, opts, id, bytes) {
|
|
7979
|
+
if (opts.openKind === "layerBytes") return engine.open({
|
|
7980
|
+
kind: "layerBytes",
|
|
7981
|
+
id,
|
|
7982
|
+
baseBytes: bytes
|
|
7983
|
+
});
|
|
7984
|
+
return engine.open({
|
|
7985
|
+
kind: "bytes",
|
|
7986
|
+
id,
|
|
7987
|
+
bytes
|
|
7988
|
+
});
|
|
7989
|
+
}
|
|
7990
|
+
async function open(engine, opts, fixture) {
|
|
7991
|
+
if (opts.openKind === "bytes") return engine.open({
|
|
7992
|
+
kind: "bytes",
|
|
7993
|
+
id: fixture.id,
|
|
7994
|
+
bytes: await fixture.bytes()
|
|
7995
|
+
});
|
|
7996
|
+
if (opts.openKind === "layerBytes") return engine.open({
|
|
7997
|
+
kind: "layerBytes",
|
|
7998
|
+
id: `${fixture.id}-layer`,
|
|
7999
|
+
baseBytes: await fixture.bytes()
|
|
8000
|
+
});
|
|
8001
|
+
return engine.open({
|
|
8002
|
+
kind: "id",
|
|
8003
|
+
id: fixture.cloudId ?? fixture.id
|
|
8004
|
+
});
|
|
8005
|
+
}
|
|
8006
|
+
function concat(a, b) {
|
|
8007
|
+
const out = new Uint8Array(a.byteLength + b.byteLength);
|
|
8008
|
+
out.set(a, 0);
|
|
8009
|
+
out.set(b, a.byteLength);
|
|
8010
|
+
return out;
|
|
8011
|
+
}
|
|
8012
|
+
function bytesEqual(a, b) {
|
|
8013
|
+
if (a.byteLength !== b.byteLength) return false;
|
|
8014
|
+
for (let i = 0; i < a.byteLength; i++) if (a[i] !== b[i]) return false;
|
|
8015
|
+
return true;
|
|
8016
|
+
}
|
|
8017
|
+
function toHex(bytes) {
|
|
8018
|
+
let out = "";
|
|
8019
|
+
for (const b of bytes) out += b.toString(16).padStart(2, "0");
|
|
8020
|
+
return out;
|
|
8021
|
+
}
|
|
8022
|
+
async function sha256Hex(bytes) {
|
|
8023
|
+
const copy = new Uint8Array(bytes.byteLength);
|
|
8024
|
+
copy.set(bytes);
|
|
8025
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", copy);
|
|
8026
|
+
return toHex(new Uint8Array(digest));
|
|
8027
|
+
}
|
|
8028
|
+
//#endregion
|
|
6678
8029
|
exports.TEXT_DIVERGENCE_CASES = TEXT_DIVERGENCE_CASES;
|
|
6679
8030
|
exports.diffAnnotationListSnapshot = diffAnnotationListSnapshot;
|
|
6680
8031
|
exports.diffAnnotationListSnapshotAll = diffAnnotationListSnapshotAll;
|
|
@@ -6687,6 +8038,7 @@ exports.runAnnotationReadConformance = runAnnotationReadConformance;
|
|
|
6687
8038
|
exports.runAttachmentConformance = runAttachmentConformance;
|
|
6688
8039
|
exports.runDocumentEventsConformance = runDocumentEventsConformance;
|
|
6689
8040
|
exports.runFormConformance = runFormConformance;
|
|
8041
|
+
exports.runMeasurementConformance = runMeasurementConformance;
|
|
6690
8042
|
exports.runMetadataConformance = runMetadataConformance;
|
|
6691
8043
|
exports.runNamedPagesConformance = runNamedPagesConformance;
|
|
6692
8044
|
exports.runPageDeleteConformance = runPageDeleteConformance;
|
|
@@ -6701,6 +8053,7 @@ exports.runPageTextConformance = runPageTextConformance;
|
|
|
6701
8053
|
exports.runPieceInfoConformance = runPieceInfoConformance;
|
|
6702
8054
|
exports.runRedactionApplyConformance = runRedactionApplyConformance;
|
|
6703
8055
|
exports.runSearchConformance = runSearchConformance;
|
|
8056
|
+
exports.runSignatureConformance = runSignatureConformance;
|
|
6704
8057
|
exports.runTextDivergenceConformance = runTextDivergenceConformance;
|
|
6705
8058
|
|
|
6706
8059
|
//# sourceMappingURL=conformance.cjs.map
|