Skip to main content

bare_types/sys/
kernel_version.rs

1//! Kernel version type for system information.
2//!
3//! This module provides a type-safe abstraction for kernel versions,
4//! ensuring valid version number parsing and comparison.
5//!
6//! Kernel versions typically follow semantic versioning (major.minor.patch)
7//! with an optional release/build string.
8//!
9//! # Examples
10//!
11//! ```rust
12//! use bare_types::sys::KernelVersion;
13//!
14//! // Parse from string
15//! let version: KernelVersion = "6.8.0-40-generic".parse()?;
16//!
17//! // Access components
18//! assert_eq!(version.major(), 6);
19//! assert_eq!(version.minor(), 8);
20//! assert_eq!(version.patch(), 0);
21//!
22//! // Get release string
23//! assert_eq!(version.release(), Some("40-generic"));
24//!
25//! // Compare versions
26//! assert!(version >= KernelVersion::new(6, 0, 0));
27//! # Ok::<(), bare_types::sys::KernelVersionError>(())
28//! ```
29use core::fmt;
30use core::str::FromStr;
31
32#[cfg(feature = "serde")]
33use serde::{Deserialize, Serialize};
34
35/// Error type for kernel version parsing.
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
38#[non_exhaustive]
39pub enum KernelVersionError {
40    /// Empty version string
41    ///
42    /// The provided string is empty. Kernel version strings must contain at least
43    /// major and a minor version number (e.g., "6.8").
44    Empty,
45    /// Invalid major version number
46    ///
47    /// The major version component could not be parsed as a valid u16 number.
48    /// Kernel version numbers must be non-negative integers.
49    InvalidMajor,
50    /// Invalid minor version number
51    ///
52    /// The minor version component could not be parsed as a valid u16 number.
53    /// Kernel version numbers must be non-negative integers.
54    InvalidMinor,
55    /// Invalid patch version number
56    ///
57    /// The patch version component could not be parsed as a valid u16 number.
58    /// Kernel version numbers must be non-negative integers.
59    InvalidPatch,
60    /// Too many numeric components (max 3)
61    ///
62    /// Kernel version strings can have at most 3 numeric components:
63    /// major.minor.patch. More than 3 components are not supported.
64    TooManyComponents,
65    /// Not enough numeric components (need at least 2)
66    ///
67    /// Kernel version strings must contain at least major and minor components.
68    /// Only a patch number (e.g., "6") is not sufficient.
69    NotEnoughComponents,
70    /// Negative version number
71    ///
72    /// Kernel version numbers cannot be negative. This error may occur if parsing
73    /// negative integers in version components.
74    NegativeVersion,
75}
76
77impl fmt::Display for KernelVersionError {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        match self {
80            Self::Empty => write!(f, "kernel version string is empty"),
81            Self::InvalidMajor => write!(f, "invalid major kernel version number"),
82            Self::InvalidMinor => write!(f, "invalid minor kernel version number"),
83            Self::InvalidPatch => write!(f, "invalid patch kernel version number"),
84            Self::TooManyComponents => {
85                write!(f, "kernel version has too many numeric components (max 3)")
86            }
87            Self::NotEnoughComponents => {
88                write!(f, "kernel version needs at least 2 numeric components")
89            }
90            Self::NegativeVersion => write!(f, "kernel version numbers cannot be negative"),
91        }
92    }
93}
94
95#[cfg(feature = "std")]
96impl std::error::Error for KernelVersionError {}
97
98/// Kernel version.
99///
100/// This type provides type-safe kernel version numbers with three numeric
101/// components (major, minor, patch) and an optional release string.
102///
103/// # Format
104///
105/// Kernel version format: `major.minor.patch[-release]`
106///
107/// - **Major**: Major version number (e.g., 6 for Linux 6.x)
108/// - **Minor**: Minor version number (e.g., 8 for Linux 6.8)
109/// - **Patch**: Patch level (e.g., 0 for Linux 6.8.0)
110/// - **Release**: Optional release string (e.g., "40-generic" for Ubuntu)
111///
112/// # Invariants
113///
114/// - Major, minor, and patch versions are always present (u16)
115/// - Release string is optional and must not contain leading '-'
116/// - All version numbers are non-negative
117///
118/// # Examples
119///
120/// ```rust
121/// use bare_types::sys::KernelVersion;
122///
123/// // Create from components
124/// let version = KernelVersion::new(6, 8, 0);
125///
126/// // With release string
127/// let version = KernelVersion::with_release(6, 8, 0, "40-generic");
128///
129/// // Parse from string
130/// let version: KernelVersion = "6.8.0-40-generic".parse()?;
131/// assert_eq!(version.major(), 6);
132/// assert_eq!(version.release(), Some("40-generic"));
133/// # Ok::<(), bare_types::sys::KernelVersionError>(())
134/// ```
135#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
136#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
137pub struct KernelVersion {
138    /// The major version number
139    major: u16,
140    /// The minor version number
141    minor: u16,
142    /// The patch version number
143    patch: u16,
144    /// The optional release/build string
145    release: Option<heapless::String<64>>,
146}
147
148impl KernelVersion {
149    /// Creates a new kernel version from components.
150    ///
151    /// # Arguments
152    ///
153    /// * `major` - The major version number
154    /// * `minor` - The minor version number
155    /// * `patch` - The patch version number
156    ///
157    /// To include a release string, use [`KernelVersion::with_release`].
158    ///
159    /// # Examples
160    ///
161    /// ```rust
162    /// use bare_types::sys::KernelVersion;
163    ///
164    /// // Simple version
165    /// let version = KernelVersion::new(6, 8, 0);
166    /// assert_eq!(version.major(), 6);
167    /// assert_eq!(version.minor(), 8);
168    /// assert_eq!(version.patch(), 0);
169    /// assert_eq!(version.release(), None);
170    ///
171    /// // With release string
172    /// let version = KernelVersion::with_release(6, 8, 0, "40-generic");
173    /// assert_eq!(version.release(), Some("40-generic"));
174    /// ```
175    #[must_use]
176    pub const fn new(major: u16, minor: u16, patch: u16) -> Self {
177        Self {
178            major,
179            minor,
180            patch,
181            release: None,
182        }
183    }
184
185    /// Creates a new kernel version with a release string.
186    ///
187    /// This is a convenience method for creating a kernel version with
188    /// a release/build string. For versions without a release string,
189    /// use [`KernelVersion::new`].
190    ///
191    /// # Examples
192    ///
193    /// ```rust
194    /// use bare_types::sys::KernelVersion;
195    ///
196    /// let version = KernelVersion::with_release(6, 8, 0, "40-generic");
197    /// assert_eq!(version.release(), Some("40-generic"));
198    /// ```
199    #[must_use]
200    pub fn with_release(major: u16, minor: u16, patch: u16, release: &str) -> Self {
201        let mut rel_str: heapless::String<64> = heapless::String::new();
202        // Ignore error, truncation is acceptable for release strings
203        let _ = rel_str.push_str(release);
204
205        Self {
206            major,
207            minor,
208            patch,
209            release: Some(rel_str),
210        }
211    }
212
213    /// Returns the major version number.
214    ///
215    /// # Examples
216    ///
217    /// ```rust
218    /// use bare_types::sys::KernelVersion;
219    ///
220    /// let version = KernelVersion::new(6, 8, 0);
221    /// assert_eq!(version.major(), 6);
222    /// ```
223    #[must_use]
224    #[inline]
225    pub const fn major(&self) -> u16 {
226        self.major
227    }
228
229    /// Returns the minor version number.
230    ///
231    /// # Examples
232    ///
233    /// ```rust
234    /// use bare_types::sys::KernelVersion;
235    ///
236    /// let version = KernelVersion::new(6, 8, 0);
237    /// assert_eq!(version.minor(), 8);
238    /// ```
239    #[must_use]
240    #[inline]
241    pub const fn minor(&self) -> u16 {
242        self.minor
243    }
244
245    /// Returns the patch version number.
246    ///
247    /// # Examples
248    ///
249    /// ```rust
250    /// use bare_types::sys::KernelVersion;
251    ///
252    /// let version = KernelVersion::new(6, 8, 0);
253    /// assert_eq!(version.patch(), 0);
254    /// ```
255    #[must_use]
256    #[inline]
257    pub const fn patch(&self) -> u16 {
258        self.patch
259    }
260
261    /// Returns the optional release string.
262    ///
263    /// # Examples
264    ///
265    /// ```rust
266    /// use bare_types::sys::KernelVersion;
267    ///
268    /// let version = KernelVersion::with_release(6, 8, 0, "40-generic");
269    /// assert_eq!(version.release(), Some("40-generic"));
270    ///
271    /// let version = KernelVersion::new(6, 8, 0);
272    /// assert_eq!(version.release(), None);
273    /// ```
274    #[must_use]
275    #[inline]
276    pub fn release(&self) -> Option<&str> {
277        self.release.as_deref()
278    }
279
280    /// Returns `true` if this is a development/pre-release kernel.
281    ///
282    /// A kernel is considered a development kernel if the minor version
283    /// is odd (Linux convention: odd minor = development, even = stable).
284    ///
285    /// # Examples
286    ///
287    /// ```rust
288    /// use bare_types::sys::KernelVersion;
289    ///
290    /// // Development kernels have odd minor versions
291    /// assert!(KernelVersion::new(6, 7, 0).is_development());
292    ///
293    /// // Stable kernels have even minor versions
294    /// assert!(!KernelVersion::new(6, 8, 0).is_development());
295    /// ```
296    #[must_use]
297    pub const fn is_development(&self) -> bool {
298        // Linux convention: odd minor = development, even = stable
299        self.minor % 2 == 1
300    }
301
302    /// Returns `true` if this is a stable kernel.
303    ///
304    /// A kernel is considered stable if the minor version is even
305    /// (Linux convention).
306    ///
307    /// # Examples
308    ///
309    /// ```rust
310    /// use bare_types::sys::KernelVersion;
311    ///
312    /// assert!(KernelVersion::new(6, 8, 0).is_stable());
313    /// assert!(!KernelVersion::new(6, 7, 0).is_stable());
314    /// ```
315    #[must_use]
316    pub const fn is_stable(&self) -> bool {
317        !self.is_development()
318    }
319
320    /// Returns `true` if this is a long-term support (LTS) kernel.
321    ///
322    /// This checks if the release string contains "lts" (case-insensitive).
323    /// Note: This is a heuristic and may not be accurate for all distros.
324    ///
325    /// # Examples
326    ///
327    /// ```rust
328    /// use bare_types::sys::KernelVersion;
329    ///
330    /// let lts = KernelVersion::with_release(6, 1, 0, "lts");
331    /// assert!(lts.is_lts());
332    ///
333    /// let regular = KernelVersion::new(6, 8, 0);
334    /// assert!(!regular.is_lts());
335    /// ```
336    #[must_use]
337    pub fn is_lts(&self) -> bool {
338        self.release
339            .as_ref()
340            .is_some_and(|r| r.to_lowercase().contains("lts"))
341    }
342
343    /// Returns a tuple of (major, minor, patch) for comparison.
344    ///
345    /// # Examples
346    ///
347    /// ```rust
348    /// use bare_types::sys::KernelVersion;
349    ///
350    /// let version = KernelVersion::new(6, 8, 0);
351    /// assert_eq!(version.as_tuple(), (6, 8, 0));
352    /// ```
353    #[must_use]
354    pub const fn as_tuple(&self) -> (u16, u16, u16) {
355        (self.major, self.minor, self.patch)
356    }
357
358    /// Returns a new version with the patch level incremented.
359    ///
360    /// # Examples
361    ///
362    /// ```rust
363    /// use bare_types::sys::KernelVersion;
364    ///
365    /// let version = KernelVersion::new(6, 8, 0);
366    /// let bumped = version.bump_patch();
367    /// assert_eq!(bumped.patch(), 1);
368    /// ```
369    #[must_use]
370    pub const fn bump_patch(&self) -> Self {
371        Self::new(self.major, self.minor, self.patch.saturating_add(1))
372    }
373
374    /// Returns a new version with the minor version incremented and patch reset.
375    ///
376    /// # Examples
377    ///
378    /// ```rust
379    /// use bare_types::sys::KernelVersion;
380    ///
381    /// let version = KernelVersion::new(6, 8, 5);
382    /// let bumped = version.bump_minor();
383    /// assert_eq!(bumped.minor(), 9);
384    /// assert_eq!(bumped.patch(), 0);
385    /// ```
386    #[must_use]
387    pub const fn bump_minor(&self) -> Self {
388        Self::new(self.major, self.minor.saturating_add(1), 0)
389    }
390
391    /// Returns a new version with the major version incremented and others reset.
392    ///
393    /// # Examples
394    ///
395    /// ```rust
396    /// use bare_types::sys::KernelVersion;
397    ///
398    /// let version = KernelVersion::new(6, 8, 5);
399    /// let bumped = version.bump_major();
400    /// assert_eq!(bumped.major(), 7);
401    /// assert_eq!(bumped.minor(), 0);
402    /// assert_eq!(bumped.patch(), 0);
403    /// ```
404    #[must_use]
405    pub const fn bump_major(&self) -> Self {
406        Self::new(self.major.saturating_add(1), 0, 0)
407    }
408
409    /// Returns a version without the release string.
410    ///
411    /// # Examples
412    ///
413    /// ```rust
414    /// use bare_types::sys::KernelVersion;
415    ///
416    /// let version = KernelVersion::with_release(6, 8, 0, "40-generic");
417    /// let without = version.without_release();
418    /// assert_eq!(without.release(), None);
419    /// assert_eq!(without.major(), 6);
420    /// ```
421    #[must_use]
422    pub const fn without_release(&self) -> Self {
423        Self::new(self.major, self.minor, self.patch)
424    }
425}
426
427impl FromStr for KernelVersion {
428    type Err = KernelVersionError;
429
430    fn from_str(s: &str) -> Result<Self, Self::Err> {
431        if s.is_empty() {
432            return Err(KernelVersionError::Empty);
433        }
434
435        // Split on '-' to separate version from release
436        let (version_part, release_part) = s
437            .find('-')
438            .map_or((s, None), |idx| (&s[..idx], Some(&s[idx + 1..])));
439
440        let parts: Vec<&str> = version_part.split('.').collect();
441
442        if parts.len() > 3 {
443            return Err(KernelVersionError::TooManyComponents);
444        }
445
446        if parts.len() < 2 {
447            return Err(KernelVersionError::NotEnoughComponents);
448        }
449
450        let major = parts[0]
451            .parse::<u16>()
452            .map_err(|_| KernelVersionError::InvalidMajor)?;
453
454        let minor = parts[1]
455            .parse::<u16>()
456            .map_err(|_| KernelVersionError::InvalidMinor)?;
457
458        let patch = if parts.len() > 2 {
459            parts[2]
460                .parse::<u16>()
461                .map_err(|_| KernelVersionError::InvalidPatch)?
462        } else {
463            0
464        };
465
466        let release = release_part.map(|r| {
467            let mut rel_str: heapless::String<64> = heapless::String::new();
468            // Truncate if necessary, ignoring errors
469            let _ = rel_str.push_str(r);
470            rel_str
471        });
472
473        Ok(Self {
474            major,
475            minor,
476            patch,
477            release,
478        })
479    }
480}
481
482impl TryFrom<&str> for KernelVersion {
483    type Error = KernelVersionError;
484
485    fn try_from(s: &str) -> Result<Self, Self::Error> {
486        s.parse()
487    }
488}
489
490impl fmt::Display for KernelVersion {
491    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
492        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)?;
493        if let Some(release) = &self.release {
494            write!(f, "-{release}")?;
495        }
496        Ok(())
497    }
498}
499
500#[cfg(feature = "arbitrary")]
501impl<'a> arbitrary::Arbitrary<'a> for KernelVersion {
502    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
503        let major = u16::arbitrary(u)?;
504        let minor = u16::arbitrary(u)?;
505        let patch = u16::arbitrary(u)?;
506        let has_release = bool::arbitrary(u)?;
507
508        let release = if has_release {
509            // Generate a limited release string to avoid excessive allocations
510            let len = u.int_in_range(0..=32usize)?;
511            let mut s: heapless::String<64> = heapless::String::new();
512            for _ in 0..len {
513                let ch: char = char::arbitrary(u)?;
514                if ch.is_ascii_alphanumeric() || ch == '-' || ch == '.' || ch == '_' {
515                    let _ = s.push(ch);
516                }
517            }
518            Some(s)
519        } else {
520            None
521        };
522
523        Ok(Self {
524            major,
525            minor,
526            patch,
527            release,
528        })
529    }
530}
531
532#[cfg(test)]
533mod tests {
534    use super::*;
535
536    #[test]
537    fn test_new() {
538        let version = KernelVersion::new(6, 8, 0);
539        assert_eq!(version.major(), 6);
540        assert_eq!(version.minor(), 8);
541        assert_eq!(version.patch(), 0);
542        assert_eq!(version.release(), None);
543    }
544
545    #[test]
546    fn test_with_release() {
547        let version = KernelVersion::with_release(6, 8, 0, "40-generic");
548        assert_eq!(version.major(), 6);
549        assert_eq!(version.minor(), 8);
550        assert_eq!(version.patch(), 0);
551        assert_eq!(version.release(), Some("40-generic"));
552    }
553
554    #[test]
555    fn test_is_development() {
556        // Odd minor = development
557        assert!(KernelVersion::new(6, 7, 0).is_development());
558        assert!(KernelVersion::new(6, 9, 0).is_development());
559
560        // Even minor = stable
561        assert!(!KernelVersion::new(6, 8, 0).is_development());
562        assert!(!KernelVersion::new(6, 10, 0).is_development());
563    }
564
565    #[test]
566    fn test_is_stable() {
567        assert!(KernelVersion::new(6, 8, 0).is_stable());
568        assert!(!KernelVersion::new(6, 7, 0).is_stable());
569    }
570
571    #[test]
572    fn test_is_lts() {
573        let lts = KernelVersion::with_release(6, 1, 0, "lts");
574        assert!(lts.is_lts());
575
576        let lts_upper = KernelVersion::with_release(6, 1, 0, "LTS");
577        assert!(lts_upper.is_lts());
578
579        let regular = KernelVersion::new(6, 8, 0);
580        assert!(!regular.is_lts());
581
582        let generic = KernelVersion::with_release(6, 8, 0, "40-generic");
583        assert!(!generic.is_lts());
584    }
585
586    #[test]
587    fn test_as_tuple() {
588        let version = KernelVersion::new(6, 8, 5);
589        assert_eq!(version.as_tuple(), (6, 8, 5));
590    }
591
592    #[test]
593    fn test_bump_patch() {
594        let version = KernelVersion::new(6, 8, 0);
595        let bumped = version.bump_patch();
596        assert_eq!(bumped.patch(), 1);
597        assert_eq!(bumped.major(), 6);
598        assert_eq!(bumped.minor(), 8);
599    }
600
601    #[test]
602    fn test_bump_minor() {
603        let version = KernelVersion::new(6, 8, 5);
604        let bumped = version.bump_minor();
605        assert_eq!(bumped.major(), 6);
606        assert_eq!(bumped.minor(), 9);
607        assert_eq!(bumped.patch(), 0);
608    }
609
610    #[test]
611    fn test_bump_major() {
612        let version = KernelVersion::new(6, 8, 5);
613        let bumped = version.bump_major();
614        assert_eq!(bumped.major(), 7);
615        assert_eq!(bumped.minor(), 0);
616        assert_eq!(bumped.patch(), 0);
617    }
618
619    #[test]
620    fn test_without_release() {
621        let version = KernelVersion::with_release(6, 8, 0, "40-generic");
622        let without = version.without_release();
623        assert_eq!(without.release(), None);
624        assert_eq!(without.major(), 6);
625        assert_eq!(without.minor(), 8);
626        assert_eq!(without.patch(), 0);
627    }
628
629    #[test]
630    fn test_from_str_simple() {
631        let version: KernelVersion = "6.8.0".parse().unwrap();
632        assert_eq!(version.major(), 6);
633        assert_eq!(version.minor(), 8);
634        assert_eq!(version.patch(), 0);
635        assert_eq!(version.release(), None);
636    }
637
638    #[test]
639    fn test_from_str_with_release() {
640        let version: KernelVersion = "6.8.0-40-generic".parse().unwrap();
641        assert_eq!(version.major(), 6);
642        assert_eq!(version.minor(), 8);
643        assert_eq!(version.patch(), 0);
644        assert_eq!(version.release(), Some("40-generic"));
645    }
646
647    #[test]
648    fn test_from_str_two_components() {
649        let version: KernelVersion = "6.8".parse().unwrap();
650        assert_eq!(version.major(), 6);
651        assert_eq!(version.minor(), 8);
652        assert_eq!(version.patch(), 0);
653    }
654
655    #[test]
656    fn test_from_str_long_release() {
657        let version: KernelVersion = "5.15.0-1052-aws".parse().unwrap();
658        assert_eq!(version.major(), 5);
659        assert_eq!(version.minor(), 15);
660        assert_eq!(version.patch(), 0);
661        assert_eq!(version.release(), Some("1052-aws"));
662    }
663
664    #[test]
665    fn test_from_str_errors() {
666        // Empty
667        assert!(matches!(
668            "".parse::<KernelVersion>(),
669            Err(KernelVersionError::Empty)
670        ));
671
672        // Too many numeric components
673        assert!(matches!(
674            "1.2.3.4".parse::<KernelVersion>(),
675            Err(KernelVersionError::TooManyComponents)
676        ));
677
678        // Not enough components
679        assert!(matches!(
680            "6".parse::<KernelVersion>(),
681            Err(KernelVersionError::NotEnoughComponents)
682        ));
683
684        // Invalid numbers
685        assert!("abc.def".parse::<KernelVersion>().is_err());
686        assert!("6.abc".parse::<KernelVersion>().is_err());
687        assert!("6.8.abc".parse::<KernelVersion>().is_err());
688    }
689
690    #[test]
691    fn test_display() {
692        let version = KernelVersion::new(6, 8, 0);
693        assert_eq!(format!("{}", version), "6.8.0");
694
695        let version = KernelVersion::with_release(6, 8, 0, "40-generic");
696        assert_eq!(format!("{}", version), "6.8.0-40-generic");
697    }
698
699    #[test]
700    fn test_equality() {
701        let v1 = KernelVersion::new(6, 8, 0);
702        let v2 = KernelVersion::new(6, 8, 0);
703        let v3 = KernelVersion::with_release(6, 8, 0, "40-generic");
704
705        assert_eq!(v1, v2);
706        assert_ne!(v1, v3);
707    }
708
709    #[test]
710    fn test_ordering() {
711        let v1 = KernelVersion::new(6, 8, 0);
712        let v2 = KernelVersion::new(6, 8, 1);
713        let v3 = KernelVersion::new(6, 9, 0);
714        let v4 = KernelVersion::new(7, 0, 0);
715
716        assert!(v1 < v2);
717        assert!(v2 < v3);
718        assert!(v3 < v4);
719
720        // Release string affects ordering because KernelVersion derives PartialOrd
721        // Two versions with different release strings are not equal
722        let with_release = KernelVersion::with_release(6, 8, 0, "40-generic");
723        let without_release = KernelVersion::new(6, 8, 0);
724        // Version numbers are the same, but release strings differ
725        assert_ne!(with_release, without_release);
726    }
727
728    #[test]
729    fn test_clone() {
730        let version = KernelVersion::with_release(6, 8, 0, "40-generic");
731        let version2 = version.clone();
732        assert_eq!(version, version2);
733    }
734
735    #[test]
736    fn test_common_kernel_versions() {
737        // Linux kernel versions
738        let linux_6_8: KernelVersion = "6.8.0".parse().unwrap();
739        assert_eq!(linux_6_8.major(), 6);
740        assert!(linux_6_8.is_stable());
741
742        let linux_5_15: KernelVersion = "5.15.0".parse().unwrap();
743        assert_eq!(linux_5_15.major(), 5);
744
745        // Ubuntu kernel
746        let ubuntu: KernelVersion = "6.8.0-40-generic".parse().unwrap();
747        assert_eq!(ubuntu.major(), 6);
748        assert_eq!(ubuntu.release(), Some("40-generic"));
749
750        // AWS kernel
751        let aws: KernelVersion = "5.15.0-1052-aws".parse().unwrap();
752        assert_eq!(aws.major(), 5);
753        assert_eq!(aws.release(), Some("1052-aws"));
754    }
755}