mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-27 15:17:38 +00:00
272 lines
8.1 KiB
Swift
272 lines
8.1 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import VibeTunnel
|
|
|
|
@Suite("Session Model Tests", .tags(.models))
|
|
struct SessionTests {
|
|
@Test("Decodes valid session JSON")
|
|
func decodeValidSession() throws {
|
|
// Arrange
|
|
let json = """
|
|
{
|
|
"id": "test-123",
|
|
"command": "/bin/bash",
|
|
"workingDir": "/Users/test",
|
|
"name": "Test Session",
|
|
"status": "running",
|
|
"startedAt": "2024-01-01T10:00:00Z",
|
|
"lastModified": "2024-01-01T10:05:00Z",
|
|
"pid": 12345,
|
|
"waiting": false,
|
|
"width": 80,
|
|
"height": 24
|
|
}
|
|
"""
|
|
|
|
// Act
|
|
let data = json.data(using: .utf8)!
|
|
let session = try JSONDecoder().decode(Session.self, from: data)
|
|
|
|
// Assert
|
|
#expect(session.id == "test-123")
|
|
#expect(session.command == "/bin/bash")
|
|
#expect(session.workingDir == "/Users/test")
|
|
#expect(session.name == "Test Session")
|
|
#expect(session.status == .running)
|
|
#expect(session.pid == 12_345)
|
|
#expect(session.exitCode == nil)
|
|
#expect(session.isRunning == true)
|
|
#expect(session.width == 80)
|
|
#expect(session.height == 24)
|
|
}
|
|
|
|
@Test("Decodes exited session JSON")
|
|
func decodeExitedSession() throws {
|
|
// Arrange
|
|
let json = """
|
|
{
|
|
"id": "exited-456",
|
|
"command": "/usr/bin/echo",
|
|
"workingDir": "/tmp",
|
|
"name": "Echo Command",
|
|
"status": "exited",
|
|
"exitCode": 0,
|
|
"startedAt": "2024-01-01T09:00:00Z",
|
|
"lastModified": "2024-01-01T09:00:05Z",
|
|
"waiting": false,
|
|
"width": 80,
|
|
"height": 24
|
|
}
|
|
"""
|
|
|
|
// Act
|
|
let data = json.data(using: .utf8)!
|
|
let session = try JSONDecoder().decode(Session.self, from: data)
|
|
|
|
// Assert
|
|
#expect(session.id == "exited-456")
|
|
#expect(session.status == .exited)
|
|
#expect(session.pid == nil)
|
|
#expect(session.exitCode == 0)
|
|
#expect(session.isRunning == false)
|
|
}
|
|
|
|
@Test("Handles optional fields correctly")
|
|
func optionalFields() throws {
|
|
// Arrange - Minimal valid JSON
|
|
let json = """
|
|
{
|
|
"id": "minimal",
|
|
"command": "ls",
|
|
"workingDir": "/",
|
|
"status": "running",
|
|
"startedAt": "2024-01-01T10:00:00Z"
|
|
}
|
|
"""
|
|
|
|
// Act
|
|
let data = json.data(using: .utf8)!
|
|
let session = try JSONDecoder().decode(Session.self, from: data)
|
|
|
|
// Assert
|
|
#expect(session.id == "minimal")
|
|
#expect(session.name == nil)
|
|
#expect(session.pid == nil)
|
|
#expect(session.exitCode == nil)
|
|
#expect(session.lastModified == nil)
|
|
#expect(session.waiting == nil)
|
|
#expect(session.width == nil)
|
|
#expect(session.height == nil)
|
|
}
|
|
|
|
@Test("Computed property isRunning works correctly")
|
|
func isRunningProperty() {
|
|
// Test running session
|
|
let runningSession = TestFixtures.validSession
|
|
#expect(runningSession.isRunning == true)
|
|
#expect(runningSession.status == .running)
|
|
|
|
// Test exited session
|
|
let exitedSession = TestFixtures.exitedSession
|
|
#expect(exitedSession.isRunning == false)
|
|
#expect(exitedSession.status == .exited)
|
|
}
|
|
|
|
@Test("Display name computed property")
|
|
func testDisplayName() {
|
|
// With custom name
|
|
let namedSession = TestFixtures.validSession
|
|
#expect(namedSession.displayName == "Test Session")
|
|
|
|
// Without custom name
|
|
var unnamedSession = TestFixtures.validSession
|
|
unnamedSession = Session(
|
|
id: unnamedSession.id,
|
|
command: unnamedSession.command,
|
|
workingDir: unnamedSession.workingDir,
|
|
name: nil,
|
|
status: unnamedSession.status,
|
|
exitCode: unnamedSession.exitCode,
|
|
startedAt: unnamedSession.startedAt,
|
|
lastModified: unnamedSession.lastModified,
|
|
pid: unnamedSession.pid,
|
|
waiting: unnamedSession.waiting,
|
|
width: unnamedSession.width,
|
|
height: unnamedSession.height
|
|
)
|
|
#expect(unnamedSession.displayName == "/bin/bash")
|
|
}
|
|
|
|
@Test("Formatted start time")
|
|
func testFormattedStartTime() throws {
|
|
// Test ISO8601 format
|
|
let session = TestFixtures.validSession
|
|
let formattedTime = session.formattedStartTime
|
|
|
|
// Should format to a time string (exact format depends on locale)
|
|
#expect(!formattedTime.isEmpty)
|
|
#expect(formattedTime != session.startedAt) // Should be formatted, not raw
|
|
}
|
|
|
|
@Test("Decode array of sessions")
|
|
func decodeSessionArray() throws {
|
|
// Arrange
|
|
let json = TestFixtures.sessionsJSON
|
|
|
|
// Act
|
|
let data = json.data(using: .utf8)!
|
|
let sessions = try JSONDecoder().decode([Session].self, from: data)
|
|
|
|
// Assert
|
|
#expect(sessions.count == 2)
|
|
#expect(sessions[0].id == "test-session-123")
|
|
#expect(sessions[1].id == "exited-session-456")
|
|
#expect(sessions[0].isRunning == true)
|
|
#expect(sessions[1].isRunning == false)
|
|
}
|
|
|
|
@Test("Throws on invalid JSON")
|
|
func invalidJSON() throws {
|
|
// Arrange - Missing required fields
|
|
let json = """
|
|
{
|
|
"id": "invalid",
|
|
"workingDir": "/tmp"
|
|
}
|
|
"""
|
|
|
|
// Act & Assert
|
|
let data = json.data(using: .utf8)!
|
|
#expect(throws: Error.self) {
|
|
try JSONDecoder().decode(Session.self, from: data)
|
|
}
|
|
}
|
|
|
|
@Test("Session equality")
|
|
func sessionEquality() {
|
|
let session1 = TestFixtures.validSession
|
|
var session2 = TestFixtures.validSession
|
|
|
|
// Same ID = equal
|
|
#expect(session1 == session2)
|
|
|
|
// Different ID = not equal
|
|
session2.id = "different-id"
|
|
#expect(session1 != session2)
|
|
}
|
|
|
|
@Test("Session is hashable")
|
|
func sessionHashable() {
|
|
let session1 = TestFixtures.validSession
|
|
let session2 = TestFixtures.exitedSession
|
|
|
|
var set = Set<Session>()
|
|
set.insert(session1)
|
|
set.insert(session2)
|
|
|
|
#expect(set.count == 2)
|
|
#expect(set.contains(session1))
|
|
#expect(set.contains(session2))
|
|
}
|
|
}
|
|
|
|
// MARK: - SessionCreateData Tests
|
|
|
|
@Suite("SessionCreateData Tests", .tags(.models))
|
|
struct SessionCreateDataTests {
|
|
@Test("Encodes to correct JSON")
|
|
func encoding() throws {
|
|
// Arrange
|
|
let data = SessionCreateData(
|
|
command: "/bin/bash",
|
|
workingDir: "/Users/test",
|
|
name: "Test Session",
|
|
cols: 80,
|
|
rows: 24
|
|
)
|
|
|
|
// Act
|
|
let jsonData = try JSONEncoder().encode(data)
|
|
let json = try JSONSerialization.jsonObject(with: jsonData) as? [String: Any]
|
|
|
|
// Assert
|
|
#expect(json?["command"] as? [String] == ["/bin/bash"])
|
|
#expect(json?["workingDir"] as? String == "/Users/test")
|
|
#expect(json?["name"] as? String == "Test Session")
|
|
#expect(json?["cols"] as? Int == 80)
|
|
#expect(json?["rows"] as? Int == 24)
|
|
#expect(json?["spawn_terminal"] as? Bool == false)
|
|
}
|
|
|
|
@Test("Uses default terminal size")
|
|
func defaultTerminalSize() {
|
|
// Arrange & Act
|
|
let data = SessionCreateData(
|
|
command: "ls",
|
|
workingDir: "/tmp"
|
|
)
|
|
|
|
// Assert
|
|
#expect(data.cols == 120) // Default is 120, not 80
|
|
#expect(data.rows == 30) // Default is 30, not 24
|
|
#expect(data.command == ["ls"])
|
|
#expect(data.spawnTerminal == false)
|
|
}
|
|
|
|
@Test("Optional name field")
|
|
func optionalName() throws {
|
|
// Arrange
|
|
let data = SessionCreateData(
|
|
command: "ls",
|
|
workingDir: "/tmp",
|
|
name: nil
|
|
)
|
|
|
|
// Act
|
|
let jsonData = try JSONEncoder().encode(data)
|
|
let json = try JSONSerialization.jsonObject(with: jsonData) as? [String: Any]
|
|
|
|
// Assert
|
|
#expect(json?["name"] == nil)
|
|
}
|
|
}
|