| # Copyright 2022 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import abc |
| import unittest |
| |
| from crossbench.flags.base import Flags, FrozenFlagsError |
| from crossbench.flags.chrome import (ChromeBaseFeatures, ChromeBlinkFeatures, |
| ChromeFeatures, ChromeFlags) |
| from crossbench.flags.js_flags import JSFlags |
| from crossbench.flags.known_chrome_flags import KNOWN_CHROME_FLAGS |
| from crossbench.flags.known_js_flags import KNOWN_JS_FLAGS |
| from tests import test_helper |
| |
| |
| class TestFlags(unittest.TestCase): |
| |
| CLASS = Flags |
| |
| def test_construct(self): |
| flags = self.CLASS() |
| self.assertEqual(len(flags), 0) |
| self.assertNotIn("foo", flags) |
| |
| def test_construct_dict(self): |
| flags = self.CLASS({"--foo": "v1", "--bar": "v2"}) |
| self.assertIn("--foo", flags) |
| self.assertIn("--bar", flags) |
| self.assertEqual(flags["--foo"], "v1") |
| self.assertEqual(flags["--bar"], "v2") |
| |
| def test_construct_list(self): |
| flags = self.CLASS(("--foo", "--bar")) |
| self.assertIn("--foo", flags) |
| self.assertIn("--bar", flags) |
| self.assertIsNone(flags["--foo"]) |
| self.assertIsNone(flags["--bar"]) |
| with self.assertRaises(ValueError): |
| self.CLASS(("--foo=v1", "--bar=v2")) |
| flags = self.CLASS((("--foo", "v3"), "--bar")) |
| self.assertEqual(flags["--foo"], "v3") |
| self.assertIsNone(flags["--bar"]) |
| |
| def test_construct_flags(self): |
| original_flags = self.CLASS({"--foo": "v1", "--bar": "v2"}) |
| flags = self.CLASS(original_flags) |
| self.assertIn("--foo", flags) |
| self.assertIn("--bar", flags) |
| self.assertEqual(flags["--foo"], "v1") |
| self.assertEqual(flags["--bar"], "v2") |
| |
| def test_set(self): |
| flags = self.CLASS() |
| flags["--foo"] = "v1" |
| with self.assertRaises(ValueError): |
| flags["--foo"] = "v2" |
| # setting the same value is ok |
| flags["--foo"] = "v1" |
| self.assertEqual(flags["--foo"], "v1") |
| flags.set("--bar") |
| self.assertIn("--foo", flags) |
| self.assertIn("--bar", flags) |
| self.assertIsNone(flags["--bar"]) |
| with self.assertRaises(ValueError): |
| flags.set("--bar", "v3") |
| flags.set("--bar", "v4", override=True) |
| self.assertEqual(flags["--foo"], "v1") |
| self.assertEqual(flags["--bar"], "v4") |
| |
| def test_set_invalid(self): |
| flags = self.CLASS() |
| with self.assertRaises(TypeError) as cm: |
| flags["--foo"] = 123 # pytype: disable=unsupported-operands |
| self.assertIn("123", str(cm.exception)) |
| with self.assertRaises(ValueError) as cm: |
| flags["foo"] = 123 # pytype: disable=unsupported-operands |
| self.assertIn("-", str(cm.exception)) |
| |
| def test_set_invalid_flag_name(self): |
| flags = self.CLASS() |
| for invalid in ("- -foo", "--f oo", "", "-", "--", "--foo\n", "--\nfoo", |
| "--foo,"): |
| with self.subTest(invalid_flag=invalid): |
| with self.assertRaises(ValueError): |
| flags.set(invalid) |
| self.assertFalse(invalid in flags) |
| |
| def test_get_list(self): |
| flags = self.CLASS({"--foo": "v1", "--bar": None}) |
| self.assertEqual(list(flags), ["--foo=v1", "--bar"]) |
| |
| def test_copy(self): |
| flags = self.CLASS({"--foo": "v1", "--bar": None}) |
| copy = flags.copy() |
| self.assertEqual(list(flags), list(copy)) |
| self.assertEqual(str(flags), str(copy)) |
| self.assertTrue(copy) |
| |
| def test_copy_frozen(self): |
| flags = self.CLASS({"--foo": "v1", "--bar": None}) |
| flags.freeze() |
| self.assertTrue(flags.is_frozen) |
| copy = flags.copy() |
| with self.assertRaises(FrozenFlagsError): |
| flags["--custom"] = "123" |
| self.assertNotIn("--custom", flags) |
| copy["--custom"] = "123" |
| self.assertEqual(copy["--custom"], "123") |
| copy.freeze() |
| with self.assertRaises(FrozenFlagsError): |
| copy["--custom-other"] = "123" |
| |
| def test_update(self): |
| flags = self.CLASS({"--foo": "v1", "--bar": None}) |
| with self.assertRaises(ValueError): |
| flags.update({"--bar": "v2"}) |
| self.assertEqual(flags["--foo"], "v1") |
| self.assertIsNone(flags["--bar"]) |
| flags.update({"--bar": "v2"}, override=True) |
| self.assertEqual(flags["--foo"], "v1") |
| self.assertEqual(flags["--bar"], "v2") |
| self.assertTrue(flags) |
| |
| def test_str_basic(self): |
| flags = self.CLASS({"--foo": None}) |
| self.assertEqual(str(flags), "--foo") |
| flags = self.CLASS({"--foo": "bar"}) |
| self.assertEqual(str(flags), "--foo=bar") |
| |
| def test_str_multiple(self): |
| flags = self.CLASS({ |
| "--flag1": "value1", |
| "--flag2": None, |
| "--flag3": "value3" |
| }) |
| self.assertEqual(str(flags), "--flag1=value1 --flag2 --flag3=value3") |
| |
| def test_merge(self): |
| flags = self.CLASS({"--foo": "v1", "--bar": None}) |
| with self.assertRaises(ValueError): |
| flags.merge({"--bar": "v2"}) |
| self.assertEqual(flags["--foo"], "v1") |
| self.assertIsNone(flags["--bar"]) |
| self.assertTrue(flags) |
| |
| def test_parse_single(self): |
| flags = self.CLASS.parse("--foo") |
| self.assertEqual(len(flags), 1) |
| self.assertTrue(flags) |
| self.assertEqual(flags["--foo"], None) |
| self.assertEqual(str(flags), "--foo") |
| |
| flags = self.CLASS.parse("--foo=123") |
| self.assertEqual(len(flags), 1) |
| self.assertTrue(flags) |
| self.assertEqual(flags["--foo"], "123") |
| self.assertEqual(str(flags), "--foo=123") |
| |
| flags = self.CLASS.parse("--foo=--bar123") |
| self.assertEqual(len(flags), 1) |
| self.assertTrue(flags) |
| self.assertEqual(flags["--foo"], "--bar123") |
| self.assertEqual(str(flags), "--foo=--bar123") |
| |
| def test_parse_nested(self): |
| flags = self.CLASS.parse("--foo=--bar=123") |
| self.assertEqual(len(flags), 1) |
| self.assertTrue(flags) |
| self.assertEqual(flags["--foo"], "--bar=123") |
| self.assertEqual(str(flags), "--foo=--bar=123") |
| |
| def test_parse_multiple(self): |
| flags = self.CLASS.parse("--foo --bar") |
| self.assertEqual(len(flags), 2) |
| self.assertTrue(flags) |
| self.assertEqual(flags["--foo"], None) |
| self.assertEqual(flags["--bar"], None) |
| flags = self.CLASS.parse("--foo --bar=1") |
| self.assertEqual(len(flags), 2) |
| self.assertTrue(flags) |
| self.assertEqual(flags["--foo"], None) |
| self.assertEqual(flags["--bar"], "1") |
| flags = self.CLASS.parse("--foo=1 --bar=2") |
| self.assertEqual(len(flags), 2) |
| self.assertTrue(flags) |
| self.assertEqual(flags["--foo"], "1") |
| self.assertEqual(flags["--bar"], "2") |
| flags = self.CLASS.parse("--foo='1' --bar='2'") |
| self.assertEqual(len(flags), 2) |
| self.assertTrue(flags) |
| self.assertEqual(flags["--foo"], "1") |
| self.assertEqual(flags["--bar"], "2") |
| |
| def test_hashable(self): |
| flags = self.CLASS.parse("--foo") |
| flags["--bar"] = "10" |
| test_set = {flags} |
| self.assertIn(flags, test_set) |
| self.assertIn(self.CLASS.parse("--foo --bar=10"), test_set) |
| self.assertNotIn(self.CLASS.parse("--foo --bar=999"), test_set) |
| # post-hash modification are not allowed anymore: |
| with self.assertRaises(FrozenFlagsError) as cm: |
| flags["--bar"] = "0" |
| self.assertIn("frozen", str(cm.exception)) |
| |
| def test_iter(self): |
| flags = self.CLASS.parse("--foo --bar=1") |
| self.assertListEqual(list(flags), ["--foo", "--bar=1"]) |
| self.assertListEqual([*flags], ["--foo", "--bar=1"]) |
| |
| def test_bool_basic(self): |
| self.assertFalse(self.CLASS()) |
| self.assertTrue(self.CLASS.parse("--foo --bar")) |
| |
| |
| class TestChromeFlags(TestFlags): |
| |
| CLASS = ChromeFlags |
| |
| def test_js_flags(self): |
| flags = self.CLASS({ |
| "--foo": None, |
| "--bar": "v1", |
| }) |
| self.assertIsNone(flags["--foo"]) |
| self.assertEqual(flags["--bar"], "v1") |
| self.assertTrue(flags) |
| self.assertFalse(flags.js_flags) |
| self.assertNotIn("--js-flags", flags) |
| with self.assertRaises(ValueError): |
| flags["--js-flags"] = "--js-foo, --no-js-foo" |
| flags["--js-flags"] = "--js-foo=v3, --no-js-bar" |
| with self.assertRaises(ValueError): |
| flags["--js-flags"] = "--js-foo=v4, --no-js-bar" |
| js_flags = flags.js_flags |
| self.assertTrue(js_flags) |
| self.assertNotIn(flags["--js-flags"], js_flags) |
| self.assertEqual(js_flags["--js-foo"], "v3") |
| self.assertIsNone(js_flags["--no-js-bar"]) |
| |
| def test_set_empty_js_flags(self): |
| flags = self.CLASS({ |
| "--foo": None, |
| "--bar": "v1", |
| }) |
| self.assertNotIn("--js-flags", flags) |
| self.assertTrue(flags) |
| with self.assertRaises(ValueError): |
| flags["--js-flags"] = None |
| self.assertNotIn("--js-flags", flags) |
| self.assertFalse(flags.js_flags) |
| flags["--js-flags"] = "" |
| self.assertNotIn("--js-flags", flags) |
| self.assertFalse(flags.js_flags) |
| flags["--js-flags"] = " " |
| self.assertNotIn("--js-flags", flags) |
| self.assertFalse(flags.js_flags) |
| |
| def test_set_js_flags_invalid(self): |
| flags = self.CLASS() |
| for invalid in ("-foo", "--bar'f'", "--", "-8", "--8"): |
| with self.subTest(js_flag=invalid): |
| with self.assertRaises(ValueError) as cm: |
| flags["--js-flags"] = invalid |
| self.assertNotIn("--js-flags", flags) |
| self.assertIn(invalid, str(cm.exception)) |
| for invalid in ("--foo=", "--foo,--bar=,--baz", "---foo", "--foo,--,--bar", |
| "--foo;;;,;;;--bar"): |
| with self.subTest(js_flag=invalid): |
| with self.assertRaises(ValueError) as cm: |
| flags["--js-flags"] = invalid |
| self.assertNotIn("--js-flags", flags) |
| |
| def test_js_flags_initial_data(self): |
| flags = self.CLASS({ |
| "--js-flags": "--foo=v1,--no-bar", |
| }) |
| js_flags = flags.js_flags |
| self.assertEqual(js_flags["--foo"], "v1") |
| self.assertIsNone(js_flags["--no-bar"]) |
| self.assertTrue(flags) |
| self.assertTrue(flags.js_flags) |
| |
| def test_features(self): |
| flags = self.CLASS() |
| features = flags.features |
| self.assertFalse(flags) |
| self.assertFalse(flags.features) |
| self.assertTrue(features.is_empty) |
| flags["--enable-features"] = "F1,F2" |
| self.assertTrue(flags) |
| self.assertTrue(flags.features) |
| with self.assertRaises(ValueError): |
| flags["--disable-features"] = "F1,F2" |
| with self.assertRaises(ValueError): |
| flags["--disable-features"] = "F2,F1" |
| flags["--disable-features"] = "F3,F4" |
| self.assertEqual(features.enabled, {"F1": None, "F2": None}) |
| self.assertEqual(flags["--enable-features"], "F1,F2") |
| self.assertEqual(features.disabled, set(("F3", "F4"))) |
| self.assertEqual(flags["--disable-features"], "F3,F4") |
| self.assertTrue(flags) |
| self.assertTrue(flags.features) |
| |
| def test_blink_features(self): |
| flags = self.CLASS() |
| features = flags.blink_features |
| self.assertFalse(flags) |
| self.assertFalse(flags.blink_features) |
| self.assertTrue(features.is_empty) |
| flags["--enable-blink-features"] = "F1,F2" |
| self.assertTrue(flags) |
| self.assertTrue(flags.blink_features) |
| with self.assertRaises(ValueError): |
| flags["--disable-blink-features"] = "F1,F2" |
| with self.assertRaises(ValueError): |
| flags["--disable-blink-features"] = "F2,F1" |
| flags["--disable-blink-features"] = "F3,F4" |
| self.assertEqual(features.enabled, {"F1": None, "F2": None}) |
| self.assertEqual(flags["--enable-blink-features"], "F1,F2") |
| self.assertEqual(features.disabled, set(("F3", "F4"))) |
| self.assertEqual(flags["--disable-blink-features"], "F3,F4") |
| |
| def test_features_invalid_none(self): |
| flags = self.CLASS() |
| features = flags.features |
| self.assertFalse(features) |
| self.assertTrue(features.is_empty) |
| with self.assertRaises(ValueError): |
| flags["--disable-features"] = None |
| self.assertFalse(features) |
| self.assertTrue(features.is_empty) |
| with self.assertRaises(ValueError): |
| flags["--enable-features"] = None |
| self.assertFalse(features) |
| self.assertTrue(features.is_empty) |
| |
| def test_blink_features_invalid_none(self): |
| flags = self.CLASS() |
| features = flags.blink_features |
| self.assertTrue(features.is_empty) |
| with self.assertRaises(ValueError): |
| flags["--disable-blink-features"] = None |
| self.assertTrue(features.is_empty) |
| with self.assertRaises(ValueError): |
| flags["--enable-blink-features"] = None |
| self.assertNotIn("--enable-blink-features", flags) |
| self.assertTrue(features.is_empty) |
| |
| def test_user_data_dir(self): |
| flags = self.CLASS() |
| for invalid in (None, "", " "): |
| with self.subTest(user_dat_dir=invalid): |
| with self.assertRaises(ValueError) as cm: |
| flags["--user-data-dir"] = invalid |
| self.assertIn("empty string", str(cm.exception)) |
| |
| def test_get_list(self): |
| flags = self.CLASS() |
| flags["--user-data-dir"] = "/tmp" |
| flags.set("--single-process") |
| flags["--js-flags"] = "--js-foo=v3, --no-js-bar" |
| flags["--enable-features"] = "F1,F2" |
| flags["--disable-features"] = "F3,F4" |
| flags["--enable-blink-features"] = "BLINK_F1,BLINK_F2" |
| flags["--disable-blink-features"] = "BLINK_F3,BLINK_F4" |
| flags_list = list(flags) |
| self.assertListEqual(flags_list, [ |
| "--user-data-dir=/tmp", |
| "--single-process", |
| "--js-flags=--js-foo=v3,--no-js-bar", |
| "--enable-features=F1,F2", |
| "--disable-features=F3,F4", |
| "--enable-blink-features=BLINK_F1,BLINK_F2", |
| "--disable-blink-features=BLINK_F3,BLINK_F4", |
| ]) |
| |
| def test_to_dict(self): |
| flags = self.CLASS() |
| flags["--user-data-dir"] = "/tmp" |
| flags.set("--single-process") |
| flags["--js-flags"] = "--js-foo=v3, --no-js-bar" |
| flags["--enable-features"] = "F1,F2" |
| flags["--disable-features"] = "F3,F4" |
| flags["--enable-blink-features"] = "BLINK_F1,BLINK_F2" |
| flags["--disable-blink-features"] = "BLINK_F3,BLINK_F4" |
| self.assertDictEqual( |
| flags.to_dict(), { |
| "--user-data-dir": "/tmp", |
| "--single-process": None, |
| "--js-flags": "--js-foo=v3,--no-js-bar", |
| "--enable-features": "F1,F2", |
| "--disable-features": "F3,F4", |
| "--enable-blink-features": "BLINK_F1,BLINK_F2", |
| "--disable-blink-features": "BLINK_F3,BLINK_F4", |
| }) |
| |
| def test_initial_data_empty(self): |
| flags = self.CLASS() |
| flags_copy = self.CLASS(flags) |
| self.assertListEqual(list(flags), list(flags_copy)) |
| self.assertFalse(flags_copy) |
| flags_copy = self.CLASS() |
| flags_copy.update(flags) |
| self.assertListEqual(list(flags), list(flags_copy)) |
| self.assertFalse(flags_copy) |
| |
| def test_initial_data_simple(self): |
| flags = self.CLASS() |
| flags["--no-sandbox"] = None |
| flags_copy = self.CLASS(flags) |
| self.assertListEqual(list(flags), list(flags_copy)) |
| self.assertTrue(flags_copy) |
| flags_copy = self.CLASS() |
| flags_copy.update(flags) |
| self.assertListEqual(list(flags), list(flags_copy)) |
| self.assertTrue(flags_copy) |
| |
| def test_initial_data_js_flags(self): |
| flags = self.CLASS() |
| flags["--js-flags"] = "--js-foo=v3, --no-js-bar" |
| flags_copy = self.CLASS(flags) |
| self.assertListEqual(list(flags), list(flags_copy)) |
| self.assertTrue(flags_copy) |
| flags_copy = self.CLASS() |
| flags_copy.update(flags) |
| self.assertListEqual(list(flags), list(flags_copy)) |
| self.assertTrue(flags_copy) |
| |
| def test_initial_data_features(self): |
| flags = self.CLASS() |
| flags["--enable-features"] = "F1,F2" |
| flags["--disable-features"] = "F3,F4" |
| flags_copy = self.CLASS(flags) |
| self.assertListEqual(list(flags), list(flags_copy)) |
| self.assertTrue(flags_copy) |
| flags_copy = self.CLASS() |
| flags_copy.update(flags) |
| self.assertListEqual(list(flags), list(flags_copy)) |
| self.assertTrue(flags_copy) |
| |
| def test_initial_data_blink_features(self): |
| flags = self.CLASS() |
| flags["--enable-blink-features"] = "BLINK_F1,BLINK_F2" |
| flags["--disable-blink-features"] = "BLINK_F3,BLINK_F4" |
| flags_copy = self.CLASS(flags) |
| self.assertListEqual(list(flags), list(flags_copy)) |
| self.assertTrue(flags_copy) |
| flags_copy = self.CLASS() |
| flags_copy.update(flags) |
| self.assertListEqual(list(flags), list(flags_copy)) |
| self.assertTrue(flags_copy) |
| |
| def test_initial_data_all(self): |
| flags = self.CLASS() |
| flags["--no-sandbox"] = None |
| flags["--js-flags"] = "--js-foo=v3, --no-js-bar" |
| flags["--enable-features"] = "F1,F2" |
| flags["--disable-features"] = "F3,F4" |
| flags["--enable-blink-features"] = "BLINK_F1,BLINK_F2" |
| flags["--disable-blink-features"] = "BLINK_F3,BLINK_F4" |
| flags_copy = self.CLASS(flags) |
| self.assertListEqual(list(flags), list(flags_copy)) |
| self.assertTrue(flags_copy) |
| flags_copy = self.CLASS() |
| flags_copy.update(flags) |
| self.assertListEqual(list(flags), list(flags_copy)) |
| self.assertTrue(flags_copy) |
| |
| def test_set_js_flags(self): |
| flags = self.CLASS() |
| flags["--js-flags"] = "--foo=a/b/c-d-e.log,--bar=a--b/c ,--no-baz" |
| self.assertEqual(flags.js_flags["--foo"], "a/b/c-d-e.log") |
| self.assertEqual(flags.js_flags["--bar"], "a--b/c") |
| self.assertEqual(flags.js_flags["--no-baz"], None) |
| |
| def test_js_flags_separators(self): |
| flags_1 = self.CLASS() |
| flags_1["--js-flags"] = "--f-one=1,--no-f-two,--f-three=3" |
| flags_2 = self.CLASS() |
| flags_2["--js-flags"] = "--f-one=1 --no-f-two --f-three=3" |
| flags_3 = self.CLASS() |
| flags_3["--js-flags"] = "--f-one='1',--no-f-two,--f-three=\"3\"" |
| flags_4 = self.CLASS() |
| flags_4["--js-flags"] = "--f-one='1' --no-f-two, --f-three=\"3\"" |
| |
| list_1 = list(flags_1.js_flags) |
| list_2 = list(flags_2.js_flags) |
| self.assertListEqual(list_1, list_2) |
| list_3 = list(flags_3.js_flags) |
| self.assertListEqual(list_1, list_3) |
| list_4 = list(flags_4.js_flags) |
| self.assertListEqual(list_1, list_4) |
| |
| for flags in (flags_1, flags_2, flags_3): |
| self.assertEqual(flags.js_flags["--f-one"], "1") |
| self.assertEqual(flags.js_flags["--no-f-two"], None) |
| self.assertEqual(flags.js_flags["--f-three"], "3") |
| |
| def test_set_invalid_js_flags(self): |
| flags = self.CLASS() |
| flags["--js-flags"] = "--foo=1--bar" |
| for invalid in ("--bar,=", "-bar=1", "--bar,,", "--", "-", "a=b", |
| "--bar==1", "--bar==--bar", "--bar='1\", --foo=1", |
| "--foo='1'--bar", "--bar='a b c'"): |
| with self.subTest(invalid=invalid): |
| with self.assertRaises(ValueError): |
| flags["--js-flags"] = invalid |
| |
| def test_merge(self): |
| flags = self.CLASS({ |
| "--foo": "v1", |
| "--bar": None, |
| "--js-flags": "--log-maps,--log-ic", |
| "--enable-features": "feature_1,feature_2", |
| "--disable-features": "feature_3", |
| "--enable-blink-features": "blink_feature_1,blink_feature_2", |
| "--disable-blink-features": "blink_feature_3" |
| }) |
| with self.assertRaises(ValueError): |
| flags.merge({"--bar": "v2"}) |
| with self.assertRaises(ValueError): |
| flags.merge({"--js-flags": "--no-log-maps"}) |
| with self.assertRaises(ValueError): |
| flags.merge({"--disable-features": "feature_1,"}) |
| with self.assertRaises(ValueError): |
| flags.merge({"--enable-features": "feature_3"}) |
| with self.assertRaises(ValueError): |
| flags.merge({"--enable-blink-features": "blink_feature_3"}) |
| flags.merge({ |
| "--js-flags": "--log-all", |
| "--enable-features": "feature_x", |
| "--disable-features": "feature_y,feature_z", |
| "--enable-blink-features": "blink_feature_x", |
| "--disable-blink-features": "blink_feature_y,blink_feature_z" |
| }) |
| self.assertListEqual( |
| list(flags.js_flags), ["--log-maps", "--log-ic", "--log-all"]) |
| self.assertListEqual( |
| list(flags.features), [ |
| "--enable-features=feature_1,feature_2,feature_x", |
| "--disable-features=feature_3,feature_y,feature_z" |
| ]) |
| self.assertListEqual( |
| list(flags.blink_features), [ |
| "--enable-blink-features=blink_feature_1,blink_feature_2,blink_feature_x", |
| "--disable-blink-features=blink_feature_3,blink_feature_y,blink_feature_z" |
| ]) |
| |
| def test_flag_typos_enable_features(self): |
| for invalid_flag in ("--enable-feature", "--enabled-feature", |
| "--enabled-features"): |
| with self.assertLogs(level="ERROR") as cm: |
| self.CLASS({invalid_flag: "feature_1"}) |
| output = "\n".join(cm.output) |
| self.assertIn(invalid_flag, output) |
| self.assertIn("--enable-features", output) |
| |
| for invalid_flag in ("--disable-feature", "--disabled-feature", |
| "--disabled-features"): |
| with self.assertLogs(level="ERROR") as cm: |
| self.CLASS({invalid_flag: "feature_1"}) |
| output = "\n".join(cm.output) |
| self.assertIn(invalid_flag, output) |
| self.assertIn("--disable-features", output) |
| |
| def test_flag_typos_enable_blink_features(self): |
| for invalid_flag in ("--enable-blink-feature", "--enabled-blink-feature", |
| "--enabled-blink-features"): |
| with self.assertLogs(level="ERROR") as cm: |
| self.CLASS({invalid_flag: "feature_1"}) |
| output = "\n".join(cm.output) |
| self.assertIn(invalid_flag, output) |
| self.assertIn("--enable-blink-features", output) |
| |
| for invalid_flag in ("--disable-blink-feature", "--disabled-blink-feature", |
| "--disabled-blink-features"): |
| with self.assertLogs(level="ERROR") as cm: |
| self.CLASS({invalid_flag: "feature_1"}) |
| output = "\n".join(cm.output) |
| self.assertIn(invalid_flag, output) |
| self.assertIn("--disable-blink-features", output) |
| |
| def test_flag_js_flags_as_chrome_flags(self): |
| for invalid_flag in ("--no-maglev", "--maglev"): |
| flags = self.CLASS() |
| with self.assertLogs(level="ERROR") as cm: |
| flags.set(invalid_flag) |
| self.assertIn(invalid_flag, str(cm.output)) |
| self.assertIn(invalid_flag, flags) |
| |
| def test_known_flags(self): |
| for chrome_flag in KNOWN_CHROME_FLAGS: |
| self.assertNotIn("=", chrome_flag, "Only allow names, no values") |
| |
| def test_known_flags_chrome_overlap(self): |
| for chrome_flag in KNOWN_CHROME_FLAGS: |
| self.assertNotIn(chrome_flag, KNOWN_JS_FLAGS) |
| |
| class TestJSFlags(TestFlags): |
| |
| CLASS = JSFlags |
| |
| def test_invalid_js_flags(self): |
| flags = self.CLASS() |
| with self.assertRaises(ValueError) as cm: |
| flags.set("-foo") |
| self.assertIn("'-foo'", str(cm.exception)) |
| with self.assertRaises(ValueError) as cm: |
| flags.set("--foo,--bar") |
| self.assertIn("'--foo,--bar'", str(cm.exception)) |
| with self.assertRaises(ValueError) as cm: |
| flags.set("--v8-log", "foo,bar") |
| self.assertIn("comma", str(cm.exception).lower()) |
| self.assertIn("--v8-log", str(cm.exception)) |
| self.assertIn("foo,bar", str(cm.exception)) |
| with self.assertRaises(ValueError) as cm: |
| flags["--foo"] = "a b c d" |
| self.assertIn("whitespace", str(cm.exception).lower()) |
| self.assertIn("--foo", str(cm.exception)) |
| self.assertIn("a b c d", str(cm.exception)) |
| |
| def test_conflicting_flags(self): |
| with self.assertRaises(ValueError): |
| flags = self.CLASS(("--foo", "--no-foo")) |
| with self.assertRaises(ValueError): |
| flags = self.CLASS(("--foo", "--nofoo")) |
| flags = self.CLASS(("--foo", "--no-bar")) |
| self.assertIsNone(flags["--foo"]) |
| self.assertIsNone(flags["--no-bar"]) |
| self.assertIn("--foo", flags) |
| self.assertNotIn("--no-foo", flags) |
| self.assertNotIn("--bar", flags) |
| self.assertIn("--no-bar", flags) |
| |
| def test_conflicting_override(self): |
| flags = self.CLASS(("--foo", "--no-bar")) |
| with self.assertRaises(ValueError): |
| flags.set("--no-foo") |
| with self.assertRaises(ValueError): |
| flags.set("--nofoo") |
| flags.set("--nobar") |
| with self.assertRaises(ValueError): |
| flags.set("--bar") |
| with self.assertRaises(ValueError): |
| flags.set("--foo", "v2") |
| self.assertIsNone(flags["--foo"]) |
| self.assertIsNone(flags["--no-bar"]) |
| |
| flags.set("--no-foo", override=True) |
| self.assertNotIn("--foo", flags) |
| self.assertIn("--no-foo", flags) |
| self.assertNotIn("--bar", flags) |
| self.assertIn("--no-bar", flags) |
| |
| flags.set("--bar", override=True) |
| self.assertNotIn("--foo", flags) |
| self.assertIn("--no-foo", flags) |
| self.assertIn("--bar", flags) |
| self.assertNotIn("--no-bar", flags) |
| |
| def test_str_multiple(self): |
| flags = self.CLASS({ |
| "--flag-a": "value1", |
| "--flag-b": None, |
| "--flag-c": "value3" |
| }) |
| self.assertEqual(str(flags), "--flag-a=value1,--flag-b,--flag-c=value3") |
| |
| def test_initial_data_empty(self): |
| flags = self.CLASS() |
| flags_copy = self.CLASS(flags) |
| self.assertEqual(str(flags), str(flags_copy)) |
| flags_copy = self.CLASS() |
| flags_copy.update(flags) |
| self.assertEqual(str(flags), str(flags_copy)) |
| |
| def test_initial_data(self): |
| flags = self.CLASS({ |
| "--flag-a": "value1", |
| "--flag-b": None, |
| "--flag-c": "value3" |
| }) |
| flags_copy = self.CLASS(flags) |
| self.assertEqual(str(flags), str(flags_copy)) |
| flags_copy = self.CLASS() |
| flags_copy.update(flags) |
| self.assertEqual(str(flags), str(flags_copy)) |
| |
| def test_parse_nested(self): |
| self.skipTest("Not supported for JSFlags") |
| |
| def test_known_flags(self): |
| self.assertNotIn( |
| "--help", KNOWN_JS_FLAGS, |
| "--help is also present in chrome, this should be filtered out") |
| for flag in KNOWN_JS_FLAGS: |
| self.assertFalse( |
| flag.startswith("--no"), "Strip --no prefix from all flags.") |
| self.assertNotIn("=", flag, "Only allow names, no values") |
| |
| def test_known_flags_chrome_overlap(self): |
| for js_flag in KNOWN_JS_FLAGS: |
| self.assertNotIn(js_flag, KNOWN_CHROME_FLAGS) |
| |
| |
| class _ChromeBaseFeaturesTestCase(unittest.TestCase, metaclass=abc.ABCMeta): |
| |
| @abc.abstractmethod |
| def instance(self) -> ChromeBaseFeatures: |
| pass |
| |
| def test_empty(self): |
| features = self.instance() |
| self.assertEqual(str(features), "") |
| features_list = list(features) |
| self.assertEqual(len(features_list), 0) |
| self.assertDictEqual(features.enabled, {}) |
| self.assertSetEqual(features.disabled, set()) |
| |
| def test_enable_simple(self): |
| features = self.instance() |
| features.enable("feature1") |
| features.enable("feature2") |
| features_list = list(features) |
| self.assertEqual(len(features_list), 1) |
| features_str = str(features) |
| self.assertIn("=feature1,feature2", features_str) |
| |
| def test_disable_simple(self): |
| features = self.instance() |
| features.disable("feature1") |
| features.disable("feature2") |
| features_list = list(features) |
| self.assertEqual(len(features_list), 1) |
| features_str = str(features) |
| self.assertIn("=feature1,feature2", features_str) |
| |
| def test_enable_disable(self): |
| features = self.instance() |
| features.enable("feature1") |
| features.disable("feature2") |
| features_list = list(features) |
| self.assertEqual(len(features_list), 2) |
| features_str = str(features) |
| self.assertIn("feature1", features_str) |
| self.assertIn("feature2", features_str) |
| self.assertDictEqual(features.enabled, {"feature1": None}) |
| self.assertSetEqual(features.disabled, {"feature2"}) |
| |
| def test_update_same(self): |
| features_1 = self.instance() |
| features_1.disable("feature1") |
| features_2 = self.instance() |
| features_2.disable("feature1") |
| features_1.update(features_2) |
| self.assertEqual(str(features_1), str(features_2)) |
| |
| def test_update_add(self): |
| features_1 = self.instance() |
| features_1.disable("feature1") |
| features_1.enable("feature2") |
| features_2 = self.instance() |
| features_2.disable("featureX") |
| features_2.enable("featureY") |
| features_1.update(features_2) |
| self.assertSetEqual(features_1.disabled, {"feature1", "featureX"}) |
| self.assertSetEqual( |
| set(features_1.enabled.keys()), {"feature2", "featureY"}) |
| |
| def test_update_conflict(self): |
| features_1 = self.instance() |
| features_1.enable("feature1") |
| features_2 = self.instance() |
| features_2.disable("feature1") |
| with self.assertRaises(ValueError): |
| features_1.update(features_2) |
| |
| def test_enable_disable_frozen(self): |
| features = self.instance() |
| features.freeze() |
| with self.assertRaises(FrozenFlagsError): |
| features.disable("feature1") |
| with self.assertRaises(FrozenFlagsError): |
| features.enable("feature2") |
| |
| |
| class ChromeFeaturesTestCase(_ChromeBaseFeaturesTestCase): |
| |
| def instance(self) -> ChromeFeatures: |
| return ChromeFeatures() |
| |
| def test_enable_complex_features(self): |
| features = self.instance() |
| features.enable("feature1") |
| features.enable("feature2:k1") |
| features.enable("feature3:k1/v1/k2/v2") |
| features.enable("feature4<Trial1:k1/v1/k2/v2") |
| features.enable("feature5<Trial1.Group1:k1/v1/k2/v2") |
| features_list = list(features) |
| self.assertEqual(len(features_list), 1) |
| |
| def test_disable_complex_features(self): |
| features = self.instance() |
| features.disable("feature1") |
| features.disable("feature2:k1") |
| features.disable("feature3:k1/v1/k2/v2") |
| features.disable("feature4<Trial1:k1/v1/k2/v2") |
| features.disable("feature5<Trial1.Group1:k1/v1/k2/v2") |
| features_list = list(features) |
| self.assertEqual(len(features_list), 1) |
| features_str = str(features) |
| self.assertIn("feature1", features_str) |
| self.assertIn("feature2", features_str) |
| self.assertIn("feature3", features_str) |
| self.assertIn("feature4", features_str) |
| |
| def test_enable_simple_chrome(self): |
| features = self.instance() |
| features.enable("feature1") |
| features.enable("feature2") |
| self.assertEqual(str(features), "--enable-features=feature1,feature2") |
| |
| def test_disable_simple_chrome(self): |
| features = self.instance() |
| features.disable("feature1") |
| features.disable("feature2") |
| self.assertEqual(str(features), "--disable-features=feature1,feature2") |
| |
| def test_enable_disable_chrome(self): |
| features = self.instance() |
| features.enable("feature1") |
| features.disable("feature2") |
| self.assertEqual( |
| str(features), "--enable-features=feature1 --disable-features=feature2") |
| |
| def test_enable_disable_complex(self): |
| features = self.instance() |
| features.enable("feature0") |
| features.enable("feature1:k1/v1") |
| features.enable("feature2<Trial.Group:k2/v2") |
| features.disable("feature3:k3/v3") |
| self.assertDictEqual(features.enabled, { |
| "feature0": None, |
| "feature1": ":k1/v1", |
| "feature2": "<Trial.Group:k2/v2" |
| }) |
| self.assertSetEqual(features.disabled, {"feature3"}) |
| |
| def test_conflicting_values_enabled(self): |
| features = self.instance() |
| features.enable("feature1") |
| features.enable("feature1") |
| with self.assertRaises(ValueError): |
| features.disable("feature1") |
| with self.assertRaises(ValueError): |
| features.enable("feature1:k1/v1") |
| features_str = str(features) |
| self.assertEqual(features_str, "--enable-features=feature1") |
| |
| def test_conflicting_values_disabled(self): |
| features = self.instance() |
| features.disable("feature1") |
| features.disable("feature1") |
| with self.assertRaises(ValueError): |
| features.enable("feature1") |
| features.disable("feature1:k1/v1") |
| features_str = str(features) |
| self.assertEqual(features_str, "--disable-features=feature1") |
| |
| |
| class ChromeBlinkFeaturesTestCase(_ChromeBaseFeaturesTestCase): |
| |
| def instance(self) -> ChromeBlinkFeatures: |
| return ChromeBlinkFeatures() |
| |
| def test_empty(self): |
| features = self.instance() |
| self.assertEqual(str(features), "") |
| features_list = list(features) |
| self.assertEqual(len(features_list), 0) |
| self.assertDictEqual(features.enabled, {}) |
| self.assertSetEqual(features.disabled, set()) |
| |
| def test_enable_basic_features(self): |
| features = self.instance() |
| features.enable("feature1") |
| |
| def test_enable_invalid(self): |
| features = self.instance() |
| for invalid in ("feature2:k1", "feature3:k1/v1/k2/v2", |
| "feature4<Trial1:k1/v1/k2/v2", |
| "feature5<Trial1.Group1:k1/v1/k2/v2"): |
| with self.assertRaises(ValueError): |
| features.enable(invalid) |
| self.assertTrue(features.is_empty) |
| |
| def test_enable_simple_chrome_blink(self): |
| features = self.instance() |
| features.enable("feature1") |
| features.enable("feature2") |
| self.assertEqual(str(features), "--enable-blink-features=feature1,feature2") |
| |
| def test_disable_simple_chrome_blink(self): |
| features = self.instance() |
| features.disable("feature1") |
| features.disable("feature2") |
| self.assertEqual( |
| str(features), "--disable-blink-features=feature1,feature2") |
| |
| def test_enable_disable_chrome_blink(self): |
| features = self.instance() |
| features.enable("feature1") |
| features.disable("feature2") |
| self.assertEqual( |
| str(features), |
| "--enable-blink-features=feature1 --disable-blink-features=feature2") |
| |
| |
| del _ChromeBaseFeaturesTestCase |
| |
| if __name__ == "__main__": |
| test_helper.run_pytest(__file__) |