1481 lines
45 KiB
Python
1481 lines
45 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/>.
|
|
#
|
|
# pylint: disable=too-many-lines
|
|
"""Test cases for IDL binder."""
|
|
|
|
from __future__ import absolute_import, print_function, unicode_literals
|
|
|
|
import textwrap
|
|
import unittest
|
|
|
|
# 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
|
|
|
|
# All YAML tests assume 4 space indent
|
|
INDENT_SPACE_COUNT = 4
|
|
|
|
|
|
def fill_spaces(count):
|
|
# type: (int) -> unicode
|
|
"""Fill a string full of spaces."""
|
|
fill = ''
|
|
for _ in range(count * INDENT_SPACE_COUNT):
|
|
fill += ' '
|
|
|
|
return fill
|
|
|
|
|
|
def indent_text(count, unindented_text):
|
|
# type: (int, unicode) -> unicode
|
|
"""Indent each line of a multi-line string."""
|
|
lines = unindented_text.splitlines()
|
|
fill = fill_spaces(count)
|
|
return '\n'.join(fill + line for line in lines)
|
|
|
|
|
|
class TestBinder(testcase.IDLTestcase):
|
|
"""Test cases for the IDL binder."""
|
|
|
|
def test_empty(self):
|
|
# type: () -> None
|
|
"""Test an empty document works."""
|
|
self.assert_bind("")
|
|
|
|
def test_global_positive(self):
|
|
# type: () -> None
|
|
"""Postive global tests."""
|
|
spec = self.assert_bind(
|
|
textwrap.dedent("""
|
|
global:
|
|
cpp_namespace: 'something'
|
|
cpp_includes:
|
|
- 'bar'
|
|
- 'foo'"""))
|
|
self.assertEquals(spec.globals.cpp_namespace, "something")
|
|
self.assertListEqual(spec.globals.cpp_includes, ['bar', 'foo'])
|
|
|
|
def test_type_positive(self):
|
|
# type: () -> None
|
|
"""Positive type tests."""
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
"""))
|
|
|
|
# Test supported types
|
|
for bson_type in [
|
|
"bool", "date", "null", "decimal", "double", "int", "long", "objectid", "regex",
|
|
"string", "timestamp", "undefined"
|
|
]:
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: %s
|
|
default: foo
|
|
deserializer: BSONElement::fake
|
|
""" % (bson_type)))
|
|
|
|
# Test supported numeric types
|
|
for cpp_type in [
|
|
"std::int32_t",
|
|
"std::uint32_t",
|
|
"std::int32_t",
|
|
"std::uint64_t",
|
|
"std::vector<std::uint8_t>",
|
|
"std::array<std::uint8_t, 16>",
|
|
]:
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: %s
|
|
bson_serialization_type: int
|
|
deserializer: BSONElement::fake
|
|
""" % (cpp_type)))
|
|
|
|
# Test object
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: object
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
"""))
|
|
|
|
# Test 'any'
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: any
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
"""))
|
|
|
|
# Test 'chain'
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: chain
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
"""))
|
|
|
|
# Test supported bindata_subtype
|
|
for bindata_subtype in ["generic", "function", "uuid", "md5"]:
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: bindata
|
|
bindata_subtype: %s
|
|
deserializer: BSONElement::fake
|
|
""" % (bindata_subtype)))
|
|
|
|
def test_type_negative(self):
|
|
# type: () -> None
|
|
"""Negative type tests for properties that types and fields share."""
|
|
|
|
# Test bad bson type name
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: foo
|
|
"""), idl.errors.ERROR_ID_BAD_BSON_TYPE)
|
|
|
|
# Test bad cpp_type name
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: StringData
|
|
bson_serialization_type: string
|
|
deserializer: bar
|
|
"""), idl.errors.ERROR_ID_NO_STRINGDATA)
|
|
|
|
# Test unsupported serialization
|
|
for cpp_type in [
|
|
"char",
|
|
"signed char",
|
|
"unsigned char",
|
|
"signed short int",
|
|
"short int",
|
|
"short",
|
|
"signed short",
|
|
"unsigned short",
|
|
"unsigned short int",
|
|
"signed int",
|
|
"signed",
|
|
"unsigned int",
|
|
"unsigned",
|
|
"signed long int",
|
|
"signed long",
|
|
"int",
|
|
"long int",
|
|
"long",
|
|
"unsigned long int",
|
|
"unsigned long",
|
|
"signed long long int",
|
|
"signed long long",
|
|
"long long int",
|
|
"long long",
|
|
"unsigned long int",
|
|
"unsigned long",
|
|
"wchar_t",
|
|
"char16_t",
|
|
"char32_t",
|
|
"int8_t",
|
|
"int16_t",
|
|
"int32_t",
|
|
"int64_t",
|
|
"uint8_t",
|
|
"uint16_t",
|
|
"uint32_t",
|
|
"uint64_t",
|
|
]:
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: %s
|
|
bson_serialization_type: int
|
|
deserializer: BSONElement::int
|
|
""" % (cpp_type)), idl.errors.ERROR_ID_BAD_NUMERIC_CPP_TYPE)
|
|
|
|
# Test the std prefix 8 and 16-byte integers fail
|
|
for std_cpp_type in ["std::int8_t", "std::int16_t", "std::uint8_t", "std::uint16_t"]:
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: %s
|
|
bson_serialization_type: int
|
|
deserializer: BSONElement::int
|
|
""" % (std_cpp_type)), idl.errors.ERROR_ID_BAD_NUMERIC_CPP_TYPE)
|
|
|
|
# Test bindata_subtype missing
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: bindata
|
|
deserializer: BSONElement::fake
|
|
"""), idl.errors.ERROR_ID_BAD_BSON_BINDATA_SUBTYPE_VALUE)
|
|
|
|
# Test fake bindata_subtype is wrong
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: bindata
|
|
bindata_subtype: foo
|
|
deserializer: BSONElement::fake
|
|
"""), idl.errors.ERROR_ID_BAD_BSON_BINDATA_SUBTYPE_VALUE)
|
|
|
|
# Test deprecated bindata_subtype 'binary', and 'uuid_old' are wrong
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: bindata
|
|
bindata_subtype: binary
|
|
"""), idl.errors.ERROR_ID_BAD_BSON_BINDATA_SUBTYPE_VALUE)
|
|
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: bindata
|
|
bindata_subtype: uuid_old
|
|
"""), idl.errors.ERROR_ID_BAD_BSON_BINDATA_SUBTYPE_VALUE)
|
|
|
|
# Test bindata_subtype on wrong type
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
bindata_subtype: generic
|
|
deserializer: BSONElement::fake
|
|
"""), idl.errors.ERROR_ID_BAD_BSON_BINDATA_SUBTYPE_TYPE)
|
|
|
|
# Test bindata with default
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: bindata
|
|
bindata_subtype: uuid
|
|
default: 42
|
|
"""), idl.errors.ERROR_ID_BAD_BINDATA_DEFAULT)
|
|
|
|
# Test bindata in list of types
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type:
|
|
- bindata
|
|
- string
|
|
"""), idl.errors.ERROR_ID_BAD_BSON_TYPE)
|
|
|
|
# Test bindata in list of types
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: StringData
|
|
bson_serialization_type:
|
|
- bindata
|
|
- string
|
|
"""), idl.errors.ERROR_ID_BAD_BSON_TYPE)
|
|
|
|
# Test 'any' in list of types
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type:
|
|
- any
|
|
- int
|
|
"""), idl.errors.ERROR_ID_BAD_ANY_TYPE_USE)
|
|
|
|
# Test object in list of types
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type:
|
|
- object
|
|
- int
|
|
"""), idl.errors.ERROR_ID_BAD_BSON_TYPE_LIST)
|
|
|
|
# Test fake in list of types
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type:
|
|
- int
|
|
- fake
|
|
"""), idl.errors.ERROR_ID_BAD_BSON_TYPE)
|
|
|
|
# Test 'chain' in list of types
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type:
|
|
- chain
|
|
- int
|
|
"""), idl.errors.ERROR_ID_BAD_ANY_TYPE_USE)
|
|
|
|
# Test unsupported serialization
|
|
for bson_type in [
|
|
"bool", "date", "null", "decimal", "double", "int", "long", "objectid", "regex",
|
|
"timestamp", "undefined"
|
|
]:
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: std::string
|
|
bson_serialization_type: %s
|
|
serializer: foo
|
|
deserializer: BSONElement::fake
|
|
""" % (bson_type)),
|
|
idl.errors.ERROR_ID_CUSTOM_SCALAR_SERIALIZATION_NOT_SUPPORTED)
|
|
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: std::string
|
|
bson_serialization_type: %s
|
|
deserializer: foo
|
|
""" % (bson_type)),
|
|
idl.errors.ERROR_ID_CUSTOM_SCALAR_SERIALIZATION_NOT_SUPPORTED)
|
|
|
|
# Test 'any' serialization needs deserializer
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: any
|
|
"""), idl.errors.ERROR_ID_MISSING_AST_REQUIRED_FIELD)
|
|
|
|
# Test 'chain' serialization needs deserializer
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: chain
|
|
serializer: bar
|
|
"""), idl.errors.ERROR_ID_MISSING_AST_REQUIRED_FIELD)
|
|
|
|
# Test 'string' serialization needs deserializer
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: bar
|
|
"""), idl.errors.ERROR_ID_MISSING_AST_REQUIRED_FIELD)
|
|
|
|
# Test 'date' serialization needs deserializer
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: date
|
|
"""), idl.errors.ERROR_ID_MISSING_AST_REQUIRED_FIELD)
|
|
|
|
# Test 'chain' serialization needs serializer
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: chain
|
|
deserializer: bar
|
|
"""), idl.errors.ERROR_ID_MISSING_AST_REQUIRED_FIELD)
|
|
|
|
# Test list of bson types needs deserializer
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foofoo:
|
|
description: foo
|
|
cpp_type: std::int32_t
|
|
bson_serialization_type:
|
|
- int
|
|
- string
|
|
"""), idl.errors.ERROR_ID_MISSING_AST_REQUIRED_FIELD)
|
|
|
|
# Test array as name
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
array<foo>:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
deserializer: bar
|
|
"""), idl.errors.ERROR_ID_ARRAY_NOT_VALID_TYPE)
|
|
|
|
def test_struct_positive(self):
|
|
# type: () -> None
|
|
"""Positive struct tests."""
|
|
|
|
# Setup some common types
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
""")
|
|
|
|
self.assert_bind(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo: string
|
|
"""))
|
|
|
|
def test_struct_negative(self):
|
|
# type: () -> None
|
|
"""Negative struct tests."""
|
|
|
|
# Setup some common types
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
""")
|
|
|
|
# Test array as name
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
array<foo>:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo: string
|
|
"""), idl.errors.ERROR_ID_ARRAY_NOT_VALID_TYPE)
|
|
|
|
def test_field_positive(self):
|
|
# type: () -> None
|
|
"""Positive test cases for field."""
|
|
|
|
# Setup some common types
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
""")
|
|
|
|
# Short type
|
|
self.assert_bind(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
bar:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
foo: string
|
|
"""))
|
|
|
|
# Long type
|
|
self.assert_bind(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
bar:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
foo:
|
|
type: string
|
|
"""))
|
|
|
|
# Long type with default
|
|
self.assert_bind(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
bar:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
foo:
|
|
type: string
|
|
default: bar
|
|
"""))
|
|
|
|
# Test array as field type
|
|
self.assert_bind(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo: array<string>
|
|
"""))
|
|
|
|
# Test array as field type
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
types:
|
|
arrayfake:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
arrayOfString: arrayfake
|
|
"""))
|
|
|
|
def test_field_negative(self):
|
|
# type: () -> None
|
|
"""Negative field tests."""
|
|
|
|
# Setup some common types
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
|
|
bindata:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: bindata
|
|
bindata_subtype: uuid
|
|
""")
|
|
|
|
# Test field of a struct type with a default
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
fields:
|
|
field1: string
|
|
|
|
bar:
|
|
description: foo
|
|
fields:
|
|
field2:
|
|
type: foo
|
|
default: foo
|
|
|
|
"""), idl.errors.ERROR_ID_FIELD_MUST_BE_EMPTY_FOR_STRUCT)
|
|
|
|
# Test array as field name
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
array<foo>: string
|
|
"""), idl.errors.ERROR_ID_ARRAY_NOT_VALID_TYPE)
|
|
|
|
# Test recursive array as field type
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo: array<array<string>>
|
|
"""), idl.errors.ERROR_ID_BAD_ARRAY_TYPE_NAME)
|
|
|
|
# Test inherited default with array
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo: array<string>
|
|
"""), idl.errors.ERROR_ID_ARRAY_NO_DEFAULT)
|
|
|
|
# Test non-inherited default with array
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo:
|
|
type: array<string>
|
|
default: 123
|
|
"""), idl.errors.ERROR_ID_ARRAY_NO_DEFAULT)
|
|
|
|
# Test bindata with default
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo:
|
|
type: bindata
|
|
default: 42
|
|
"""), idl.errors.ERROR_ID_BAD_BINDATA_DEFAULT)
|
|
|
|
# Test default and optional for the same field
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo:
|
|
type: string
|
|
default: 42
|
|
optional: true
|
|
"""), idl.errors.ERROR_ID_ILLEGAL_FIELD_DEFAULT_AND_OPTIONAL)
|
|
|
|
def test_ignored_field_negative(self):
|
|
# type: () -> None
|
|
"""Test that if a field is marked as ignored, no other properties are set."""
|
|
for test_value in [
|
|
"optional: true",
|
|
"default: foo",
|
|
]:
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
foo:
|
|
type: string
|
|
ignore: true
|
|
%s
|
|
""" % (test_value)), idl.errors.ERROR_ID_FIELD_MUST_BE_EMPTY_FOR_IGNORED)
|
|
|
|
def test_chained_type_positive(self):
|
|
# type: () -> None
|
|
"""Positive parser chaining test cases."""
|
|
# Setup some common types
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
|
|
|
|
foo1:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: chain
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
|
|
""")
|
|
|
|
# Chaining only
|
|
self.assert_bind(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
chained_types:
|
|
foo1: alias
|
|
"""))
|
|
|
|
def test_chained_type_negative(self):
|
|
# type: () -> None
|
|
"""Negative parser chaining test cases."""
|
|
# Setup some common types
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
|
|
foo1:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: chain
|
|
serializer: foo
|
|
deserializer: foo
|
|
|
|
""")
|
|
|
|
# Chaining with strict struct
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
bar1:
|
|
description: foo
|
|
strict: true
|
|
chained_types:
|
|
foo1: alias
|
|
"""), idl.errors.ERROR_ID_CHAINED_NO_TYPE_STRICT)
|
|
|
|
# Non-'any' type as chained type
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
chained_types:
|
|
string: alias
|
|
"""), idl.errors.ERROR_ID_CHAINED_TYPE_WRONG_BSON_TYPE)
|
|
|
|
# Chaining and fields only with same name
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
chained_types:
|
|
foo1: alias
|
|
fields:
|
|
foo1: string
|
|
"""), idl.errors.ERROR_ID_CHAINED_DUPLICATE_FIELD)
|
|
|
|
# Non-existent chained type
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
chained_types:
|
|
foobar1: alias
|
|
fields:
|
|
foo1: string
|
|
"""), idl.errors.ERROR_ID_UNKNOWN_TYPE)
|
|
|
|
# A regular field as a chained type
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
foo1: string
|
|
foo2: foobar1
|
|
"""), idl.errors.ERROR_ID_UNKNOWN_TYPE)
|
|
|
|
# Array of chained types
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
bar1:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
field1: array<foo1>
|
|
"""), idl.errors.ERROR_ID_NO_ARRAY_OF_CHAIN)
|
|
|
|
def test_chained_struct_positive(self):
|
|
# type: () -> None
|
|
"""Positive parser chaining test cases."""
|
|
# Setup some common types
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
|
|
|
|
foo1:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: chain
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
|
|
structs:
|
|
chained:
|
|
description: foo
|
|
strict: false
|
|
chained_types:
|
|
foo1: alias
|
|
|
|
chained2:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
field1: string
|
|
""")
|
|
|
|
# A struct with only chaining
|
|
self.assert_bind(test_preamble + indent_text(1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: true
|
|
chained_structs:
|
|
chained2: alias
|
|
""")))
|
|
|
|
# Chaining struct's fields and explicit fields
|
|
self.assert_bind(test_preamble + indent_text(1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: true
|
|
chained_structs:
|
|
chained2: alias
|
|
fields:
|
|
str1: string
|
|
""")))
|
|
|
|
# Chained types and structs
|
|
self.assert_bind(test_preamble + indent_text(1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
chained_types:
|
|
foo1: alias
|
|
chained_structs:
|
|
chained2: alias
|
|
fields:
|
|
str1: string
|
|
""")))
|
|
|
|
# Non-strict chained struct
|
|
self.assert_bind(test_preamble + indent_text(1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
chained_structs:
|
|
chained2: alias
|
|
fields:
|
|
foo1: string
|
|
""")))
|
|
|
|
def test_chained_struct_negative(self):
|
|
# type: () -> None
|
|
"""Negative parser chaining test cases."""
|
|
# Setup some common types
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
|
|
|
|
foo1:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: chain
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
|
|
structs:
|
|
chained:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
field1: string
|
|
|
|
chained2:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
field1: string
|
|
""")
|
|
|
|
# Non-existing chained struct
|
|
self.assert_bind_fail(test_preamble + indent_text(1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: true
|
|
chained_structs:
|
|
foobar1: alias
|
|
""")), idl.errors.ERROR_ID_UNKNOWN_TYPE)
|
|
|
|
# Type as chained struct
|
|
self.assert_bind_fail(test_preamble + indent_text(1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: true
|
|
chained_structs:
|
|
foo1: alias
|
|
""")), idl.errors.ERROR_ID_CHAINED_STRUCT_NOT_FOUND)
|
|
|
|
# Struct as chained type
|
|
self.assert_bind_fail(test_preamble + indent_text(1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
chained_types:
|
|
chained: alias
|
|
""")), idl.errors.ERROR_ID_CHAINED_TYPE_NOT_FOUND)
|
|
|
|
# Duplicated field names across chained struct's fields and fields
|
|
self.assert_bind_fail(test_preamble + indent_text(1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
chained_structs:
|
|
chained: alias
|
|
fields:
|
|
field1: string
|
|
""")), idl.errors.ERROR_ID_CHAINED_DUPLICATE_FIELD)
|
|
|
|
# Duplicated field names across chained structs
|
|
self.assert_bind_fail(test_preamble + indent_text(1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
chained_structs:
|
|
chained: alias
|
|
chained2: alias
|
|
""")), idl.errors.ERROR_ID_CHAINED_DUPLICATE_FIELD)
|
|
|
|
# Chained struct with strict true
|
|
self.assert_bind_fail(test_preamble + indent_text(1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
field1: string
|
|
|
|
foobar:
|
|
description: foo
|
|
strict: false
|
|
chained_structs:
|
|
bar1: alias
|
|
fields:
|
|
f1: string
|
|
|
|
""")), idl.errors.ERROR_ID_CHAINED_NO_NESTED_STRUCT_STRICT)
|
|
|
|
# Chained struct with nested chained struct
|
|
self.assert_bind_fail(test_preamble + indent_text(1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
chained_structs:
|
|
chained: alias
|
|
|
|
foobar:
|
|
description: foo
|
|
strict: false
|
|
chained_structs:
|
|
bar1: alias
|
|
fields:
|
|
f1: string
|
|
|
|
""")), idl.errors.ERROR_ID_CHAINED_NO_NESTED_CHAINED)
|
|
|
|
# Chained struct with nested chained type
|
|
self.assert_bind_fail(test_preamble + indent_text(1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
chained_types:
|
|
foo1: alias
|
|
|
|
foobar:
|
|
description: foo
|
|
strict: false
|
|
chained_structs:
|
|
bar1: alias
|
|
fields:
|
|
f1: bar1
|
|
|
|
""")), idl.errors.ERROR_ID_CHAINED_NO_NESTED_CHAINED)
|
|
|
|
def test_enum_positive(self):
|
|
# type: () -> None
|
|
"""Positive enum test cases."""
|
|
|
|
# Test int
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: int
|
|
values:
|
|
v1: 3
|
|
v2: 1
|
|
v3: 2
|
|
"""))
|
|
|
|
# Test string
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: string
|
|
values:
|
|
v1: 0
|
|
v2: 1
|
|
v3: 2
|
|
"""))
|
|
|
|
def test_enum_negative(self):
|
|
# type: () -> None
|
|
"""Negative enum test cases."""
|
|
|
|
# Test wrong type
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: foo
|
|
values:
|
|
v1: 0
|
|
"""), idl.errors.ERROR_ID_ENUM_BAD_TYPE)
|
|
|
|
# Test int - non continuous
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: int
|
|
values:
|
|
v1: 0
|
|
v3: 2
|
|
"""), idl.errors.ERROR_ID_ENUM_NON_CONTINUOUS_RANGE)
|
|
|
|
# Test int - dups
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: int
|
|
values:
|
|
v1: 1
|
|
v3: 1
|
|
"""), idl.errors.ERROR_ID_ENUM_NON_UNIQUE_VALUES)
|
|
|
|
# Test int - non-integer value
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: int
|
|
values:
|
|
v1: foo
|
|
v3: 1
|
|
"""), idl.errors.ERROR_ID_ENUM_BAD_INT_VAUE)
|
|
|
|
# Test string - dups
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: string
|
|
values:
|
|
v1: foo
|
|
v3: foo
|
|
"""), idl.errors.ERROR_ID_ENUM_NON_UNIQUE_VALUES)
|
|
|
|
def test_struct_enum_negative(self):
|
|
# type: () -> None
|
|
"""Negative enum test cases."""
|
|
|
|
test_preamble = textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: int
|
|
values:
|
|
v1: 0
|
|
v2: 1
|
|
""")
|
|
|
|
# Test array of enums
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo1:
|
|
description: foo
|
|
fields:
|
|
foo1: array<foo>
|
|
"""), idl.errors.ERROR_ID_NO_ARRAY_ENUM)
|
|
|
|
# Test default
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo1:
|
|
description: foo
|
|
fields:
|
|
foo1:
|
|
type: foo
|
|
default: 1
|
|
"""), idl.errors.ERROR_ID_FIELD_MUST_BE_EMPTY_FOR_ENUM)
|
|
|
|
def test_command_positive(self):
|
|
# type: () -> None
|
|
"""Positive command tests."""
|
|
|
|
# Setup some common types
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
""")
|
|
|
|
self.assert_bind(test_preamble + textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
namespace: ignored
|
|
strict: true
|
|
fields:
|
|
foo1: string
|
|
"""))
|
|
|
|
def test_command_negative(self):
|
|
# type: () -> None
|
|
"""Negative command tests."""
|
|
|
|
# Setup some common types
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
""")
|
|
|
|
# Commands cannot be fields in other commands
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
namespace: ignored
|
|
fields:
|
|
foo1: string
|
|
|
|
bar:
|
|
description: foo
|
|
namespace: ignored
|
|
fields:
|
|
foo: foo
|
|
"""), idl.errors.ERROR_ID_FIELD_NO_COMMAND)
|
|
|
|
# Commands cannot be fields in structs
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
namespace: ignored
|
|
fields:
|
|
foo1: string
|
|
|
|
structs:
|
|
bar:
|
|
description: foo
|
|
fields:
|
|
foo: foo
|
|
"""), idl.errors.ERROR_ID_FIELD_NO_COMMAND)
|
|
|
|
# Commands cannot have a field as the same name
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
namespace: ignored
|
|
fields:
|
|
foo: string
|
|
"""), idl.errors.ERROR_ID_COMMAND_DUPLICATES_FIELD)
|
|
|
|
def test_command_doc_sequence_positive(self):
|
|
# type: () -> None
|
|
"""Positive supports_doc_sequence tests."""
|
|
# pylint: disable=invalid-name
|
|
|
|
# Setup some common types
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
object:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: object
|
|
serializer: foo
|
|
deserializer: foo
|
|
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
|
|
structs:
|
|
foo_struct:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo: object
|
|
""")
|
|
|
|
self.assert_bind(test_preamble + textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
namespace: ignored
|
|
fields:
|
|
foo1:
|
|
type: array<object>
|
|
supports_doc_sequence: true
|
|
"""))
|
|
|
|
self.assert_bind(test_preamble + textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
namespace: ignored
|
|
fields:
|
|
foo1:
|
|
type: array<foo_struct>
|
|
supports_doc_sequence: true
|
|
"""))
|
|
|
|
def test_command_doc_sequence_negative(self):
|
|
# type: () -> None
|
|
"""Negative supports_doc_sequence tests."""
|
|
# pylint: disable=invalid-name
|
|
|
|
# Setup some common types
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
object:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: object
|
|
serializer: foo
|
|
deserializer: foo
|
|
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
|
|
any_type:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: any
|
|
serializer: foo
|
|
deserializer: foo
|
|
""")
|
|
|
|
test_preamble2 = test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo_struct:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo: object
|
|
""")
|
|
|
|
# A struct
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
fields:
|
|
foo:
|
|
type: array<object>
|
|
supports_doc_sequence: true
|
|
"""), idl.errors.ERROR_ID_STRUCT_NO_DOC_SEQUENCE)
|
|
|
|
# A non-array type
|
|
self.assert_bind_fail(test_preamble + textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
namespace: ignored
|
|
fields:
|
|
foo:
|
|
type: object
|
|
supports_doc_sequence: true
|
|
"""), idl.errors.ERROR_ID_NO_DOC_SEQUENCE_FOR_NON_ARRAY)
|
|
|
|
# An array of a scalar
|
|
self.assert_bind_fail(test_preamble2 + textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
namespace: ignored
|
|
fields:
|
|
foo1:
|
|
type: array<string>
|
|
supports_doc_sequence: true
|
|
"""), idl.errors.ERROR_ID_NO_DOC_SEQUENCE_FOR_NON_OBJECT)
|
|
|
|
# An array of 'any'
|
|
self.assert_bind_fail(test_preamble2 + textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
namespace: ignored
|
|
fields:
|
|
foo1:
|
|
type: array<string>
|
|
supports_doc_sequence: true
|
|
"""), idl.errors.ERROR_ID_NO_DOC_SEQUENCE_FOR_NON_OBJECT)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
unittest.main()
|