Files
mongo/buildscripts/idl/tests/test_import.py
2017-05-15 10:43:28 -04:00

477 lines
12 KiB
Python

#!/usr/bin/env python2
# Copyright (C) 2017 MongoDB Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3,
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""Test cases for IDL binder."""
from __future__ import absolute_import, print_function, unicode_literals
import io
import textwrap
import unittest
from typing import Any, Dict
# import package so that it works regardless of whether we run as a module or file
if __package__ is None:
import sys
from os import path
sys.path.append(path.dirname(path.abspath(__file__)))
from context import idl
import testcase
else:
from .context import idl
from . import testcase
class DictionaryImportResolver(idl.parser.ImportResolverBase):
"""An import resolver resolves files from a dictionary."""
def __init__(self, import_dict):
# type: (Dict[unicode, unicode]) -> None
"""Construct a DictionaryImportResolver."""
self._import_dict = import_dict
super(DictionaryImportResolver, self).__init__()
def resolve(self, base_file, imported_file_name):
# type: (unicode, unicode) -> unicode
"""Return the complete path to an imported file name."""
# pylint: disable=unused-argument
if not imported_file_name in self._import_dict:
return None
return "imported_%s" % (imported_file_name)
def open(self, resolved_file_name):
# type: (unicode) -> Any
"""Return an io.Stream for the requested file."""
assert resolved_file_name.startswith("imported_")
imported_file_name = resolved_file_name.replace("imported_", "")
return io.StringIO(self._import_dict[imported_file_name])
class TestImport(testcase.IDLTestcase):
"""Test cases for the IDL binder."""
# Test: import wrong types
def test_import_negative_parser(self):
# type: () -> None
"""Negative import parser tests."""
self.assert_parse_fail(
textwrap.dedent("""
imports:
- "a.idl"
imports:
- "b.idl"
"""), idl.errors.ERROR_ID_DUPLICATE_NODE)
self.assert_parse_fail(
textwrap.dedent("""
imports: "basetypes.idl"
"""), idl.errors.ERROR_ID_IS_NODE_TYPE)
self.assert_parse_fail(
textwrap.dedent("""
imports:
a: "a.idl"
b: "b.idl"
"""), idl.errors.ERROR_ID_IS_NODE_TYPE)
def test_import_positive(self):
# type: () -> None
"""Postive import tests."""
import_dict = {
"basetypes.idl":
textwrap.dedent("""
global:
cpp_namespace: 'something'
types:
string:
description: foo
cpp_type: foo
bson_serialization_type: string
serializer: foo
deserializer: foo
default: foo
structs:
bar:
description: foo
strict: false
fields:
foo: string
"""),
"recurse1.idl":
textwrap.dedent("""
imports:
- "basetypes.idl"
types:
int:
description: foo
cpp_type: foo
bson_serialization_type: int
deserializer: BSONElement::fake
"""),
"recurse2.idl":
textwrap.dedent("""
imports:
- "recurse1.idl"
types:
double:
description: foo
cpp_type: foo
bson_serialization_type: double
deserializer: BSONElement::fake
"""),
"recurse1b.idl":
textwrap.dedent("""
imports:
- "basetypes.idl"
types:
bool:
description: foo
cpp_type: foo
bson_serialization_type: bool
deserializer: BSONElement::fake
"""),
"cycle1a.idl":
textwrap.dedent("""
global:
cpp_namespace: 'something'
imports:
- "cycle1b.idl"
types:
string:
description: foo
cpp_type: foo
bson_serialization_type: string
serializer: foo
deserializer: foo
default: foo
structs:
bar:
description: foo
strict: false
fields:
foo: string
foo1: bool
"""),
"cycle1b.idl":
textwrap.dedent("""
global:
cpp_namespace: 'something'
imports:
- "cycle1a.idl"
types:
bool:
description: foo
cpp_type: foo
bson_serialization_type: bool
deserializer: BSONElement::fake
structs:
bar2:
description: foo
strict: false
fields:
foo: string
foo1: bool
"""),
"cycle2.idl":
textwrap.dedent("""
global:
cpp_namespace: 'something'
imports:
- "cycle2.idl"
types:
string:
description: foo
cpp_type: foo
bson_serialization_type: string
serializer: foo
deserializer: foo
default: foo
"""),
}
resolver = DictionaryImportResolver(import_dict)
# Test simple import
self.assert_bind(
textwrap.dedent("""
global:
cpp_namespace: 'something'
imports:
- "basetypes.idl"
structs:
foobar:
description: foo
strict: false
fields:
foo: string
"""),
resolver=resolver)
# Test nested import
self.assert_bind(
textwrap.dedent("""
global:
cpp_namespace: 'something'
imports:
- "recurse2.idl"
structs:
foobar:
description: foo
strict: false
fields:
foo: string
foo1: int
foo2: double
"""),
resolver=resolver)
# Test diamond import
self.assert_bind(
textwrap.dedent("""
global:
cpp_namespace: 'something'
imports:
- "recurse2.idl"
- "recurse1b.idl"
structs:
foobar:
description: foo
strict: false
fields:
foo: string
foo1: int
foo2: double
foo3: bool
"""),
resolver=resolver)
# Test cycle import
self.assert_bind(
textwrap.dedent("""
global:
cpp_namespace: 'something'
imports:
- "cycle1a.idl"
structs:
foobar:
description: foo
strict: false
fields:
foo: string
foo1: bool
"""),
resolver=resolver)
# Test self cycle import
self.assert_bind(
textwrap.dedent("""
global:
cpp_namespace: 'something'
imports:
- "cycle2.idl"
structs:
foobar:
description: foo
strict: false
fields:
foo: string
"""),
resolver=resolver)
def test_import_negative(self):
# type: () -> None
"""Negative import tests."""
import_dict = {
"basetypes.idl":
textwrap.dedent("""
global:
cpp_namespace: 'something'
types:
string:
description: foo
cpp_type: foo
bson_serialization_type: string
serializer: foo
deserializer: foo
default: foo
structs:
bar:
description: foo
strict: false
fields:
foo: string
enums:
IntEnum:
description: "An example int enum"
type: int
values:
a0: 0
b1: 1
"""),
"bug.idl":
textwrap.dedent("""
global:
cpp_namespace: 'something'
types:
bool:
description: foo
bson_serialization_type: bool
deserializer: BSONElement::fake
"""),
}
resolver = DictionaryImportResolver(import_dict)
# Bad import
self.assert_parse_fail(
textwrap.dedent("""
imports:
- "notfound.idl"
"""),
idl.errors.ERROR_ID_BAD_IMPORT,
resolver=resolver)
# Duplicate types
self.assert_parse_fail(
textwrap.dedent("""
imports:
- "basetypes.idl"
types:
string:
description: foo
cpp_type: foo
bson_serialization_type: string
"""),
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
resolver=resolver)
# Duplicate structs
self.assert_parse_fail(
textwrap.dedent("""
imports:
- "basetypes.idl"
structs:
bar:
description: foo
fields:
foo1: string
"""),
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
resolver=resolver)
# Duplicate struct and type
self.assert_parse_fail(
textwrap.dedent("""
imports:
- "basetypes.idl"
structs:
string:
description: foo
fields:
foo1: string
"""),
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
resolver=resolver)
# Duplicate type and struct
self.assert_parse_fail(
textwrap.dedent("""
imports:
- "basetypes.idl"
types:
bar:
description: foo
cpp_type: foo
bson_serialization_type: string
"""),
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
resolver=resolver)
# Duplicate enums
self.assert_parse_fail(
textwrap.dedent("""
imports:
- "basetypes.idl"
enums:
IntEnum:
description: "An example int enum"
type: int
values:
a0: 0
b1: 1
"""),
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
resolver=resolver)
# Import a file with errors
self.assert_parse_fail(
textwrap.dedent("""
imports:
- "basetypes.idl"
- "bug.idl"
types:
string2:
description: foo
cpp_type: foo
bson_serialization_type: string
"""),
idl.errors.ERROR_ID_MISSING_REQUIRED_FIELD,
resolver=resolver)
if __name__ == '__main__':
unittest.main()