An attempt at getting image data back

This commit is contained in:
2024-07-14 00:27:33 +02:00
parent e026bc93f7
commit 6452d2e774
1314 changed files with 218350 additions and 38 deletions

View File

@@ -0,0 +1,170 @@
# 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.
"""Validate mojo attributes are allowed in Chrome before generation."""
import mojom.generate.check as check
import mojom.generate.module as module
_COMMON_ATTRIBUTES = {
'EnableIf',
'EnableIfNot',
}
# For struct, union & parameter lists.
_COMMON_FIELD_ATTRIBUTES = _COMMON_ATTRIBUTES | {
'MinVersion',
'RenamedFrom',
}
# Note: `Default`` goes on the default _value_, not on the enum.
# Note: [Stable] without [Extensible] is not allowed.
_ENUM_ATTRIBUTES = _COMMON_ATTRIBUTES | {
'Extensible',
'Native',
'Stable',
'RenamedFrom',
'Uuid',
}
# TODO(crbug.com/1234883) MinVersion is not needed for EnumVal.
_ENUMVAL_ATTRIBUTES = _COMMON_ATTRIBUTES | {
'Default',
'MinVersion',
}
_INTERFACE_ATTRIBUTES = _COMMON_ATTRIBUTES | {
'RenamedFrom',
'RequireContext',
'RuntimeFeature',
'ServiceSandbox',
'Stable',
'Uuid',
}
_METHOD_ATTRIBUTES = _COMMON_ATTRIBUTES | {
'AllowedContext',
'MinVersion',
'NoInterrupt',
'RuntimeFeature',
'SupportsUrgent',
'Sync',
'UnlimitedSize',
}
_MODULE_ATTRIBUTES = _COMMON_ATTRIBUTES | {
'JavaConstantsClassName',
'JavaPackage',
}
_PARAMETER_ATTRIBUTES = _COMMON_FIELD_ATTRIBUTES
_STRUCT_ATTRIBUTES = _COMMON_ATTRIBUTES | {
'CustomSerializer',
'JavaClassName',
'Native',
'Stable',
'RenamedFrom',
'Uuid',
}
_STRUCT_FIELD_ATTRIBUTES = _COMMON_FIELD_ATTRIBUTES
_UNION_ATTRIBUTES = _COMMON_ATTRIBUTES | {
'Extensible',
'Stable',
'RenamedFrom',
'Uuid',
}
_UNION_FIELD_ATTRIBUTES = _COMMON_FIELD_ATTRIBUTES | {
'Default',
}
# TODO(https://crbug.com/1193875) empty this set and remove the allowlist.
_STABLE_ONLY_ALLOWLISTED_ENUMS = {
'crosapi.mojom.OptionalBool',
'crosapi.mojom.TriState',
}
class Check(check.Check):
def __init__(self, *args, **kwargs):
super(Check, self).__init__(*args, **kwargs)
def _Respell(self, allowed, attribute):
for a in allowed:
if a.lower() == attribute.lower():
return f" - Did you mean: {a}?"
return ""
def _CheckAttributes(self, context, allowed, attributes):
if not attributes:
return
for attribute in attributes:
if not attribute in allowed:
# Is there a close misspelling?
hint = self._Respell(allowed, attribute)
raise check.CheckException(
self.module,
f"attribute {attribute} not allowed on {context}{hint}")
def _CheckEnumAttributes(self, enum):
if enum.attributes:
self._CheckAttributes("enum", _ENUM_ATTRIBUTES, enum.attributes)
if 'Stable' in enum.attributes and not 'Extensible' in enum.attributes:
full_name = f"{self.module.mojom_namespace}.{enum.mojom_name}"
if full_name not in _STABLE_ONLY_ALLOWLISTED_ENUMS:
raise check.CheckException(
self.module,
f"[Extensible] required on [Stable] enum {full_name}")
for enumval in enum.fields:
self._CheckAttributes("enum value", _ENUMVAL_ATTRIBUTES,
enumval.attributes)
def _CheckInterfaceAttributes(self, interface):
self._CheckAttributes("interface", _INTERFACE_ATTRIBUTES,
interface.attributes)
for method in interface.methods:
self._CheckAttributes("method", _METHOD_ATTRIBUTES, method.attributes)
for param in method.parameters:
self._CheckAttributes("parameter", _PARAMETER_ATTRIBUTES,
param.attributes)
if method.response_parameters:
for param in method.response_parameters:
self._CheckAttributes("parameter", _PARAMETER_ATTRIBUTES,
param.attributes)
for enum in interface.enums:
self._CheckEnumAttributes(enum)
def _CheckModuleAttributes(self):
self._CheckAttributes("module", _MODULE_ATTRIBUTES, self.module.attributes)
def _CheckStructAttributes(self, struct):
self._CheckAttributes("struct", _STRUCT_ATTRIBUTES, struct.attributes)
for field in struct.fields:
self._CheckAttributes("struct field", _STRUCT_FIELD_ATTRIBUTES,
field.attributes)
for enum in struct.enums:
self._CheckEnumAttributes(enum)
def _CheckUnionAttributes(self, union):
self._CheckAttributes("union", _UNION_ATTRIBUTES, union.attributes)
for field in union.fields:
self._CheckAttributes("union field", _UNION_FIELD_ATTRIBUTES,
field.attributes)
def CheckModule(self):
"""Note that duplicate attributes are forbidden at the parse phase.
We also do not need to look at the types of any parameters, as they will be
checked where they are defined. Consts do not have attributes so can be
skipped."""
self._CheckModuleAttributes()
for interface in self.module.interfaces:
self._CheckInterfaceAttributes(interface)
for enum in self.module.enums:
self._CheckEnumAttributes(enum)
for struct in self.module.structs:
self._CheckStructAttributes(struct)
for union in self.module.unions:
self._CheckUnionAttributes(union)

