144 144 | scheme_id: Cow<'static, str>,
|
145 145 | }
|
146 146 |
|
147 147 | // See: https://doc.rust-lang.org/std/convert/trait.AsRef.html#reflexivity
|
148 148 | impl AsRef<AuthSchemeId> for AuthSchemeId {
|
149 149 | fn as_ref(&self) -> &AuthSchemeId {
|
150 150 | self
|
151 151 | }
|
152 152 | }
|
153 153 |
|
154 + | // Normalizes auth scheme IDs for comparison and hashing by treating "no_auth" and "noAuth" as equivalent
|
155 + | // by converting "no_auth" to "noAuth".
|
156 + | // This is for backward compatibility; "no_auth" was incorrectly used in earlier GA versions of the SDK and
|
157 + | // could be used still in some places.
|
158 + | const fn normalize_auth_scheme_id(s: &'static str) -> &'static str {
|
159 + | match s.as_bytes() {
|
160 + | b"no_auth" => "noAuth",
|
161 + | _ => s,
|
162 + | }
|
163 + | }
|
164 + |
|
154 165 | impl AuthSchemeId {
|
155 166 | /// Creates a new auth scheme ID.
|
156 167 | pub const fn new(scheme_id: &'static str) -> Self {
|
157 168 | Self {
|
158 - | scheme_id: Cow::Borrowed(scheme_id),
|
169 + | scheme_id: Cow::Borrowed(normalize_auth_scheme_id(scheme_id)),
|
159 170 | }
|
160 171 | }
|
161 172 |
|
162 173 | /// Returns the string equivalent of this auth scheme ID.
|
163 174 | #[deprecated(
|
164 175 | note = "This function is no longer functional. Use `inner` instead",
|
165 176 | since = "1.8.0"
|
166 177 | )]
|
167 178 | pub const fn as_str(&self) -> &'static str {
|
168 179 | match self.scheme_id {
|
169 180 | Cow::Borrowed(val) => val,
|
170 181 | Cow::Owned(_) => {
|
171 182 | // cannot obtain `&'static str` from `String` unless we use `Box::leak`
|
172 183 | ""
|
173 184 | }
|
174 185 | }
|
175 186 | }
|
176 187 |
|
177 188 | /// Returns the string equivalent of this auth scheme ID.
|
178 189 | pub fn inner(&self) -> &str {
|
179 190 | &self.scheme_id
|
180 191 | }
|
181 192 | }
|
182 193 |
|
183 194 | impl From<&'static str> for AuthSchemeId {
|
184 195 | fn from(scheme_id: &'static str) -> Self {
|
185 196 | Self::new(scheme_id)
|
186 197 | }
|
187 198 | }
|
188 199 |
|
189 200 | impl From<Cow<'static, str>> for AuthSchemeId {
|
190 201 | fn from(scheme_id: Cow<'static, str>) -> Self {
|
191 - | Self { scheme_id }
|
202 + | let normalized_scheme_id = match &scheme_id {
|
203 + | Cow::Borrowed(s) => Cow::Borrowed(normalize_auth_scheme_id(s)),
|
204 + | Cow::Owned(s) => {
|
205 + | if s == "no_auth" {
|
206 + | Cow::Borrowed("noAuth")
|
207 + | } else {
|
208 + | scheme_id
|
209 + | }
|
210 + | }
|
211 + | };
|
212 + | Self {
|
213 + | scheme_id: normalized_scheme_id,
|
214 + | }
|
192 215 | }
|
193 216 | }
|
194 217 |
|
195 218 | /// Parameters needed to resolve auth scheme options.
|
196 219 | ///
|
197 220 | /// Most generated clients will use the [`StaticAuthSchemeOptionResolver`](static_resolver::StaticAuthSchemeOptionResolver),
|
198 221 | /// which doesn't require any parameters for resolution (and has its own empty params struct).
|
199 222 | ///
|
200 223 | /// However, more complex auth scheme resolvers may need modeled parameters in order to resolve
|
201 224 | /// the auth scheme options. For those, this params struct holds a type erased box so that any
|
447 470 | impl<T> From<T> for AuthSchemePreference
|
448 471 | where
|
449 472 | T: AsRef<[AuthSchemeId]>,
|
450 473 | {
|
451 474 | fn from(slice: T) -> Self {
|
452 475 | AuthSchemePreference {
|
453 476 | preference_list: slice.as_ref().to_vec(),
|
454 477 | }
|
455 478 | }
|
456 479 | }
|
480 + |
|
481 + | #[cfg(test)]
|
482 + | mod tests {
|
483 + | use super::*;
|
484 + |
|
485 + | #[test]
|
486 + | fn test_auth_scheme_id_new_normalizes_no_auth() {
|
487 + | // Test that "no_auth" gets normalized to "noAuth"
|
488 + | let auth_scheme_id = AuthSchemeId::new("no_auth");
|
489 + | assert_eq!(auth_scheme_id.inner(), "noAuth");
|
490 + | }
|
491 + |
|
492 + | #[test]
|
493 + | fn test_auth_scheme_id_new_preserves_no_auth_camel_case() {
|
494 + | // Test that "noAuth" remains unchanged
|
495 + | let auth_scheme_id = AuthSchemeId::new("noAuth");
|
496 + | assert_eq!(auth_scheme_id.inner(), "noAuth");
|
497 + | }
|
498 + |
|
499 + | #[test]
|
500 + | fn test_auth_scheme_id_new_preserves_other_schemes() {
|
501 + | // Test that other auth scheme IDs are not modified
|
502 + | let test_cases = [
|
503 + | "sigv4",
|
504 + | "sigv4a",
|
505 + | "httpBearerAuth",
|
506 + | "httpBasicAuth",
|
507 + | "custom_auth",
|
508 + | "bearer",
|
509 + | "basic",
|
510 + | ];
|
511 + |
|
512 + | for scheme in test_cases {
|
513 + | let auth_scheme_id = AuthSchemeId::new(scheme);
|
514 + | assert_eq!(auth_scheme_id.inner(), scheme);
|
515 + | }
|
516 + | }
|
517 + |
|
518 + | #[test]
|
519 + | fn test_auth_scheme_id_equality_after_normalization() {
|
520 + | // Test that "no_auth" and "noAuth" are considered equal after normalization
|
521 + | let no_auth_underscore = AuthSchemeId::new("no_auth");
|
522 + | let no_auth_camel = AuthSchemeId::new("noAuth");
|
523 + |
|
524 + | assert_eq!(no_auth_underscore, no_auth_camel);
|
525 + | assert_eq!(no_auth_underscore.inner(), no_auth_camel.inner());
|
526 + | }
|
527 + |
|
528 + | #[test]
|
529 + | fn test_auth_scheme_id_hash_consistency_after_normalization() {
|
530 + | use std::collections::HashMap;
|
531 + |
|
532 + | // Test that normalized IDs have consistent hashing behavior
|
533 + | let mut map = HashMap::new();
|
534 + | let no_auth_underscore = AuthSchemeId::new("no_auth");
|
535 + | let no_auth_camel = AuthSchemeId::new("noAuth");
|
536 + |
|
537 + | map.insert(no_auth_underscore.clone(), "value1");
|
538 + | map.insert(no_auth_camel.clone(), "value2");
|
539 + |
|
540 + | // Should only have one entry since they normalize to the same value
|
541 + | assert_eq!(map.len(), 1);
|
542 + | assert_eq!(map.get(&no_auth_underscore), Some(&"value2"));
|
543 + | assert_eq!(map.get(&no_auth_camel), Some(&"value2"));
|
544 + | }
|
545 + |
|
546 + | #[test]
|
547 + | fn test_auth_scheme_id_ordering_after_normalization() {
|
548 + | // Test that ordering works correctly with normalized values
|
549 + | let no_auth_underscore = AuthSchemeId::new("no_auth");
|
550 + | let no_auth_camel = AuthSchemeId::new("noAuth");
|
551 + | let other_scheme = AuthSchemeId::new("sigv4");
|
552 + |
|
553 + | assert_eq!(
|
554 + | no_auth_underscore.cmp(&no_auth_camel),
|
555 + | std::cmp::Ordering::Equal
|
556 + | );
|
557 + | assert_eq!(no_auth_underscore.cmp(&other_scheme), "noAuth".cmp("sigv4"));
|
558 + | }
|
559 + |
|
560 + | #[test]
|
561 + | fn test_normalize_auth_scheme_id_function() {
|
562 + | // Test the normalize function directly
|
563 + | assert_eq!(normalize_auth_scheme_id("no_auth"), "noAuth");
|
564 + | assert_eq!(normalize_auth_scheme_id("noAuth"), "noAuth");
|
565 + | assert_eq!(normalize_auth_scheme_id("sigv4"), "sigv4");
|
566 + | assert_eq!(normalize_auth_scheme_id("custom"), "custom");
|
567 + | }
|
568 + |
|
569 + | #[test]
|
570 + | fn test_auth_scheme_id_from_cow_borrowed_normalizes_no_auth() {
|
571 + | // Test that Cow::Borrowed("no_auth") gets normalized to "noAuth"
|
572 + | let auth_scheme_id = AuthSchemeId::from(Cow::Borrowed("no_auth"));
|
573 + | assert_eq!(auth_scheme_id.inner(), "noAuth");
|
574 + | }
|
575 + |
|
576 + | #[test]
|
577 + | fn test_auth_scheme_id_from_cow_borrowed_preserves_no_auth_camel_case() {
|
578 + | // Test that Cow::Borrowed("noAuth") remains unchanged
|
579 + | let auth_scheme_id = AuthSchemeId::from(Cow::Borrowed("noAuth"));
|
580 + | assert_eq!(auth_scheme_id.inner(), "noAuth");
|
581 + | }
|
582 + |
|
583 + | #[test]
|
584 + | fn test_auth_scheme_id_from_cow_owned_normalizes_no_auth() {
|
585 + | // Test that Cow::Owned(String::from("no_auth")) gets normalized to "noAuth"
|
586 + | let auth_scheme_id = AuthSchemeId::from(Cow::Owned(String::from("no_auth")));
|
587 + | assert_eq!(auth_scheme_id.inner(), "noAuth");
|
588 + | }
|
589 + |
|
590 + | #[test]
|
591 + | fn test_auth_scheme_id_from_cow_owned_preserves_no_auth_camel_case() {
|
592 + | // Test that Cow::Owned(String::from("noAuth")) remains unchanged
|
593 + | let auth_scheme_id = AuthSchemeId::from(Cow::Owned(String::from("noAuth")));
|
594 + | assert_eq!(auth_scheme_id.inner(), "noAuth");
|
595 + | }
|
596 + |
|
597 + | #[test]
|
598 + | fn test_auth_scheme_id_from_cow_between_borrowed_and_owned_mixing_updated_and_legacy() {
|
599 + | let borrowed_no_auth = AuthSchemeId::from(Cow::Borrowed("noAuth"));
|
600 + | let owned_no_auth = AuthSchemeId::from(Cow::Owned(String::from("no_auth")));
|
601 + |
|
602 + | assert_eq!(borrowed_no_auth, owned_no_auth);
|
603 + | assert_eq!(borrowed_no_auth.inner(), owned_no_auth.inner());
|
604 + | }
|
605 + | }
|