mirror of https://github.com/mongodb/mongo
1992 lines
60 KiB
Python
1992 lines
60 KiB
Python
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (C) 2018-present MongoDB, Inc.
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the Server Side Public License, version 1,
|
|
# as published by MongoDB, Inc.
|
|
#
|
|
# 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
|
|
# Server Side Public License for more details.
|
|
#
|
|
# You should have received a copy of the Server Side Public License
|
|
# along with this program. If not, see
|
|
# <http://www.mongodb.com/licensing/server-side-public-license>.
|
|
#
|
|
# As a special exception, the copyright holders give permission to link the
|
|
# code of portions of this program with the OpenSSL library under certain
|
|
# conditions as described in each individual source file and distribute
|
|
# linked combinations including the program with the OpenSSL library. You
|
|
# must comply with the Server Side Public License in all respects for
|
|
# all of the code used other than as permitted herein. If you modify file(s)
|
|
# with this exception, you may extend this exception to your version of the
|
|
# file(s), but you are not obligated to do so. If you do not wish to do so,
|
|
# delete this exception statement from your version. If you delete this
|
|
# exception statement from all source files in the program, then also delete
|
|
# it in the license file.
|
|
#
|
|
# pylint: disable=too-many-lines
|
|
"""Test cases for IDL binder."""
|
|
|
|
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) -> str
|
|
"""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, str) -> str
|
|
"""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."""
|
|
|
|
# pylint: disable=too-many-public-methods
|
|
|
|
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.assertEqual(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)
|
|
|
|
# Test duplicate comparison order
|
|
self.assert_bind_fail(
|
|
test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: false
|
|
generate_comparison_operators: true
|
|
fields:
|
|
foo:
|
|
type: string
|
|
comparison_order: 1
|
|
bar:
|
|
type: string
|
|
comparison_order: 1
|
|
"""), idl.errors.ERROR_ID_IS_DUPLICATE_COMPARISON_ORDER)
|
|
|
|
# Test field marked with non_const_getter in immutable struct
|
|
self.assert_bind_fail(
|
|
test_preamble + textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
immutable: true
|
|
fields:
|
|
foo:
|
|
type: string
|
|
non_const_getter: true
|
|
"""), idl.errors.ERROR_ID_NON_CONST_GETTER_IN_IMMUTABLE_STRUCT)
|
|
|
|
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
|
|
""")))
|
|
|
|
# Inline Chained struct with strict true
|
|
self.assert_bind(test_preamble + indent_text(
|
|
1,
|
|
textwrap.dedent("""
|
|
bar1:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
field1: string
|
|
|
|
foobar:
|
|
description: foo
|
|
strict: false
|
|
inline_chained_structs: true
|
|
chained_structs:
|
|
bar1: alias
|
|
fields:
|
|
f1: string
|
|
|
|
""")))
|
|
|
|
# Inline Chained struct with strict true and inline_chained_structs defaulted
|
|
self.assert_bind(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
|
|
""")))
|
|
|
|
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
|
|
inline_chained_structs: 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)
|
|
|
|
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)
|
|
|
|
def test_command_type_positive(self):
|
|
# type: () -> None
|
|
"""Positive command custom type test cases."""
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
""")
|
|
|
|
# string
|
|
self.assert_bind(test_preamble + textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
namespace: type
|
|
type: string
|
|
fields:
|
|
field1: string
|
|
"""))
|
|
|
|
# array of string
|
|
self.assert_bind(test_preamble + textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
namespace: type
|
|
type: array<string>
|
|
fields:
|
|
field1: string
|
|
"""))
|
|
|
|
def test_command_type_negative(self):
|
|
# type: () -> None
|
|
"""Negative command type test cases."""
|
|
test_preamble = textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
""")
|
|
|
|
# supports_doc_sequence must be a bool
|
|
self.assert_bind_fail(
|
|
test_preamble + textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
namespace: type
|
|
type: int
|
|
fields:
|
|
field1: string
|
|
"""), idl.errors.ERROR_ID_UNKNOWN_TYPE)
|
|
|
|
def test_server_parameter_positive(self):
|
|
# type: () -> None
|
|
"""Positive server parameter test cases."""
|
|
|
|
# server parameter with storage.
|
|
# Also try valid set_at values.
|
|
for set_at in ["startup", "runtime", "[ startup, runtime ]"]:
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
server_parameters:
|
|
foo:
|
|
set_at: %s
|
|
description: bar
|
|
cpp_varname: baz
|
|
""" % (set_at)))
|
|
|
|
# server parameter with storage and optional fields.
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
server_parameters:
|
|
foo:
|
|
set_at: startup
|
|
description: bar
|
|
cpp_varname: baz
|
|
default: 42
|
|
on_update: buzz
|
|
validator:
|
|
gt: 0
|
|
gte: 1
|
|
lte: 999
|
|
lt: 1000
|
|
callback: qux
|
|
"""))
|
|
|
|
# Bound setting with arbitrary expression default and validators.
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
server_parameters:
|
|
foo:
|
|
set_at: startup
|
|
description: bar
|
|
cpp_varname: baz
|
|
default:
|
|
expr: 'kDefaultValue'
|
|
validator:
|
|
gte:
|
|
expr: 'kMinimumValue'
|
|
is_constexpr: true
|
|
lte:
|
|
expr: 'kMaximumValue'
|
|
is_constexpr: false
|
|
gt: 0
|
|
lt: 255
|
|
"""))
|
|
|
|
# Specialized SCPs.
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
server_parameters:
|
|
foo:
|
|
set_at: startup
|
|
description: bar
|
|
cpp_class: baz
|
|
"""))
|
|
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
server_parameters:
|
|
foo:
|
|
set_at: startup
|
|
description: bar
|
|
cpp_class:
|
|
name: baz
|
|
"""))
|
|
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
server_parameters:
|
|
foo:
|
|
set_at: startup
|
|
description: bar
|
|
cpp_class:
|
|
name: baz
|
|
data: bling
|
|
override_set: true
|
|
override_ctor: false
|
|
"""))
|
|
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
server_parameters:
|
|
foo:
|
|
set_at: startup
|
|
description: bar
|
|
cpp_class: baz
|
|
condition: { expr: "true" }
|
|
redact: true
|
|
test_only: true
|
|
deprecated_name: bling
|
|
"""))
|
|
|
|
# Default without data.
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
server_parameters:
|
|
foo:
|
|
set_at: startup
|
|
description: bar
|
|
cpp_class: baz
|
|
default: blong
|
|
"""))
|
|
|
|
def test_server_parameter_negative(self):
|
|
# type: () -> None
|
|
"""Negative server parameter test cases."""
|
|
|
|
# Invalid set_at values.
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
server_parameters:
|
|
foo:
|
|
set_at: shutdown
|
|
description: bar
|
|
cpp_varname: baz
|
|
"""), idl.errors.ERROR_ID_BAD_SETAT_SPECIFIER)
|
|
|
|
# Mix of specialized with bound storage.
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
server_parameters:
|
|
foo:
|
|
set_at: startup
|
|
description: bar
|
|
cpp_class: baz
|
|
cpp_varname: bling
|
|
"""), idl.errors.ERROR_ID_SERVER_PARAMETER_INVALID_ATTR)
|
|
|
|
def test_config_option_positive(self):
|
|
# type: () -> None
|
|
"""Posative config option test cases."""
|
|
|
|
# Every field.
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
short_name: bar
|
|
deprecated_name: baz
|
|
deprecated_short_name: qux
|
|
description: comment
|
|
section: here
|
|
arg_vartype: String
|
|
cpp_varname: gStringVal
|
|
conflicts: bling
|
|
requires: blong
|
|
hidden: false
|
|
default: one
|
|
implicit: two
|
|
duplicate_behavior: append
|
|
source: yaml
|
|
positional: 1-2
|
|
validator:
|
|
gt: 0
|
|
lt: 100
|
|
gte: 1
|
|
lte: 99
|
|
callback: doSomething
|
|
"""))
|
|
|
|
# Required fields only.
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
description: comment
|
|
arg_vartype: Switch
|
|
source: yaml
|
|
"""))
|
|
|
|
# List and enum variants.
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
deprecated_name: [ baz, baz ]
|
|
deprecated_short_name: [ bling, blong ]
|
|
description: comment
|
|
arg_vartype: StringVector
|
|
source: [ cli, ini, yaml ]
|
|
conflicts: [ a, b, c ]
|
|
requires: [ d, e, f ]
|
|
hidden: true
|
|
duplicate_behavior: overwrite
|
|
"""))
|
|
|
|
# Positional variants.
|
|
for positional in ['1', '1-', '-2', '1-2']:
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
short_name: foo
|
|
description: comment
|
|
arg_vartype: Bool
|
|
source: cli
|
|
positional: %s
|
|
""" % (positional)))
|
|
# With implicit short name.
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
description: comment
|
|
arg_vartype: Bool
|
|
source: cli
|
|
positional: %s
|
|
""" % (positional)))
|
|
|
|
# Expressions in default, implicit, and validators.
|
|
self.assert_bind(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
description: bar
|
|
arg_vartype: String
|
|
source: cli
|
|
default: { expr: kDefault, is_constexpr: true }
|
|
implicit: { expr: kImplicit, is_constexpr: false }
|
|
validator:
|
|
gte: { expr: kMinimum }
|
|
lte: { expr: kMaximum }
|
|
"""))
|
|
|
|
def test_config_option_negative(self):
|
|
# type: () -> None
|
|
"""Negative config option test cases."""
|
|
|
|
# Invalid source.
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
description: comment
|
|
arg_vartype: Long
|
|
source: json
|
|
"""), idl.errors.ERROR_ID_BAD_SOURCE_SPECIFIER)
|
|
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
description: comment
|
|
arg_vartype: StringMap
|
|
source: [ cli, yaml ]
|
|
duplicate_behavior: guess
|
|
"""), idl.errors.ERROR_ID_BAD_DUPLICATE_BEHAVIOR_SPECIFIER)
|
|
|
|
for positional in ["x", "1-2-3", "-2-", "1--3"]:
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
description: comment
|
|
arg_vartype: String
|
|
source: cli
|
|
positional: %s
|
|
""" % (positional)), idl.errors.ERROR_ID_BAD_NUMERIC_RANGE)
|
|
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
description: comment
|
|
short_name: "bar.baz"
|
|
arg_vartype: Bool
|
|
source: cli
|
|
"""), idl.errors.ERROR_ID_INVALID_SHORT_NAME)
|
|
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
description: comment
|
|
short_name: bar
|
|
deprecated_short_name: "baz.qux"
|
|
arg_vartype: Long
|
|
source: cli
|
|
"""), idl.errors.ERROR_ID_INVALID_SHORT_NAME)
|
|
|
|
# dottedName is not valid as a shortName.
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
configs:
|
|
"foo.bar":
|
|
description: comment
|
|
arg_vartype: String
|
|
source: cli
|
|
positional: 1
|
|
"""), idl.errors.ERROR_ID_MISSING_SHORTNAME_FOR_POSITIONAL)
|
|
|
|
# Invalid shortname using boost::po format directly.
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
short_name: "foo,f"
|
|
arg_vartype: Switch
|
|
description: comment
|
|
source: cli
|
|
"""), idl.errors.ERROR_ID_INVALID_SHORT_NAME)
|
|
|
|
# Invalid single names, must be single alpha char.
|
|
for name in ["foo", "1", ".", ""]:
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
configs:
|
|
foo:
|
|
single_name: "%s"
|
|
arg_vartype: Switch
|
|
description: comment
|
|
source: cli
|
|
""" % (name)), idl.errors.ERROR_ID_INVALID_SINGLE_NAME)
|
|
|
|
# Single names require a valid short name.
|
|
self.assert_bind_fail(
|
|
textwrap.dedent("""
|
|
configs:
|
|
"foo.bar":
|
|
single_name: f
|
|
arg_vartype: Switch
|
|
description: comment
|
|
source: cli
|
|
"""), idl.errors.ERROR_ID_MISSING_SHORT_NAME_WITH_SINGLE_NAME)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
unittest.main()
|