summaryrefslogtreecommitdiffstats
path: root/modules/libpref/test/test_generate_static_pref_list.py
diff options
context:
space:
mode:
Diffstat (limited to 'modules/libpref/test/test_generate_static_pref_list.py')
-rw-r--r--modules/libpref/test/test_generate_static_pref_list.py493
1 files changed, 493 insertions, 0 deletions
diff --git a/modules/libpref/test/test_generate_static_pref_list.py b/modules/libpref/test/test_generate_static_pref_list.py
new file mode 100644
index 0000000000..2c8797099e
--- /dev/null
+++ b/modules/libpref/test/test_generate_static_pref_list.py
@@ -0,0 +1,493 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import sys
+import unittest
+from os import path
+
+import mozpack.path as mozpath
+import mozunit
+import yaml
+
+try:
+ from StringIO import StringIO
+except ImportError:
+ from io import StringIO
+
+sys.path.append(path.join(path.dirname(__file__), ".."))
+from init.generate_static_pref_list import generate_code
+
+test_data_path = mozpath.abspath(mozpath.dirname(__file__))
+test_data_path = mozpath.join(test_data_path, "data")
+
+# A single good input with lots of different combinations.
+good_input = """
+- name: my.bool
+ type: bool
+ value: false
+ mirror: never
+
+- name: my.int
+ type: int32_t
+ value: -123
+ mirror: once
+ do_not_use_directly: false
+ rust: false
+
+- mirror: always
+ value: 999
+ type: uint32_t
+ name: my.uint
+ rust: true
+
+- name: my.float # A comment.
+ type: float # A comment.
+ do_not_use_directly: true # A comment.
+ value: 0.0f # A comment.
+ mirror: once # A comment.
+ rust: true # A comment.
+
+# A comment.
+- name: my.string
+ type: String
+ value: foo"bar # The double quote needs escaping.
+ mirror: never
+ include: foobar.h
+
+# A comment.
+- name: my.string2
+ type: String
+ value: "foobar" # This string is quoted.
+ mirror: never
+
+# A comment.
+- name: my.atomic.bool
+ type: RelaxedAtomicBool
+ value: true
+ mirror: always
+ rust: true
+
+# A comment.
+- name: my.datamutex.string
+ type: DataMutexString
+ value: "foobar" # This string is quoted.
+ mirror: always
+
+# Mirrored string-valued prefs are interesting in Rust.
+- name: my.datamutex.string.rust
+ type: DataMutexString
+ value: ""
+ mirror: always
+ rust: true
+
+# YAML+Python interprets `10 + 10 * 20` as a string, and so it is printed
+# unchanged.
+- name: my.atomic.int
+ type: ReleaseAcquireAtomicInt32
+ value: 10 + 10 * 20
+ mirror: always
+ do_not_use_directly: true # A comment.
+
+# YAML+Python changes `0x44` to `68` because it interprets the value as an
+# integer.
+- name: my.atomic.uint
+ type: SequentiallyConsistentAtomicUint32
+ value: 0x44
+ mirror: once
+
+# YAML+Python changes `.4455667` to `0.4455667` because it interprets the value
+# as a float.
+- name: my-dashed.atomic.float
+ type: AtomicFloat
+ value: .4455667
+ mirror: never
+ include: <math.h>
+"""
+
+# The corresponding code for good_input.
+good = {}
+
+good[
+ "static_pref_list_all_h"
+] = """\
+// This file was generated by generate_static_pref_list.py from (string input). DO NOT EDIT.
+
+#include "mozilla/StaticPrefList_my.h"
+#include "mozilla/StaticPrefList_my_dashed.h"
+"""
+
+good[
+ "static_prefs_all_h"
+] = """\
+// This file was generated by generate_static_pref_list.py from (string input). DO NOT EDIT.
+
+#include "mozilla/StaticPrefs_my.h"
+#include "mozilla/StaticPrefs_my_dashed.h"
+"""
+
+good["static_pref_list_group_h"] = {
+ "my": """\
+// This file was generated by generate_static_pref_list.py from (string input). DO NOT EDIT.
+
+NEVER_PREF("my.bool", bool, false)
+
+ONCE_PREF(
+ "my.int",
+ my_int,
+ my_int_AtStartup,
+ int32_t, -123
+)
+
+ALWAYS_PREF(
+ "my.uint",
+ my_uint,
+ my_uint,
+ uint32_t, 999
+)
+
+ONCE_PREF(
+ "my.float",
+ my_float,
+ my_float_AtStartup_DoNotUseDirectly,
+ float, 0.0f
+)
+
+NEVER_PREF("my.string", String, "foo\\"bar")
+
+NEVER_PREF("my.string2", String, "foobar")
+
+ALWAYS_PREF(
+ "my.atomic.bool",
+ my_atomic_bool,
+ my_atomic_bool,
+ RelaxedAtomicBool, true
+)
+
+ALWAYS_DATAMUTEX_PREF(
+ "my.datamutex.string",
+ my_datamutex_string,
+ my_datamutex_string,
+ DataMutexString, "foobar"_ns
+)
+
+ALWAYS_DATAMUTEX_PREF(
+ "my.datamutex.string.rust",
+ my_datamutex_string_rust,
+ my_datamutex_string_rust,
+ DataMutexString, ""_ns
+)
+
+ALWAYS_PREF(
+ "my.atomic.int",
+ my_atomic_int,
+ my_atomic_int_DoNotUseDirectly,
+ ReleaseAcquireAtomicInt32, 10 + 10 * 20
+)
+
+ONCE_PREF(
+ "my.atomic.uint",
+ my_atomic_uint,
+ my_atomic_uint_AtStartup,
+ SequentiallyConsistentAtomicUint32, 68
+)
+""",
+ "my_dashed": """\
+// This file was generated by generate_static_pref_list.py from (string input). DO NOT EDIT.
+
+NEVER_PREF("my-dashed.atomic.float", AtomicFloat, 0.4455667)
+""",
+}
+
+good["static_prefs_group_h"] = {
+ "my": """\
+// This file was generated by generate_static_pref_list.py from (string input). DO NOT EDIT.
+// Include it to gain access to StaticPrefs::my_*.
+
+#ifndef mozilla_StaticPrefs_my_h
+#define mozilla_StaticPrefs_my_h
+
+#include "foobar.h"
+
+#include "mozilla/StaticPrefListBegin.h"
+#include "mozilla/StaticPrefList_my.h"
+#include "mozilla/StaticPrefListEnd.h"
+
+#endif // mozilla_StaticPrefs_my_h
+"""
+}
+
+good[
+ "static_prefs_c_getters_cpp"
+] = """\
+// This file was generated by generate_static_pref_list.py from (string input). DO NOT EDIT.
+
+extern "C" uint32_t StaticPrefs_my_uint() {
+ return mozilla::StaticPrefs::my_uint();
+}
+
+extern "C" float StaticPrefs_my_float_AtStartup_DoNotUseDirectly() {
+ return mozilla::StaticPrefs::my_float_AtStartup_DoNotUseDirectly();
+}
+
+extern "C" bool StaticPrefs_my_atomic_bool() {
+ return mozilla::StaticPrefs::my_atomic_bool();
+}
+
+extern "C" void StaticPrefs_my_datamutex_string_rust(nsACString *result) {
+ const auto preflock = mozilla::StaticPrefs::my_datamutex_string_rust();
+ result->Append(*preflock);
+}
+"""
+
+good[
+ "static_prefs_rs"
+] = """\
+// This file was generated by generate_static_pref_list.py from (string input). DO NOT EDIT.
+
+pub use nsstring::nsCString;
+extern "C" {
+ pub fn StaticPrefs_my_uint() -> u32;
+ pub fn StaticPrefs_my_float_AtStartup_DoNotUseDirectly() -> f32;
+ pub fn StaticPrefs_my_atomic_bool() -> bool;
+ pub fn StaticPrefs_my_datamutex_string_rust(result: *mut nsstring::nsACString);
+}
+
+#[macro_export]
+macro_rules! pref {
+ ("my.uint") => (unsafe { $crate::StaticPrefs_my_uint() });
+ ("my.float") => (unsafe { $crate::StaticPrefs_my_float_AtStartup_DoNotUseDirectly() });
+ ("my.atomic.bool") => (unsafe { $crate::StaticPrefs_my_atomic_bool() });
+ ("my.datamutex.string.rust") => (unsafe { let mut result = $crate::nsCString::new(); $crate::StaticPrefs_my_datamutex_string_rust(&mut *result); result });
+}
+"""
+
+# A lot of bad inputs, each with an accompanying error message. Listed in order
+# of the relevant `error` calls within generate_static_pref_list.py.
+bad_inputs = [
+ (
+ """
+- invalidkey: 3
+""",
+ "invalid key `invalidkey`",
+ ),
+ (
+ """
+- type: int32_t
+""",
+ "missing `name` key",
+ ),
+ (
+ """
+- name: 99
+""",
+ "non-string `name` value `99`",
+ ),
+ (
+ """
+- name: name_with_no_dot
+""",
+ "`name` value `name_with_no_dot` lacks a '.'",
+ ),
+ (
+ """
+- name: pref.is.defined.more.than.once
+ type: bool
+ value: false
+ mirror: never
+- name: pref.is.defined.more.than.once
+ type: int32_t
+ value: 111
+ mirror: always
+""",
+ "`pref.is.defined.more.than.once` pref is defined more than once",
+ ),
+ (
+ """
+- name: your.pref
+ type: bool
+ value: false
+ mirror: never
+- name: my.pref
+ type: bool
+ value: false
+ mirror: never
+""",
+ "`my.pref` pref must come before `your.pref` pref",
+ ),
+ (
+ """
+- name: missing.type.key
+ value: false
+ mirror: never
+""",
+ "missing `type` key for pref `missing.type.key`",
+ ),
+ (
+ """
+- name: invalid.type.value
+ type: const char*
+ value: true
+ mirror: never
+""",
+ "invalid `type` value `const char*` for pref `invalid.type.value`",
+ ),
+ (
+ """
+- name: missing.value.key
+ type: int32_t
+ mirror: once
+""",
+ "missing `value` key for pref `missing.value.key`",
+ ),
+ (
+ """
+- name: non-string.value
+ type: String
+ value: 3.45
+ mirror: once
+""",
+ "non-string `value` value `3.45` for `String` pref `non-string.value`; add double quotes",
+ ),
+ (
+ """
+- name: invalid.boolean.value
+ type: bool
+ value: true || false
+ mirror: once
+""",
+ "invalid boolean value `true || false` for pref `invalid.boolean.value`",
+ ),
+ (
+ """
+- name: missing.mirror.key
+ type: int32_t
+ value: 3
+""",
+ "missing `mirror` key for pref `missing.mirror.key`",
+ ),
+ (
+ """
+- name: invalid.mirror.value
+ type: bool
+ value: true
+ mirror: sometimes
+""",
+ "invalid `mirror` value `sometimes` for pref `invalid.mirror.value`",
+ ),
+ (
+ """
+- name: non-boolean.do_not_use_directly.value
+ type: bool
+ value: true
+ mirror: always
+ do_not_use_directly: 0
+""",
+ "non-boolean `do_not_use_directly` value `0` for pref "
+ "`non-boolean.do_not_use_directly.value`",
+ ),
+ (
+ """
+- name: do_not_use_directly.uselessly.set
+ type: int32_t
+ value: 0
+ mirror: never
+ do_not_use_directly: true
+""",
+ "`do_not_use_directly` uselessly set with `mirror` value `never` for "
+ "pref `do_not_use_directly.uselessly.set`",
+ ),
+ (
+ """
+- name: non-string.include.value
+ type: bool
+ value: true
+ mirror: always
+ include: 33
+""",
+ "non-string `include` value `33` for pref `non-string.include.value`",
+ ),
+ (
+ """
+- name: include.value.starts.with
+ type: float
+ value: M_PI
+ mirror: never
+ include: <cmath
+""",
+ "`include` value `<cmath` starts with `<` but does not end with `>` for "
+ "pref `include.value.starts.with`",
+ ),
+ (
+ """
+- name: non-boolean.rust.value
+ type: bool
+ value: true
+ mirror: always
+ rust: 1
+""",
+ "non-boolean `rust` value `1` for pref `non-boolean.rust.value`",
+ ),
+ (
+ """
+- name: rust.uselessly.set
+ type: int32_t
+ value: 0
+ mirror: never
+ rust: true
+""",
+ "`rust` uselessly set with `mirror` value `never` for pref "
+ "`rust.uselessly.set`",
+ ),
+]
+
+
+class TestGenerateStaticPrefList(unittest.TestCase):
+ """
+ Unit tests for generate_static_pref_list.py.
+ """
+
+ def test_good(self):
+ "Test various pieces of good input."
+ inp = StringIO(good_input)
+ pref_list = yaml.safe_load(inp)
+ code = generate_code(pref_list, "(string input)")
+
+ self.assertEqual(good["static_pref_list_all_h"], code["static_pref_list_all_h"])
+
+ self.assertEqual(good["static_prefs_all_h"], code["static_prefs_all_h"])
+
+ self.assertEqual(
+ good["static_pref_list_group_h"]["my"],
+ code["static_pref_list_group_h"]["my"],
+ )
+ self.assertEqual(
+ good["static_pref_list_group_h"]["my_dashed"],
+ code["static_pref_list_group_h"]["my_dashed"],
+ )
+
+ self.assertEqual(
+ good["static_prefs_group_h"]["my"], code["static_prefs_group_h"]["my"]
+ )
+
+ self.assertEqual(
+ good["static_prefs_c_getters_cpp"], code["static_prefs_c_getters_cpp"]
+ )
+
+ self.assertEqual(good["static_prefs_rs"], code["static_prefs_rs"])
+
+ def test_bad(self):
+ "Test various pieces of bad input."
+
+ for (input_string, expected) in bad_inputs:
+ inp = StringIO(input_string)
+ try:
+ pref_list = yaml.safe_load(inp)
+ generate_code(pref_list, "(string input")
+ self.assertEqual(0, 1)
+ except ValueError as e:
+ self.assertEqual(str(e), expected)
+
+
+if __name__ == "__main__":
+ mozunit.main()