Skip to content

Commit 2f9497e

Browse files
authored
Merge pull request #55 from boukeversteegh/pr/xfail-tests
Add intentionally failing test-cases for unimplemented bug-fixes
2 parents 0fe557b + 33964b8 commit 2f9497e

31 files changed

+352
-51
lines changed

betterproto/tests/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,18 @@ The following tests are automatically executed for all cases:
7373
- `betterproto/tests/output_reference` — *reference implementation classes*
7474
- `pipenv run test`
7575

76+
## Intentionally Failing tests
77+
78+
The standard test suite includes tests that fail by intention. These tests document known bugs and missing features that are intended to be corrented in the future.
79+
80+
When running `pytest`, they show up as `x` or `X` in the test results.
81+
82+
```
83+
betterproto/tests/test_inputs.py ..x...x..x...x.X........xx........x.....x.......x.xx....x...................... [ 84%]
84+
```
85+
86+
- `.` — PASSED
87+
- `x` — XFAIL: expected failure
88+
- `X` — XPASS: expected failure, but still passed
89+
90+
Test cases marked for expected failure are declared in [inputs/xfail.py](inputs.xfail.py)

betterproto/tests/generate.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#!/usr/bin/env python
2+
import glob
23
import os
4+
import shutil
35
import sys
46
from typing import Set
57

@@ -17,33 +19,48 @@
1719
os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "python"
1820

1921

22+
def clear_directory(path: str):
23+
for file_or_directory in glob.glob(os.path.join(path, "*")):
24+
if os.path.isdir(file_or_directory):
25+
shutil.rmtree(file_or_directory)
26+
else:
27+
os.remove(file_or_directory)
28+
29+
2030
def generate(whitelist: Set[str]):
2131
path_whitelist = {os.path.realpath(e) for e in whitelist if os.path.exists(e)}
2232
name_whitelist = {e for e in whitelist if not os.path.exists(e)}
2333

2434
test_case_names = set(get_directories(inputs_path))
2535

2636
for test_case_name in sorted(test_case_names):
27-
test_case_path = os.path.realpath(os.path.join(inputs_path, test_case_name))
37+
test_case_input_path = os.path.realpath(
38+
os.path.join(inputs_path, test_case_name)
39+
)
2840

2941
if (
3042
whitelist
31-
and test_case_path not in path_whitelist
43+
and test_case_input_path not in path_whitelist
3244
and test_case_name not in name_whitelist
3345
):
3446
continue
3547

36-
case_output_dir_reference = os.path.join(output_path_reference, test_case_name)
37-
case_output_dir_betterproto = os.path.join(
48+
test_case_output_path_reference = os.path.join(
49+
output_path_reference, test_case_name
50+
)
51+
test_case_output_path_betterproto = os.path.join(
3852
output_path_betterproto, test_case_name
3953
)
4054

4155
print(f"Generating output for {test_case_name}")
42-
os.makedirs(case_output_dir_reference, exist_ok=True)
43-
os.makedirs(case_output_dir_betterproto, exist_ok=True)
56+
os.makedirs(test_case_output_path_reference, exist_ok=True)
57+
os.makedirs(test_case_output_path_betterproto, exist_ok=True)
58+
59+
clear_directory(test_case_output_path_reference)
60+
clear_directory(test_case_output_path_betterproto)
4461

45-
protoc_reference(test_case_path, case_output_dir_reference)
46-
protoc_plugin(test_case_path, case_output_dir_betterproto)
62+
protoc_reference(test_case_input_path, test_case_output_path_reference)
63+
protoc_plugin(test_case_input_path, test_case_output_path_betterproto)
4764

4865

4966
HELP = "\n".join(

betterproto/tests/inputs/googletypes_response/test_googletypes_response.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,14 @@ async def test_channel_receives_wrapped_type(
4343
async def test_service_unwraps_response(
4444
service_method: Callable[[TestStub], Any], wrapper_class: Callable, value
4545
):
46+
"""
47+
grpclib does not unwrap wrapper values returned by services
48+
"""
4649
wrapped_value = wrapper_class()
4750
wrapped_value.value = value
4851
service = TestStub(MockChannel(responses=[wrapped_value]))
4952

5053
response_value = await service_method(service)
5154

52-
assert type(response_value) == value
55+
assert response_value == value
5356
assert type(response_value) == type(value)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
syntax = "proto3";
2+
3+
package package.childpackage;
4+
5+
message ChildMessage {
6+
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
syntax = "proto3";
2+
3+
import "package_message.proto";
4+
5+
// Tests generated imports when a message in a package refers to a message in a nested child package.
6+
7+
message Test {
8+
package.PackageMessage message = 1;
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
syntax = "proto3";
2+
3+
import "child.proto";
4+
5+
package package;
6+
7+
message PackageMessage {
8+
package.childpackage.ChildMessage c = 1;
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
syntax = "proto3";
2+
3+
package childpackage;
4+
5+
message Message {
6+
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
syntax = "proto3";
2+
3+
import "child.proto";
4+
5+
// Tests generated imports when a message in root refers to a message in a child package.
6+
7+
message Test {
8+
childpackage.Message child = 1;
9+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
syntax = "proto3";
2+
3+
import "root.proto";
4+
import "other.proto";
5+
6+
// This test-case verifies that future implementations will support circular dependencies in the generated python files.
7+
//
8+
// This becomes important when generating 1 python file/module per package, rather than 1 file per proto file.
9+
//
10+
// Scenario:
11+
//
12+
// The proto messages depend on each other in a non-circular way:
13+
//
14+
// Test -------> RootPackageMessage <--------------.
15+
// `------------------------------------> OtherPackageMessage
16+
//
17+
// Test and RootPackageMessage are in different files, but belong to the same package (root):
18+
//
19+
// (Test -------> RootPackageMessage) <------------.
20+
// `------------------------------------> OtherPackageMessage
21+
//
22+
// After grouping the packages into single files or modules, a circular dependency is created:
23+
//
24+
// (root: Test & RootPackageMessage) <-------> (other: OtherPackageMessage)
25+
message Test {
26+
RootPackageMessage message = 1;
27+
other.OtherPackageMessage other =2;
28+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
syntax = "proto3";
2+
3+
import "root.proto";
4+
package other;
5+
6+
message OtherPackageMessage {
7+
RootPackageMessage rootPackageMessage = 1;
8+
}

0 commit comments

Comments
 (0)