diff options
Diffstat (limited to 'modules/libpref/test/test_generate_static_pref_list.py')
-rw-r--r-- | modules/libpref/test/test_generate_static_pref_list.py | 493 |
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..ef4c9d28ca --- /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() |