import XCTest @testable import DuooomiBleSDK final class PlayModeTests: XCTestCase { func testRawValues() { XCTAssertEqual(PlayMode.single.rawValue, 0) XCTAssertEqual(PlayMode.loop.rawValue, 1) } func testInitFromRawValue() { XCTAssertEqual(PlayMode(rawValue: 0), .single) XCTAssertEqual(PlayMode(rawValue: 1), .loop) XCTAssertNil(PlayMode(rawValue: 2)) } func testCodableRoundTrip() throws { let data = try JSONEncoder().encode(PlayMode.loop) XCTAssertEqual(String(data: data, encoding: .utf8), "1") let decoded = try JSONDecoder().decode(PlayMode.self, from: Data("0".utf8)) XCTAssertEqual(decoded, .single) } } final class DeviceInfoLoopTests: XCTestCase { private func decode(_ json: String) throws -> DeviceInfo { try JSONDecoder().decode(DeviceInfo.self, from: Data(json.utf8)) } func testLoopMissingDecodesToNil() throws { let json = #"{"name":"d1","size":"360","brand":"duomi","powerlevel":80,"allspace":1024,"freespace":512}"# let info = try decode(json) XCTAssertNil(info.loop) } func testLoopZeroDecodesToSingle() throws { let json = #"{"name":"d1","size":"360","brand":"duomi","powerlevel":80,"allspace":1024,"freespace":512,"loop":0}"# let info = try decode(json) XCTAssertEqual(info.loop, .single) } func testLoopOneDecodesToLoop() throws { let json = #"{"name":"d1","size":"360","brand":"duomi","powerlevel":80,"allspace":1024,"freespace":512,"loop":1}"# let info = try decode(json) XCTAssertEqual(info.loop, .loop) } func testLoopInvalidValueDecodesToNil() throws { let json = #"{"name":"d1","size":"360","brand":"duomi","powerlevel":80,"allspace":1024,"freespace":512,"loop":7}"# let info = try decode(json) XCTAssertNil(info.loop) } } final class BindPayloadEncodingTests: XCTestCase { private func encode(_ payload: BindPayload) throws -> [String: Any] { let data = try JSONEncoder().encode(payload) return try JSONSerialization.jsonObject(with: data) as? [String: Any] ?? [:] } func testBindPayloadWithoutLoopOmitsKey() throws { let payload = BindPayload(type: 0x0F, userId: "u1", loop: nil) let dict = try encode(payload) XCTAssertEqual(dict["type"] as? Int, 0x0F) XCTAssertEqual(dict["userId"] as? String, "u1") XCTAssertNil(dict["loop"], "loop key MUST be omitted when nil (not encoded as null)") XCTAssertEqual(dict.count, 2) } func testBindPayloadWithLoopIncludesValue() throws { let payload = BindPayload(type: 0x0F, userId: "u1", loop: 1) let dict = try encode(payload) XCTAssertEqual(dict["type"] as? Int, 0x0F) XCTAssertEqual(dict["userId"] as? String, "u1") XCTAssertEqual(dict["loop"] as? Int, 1) XCTAssertEqual(dict.count, 3) } func testBindPayloadWithLoopZeroIncludesValue() throws { let payload = BindPayload(type: 0x0F, userId: "u1", loop: 0) let dict = try encode(payload) XCTAssertEqual(dict["loop"] as? Int, 0) } }