commit 5662c167bc54291e64cb32bd309ee4d3f841b9f0
parent d4d6190c1cf37ec44e0cb488326425ca1b669227
Author: Zack Newman <zack@philomathiclife.com>
Date: Sun, 12 Jul 2026 13:45:33 -0600
bump msrv. update deps. new lints. move unit tests
Diffstat:
| M | Cargo.toml | | | 8 | +++++--- |
| M | src/lib.rs | | | 7 | ++----- |
| D | src/test.rs | | | 153 | ------------------------------------------------------------------------------- |
| A | src/tests.rs | | | 249 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
4 files changed, 256 insertions(+), 161 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
name = "base64url_nopad"
readme = "README.md"
repository = "https://git.philomathiclife.com/repos/base64url_nopad/"
-rust-version = "1.96.0"
+rust-version = "1.97.0"
version = "0.2.0"
[lints.rust]
@@ -28,13 +28,14 @@ unused = { level = "deny", priority = -1 }
warnings = { level = "deny", priority = -1 }
ambiguous-negative-literals = { level = "deny", priority = -1 }
closure-returning-async-block = { level = "deny", priority = -1 }
+dead-code-pub-in-binary = { level = "deny", priority = -1 }
deprecated-in-future = { level = "deny", priority = -1 }
+#deprecated-llvm-intrinsic = { level = "deny", priority = -1 }
deref-into-dyn-supertrait = { level = "deny", priority = -1 }
ffi-unwind-calls = { level = "deny", priority = -1 }
#fuzzy-provenance-casts = { level = "deny", priority = -1 }
impl-trait-redundant-captures = { level = "deny", priority = -1 }
linker-info = { level = "deny", priority = -1 }
-linker-messages = { level = "deny", priority = -1 }
#lossy-provenance-casts = { level = "deny", priority = -1 }
macro-use-extern-crate = { level = "deny", priority = -1 }
meta-variable-misuse = { level = "deny", priority = -1 }
@@ -80,6 +81,7 @@ arbitrary_source_item_ordering = "allow"
blanket_clippy_restriction_lints = "allow"
exhaustive_enums = "allow"
implicit_return = "allow"
+inline_trait_bounds = "allow"
min_ident_chars = "allow"
missing_trait_methods = "allow"
question_mark_used = "allow"
@@ -109,7 +111,7 @@ targets = [
]
[dev-dependencies]
-rand = { version = "0.10.1", default-features = false, features = ["sys_rng"] }
+rand = { version = "0.10.2", default-features = false, features = ["sys_rng"] }
### FEATURES #################################################################
diff --git a/src/lib.rs b/src/lib.rs
@@ -59,10 +59,7 @@
target_pointer_width = "64"
)
),
- allow(
- linker_messages,
- reason = "getrandom produces a linker message on macos"
- )
+ allow(linker_info, reason = "getrandom causes linker-info to fire on macos")
)]
#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
@@ -70,7 +67,7 @@
extern crate alloc;
/// Unit tests.
#[cfg(test)]
-mod test;
+mod tests;
#[cfg(any(doc, feature = "alloc"))]
use alloc::{collections::TryReserveError, string::String, vec::Vec};
use core::{
diff --git a/src/test.rs b/src/test.rs
@@ -1,153 +0,0 @@
-#[cfg(any(
- target_pointer_width = "16",
- target_pointer_width = "32",
- target_pointer_width = "64",
-))]
-use super::MAX_ENCODE_INPUT_LEN;
-#[cfg(feature = "alloc")]
-use alloc::string::String;
-#[cfg(any(
- target_pointer_width = "16",
- target_pointer_width = "32",
- target_pointer_width = "64",
-))]
-use rand::{RngExt as _, rngs::SmallRng};
-#[expect(
- clippy::as_conversions,
- clippy::cast_possible_truncation,
- reason = "comment justifies correctness"
-)]
-#[cfg(any(
- target_pointer_width = "16",
- target_pointer_width = "32",
- target_pointer_width = "64",
-))]
-#[ignore = "slow"]
-#[test]
-fn encode_decode_len() {
- assert_eq!(MAX_ENCODE_INPUT_LEN, 3 * (usize::MAX.div_ceil(4)) - 1);
- let mut rng = rand::make_rng::<SmallRng>();
- for _ in 0u32..10_000_000 {
- // `uN as usize` is fine since we `cfg` by pointer width.
- #[cfg(target_pointer_width = "16")]
- let len = rng.random::<u16>() as usize;
- #[cfg(target_pointer_width = "32")]
- let len = rng.random::<u32>() as usize;
- #[cfg(target_pointer_width = "64")]
- let len = rng.random::<u64>() as usize;
- if len <= MAX_ENCODE_INPUT_LEN {
- assert_eq!(
- super::encode_len_checked(len).map(super::decode_len),
- Some(Some(len))
- );
- } else {
- assert!(super::encode_len_checked(len).is_none());
- }
- }
- for i in 0..1025 {
- assert_eq!(
- super::encode_len_checked(i).map(super::decode_len),
- Some(Some(i))
- );
- }
- #[cfg(target_pointer_width = "16")]
- for i in MAX_ENCODE_INPUT_LEN + 1.. {
- assert!(super::encode_len_checked(i).is_none());
- }
- #[cfg(not(target_pointer_width = "16"))]
- for i in MAX_ENCODE_INPUT_LEN + 1..MAX_ENCODE_INPUT_LEN + 1_000_000 {
- assert!(super::encode_len_checked(i).is_none());
- }
- assert!(super::encode_len_checked(usize::MAX).is_none());
- assert_eq!(
- super::encode_len_checked(MAX_ENCODE_INPUT_LEN),
- Some(usize::MAX)
- );
- for _ in 0u32..10_000_000 {
- #[cfg(target_pointer_width = "16")]
- let len = rng.random::<u16>() as usize;
- #[cfg(target_pointer_width = "32")]
- let len = rng.random::<u32>() as usize;
- #[cfg(target_pointer_width = "64")]
- let len = rng.random::<u64>() as usize;
- if len & 3 == 1 {
- assert!(super::decode_len(len).is_none());
- } else {
- assert_eq!(
- super::decode_len(len).map(super::encode_len_checked),
- Some(Some(len))
- );
- }
- }
- for i in 0..1025 {
- if i & 3 == 1 {
- assert!(super::decode_len(i).is_none());
- } else {
- assert_eq!(
- super::decode_len(i).map(super::encode_len_checked),
- Some(Some(i))
- );
- }
- }
- #[cfg(target_pointer_width = "16")]
- for i in 0..=usize::MAX {
- if i & 3 == 1 {
- assert!(super::decode_len(i).is_none());
- } else {
- assert_eq!(
- super::decode_len(i).map(super::encode_len_checked),
- Some(Some(i))
- );
- }
- }
- #[cfg(not(target_pointer_width = "16"))]
- for i in usize::MAX - 1_000_000..=usize::MAX {
- if i & 3 == 1 {
- assert!(super::decode_len(i).is_none());
- } else {
- assert_eq!(
- super::decode_len(i).map(super::encode_len_checked),
- Some(Some(i))
- );
- }
- }
- assert_eq!(super::decode_len(usize::MAX), Some(MAX_ENCODE_INPUT_LEN));
-}
-#[expect(clippy::indexing_slicing, reason = "comments justify correctness")]
-#[cfg(feature = "alloc")]
-#[test]
-fn encode_write() {
- let input = [9; 8192];
- let mut buffer = String::with_capacity(super::encode_len(input.len()));
- let cap = buffer.capacity();
- let mut write_len;
- for len in 0..input.len() {
- write_len = super::encode_len(len);
- match write_len.checked_add(buffer.len()) {
- None => {
- buffer.clear();
- // Indexing is fine since `len <= input.len()`.
- assert_eq!(super::encode_write(&input[..len], &mut buffer), Ok(()));
- assert_eq!(buffer.len(), write_len);
- }
- Some(l) => {
- if l > cap {
- buffer.clear();
- // Indexing is fine since `len <= input.len()`.
- assert_eq!(super::encode_write(&input[..len], &mut buffer), Ok(()));
- assert_eq!(buffer.len(), write_len);
- } else {
- // Indexing is fine since `len <= input.len()`.
- assert_eq!(super::encode_write(&input[..len], &mut buffer), Ok(()));
- assert_eq!(buffer.len(), l);
- }
- }
- }
- assert!(
- buffer
- .as_bytes()
- .iter()
- .all(|b| { matches!(*b, b'C' | b'J' | b'Q' | b'k') })
- );
- }
-}
diff --git a/src/tests.rs b/src/tests.rs
@@ -0,0 +1,249 @@
+use super::DecodeErr;
+#[cfg(any(
+ target_pointer_width = "16",
+ target_pointer_width = "32",
+ target_pointer_width = "64",
+))]
+use super::MAX_ENCODE_INPUT_LEN;
+#[cfg(feature = "alloc")]
+use alloc::{borrow::ToOwned as _, string::String, vec};
+use core::fmt::{self, Write};
+#[cfg(any(
+ target_pointer_width = "16",
+ target_pointer_width = "32",
+ target_pointer_width = "64",
+))]
+use rand::{RngExt as _, rngs::SmallRng};
+#[expect(
+ clippy::as_conversions,
+ clippy::cast_possible_truncation,
+ reason = "comment justifies correctness"
+)]
+#[cfg(any(
+ target_pointer_width = "16",
+ target_pointer_width = "32",
+ target_pointer_width = "64",
+))]
+#[ignore = "slow"]
+#[test]
+fn encode_decode_len() {
+ assert_eq!(MAX_ENCODE_INPUT_LEN, 3 * (usize::MAX.div_ceil(4)) - 1);
+ let mut rng = rand::make_rng::<SmallRng>();
+ for _ in 0u32..10_000_000 {
+ // `uN as usize` is fine since we `cfg` by pointer width.
+ #[cfg(target_pointer_width = "16")]
+ let len = rng.random::<u16>() as usize;
+ #[cfg(target_pointer_width = "32")]
+ let len = rng.random::<u32>() as usize;
+ #[cfg(target_pointer_width = "64")]
+ let len = rng.random::<u64>() as usize;
+ if len <= MAX_ENCODE_INPUT_LEN {
+ assert_eq!(
+ super::encode_len_checked(len).map(super::decode_len),
+ Some(Some(len))
+ );
+ } else {
+ assert!(super::encode_len_checked(len).is_none());
+ }
+ }
+ for i in 0..1025 {
+ assert_eq!(
+ super::encode_len_checked(i).map(super::decode_len),
+ Some(Some(i))
+ );
+ }
+ #[cfg(target_pointer_width = "16")]
+ for i in MAX_ENCODE_INPUT_LEN + 1.. {
+ assert!(super::encode_len_checked(i).is_none());
+ }
+ #[cfg(not(target_pointer_width = "16"))]
+ for i in MAX_ENCODE_INPUT_LEN + 1..MAX_ENCODE_INPUT_LEN + 1_000_000 {
+ assert!(super::encode_len_checked(i).is_none());
+ }
+ assert!(super::encode_len_checked(usize::MAX).is_none());
+ assert_eq!(
+ super::encode_len_checked(MAX_ENCODE_INPUT_LEN),
+ Some(usize::MAX)
+ );
+ for _ in 0u32..10_000_000 {
+ #[cfg(target_pointer_width = "16")]
+ let len = rng.random::<u16>() as usize;
+ #[cfg(target_pointer_width = "32")]
+ let len = rng.random::<u32>() as usize;
+ #[cfg(target_pointer_width = "64")]
+ let len = rng.random::<u64>() as usize;
+ if len & 3 == 1 {
+ assert!(super::decode_len(len).is_none());
+ } else {
+ assert_eq!(
+ super::decode_len(len).map(super::encode_len_checked),
+ Some(Some(len))
+ );
+ }
+ }
+ for i in 0..1025 {
+ if i & 3 == 1 {
+ assert!(super::decode_len(i).is_none());
+ } else {
+ assert_eq!(
+ super::decode_len(i).map(super::encode_len_checked),
+ Some(Some(i))
+ );
+ }
+ }
+ #[cfg(target_pointer_width = "16")]
+ for i in 0..=usize::MAX {
+ if i & 3 == 1 {
+ assert!(super::decode_len(i).is_none());
+ } else {
+ assert_eq!(
+ super::decode_len(i).map(super::encode_len_checked),
+ Some(Some(i))
+ );
+ }
+ }
+ #[cfg(not(target_pointer_width = "16"))]
+ for i in usize::MAX - 1_000_000..=usize::MAX {
+ if i & 3 == 1 {
+ assert!(super::decode_len(i).is_none());
+ } else {
+ assert_eq!(
+ super::decode_len(i).map(super::encode_len_checked),
+ Some(Some(i))
+ );
+ }
+ }
+ assert_eq!(super::decode_len(usize::MAX), Some(MAX_ENCODE_INPUT_LEN));
+}
+#[expect(clippy::indexing_slicing, reason = "comments justify correctness")]
+#[cfg(feature = "alloc")]
+#[test]
+fn encode_write() {
+ let input = [9; 8192];
+ let mut buffer = String::with_capacity(super::encode_len(input.len()));
+ let cap = buffer.capacity();
+ let mut write_len;
+ for len in 0..input.len() {
+ write_len = super::encode_len(len);
+ match write_len.checked_add(buffer.len()) {
+ None => {
+ buffer.clear();
+ // Indexing is fine since `len <= input.len()`.
+ assert_eq!(super::encode_write(&input[..len], &mut buffer), Ok(()));
+ assert_eq!(buffer.len(), write_len);
+ }
+ Some(l) => {
+ if l > cap {
+ buffer.clear();
+ // Indexing is fine since `len <= input.len()`.
+ assert_eq!(super::encode_write(&input[..len], &mut buffer), Ok(()));
+ assert_eq!(buffer.len(), write_len);
+ } else {
+ // Indexing is fine since `len <= input.len()`.
+ assert_eq!(super::encode_write(&input[..len], &mut buffer), Ok(()));
+ assert_eq!(buffer.len(), l);
+ }
+ }
+ }
+ assert!(
+ buffer
+ .as_bytes()
+ .iter()
+ .all(|b| { matches!(*b, b'C' | b'J' | b'Q' | b'k') })
+ );
+ }
+}
+#[cfg(feature = "alloc")]
+#[test]
+fn try_encode() {
+ assert_eq!(super::try_encode(&[0]), Ok("AA".to_owned()));
+}
+#[cfg(feature = "alloc")]
+#[test]
+fn encode() {
+ assert_eq!(super::encode(&[0]), "AA".to_owned());
+}
+#[cfg(feature = "alloc")]
+#[test]
+fn try_encode_append() {
+ let mut val = "Hi".to_owned();
+ assert_eq!(
+ super::try_encode_append(&[0], &mut val),
+ Ok("AA".to_owned().as_mut_str())
+ );
+ assert_eq!(val, "HiAA");
+}
+#[cfg(feature = "alloc")]
+#[test]
+fn encode_append() {
+ let mut val = "Hi".to_owned();
+ assert_eq!(
+ super::encode_append(&[0], &mut val),
+ "AA".to_owned().as_mut_str()
+ );
+ assert_eq!(val, "HiAA");
+}
+#[cfg(feature = "alloc")]
+#[test]
+fn try_encode_append_only() {
+ let mut val = "Hi".to_owned();
+ assert_eq!(super::try_encode_append_only(&[0], &mut val), Ok(()));
+ assert_eq!(val, "HiAA");
+}
+#[cfg(feature = "alloc")]
+#[test]
+fn encode_append_only() {
+ let mut val = "Hi".to_owned();
+ super::encode_append_only(&[0], &mut val);
+ assert_eq!(val, "HiAA");
+}
+#[test]
+fn decode_buffer() {
+ assert_eq!(
+ super::decode_buffer(b"AA", &mut [0]),
+ Ok([0].as_mut_slice())
+ );
+ assert_eq!(
+ super::decode_buffer(b"AA", &mut []),
+ Err(DecodeErr::BufferLen)
+ );
+}
+#[cfg(feature = "alloc")]
+#[test]
+fn decode() {
+ assert_eq!(super::decode(b"AA"), Ok(vec![0]));
+}
+#[test]
+fn validate_encoded_data() {
+ assert_eq!(super::validate_encoded_data(b"AA"), Ok(()));
+}
+#[test]
+fn encode_buffer_exact() {
+ let mut output = [0; 2];
+ super::encode_buffer_exact(&[0], &mut output);
+ assert_eq!(output, *b"AA");
+}
+#[test]
+fn decode_buffer_exact() {
+ let mut output = [1];
+ assert_eq!(super::decode_buffer_exact(b"AA", &mut output), Ok(()));
+ assert_eq!(output, [0]);
+}
+#[test]
+fn encode_write_core() {
+ struct Writer<'a>(&'a mut [u8]);
+ impl Write for Writer<'_> {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ self.0.get_mut(..s.len()).ok_or(fmt::Error).map(|bytes| {
+ bytes.copy_from_slice(s.as_bytes());
+ })
+ }
+ }
+ let mut writer = Writer(&mut [0, 0, 1]);
+ assert_eq!(super::encode_write(&[0], &mut writer), Ok(()));
+ assert_eq!(writer.0, b"AA\x01");
+ assert_eq!(
+ super::encode_write(&[0, 0, 0], &mut writer),
+ Err(fmt::Error)
+ );
+}