In Part I, I started writing tests and then writing code to make them pass. Let’s continue with more tests.

The next test will be for an incomplete todo with no priority and a completion date.

Sub TEST_NotCompleteNoPriorityCompletionDate()

    Dim clsTodo As CTodo
    
    Set clsTodo = New CTodo
    clsTodo.Raw = "2016-05-20 Call Mom @Phone +Family due:2016-05-30"
    Debug.Assert Not clsTodo.Complete
    Debug.Assert clsTodo.Priority = vbNullString
    Debug.Assert clsTodo.CompleteDate = DateSerial(2016, 5, 20)
    
    Debug.Print "TEST_NotCompleteNoPriorityCompletionDate"

End Sub

Hey, it already passes. Let’s add some tests for when there’s a priority and a completion date

Sub TEST_CompletePriorityCompletionDate()

    Dim clsTodo As CTodo
    
    Set clsTodo = New CTodo
    clsTodo.Raw = "x (A) 2016-05-20 Call Mom @Phone +Family due:2016-05-30"
    Debug.Assert clsTodo.Complete
    Debug.Assert clsTodo.Priority = "A"
    Debug.Assert clsTodo.CompleteDate = DateSerial(2016, 5, 20)
    
    Debug.Print "TEST_CompletePriorityCompletionDate"

End Sub

Sub TEST_NotCompletePriorityCompletionDate()

    Dim clsTodo As CTodo
    
    Set clsTodo = New CTodo
    clsTodo.Raw = "(A) 2016-05-20 Call Mom @Phone +Family due:2016-05-30"
    Debug.Assert Not clsTodo.Complete
    Debug.Assert clsTodo.Priority = "A"
    Debug.Assert clsTodo.CompleteDate = DateSerial(2016, 5, 20)
    
    Debug.Print "TEST_NotCompletePriorityCompletionDate"

End Sub

I expected these would already pass as a result of my refactoring, and they did. The next part of the spec says “Optional Creation Date, must be specified if completion date is”. First, I just want to test that it exists. That is, if there’s a completion date, there must be a creation date.

Sub TEST_CreationDateExists()

    Dim clsTodo As CTodo
    
    Set clsTodo = New CTodo
    clsTodo.Raw = "(A) 2016-05-20 2016-04-30 Call Mom @Phone +Family due:2016-05-30"
    Debug.Assert Not clsTodo.Complete
    Debug.Assert clsTodo.Priority = "A"
    Debug.Assert clsTodo.CompleteDate = DateSerial(2016, 5, 20)
    Debug.Assert clsTodo.CreationDate <> TimeSerial(0, 0, 0)
    
    Set clsTodo = New CTodo
    clsTodo.Raw = "(A) Call Mom @Phone +Family due:2016-05-30"
    Debug.Assert Not clsTodo.Complete
    Debug.Assert clsTodo.Priority = "A"
    Debug.Assert clsTodo.CompleteDate = TimeSerial(0, 0, 0)
    Debug.Assert clsTodo.CreationDate = TimeSerial(0, 0, 0)
    
    Debug.Print "TEST_CreationDateExists"

End Sub

This fails because I haven’t parsed the creation date yet. So let’s do that.

Public Property Let Raw(ByVal sRaw As String)
    
    Dim vaSplit As Variant
    Dim lNext As Long
    
    vaSplit = Split(sRaw, Space(1))
        
    Me.Complete = vaSplit(0) = "x"
            
    If vaSplit(0) = "x" Then
        lNext = lNext + 1
    End If

    If vaSplit(lNext) Like "([A-Z])" Then
        Me.Priority = Mid$(vaSplit(lNext), 2, 1)
        lNext = lNext + 1
    End If

    If IsDate(vaSplit(lNext)) Then
        If IsDate(vaSplit(lNext + 1)) Then
            Me.CompleteDate = DateValue(vaSplit(lNext))
            Me.CreationDate = DateValue(vaSplit(lNext + 1))
            lNext = lNext + 2
        Else
            Me.CreationDate = DateValue(vaSplit(lNext))
            lNext = lNext + 1
        End If
    End If
    
