Skip to content

Commit 42465fa

Browse files
committed
Add tests for validation of thing context URLs.
This checks that any URL specified for the "context" field of a Thing Description is valid.
1 parent e6d0253 commit 42465fa

2 files changed

Lines changed: 74 additions & 17 deletions

File tree

src/labthings_fastapi/thing_description/_model.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -84,32 +84,37 @@ class Subprotocol(Enum):
8484
def uses_thing_context(v: ThingContextType) -> None:
8585
"""Check the URLs in the ThingContextType are valid.
8686
87-
This function makes ``assert`` statements, so will fail with an exception
88-
if it is not valid. This module is hard coded to use valid URLs, so it is
89-
not an expected error.
87+
This function checks a valid context URL is provided. See the
88+
JSONSchema for Thing Description (`td-json-schema-validation.json`)
89+
for more details.
9090
9191
See https://www.w3.org/TR/wot-thing-description11/#thing
92-
This refers to the ``@context`` property.
92+
Specifically, the ``@context`` property is what this function
93+
validates.
9394
9495
:param v: the ThingContextType object.
9596
9697
:raises ValueError: if the URL is not correct.
9798
"""
9899
if not isinstance(v, list):
99-
if v is not THING_CONTEXT_URL:
100-
raise ValueError(f"{v} must be {THING_CONTEXT_URL}") # pragma: no cover
101-
# excluded from coverage as this is hardcoded, so we shouldn't ever
102-
# see the error.
100+
if v != THING_CONTEXT_URL:
101+
raise ValueError(f"{v} must be {THING_CONTEXT_URL}")
103102
else:
104-
if not (
105-
v[0] == THING_CONTEXT_URL
106-
or v[1] == THING_CONTEXT_URL
107-
and v[0] == THING_CONTEXT_URL_v1
108-
):
109-
raise ValueError(
110-
f"{v} must contain {THING_CONTEXT_URL}"
111-
) # pragma: no cover
112-
# This is hard-coded, so is not an error we ever expect to see.
103+
if len(v) == 0:
104+
raise ValueError("The context can't be an empty list.")
105+
if v[0] == THING_CONTEXT_URL:
106+
if THING_CONTEXT_URL_v1 in v[1:]:
107+
raise ValueError("An old context is given after the current one.")
108+
return # If the old URL isn't in the list, it's OK.
109+
if v[0] == THING_CONTEXT_URL_v1:
110+
# It's OK to start with the old URL, provided the new URL follows.
111+
if len(v) > 1 and v[1] == THING_CONTEXT_URL:
112+
return # Old URL followed by new URL is OK.
113+
else:
114+
raise ValueError("The thing context URL is outdated, should be v1.1.")
115+
raise ValueError(
116+
f"{v} must contain {THING_CONTEXT_URL} before {THING_CONTEXT_URL_v1}."
117+
)
113118

114119

115120
ThingContext = Annotated[

tests/test_thing_description.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""Tests for the thing_description submodule.
2+
3+
The `.thing_description` module is mostly tested by other files in the test suite.
4+
This file checks a validation function that's not currently used (as we validate
5+
against the JSONSchema directly, rather than my port of it to Pydantic).
6+
"""
7+
8+
import pytest
9+
import labthings_fastapi.thing_description._model as model
10+
11+
OLD_CONTEXT = "https://www.w3.org/2019/wot/td/v1"
12+
CONTEXT = "https://www.w3.org/2022/wot/td/v1.1"
13+
14+
15+
@pytest.mark.parametrize(
16+
"value",
17+
[
18+
CONTEXT,
19+
[CONTEXT],
20+
[CONTEXT, {"@language": "en"}],
21+
[OLD_CONTEXT, CONTEXT],
22+
[OLD_CONTEXT, CONTEXT, "https://something.else/context"],
23+
],
24+
)
25+
def test_thing_context_valid(value):
26+
"""Test the uses_thing_context validator.
27+
28+
Note that ``model.uses_thing_context`` is a pydantic validator, so it either
29+
returns ``None`` or raises an exception.
30+
31+
This validation logic should reproduce what's done in the JSON Schema provided
32+
by W3C, which is included in the ``thing_description`` submodule.
33+
"""
34+
assert model.uses_thing_context(value) is None
35+
36+
37+
@pytest.mark.parametrize(
38+
"value",
39+
[
40+
OLD_CONTEXT,
41+
[OLD_CONTEXT],
42+
[CONTEXT, OLD_CONTEXT],
43+
"https://some.url/",
44+
"a random string",
45+
{"key": "value"},
46+
["a list of strings", "with two elements"],
47+
],
48+
)
49+
def test_thing_context_invalid(value):
50+
"""Test invalid values fail to be validated as thing contexts."""
51+
with pytest.raises(ValueError):
52+
model.uses_thing_context(value)

0 commit comments

Comments
 (0)