View File

@@ -0,0 +1,194 @@
# 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 unittest
import mojom.generate.check as check
from mojom_bindings_generator import LoadChecks, _Generate
from mojom_parser_test_case import MojomParserTestCase
class FakeArgs:
"""Fakes args to _Generate - intention is to do just enough to run checks"""
def __init__(self, tester, files=None):
""" `tester` is MojomParserTestCase for paths.
`files` will have tester path added."""
self.checks_string = 'attributes'
self.depth = tester.GetPath('')
self.filelist = None
self.filename = [tester.GetPath(x) for x in files]
self.gen_directories = tester.GetPath('gen')
self.generators_string = ''
self.import_directories = []
self.output_dir = tester.GetPath('out')
self.scrambled_message_id_salt_paths = None
self.typemaps = []
self.variant = 'none'
class MojoBindingsCheckTest(MojomParserTestCase):
def _ParseAndGenerate(self, mojoms):
self.ParseMojoms(mojoms)
args = FakeArgs(self, files=mojoms)
_Generate(args, {})
def _testValid(self, filename, content):
self.WriteFile(filename, content)
self._ParseAndGenerate([filename])
def _testThrows(self, filename, content, regexp):
mojoms = []
self.WriteFile(filename, content)
mojoms.append(filename)
with self.assertRaisesRegexp(check.CheckException, regexp):
self._ParseAndGenerate(mojoms)
def testLoads(self):
"""Validate that the check is registered under the expected name."""
check_modules = LoadChecks('attributes')
self.assertTrue(check_modules['attributes'])
def testNoAnnotations(self):
# Undecorated mojom should be fine.
self._testValid(
"a.mojom", """
module a;
struct Bar { int32 a; };
enum Hello { kValue };
union Thingy { Bar b; Hello hi; };
interface Foo {
Foo(int32 a, Hello hi, Thingy t) => (Bar b);
};
""")
def testValidAnnotations(self):
# Obviously this is meaningless and won't generate, but it should pass
# the attribute check's validation.
self._testValid(
"a.mojom", """
[JavaConstantsClassName="FakeClass",JavaPackage="org.chromium.Fake"]
module a;
[Stable, Extensible]
enum Hello { [Default] kValue, kValue2, [MinVersion=2] kValue3 };
[Native]
enum NativeEnum {};
[Stable,Extensible]
union Thingy { Bar b; [Default]int32 c; Hello hi; };
[Stable,RenamedFrom="module.other.Foo",
Uuid="4C178401-4B07-4C2E-9255-5401A943D0C7"]
struct Structure { Hello hi; };
[ServiceSandbox=Hello.kValue,RequireContext=Hello.kValue,Stable,
Uuid="2F17D7DD-865A-4B1C-9394-9C94E035E82F"]
interface Foo {
[AllowedContext=Hello.kValue]
Foo@0(int32 a) => (int32 b);
[MinVersion=2,Sync,UnlimitedSize,NoInterrupt]
Bar@1(int32 b, [MinVersion=2]Structure? s) => (bool c);
};
[RuntimeFeature=test.mojom.FeatureName]
interface FooFeatureControlled {};
interface FooMethodFeatureControlled {
[RuntimeFeature=test.mojom.FeatureName]
MethodWithFeature() => (bool c);
};
""")
def testWrongModuleStable(self):
contents = """
// err: module cannot be Stable
[Stable]
module a;
enum Hello { kValue, kValue2, kValue3 };
enum NativeEnum {};
struct Structure { Hello hi; };
interface Foo {
Foo(int32 a) => (int32 b);
Bar(int32 b, Structure? s) => (bool c);
};
"""
self._testThrows('b.mojom', contents,
'attribute Stable not allowed on module')
def testWrongEnumDefault(self):
contents = """
module a;
// err: default should go on EnumValue not Enum.
[Default=kValue]
enum Hello { kValue, kValue2, kValue3 };
enum NativeEnum {};
struct Structure { Hello hi; };
interface Foo {
Foo(int32 a) => (int32 b);
Bar(int32 b, Structure? s) => (bool c);
};
"""
self._testThrows('b.mojom', contents,
'attribute Default not allowed on enum')
def testWrongStructMinVersion(self):
contents = """
module a;
enum Hello { kValue, kValue2, kValue3 };
enum NativeEnum {};
// err: struct cannot have MinVersion.
[MinVersion=2]
struct Structure { Hello hi; };
interface Foo {
Foo(int32 a) => (int32 b);
Bar(int32 b, Structure? s) => (bool c);
};
"""
self._testThrows('b.mojom', contents,
'attribute MinVersion not allowed on struct')
def testWrongMethodRequireContext(self):
contents = """
module a;
enum Hello { kValue, kValue2, kValue3 };
enum NativeEnum {};
struct Structure { Hello hi; };
interface Foo {
// err: RequireContext is for interfaces.
[RequireContext=Hello.kValue]
Foo(int32 a) => (int32 b);
Bar(int32 b, Structure? s) => (bool c);
};
"""
self._testThrows('b.mojom', contents,
'RequireContext not allowed on method')
def testWrongMethodRequireContext(self):
# crbug.com/1230122
contents = """
module a;
interface Foo {
// err: sync not Sync.
[sync]
Foo(int32 a) => (int32 b);
};
"""
self._testThrows('b.mojom', contents,
'attribute sync not allowed.*Did you mean: Sync')
def testStableExtensibleEnum(self):
# crbug.com/1193875
contents = """
module a;
[Stable]
enum Foo {
kDefaultVal,
kOtherVal = 2,
};
"""
self._testThrows('a.mojom', contents,
'Extensible.*?required.*?Stable.*?enum')

