Skip to content

Commit

Permalink
imp - brk|doc - Got rid of second step
Browse files Browse the repository at this point in the history
---

We've got rid of the second step. This means that you'll only have to parse cards using CardTools.GetCards().

---

Type: imp
Breaking: True
Doc Required: True
Part: 1/1
  • Loading branch information
AptiviCEO committed Mar 29, 2024
1 parent d315189 commit 380d387
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 266 deletions.
22 changes: 10 additions & 12 deletions VisualCard.ShowContacts/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,17 @@ static void Main(string[] args)
Stopwatch elapsed = new();
elapsed.Start();

// Get parsers
List<BaseVcardParser> ContactParsers =
android ? AndroidContactsDb.GetContactsFromDb(args[0]) :
// Parse all contacts
Card[] contacts =
android ? AndroidContactsDb.GetContactsFromDb(args[0]) :
mecard ? MeCard.GetContactsFromMeCardString(meCardString) :
CardTools.GetCardParsers(args[0]);
List<Card> Contacts = [];
CardTools.GetCards(args[0]);

// Parse all contacts
foreach (BaseVcardParser ContactParser in ContactParsers)
// If told to save them, do it
foreach (var contact in contacts)
{
Card Contact = ContactParser.Parse();
Contacts.Add(Contact);
if (save)
Contact.SaveTo($"contact_{DateTime.Now:dd-MM-yyyy_HH-mm-ss_ffffff}.vcf");
contact.SaveTo($"contact_{DateTime.Now:dd-MM-yyyy_HH-mm-ss_ffffff}.vcf");
}

// If not printing, exit
Expand All @@ -86,8 +83,8 @@ static void Main(string[] args)
}

