rust/bt-mcs: Fix supporting type definitions

Update type values to match their spec-defined values.

Add remaining PlayingOrder variants that are defined in MCS v1.0.1.

Expand unit test coverage in types.rs to validate all opcode
encodings, decodings, parameter handling, error cases, and bitmasks.

Bug: 540400364
Test: ./presubmit.sh
Change-Id: If0831d7ae030971543515513ba01a04e145d6973
Reviewed-on: https://bluetooth-review.googlesource.com/c/bluetooth/+/3780
diff --git a/rust/bt-mcs/src/types.rs b/rust/bt-mcs/src/types.rs
index ca765f5..cd49de0 100644
--- a/rust/bt-mcs/src/types.rs
+++ b/rust/bt-mcs/src/types.rs
@@ -42,7 +42,7 @@
 /// Media Control Point Opcodes Supported characteristic UUID.
 pub(crate) const MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_UUID: Uuid = Uuid::from_u16(0x2BA5);
 /// Content Control ID (CCID) characteristic UUID.
-pub(crate) const CONTENT_CONTROL_ID_UUID: Uuid = Uuid::from_u16(0x2BA8);
+pub(crate) const CONTENT_CONTROL_ID_UUID: Uuid = Uuid::from_u16(0x2BBA);
 
 decodable_enum! {
     /// State of the media player.
@@ -127,20 +127,28 @@
 }
 
 decodable_enum! {
-    /// Playing order mode for media playback.
+    /// Playing order mode for media playback (MCS v1.0.1 Section 3.15, Table 3.3).
     pub enum PlayingOrder<u8, PacketError, OutOfRange> {
-        /// Play a single track once, then stop.
+        /// A single track is played once; there is no next track.
         SingleOnce = 0x01,
-        /// Play a single track repeatedly.
+        /// A single track is played repeatedly; the next track is the current track.
         SingleRepeat = 0x02,
-        /// Play all tracks in normal sequence once, then stop.
-        Normal = 0x03,
-        /// Play all tracks in normal sequence repeatedly.
-        NormalRepeat = 0x04,
-        /// Play all tracks in shuffled order once, then stop.
-        ShuffleOnce = 0x05,
-        /// Play all tracks in shuffled order repeatedly.
-        ShuffleRepeat = 0x06,
+        /// The tracks within a group are played once in track order.
+        InOrderOnce = 0x03,
+        /// The tracks within a group are played in track order repeatedly.
+        InOrderRepeat = 0x04,
+        /// The tracks within a group are played once only from the oldest first.
+        OldestOnce = 0x05,
+        /// The tracks within a group are played from the oldest first repeatedly.
+        OldestRepeat = 0x06,
+        /// The tracks within a group are played once only from the newest first.
+        NewestOnce = 0x07,
+        /// The tracks within a group are played from the newest first repeatedly.
+        NewestRepeat = 0x08,
+        /// The tracks within a group are played in random order once.
+        ShuffleOnce = 0x09,
+        /// The tracks within a group are played in random order repeatedly.
+        ShuffleRepeat = 0x0A,
     }
 }
 
@@ -172,15 +180,29 @@
 }
 
 bitflags! {
-    /// Bitmask representing supported playing orders (MCS v1.0.1 Section 3.10).
-    #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+    /// Bitmask representing supported playing orders (MCS v1.0.1 Section 3.16, Table 3.4).
+    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
     pub struct SupportedPlayingOrders: u16 {
+        /// A single track is played once; there is no next track.
         const SINGLE_ONCE = 0x0001;
+        /// A single track is played repeatedly; the next track is the current track.
         const SINGLE_REPEAT = 0x0002;
-        const NORMAL = 0x0004;
-        const NORMAL_REPEAT = 0x0008;
-        const SHUFFLE_ONCE = 0x0010;
-        const SHUFFLE_REPEAT = 0x0020;
+        /// The tracks within a group are played once in track order.
+        const IN_ORDER_ONCE = 0x0004;
+        /// The tracks within a group are played in track order repeatedly.
+        const IN_ORDER_REPEAT = 0x0008;
+        /// The tracks within a group are played once only from the oldest first.
+        const OLDEST_ONCE = 0x0010;
+        /// The tracks within a group are played from the oldest first repeatedly.
+        const OLDEST_REPEAT = 0x0020;
+        /// The tracks within a group are played once only from the newest first.
+        const NEWEST_ONCE = 0x0040;
+        /// The tracks within a group are played from the newest first repeatedly.
+        const NEWEST_REPEAT = 0x0080;
+        /// The tracks within a group are played in random order once.
+        const SHUFFLE_ONCE = 0x0100;
+        /// The tracks within a group are played in random order repeatedly.
+        const SHUFFLE_REPEAT = 0x0200;
     }
 }
 