End Property

My test passes, but I broke a previous one. In my prior completion date testing, I didn’t include a creation date because I wasn’t that far in the spec yet. I need to rewrite those tests

ub TEST_CompleteNoPriorityCompletionDate()

    Dim clsTodo As CTodo
    
    Set clsTodo = New CTodo
    clsTodo.Raw = "x 2016-05-20 2016-04-30 Call Mom @Phone +Family due:2016-05-30"
    Debug.Assert clsTodo.Complete
    Debug.Assert clsTodo.Priority = vbNullString
    Debug.Assert clsTodo.CompleteDate = DateSerial(2016, 5, 20)
    
    Debug.Print "TEST_CompleteNoPriorityCompletionDate"

End Sub

Sub TEST_NotCompleteNoPriorityCompletionDate()

    Dim clsTodo As CTodo
    
    Set clsTodo = New CTodo
    clsTodo.Raw = "2016-05-20 2016-04-30 Call Mom @Phone +Family due:2016-05-30"
    Debug.Assert Not clsTodo.Complete
    Debug.Assert clsTodo.Priority = vbNullString
    Debug.Assert clsTodo.CompleteDate = DateSerial(2016, 5, 20)
    
    Debug.Print "TEST_NotCompleteNoPriorityCompletionDate"

End Sub

Sub TEST_CompletePriorityCompletionDate()

    Dim clsTodo As CTodo
    
    Set clsTodo = New CTodo
    clsTodo.Raw = "x (A) 2016-05-20 2016-04-30 Call Mom @Phone +Family due:2016-05-30"
    Debug.Assert clsTodo.Complete
    Debug.Assert clsTodo.Priority = "A"
    Debug.Assert clsTodo.CompleteDate = DateSerial(2016, 5, 20)
    
    Debug.Print "TEST_CompletePriorityCompletionDate"

End Sub

Sub TEST_NotCompletePriorityCompletionDate()

    Dim clsTodo As CTodo
    
    Set clsTodo = New CTodo
    clsTodo.Raw = "(A) 2016-05-20 2016-04-30 Call Mom @Phone +Family due:2016-05-30"
    Debug.Assert Not clsTodo.Complete
    Debug.Assert clsTodo.Priority = "A"
    Debug.Assert clsTodo.CompleteDate = DateSerial(2016, 5, 20)
    
    Debug.Print "TEST_NotCompletePriorityCompletionDate"

End Sub

I added a creation date to the Raw for each of those tests, and now all tests pass. Now I can move on to testing what the creation date actually is.

Sub TEST_CreationDate()

    Dim clsTodo As CTodo
    
    Set clsTodo = New CTodo
    clsTodo.Raw = "(A) 2016-05-20 2016-04-30 Call Mom @Phone +Family due:2016-05-30"
    Debug.Assert Not clsTodo.Complete
    Debug.Assert clsTodo.Priority = "A"
    Debug.Assert clsTodo.CompleteDate = DateSerial(2016, 5, 20)
    Debug.Assert clsTodo.CreationDate = DateSerial(2016, 4, 30)
    
    Set clsTodo = New CTodo
    clsTodo.Raw = "(A) 2016-04-30 Call Mom @Phone +Family due:2016-05-30"
    Debug.Assert Not clsTodo.Complete
    Debug.Assert clsTodo.Priority = "A"
    Debug.Assert clsTodo.CompleteDate = TimeSerial(0, 0, 0)
    Debug.Assert clsTodo.CreationDate = DateSerial(2016, 4, 30)
    
    Debug.Print "TEST_CreationDate"

End Sub

This test already passes. Once I get past the creation date, the rest of the string is called the Description. It can contain projects that start with a plus sign(+) or contexts that start with an at symbol(@) or key/value pairs with a colon(:). We’ll test those in the next part.

You can download TodoTxt.zip

Series:

  1. todo-txt-tdd-part-1/
  2. todo-txt-tdd-part-2/
  3. todo-txt-tdd-part-3/