mirror of https://github.com/mongodb/mongo
2156 lines
58 KiB
Python
2156 lines
58 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.
|
|
#
|
|
"""Test cases for IDL parser."""
|
|
|
|
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__)))
|
|
import testcase
|
|
from context import idl
|
|
else:
|
|
from . import testcase
|
|
from .context import idl
|
|
|
|
|
|
class TestParser(testcase.IDLTestcase):
|
|
"""Test the IDL parser only."""
|
|
|
|
def test_empty(self):
|
|
# type: () -> None
|
|
"""Test an empty document works."""
|
|
self.assert_parse("")
|
|
|
|
def test_root_negative(self):
|
|
# type: () -> None
|
|
"""Test unknown root scalar fails."""
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
fake:
|
|
cpp_namespace: 'foo'
|
|
"""),
|
|
idl.errors.ERROR_ID_UNKNOWN_ROOT,
|
|
)
|
|
|
|
def test_global_positive(self):
|
|
# type: () -> None
|
|
"""Postive global tests."""
|
|
# cpp_namespace alone
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
global:
|
|
cpp_namespace: 'foo'""")
|
|
)
|
|
|
|
# cpp_includes scalar
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
global:
|
|
cpp_includes: 'foo'""")
|
|
)
|
|
|
|
# cpp_includes list
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
global:
|
|
cpp_includes:
|
|
- 'bar'
|
|
- 'foo'""")
|
|
)
|
|
|
|
def test_global_negative(self):
|
|
# type: () -> None
|
|
"""Negative global tests."""
|
|
|
|
# Global is a scalar
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
global: foo
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# Duplicate globals
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
global:
|
|
cpp_namespace: 'foo'
|
|
global:
|
|
cpp_namespace: 'bar'
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_NODE,
|
|
)
|
|
|
|
# Duplicate cpp_namespace
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
global:
|
|
cpp_namespace: 'foo'
|
|
cpp_namespace: 'foo'"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_NODE,
|
|
)
|
|
|
|
# Duplicate cpp_includes
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
global:
|
|
cpp_includes: 'foo'
|
|
cpp_includes: 'foo'"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_NODE,
|
|
)
|
|
|
|
# cpp_namespace as a sequence
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
global:
|
|
cpp_namespace:
|
|
- 'foo'
|
|
- 'bar'"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# cpp_namespace as a map
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
global:
|
|
cpp_namespace:
|
|
name: 'foo'"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# cpp_includes as a map
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
global:
|
|
cpp_includes:
|
|
inc1: 'foo'"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE_SCALAR_OR_SEQUENCE,
|
|
)
|
|
|
|
# cpp_includes as a sequence of tuples
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
global:
|
|
cpp_includes:
|
|
- inc1: 'foo'"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# Unknown scalar
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
global:
|
|
bar: 'foo'
|
|
"""),
|
|
idl.errors.ERROR_ID_UNKNOWN_NODE,
|
|
)
|
|
|
|
def test_type_positive(self):
|
|
# type: () -> None
|
|
"""Positive type test cases."""
|
|
|
|
# Test all positive fields works
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: foo
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
bindata_subtype: foo
|
|
is_view: false
|
|
""")
|
|
)
|
|
|
|
# Test sequence of bson serialization types
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type:
|
|
- foo
|
|
- bar
|
|
is_view: false
|
|
""")
|
|
)
|
|
|
|
def test_type_negative(self):
|
|
# type: () -> None
|
|
"""Negative type test cases."""
|
|
|
|
# Test duplicate types
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo:
|
|
description: test
|
|
cpp_type: foo
|
|
bson_serialization_type: int
|
|
is_view: false
|
|
types:
|
|
bar:
|
|
description: test
|
|
cpp_type: foo
|
|
bson_serialization_type: int
|
|
is_view: false
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_NODE,
|
|
)
|
|
|
|
# Test scalar fails
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo: 'bar'"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# Test unknown field
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo:
|
|
bogus: foo
|
|
description: test
|
|
cpp_type: foo
|
|
bson_serialization_type:
|
|
is_view: false
|
|
"""),
|
|
idl.errors.ERROR_ID_UNKNOWN_NODE,
|
|
)
|
|
|
|
# test duplicate field
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo:
|
|
description: foo
|
|
description: test
|
|
cpp_type: foo
|
|
bson_serialization_type:
|
|
is_view: false
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_NODE,
|
|
)
|
|
|
|
# test list instead of scalar
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
- foo:
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
multiple=True,
|
|
)
|
|
|
|
# test list instead of scalar
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo:
|
|
- bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
multiple=True,
|
|
)
|
|
|
|
# test map instead of scalar
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo:
|
|
description:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
multiple=True,
|
|
)
|
|
|
|
# test missing bson_serialization_type field
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo:
|
|
description: foo
|
|
cpp_type: foo
|
|
is_view: false
|
|
"""),
|
|
idl.errors.ERROR_ID_MISSING_REQUIRED_FIELD,
|
|
)
|
|
|
|
# test missing cpp_type field
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo:
|
|
description: foo
|
|
bson_serialization_type: foo
|
|
is_view: false
|
|
"""),
|
|
idl.errors.ERROR_ID_MISSING_REQUIRED_FIELD,
|
|
)
|
|
|
|
def test_struct_positive(self):
|
|
# type: () -> None
|
|
"""Positive struct test cases."""
|
|
|
|
# All fields with true for bools
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
immutable: true
|
|
inline_chained_structs: true
|
|
generate_comparison_operators: true
|
|
cpp_validator_func: funcName
|
|
fields:
|
|
foo: bar
|
|
""")
|
|
)
|
|
|
|
# All fields with false for bools
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: false
|
|
immutable: false
|
|
inline_chained_structs: false
|
|
generate_comparison_operators: false
|
|
cpp_validator_func: funcName
|
|
fields:
|
|
foo: bar
|
|
""")
|
|
)
|
|
|
|
# Missing fields
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
""")
|
|
)
|
|
|
|
def test_struct_negative(self):
|
|
# type: () -> None
|
|
"""Negative struct test cases."""
|
|
|
|
# Struct as a scalar
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo: foo
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# unknown field
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
foo: bar
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_UNKNOWN_NODE,
|
|
)
|
|
|
|
# strict is a bool
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: bar
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_VALID_BOOL,
|
|
)
|
|
|
|
# immutable is a bool
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
immutable: bar
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_VALID_BOOL,
|
|
)
|
|
|
|
# inline_chained_structs is a bool
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
inline_chained_structs: bar
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_VALID_BOOL,
|
|
)
|
|
|
|
# generate_comparison_operators is a bool
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
generate_comparison_operators: bar
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_VALID_BOOL,
|
|
)
|
|
|
|
# cpp_name is not allowed
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
cpp_name: bar
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_UNKNOWN_NODE,
|
|
)
|
|
|
|
def test_variant_positive(self):
|
|
# type: () -> None
|
|
"""Positive variant test cases."""
|
|
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
fields:
|
|
my_variant_field1:
|
|
type:
|
|
variant: [int, string]
|
|
my_variant_field2:
|
|
type:
|
|
variant:
|
|
- string
|
|
- array<string>
|
|
- object
|
|
""")
|
|
)
|
|
|
|
def test_variant_negative(self):
|
|
# type: () -> None
|
|
"""Negative variant test cases."""
|
|
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
fields:
|
|
my_variant_field:
|
|
type:
|
|
variant: {}
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
fields:
|
|
my_variant_field:
|
|
type:
|
|
variant: 1
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
fields:
|
|
my_variant_field:
|
|
type:
|
|
variant: []
|
|
unknown_option: true
|
|
"""),
|
|
idl.errors.ERROR_ID_UNKNOWN_NODE,
|
|
)
|
|
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
fields:
|
|
my_variant_field:
|
|
type:
|
|
variant:
|
|
- string
|
|
- {variant: [string, int]}
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
generate_comparison_operators: true
|
|
fields:
|
|
my_variant_field:
|
|
type:
|
|
variant: [string, int]
|
|
"""),
|
|
idl.errors.ERROR_ID_VARIANT_COMPARISON,
|
|
)
|
|
|
|
def test_field_positive(self):
|
|
# type: () -> None
|
|
"""Positive field test cases."""
|
|
|
|
# Test short types
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
fields:
|
|
foo: short
|
|
""")
|
|
)
|
|
|
|
# Test all fields
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
fields:
|
|
foo:
|
|
type: foo
|
|
description: foo
|
|
optional: true
|
|
ignore: true
|
|
cpp_name: bar
|
|
comparison_order: 3
|
|
stability: unstable
|
|
""")
|
|
)
|
|
|
|
# Test false bools
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
foo:
|
|
type: string
|
|
optional: false
|
|
ignore: false
|
|
stability: stable
|
|
""")
|
|
)
|
|
|
|
def test_field_negative(self):
|
|
# type: () -> None
|
|
"""Negative field test cases."""
|
|
|
|
# Test duplicate fields
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
foo: short
|
|
foo: int
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_NODE,
|
|
)
|
|
|
|
# Test bad bool
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
foo:
|
|
type: string
|
|
optional: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_VALID_BOOL,
|
|
)
|
|
|
|
# Test bad bool
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
foo:
|
|
type: string
|
|
ignore: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_VALID_BOOL,
|
|
)
|
|
|
|
# Test bad int scalar
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
foo:
|
|
type: string
|
|
comparison_order:
|
|
- a
|
|
- b
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# Test bad int
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
foo:
|
|
type: string
|
|
comparison_order: 3.14159
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_VALID_INT,
|
|
)
|
|
|
|
# Test bad negative int
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: false
|
|
fields:
|
|
foo:
|
|
type: string
|
|
comparison_order: -1
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_VALID_NON_NEGATIVE_INT,
|
|
)
|
|
|
|
def test_name_collisions_negative(self):
|
|
# type: () -> None
|
|
"""Negative tests for type collisions."""
|
|
# Struct after type
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo1:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
is_view: false
|
|
|
|
structs:
|
|
foo1:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo: string
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
|
|
)
|
|
|
|
# Type after struct
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo1:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo: string
|
|
|
|
types:
|
|
foo1:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
is_view: false
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
|
|
)
|
|
|
|
def test_chained_type_positive(self):
|
|
# type: () -> None
|
|
"""Positive parser chaining test cases."""
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo1:
|
|
description: foo
|
|
chained_types:
|
|
foo1: alias
|
|
foo2: alias
|
|
""")
|
|
)
|
|
|
|
def test_chained_type_negative(self):
|
|
# type: () -> None
|
|
"""Negative parser chaining test cases."""
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo1:
|
|
description: foo
|
|
chained_types: foo1
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo1:
|
|
description: foo
|
|
chained_types:
|
|
- foo1
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# Duplicate chained types
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
bar1:
|
|
description: foo
|
|
strict: false
|
|
chained_types:
|
|
foo1: alias
|
|
foo1: alias
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_NODE,
|
|
)
|
|
|
|
def test_chained_struct_positive(self):
|
|
# type: () -> None
|
|
"""Positive parser chaining test cases."""
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo1:
|
|
description: foo
|
|
chained_structs:
|
|
foo1: foo1_cpp
|
|
foo2: foo2_cpp
|
|
""")
|
|
)
|
|
|
|
def test_chained_struct_negative(self):
|
|
# type: () -> None
|
|
"""Negative parser chaining test cases."""
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo1:
|
|
description: foo
|
|
chained_structs: foo1
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
foo1:
|
|
description: foo
|
|
chained_structs:
|
|
- foo1
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# Duplicate chained structs
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
structs:
|
|
bar1:
|
|
description: foo
|
|
strict: true
|
|
chained_structs:
|
|
chained: alias
|
|
chained: alias
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_NODE,
|
|
)
|
|
|
|
def test_enum_positive(self):
|
|
# type: () -> None
|
|
"""Positive enum test cases."""
|
|
|
|
# Test all positive fields works
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: foo
|
|
values:
|
|
v1: 0
|
|
""")
|
|
)
|
|
|
|
# Test extended value
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: foo
|
|
values:
|
|
v1:
|
|
description: foo
|
|
value: 0
|
|
""")
|
|
)
|
|
|
|
# Test extra_data
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: foo
|
|
values:
|
|
v1:
|
|
description: foo
|
|
value: 0
|
|
extra_data:
|
|
bar: baz
|
|
""")
|
|
)
|
|
|
|
def test_enum_negative(self):
|
|
# type: () -> None
|
|
"""Negative enum test cases."""
|
|
|
|
# Test duplicate enums
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: test
|
|
type: int
|
|
values:
|
|
v1: 0
|
|
|
|
foo:
|
|
description: test
|
|
type: int
|
|
values:
|
|
v1: 0
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
|
|
)
|
|
|
|
# Test scalar fails
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo: 'bar'"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# Test unknown field
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
bogus: foo
|
|
description: foo
|
|
type: foo
|
|
values:
|
|
v1: 0
|
|
"""),
|
|
idl.errors.ERROR_ID_UNKNOWN_NODE,
|
|
)
|
|
|
|
# test duplicate field
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
description: test
|
|
type: foo
|
|
values:
|
|
v1: 0
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_NODE,
|
|
)
|
|
|
|
# test list instead of scalar
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
- foo:
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
multiple=True,
|
|
)
|
|
|
|
# test list instead of scalar
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
- bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
multiple=True,
|
|
)
|
|
|
|
# test missing type field
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
values:
|
|
v1: 0
|
|
"""),
|
|
idl.errors.ERROR_ID_MISSING_REQUIRED_FIELD,
|
|
)
|
|
|
|
# test missing values field
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: foo
|
|
"""),
|
|
idl.errors.ERROR_ID_BAD_EMPTY_ENUM,
|
|
)
|
|
|
|
# Test no values
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: int
|
|
"""),
|
|
idl.errors.ERROR_ID_BAD_EMPTY_ENUM,
|
|
)
|
|
|
|
# Name collision with types
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
foo:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
is_view: false
|
|
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: foo
|
|
values:
|
|
v1: 0
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
|
|
)
|
|
|
|
# Name collision with structs
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
types:
|
|
string:
|
|
description: foo
|
|
cpp_type: foo
|
|
bson_serialization_type: string
|
|
serializer: foo
|
|
deserializer: foo
|
|
default: foo
|
|
is_view: false
|
|
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
fields:
|
|
foo: string
|
|
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: foo
|
|
values:
|
|
v1: 0
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
|
|
)
|
|
|
|
# Test int - duplicate names
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: int
|
|
values:
|
|
v1: 0
|
|
v1: 1
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_NODE,
|
|
)
|
|
|
|
# Test extra_data invalid type
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: int
|
|
values:
|
|
v1: [ 'foo' ]
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# Test extended value missing fields (description)
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: int
|
|
values:
|
|
v1:
|
|
value: 0
|
|
"""),
|
|
idl.errors.ERROR_ID_MISSING_REQUIRED_FIELD,
|
|
)
|
|
|
|
# Test extended value missing fields (value)
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: int
|
|
values:
|
|
v1:
|
|
description: foo
|
|
"""),
|
|
idl.errors.ERROR_ID_MISSING_REQUIRED_FIELD,
|
|
)
|
|
|
|
# Test invalid extra_data (scalar)
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: int
|
|
values:
|
|
v1:
|
|
description: foo
|
|
value: 0
|
|
extra_data: foo
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# Test invalid extra_data (sequence)
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
enums:
|
|
foo:
|
|
description: foo
|
|
type: int
|
|
values:
|
|
v1:
|
|
description: foo
|
|
value: 0
|
|
extra_data: [ foo ]
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
def test_command_positive(self):
|
|
# type: () -> None
|
|
"""Positive command test cases."""
|
|
|
|
# All fields with true for bools
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
strict: true
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: 1
|
|
is_deprecated: true
|
|
immutable: true
|
|
inline_chained_structs: true
|
|
generate_comparison_operators: true
|
|
cpp_name: foo
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
""")
|
|
)
|
|
|
|
# All fields with false for bools
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
strict: false
|
|
namespace: ignored
|
|
api_version: 1
|
|
is_deprecated: false
|
|
immutable: false
|
|
inline_chained_structs: false
|
|
generate_comparison_operators: false
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
""")
|
|
)
|
|
|
|
# All fields with false for bools, empty api_version
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
strict: false
|
|
namespace: ignored
|
|
api_version: ""
|
|
is_deprecated: false
|
|
immutable: false
|
|
inline_chained_structs: false
|
|
generate_comparison_operators: false
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
""")
|
|
)
|
|
|
|
# Quoted api_version
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: "1"
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
""")
|
|
)
|
|
|
|
# Namespace ignored
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
fields:
|
|
foo: bar
|
|
""")
|
|
)
|
|
|
|
# Namespace concatenate_with_db
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: concatenate_with_db
|
|
api_version: ""
|
|
fields:
|
|
foo: bar
|
|
""")
|
|
)
|
|
|
|
# No fields
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
strict: true
|
|
""")
|
|
)
|
|
|
|
# Reply type permitted without api_version
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
reply_type: foo_reply_struct
|
|
""")
|
|
)
|
|
|
|
def test_command_negative(self):
|
|
# type: () -> None
|
|
"""Negative command test cases."""
|
|
|
|
# Command as a scalar
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo: foo
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# unknown field
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
foo: bar
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_UNKNOWN_NODE,
|
|
)
|
|
|
|
# strict is a bool
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
strict: bar
|
|
namespace: ignored
|
|
api_version: ""
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_VALID_BOOL,
|
|
)
|
|
|
|
# command_name is required
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_MISSING_REQUIRED_FIELD,
|
|
)
|
|
|
|
# command_name is a scalar
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: [1]
|
|
namespace: ignored
|
|
api_version: ""
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
True,
|
|
)
|
|
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: ["1"]
|
|
namespace: ignored
|
|
api_version: ""
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
True,
|
|
)
|
|
|
|
# is_deprecated is a bool
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
is_deprecated: bar
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_VALID_BOOL,
|
|
)
|
|
|
|
# api_version is required
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_MISSING_REQUIRED_FIELD,
|
|
True,
|
|
)
|
|
|
|
# api_version is a scalar
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: [1]
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
True,
|
|
)
|
|
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ["1"]
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
True,
|
|
)
|
|
|
|
# Must specify reply_type if api_version is non-empty
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: 1
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_MISSING_REPLY_TYPE,
|
|
)
|
|
|
|
# Namespace is required
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: ""
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_MISSING_REQUIRED_FIELD,
|
|
)
|
|
|
|
# Namespace is wrong
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: foo
|
|
api_version: ""
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_BAD_COMMAND_NAMESPACE,
|
|
)
|
|
|
|
# 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
|
|
is_view: false
|
|
""")
|
|
|
|
# Commands and structs with same name
|
|
self.assert_parse_fail(
|
|
test_preamble
|
|
+ textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
fields:
|
|
foo: string
|
|
|
|
structs:
|
|
foo:
|
|
description: foo
|
|
fields:
|
|
foo: foo
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
|
|
)
|
|
|
|
# Commands and types with same name
|
|
self.assert_parse_fail(
|
|
test_preamble
|
|
+ textwrap.dedent("""
|
|
commands:
|
|
string:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
strict: true
|
|
fields:
|
|
foo: string
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
|
|
)
|
|
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: string
|
|
namespace: ignored
|
|
api_version: ""
|
|
strict: true
|
|
fields:
|
|
foo: string
|
|
""")
|
|
+ test_preamble,
|
|
idl.errors.ERROR_ID_DUPLICATE_SYMBOL,
|
|
)
|
|
|
|
# Namespace concatenate_with_db
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: concatenate_with_db
|
|
api_version: ""
|
|
type: foobar
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_COMMAND_TYPE_EXTRANEOUS,
|
|
)
|
|
|
|
# Reply type must be a scalar, not a mapping
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
reply_type:
|
|
arbitrary_field: foo
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
def test_command_doc_sequence_positive(self):
|
|
# type: () -> None
|
|
"""Positive supports_doc_sequence test cases."""
|
|
|
|
# supports_doc_sequence can be false
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
fields:
|
|
foo:
|
|
type: bar
|
|
supports_doc_sequence: false
|
|
""")
|
|
)
|
|
|
|
# supports_doc_sequence can be true
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
fields:
|
|
foo:
|
|
type: bar
|
|
supports_doc_sequence: true
|
|
""")
|
|
)
|
|
|
|
def test_command_doc_sequence_negative(self):
|
|
# type: () -> None
|
|
"""Negative supports_doc_sequence test cases."""
|
|
|
|
# supports_doc_sequence must be a bool
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
fields:
|
|
foo:
|
|
type: bar
|
|
supports_doc_sequence: foo
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_VALID_BOOL,
|
|
)
|
|
|
|
def test_command_type_positive(self):
|
|
# type: () -> None
|
|
"""Positive command custom type test cases."""
|
|
# string
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
strict: true
|
|
namespace: type
|
|
api_version: ""
|
|
type: string
|
|
fields:
|
|
foo: bar
|
|
""")
|
|
)
|
|
|
|
# array of string
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
strict: true
|
|
namespace: type
|
|
api_version: ""
|
|
type: array<string>
|
|
fields:
|
|
foo: bar
|
|
""")
|
|
)
|
|
|
|
# no fields
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
strict: true
|
|
namespace: type
|
|
api_version: ""
|
|
type: string
|
|
""")
|
|
)
|
|
|
|
def test_command_type_negative(self):
|
|
# type: () -> None
|
|
"""Negative command type test cases."""
|
|
|
|
# supports_doc_sequence must be a bool
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: type
|
|
api_version: ""
|
|
fields:
|
|
foo: bar
|
|
"""),
|
|
idl.errors.ERROR_ID_MISSING_REQUIRED_FIELD,
|
|
)
|
|
|
|
def test_stability_positive(self):
|
|
# type: () -> None
|
|
"""Positive stability-field test cases."""
|
|
for stability in ("stable", "unstable", "internal"):
|
|
self.assert_parse(
|
|
textwrap.dedent(f"""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: "1"
|
|
fields:
|
|
foo:
|
|
type: bar
|
|
stability: {stability}
|
|
reply_type: foo_reply_struct
|
|
""")
|
|
)
|
|
|
|
def test_stability_negative(self):
|
|
# type: () -> None
|
|
"""Negative stability-field test cases."""
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: ""
|
|
fields:
|
|
foo:
|
|
type: bar
|
|
stability: unstable
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_STABILITY_NO_API_VERSION,
|
|
)
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: "1"
|
|
fields:
|
|
foo:
|
|
type: bar
|
|
stability: "unknown"
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_STABILITY_UNKNOWN_VALUE,
|
|
)
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
namespace: ignored
|
|
api_version: "1"
|
|
fields:
|
|
foo:
|
|
type: bar
|
|
unstable: true
|
|
stability: "unstable"
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_DUPLICATE_UNSTABLE_STABILITY,
|
|
)
|
|
|
|
def test_scalar_or_mapping_negative(self):
|
|
# type: () -> None
|
|
"""Negative test for scalar_or_mapping type."""
|
|
|
|
# Test for scalar_or_mapping with a sequence.
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
server_parameters:
|
|
foo:
|
|
set_at: startup
|
|
description: bar
|
|
cpp_varname: baz
|
|
redact: false
|
|
default:
|
|
- one
|
|
- two
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE_SCALAR_OR_MAPPING,
|
|
)
|
|
|
|
def test_feature_flag(self):
|
|
# type: () -> None
|
|
"""Test feature flag."""
|
|
|
|
# Missing default
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
feature_flags:
|
|
featureFlagToaster:
|
|
description: "Make toast"
|
|
cpp_varname: gToaster
|
|
shouldBeFCVGated: true
|
|
"""),
|
|
idl.errors.ERROR_ID_MISSING_REQUIRED_FIELD,
|
|
)
|
|
|
|
# Missing shouldBeFCVGated
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
feature_flags:
|
|
featureFlagToaster:
|
|
description: "Make toast"
|
|
cpp_varname: gToaster
|
|
default: false
|
|
"""),
|
|
idl.errors.ERROR_ID_MISSING_REQUIRED_FIELD,
|
|
)
|
|
|
|
def test_command_alias(self):
|
|
# type: () -> None
|
|
"""Test the 'command_alis' field."""
|
|
|
|
# The 'command_name' and 'command_alias' fields cannot have same value.
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
command_alias: foo
|
|
namespace: ignored
|
|
api_version: 1
|
|
fields:
|
|
foo:
|
|
type: bar
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_COMMAND_DUPLICATES_NAME_AND_ALIAS,
|
|
)
|
|
|
|
def test_access_checks_positive(self):
|
|
# type: () -> None
|
|
"""Positive access_check test cases."""
|
|
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: 1
|
|
namespace: ignored
|
|
access_check:
|
|
ignore: true
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
""")
|
|
)
|
|
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: 1
|
|
namespace: ignored
|
|
access_check:
|
|
none: true
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
""")
|
|
)
|
|
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: 1
|
|
namespace: ignored
|
|
access_check:
|
|
simple:
|
|
check: is_authenticated
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
""")
|
|
)
|
|
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: 1
|
|
namespace: ignored
|
|
access_check:
|
|
complex:
|
|
- privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
- privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
- privilege:
|
|
agg_stage: bar
|
|
resource_pattern: bar
|
|
action_type: bar
|
|
- check: is_authenticated
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
""")
|
|
)
|
|
|
|
self.assert_parse(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: 1
|
|
namespace: ignored
|
|
access_check:
|
|
simple:
|
|
privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
""")
|
|
)
|
|
|
|
def test_access_checks_negative(self):
|
|
# type: () -> None
|
|
"""Negative access_check test cases."""
|
|
|
|
# check and privilege are present
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: 1
|
|
namespace: ignored
|
|
access_check:
|
|
simple:
|
|
check: foo
|
|
privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_EITHER_CHECK_OR_PRIVILEGE,
|
|
)
|
|
|
|
# simple: true fails
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: 1
|
|
namespace: ignored
|
|
access_check:
|
|
simple: true
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_IS_NODE_TYPE,
|
|
)
|
|
|
|
# simple empty fails
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: 1
|
|
namespace: ignored
|
|
access_check:
|
|
simple: {}
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_EITHER_CHECK_OR_PRIVILEGE,
|
|
)
|
|
|
|
# duplicate access_check - none and simple
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: 1
|
|
namespace: ignored
|
|
access_check:
|
|
none: true
|
|
simple:
|
|
privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_EMPTY_ACCESS_CHECK,
|
|
)
|
|
|
|
# duplicate access_check - none and complex
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: 1
|
|
namespace: ignored
|
|
access_check:
|
|
none: true
|
|
complex:
|
|
- privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
- privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
- check: is_authenticated
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_EMPTY_ACCESS_CHECK,
|
|
)
|
|
|
|
# duplicate access_check - simple and complex
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: 1
|
|
namespace: ignored
|
|
access_check:
|
|
simple:
|
|
privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
complex:
|
|
- privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
- privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
- check: is_authenticated
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_EMPTY_ACCESS_CHECK,
|
|
)
|
|
|
|
# duplicate access_check - none, simple and complex
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
foo:
|
|
description: foo
|
|
command_name: foo
|
|
api_version: 1
|
|
namespace: ignored
|
|
access_check:
|
|
none: true
|
|
simple:
|
|
privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
complex:
|
|
- privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
- privilege:
|
|
resource_pattern: foo
|
|
action_type: foo
|
|
- check: is_authenticated
|
|
fields:
|
|
foo: bar
|
|
reply_type: foo_reply_struct
|
|
"""),
|
|
idl.errors.ERROR_ID_EMPTY_ACCESS_CHECK,
|
|
)
|
|
|
|
# pylint: disable=invalid-name
|
|
def test_struct_unsafe_dangerous_disable_extra_field_duplicate_checks_negative(self):
|
|
# Test commands and unsafe_dangerous_disable_extra_field_duplicate_checks are disallowed
|
|
self.assert_parse_fail(
|
|
textwrap.dedent("""
|
|
commands:
|
|
dangerc:
|
|
description: foo
|
|
namespace: ignored
|
|
command_name: dangerc
|
|
api_version: ""
|
|
strict: false
|
|
unsafe_dangerous_disable_extra_field_duplicate_checks: true
|
|
fields:
|
|
foo: string
|
|
"""),
|
|
idl.errors.ERROR_ID_UNKNOWN_NODE,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|