pdf.js/test/unit/cmap_spec.js
Jonas Jenwald 941b65f683 Remove unncessary CanvasFactory/CMapReaderFactory/FileReaderFactory duplication in unit-tests
Given that the API will now, after PR 12039, automatically pick the correct factories to use depending on the environment (browser vs. Node.js), we can utilize that in the unit-tests as well. This way we don't have to manually repeat the same initialization code in *multiple* unit-tests.
*Note:* The *official* PDF.js API is defined in `src/pdf.js`, hence the new exports in `src/display/api.js` will not affect that.

Also, updates the unit-test `FileReaderFactory` helpers similarily.

*Drive-by change:* Fix the `CMapReaderFactory` usage in the annotation unit-tests, since the cache should only contain raw data and not a Promise. While this obviously works as-is, having unit-tests that "abuse" the intended data format can easily lead to unnecessary failures if changes are made to the relevant `src/core/` code.
2021-01-08 17:33:59 +01:00

346 lines
11 KiB
JavaScript

/* Copyright 2017 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CMap, CMapFactory, IdentityCMap } from "../../src/core/cmap.js";
import { CMAP_PARAMS } from "./test_utils.js";
import { DefaultCMapReaderFactory } from "../../src/display/api.js";
import { Name } from "../../src/core/primitives.js";
import { StringStream } from "../../src/core/stream.js";
describe("cmap", function () {
let fetchBuiltInCMap;
beforeAll(function (done) {
// Allow CMap testing in Node.js, e.g. for Travis.
const CMapReaderFactory = new DefaultCMapReaderFactory({
baseUrl: CMAP_PARAMS.cMapUrl,
isCompressed: CMAP_PARAMS.cMapPacked,
});
fetchBuiltInCMap = function (name) {
return CMapReaderFactory.fetch({
name,
});
};
done();
});
afterAll(function () {
fetchBuiltInCMap = null;
});
it("parses beginbfchar", function (done) {
// prettier-ignore
const str = "2 beginbfchar\n" +
"<03> <00>\n" +
"<04> <01>\n" +
"endbfchar\n";
const stream = new StringStream(str);
const cmapPromise = CMapFactory.create({ encoding: stream });
cmapPromise
.then(function (cmap) {
expect(cmap.lookup(0x03)).toEqual(String.fromCharCode(0x00));
expect(cmap.lookup(0x04)).toEqual(String.fromCharCode(0x01));
expect(cmap.lookup(0x05)).toBeUndefined();
done();
})
.catch(function (reason) {
done.fail(reason);
});
});
it("parses beginbfrange with range", function (done) {
// prettier-ignore
const str = "1 beginbfrange\n" +
"<06> <0B> 0\n" +
"endbfrange\n";
const stream = new StringStream(str);
const cmapPromise = CMapFactory.create({ encoding: stream });
cmapPromise
.then(function (cmap) {
expect(cmap.lookup(0x05)).toBeUndefined();
expect(cmap.lookup(0x06)).toEqual(String.fromCharCode(0x00));
expect(cmap.lookup(0x0b)).toEqual(String.fromCharCode(0x05));
expect(cmap.lookup(0x0c)).toBeUndefined();
done();
})
.catch(function (reason) {
done.fail(reason);
});
});
it("parses beginbfrange with array", function (done) {
// prettier-ignore
const str = "1 beginbfrange\n" +
"<0D> <12> [ 0 1 2 3 4 5 ]\n" +
"endbfrange\n";
const stream = new StringStream(str);
const cmapPromise = CMapFactory.create({ encoding: stream });
cmapPromise
.then(function (cmap) {
expect(cmap.lookup(0x0c)).toBeUndefined();
expect(cmap.lookup(0x0d)).toEqual(0x00);
expect(cmap.lookup(0x12)).toEqual(0x05);
expect(cmap.lookup(0x13)).toBeUndefined();
done();
})
.catch(function (reason) {
done.fail(reason);
});
});
it("parses begincidchar", function (done) {
// prettier-ignore
const str = "1 begincidchar\n" +
"<14> 0\n" +
"endcidchar\n";
const stream = new StringStream(str);
const cmapPromise = CMapFactory.create({ encoding: stream });
cmapPromise
.then(function (cmap) {
expect(cmap.lookup(0x14)).toEqual(0x00);
expect(cmap.lookup(0x15)).toBeUndefined();
done();
})
.catch(function (reason) {
done.fail(reason);
});
});
it("parses begincidrange", function (done) {
// prettier-ignore
const str = "1 begincidrange\n" +
"<0016> <001B> 0\n" +
"endcidrange\n";
const stream = new StringStream(str);
const cmapPromise = CMapFactory.create({ encoding: stream });
cmapPromise
.then(function (cmap) {
expect(cmap.lookup(0x15)).toBeUndefined();
expect(cmap.lookup(0x16)).toEqual(0x00);
expect(cmap.lookup(0x1b)).toEqual(0x05);
expect(cmap.lookup(0x1c)).toBeUndefined();
done();
})
.catch(function (reason) {
done.fail(reason);
});
});
it("decodes codespace ranges", function (done) {
// prettier-ignore
const str = "1 begincodespacerange\n" +
"<01> <02>\n" +
"<00000003> <00000004>\n" +
"endcodespacerange\n";
const stream = new StringStream(str);
const cmapPromise = CMapFactory.create({ encoding: stream });
cmapPromise
.then(function (cmap) {
const c = {};
cmap.readCharCode(String.fromCharCode(1), 0, c);
expect(c.charcode).toEqual(1);
expect(c.length).toEqual(1);
cmap.readCharCode(String.fromCharCode(0, 0, 0, 3), 0, c);
expect(c.charcode).toEqual(3);
expect(c.length).toEqual(4);
done();
})
.catch(function (reason) {
done.fail(reason);
});
});
it("decodes 4 byte codespace ranges", function (done) {
// prettier-ignore
const str = "1 begincodespacerange\n" +
"<8EA1A1A1> <8EA1FEFE>\n" +
"endcodespacerange\n";
const stream = new StringStream(str);
const cmapPromise = CMapFactory.create({ encoding: stream });
cmapPromise
.then(function (cmap) {
const c = {};
cmap.readCharCode(String.fromCharCode(0x8e, 0xa1, 0xa1, 0xa1), 0, c);
expect(c.charcode).toEqual(0x8ea1a1a1);
expect(c.length).toEqual(4);
done();
})
.catch(function (reason) {
done.fail(reason);
});
});
it("read usecmap", function (done) {
const str = "/Adobe-Japan1-1 usecmap\n";
const stream = new StringStream(str);
const cmapPromise = CMapFactory.create({
encoding: stream,
fetchBuiltInCMap,
useCMap: null,
});
cmapPromise
.then(function (cmap) {
expect(cmap instanceof CMap).toEqual(true);
expect(cmap.useCMap).not.toBeNull();
expect(cmap.builtInCMap).toBeFalsy();
expect(cmap.length).toEqual(0x20a7);
expect(cmap.isIdentityCMap).toEqual(false);
done();
})
.catch(function (reason) {
done.fail(reason);
});
});
it("parses cmapname", function (done) {
const str = "/CMapName /Identity-H def\n";
const stream = new StringStream(str);
const cmapPromise = CMapFactory.create({ encoding: stream });
cmapPromise
.then(function (cmap) {
expect(cmap.name).toEqual("Identity-H");
done();
})
.catch(function (reason) {
done.fail(reason);
});
});
it("parses wmode", function (done) {
const str = "/WMode 1 def\n";
const stream = new StringStream(str);
const cmapPromise = CMapFactory.create({ encoding: stream });
cmapPromise
.then(function (cmap) {
expect(cmap.vertical).toEqual(true);
done();
})
.catch(function (reason) {
done.fail(reason);
});
});
it("loads built in cmap", function (done) {
const cmapPromise = CMapFactory.create({
encoding: Name.get("Adobe-Japan1-1"),
fetchBuiltInCMap,
useCMap: null,
});
cmapPromise
.then(function (cmap) {
expect(cmap instanceof CMap).toEqual(true);
expect(cmap.useCMap).toBeNull();
expect(cmap.builtInCMap).toBeTruthy();
expect(cmap.length).toEqual(0x20a7);
expect(cmap.isIdentityCMap).toEqual(false);
done();
})
.catch(function (reason) {
done.fail(reason);
});
});
it("loads built in identity cmap", function (done) {
const cmapPromise = CMapFactory.create({
encoding: Name.get("Identity-H"),
fetchBuiltInCMap,
useCMap: null,
});
cmapPromise
.then(function (cmap) {
expect(cmap instanceof IdentityCMap).toEqual(true);
expect(cmap.vertical).toEqual(false);
expect(cmap.length).toEqual(0x10000);
expect(function () {
return cmap.isIdentityCMap;
}).toThrow(new Error("should not access .isIdentityCMap"));
done();
})
.catch(function (reason) {
done.fail(reason);
});
});
it("attempts to load a non-existent built-in CMap", function (done) {
const cmapPromise = CMapFactory.create({
encoding: Name.get("null"),
fetchBuiltInCMap,
useCMap: null,
});
cmapPromise.then(
function () {
done.fail("No CMap should be loaded");
},
function (reason) {
expect(reason instanceof Error).toEqual(true);
expect(reason.message).toEqual("Unknown CMap name: null");
done();
}
);
});
it("attempts to load a built-in CMap without the necessary API parameters", function (done) {
function tmpFetchBuiltInCMap(name) {
const CMapReaderFactory = new DefaultCMapReaderFactory({});
return CMapReaderFactory.fetch({
name,
});
}
const cmapPromise = CMapFactory.create({
encoding: Name.get("Adobe-Japan1-1"),
fetchBuiltInCMap: tmpFetchBuiltInCMap,
useCMap: null,
});
cmapPromise.then(
function () {
done.fail("No CMap should be loaded");
},
function (reason) {
expect(reason instanceof Error).toEqual(true);
expect(reason.message).toEqual(
'The CMap "baseUrl" parameter must be specified, ensure that ' +
'the "cMapUrl" and "cMapPacked" API parameters are provided.'
);
done();
}
);
});
it("attempts to load a built-in CMap with inconsistent API parameters", function (done) {
function tmpFetchBuiltInCMap(name) {
const CMapReaderFactory = new DefaultCMapReaderFactory({
baseUrl: CMAP_PARAMS.cMapUrl,
isCompressed: false,
});
return CMapReaderFactory.fetch({
name,
});
}
const cmapPromise = CMapFactory.create({
encoding: Name.get("Adobe-Japan1-1"),
fetchBuiltInCMap: tmpFetchBuiltInCMap,
useCMap: null,
});
cmapPromise.then(
function () {
done.fail("No CMap should be loaded");
},
function (reason) {
expect(reason instanceof Error).toEqual(true);
const message = reason.message;
expect(message.startsWith("Unable to load CMap at: ")).toEqual(true);
expect(message.endsWith("/external/bcmaps/Adobe-Japan1-1")).toEqual(
true
);
done();
}
);
});
});