From d05753cf947bde7dd588b80bfd0c0c973e0b1458 Mon Sep 17 00:00:00 2001 From: zzstoatzz Date: Sun, 24 Nov 2024 16:37:42 -0600 Subject: [PATCH] invert condition and source test data lint --- .../atproto_client/models/string_formats.py | 6 +- .../syntax/atidentifier_syntax_invalid.txt | 28 ++++++ .../syntax/atidentifier_syntax_valid.txt | 15 ++++ .../syntax/aturi_syntax_invalid.txt | 89 ++++++++++++++++++ .../syntax/aturi_syntax_valid.txt | 34 +++++++ .../syntax/datetime_parse_invalid.txt | 7 ++ .../syntax/datetime_syntax_invalid.txt | 68 ++++++++++++++ .../syntax/datetime_syntax_valid.txt | 40 +++++++++ .../syntax/did_syntax_invalid.txt | 19 ++++ .../syntax/did_syntax_valid.txt | 26 ++++++ .../syntax/handle_syntax_invalid.txt | 61 +++++++++++++ .../syntax/handle_syntax_valid.txt | 90 +++++++++++++++++++ .../syntax/nsid_syntax_invalid.txt | 32 +++++++ .../syntax/nsid_syntax_valid.txt | 29 ++++++ .../syntax/recordkey_syntax_invalid.txt | 15 ++++ .../syntax/recordkey_syntax_valid.txt | 21 +++++ .../syntax/tid_syntax_invalid.txt | 15 ++++ .../syntax/tid_syntax_valid.txt | 6 ++ .../models/tests/test_string_formats.py | 87 +++++++++++++----- 19 files changed, 661 insertions(+), 27 deletions(-) create mode 100644 tests/test_atproto_client/interop-test-files/syntax/atidentifier_syntax_invalid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/atidentifier_syntax_valid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/aturi_syntax_invalid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/aturi_syntax_valid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/datetime_parse_invalid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/datetime_syntax_invalid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/datetime_syntax_valid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/did_syntax_invalid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/did_syntax_valid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/handle_syntax_invalid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/handle_syntax_valid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/nsid_syntax_invalid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/nsid_syntax_valid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/recordkey_syntax_invalid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/recordkey_syntax_valid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/tid_syntax_invalid.txt create mode 100644 tests/test_atproto_client/interop-test-files/syntax/tid_syntax_valid.txt diff --git a/packages/atproto_client/models/string_formats.py b/packages/atproto_client/models/string_formats.py index 19da26d8..33df0005 100644 --- a/packages/atproto_client/models/string_formats.py +++ b/packages/atproto_client/models/string_formats.py @@ -34,9 +34,9 @@ def only_validate_if_strict(validate_fn: core_schema.WithInfoValidatorFunction) """Skip validation if not opting into strict validation.""" def wrapper(v: str, info: ValidationInfo) -> str: - if not (info and isinstance(info.context, Mapping) and info.context.get(_OPT_IN_KEY, False)): - return v - return validate_fn(v, info) + if info and isinstance(info.context, Mapping) and info.context.get(_OPT_IN_KEY, False): + return validate_fn(v, info) + return v return wrapper diff --git a/tests/test_atproto_client/interop-test-files/syntax/atidentifier_syntax_invalid.txt b/tests/test_atproto_client/interop-test-files/syntax/atidentifier_syntax_invalid.txt new file mode 100644 index 00000000..f0f84309 --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/atidentifier_syntax_invalid.txt @@ -0,0 +1,28 @@ + +# invalid handles +did:thing.test +did:thing +john-.test +john.0 +john.- +xn--bcher-.tld +john..test +jo_hn.test + +# invalid DIDs +did +didmethodval +method:did:val +did:method: +didmethod:val +did:methodval) +:did:method:val +did:method:val: +did:method:val% +DID:method:val + +# other invalid stuff +email@example.com +@handle@example.com +@handle +blah diff --git a/tests/test_atproto_client/interop-test-files/syntax/atidentifier_syntax_valid.txt b/tests/test_atproto_client/interop-test-files/syntax/atidentifier_syntax_valid.txt new file mode 100644 index 00000000..cc4a42b0 --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/atidentifier_syntax_valid.txt @@ -0,0 +1,15 @@ + +# allows valid handles +XX.LCS.MIT.EDU +john.test +jan.test +a234567890123456789.test +john2.test +john-john.test + +# allows valid DIDs +did:method:val +did:method:VAL +did:method:val123 +did:method:123 +did:method:val-two diff --git a/tests/test_atproto_client/interop-test-files/syntax/aturi_syntax_invalid.txt b/tests/test_atproto_client/interop-test-files/syntax/aturi_syntax_invalid.txt new file mode 100644 index 00000000..2ac2eada --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/aturi_syntax_invalid.txt @@ -0,0 +1,89 @@ + +# enforces spec basics +a://did:plc:asdf123 +at//did:plc:asdf123 +at:/a/did:plc:asdf123 +at:/did:plc:asdf123 +AT://did:plc:asdf123 +http://did:plc:asdf123 +://did:plc:asdf123 +at:did:plc:asdf123 +at:/did:plc:asdf123 +at:///did:plc:asdf123 +at://:/did:plc:asdf123 +at:/ /did:plc:asdf123 +at://did:plc:asdf123 +at://did:plc:asdf123/ + at://did:plc:asdf123 +at://did:plc:asdf123/com.atproto.feed.post +at://did:plc:asdf123/com.atproto.feed.post# +at://did:plc:asdf123/com.atproto.feed.post#/ +at://did:plc:asdf123/com.atproto.feed.post#/frag +at://did:plc:asdf123/com.atproto.feed.post#fr ag +//did:plc:asdf123 +at://name +at://name.0 +at://diD:plc:asdf123 +at://did:plc:asdf123/com.atproto.feed.p@st +at://did:plc:asdf123/com.atproto.feed.p$st +at://did:plc:asdf123/com.atproto.feed.p%st +at://did:plc:asdf123/com.atproto.feed.p&st +at://did:plc:asdf123/com.atproto.feed.p()t +at://did:plc:asdf123/com.atproto.feed_post +at://did:plc:asdf123/-com.atproto.feed.post +at://did:plc:asdf@123/com.atproto.feed.post +at://DID:plc:asdf123 +at://user.bsky.123 +at://bsky +at://did:plc: +at://did:plc: +at://frag + +# too long: 'at://did:plc:asdf123/com.atproto.feed.post/' + 'o'.repeat(8200) +at://did:plc:asdf123/com.atproto.feed.post/oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo + +# has specified behavior on edge cases +at://user.bsky.social// +at://user.bsky.social//com.atproto.feed.post +at://user.bsky.social/com.atproto.feed.post// +at://did:plc:asdf123/com.atproto.feed.post/asdf123/more/more', +at://did:plc:asdf123/short/stuff +at://did:plc:asdf123/12345 + +# enforces no trailing slashes +at://did:plc:asdf123/ +at://user.bsky.social/ +at://did:plc:asdf123/com.atproto.feed.post/ +at://did:plc:asdf123/com.atproto.feed.post/record/ +at://did:plc:asdf123/com.atproto.feed.post/record/#/frag + +# enforces strict paths +at://did:plc:asdf123/com.atproto.feed.post/asdf123/asdf + +# is very permissive about fragments +at://did:plc:asdf123# +at://did:plc:asdf123## +#at://did:plc:asdf123 +at://did:plc:asdf123#/asdf#/asdf + +# new less permissive about record keys for Lexicon use (with recordkey more specified) +at://did:plc:asdf123/com.atproto.feed.post/%23 +at://did:plc:asdf123/com.atproto.feed.post/$@!*)(:,;~.sdf123 +at://did:plc:asdf123/com.atproto.feed.post/~'sdf123") +at://did:plc:asdf123/com.atproto.feed.post/$ +at://did:plc:asdf123/com.atproto.feed.post/@ +at://did:plc:asdf123/com.atproto.feed.post/! +at://did:plc:asdf123/com.atproto.feed.post/* +at://did:plc:asdf123/com.atproto.feed.post/( +at://did:plc:asdf123/com.atproto.feed.post/, +at://did:plc:asdf123/com.atproto.feed.post/; +at://did:plc:asdf123/com.atproto.feed.post/abc%30123 +at://did:plc:asdf123/com.atproto.feed.post/%30 +at://did:plc:asdf123/com.atproto.feed.post/%3 +at://did:plc:asdf123/com.atproto.feed.post/% +at://did:plc:asdf123/com.atproto.feed.post/%zz +at://did:plc:asdf123/com.atproto.feed.post/%%% + +# disallow dot / double-dot +at://did:plc:asdf123/com.atproto.feed.post/. +at://did:plc:asdf123/com.atproto.feed.post/.. diff --git a/tests/test_atproto_client/interop-test-files/syntax/aturi_syntax_valid.txt b/tests/test_atproto_client/interop-test-files/syntax/aturi_syntax_valid.txt new file mode 100644 index 00000000..fd4523d0 --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/aturi_syntax_valid.txt @@ -0,0 +1,34 @@ + +# enforces spec basics +at://did:plc:asdf123 +at://user.bsky.social +at://did:plc:asdf123/com.atproto.feed.post +at://did:plc:asdf123/com.atproto.feed.post/record + +# very long: 'at://did:plc:asdf123/com.atproto.feed.post/' + 'o'.repeat(512) +at://did:plc:asdf123/com.atproto.feed.post/oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo + +# enforces no trailing slashes +at://did:plc:asdf123 +at://user.bsky.social +at://did:plc:asdf123/com.atproto.feed.post +at://did:plc:asdf123/com.atproto.feed.post/record + +# enforces strict paths +at://did:plc:asdf123/com.atproto.feed.post/asdf123 + +# is very permissive about record keys +at://did:plc:asdf123/com.atproto.feed.post/asdf123 +at://did:plc:asdf123/com.atproto.feed.post/a + +at://did:plc:asdf123/com.atproto.feed.post/asdf-123 +at://did:abc:123 +at://did:abc:123/io.nsid.someFunc/record-key + +at://did:abc:123/io.nsid.someFunc/self. +at://did:abc:123/io.nsid.someFunc/lang: +at://did:abc:123/io.nsid.someFunc/: +at://did:abc:123/io.nsid.someFunc/- +at://did:abc:123/io.nsid.someFunc/_ +at://did:abc:123/io.nsid.someFunc/~ +at://did:abc:123/io.nsid.someFunc/... diff --git a/tests/test_atproto_client/interop-test-files/syntax/datetime_parse_invalid.txt b/tests/test_atproto_client/interop-test-files/syntax/datetime_parse_invalid.txt new file mode 100644 index 00000000..3672453a --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/datetime_parse_invalid.txt @@ -0,0 +1,7 @@ +# superficial syntax parses ok, but are not valid datetimes for semantic reasons (eg, "month zero") +1985-00-12T23:20:50.123Z +1985-04-00T23:20:50.123Z +1985-13-12T23:20:50.123Z +1985-04-12T25:20:50.123Z +1985-04-12T23:99:50.123Z +1985-04-12T23:20:61.123Z diff --git a/tests/test_atproto_client/interop-test-files/syntax/datetime_syntax_invalid.txt b/tests/test_atproto_client/interop-test-files/syntax/datetime_syntax_invalid.txt new file mode 100644 index 00000000..6702e43e --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/datetime_syntax_invalid.txt @@ -0,0 +1,68 @@ + +# subtle changes to: 1985-04-12T23:20:50.123Z +1985-04-12T23:20:50.123z +01985-04-12T23:20:50.123Z +985-04-12T23:20:50.123Z +1985-04-12T23:20:50.Z +1985-04-32T23;20:50.123Z +1985-04-32T23;20:50.123Z + +# en-dash and em-dash +1985—04-32T23;20:50.123Z +1985–04-32T23;20:50.123Z + +# whitespace + 1985-04-12T23:20:50.123Z +1985-04-12T23:20:50.123Z +1985-04-12T 23:20:50.123Z + +# not enough zero padding +1985-4-12T23:20:50.123Z +1985-04-2T23:20:50.123Z +1985-04-12T3:20:50.123Z +1985-04-12T23:0:50.123Z +1985-04-12T23:20:5.123Z + +# too much zero padding +01985-04-12T23:20:50.123Z +1985-004-12T23:20:50.123Z +1985-04-012T23:20:50.123Z +1985-04-12T023:20:50.123Z +1985-04-12T23:020:50.123Z +1985-04-12T23:20:050.123Z + +# strict capitalization (ISO-8601) +1985-04-12t23:20:50.123Z +1985-04-12T23:20:50.123z + +# RFC-3339, but not ISO-8601 +1985-04-12T23:20:50.123-00:00 +1985-04-12_23:20:50.123Z +1985-04-12 23:20:50.123Z + +# ISO-8601, but weird +1985-04-274T23:20:50.123Z + +# timezone is required +1985-04-12T23:20:50.123 +1985-04-12T23:20:50 + +1985-04-12 +1985-04-12T23:20Z +1985-04-12T23:20:5Z +1985-04-12T23:20:50.123 ++001985-04-12T23:20:50.123Z +23:20:50.123Z + +1985-04-12T23:20:50.123+00 +1985-04-12T23:20:50.123+00:0 +1985-04-12T23:20:50.123+0:00 +1985-04-12T23:20:50.123 +1985-04-12T23:20:50.123+0000 +1985-04-12T23:20:50.123+00 +1985-04-12T23:20:50.123+ +1985-04-12T23:20:50.123- + +# ISO-8601, but normalizes to a negative time +0000-01-01T00:00:00+01:00 +-000001-12-31T23:00:00.000Z diff --git a/tests/test_atproto_client/interop-test-files/syntax/datetime_syntax_valid.txt b/tests/test_atproto_client/interop-test-files/syntax/datetime_syntax_valid.txt new file mode 100644 index 00000000..f47d539c --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/datetime_syntax_valid.txt @@ -0,0 +1,40 @@ +# "preferred" +1985-04-12T23:20:50.123Z +1985-04-12T23:20:50.000Z +2000-01-01T00:00:00.000Z +1985-04-12T23:20:50.123456Z +1985-04-12T23:20:50.120Z +1985-04-12T23:20:50.120000Z + +# "supported" +1985-04-12T23:20:50.1235678912345Z +1985-04-12T23:20:50.100Z +1985-04-12T23:20:50Z +1985-04-12T23:20:50.0Z +1985-04-12T23:20:50.123+00:00 +1985-04-12T23:20:50.123-07:00 +1985-04-12T23:20:50.123+07:00 +1985-04-12T23:20:50.123+01:45 +0985-04-12T23:20:50.123-07:00 +1985-04-12T23:20:50.123-07:00 +0123-01-01T00:00:00.000Z + +# various precisions, up through at least 12 digits +1985-04-12T23:20:50.1Z +1985-04-12T23:20:50.12Z +1985-04-12T23:20:50.123Z +1985-04-12T23:20:50.1234Z +1985-04-12T23:20:50.12345Z +1985-04-12T23:20:50.123456Z +1985-04-12T23:20:50.1234567Z +1985-04-12T23:20:50.12345678Z +1985-04-12T23:20:50.123456789Z +1985-04-12T23:20:50.1234567890Z +1985-04-12T23:20:50.12345678901Z +1985-04-12T23:20:50.123456789012Z + +# extreme but currently allowed +0010-12-31T23:00:00.000Z +1000-12-31T23:00:00.000Z +1900-12-31T23:00:00.000Z +3001-12-31T23:00:00.000Z diff --git a/tests/test_atproto_client/interop-test-files/syntax/did_syntax_invalid.txt b/tests/test_atproto_client/interop-test-files/syntax/did_syntax_invalid.txt new file mode 100644 index 00000000..9e724b3d --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/did_syntax_invalid.txt @@ -0,0 +1,19 @@ +did +didmethodval +method:did:val +did:method: +didmethod:val +did:methodval) +:did:method:val +did.method.val +did:method:val: +did:method:val% +DID:method:val +did:METHOD:val +did:m123:val +did:method:val/two +did:method:val?two +did:method:val#two +did:method:val% +did:method:vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv + diff --git a/tests/test_atproto_client/interop-test-files/syntax/did_syntax_valid.txt b/tests/test_atproto_client/interop-test-files/syntax/did_syntax_valid.txt new file mode 100644 index 00000000..5aa6c9e7 --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/did_syntax_valid.txt @@ -0,0 +1,26 @@ +did:method:val +did:method:VAL +did:method:val123 +did:method:123 +did:method:val-two +did:method:val_two +did:method:val.two +did:method:val:two +did:method:val%BB +did:method:vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv +did:m:v +did:method::::val +did:method:- +did:method:-:_:.:%ab +did:method:. +did:method:_ +did:method::. + +# allows some real DID values +did:onion:2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid +did:example:123456789abcdefghi +did:plc:7iza6de2dwap2sbkpav7c6c6 +did:web:example.com +did:web:localhost%3A1234 +did:key:zQ3shZc2QzApp2oymGvQbzP8eKheVshBHbU4ZYjeXqwSKEn6N +did:ethr:0xb9c5714089478a327f09197987f16f9e5d936e8a diff --git a/tests/test_atproto_client/interop-test-files/syntax/handle_syntax_invalid.txt b/tests/test_atproto_client/interop-test-files/syntax/handle_syntax_invalid.txt new file mode 100644 index 00000000..49275a39 --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/handle_syntax_invalid.txt @@ -0,0 +1,61 @@ +# throws on invalid handles +did:thing.test +did:thing +john-.test +john.0 +john.- +xn--bcher-.tld +john..test +jo_hn.test +-john.test +.john.test +jo!hn.test +jo%hn.test +jo&hn.test +jo@hn.test +jo*hn.test +jo|hn.test +jo:hn.test +jo/hn.test +john💩.test +bücher.test +john .test +john.test. +john +john. +.john +john.test. +.john.test + john.test +john.test +joh-.test +john.-est +john.tes- + +# max over all handle: 'shoooort' + '.loooooooooooooooooooooooooong'.repeat(9) + '.test' +shoooort.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.test + +# max segment: 'short.' + 'o'.repeat(64) + '.test' +short.oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo.test + +# throws on "dotless" TLD handles +org +ai +gg +io + +# correctly validates corner cases (modern vs. old RFCs) +cn.8 +thing.0aa +thing.0aa + +# does not allow IP addresses as handles +127.0.0.1 +192.168.0.142 +fe80::7325:8a97:c100:94b +2600:3c03::f03c:9100:feb0:af1f + +# examples from stackoverflow +-notvalid.at-all +-thing.com +www.masełkowski.pl.com diff --git a/tests/test_atproto_client/interop-test-files/syntax/handle_syntax_valid.txt b/tests/test_atproto_client/interop-test-files/syntax/handle_syntax_valid.txt new file mode 100644 index 00000000..a23a9213 --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/handle_syntax_valid.txt @@ -0,0 +1,90 @@ +# allows valid handles +A.ISI.EDU +XX.LCS.MIT.EDU +SRI-NIC.ARPA +john.test +jan.test +a234567890123456789.test +john2.test +john-john.test +john.bsky.app +jo.hn +a.co +a.org +joh.n +j0.h0 +jaymome-johnber123456.test +jay.mome-johnber123456.test +john.test.bsky.app + +# max over all handle: 'shoooort' + '.loooooooooooooooooooooooooong'.repeat(8) + '.test' +shoooort.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.test + +# max segment: 'short.' + 'o'.repeat(63) + '.test' +short.ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo.test + +# NOTE: this probably isn't ever going to be a real domain, but my read of the RFC is that it would be possible +john.t + +# allows .local and .arpa handles (proto-level) +laptop.local +laptop.arpa + +# allows punycode handles +# 💩.test +xn--ls8h.test +# bücher.tld +xn--bcher-kva.tld +xn--3jk.com +xn--w3d.com +xn--vqb.com +xn--ppd.com +xn--cs9a.com +xn--8r9a.com +xn--cfd.com +xn--5jk.com +xn--2lb.com + +# allows onion (Tor) handles +expyuzz4wqqyqhjn.onion +friend.expyuzz4wqqyqhjn.onion +g2zyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion +friend.g2zyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion +friend.g2zyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion +2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion +friend.2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion + +# correctly validates corner cases (modern vs. old RFCs) +12345.test +8.cn +4chan.org +4chan.o-g +blah.4chan.org +thing.a01 +120.0.0.1.com +0john.test +9sta--ck.com +99stack.com +0ohn.test +john.t--t +thing.0aa.thing + +# examples from stackoverflow +stack.com +sta-ck.com +sta---ck.com +sta--ck9.com +stack99.com +sta99ck.com +google.com.uk +google.co.in +google.com +maselkowski.pl +m.maselkowski.pl +xn--masekowski-d0b.pl +xn--fiqa61au8b7zsevnm8ak20mc4a87e.xn--fiqs8s +xn--stackoverflow.com +stackoverflow.xn--com +stackoverflow.co.uk +xn--masekowski-d0b.pl +xn--fiqa61au8b7zsevnm8ak20mc4a87e.xn--fiqs8s diff --git a/tests/test_atproto_client/interop-test-files/syntax/nsid_syntax_invalid.txt b/tests/test_atproto_client/interop-test-files/syntax/nsid_syntax_invalid.txt new file mode 100644 index 00000000..bc0bd2fd --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/nsid_syntax_invalid.txt @@ -0,0 +1,32 @@ +# length checks +com.oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo.foo +com.example.oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo +com.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.foo + +# invliad examples +com.example.foo.* +com.example.foo.blah* +com.example.foo.*blah +com.example.f00 +com.exa💩ple.thing +a-0.b-1.c-3 +a-0.b-1.c-o +a0.b1.c3 +1.0.0.127.record +0two.example.foo +example.com +com.example +a. +.one.two.three +one.two.three +one.two..three +one .two.three + one.two.three +com.exa💩ple.thing +com.atproto.feed.p@st +com.atproto.feed.p_st +com.atproto.feed.p*st +com.atproto.feed.po#t +com.atproto.feed.p!ot +com.example-.foo + diff --git a/tests/test_atproto_client/interop-test-files/syntax/nsid_syntax_valid.txt b/tests/test_atproto_client/interop-test-files/syntax/nsid_syntax_valid.txt new file mode 100644 index 00000000..54ef351f --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/nsid_syntax_valid.txt @@ -0,0 +1,29 @@ +# length checks +com.ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo.foo +com.example.ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo +com.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.middle.foo + +# valid examples +com.example.fooBar +net.users.bob.ping +a.b.c +m.xn--masekowski-d0b.pl +one.two.three +one.two.three.four-and.FiVe +one.2.three +a-0.b-1.c +a0.b1.cc +cn.8.lex.stuff +test.12345.record +a01.thing.record +a.0.c +xn--fiqs8s.xn--fiqa61au8b7zsevnm8ak20mc4a87e.record.two + +# allows onion (Tor) NSIDs +onion.expyuzz4wqqyqhjn.spec.getThing +onion.g2zyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.lex.deleteThing + +# allows starting-with-numeric segments (same as domains) +org.4chan.lex.getThing +cn.8.lex.stuff +onion.2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.lex.deleteThing diff --git a/tests/test_atproto_client/interop-test-files/syntax/recordkey_syntax_invalid.txt b/tests/test_atproto_client/interop-test-files/syntax/recordkey_syntax_invalid.txt new file mode 100644 index 00000000..52106d87 --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/recordkey_syntax_invalid.txt @@ -0,0 +1,15 @@ +# specs +alpha/beta +. +.. +#extra +@handle +any space +any+space +number[3] +number(3) +"quote" +dHJ1ZQ== + +# too long: 'o'.repeat(513) +ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo diff --git a/tests/test_atproto_client/interop-test-files/syntax/recordkey_syntax_valid.txt b/tests/test_atproto_client/interop-test-files/syntax/recordkey_syntax_valid.txt new file mode 100644 index 00000000..92e8b7e3 --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/recordkey_syntax_valid.txt @@ -0,0 +1,21 @@ +# specs +self +example.com +~1.2-3_ +dHJ1ZQ +_ +literal:self +pre:fix + +# more corner-cases +: +- +_ +~ +... +self. +lang: +:lang + +# very long: 'o'.repeat(512) +oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo diff --git a/tests/test_atproto_client/interop-test-files/syntax/tid_syntax_invalid.txt b/tests/test_atproto_client/interop-test-files/syntax/tid_syntax_invalid.txt new file mode 100644 index 00000000..eca90b2d --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/tid_syntax_invalid.txt @@ -0,0 +1,15 @@ + +# not base32 +3jzfcijpj2z21 +0000000000000 + +# too long/short +3jzfcijpj2z2aa +3jzfcijpj2z2 + +# old dashes syntax not actually supported (TTTT-TTT-TTTT-CC) +3jzf-cij-pj2z-2a + +# high bit can't be high +zzzzzzzzzzzzz +kjzfcijpj2z2a diff --git a/tests/test_atproto_client/interop-test-files/syntax/tid_syntax_valid.txt b/tests/test_atproto_client/interop-test-files/syntax/tid_syntax_valid.txt new file mode 100644 index 00000000..b161a3fe --- /dev/null +++ b/tests/test_atproto_client/interop-test-files/syntax/tid_syntax_valid.txt @@ -0,0 +1,6 @@ +# 13 digits +# 234567abcdefghijklmnopqrstuvwxyz + +3jzfcijpj2z2a +7777777777777 +3zzzzzzzzzzzz diff --git a/tests/test_atproto_client/models/tests/test_string_formats.py b/tests/test_atproto_client/models/tests/test_string_formats.py index d29c666d..16725ee4 100644 --- a/tests/test_atproto_client/models/tests/test_string_formats.py +++ b/tests/test_atproto_client/models/tests/test_string_formats.py @@ -1,3 +1,5 @@ +from pathlib import Path + import pytest from atproto_client.exceptions import ModelError from atproto_client.models import string_formats @@ -5,38 +7,75 @@ from atproto_client.models.utils import get_or_create from pydantic import BaseModel, TypeAdapter, ValidationError +# Test data sourced directly from bluesky-social/atproto repo: +# https://github.com/bluesky-social/atproto/tree/main/interop-test-files/syntax +INTEROP_TEST_FILES_DIR: Path = Path('tests/test_atproto_client/interop-test-files/syntax') + +def get_test_cases(filename: str) -> list[str]: + """Get non-comment, non-empty lines from an interop test file.""" + return [ + line.strip() for line in INTEROP_TEST_FILES_DIR.joinpath(filename).read_text().splitlines() + if line.strip() and not line.startswith('#') + ] @pytest.fixture -def invalid_data() -> dict: - return { - 'handle': 'invalid@ @handle', - 'did': 'not-a-did', - 'nsid': 'invalid-nsid', - 'at_uri': 'not-an-at-uri', - 'cid': 'short', - 'datetime': '2023-01-01', - 'tid': 'invalid-tid', - 'record_key': '..', - 'uri': 'invalid-uri-no-scheme', - 'language': 'invalid!', - } +def valid_handles() -> list[str]: + return get_test_cases('handle_syntax_valid.txt') + +@pytest.fixture +def valid_dids() -> list[str]: + return get_test_cases('did_syntax_valid.txt') + +@pytest.fixture +def valid_nsids() -> list[str]: + return get_test_cases('nsid_syntax_valid.txt') + +@pytest.fixture +def valid_aturis() -> list[str]: + return get_test_cases('aturi_syntax_valid.txt') + +@pytest.fixture +def valid_datetimes() -> list[str]: + return get_test_cases('datetime_syntax_valid.txt') + +@pytest.fixture +def valid_tids() -> list[str]: + return get_test_cases('tid_syntax_valid.txt') +@pytest.fixture +def valid_record_keys() -> list[str]: + return get_test_cases('recordkey_syntax_valid.txt') @pytest.fixture -def valid_data() -> dict: +def valid_data(valid_handles: list[str], valid_dids: list[str], valid_nsids: list[str], valid_aturis: list[str], + valid_datetimes: list[str], valid_tids: list[str], valid_record_keys: list[str]) -> dict: return { - 'handle': 'test.bsky.social', - 'did': 'did:plc:1234abcd', - 'nsid': 'app.bsky.feed.post', - 'at_uri': 'at://user.bsky.social/posts/123', - 'cid': 'bafyreidfayvfuwqa2beehqn7axeeeaej5aqvaowxgwcdt2rw', - 'datetime': '2023-01-01T12:00:00Z', - 'tid': '3jqvenncqkgbm', - 'record_key': 'valid-key', - 'uri': 'https://example.com', - 'language': 'en-US', + 'handle': valid_handles[0], + 'did': valid_dids[0], + 'nsid': valid_nsids[0], + 'at_uri': valid_aturis[0], + 'cid': 'bafyreidfayvfuwqa2beehqn7axeeeaej5aqvaowxgwcdt2rw', # No interop test file for CID + 'datetime': valid_datetimes[0], + 'tid': valid_tids[0], + 'record_key': valid_record_keys[0], + 'uri': 'https://example.com', # No interop test file for URI + 'language': 'en-US', # No interop test file for language } +@pytest.fixture +def invalid_data() -> dict: + return { + 'handle': get_test_cases('handle_syntax_invalid.txt')[0], + 'did': get_test_cases('did_syntax_invalid.txt')[0], + 'nsid': get_test_cases('nsid_syntax_invalid.txt')[0], + 'at_uri': get_test_cases('aturi_syntax_invalid.txt')[0], + 'cid': 'short', # No interop test file for CID + 'datetime': get_test_cases('datetime_syntax_invalid.txt')[0], + 'tid': get_test_cases('tid_syntax_invalid.txt')[0], + 'record_key': get_test_cases('recordkey_syntax_invalid.txt')[0], + 'uri': 'invalid-uri-no-scheme', # No interop test file for URI + 'language': 'invalid!', # No interop test file for language + } @pytest.mark.parametrize( 'validator_type,field_name,expected_error',