From b9c2b33681e480071aa685c157b456bf5990ef41 Mon Sep 17 00:00:00 2001 From: Steve Brokenshire Date: Sun, 13 Dec 2015 15:06:35 +0000 Subject: [PATCH] Added code and unit tests for BDAY and ANNIVERSARY in the ContactDataObject. --- source/contacteditor/ContactDataObject.cpp | 358 +++++++++++++++++++++ source/contacteditor/ContactDataObject.h | 3 + source/tests/LoadCheck-Load4.vcf | 3 + source/tests/xestiaab_contactload.h | 115 ++++++- 4 files changed, 478 insertions(+), 1 deletion(-) diff --git a/source/contacteditor/ContactDataObject.cpp b/source/contacteditor/ContactDataObject.cpp index 7ff2d76..5275553 100644 --- a/source/contacteditor/ContactDataObject.cpp +++ b/source/contacteditor/ContactDataObject.cpp @@ -75,6 +75,9 @@ ContactLoadStatus ContactDataObject::LoadFile(wxString Filename){ bool PropertyFind = TRUE; bool KindProcessed = FALSE; bool NameProcessed = FALSE; + bool GenderProcessed = FALSE; + bool BirthdayProcessed = FALSE; + bool AnniversaryProcessed = FALSE; int ContactLineLen = 0; int QuoteBreakPoint = 0; int GroupCount = 0; @@ -202,6 +205,21 @@ ContactLoadStatus ContactDataObject::LoadFile(wxString Filename){ ProcessNickname(PropertySeg1, PropertySeg2, &NicknameCount); NicknameCount++; + } else if (Property == wxT("GENDER") && GenderProcessed == FALSE){ + + ProcessGender(PropertySeg1, PropertySeg2); + GenderProcessed = TRUE; + + } else if (Property == wxT("BDAY") && BirthdayProcessed == FALSE){ + + ProcessBirthday(PropertySeg1, PropertySeg2); + BirthdayProcessed = TRUE; + + } else if (Property == wxT("ANNIVERSARY") && AnniversaryProcessed == FALSE){ + + ProcessAnniversary(PropertySeg1, PropertySeg2); + AnniversaryProcessed = TRUE; + } } @@ -746,6 +764,346 @@ void ContactDataObject::ProcessNickname(wxString PropertySeg1, wxString Property } +void ContactDataObject::ProcessGender(wxString PropertySeg1, wxString PropertySeg2){ + + std::map SplitPoints; + std::map SplitLength; + std::map::iterator SLiter; + wxString PropertyData; + wxString PropertyName; + wxString PropertyValue; + wxString PropertyTokens; + bool FirstToken = TRUE; + int intPrevValue = 8; + + SplitValues(&PropertySeg1, &SplitPoints, &SplitLength, intPrevValue); + + intPrevValue = 7; + + for (std::map::iterator intiter = SplitPoints.begin(); + intiter != SplitPoints.end(); ++intiter){ + + SLiter = SplitLength.find(intiter->first); + + PropertyData = PropertySeg1.Mid(intPrevValue, (SLiter->second)); + + wxStringTokenizer PropertyElement (PropertyData, wxT("=")); + PropertyName = PropertyElement.GetNextToken(); + PropertyValue = PropertyElement.GetNextToken(); + + intPrevValue = intiter->second; + + // Process properties. + + size_t intPropertyValueLen = PropertyValue.Len(); + + if (PropertyValue.Mid((intPropertyValueLen - 1), 1) == wxT("\"")){ + + PropertyValue.Trim(); + PropertyValue.RemoveLast(); + + } + + if (PropertyValue.Mid(0, 1) == wxT("\"")){ + + PropertyValue.Remove(0, 1); + + } + + if (!PropertyName.IsEmpty() && !PropertyValue.IsEmpty()){ + + if (FirstToken == TRUE){ + + PropertyTokens.Append(PropertyName + wxT("=") + PropertyValue); + FirstToken = FALSE; + + } else { + + PropertyTokens.Append(wxT(";") + PropertyName + wxT("=") + PropertyValue); + + } + + } + + } + + wxStringTokenizer GenderData (PropertySeg2, wxT(";")); + + wxString GenderComponent; + + if (GenderData.CountTokens() >= 2){ + + Gender = GenderData.GetNextToken(); + GenderDetails = GenderData.GetString(); + + CaptureString(&GenderDetails, FALSE); + + } else { + + Gender = GenderData.GetNextToken(); + + } + + if (!PropertyTokens.IsEmpty()){ + + GenderTokens = PropertyTokens; + + } + +} + +void ContactDataObject::ProcessBirthday(wxString PropertySeg1, wxString PropertySeg2){ + + // Process date. Preserve the remainder in the string. + + std::map SplitPoints; + std::map SplitLength; + std::map::iterator SLiter; + wxString PropertyData; + wxString PropertyName; + wxString PropertyValue; + wxString PropertyTokens; + bool BirthdayText = FALSE; + int intPrevValue = 6; + + SplitValues(&PropertySeg1, &SplitPoints, &SplitLength, intPrevValue); + + intPrevValue = 5; + + // Look for type before continuing. + + for (std::map::iterator intiter = SplitPoints.begin(); + intiter != SplitPoints.end(); ++intiter){ + + SLiter = SplitLength.find(intiter->first); + + PropertyData = PropertySeg1.Mid(intPrevValue, SLiter->second); + + wxStringTokenizer PropertyElement (PropertyData, wxT("=")); + PropertyName = PropertyElement.GetNextToken(); + PropertyValue = PropertyElement.GetNextToken(); + + intPrevValue = intiter->second; + + if (PropertyName == wxT("VALUE") && PropertyValue == wxT("text") && BirthdayText == FALSE){ + + CaptureString(&PropertySeg2, FALSE); + Birthday = PropertySeg2; + BirthdayText = TRUE; + + } + + } + + // Setup blank lines for later on. + + intPrevValue = 5; + bool FirstToken = TRUE; + + for (std::map::iterator intiter = SplitPoints.begin(); + intiter != SplitPoints.end(); ++intiter){ + + SLiter = SplitLength.find(intiter->first); + + PropertyData = PropertySeg1.Mid(intPrevValue, SLiter->second); + + wxStringTokenizer PropertyElement (PropertyData, wxT("=")); + PropertyName = PropertyElement.GetNextToken(); + PropertyValue = PropertyElement.GetNextToken(); + + intPrevValue = intiter->second; + + // Process properties. + + CaptureString(&PropertyValue, FALSE); + + if (PropertyValue.Mid((PropertyValue.Len() - 1), 1) == wxT("\"")){ + + PropertyValue.Trim(); + PropertyValue.RemoveLast(); + + } + + if (PropertyValue.Mid(0, 1) == wxT("\"")){ + + PropertyValue.Remove(0, 1); + + } + + if (PropertyName == wxT("ALTID")){ + + BirthdayAltID = PropertyValue; + + } else if (PropertyName == wxT("CALSCALE")){ + + BirthdayCalScale = PropertyValue; + + } else if (PropertyName != wxT("VALUE")) { + + // Something else we don't know about so append + // to the tokens variable. + + if (!PropertyName.IsEmpty() && !PropertyValue.IsEmpty()){ + + if (FirstToken == TRUE){ + + PropertyTokens.Append(PropertyName + wxT("=") + PropertyValue); + FirstToken = FALSE; + + } else { + + PropertyTokens.Append(wxT(";") + PropertyName + wxT("=") + PropertyValue); + + } + + } + + } + + } + + // Add the data to the variables and form. + + if (BirthdayText == FALSE){ + + Birthday = PropertySeg2; + + } + + if (!PropertyTokens.IsEmpty()){ + + BirthdayTokens = PropertyTokens; + + } + +} + +void ContactDataObject::ProcessAnniversary(wxString PropertySeg1, wxString PropertySeg2){ + + // Process date. Preserve the remainder in the string. + + std::map SplitPoints; + std::map SplitLength; + std::map::iterator SLiter; + wxString PropertyData; + wxString PropertyName; + wxString PropertyValue; + wxString PropertyTokens; + bool AnniversaryText = FALSE; + int intPrevValue = 6; + + SplitValues(&PropertySeg1, &SplitPoints, &SplitLength, intPrevValue); + + intPrevValue = 5; + + // Look for type before continuing. + + for (std::map::iterator intiter = SplitPoints.begin(); + intiter != SplitPoints.end(); ++intiter){ + + SLiter = SplitLength.find(intiter->first); + + PropertyData = PropertySeg1.Mid(intPrevValue, SLiter->second); + + wxStringTokenizer PropertyElement (PropertyData, wxT("=")); + PropertyName = PropertyElement.GetNextToken(); + PropertyValue = PropertyElement.GetNextToken(); + + intPrevValue = intiter->second; + + if (PropertyName == wxT("VALUE") && PropertyValue == wxT("text") && AnniversaryText == FALSE){ + + CaptureString(&PropertySeg2, FALSE); + Anniversary = PropertySeg2; + AnniversaryText = TRUE; + + } + + } + + // Setup blank lines for later on. + + intPrevValue = 5; + bool FirstToken = TRUE; + + for (std::map::iterator intiter = SplitPoints.begin(); + intiter != SplitPoints.end(); ++intiter){ + + SLiter = SplitLength.find(intiter->first); + + PropertyData = PropertySeg1.Mid(intPrevValue, SLiter->second); + + wxStringTokenizer PropertyElement (PropertyData, wxT("=")); + PropertyName = PropertyElement.GetNextToken(); + PropertyValue = PropertyElement.GetNextToken(); + + intPrevValue = intiter->second; + + // Process properties. + + CaptureString(&PropertyValue, FALSE); + + if (PropertyValue.Mid((PropertyValue.Len() - 1), 1) == wxT("\"")){ + + PropertyValue.Trim(); + PropertyValue.RemoveLast(); + + } + + if (PropertyValue.Mid(0, 1) == wxT("\"")){ + + PropertyValue.Remove(0, 1); + + } + + if (PropertyName == wxT("ALTID")){ + + AnniversaryAltID = PropertyValue; + + } else if (PropertyName == wxT("CALSCALE")){ + + AnniversaryCalScale = PropertyValue; + + } else if (PropertyName != wxT("VALUE")) { + + // Something else we don't know about so append + // to the tokens variable. + + if (!PropertyName.IsEmpty() && !PropertyValue.IsEmpty()){ + + if (FirstToken == TRUE){ + + PropertyTokens.Append(PropertyName + wxT("=") + PropertyValue); + FirstToken = FALSE; + + } else { + + PropertyTokens.Append(wxT(";") + PropertyName + wxT("=") + PropertyValue); + + } + + } + + } + + } + + // Add the data to the variables and form. + + if (AnniversaryText == FALSE){ + + Anniversary = PropertySeg2; + + } + + if (!PropertyTokens.IsEmpty()){ + + AnniversaryTokens = PropertyTokens; + + } + +} + void SplitValues(wxString *PropertyLine, std::map *SplitPoints, std::map *SplitLength, diff --git a/source/contacteditor/ContactDataObject.h b/source/contacteditor/ContactDataObject.h index d75410b..3a2ca7f 100644 --- a/source/contacteditor/ContactDataObject.h +++ b/source/contacteditor/ContactDataObject.h @@ -569,6 +569,9 @@ class ContactDataObject{ void ProcessFN(wxString PropertySeg1, wxString PropertySeg2, int *FNCount); void ProcessN(wxString PropertySeg1, wxString PropertySeg2); void ProcessNickname(wxString PropertySeg1, wxString PropertySeg2, int *NicknameCount); + void ProcessGender(wxString PropertySeg1, wxString PropertySeg2); + void ProcessBirthday(wxString PropertySeg1, wxString PropertySeg2); + void ProcessAnniversary(wxString PropertySeg1, wxString PropertySeg2); }; diff --git a/source/tests/LoadCheck-Load4.vcf b/source/tests/LoadCheck-Load4.vcf index 75d8d91..32ef415 100644 --- a/source/tests/LoadCheck-Load4.vcf +++ b/source/tests/LoadCheck-Load4.vcf @@ -11,4 +11,7 @@ NICKNAME;TYPE=home;ALTID=17;PID=39;PREF=78;LANGUAGE=en;YAY=Yep;Beep=Boop:Tes ty NICKNAME;TYPE=work;ALTID=99;PID=10;PREF=1;LANGUAGE=en-GB;YAY=Maybe;Boop=Boin g:The Testing One +GENDER;BEEP=Boop:F;Example Text +BDAY;ALTID=35;CALSCALE=georgian;HAPPY=Days:20040101 +ANNIVERSARY;ALTID=70;CALSCALE=georgian;WONDERFUL=Day:20200516 END:VCARD diff --git a/source/tests/xestiaab_contactload.h b/source/tests/xestiaab_contactload.h index 6ace86f..10d10b0 100644 --- a/source/tests/xestiaab_contactload.h +++ b/source/tests/xestiaab_contactload.h @@ -154,7 +154,20 @@ TEST(ContactLoad, ContactLoadTests){ // Check the extra tokens parameter. ASSERT_EQ("TEST=Yes", TestFile.NameTokens); - + +} + +TEST(ContactLoad, NicknameTests){ + + ContactDataObject TestFile; + + // Check that the vCard 4.0 file loads OK. + + ASSERT_EQ(CONTACTLOAD_OK, TestFile.LoadFile("LoadCheck-Load4.vcf")); + + std::map::iterator TestFileIter; + std::map::iterator TestFileIntIter; + // Check that the nickname has been read (NICKNAME). General. TestFileIter = TestFile.GeneralNicknamesList.find(0); @@ -265,4 +278,104 @@ TEST(ContactLoad, ContactLoadTests){ } +TEST(ContactLoad, GenderTests){ + + // Check that the gender has been read. + + ContactDataObject TestFile; + + // Check that the vCard 4.0 file loads OK. + + ASSERT_EQ(CONTACTLOAD_OK, TestFile.LoadFile("LoadCheck-Load4.vcf")); + + std::map::iterator TestFileIter; + std::map::iterator TestFileIntIter; + + ASSERT_NE("", TestFile.Gender); + ASSERT_EQ("F", TestFile.Gender); + ASSERT_EQ("Example Text", TestFile.GenderDetails); + ASSERT_EQ("BEEP=Boop", TestFile.GenderTokens); + +} + +TEST(ContactLoad, BirthdayTests){ + + // Check that the birthday has been read. + + // Check that the gender has been read. + + ContactDataObject TestFile; + + // Check that the vCard 4.0 file loads OK. + + ASSERT_EQ(CONTACTLOAD_OK, TestFile.LoadFile("LoadCheck-Load4.vcf")); + + std::map::iterator TestFileIter; + std::map::iterator TestFileIntIter; + + ASSERT_NE("", TestFile.Birthday); + ASSERT_EQ("20040101", TestFile.Birthday); + + // Check the ALTID parameter. + + ASSERT_EQ("35", TestFile.BirthdayAltID); + + // Check the CALSCALE parameter. + + ASSERT_EQ("georgian", TestFile.BirthdayCalScale); + + // Check the extra tokens parameter. + + ASSERT_EQ("HAPPY=Days", TestFile.BirthdayTokens); + + // Check the VALUE parameter. (Note have to use a different file + // due to the *1 rule in RFC6350. + + ContactDataObject TestFileValue; + ASSERT_EQ(CONTACTLOAD_OK, TestFile.LoadFile("LoadCheck-Load4-BDayValue.vcf")); + + ASSERT_EQ("Circa 2000s", TestFile.Birthday); + +} + +TEST(ContactLoad, AnniversaryTests){ + + // Check that the birthday has been read. + + // Check that the gender has been read. + + ContactDataObject TestFile; + + // Check that the vCard 4.0 file loads OK. + + ASSERT_EQ(CONTACTLOAD_OK, TestFile.LoadFile("LoadCheck-Load4.vcf")); + + std::map::iterator TestFileIter; + std::map::iterator TestFileIntIter; + + ASSERT_NE("", TestFile.Anniversary); + ASSERT_EQ("20200516", TestFile.Anniversary); + + // Check the ALTID parameter. + + ASSERT_EQ("70", TestFile.AnniversaryAltID); + + // Check the CALSCALE parameter. + + ASSERT_EQ("georgian", TestFile.AnniversaryCalScale); + + // Check the extra tokens parameter. + + ASSERT_EQ("WONDERFUL=Day", TestFile.AnniversaryTokens); + + // Check the VALUE parameter. (Note have to use a different file + // due to the *1 rule in RFC6350. + + ContactDataObject TestFileValue; + ASSERT_EQ(CONTACTLOAD_OK, TestFile.LoadFile("LoadCheck-Load4-BDayValue.vcf")); + + ASSERT_EQ("Circa 2020s", TestFile.Anniversary); + +} + // TODO: Add tests for the Contact Loading process. \ No newline at end of file -- 2.39.2