import Foundation import Testing @testable import Todos @Suite("NewTaskView view model tests") struct NewTaskViewModelTests { // MARK: Initialization tests @Test("View model initializes with default values") func initialization() { // GIVEN // WHEN let viewModel = NewTaskView.ViewModel() // THEN #expect(viewModel.title == "") #expect(viewModel.note == "") #expect(viewModel.due.timeIntervalSinceNow < 1.0) } // MARK: Properties tests @Test("due property can be modified") func dueModifications() { // GIVEN let dateInsert = Date(timeIntervalSince1970: 1000000000) let dateUpdate = Date(timeIntervalSince1970: 2000000000) // WHEN let viewModel = NewTaskView.ViewModel() // THEN viewModel.due = dateInsert #expect(viewModel.due == dateInsert) viewModel.due = dateUpdate #expect(viewModel.due == dateUpdate) } @Test("note property can be modified") func noteModifications() { // GIVEN let noteInsert = "Initial note" let noteUpdate = "Updated note" // WHEN let viewModel = NewTaskView.ViewModel() // THEN viewModel.note = noteInsert #expect(viewModel.note == noteInsert) viewModel.note = noteUpdate #expect(viewModel.note == noteUpdate) } @Test("title property can be modified") func titleModifications() { // GIVEN let titleInsert = "Initial title" let titleUpdate = "Updated title" // WHEN let viewModel = NewTaskView.ViewModel() // THEN viewModel.title = titleInsert #expect(viewModel.title == titleInsert) viewModel.title = titleUpdate #expect(viewModel.title == titleUpdate) } // MARK: Computed tests @Test( "canConfirm property validation", arguments: zip( ["", "Some title goes here...", " "], [false, true, false] ) ) func canConfirm( with title: String, expects expectation: Bool ) { // GIVEN let viewModel = NewTaskView.ViewModel() // WHEN viewModel.title = title // THEN #expect(viewModel.canConfirm == expectation) } @Test("canConfirm updates when title changes") func canConfirmWithTitleChanges() { // GIVEN let titleEmpty = "" let titleFilled = "New task" let titleTrimmed = " " // WHEN let viewModel = NewTaskView.ViewModel() // THEN viewModel.title = titleEmpty #expect(viewModel.canConfirm == false) viewModel.title = titleFilled #expect(viewModel.canConfirm == true) viewModel.title = titleTrimmed #expect(viewModel.canConfirm == false) } // MARK: Functions tests @Test("save creates todo with all properties") func saveWithAllProperties() throws { // GIVEN let repository = MockTodoRepository() let viewModel = NewTaskView.ViewModel() // WHEN viewModel.title = "Complete project" viewModel.note = "Finish by end of week" viewModel.due = Date(timeIntervalSince1970: 1000000000) viewModel.save(to: repository) // THEN let todo = try #require(repository.todos.first) #expect(todo.title == viewModel.title) #expect(todo.note == viewModel.note) #expect(todo.due == viewModel.due) #expect(todo.completed == nil) } @Test("save creates todo without note when note is empty") func saveWithEmptyNote() throws { // GIVEN let repository = MockTodoRepository() let viewModel = NewTaskView.ViewModel() // WHEN viewModel.title = "Task without note" viewModel.note = "" viewModel.due = Date() viewModel.save(to: repository) // THEN let todo = try #require(repository.todos.first) #expect(todo.title == viewModel.title) #expect(todo.note == nil) #expect(todo.due == viewModel.due) #expect(todo.completed == nil) } @Test("save creates todo with note containing only whitespace as nil") func saveWithWhitespaceNote() throws { // GIVEN let repository = MockTodoRepository() let viewModel = NewTaskView.ViewModel() // WHEN viewModel.title = "Task with whitespace note" viewModel.note = " " viewModel.due = Date() viewModel.save(to: repository) // THEN let todo = try #require(repository.todos.first) #expect(todo.title == viewModel.title) #expect(todo.note == nil) #expect(todo.due == viewModel.due) #expect(todo.completed == nil) } @Test("save inserts multiple todos independently") func saveMultipleTodos() { // GIVEN let repository = MockTodoRepository() let viewModelFirst = NewTaskView.ViewModel() let viewModelSecond = NewTaskView.ViewModel() // WHEN viewModelFirst.title = "First task" viewModelFirst.save(to: repository) viewModelSecond.title = "Second task" viewModelSecond.note = "With a note" viewModelSecond.save(to: repository) // THEN #expect(repository.todos.count == 2) #expect(repository.todos.contains { $0.title == "First task" }) #expect(repository.todos.contains { $0.title == "Second task" }) } }