diff --git a/gulpfile.mjs b/gulpfile.mjs index 6d7033e40011e9..cd56bbf15b5eb1 100644 --- a/gulpfile.mjs +++ b/gulpfile.mjs @@ -863,11 +863,17 @@ async function parseDefaultPreferences(dir) { "./" + DEFAULT_PREFERENCES_DIR + dir + "app_options.mjs" ); - const browserPrefs = AppOptions.getAll(OptionKind.BROWSER); + const browserPrefs = AppOptions.getAll( + OptionKind.BROWSER, + /* defaultOnly = */ true + ); if (Object.keys(browserPrefs).length === 0) { throw new Error("No browser preferences found."); } - const prefs = AppOptions.getAll(OptionKind.PREFERENCE); + const prefs = AppOptions.getAll( + OptionKind.PREFERENCE, + /* defaultOnly = */ true + ); if (Object.keys(prefs).length === 0) { throw new Error("No default preferences found."); } diff --git a/test/unit/app_options_spec.js b/test/unit/app_options_spec.js new file mode 100644 index 00000000000000..78981a7398eb2f --- /dev/null +++ b/test/unit/app_options_spec.js @@ -0,0 +1,31 @@ +/* Copyright 2024 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 { AppOptions, OptionKind } from "../../web/app_options.js"; +import { objectSize } from "../../src/shared/util.js"; + +describe("AppOptions", function () { + it("checks that getAll returns data, for every OptionKind", function () { + const KIND_NAMES = ["BROWSER", "VIEWER", "API", "WORKER", "PREFERENCE"]; + + for (const name of KIND_NAMES) { + const kind = OptionKind[name]; + expect(typeof kind).toEqual("number"); + + const options = AppOptions.getAll(kind); + expect(objectSize(options)).toBeGreaterThan(0); + } + }); +}); diff --git a/test/unit/clitests.json b/test/unit/clitests.json index 6ea14e1ed08b29..4a43e773f0d2b7 100644 --- a/test/unit/clitests.json +++ b/test/unit/clitests.json @@ -7,6 +7,7 @@ "annotation_spec.js", "annotation_storage_spec.js", "api_spec.js", + "app_options_spec.js", "bidi_spec.js", "cff_parser_spec.js", "cmap_spec.js", diff --git a/test/unit/jasmine-boot.js b/test/unit/jasmine-boot.js index 5852ae6daa8f6c..da98ceeb313771 100644 --- a/test/unit/jasmine-boot.js +++ b/test/unit/jasmine-boot.js @@ -50,6 +50,7 @@ async function initializePDFJS(callback) { "pdfjs-test/unit/annotation_spec.js", "pdfjs-test/unit/annotation_storage_spec.js", "pdfjs-test/unit/api_spec.js", + "pdfjs-test/unit/app_options_spec.js", "pdfjs-test/unit/bidi_spec.js", "pdfjs-test/unit/cff_parser_spec.js", "pdfjs-test/unit/cmap_spec.js", diff --git a/web/app_options.js b/web/app_options.js index 998a6ed2c2bcb2..538d8ebf23ce39 100644 --- a/web/app_options.js +++ b/web/app_options.js @@ -404,6 +404,34 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { const userOptions = Object.create(null); +if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING || LIB")) { + // Ensure that the `defaultOptions` are correctly specified. + for (const name in defaultOptions) { + const { value, kind } = defaultOptions[name]; + + if (kind & OptionKind.PREFERENCE) { + if (kind & OptionKind.BROWSER) { + throw new Error(`Cannot mix "PREFERENCE" and "BROWSER" kind: ${name}`); + } + if (compatibilityParams[name] !== undefined) { + throw new Error( + `Should not have compatibility-value for "PREFERENCE" kind: ${name}` + ); + } + const valueType = typeof value; + + if ( + valueType === "boolean" || + valueType === "string" || + (valueType === "number" && Number.isInteger(value)) + ) { + continue; // Only "simple" values are allowed. + } + throw new Error(`Invalid value for "PREFERENCE" kind: ${name}`); + } + } +} + class AppOptions { constructor() { throw new Error("Cannot initialize AppOptions."); @@ -421,36 +449,20 @@ class AppOptions { return undefined; } - static getAll(kind = null) { + static getAll(kind = null, defaultOnly = false) { const options = Object.create(null); for (const name in defaultOptions) { const defaultOption = defaultOptions[name]; - if (kind) { - if (!(kind & defaultOption.kind)) { - continue; - } - if ( - (typeof PDFJSDev === "undefined" || PDFJSDev.test("LIB")) && - kind === OptionKind.PREFERENCE - ) { - if (defaultOption.kind & OptionKind.BROWSER) { - throw new Error(`Invalid kind for preference: ${name}`); - } - const value = defaultOption.value, - valueType = typeof value; - if ( - valueType === "boolean" || - valueType === "string" || - (valueType === "number" && Number.isInteger(value)) - ) { - options[name] = value; - continue; - } - throw new Error(`Invalid type for preference: ${name}`); - } + if (kind && !(kind & defaultOption.kind)) { + continue; + } + if (defaultOnly) { + options[name] = defaultOption.value; + continue; } const userOption = userOptions[name]; + options[name] = userOption !== undefined ? userOption diff --git a/web/preferences.js b/web/preferences.js index b669f37420ebc0..312176fa864f56 100644 --- a/web/preferences.js +++ b/web/preferences.js @@ -23,7 +23,7 @@ import { AppOptions, OptionKind } from "./app_options.js"; class BasePreferences { #defaults = Object.freeze( typeof PDFJSDev === "undefined" - ? AppOptions.getAll(OptionKind.PREFERENCE) + ? AppOptions.getAll(OptionKind.PREFERENCE, /* defaultOnly = */ true) : PDFJSDev.eval("DEFAULT_PREFERENCES") ); @@ -48,7 +48,7 @@ class BasePreferences { ({ browserPrefs, prefs }) => { const BROWSER_PREFS = typeof PDFJSDev === "undefined" - ? AppOptions.getAll(OptionKind.BROWSER) + ? AppOptions.getAll(OptionKind.BROWSER, /* defaultOnly = */ true) : PDFJSDev.eval("BROWSER_PREFERENCES"); const options = Object.create(null);