Merge pull request #69 from boukeversteegh/pr/bugreports

Bugreports
This commit is contained in:
Bouke Versteegh 2020-05-28 09:07:11 +02:00 committed by GitHub
commit 5c4969ff1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 298 additions and 46 deletions

View File

@ -87,4 +87,4 @@ betterproto/tests/test_inputs.py ..x...x..x...x.X........xx........x.....x......
- `x` — XFAIL: expected failure
- `X` — XPASS: expected failure, but still passed
Test cases marked for expected failure are declared in [inputs/xfail.py](inputs.xfail.py)
Test cases marked for expected failure are declared in [inputs/config.py](inputs/config.py)

View File

@ -2,6 +2,7 @@
import glob
import os
import shutil
import subprocess
import sys
from typing import Set
@ -33,6 +34,8 @@ def generate(whitelist: Set[str]):
test_case_names = set(get_directories(inputs_path))
failed_test_cases = []
for test_case_name in sorted(test_case_names):
test_case_input_path = os.path.realpath(
os.path.join(inputs_path, test_case_name)
@ -45,6 +48,24 @@ def generate(whitelist: Set[str]):
):
continue
print(f"Generating output for {test_case_name}")
try:
generate_test_case_output(test_case_name, test_case_input_path)
except subprocess.CalledProcessError as e:
failed_test_cases.append(test_case_name)
if failed_test_cases:
sys.stderr.write("\nFailed to generate the following test cases:\n")
for failed_test_case in failed_test_cases:
sys.stderr.write(f"- {failed_test_case}\n")
def generate_test_case_output(test_case_name, test_case_input_path=None):
if not test_case_input_path:
test_case_input_path = os.path.realpath(
os.path.join(inputs_path, test_case_name)
)
test_case_output_path_reference = os.path.join(
output_path_reference, test_case_name
)
@ -52,7 +73,6 @@ def generate(whitelist: Set[str]):
output_path_betterproto, test_case_name
)
print(f"Generating output for {test_case_name}")
os.makedirs(test_case_output_path_reference, exist_ok=True)
os.makedirs(test_case_output_path_betterproto, exist_ok=True)

View File

@ -0,0 +1,5 @@
{
"UPPERCASE": 10,
"UPPERCASE_V2": 10,
"UPPER_CAMEL_CASE": 10
}

View File

@ -0,0 +1,7 @@
syntax = "proto3";
message Test {
int32 UPPERCASE = 1;
int32 UPPERCASE_V2 = 2;
int32 UPPER_CAMEL_CASE = 3;
}

View File

@ -0,0 +1,16 @@
from betterproto.tests.output_betterproto.casing_message_field_uppercase.casing_message_field_uppercase import (
Test,
)
def test_message_casing():
message = Test()
assert hasattr(
message, "uppercase"
), "UPPERCASE attribute is converted to 'uppercase' in python"
assert hasattr(
message, "uppercase_v2"
), "UPPERCASE_V2 attribute is converted to 'uppercase_v2' in python"
assert hasattr(
message, "upper_camel_case"
), "UPPER_CAMEL_CASE attribute is converted to upper_camel_case in python"

View File

@ -0,0 +1,23 @@
# Test cases that are expected to fail, e.g. unimplemented features or bug-fixes.
# Remove from list when fixed.
tests = {
"import_root_sibling", # 61
"import_child_package_from_package", # 58
"import_root_package_from_child", # 60
"import_parent_package_from_child", # 59
"import_circular_dependency", # failing because of other bugs now
"import_packages_same_name", # 25
"oneof_enum", # 63
"googletypes_service_returns_empty", # 9
"casing_message_field_uppercase", # 11
"namespace_keywords", # 70
"namespace_builtin_types" # 53
}
services = {
"googletypes_response",
"googletypes_response_embedded",
"service",
"import_service_input_message",
"googletypes_service_returns_empty",
}

View File

@ -0,0 +1,11 @@
syntax = "proto3";
import "google/protobuf/empty.proto";
service Test {
rpc Send (RequestMessage) returns (google.protobuf.Empty) {
}
}
message RequestMessage {
}

View File

@ -0,0 +1,11 @@
syntax = "proto3";
import "users_v1.proto";
import "posts_v1.proto";
// Tests generated message can correctly reference two packages with the same leaf-name
message Test {
users.v1.User user = 1;
posts.v1.Post post = 2;
}

View File

@ -0,0 +1,7 @@
syntax = "proto3";
package posts.v1;
message Post {
}

View File

@ -0,0 +1,7 @@
syntax = "proto3";
package users.v1;
message User {
}

View File

@ -0,0 +1,15 @@
syntax = "proto3";
import "request_message.proto";
// Tests generated service correctly imports the RequestMessage
service Test {
rpc DoThing (RequestMessage) returns (RequestResponse);
}
message RequestResponse {
int32 value = 1;
}

View File

@ -0,0 +1,5 @@
syntax = "proto3";
message RequestMessage {
int32 argument = 1;
}

View File