View File

@@ -0,0 +1,34 @@
# 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.
"""Ensure no duplicate type definitions before generation."""
import mojom.generate.check as check
import mojom.generate.module as module
class Check(check.Check):
def __init__(self, *args, **kwargs):
super(Check, self).__init__(*args, **kwargs)
def CheckModule(self):
kinds = dict()
for module in self.module.imports:
for kind in module.enums + module.structs + module.unions:
kind_name = f'{kind.module.mojom_namespace}.{kind.mojom_name}'
if kind_name in kinds:
previous_module = kinds[kind_name]
if previous_module.path != module.path:
raise check.CheckException(
self.module, f"multiple-definition for type {kind_name}" +
f"(defined in both {previous_module} and {module})")
kinds[kind_name] = kind.module
for kind in self.module.enums + self.module.structs + self.module.unions:
kind_name = f'{kind.module.mojom_namespace}.{kind.mojom_name}'
if kind_name in kinds:
previous_module = kinds[kind_name]
raise check.CheckException(
self.module, f"multiple-definition for type {kind_name}" +
f"(previous definition in {previous_module})")
return True

View File

@@ -0,0 +1,62 @@
# Copyright 2023 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Validate mojo runtime feature guarded interfaces are nullable."""
import mojom.generate.check as check
import mojom.generate.module as module
class Check(check.Check):
def __init__(self, *args, **kwargs):
super(Check, self).__init__(*args, **kwargs)
# `param` is an Interface of some sort.
def _CheckNonNullableFeatureGuardedInterface(self, kind):
# Only need to validate interface if it has a RuntimeFeature
if not kind.kind.runtime_feature:
return
# Nullable (optional) is ok as the interface expects they might not be sent.
if kind.is_nullable:
return
interface = kind.kind.mojom_name
raise check.CheckException(
self.module,
f"interface {interface} has a RuntimeFeature but is not nullable")
# `param` can be a lot of things so check if it is a remote/receiver.
# Array/Map must be recursed into.
def _CheckFieldOrParam(self, kind):
if module.IsAnyInterfaceKind(kind):
self._CheckNonNullableFeatureGuardedInterface(kind)
if module.IsArrayKind(kind):
self._CheckFieldOrParam(kind.kind)
if module.IsMapKind(kind):
self._CheckFieldOrParam(kind.key_kind)
self._CheckFieldOrParam(kind.value_kind)
def _CheckInterfaceFeatures(self, interface):
for method in interface.methods:
for param in method.parameters:
self._CheckFieldOrParam(param.kind)
if method.response_parameters:
for param in method.response_parameters:
self._CheckFieldOrParam(param.kind)
def _CheckStructFeatures(self, struct):
for field in struct.fields:
self._CheckFieldOrParam(field.kind)
def _CheckUnionFeatures(self, union):
for field in union.fields:
self._CheckFieldOrParam(field.kind)
def CheckModule(self):
"""Validate that any runtime feature guarded interfaces that might be passed
over mojo are nullable."""
for interface in self.module.interfaces:
self._CheckInterfaceFeatures(interface)
for struct in self.module.structs:
self._CheckStructFeatures(struct)
for union in self.module.unions:
self._CheckUnionFeatures(union)