@@ -189,14 +211,24 @@
         match order {
             PlayingOrder::SingleOnce => Self::SINGLE_ONCE,
             PlayingOrder::SingleRepeat => Self::SINGLE_REPEAT,
-            PlayingOrder::Normal => Self::NORMAL,
-            PlayingOrder::NormalRepeat => Self::NORMAL_REPEAT,
+            PlayingOrder::InOrderOnce => Self::IN_ORDER_ONCE,
+            PlayingOrder::InOrderRepeat => Self::IN_ORDER_REPEAT,
+            PlayingOrder::OldestOnce => Self::OLDEST_ONCE,
+            PlayingOrder::OldestRepeat => Self::OLDEST_REPEAT,
+            PlayingOrder::NewestOnce => Self::NEWEST_ONCE,
+            PlayingOrder::NewestRepeat => Self::NEWEST_REPEAT,
             PlayingOrder::ShuffleOnce => Self::SHUFFLE_ONCE,
             PlayingOrder::ShuffleRepeat => Self::SHUFFLE_REPEAT,
         }
     }
 }
 
+impl From<&PlayingOrder> for SupportedPlayingOrders {
+    fn from(order: &PlayingOrder) -> Self {
+        Self::from(*order)
+    }
+}
+
 impl Encodable for SupportedPlayingOrders {
     type Error = PacketError;
 
@@ -225,7 +257,7 @@
     }
 }
 