// Show contact information
bool showVcard5Disclaimer = Contacts.Any((card) => card.CardVersion.ToString(2) == "5.0");
foreach (Card Contact in Contacts)
bool showVcard5Disclaimer = contacts.Any((card) => card.CardVersion.ToString(2) == "5.0");
foreach (Card Contact in contacts)
{
TextWriterColor.WriteColor("----------------------------", ConsoleColors.Green);
TextWriterColor.WriteColor("Name: {0}", ConsoleColors.Green, Contact.GetString(StringsEnum.FullName));
Expand Down Expand Up @@ -192,6 +189,7 @@ static void Main(string[] args)
}
if (showVcard5Disclaimer)
TextWriterColor.WriteColor("This application uses vCard 5.0, a revised version of vCard 4.0, made by Aptivi.", ConsoleColors.Silver);
TextWriterColor.Write("Elapsed time: {0}", elapsed.Elapsed.ToString());
}
}
}
Expand Down
130 changes: 31 additions & 99 deletions VisualCard.Tests/ContactParseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,6 @@ namespace VisualCard.Tests
[TestClass]
public class ContactParseTests
{
[TestMethod]
[DynamicData(nameof(ContactData.singleVcardContactShorts), typeof(ContactData))]
public void GetCardParsersFromDifferentContactsShorts(string cardText)
=> Should.NotThrow(() => CardTools.GetCardParsersFromString(cardText));

[TestMethod]
[DynamicData(nameof(ContactData.singleVcardContacts), typeof(ContactData))]
public void GetCardParsersFromDifferentContacts(string cardText)
=> Should.NotThrow(() => CardTools.GetCardParsersFromString(cardText));

[TestMethod]
[DynamicData(nameof(ContactData.multipleVcardContacts), typeof(ContactData))]
public void GetCardParsersFromDifferentContactsMultiple(string cardText)
=> Should.NotThrow(() => CardTools.GetCardParsersFromString(cardText));

[TestMethod]
[DynamicData(nameof(ContactData.remainingContacts), typeof(ContactData))]
public void GetCardParsersFromDifferentContactsRemaining(string cardText)
=> Should.NotThrow(() => CardTools.GetCardParsersFromString(cardText));

[TestMethod]
[DynamicData(nameof(ContactData.singleVcardContactShorts), typeof(ContactData))]
public void ParseDifferentContactsShorts(string cardText) =>
Expand All @@ -72,10 +52,8 @@ public void ParseDifferentContactsRemaining(string cardText) =>

internal void ParseDifferentContactsInternal(string cardText)
{
List<BaseVcardParser> parsers = [];
Should.NotThrow(() => parsers = CardTools.GetCardParsersFromString(cardText));
foreach (BaseVcardParser parser in parsers)
Should.NotThrow(parser.Parse);
Card[] cards;
Should.NotThrow(() => cards = CardTools.GetCardsFromString(cardText));
}

[TestMethod]
Expand All @@ -100,17 +78,12 @@ public void ParseDifferentContactsAndTestEqualityRemaining(string cardText) =>

internal void ParseDifferentContactsAndTestEqualityInternal(string cardText)
{
List<BaseVcardParser> parsers = [];
List<Card> cards = [];
List<Card> secondCards = [];
Card[] cards = [];
Card[] secondCards = [];

// Parse the cards
Should.NotThrow(() => parsers = CardTools.GetCardParsersFromString(cardText));
foreach (BaseVcardParser parser in parsers)
{
cards.Add(Should.NotThrow(parser.Parse));
secondCards.Add(Should.NotThrow(parser.Parse));
}
Should.NotThrow(() => cards = CardTools.GetCardsFromString(cardText));
Should.NotThrow(() => secondCards = CardTools.GetCardsFromString(cardText));

// Test equality with available data
List<bool> foundCards = [];
Expand Down Expand Up @@ -150,26 +123,19 @@ public void ParseDifferentContactsSaveToStringAndTestEqualityRemaining(string ca

public void ParseDifferentContactsSaveToStringAndTestEqualityInternal(string cardText)
{
List<BaseVcardParser> parsers = [];
List<Card> cards = [];
List<Card> secondCards = [];
List<Card> savedCards = [];
Card[] cards = [];
Card[] secondCards = [];

// Parse the cards
Should.NotThrow(() => parsers = CardTools.GetCardParsersFromString(cardText));
foreach (BaseVcardParser parser in parsers)
{
cards.Add(Should.NotThrow(parser.Parse));
secondCards.Add(Should.NotThrow(parser.Parse));
}
Should.NotThrow(() => cards = CardTools.GetCardsFromString(cardText));
Should.NotThrow(() => secondCards = CardTools.GetCardsFromString(cardText));

// Save all the cards to strings and re-parse
foreach (Card card in cards)
{
string saved = Should.NotThrow(card.SaveToString);
Should.NotThrow(() => parsers = CardTools.GetCardParsersFromString(saved));
foreach (BaseVcardParser parser in parsers)
savedCards.Add(Should.NotThrow(parser.Parse));
Should.NotThrow(() => secondCards = CardTools.GetCardsFromString(saved));
}

// Test equality with available data
Expand All @@ -192,39 +158,30 @@ public void ParseDifferentContactsSaveToStringAndTestEqualityInternal(string car
[DynamicData(nameof(ContactData.vCardFromMeCardContacts), typeof(ContactData))]
public void ParseAndCheckDifferentMeCardContacts((string, string) cardText)
{
List<BaseVcardParser> parsers = [];
Should.NotThrow(() => parsers = MeCard.GetContactsFromMeCardString(cardText.Item1));
Card card = default;
foreach (BaseVcardParser parser in parsers)
Should.NotThrow(() => card = parser.Parse());
Card[] cards = [];
Should.NotThrow(() => cards = MeCard.GetContactsFromMeCardString(cardText.Item1));
Card card = cards[0];
card.SaveToString().ShouldBe(cardText.Item2);
}

[TestMethod]
[DynamicData(nameof(ContactData.meCardContacts), typeof(ContactData))]
public void ParseDifferentMeCardContacts(string cardText)
{
List<BaseVcardParser> parsers = [];
Should.NotThrow(() => parsers = MeCard.GetContactsFromMeCardString(cardText));
foreach (BaseVcardParser parser in parsers)
Should.NotThrow(parser.Parse);
Card[] cards;
Should.NotThrow(() => cards = MeCard.GetContactsFromMeCardString(cardText));
}

[TestMethod]
[DynamicData(nameof(ContactData.meCardContacts), typeof(ContactData))]
public void ParseDifferentMeCardContactsAndTestEquality(string cardText)
{
List<BaseVcardParser> parsers = [];
List<Card> cards = [];
List<Card> secondCards = [];
Card[] cards = [];
Card[] secondCards = [];

// Parse the cards
Should.NotThrow(() => parsers = MeCard.GetContactsFromMeCardString(cardText));
foreach (BaseVcardParser parser in parsers)
{
cards.Add(Should.NotThrow(parser.Parse));
secondCards.Add(Should.NotThrow(parser.Parse));
}
Should.NotThrow(() => cards = CardTools.GetCardsFromString(cardText));
Should.NotThrow(() => secondCards = CardTools.GetCardsFromString(cardText));

// Test equality with available data
List<bool> foundCards = [];
Expand All @@ -246,26 +203,19 @@ public void ParseDifferentMeCardContactsAndTestEquality(string cardText)
[DynamicData(nameof(ContactData.meCardContacts), typeof(ContactData))]
public void ParseDifferentMeCardContactsSaveToStringAndTestEquality(string cardText)
{
List<BaseVcardParser> parsers = [];
List<Card> cards = [];
List<Card> secondCards = [];
List<Card> savedCards = [];
Card[] cards = [];
Card[] secondCards = [];

// Parse the cards
Should.NotThrow(() => parsers = MeCard.GetContactsFromMeCardString(cardText));
foreach (BaseVcardParser parser in parsers)
{
cards.Add(Should.NotThrow(parser.Parse));
secondCards.Add(Should.NotThrow(parser.Parse));
}
Should.NotThrow(() => cards = CardTools.GetCardsFromString(cardText));
Should.NotThrow(() => secondCards = CardTools.GetCardsFromString(cardText));

// Save all the cards to strings and re-parse
foreach (Card card in cards)
{
string saved = Should.NotThrow(card.SaveToString);
Should.NotThrow(() => parsers = CardTools.GetCardParsersFromString(saved));
foreach (BaseVcardParser parser in parsers)
savedCards.Add(Should.NotThrow(parser.Parse));
Should.NotThrow(() => secondCards = CardTools.GetCardsFromString(saved));
}

// Test equality with available data
Expand All @@ -284,37 +234,19 @@ public void ParseDifferentMeCardContactsSaveToStringAndTestEquality(string cardT
foundCards.ShouldAllBe((b) => b);
}

[TestMethod]
[DynamicData(nameof(ContactDataBogus.invalidContacts), typeof(ContactDataBogus))]
public void InvalidContactShouldThrowWhenGettingCardParsers(string cardText)
=> Should.Throw<InvalidDataException>(() => CardTools.GetCardParsersFromString(cardText));

[TestMethod]
[DynamicData(nameof(ContactDataBogus.invalidContactsParser), typeof(ContactDataBogus))]
public void InvalidContactShouldThrowWhenParsing(string cardText)
{
List<BaseVcardParser> parsers = [];
Should.NotThrow(() => parsers = CardTools.GetCardParsersFromString(cardText));
foreach (BaseVcardParser parser in parsers)
Should.Throw<InvalidDataException>(parser.Parse);
}

[TestMethod]
[DynamicData(nameof(ContactDataBogus.seemsValidContacts), typeof(ContactDataBogus))]
public void BogusButSeemsValidShouldNotThrowWhenGettingCardParsers(string cardText)
=> Should.NotThrow(() => CardTools.GetCardParsersFromString(cardText));
public void InvalidContactShouldThrowWhenParsing(string cardText) =>
Should.Throw<InvalidDataException>(() => CardTools.GetCardsFromString(cardText));

[TestMethod]
[DynamicData(nameof(ContactDataBogus.seemsValidContacts), typeof(ContactDataBogus))]
public void BogusButSeemsValidShouldNotThrowWhenParsing(string cardText)
{
List<BaseVcardParser> parsers = [];
Should.NotThrow(() => parsers = CardTools.GetCardParsersFromString(cardText));
foreach (BaseVcardParser parser in parsers)
{
var resultingCard = Should.NotThrow(parser.Parse);
resultingCard.ShouldNotBeNull();
}
Card[] cards = [];
Should.NotThrow(() => cards = CardTools.GetCardsFromString(cardText));
foreach (Card card in cards)
card.ShouldNotBeNull();
}
}
}
37 changes: 24 additions & 13 deletions VisualCard/CardTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
using VisualCard.Parsers;
using System;
using VisualCard.Parsers.Versioned;
using VisualCard.Parts;

namespace VisualCard
{
Expand All @@ -36,36 +37,37 @@ public static class CardTools
/// </summary>
/// <param name="cardText">Contacts text</param>
/// <returns>List of contact parsers for single or multiple contacts</returns>
public static List<BaseVcardParser> GetCardParsersFromString(string cardText)
public static Card[] GetCardsFromString(string cardText)
{
// Open the stream to parse multiple contact versions (required to parse more than one contact)
MemoryStream CardFs = new(Encoding.Default.GetBytes(cardText));
StreamReader CardReader = new(CardFs);
return GetCardParsers(CardReader);
return GetCards(CardReader);
}

/// <summary>
/// Gets the list of parsers for single/multiple contacts from the path
/// </summary>
/// <param name="Path">Path to the contacts file</param>
/// <returns>List of contact parsers for single or multiple contacts</returns>
public static List<BaseVcardParser> GetCardParsers(string Path)
public static Card[] GetCards(string Path)
{
// Open the stream to parse multiple contact versions (required to parse more than one contact)
FileStream CardFs = new(Path, FileMode.Open, FileAccess.Read);
StreamReader CardReader = new(CardFs);
return GetCardParsers(CardReader);
return GetCards(CardReader);
}

/// <summary>
/// Gets the list of parsers for single/multiple contacts from the stream
/// </summary>
/// <param name="stream">Stream containing the contacts</param>
/// <returns>List of contact parsers for single or multiple contacts</returns>
public static List<BaseVcardParser> GetCardParsers(StreamReader stream)
public static Card[] GetCards(StreamReader stream)
{
// Variables and flags
List<BaseVcardParser> FinalParsers = [];
List<Card> FinalCards = [];
bool BeginSpotted = false;
bool VersionSpotted = false;
bool EndSpotted = false;
Expand All @@ -86,11 +88,13 @@ public static List<BaseVcardParser> GetCardParsers(StreamReader stream)
if (!stream.EndOfStream)
continue;
}
else
else if (CardLine != VcardConstants._beginText &&
!CardLine.StartsWith(VcardConstants._versionSpecifier) &&
CardLine != VcardConstants._endText)
CardContent.AppendLine(CardLine);

// All VCards must begin with BEGIN:VCARD
if (CardLine != "BEGIN:VCARD" && !BeginSpotted)
if (CardLine != VcardConstants._beginText && !BeginSpotted)
throw new InvalidDataException($"This is not a valid VCard contact file.");
else if (!BeginSpotted)
{
Expand All @@ -105,10 +109,10 @@ public static List<BaseVcardParser> GetCardParsers(StreamReader stream)
if (!CardSawNull)
CardLine = stream.ReadLine();
CardSawNull = false;
if (CardLine != "VERSION:2.1" &&
CardLine != "VERSION:3.0" &&
CardLine != "VERSION:4.0" &&
CardLine != "VERSION:5.0" &&
if (CardLine != $"{VcardConstants._versionSpecifier}:2.1" &&
CardLine != $"{VcardConstants._versionSpecifier}:3.0" &&
CardLine != $"{VcardConstants._versionSpecifier}:4.0" &&
CardLine != $"{VcardConstants._versionSpecifier}:5.0" &&
!VersionSpotted)
throw new InvalidDataException($"This has an invalid VCard version {CardLine}.");
else if (!VersionSpotted)
Expand All @@ -118,7 +122,7 @@ public static List<BaseVcardParser> GetCardParsers(StreamReader stream)
}

// If the ending tag is spotted, reset everything.
if (CardLine == "END:VCARD" && !EndSpotted)
if (CardLine == VcardConstants._endText && !EndSpotted)
{
EndSpotted = true;
CardContent.AppendLine(CardLine);
Expand Down Expand Up @@ -158,7 +162,14 @@ public static List<BaseVcardParser> GetCardParsers(StreamReader stream)
// Throw if the card ended prematurely
if (!EndSpotted)
throw new InvalidDataException("Card ended prematurely without the ending tag");
return FinalParsers;

// Now, assuming that all cards and their parsers are valid, parse all of them
foreach (var parser in FinalParsers)
{
var card = parser.Parse();
FinalCards.Add(card);
}
return [.. FinalCards];
}
}
}
Loading

0 comments on commit 380d387

Please sign in to comment.