View File

@@ -0,0 +1,173 @@
# Copyright 2023 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import unittest
import mojom.generate.check as check
from mojom_bindings_generator import LoadChecks, _Generate
from mojom_parser_test_case import MojomParserTestCase
class FakeArgs:
"""Fakes args to _Generate - intention is to do just enough to run checks"""
def __init__(self, tester, files=None):
""" `tester` is MojomParserTestCase for paths.
`files` will have tester path added."""
self.checks_string = 'features'
self.depth = tester.GetPath('')
self.filelist = None
self.filename = [tester.GetPath(x) for x in files]
self.gen_directories = tester.GetPath('gen')
self.generators_string = ''
self.import_directories = []
self.output_dir = tester.GetPath('out')
self.scrambled_message_id_salt_paths = None
self.typemaps = []
self.variant = 'none'
class MojoBindingsCheckTest(MojomParserTestCase):
def _ParseAndGenerate(self, mojoms):
self.ParseMojoms(mojoms)
args = FakeArgs(self, files=mojoms)
_Generate(args, {})
def assertValid(self, filename, content):
self.WriteFile(filename, content)
self._ParseAndGenerate([filename])
def assertThrows(self, filename, content, regexp):
mojoms = []
self.WriteFile(filename, content)
mojoms.append(filename)
with self.assertRaisesRegexp(check.CheckException, regexp):
self._ParseAndGenerate(mojoms)
def testLoads(self):
"""Validate that the check is registered under the expected name."""
check_modules = LoadChecks('features')
self.assertTrue(check_modules['features'])
def testNullableOk(self):
self.assertValid(
"a.mojom", """
module a;
// Scaffolding.
feature kFeature {
const string name = "Hello";
const bool enabled_state = false;
};
[RuntimeFeature=kFeature]
interface Guarded {
};
// Unguarded interfaces should be ok everywhere.
interface NotGuarded { };
// Optional (nullable) interfaces should be ok everywhere:
struct Bar {
pending_remote<Guarded>? remote;
pending_receiver<Guarded>? receiver;
};
union Thingy {
pending_remote<Guarded>? remote;
pending_receiver<Guarded>? receiver;
};
interface Foo {
Foo(
pending_remote<Guarded>? remote,
pending_receiver<Guarded>? receiver,
pending_associated_remote<Guarded>? a_remote,
pending_associated_receiver<Guarded>? a_receiver,
// Unguarded interfaces do not have to be nullable.
pending_remote<NotGuarded> remote,
pending_receiver<NotGuarded> receiver,
pending_associated_remote<NotGuarded> a_remote,
pending_associated_receiver<NotGuarded> a_receiver
) => (
pending_remote<Guarded>? remote,
pending_receiver<Guarded>? receiver
);
Bar(array<pending_remote<Guarded>?> remote)
=> (map<string, pending_receiver<Guarded>?> a);
};
""")
def testMethodParamsMustBeNullable(self):
prelude = """
module a;
// Scaffolding.
feature kFeature {
const string name = "Hello";
const bool enabled_state = false;
};
[RuntimeFeature=kFeature]
interface Guarded { };
"""
self.assertThrows(
'a.mojom', prelude + """
interface Trial {
Method(pending_remote<Guarded> a) => ();
};
""", 'interface Guarded has a RuntimeFeature')
self.assertThrows(
'a.mojom', prelude + """
interface Trial {
Method(bool foo) => (pending_receiver<Guarded> a);
};
""", 'interface Guarded has a RuntimeFeature')
self.assertThrows(
'a.mojom', prelude + """
interface Trial {
Method(pending_receiver<Guarded> a) => ();
};
""", 'interface Guarded has a RuntimeFeature')
self.assertThrows(
'a.mojom', prelude + """
interface Trial {
Method(pending_associated_remote<Guarded> a) => ();
};
""", 'interface Guarded has a RuntimeFeature')
self.assertThrows(
'a.mojom', prelude + """
interface Trial {
Method(pending_associated_receiver<Guarded> a) => ();
};
""", 'interface Guarded has a RuntimeFeature')
self.assertThrows(
'a.mojom', prelude + """
interface Trial {
Method(array<pending_associated_receiver<Guarded>> a) => ();
};
""", 'interface Guarded has a RuntimeFeature')
self.assertThrows(
'a.mojom', prelude + """
interface Trial {
Method(map<string, pending_associated_receiver<Guarded>> a) => ();
};
""", 'interface Guarded has a RuntimeFeature')
def testStructUnionMembersMustBeNullable(self):
prelude = """
module a;
// Scaffolding.
feature kFeature {
const string name = "Hello";
const bool enabled_state = false;
};
[RuntimeFeature=kFeature]
interface Guarded { };
"""
self.assertThrows(
'a.mojom', prelude + """
struct Trial {
pending_remote<Guarded> a;
};
""", 'interface Guarded has a RuntimeFeature')
self.assertThrows(
'a.mojom', prelude + """
union Trial {
pending_remote<Guarded> a;
};
""", 'interface Guarded has a RuntimeFeature')

