xcore-protocol 0.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tests/test_canonical_protocol_fixtures.py +171 -0
- tests/test_chat_fixtures.py +145 -0
- tests/test_discord_fixtures.py +87 -0
- tests/test_envelope_schemas.py +396 -0
- tests/test_generated_chat_models.py +251 -0
- tests/test_generated_discord_models.py +123 -0
- tests/test_generated_maps_models.py +120 -0
- tests/test_generated_moderation_models.py +223 -0
- tests/test_generated_telemetry_models.py +32 -0
- tests/test_generator_bootstrap.py +121 -0
- tests/test_java_python_route_compatibility.py +125 -0
- tests/test_java_python_serialized_compatibility.py +68 -0
- tests/test_maps_fixtures.py +81 -0
- tests/test_moderation_fixtures.py +113 -0
- tests/test_normalized_route_model.py +264 -0
- tests/test_telemetry_fixtures.py +49 -0
- xcore_protocol/__init__.py +1 -0
- xcore_protocol/generated/__init__.py +195 -0
- xcore_protocol/generated/chat.py +747 -0
- xcore_protocol/generated/discord.py +389 -0
- xcore_protocol/generated/envelopes.py +695 -0
- xcore_protocol/generated/maps.py +312 -0
- xcore_protocol/generated/moderation.py +478 -0
- xcore_protocol/generated/routes.py +634 -0
- xcore_protocol/generated/shared.py +605 -0
- xcore_protocol/generated/telemetry.py +177 -0
- xcore_protocol/models/__init__.py +1 -0
- xcore_protocol/paths.py +15 -0
- xcore_protocol/schema_validation.py +66 -0
- xcore_protocol-0.5.1.dist-info/METADATA +92 -0
- xcore_protocol-0.5.1.dist-info/RECORD +33 -0
- xcore_protocol-0.5.1.dist-info/WHEEL +5 -0
- xcore_protocol-0.5.1.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from collections.abc import Callable, Mapping
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from xcore_protocol.generated import (
|
|
11
|
+
ActorRefV1ActorType,
|
|
12
|
+
DiscordAdminAccessChangedCommandV1,
|
|
13
|
+
DiscordUnlinkCommandV1,
|
|
14
|
+
MetricsSnapshotV1,
|
|
15
|
+
ServerHeartbeatV1,
|
|
16
|
+
)
|
|
17
|
+
from xcore_protocol.paths import fixtures_root, spec_root
|
|
18
|
+
from xcore_protocol.schema_validation import assert_valid
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
REPO_ROOT = fixtures_root().parent
|
|
22
|
+
CANONICAL_FIXTURES_ROOT = REPO_ROOT / "spec" / "fixtures" / "valid"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _load_fixture(path: Path) -> dict[str, Any]:
|
|
26
|
+
return json.loads(path.read_text(encoding="utf-8"))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _model_dump_json(model: Any) -> dict[str, Any]:
|
|
30
|
+
model_dump = getattr(model, "model_dump", None)
|
|
31
|
+
if callable(model_dump):
|
|
32
|
+
payload = model_dump(mode="json")
|
|
33
|
+
if not isinstance(payload, dict):
|
|
34
|
+
raise TypeError("model_dump(mode='json') must return a dict payload")
|
|
35
|
+
return payload
|
|
36
|
+
|
|
37
|
+
to_payload = getattr(model, "to_payload", None)
|
|
38
|
+
if callable(to_payload):
|
|
39
|
+
payload = to_payload()
|
|
40
|
+
if not isinstance(payload, dict):
|
|
41
|
+
raise TypeError("to_payload() must return a dict payload")
|
|
42
|
+
return payload
|
|
43
|
+
|
|
44
|
+
raise TypeError("Generated model must provide model_dump(mode='json') or to_payload()")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _assert_no_snake_case_keys(value: Any) -> None:
|
|
48
|
+
if isinstance(value, Mapping):
|
|
49
|
+
for key, nested_value in value.items():
|
|
50
|
+
assert "_" not in key, f"Found legacy snake_case key: {key}"
|
|
51
|
+
_assert_no_snake_case_keys(nested_value)
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
if isinstance(value, list):
|
|
55
|
+
for item in value:
|
|
56
|
+
_assert_no_snake_case_keys(item)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
CanonicalAssertion = Callable[[Any, dict[str, Any]], None]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _assert_admin_access_semantics(model: DiscordAdminAccessChangedCommandV1, payload: dict[str, Any]) -> None:
|
|
63
|
+
assert model.source.actorType is ActorRefV1ActorType.SYSTEM
|
|
64
|
+
assert payload["source"]["actorType"] == "system"
|
|
65
|
+
assert model.actor.actorType is ActorRefV1ActorType.DISCORD
|
|
66
|
+
assert model.actor.actorName == payload["actor"]["actorName"]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _assert_unlink_semantics(model: DiscordUnlinkCommandV1, payload: dict[str, Any]) -> None:
|
|
70
|
+
assert model.actor.actorType is ActorRefV1ActorType.DISCORD
|
|
71
|
+
assert model.actor.actorName == payload["actor"]["actorName"]
|
|
72
|
+
assert payload["actor"]["actorName"] == "Beta Display"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _assert_heartbeat_semantics(model: ServerHeartbeatV1, payload: dict[str, Any]) -> None:
|
|
76
|
+
assert model.serverName == payload["serverName"]
|
|
77
|
+
assert model.discordChannelId == payload["discordChannelId"]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _assert_telemetry_semantics(model: MetricsSnapshotV1, payload: dict[str, Any]) -> None:
|
|
81
|
+
assert model.server == payload["server"]
|
|
82
|
+
assert model.SCHEMA_VERSION == payload["schemaVersion"]
|
|
83
|
+
assert model.samples[2].count == payload["samples"][2]["count"]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
CANONICAL_CASES: list[tuple[str, Path, Path, type[Any], CanonicalAssertion]] = [
|
|
87
|
+
(
|
|
88
|
+
"discord_admin_access_grant",
|
|
89
|
+
spec_root() / "messages" / "discord" / "discord.admin-access.changed.command.v1.json",
|
|
90
|
+
CANONICAL_FIXTURES_ROOT / "discord" / "discord.admin-access.changed.command.v1.grant.json",
|
|
91
|
+
DiscordAdminAccessChangedCommandV1,
|
|
92
|
+
_assert_admin_access_semantics,
|
|
93
|
+
),
|
|
94
|
+
(
|
|
95
|
+
"discord_admin_access_revoke",
|
|
96
|
+
spec_root() / "messages" / "discord" / "discord.admin-access.changed.command.v1.json",
|
|
97
|
+
CANONICAL_FIXTURES_ROOT / "discord" / "discord.admin-access.changed.command.v1.revoke.json",
|
|
98
|
+
DiscordAdminAccessChangedCommandV1,
|
|
99
|
+
_assert_admin_access_semantics,
|
|
100
|
+
),
|
|
101
|
+
(
|
|
102
|
+
"discord_unlink",
|
|
103
|
+
spec_root() / "messages" / "discord" / "discord.unlink.command.v1.json",
|
|
104
|
+
CANONICAL_FIXTURES_ROOT / "discord" / "discord.unlink.command.v1.json",
|
|
105
|
+
DiscordUnlinkCommandV1,
|
|
106
|
+
_assert_unlink_semantics,
|
|
107
|
+
),
|
|
108
|
+
(
|
|
109
|
+
"server_heartbeat",
|
|
110
|
+
spec_root() / "messages" / "chat" / "server.heartbeat.v1.json",
|
|
111
|
+
CANONICAL_FIXTURES_ROOT / "chat" / "server.heartbeat.v1.json",
|
|
112
|
+
ServerHeartbeatV1,
|
|
113
|
+
_assert_heartbeat_semantics,
|
|
114
|
+
),
|
|
115
|
+
(
|
|
116
|
+
"metrics_snapshot",
|
|
117
|
+
spec_root() / "messages" / "telemetry" / "metrics.snapshot.v1.json",
|
|
118
|
+
CANONICAL_FIXTURES_ROOT / "telemetry" / "metrics.snapshot.v1.json",
|
|
119
|
+
MetricsSnapshotV1,
|
|
120
|
+
_assert_telemetry_semantics,
|
|
121
|
+
),
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_canonical_fixture_inventory_exists() -> None:
|
|
126
|
+
assert fixtures_root().exists()
|
|
127
|
+
|
|
128
|
+
for _, schema_path, fixture_path, _, _ in CANONICAL_CASES:
|
|
129
|
+
assert schema_path.exists()
|
|
130
|
+
assert fixture_path.exists()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@pytest.mark.parametrize(
|
|
134
|
+
("_case_name", "schema_path", "fixture_path", "model_type", "assert_semantics"),
|
|
135
|
+
CANONICAL_CASES,
|
|
136
|
+
)
|
|
137
|
+
def test_canonical_fixtures_remain_schema_valid(
|
|
138
|
+
_case_name: str,
|
|
139
|
+
schema_path: Path,
|
|
140
|
+
fixture_path: Path,
|
|
141
|
+
model_type: type[Any],
|
|
142
|
+
assert_semantics: CanonicalAssertion,
|
|
143
|
+
) -> None:
|
|
144
|
+
del model_type, assert_semantics
|
|
145
|
+
assert_valid(schema_path, fixture_path)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@pytest.mark.parametrize(
|
|
149
|
+
("_case_name", "schema_path", "fixture_path", "model_type", "assert_semantics"),
|
|
150
|
+
CANONICAL_CASES,
|
|
151
|
+
)
|
|
152
|
+
def test_canonical_generated_models_roundtrip(
|
|
153
|
+
_case_name: str,
|
|
154
|
+
schema_path: Path,
|
|
155
|
+
fixture_path: Path,
|
|
156
|
+
model_type: type[Any],
|
|
157
|
+
assert_semantics: CanonicalAssertion,
|
|
158
|
+
) -> None:
|
|
159
|
+
del schema_path
|
|
160
|
+
payload = _load_fixture(fixture_path)
|
|
161
|
+
|
|
162
|
+
model = model_type.from_payload(payload)
|
|
163
|
+
roundtrip_payload = _model_dump_json(model)
|
|
164
|
+
|
|
165
|
+
assert roundtrip_payload == payload
|
|
166
|
+
assert_semantics(model, payload)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_canonical_fixtures_do_not_use_legacy_snake_case_keys() -> None:
|
|
170
|
+
for _, _, fixture_path, _, _ in CANONICAL_CASES:
|
|
171
|
+
_assert_no_snake_case_keys(_load_fixture(fixture_path))
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from xcore_protocol.paths import fixtures_root, spec_root
|
|
4
|
+
from xcore_protocol.schema_validation import assert_invalid, assert_valid
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
VALID_CASES = [
|
|
8
|
+
(
|
|
9
|
+
spec_root() / "messages" / "chat" / "chat.message.v1.json",
|
|
10
|
+
fixtures_root() / "valid" / "chat" / "chat.message.v1.json",
|
|
11
|
+
),
|
|
12
|
+
(
|
|
13
|
+
spec_root() / "messages" / "chat" / "chat.global.v1.json",
|
|
14
|
+
fixtures_root() / "valid" / "chat" / "chat.global.v1.json",
|
|
15
|
+
),
|
|
16
|
+
(
|
|
17
|
+
spec_root() / "messages" / "chat" / "chat.discord-ingress.command.v1.json",
|
|
18
|
+
fixtures_root() / "valid" / "chat" / "chat.discord-ingress.command.v1.json",
|
|
19
|
+
),
|
|
20
|
+
(
|
|
21
|
+
spec_root() / "messages" / "chat" / "chat.private.v1.json",
|
|
22
|
+
fixtures_root() / "valid" / "chat" / "chat.private.v1.json",
|
|
23
|
+
),
|
|
24
|
+
(
|
|
25
|
+
spec_root() / "messages" / "chat" / "server.action.v1.json",
|
|
26
|
+
fixtures_root() / "valid" / "chat" / "server.action.v1.json",
|
|
27
|
+
),
|
|
28
|
+
(
|
|
29
|
+
spec_root() / "messages" / "chat" / "player.join-leave.v1.json",
|
|
30
|
+
fixtures_root() / "valid" / "chat" / "player.join-leave.v1.json",
|
|
31
|
+
),
|
|
32
|
+
(
|
|
33
|
+
spec_root() / "messages" / "chat" / "player.custom-nickname.changed.command.v1.json",
|
|
34
|
+
fixtures_root() / "valid" / "chat" / "player.custom-nickname.changed.command.v1.json",
|
|
35
|
+
),
|
|
36
|
+
(
|
|
37
|
+
spec_root() / "messages" / "chat" / "player.active-badge.changed.command.v1.json",
|
|
38
|
+
fixtures_root() / "valid" / "chat" / "player.active-badge.changed.command.v1.json",
|
|
39
|
+
),
|
|
40
|
+
(
|
|
41
|
+
spec_root() / "messages" / "chat" / "player.badge-inventory.changed.command.v1.json",
|
|
42
|
+
fixtures_root() / "valid" / "chat" / "player.badge-inventory.changed.command.v1.json",
|
|
43
|
+
),
|
|
44
|
+
(
|
|
45
|
+
spec_root() / "messages" / "chat" / "player.badge-symbol-color-mode.changed.command.v1.json",
|
|
46
|
+
fixtures_root() / "valid" / "chat" / "player.badge-symbol-color-mode.changed.command.v1.json",
|
|
47
|
+
),
|
|
48
|
+
(
|
|
49
|
+
spec_root() / "messages" / "chat" / "player.password-reset.command.v1.json",
|
|
50
|
+
fixtures_root() / "valid" / "chat" / "player.password-reset.command.v1.json",
|
|
51
|
+
),
|
|
52
|
+
(
|
|
53
|
+
spec_root() / "messages" / "chat" / "server.heartbeat.v1.json",
|
|
54
|
+
fixtures_root() / "valid" / "chat" / "server.heartbeat.v1.json",
|
|
55
|
+
),
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
INVALID_CASES = [
|
|
60
|
+
(
|
|
61
|
+
spec_root() / "messages" / "chat" / "chat.message.v1.json",
|
|
62
|
+
fixtures_root() / "invalid" / "chat" / "chat.message.v1.snake-author.json",
|
|
63
|
+
),
|
|
64
|
+
(
|
|
65
|
+
spec_root() / "messages" / "chat" / "chat.private.v1.json",
|
|
66
|
+
fixtures_root() / "invalid" / "chat" / "chat.private.v1.snake-from.json",
|
|
67
|
+
),
|
|
68
|
+
(
|
|
69
|
+
spec_root() / "messages" / "chat" / "player.join-leave.v1.json",
|
|
70
|
+
fixtures_root()
|
|
71
|
+
/ "invalid"
|
|
72
|
+
/ "chat"
|
|
73
|
+
/ "player.join-leave.v1.legacy-join.json",
|
|
74
|
+
),
|
|
75
|
+
(
|
|
76
|
+
spec_root() / "messages" / "chat" / "player.custom-nickname.changed.command.v1.json",
|
|
77
|
+
fixtures_root()
|
|
78
|
+
/ "invalid"
|
|
79
|
+
/ "chat"
|
|
80
|
+
/ "player.custom-nickname.changed.command.v1.legacy-uuid.json",
|
|
81
|
+
),
|
|
82
|
+
(
|
|
83
|
+
spec_root() / "messages" / "chat" / "player.active-badge.changed.command.v1.json",
|
|
84
|
+
fixtures_root()
|
|
85
|
+
/ "invalid"
|
|
86
|
+
/ "chat"
|
|
87
|
+
/ "player.active-badge.changed.command.v1.legacy-uuid.json",
|
|
88
|
+
),
|
|
89
|
+
(
|
|
90
|
+
spec_root() / "messages" / "chat" / "player.badge-inventory.changed.command.v1.json",
|
|
91
|
+
fixtures_root()
|
|
92
|
+
/ "invalid"
|
|
93
|
+
/ "chat"
|
|
94
|
+
/ "player.badge-inventory.changed.command.v1.legacy-uuid.json",
|
|
95
|
+
),
|
|
96
|
+
(
|
|
97
|
+
spec_root() / "messages" / "chat" / "player.badge-symbol-color-mode.changed.command.v1.json",
|
|
98
|
+
fixtures_root()
|
|
99
|
+
/ "invalid"
|
|
100
|
+
/ "chat"
|
|
101
|
+
/ "player.badge-symbol-color-mode.changed.command.v1.legacy-uuid.json",
|
|
102
|
+
),
|
|
103
|
+
(
|
|
104
|
+
spec_root() / "messages" / "chat" / "player.password-reset.command.v1.json",
|
|
105
|
+
fixtures_root()
|
|
106
|
+
/ "invalid"
|
|
107
|
+
/ "chat"
|
|
108
|
+
/ "player.password-reset.command.v1.legacy-uuid.json",
|
|
109
|
+
),
|
|
110
|
+
(
|
|
111
|
+
spec_root() / "messages" / "chat" / "server.heartbeat.v1.json",
|
|
112
|
+
fixtures_root()
|
|
113
|
+
/ "invalid"
|
|
114
|
+
/ "chat"
|
|
115
|
+
/ "server.heartbeat.v1.server-host-alias.json",
|
|
116
|
+
),
|
|
117
|
+
(
|
|
118
|
+
spec_root() / "messages" / "chat" / "server.heartbeat.v1.json",
|
|
119
|
+
fixtures_root()
|
|
120
|
+
/ "invalid"
|
|
121
|
+
/ "chat"
|
|
122
|
+
/ "server.heartbeat.v1.missing-channel.json",
|
|
123
|
+
),
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_valid_chat_fixtures_pass() -> None:
|
|
128
|
+
for schema_path, fixture_path in VALID_CASES:
|
|
129
|
+
assert_valid(schema_path, fixture_path)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_invalid_chat_fixtures_fail() -> None:
|
|
133
|
+
for schema_path, fixture_path in INVALID_CASES:
|
|
134
|
+
error = assert_invalid(schema_path, fixture_path)
|
|
135
|
+
assert error is not None
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_chat_fixture_inventory_exists() -> None:
|
|
139
|
+
chat_valid_dir = fixtures_root() / "valid" / "chat"
|
|
140
|
+
chat_invalid_dir = fixtures_root() / "invalid" / "chat"
|
|
141
|
+
|
|
142
|
+
assert chat_valid_dir.exists()
|
|
143
|
+
assert chat_invalid_dir.exists()
|
|
144
|
+
assert any(chat_valid_dir.iterdir())
|
|
145
|
+
assert any(chat_invalid_dir.iterdir())
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from xcore_protocol.paths import fixtures_root, spec_root
|
|
4
|
+
from xcore_protocol.schema_validation import assert_invalid, assert_valid
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
VALID_CASES = [
|
|
8
|
+
(
|
|
9
|
+
spec_root() / "messages" / "discord" / "discord.link-code-created.v1.json",
|
|
10
|
+
fixtures_root() / "valid" / "discord" / "discord.link-code-created.v1.json",
|
|
11
|
+
),
|
|
12
|
+
(
|
|
13
|
+
spec_root() / "messages" / "discord" / "discord.link.confirm.command.v1.json",
|
|
14
|
+
fixtures_root() / "valid" / "discord" / "discord.link.confirm.command.v1.json",
|
|
15
|
+
),
|
|
16
|
+
(
|
|
17
|
+
spec_root() / "messages" / "discord" / "discord.unlink.command.v1.json",
|
|
18
|
+
fixtures_root() / "valid" / "discord" / "discord.unlink.command.v1.json",
|
|
19
|
+
),
|
|
20
|
+
(
|
|
21
|
+
spec_root() / "messages" / "discord" / "discord.link.status-changed.v1.json",
|
|
22
|
+
fixtures_root() / "valid" / "discord" / "discord.link.status-changed.v1.json",
|
|
23
|
+
),
|
|
24
|
+
(
|
|
25
|
+
spec_root()
|
|
26
|
+
/ "messages"
|
|
27
|
+
/ "discord"
|
|
28
|
+
/ "discord.admin-access.changed.command.v1.json",
|
|
29
|
+
fixtures_root()
|
|
30
|
+
/ "valid"
|
|
31
|
+
/ "discord"
|
|
32
|
+
/ "discord.admin-access.changed.command.v1.json",
|
|
33
|
+
),
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
INVALID_CASES = [
|
|
38
|
+
(
|
|
39
|
+
spec_root() / "messages" / "discord" / "discord.link-code-created.v1.json",
|
|
40
|
+
fixtures_root() / "invalid" / "discord" / "discord.link-code-created.v1.bad-time.json",
|
|
41
|
+
),
|
|
42
|
+
(
|
|
43
|
+
spec_root() / "messages" / "discord" / "discord.link.confirm.command.v1.json",
|
|
44
|
+
fixtures_root()
|
|
45
|
+
/ "invalid"
|
|
46
|
+
/ "discord"
|
|
47
|
+
/ "discord.link.confirm.command.v1.bad-time.json",
|
|
48
|
+
),
|
|
49
|
+
(
|
|
50
|
+
spec_root() / "messages" / "discord" / "discord.unlink.command.v1.json",
|
|
51
|
+
fixtures_root()
|
|
52
|
+
/ "invalid"
|
|
53
|
+
/ "discord"
|
|
54
|
+
/ "discord.unlink.command.v1.missing-discord.json",
|
|
55
|
+
),
|
|
56
|
+
(
|
|
57
|
+
spec_root()
|
|
58
|
+
/ "messages"
|
|
59
|
+
/ "discord"
|
|
60
|
+
/ "discord.admin-access.changed.command.v1.json",
|
|
61
|
+
fixtures_root()
|
|
62
|
+
/ "invalid"
|
|
63
|
+
/ "discord"
|
|
64
|
+
/ "discord.admin-access.changed.command.v1.missing-reason.json",
|
|
65
|
+
),
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_valid_discord_fixtures_pass() -> None:
|
|
70
|
+
for schema_path, fixture_path in VALID_CASES:
|
|
71
|
+
assert_valid(schema_path, fixture_path)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_invalid_discord_fixtures_fail() -> None:
|
|
75
|
+
for schema_path, fixture_path in INVALID_CASES:
|
|
76
|
+
error = assert_invalid(schema_path, fixture_path)
|
|
77
|
+
assert error is not None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_discord_fixture_inventory_exists() -> None:
|
|
81
|
+
discord_valid_dir = fixtures_root() / "valid" / "discord"
|
|
82
|
+
discord_invalid_dir = fixtures_root() / "invalid" / "discord"
|
|
83
|
+
|
|
84
|
+
assert discord_valid_dir.exists()
|
|
85
|
+
assert discord_invalid_dir.exists()
|
|
86
|
+
assert any(discord_valid_dir.iterdir())
|
|
87
|
+
assert any(discord_invalid_dir.iterdir())
|