-/// Media Control Point Opcode.
+/// Media Control Point Opcode (MCS v1.0.1 Section 3.18, Table 3.6).
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum MediaControlOpcode {
     /// Start playing current track.
@@ -238,7 +270,7 @@
     FastForward,
     /// Stop playback.
     Stop,
-    /// Move playback position relative to current position in seconds.
+    /// Move playback position relative to current position by offset.
     MoveRelative(i32),
     /// Jump to previous segment.
     PreviousSegment,
@@ -273,7 +305,7 @@
 }
 
 impl MediaControlOpcode {
-    /// Returns the raw 1-byte opcode value.
+    /// Returns the raw 1-byte opcode value defined in MCS v1.0.1 Table 3.6.
     pub fn raw_opcode(&self) -> u8 {
         match self {
             Self::Play => 0x01,
@@ -281,12 +313,12 @@
             Self::FastRewind => 0x03,
             Self::FastForward => 0x04,
             Self::Stop => 0x05,
-            Self::MoveRelative(_) => 0x20,
-            Self::PreviousSegment => 0x21,
-            Self::NextSegment => 0x22,
-            Self::FirstSegment => 0x23,
-            Self::LastSegment => 0x24,
-            Self::GotoSegment(_) => 0x25,
+            Self::MoveRelative(_) => 0x10,
+            Self::PreviousSegment => 0x20,
+            Self::NextSegment => 0x21,
+            Self::FirstSegment => 0x22,
+            Self::LastSegment => 0x23,
+            Self::GotoSegment(_) => 0x24,
             Self::PreviousTrack => 0x30,
             Self::NextTrack => 0x31,
             Self::FirstTrack => 0x32,
@@ -347,7 +379,7 @@
             0x03 => (Ok(Self::FastRewind), 1),
             0x04 => (Ok(Self::FastForward), 1),
             0x05 => (Ok(Self::Stop), 1),
-            0x20 => {
+            0x10 => {
                 if buf.len() < 5 {
                     (Err(PacketError::UnexpectedDataLength), buf.len())
                 } else {
@@ -355,11 +387,11 @@
                     (Ok(Self::MoveRelative(param)), 5)
                 }
             }
-            0x21 => (Ok(Self::PreviousSegment), 1),
-            0x22 => (Ok(Self::NextSegment), 1),
-            0x23 => (Ok(Self::FirstSegment), 1),
-            0x24 => (Ok(Self::LastSegment), 1),
-            0x25 => {
+            0x20 => (Ok(Self::PreviousSegment), 1),
+            0x21 => (Ok(Self::NextSegment), 1),
+            0x22 => (Ok(Self::FirstSegment), 1),
+            0x23 => (Ok(Self::LastSegment), 1),
+            0x24 => {
                 if buf.len() < 5 {
                     (Err(PacketError::UnexpectedDataLength), buf.len())
                 } else {
@@ -397,8 +429,8 @@
 }
 
 bitflags! {
-    /// Bitmask representing supported Media Control Point opcodes (MCS v1.0.1 Section 3.13).
-    #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+    /// Bitmask representing supported Media Control Point opcodes (MCS v1.0.1 Section 3.19, Table 3.10).
+    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
     pub struct SupportedOpcodes: u32 {
         const PLAY = 0x00000001;
         const PAUSE = 0x00000002;
@@ -491,63 +523,175 @@
     use super::*;
 
     #[test]
-    fn test_media_state_encode_decode() {
-        for &state in MediaState::VARIANTS {
+    fn media_state_encode_decode_success() {
+        let states = [
+            (MediaState::Inactive, 0x00),
+            (MediaState::Playing, 0x01),
+            (MediaState::Paused, 0x02),
+            (MediaState::Seeking, 0x03),
+        ];
+
+        for (state, raw_byte) in states {
+            assert_eq!(u8::from(state), raw_byte);
+            assert_eq!(state.encoded_len(), 1);
+
             let mut buf = [0u8; 1];
             assert!(state.encode(&mut buf).is_ok());
+            assert_eq!(buf[0], raw_byte);
+
             let (decoded, consumed) = MediaState::decode(&buf);
             assert_eq!(consumed, 1);
             assert_eq!(decoded.unwrap(), state);
         }
+    }
 
+    #[test]
+    fn media_state_decode_error() {
         // Test out of range
-        let (err, consumed) = MediaState::decode(&[0xFF]);
-        assert_eq!(consumed, 1);
-        assert_eq!(err.unwrap_err(), PacketError::OutOfRange);
+        for &invalid in &[0x04, 0x05, 0xFF] {
+            let (err, consumed) = MediaState::decode(&[invalid]);
+            assert_eq!(consumed, 1);
+            assert_eq!(err.unwrap_err(), PacketError::OutOfRange);
+        }
 
         // Test empty buffer
         let (err, consumed) = MediaState::decode(&[]);
         assert_eq!(consumed, 0);
         assert_eq!(err.unwrap_err(), PacketError::UnexpectedDataLength);
+
+        // Test buffer too small for encode
+        let mut empty_buf = [0u8; 0];
+        assert_eq!(
+            MediaState::Playing.encode(&mut empty_buf).unwrap_err(),
+            PacketError::BufferTooSmall
+        );
     }
 
     #[test]
-    fn test_control_point_result_code_encode_decode() {
-        for &code in ControlPointResultCode::VARIANTS {
+    fn control_point_result_code_encode_decode_success() {
+        let codes = [
+            (ControlPointResultCode::Success, 0x01),
+            (ControlPointResultCode::OpcodeNotSupported, 0x02),
+            (ControlPointResultCode::MediaPlayerInactive, 0x03),
+            (ControlPointResultCode::CommandCannotBeCompleted, 0x04),
+        ];
+
+        for (code, raw_byte) in codes {
+            assert_eq!(u8::from(code), raw_byte);
+            assert_eq!(code.encoded_len(), 1);
+
             let mut buf = [0u8; 1];
             assert!(code.encode(&mut buf).is_ok());
+            assert_eq!(buf[0], raw_byte);
+
             let (decoded, consumed) = ControlPointResultCode::decode(&buf);
             assert_eq!(consumed, 1);
             assert_eq!(decoded.unwrap(), code);
         }
-
-        // Test out of range
-        let (err, consumed) = ControlPointResultCode::decode(&[0x00]);
-        assert_eq!(consumed, 1);
-        assert_eq!(err.unwrap_err(), PacketError::OutOfRange);
     }
 
     #[test]
-    fn test_playing_order_and_supported_bitmask() {
-        for &order in PlayingOrder::VARIANTS {
+    fn control_point_result_code_decode_error() {
+        // Test out of range
+        for &invalid in &[0x00, 0x05, 0x06, 0xFF] {
+            let (err, consumed) = ControlPointResultCode::decode(&[invalid]);
+            assert_eq!(consumed, 1);
+            assert_eq!(err.unwrap_err(), PacketError::OutOfRange);
+        }
+
+        // Test empty buffer
+        let (err, consumed) = ControlPointResultCode::decode(&[]);
+        assert_eq!(consumed, 0);
+        assert_eq!(err.unwrap_err(), PacketError::UnexpectedDataLength);
+
+        // Test buffer too small for encode
+        let mut empty_buf = [0u8; 0];
+        assert_eq!(
+            ControlPointResultCode::Success.encode(&mut empty_buf).unwrap_err(),
+            PacketError::BufferTooSmall
+        );
+    }
+
+    #[test]
+    fn playing_order_encode_decode_success() {
+        let orders = [
+            (PlayingOrder::SingleOnce, 0x01, SupportedPlayingOrders::SINGLE_ONCE),
+            (PlayingOrder::SingleRepeat, 0x02, SupportedPlayingOrders::SINGLE_REPEAT),
+            (PlayingOrder::InOrderOnce, 0x03, SupportedPlayingOrders::IN_ORDER_ONCE),
+            (PlayingOrder::InOrderRepeat, 0x04, SupportedPlayingOrders::IN_ORDER_REPEAT),
+            (PlayingOrder::OldestOnce, 0x05, SupportedPlayingOrders::OLDEST_ONCE),
+            (PlayingOrder::OldestRepeat, 0x06, SupportedPlayingOrders::OLDEST_REPEAT),
+            (PlayingOrder::NewestOnce, 0x07, SupportedPlayingOrders::NEWEST_ONCE),
+            (PlayingOrder::NewestRepeat, 0x08, SupportedPlayingOrders::NEWEST_REPEAT),
+            (PlayingOrder::ShuffleOnce, 0x09, SupportedPlayingOrders::SHUFFLE_ONCE),
+            (PlayingOrder::ShuffleRepeat, 0x0A, SupportedPlayingOrders::SHUFFLE_REPEAT),
+        ];
+
+        for (order, raw_byte, flag) in orders {
+            assert_eq!(u8::from(order), raw_byte);
+            assert_eq!(order.encoded_len(), 1);
+
             let mut buf = [0u8; 1];
             assert!(order.encode(&mut buf).is_ok());
+            assert_eq!(buf[0], raw_byte);
+
             let (decoded, consumed) = PlayingOrder::decode(&buf);
             assert_eq!(consumed, 1);
             assert_eq!(decoded.unwrap(), order);
+
+            let converted: SupportedPlayingOrders = order.into();
+            assert_eq!(converted, flag);
+            let converted_ref: SupportedPlayingOrders = (&order).into();
+            assert_eq!(converted_ref, flag);
+            assert!(SupportedPlayingOrders::all().contains(order.into()));
+        }
+    }
+
+    #[test]
+    fn playing_order_decode_error() {
+        // Test out of range
+        for &invalid in &[0x00, 0x0B, 0x10, 0xFF] {
+            let (err, consumed) = PlayingOrder::decode(&[invalid]);
+            assert_eq!(consumed, 1);
+            assert_eq!(err.unwrap_err(), PacketError::OutOfRange);
         }
 
+        // Test empty buffer
+        let (err, consumed) = PlayingOrder::decode(&[]);
+        assert_eq!(consumed, 0);
+        assert_eq!(err.unwrap_err(), PacketError::UnexpectedDataLength);
+
+        // Test buffer too small for encode
+        let mut empty_buf = [0u8; 0];
+        assert_eq!(
+            PlayingOrder::InOrderOnce.encode(&mut empty_buf).unwrap_err(),
+            PacketError::BufferTooSmall
+        );
+    }
+
+    #[test]
+    fn supported_playing_orders_bitmask_success() {
+        assert_eq!(SupportedPlayingOrders::all().bits(), 0x03FF);
+
         let supported = SupportedPlayingOrders::SINGLE_ONCE
-            | SupportedPlayingOrders::NORMAL
+            | SupportedPlayingOrders::IN_ORDER_ONCE
+            | SupportedPlayingOrders::OLDEST_ONCE
+            | SupportedPlayingOrders::NEWEST_REPEAT
             | SupportedPlayingOrders::SHUFFLE_REPEAT;
 
         assert!(supported.contains(PlayingOrder::SingleOnce.into()));
-        assert!(supported.contains(PlayingOrder::Normal.into()));
+        assert!(supported.contains(PlayingOrder::InOrderOnce.into()));
+        assert!(supported.contains(PlayingOrder::OldestOnce.into()));
+        assert!(supported.contains(PlayingOrder::NewestRepeat.into()));
         assert!(supported.contains(PlayingOrder::ShuffleRepeat.into()));
+
         assert!(!supported.contains(PlayingOrder::SingleRepeat.into()));
-        assert!(!supported.contains(PlayingOrder::NormalRepeat.into()));
+        assert!(!supported.contains(PlayingOrder::InOrderRepeat.into()));
+        assert!(!supported.contains(PlayingOrder::OldestRepeat.into()));
+        assert!(!supported.contains(PlayingOrder::NewestOnce.into()));
         assert!(!supported.contains(PlayingOrder::ShuffleOnce.into()));
 
+        // Encode and decode SupportedPlayingOrders
         let mut buf = [0u8; 2];
         assert!(supported.encode(&mut buf).is_ok());
         let (decoded, consumed) = SupportedPlayingOrders::decode(&buf);
@@ -556,17 +700,27 @@
     }
 
     #[test]
-    fn test_media_control_opcode_all_non_parameterized() {
+    fn supported_playing_orders_error() {
+        let supported = SupportedPlayingOrders::SINGLE_ONCE;
+        // Buffer too small for SupportedPlayingOrders encode/decode
+        assert_eq!(supported.encode(&mut [0u8; 1]).unwrap_err(), PacketError::BufferTooSmall);
+        let (err, consumed) = SupportedPlayingOrders::decode(&[0x01]);
+        assert_eq!(consumed, 0);
+        assert_eq!(err.unwrap_err(), PacketError::UnexpectedDataLength);
+    }
+
+    #[test]
+    fn media_control_opcode_all_non_parameterized() {
         let opcodes = [
             (MediaControlOpcode::Play, 0x01),
             (MediaControlOpcode::Pause, 0x02),
             (MediaControlOpcode::FastRewind, 0x03),
             (MediaControlOpcode::FastForward, 0x04),
             (MediaControlOpcode::Stop, 0x05),
-            (MediaControlOpcode::PreviousSegment, 0x21),
-            (MediaControlOpcode::NextSegment, 0x22),
-            (MediaControlOpcode::FirstSegment, 0x23),
-            (MediaControlOpcode::LastSegment, 0x24),
+            (MediaControlOpcode::PreviousSegment, 0x20),
+            (MediaControlOpcode::NextSegment, 0x21),
+            (MediaControlOpcode::FirstSegment, 0x22),
+            (MediaControlOpcode::LastSegment, 0x23),
             (MediaControlOpcode::PreviousTrack, 0x30),
             (MediaControlOpcode::NextTrack, 0x31),
             (MediaControlOpcode::FirstTrack, 0x32),
@@ -588,17 +742,28 @@
             let (decoded, consumed) = MediaControlOpcode::decode(&buf);
             assert_eq!(consumed, 1);
             assert_eq!(decoded.unwrap(), opcode);
+
+            // Buffer too small for encode
+            let mut empty = [0u8; 0];
+            assert_eq!(opcode.encode(&mut empty).unwrap_err(), PacketError::BufferTooSmall);
         }
     }
 
     #[test]
-    fn test_media_control_opcode_parameterized() {
+    fn media_control_opcode_parameterized() {
         let test_cases = [
-            (MediaControlOpcode::MoveRelative(10), 0x20, 10i32),
-            (MediaControlOpcode::MoveRelative(-15), 0x20, -15i32),
-            (MediaControlOpcode::GotoSegment(3), 0x25, 3i32),
+            (MediaControlOpcode::MoveRelative(10), 0x10, 10i32),
+            (MediaControlOpcode::MoveRelative(-15), 0x10, -15i32),
+            (MediaControlOpcode::MoveRelative(0), 0x10, 0i32),
+            (MediaControlOpcode::GotoSegment(3), 0x24, 3i32),
+            (MediaControlOpcode::GotoSegment(-1), 0x24, -1i32),
+            (MediaControlOpcode::GotoSegment(0), 0x24, 0i32),
             (MediaControlOpcode::GotoTrack(42), 0x34, 42i32),
+            (MediaControlOpcode::GotoTrack(-5), 0x34, -5i32),
+            (MediaControlOpcode::GotoTrack(0), 0x34, 0i32),
             (MediaControlOpcode::GotoGroup(1), 0x44, 1i32),
+            (MediaControlOpcode::GotoGroup(-2), 0x44, -2i32),
+            (MediaControlOpcode::GotoGroup(0), 0x44, 0i32),
         ];
 
         for (opcode, raw_byte, param) in test_cases {
@@ -613,20 +778,88 @@
             let (decoded, consumed) = MediaControlOpcode::decode(&buf);
             assert_eq!(consumed, 5);
             assert_eq!(decoded.unwrap(), opcode);
+
+            // Buffer too small for encode
+            let mut small = [0u8; 4];
+            assert_eq!(opcode.encode(&mut small).unwrap_err(), PacketError::BufferTooSmall);
         }
     }
 
     #[test]
-    fn test_media_control_opcode_truncated_buffer() {
-        // Opcode 0x20 (MoveRelative) requires 5 bytes, only 3 provided
-        let truncated = [0x20, 0x01, 0x02];
-        let (err, consumed) = MediaControlOpcode::decode(&truncated);
-        assert_eq!(consumed, 3);
+    fn media_control_opcode_truncated_and_invalid_buffers() {
+        // Opcode 0x10 (MoveRelative) requires 5 bytes
+        for len in 1..5 {
+            let buf = vec![0x10, 0x01, 0x02, 0x03];
+            let (err, consumed) = MediaControlOpcode::decode(&buf[..len]);
+            assert_eq!(consumed, len);
+            assert_eq!(err.unwrap_err(), PacketError::UnexpectedDataLength);
+        }
+
+        // Opcode 0x24 (GotoSegment) requires 5 bytes
+        let (err, consumed) = MediaControlOpcode::decode(&[0x24, 0x01]);
+        assert_eq!(consumed, 2);
+        assert_eq!(err.unwrap_err(), PacketError::UnexpectedDataLength);
+
+        // Opcode 0x34 (GotoTrack) requires 5 bytes
+        let (err, consumed) = MediaControlOpcode::decode(&[0x34, 0x01, 0x02, 0x03]);
+        assert_eq!(consumed, 4);
+        assert_eq!(err.unwrap_err(), PacketError::UnexpectedDataLength);
+
+        // Opcode 0x44 (GotoGroup) requires 5 bytes
+        let (err, consumed) = MediaControlOpcode::decode(&[0x44]);
+        assert_eq!(consumed, 1);
+        assert_eq!(err.unwrap_err(), PacketError::UnexpectedDataLength);
+
+        // Invalid / RFU opcodes
+        for &invalid in &[0x00, 0x06, 0x0F, 0x11, 0x1F, 0x25, 0x2F, 0x35, 0x3F, 0x45, 0xFF] {
+            let (err, consumed) = MediaControlOpcode::decode(&[invalid]);
+            assert_eq!(consumed, 1);
+            assert_eq!(err.unwrap_err(), PacketError::OutOfRange);
+        }
+
+        // Empty buffer
+        let (err, consumed) = MediaControlOpcode::decode(&[]);
+        assert_eq!(consumed, 0);
         assert_eq!(err.unwrap_err(), PacketError::UnexpectedDataLength);
     }
 
     #[test]
-    fn test_supported_opcodes_bitmask() {
+    fn supported_opcodes_bitmask_success() {
+        assert_eq!(SupportedOpcodes::all().bits(), 0x001F_FFFF);
+
+        let opcode_flags = [
+            (MediaControlOpcode::Play, SupportedOpcodes::PLAY, 0x00000001),
+            (MediaControlOpcode::Pause, SupportedOpcodes::PAUSE, 0x00000002),
+            (MediaControlOpcode::FastRewind, SupportedOpcodes::FAST_REWIND, 0x00000004),
+            (MediaControlOpcode::FastForward, SupportedOpcodes::FAST_FORWARD, 0x00000008),
+            (MediaControlOpcode::Stop, SupportedOpcodes::STOP, 0x00000010),
+            (MediaControlOpcode::MoveRelative(0), SupportedOpcodes::MOVE_RELATIVE, 0x00000020),
+            (MediaControlOpcode::PreviousSegment, SupportedOpcodes::PREVIOUS_SEGMENT, 0x00000040),
+            (MediaControlOpcode::NextSegment, SupportedOpcodes::NEXT_SEGMENT, 0x00000080),
+            (MediaControlOpcode::FirstSegment, SupportedOpcodes::FIRST_SEGMENT, 0x00000100),
+            (MediaControlOpcode::LastSegment, SupportedOpcodes::LAST_SEGMENT, 0x00000200),
+            (MediaControlOpcode::GotoSegment(0), SupportedOpcodes::GOTO_SEGMENT, 0x00000400),
+            (MediaControlOpcode::PreviousTrack, SupportedOpcodes::PREVIOUS_TRACK, 0x00000800),
+            (MediaControlOpcode::NextTrack, SupportedOpcodes::NEXT_TRACK, 0x00001000),
+            (MediaControlOpcode::FirstTrack, SupportedOpcodes::FIRST_TRACK, 0x00002000),
+            (MediaControlOpcode::LastTrack, SupportedOpcodes::LAST_TRACK, 0x00004000),
+            (MediaControlOpcode::GotoTrack(0), SupportedOpcodes::GOTO_TRACK, 0x00008000),
+            (MediaControlOpcode::PreviousGroup, SupportedOpcodes::PREVIOUS_GROUP, 0x00010000),
+            (MediaControlOpcode::NextGroup, SupportedOpcodes::NEXT_GROUP, 0x00020000),
+            (MediaControlOpcode::FirstGroup, SupportedOpcodes::FIRST_GROUP, 0x00040000),
+            (MediaControlOpcode::LastGroup, SupportedOpcodes::LAST_GROUP, 0x00080000),
+            (MediaControlOpcode::GotoGroup(0), SupportedOpcodes::GOTO_GROUP, 0x00100000),
+        ];
+
+        for (opcode, flag, bits) in opcode_flags {
+            assert_eq!(flag.bits(), bits);
+            let converted: SupportedOpcodes = opcode.into();
+            assert_eq!(converted, flag);
+            let converted_ref: SupportedOpcodes = (&opcode).into();
+            assert_eq!(converted_ref, flag);
+            assert!(SupportedOpcodes::all().contains(flag));
+        }
+
         let supported = SupportedOpcodes::PLAY
             | SupportedOpcodes::PAUSE
             | SupportedOpcodes::MOVE_RELATIVE
@@ -646,4 +879,14 @@
         assert_eq!(consumed, 4);
         assert_eq!(decoded.unwrap(), supported);
     }
+
+    #[test]
+    fn supported_opcodes_error() {
+        let supported = SupportedOpcodes::PLAY;
+        // Buffer too small for SupportedOpcodes encode/decode
+        assert_eq!(supported.encode(&mut [0u8; 3]).unwrap_err(), PacketError::BufferTooSmall);
+        let (err, consumed) = SupportedOpcodes::decode(&[0x01, 0x02, 0x03]);
+        assert_eq!(consumed, 0);
+        assert_eq!(err.unwrap_err(), PacketError::UnexpectedDataLength);
+    }
 }