View File

@@ -0,0 +1,102 @@
# 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.
"""Validate RequireContext and AllowedContext annotations before generation."""
import mojom.generate.check as check
import mojom.generate.module as module
class Check(check.Check):
def __init__(self, *args, **kwargs):
self.kind_to_interfaces = dict()
super(Check, self).__init__(*args, **kwargs)
def _IsPassedInterface(self, candidate):
if isinstance(
candidate.kind,
(module.PendingReceiver, module.PendingRemote,
module.PendingAssociatedReceiver, module.PendingAssociatedRemote)):
return True
return False
def _CheckInterface(self, method, param):
# |param| is a pending_x<Interface> so need .kind.kind to get Interface.
interface = param.kind.kind
if interface.require_context:
if method.allowed_context is None:
raise check.CheckException(
self.module, "method `{}` has parameter `{}` which passes interface"
" `{}` that requires an AllowedContext annotation but none exists.".
format(
method.mojom_name,
param.mojom_name,
interface.mojom_name,
))
# If a string was provided, or if an enum was not imported, this will
# be a string and we cannot validate that it is in range.
if not isinstance(method.allowed_context, module.EnumValue):
raise check.CheckException(
self.module,
"method `{}` has AllowedContext={} which is not a valid enum value."
.format(method.mojom_name, method.allowed_context))
# EnumValue must be from the same enum to be compared.
if interface.require_context.enum != method.allowed_context.enum:
raise check.CheckException(
self.module, "method `{}` has parameter `{}` which passes interface"
" `{}` that requires AllowedContext={} but one of kind `{}` was "
"provided.".format(
method.mojom_name,
param.mojom_name,
interface.mojom_name,
interface.require_context.enum,
method.allowed_context.enum,
))
# RestrictContext enums have most privileged field first (lowest value).
interface_value = interface.require_context.field.numeric_value
method_value = method.allowed_context.field.numeric_value
if interface_value < method_value:
raise check.CheckException(
self.module, "RequireContext={} > AllowedContext={} for method "
"`{}` which passes interface `{}`.".format(
interface.require_context.GetSpec(),
method.allowed_context.GetSpec(), method.mojom_name,
interface.mojom_name))
return True
def _GatherReferencedInterfaces(self, field):
key = field.kind.spec
# structs/unions can nest themselves so we need to bookkeep.
if not key in self.kind_to_interfaces:
# Might reference ourselves so have to create the list first.
self.kind_to_interfaces[key] = set()
for param in field.kind.fields:
if self._IsPassedInterface(param):
self.kind_to_interfaces[key].add(param)
elif isinstance(param.kind, (module.Struct, module.Union)):
for iface in self._GatherReferencedInterfaces(param):
self.kind_to_interfaces[key].add(iface)
return self.kind_to_interfaces[key]
def _CheckParams(self, method, params):
# Note: we have to repeat _CheckParams for each method as each might have
# different AllowedContext= attributes. We cannot memoize this function,
# but can do so for gathering referenced interfaces as their RequireContext
# attributes do not change.
for param in params:
if self._IsPassedInterface(param):
self._CheckInterface(method, param)
elif isinstance(param.kind, (module.Struct, module.Union)):
for interface in self._GatherReferencedInterfaces(param):
self._CheckInterface(method, interface)
def _CheckMethod(self, method):
if method.parameters:
self._CheckParams(method, method.parameters)
if method.response_parameters:
self._CheckParams(method, method.response_parameters)
def CheckModule(self):
for interface in self.module.interfaces:
for method in interface.methods:
self._CheckMethod(method)