@ -0,0 +1,16 @@
import pytest
from betterproto.tests.mocks import MockChannel
from betterproto.tests.output_betterproto.import_service_input_message.import_service_input_message import (
RequestResponse,
TestStub,
)
@pytest.mark.xfail(reason="#68 Request Input Messages are not imported for service")
@pytest.mark.asyncio
async def test_service_correctly_imports_reference_message():
mock_response = RequestResponse(value=10)
service = TestStub(MockChannel([mock_response]))
response = await service.do_thing()
assert mock_response == response

View File

@ -1,5 +0,0 @@
{
"for": 1,
"with": 2,
"as": 3
}

View File

@ -1,11 +0,0 @@
syntax = "proto3";
message Test {
int32 for = 1;
int32 with = 2;
int32 as = 3;
}
service TestService {
rpc GetTest(Test) returns (Test) {}
}

View File

@ -0,0 +1,16 @@
{
"int": "value-for-int",
"float": "value-for-float",
"complex": "value-for-complex",
"list": "value-for-list",
"tuple": "value-for-tuple",
"range": "value-for-range",
"str": "value-for-str",
"bytearray": "value-for-bytearray",
"bytes": "value-for-bytes",
"memoryview": "value-for-memoryview",
"set": "value-for-set",
"frozenset": "value-for-frozenset",
"map": "value-for-map",
"bool": "value-for-bool"
}

View File

@ -0,0 +1,38 @@
syntax = "proto3";
// Tests that messages may contain fields with names that are python types
message Test {
// https://docs.python.org/2/library/stdtypes.html#numeric-types-int-float-long-complex
string int = 1;
string float = 2;
string complex = 3;
// https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range
string list = 4;
string tuple = 5;
string range = 6;
// https://docs.python.org/3/library/stdtypes.html#str
string str = 7;
// https://docs.python.org/3/library/stdtypes.html#bytearray-objects
string bytearray = 8;
// https://docs.python.org/3/library/stdtypes.html#bytes-and-bytearray-operations
string bytes = 9;
// https://docs.python.org/3/library/stdtypes.html#memory-views
string memoryview = 10;
// https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset
string set = 11;
string frozenset = 12;
// https://docs.python.org/3/library/stdtypes.html#dict
string map = 13;
string dict = 14;
// https://docs.python.org/3/library/stdtypes.html#boolean-values
string bool = 15;
}

View File

@ -0,0 +1,37 @@
{
"False": 1,
"None": 2,
"True": 3,
"and": 4,
"as": 5,
"assert": 6,
"async": 7,
"await": 8,
"break": 9,
"class": 10,
"continue": 11,
"def": 12,
"del": 13,
"elif": 14,
"else": 15,
"except": 16,
"finally": 17,
"for": 18,
"from": 19,
"global": 20,
"if": 21,
"import": 22,
"in": 23,
"is": 24,
"lambda": 25,
"nonlocal": 26,
"not": 27,
"or": 28,
"pass": 29,
"raise": 30,
"return": 31,
"try": 32,
"while": 33,
"with": 34,
"yield": 35
}

View File

@ -0,0 +1,44 @@
syntax = "proto3";
// Tests that messages may contain fields that are Python keywords
//
// Generated with Python 3.7.6
// print('\n'.join(f'string {k} = {i+1};' for i,k in enumerate(keyword.kwlist)))
message Test {
string False = 1;
string None = 2;
string True = 3;
string and = 4;
string as = 5;
string assert = 6;
string async = 7;
string await = 8;
string break = 9;
string class = 10;
string continue = 11;
string def = 12;
string del = 13;
string elif = 14;
string else = 15;
string except = 16;
string finally = 17;
string for = 18;
string from = 19;
string global = 20;
string if = 21;
string import = 22;
string in = 23;
string is = 24;
string lambda = 25;
string nonlocal = 26;
string not = 27;
string or = 28;
string pass = 29;
string raise = 30;
string return = 31;
string try = 32;
string while = 33;
string with = 34;
string yield = 35;
}

View File

@ -1,10 +0,0 @@
# Test cases that are expected to fail, e.g. unimplemented features or bug-fixes.
# Remove from list when fixed.
tests = {
"import_root_sibling",
"import_child_package_from_package",
"import_root_package_from_child",
"import_parent_package_from_child",
"import_circular_dependency",
"oneof_enum",
}

View File

@ -8,7 +8,7 @@ from typing import Set
import pytest
import betterproto
from betterproto.tests.inputs import xfail
from betterproto.tests.inputs import config as test_input_config
from betterproto.tests.mocks import MockChannel
from betterproto.tests.util import get_directories, get_test_case_json_data, inputs_path
@ -45,9 +45,8 @@ class TestCases:
test_cases = TestCases(
path=inputs_path,
# test cases for services
services={"googletypes_response", "googletypes_response_embedded", "service"},
xfail=xfail.tests,
services=test_input_config.services,
xfail=test_input_config.tests,
)
plugin_output_package = "betterproto.tests.output_betterproto"

View File

@ -36,10 +36,11 @@ def read_relative(file: str, path: str):
return fh.read()
def protoc_plugin(path: str, output_dir: str):
subprocess.run(
def protoc_plugin(path: str, output_dir: str) -> subprocess.CompletedProcess:
return subprocess.run(
f"protoc --plugin=protoc-gen-custom={plugin_path} --custom_out={output_dir} --proto_path={path} {path}/*.proto",
shell=True,
check=True,
)