View File

@@ -0,0 +1,254 @@
# 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 unittest
import mojom.generate.check as check
from mojom_bindings_generator import LoadChecks, _Generate
from mojom_parser_test_case import MojomParserTestCase
# Mojoms that we will use in multiple tests.
basic_mojoms = {
'level.mojom':
"""
module level;
enum Level {
kHighest,
kMiddle,
kLowest,
};
""",
'interfaces.mojom':
"""
module interfaces;
import "level.mojom";
struct Foo {int32 bar;};
[RequireContext=level.Level.kHighest]
interface High {
DoFoo(Foo foo);
};
[RequireContext=level.Level.kMiddle]
interface Mid {
DoFoo(Foo foo);
};
[RequireContext=level.Level.kLowest]
interface Low {
DoFoo(Foo foo);
};
"""
}
class FakeArgs:
"""Fakes args to _Generate - intention is to do just enough to run checks"""
def __init__(self, tester, files=None):
""" `tester` is MojomParserTestCase for paths.
`files` will have tester path added."""
self.checks_string = 'restrictions'
self.depth = tester.GetPath('')
self.filelist = None
self.filename = [tester.GetPath(x) for x in files]
self.gen_directories = tester.GetPath('gen')
self.generators_string = ''
self.import_directories = []
self.output_dir = tester.GetPath('out')
self.scrambled_message_id_salt_paths = None
self.typemaps = []
self.variant = 'none'
class MojoBindingsCheckTest(MojomParserTestCase):
def _WriteBasicMojoms(self):
for filename, contents in basic_mojoms.items():
self.WriteFile(filename, contents)
return list(basic_mojoms.keys())
def _ParseAndGenerate(self, mojoms):
self.ParseMojoms(mojoms)
args = FakeArgs(self, files=mojoms)
_Generate(args, {})
def testLoads(self):
"""Validate that the check is registered under the expected name."""
check_modules = LoadChecks('restrictions')
self.assertTrue(check_modules['restrictions'])
def testValidAnnotations(self):
mojoms = self._WriteBasicMojoms()
a = 'a.mojom'
self.WriteFile(
a, """
module a;
import "level.mojom";
import "interfaces.mojom";
interface PassesHigh {
[AllowedContext=level.Level.kHighest]
DoHigh(pending_receiver<interfaces.High> hi);
};
interface PassesMedium {
[AllowedContext=level.Level.kMiddle]
DoMedium(pending_receiver<interfaces.Mid> hi);
[AllowedContext=level.Level.kMiddle]
DoMediumRem(pending_remote<interfaces.Mid> hi);
[AllowedContext=level.Level.kMiddle]
DoMediumAssoc(pending_associated_receiver<interfaces.Mid> hi);
[AllowedContext=level.Level.kMiddle]
DoMediumAssocRem(pending_associated_remote<interfaces.Mid> hi);
};
interface PassesLow {
[AllowedContext=level.Level.kLowest]
DoLow(pending_receiver<interfaces.Low> hi);
};
struct One { pending_receiver<interfaces.High> hi; };
struct Two { One one; };
interface PassesNestedHigh {
[AllowedContext=level.Level.kHighest]
DoNestedHigh(Two two);
};
// Allowed as PassesHigh is not itself restricted.
interface PassesPassesHigh {
DoPass(pending_receiver<PassesHigh> hiho);
};
""")
mojoms.append(a)
self._ParseAndGenerate(mojoms)
def _testThrows(self, filename, content, regexp):
mojoms = self._WriteBasicMojoms()
self.WriteFile(filename, content)
mojoms.append(filename)
with self.assertRaisesRegexp(check.CheckException, regexp):
self._ParseAndGenerate(mojoms)
def testMissingAnnotation(self):
contents = """
module b;
import "level.mojom";
import "interfaces.mojom";
interface PassesHigh {
// err: missing annotation.
DoHigh(pending_receiver<interfaces.High> hi);
};
"""
self._testThrows('b.mojom', contents, 'require.*?AllowedContext')
def testAllowTooLow(self):
contents = """
module b;
import "level.mojom";
import "interfaces.mojom";
interface PassesHigh {
// err: level is worse than required.
[AllowedContext=level.Level.kMiddle]
DoHigh(pending_receiver<interfaces.High> hi);
};
"""
self._testThrows('b.mojom', contents,
'RequireContext=.*?kHighest > AllowedContext=.*?kMiddle')
def testWrongEnumInAllow(self):
contents = """
module b;
import "level.mojom";
import "interfaces.mojom";
enum Blah {
kZero,
};
interface PassesHigh {
// err: different enums.
[AllowedContext=Blah.kZero]
DoHigh(pending_receiver<interfaces.High> hi);
};
"""
self._testThrows('b.mojom', contents, 'but one of kind')
def testNotAnEnumInAllow(self):
contents = """
module b;
import "level.mojom";
import "interfaces.mojom";
interface PassesHigh {
// err: not an enum.
[AllowedContext=doopdedoo.mojom.kWhatever]
DoHigh(pending_receiver<interfaces.High> hi);
};
"""
self._testThrows('b.mojom', contents, 'not a valid enum value')
def testMissingAllowedForNestedStructs(self):
contents = """
module b;
import "level.mojom";
import "interfaces.mojom";
struct One { pending_receiver<interfaces.High> hi; };
struct Two { One one; };
interface PassesNestedHigh {
// err: missing annotation.
DoNestedHigh(Two two);
};
"""
self._testThrows('b.mojom', contents, 'require.*?AllowedContext')
def testMissingAllowedForNestedUnions(self):
contents = """
module b;
import "level.mojom";
import "interfaces.mojom";
struct One { pending_receiver<interfaces.High> hi; };
struct Two { One one; };
union Three {One one; Two two; };
interface PassesNestedHigh {
// err: missing annotation.
DoNestedHigh(Three three);
};
"""
self._testThrows('b.mojom', contents, 'require.*?AllowedContext')
def testMultipleInterfacesThrows(self):
contents = """
module b;
import "level.mojom";
import "interfaces.mojom";
struct One { pending_receiver<interfaces.High> hi; };
interface PassesMultipleInterfaces {
[AllowedContext=level.Level.kMiddle]
DoMultiple(
pending_remote<interfaces.Mid> mid,
pending_receiver<interfaces.High> hi,
One one
);
};
"""
self._testThrows('b.mojom', contents,
'RequireContext=.*?kHighest > AllowedContext=.*?kMiddle')
def testMultipleInterfacesAllowed(self):
"""Multiple interfaces can be passed, all satisfy the level."""
mojoms = self._WriteBasicMojoms()
b = "b.mojom"
self.WriteFile(
b, """
module b;
import "level.mojom";
import "interfaces.mojom";
struct One { pending_receiver<interfaces.High> hi; };
interface PassesMultipleInterfaces {
[AllowedContext=level.Level.kHighest]
DoMultiple(
pending_receiver<interfaces.High> hi,
pending_remote<interfaces.Mid> mid,
One one
);
};
""")
mojoms.append(b)
self._ParseAndGenerate(mojoms)