Skip to content

Instantly share code, notes, and snippets.

@zaus
Created September 21, 2012 18:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zaus/3763223 to your computer and use it in GitHub Desktop.
Save zaus/3763223 to your computer and use it in GitHub Desktop.
Randomly create a formatting string mask for use in testing Haacked.StringLib operations, and associated tests
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AtifAzis.Extensions;
/// for http://haacked.com/archive/2009/01/14/named-formats-redux.aspx and https://gist.github.com/3763138
namespace Tests.Haacked.StringLib {
/// <summary>
/// Usage:
/// <example>
/// <code>
/// var mask = helper.CreateRandomTokenizedString(10, out tokens);
/// var replacements = helper.CreateRandomTokenReplacementsDictionaryObject(tokens); // using Aziz's DictionaryObject: http://haacked.com/archive/2009/01/14/named-formats-redux.aspx#70526
/// </code>
/// </example>
/// </summary>
public class StringLibTestSetup {
/// <summary>
/// for pseudo randomization
/// </summary>
private Random _rand = new Random();
public int[] WordSizeRange = new int[] { 5, 10 };
/// <summary>
/// Get a list of randomized replacements for each tokens
/// </summary>
/// <param name="tokens"></param>
/// <returns></returns>
public Dictionary<string, object> CreateRandomTokenReplacements(List<string> tokens) {
var replacements = new Dictionary<string, object>();
int counter = 0;
tokens.ForEach(token => {
replacements.Add(token, this.WordAsToken((counter++).ToString()));
});
return replacements;
}
/// <summary>
/// Get a list of randomized replacements for each tokens
/// </summary>
/// <param name="tokens"></param>
/// <returns></returns>
public DictionaryObject<object> CreateRandomTokenReplacementsDictionaryObject(List<string> tokens) {
var replacements = new DictionaryObject<object>();
int counter = 0;
tokens.ForEach(token => {
replacements.Add(token, this.WordAsToken((counter++).ToString()));
});
return replacements;
}
/// <summary>
/// Get a string with random words and tokens, returning the tokens
/// </summary>
/// <param name="numTokens"></param>
/// <param name="tokens"></param>
/// <param name="sentenceFactor"></param>
/// <returns></returns>
public string CreateRandomTokenizedString(int numTokens, out List<string> tokens, int sentenceFactor = 10) {
tokens = new List<string>();
var sentence = new List<string>();
string word;
for (int i = 0; i < numTokens; i++) {
word = this.CreateRandomWord(this.WordSizeRange[0], this.WordSizeRange[1]);
if( !tokens.Contains(word) )
tokens.Add(word);
}
// add tokens to sentence, formatted as tokens
tokens.ForEach(token => {
sentence.Add(this.WordAsToken(token));
});
// now add a bunch of regular words
for (int i = numTokens * sentenceFactor; i > 0; i--) {
sentence.Add(this.CreateRandomWord(this.WordSizeRange[0], this.WordSizeRange[1]));
}
// randomize
return string.Join(" ", sentence.OrderBy(o => this._rand.NextDouble()).ToArray());
}
public string WordAsToken(string word) {
return string.Format("{{{0}}}", word);
}
public string CreateRandomWord(int minLength, int maxLength) {
var length = _rand.Next(minLength, maxLength);
var word = new char[length];
for (int i = 0; i < length; i++) {
word[i] = this.CreateRandomLetter();
}
return string.Join(string.Empty, word);
}
/// <summary>
/// Get a random letter from A to Z
/// </summary>
/// <returns></returns>
public char CreateRandomLetter() {
return ((char)_rand.Next((int)'a', (int)'z'));
}
}
}
[TestMethod]
public void Performance_VariousMethods_RandomReplacementString() {
var helper = new StringLibTestSetup();
List<string> tokens;
var mask = helper.CreateRandomTokenizedString(10, out tokens);
var replacements = helper.CreateRandomTokenReplacementsDictionaryObject(tokens);
// debugging
Console.WriteLine("Mask: {0}", mask);
Console.WriteLine("Replacements:");
// enumerate ExpandoObject trick - http://stackoverflow.com/questions/5156664/how-to-flatten-an-expandoobject-returned-via-jsonresult-in-asp-net-mvc
foreach (var pair in replacements) {
Console.WriteLine(" {0}: {1}", pair.Key, pair.Value);
}
// this will run each test delegate function X times and record the result
var suite = new MiniBenchmarkSuite(50000);
string result = string.Empty;
suite.AddTest("henri", () => {
result = mask.HenriFormat(replacements);
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result ));
suite.AddTest("numerical", () => {
result = string.Format(result, tokens.ToArray());
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
suite.AddTest("haacked", () => {
result = mask.HaackFormat(replacements);
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
suite.AddTest("hanselman", () => {
result = replacements.HanselFormat(mask);
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
suite.AddTest("james", () => {
result = mask.JamesFormat(replacements);
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
suite.AddTest("zausobject", () => {
result = mask.ZausFormatObject(replacements);
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
suite.AddTest("regular", () => {
foreach (var pair in replacements) {
result = result.Replace(pair.Key, (string)pair.Value);
}
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
//build replacement string list
List<string> zausTokens = new List<string>();
foreach (var pair in replacements) {
zausTokens.Add(pair.Key);
zausTokens.Add(pair.Value.ToString());
}
var zausTokenArray = zausTokens .ToArray();
suite.AddTest("zaus", () => {
result = mask.ZausFormat(zausTokenArray );
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
Console.WriteLine(suite);
}
[TestMethod]
public void Performance_VariousMethods() {
var helper = new StringLibTestSetup();
List<string> tokens;
var mask = "aoesthaos {uthoesth}aoesuthaso thoesu{thosetuh} asoetuh {asoehtus} aotehusa{toehu} satoehus atoehus {asoehtus} ahtoeust ahoesutah oesutha oestuh {asoethu} asoetuh {asoehtus} asoteuh asoeuth asoeu astoehu {atnoh}esuth asoetuh asotehu astoheu";
var replacements = new {
uthoesth = "{0}",
thosetuh = "{1}",
asoehtus = "{2}",
toehu = "{3}",
asoethu = "{4}",
atnoh = "{5}"
};
// debugging
Console.WriteLine("Mask: {0}", mask);
Console.WriteLine("Replacements:");
var replacementDict = Extensions.AnonymousObjectToDictionary<string>(replacements);
foreach (var pair in replacementDict) {
Console.WriteLine(" {0}: {1}", pair.Key, pair.Value);
}
var suite = new MiniBenchmarkSuite(50000);
string result = string.Empty;
suite.AddTest("henri", () => {
result = mask.HenriFormat(replacements);
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
// test the regular style -- fortunately, we've already "back-converted" the mask with our replacements
tokens = new List<string>();
tokens.AddRange(replacementDict.Values);
suite.AddTest("numerical", () => {
result = string.Format(result, tokens.ToArray());
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
suite.AddTest("haacked", () => {
result = mask.HaackFormat(replacements);
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
suite.AddTest("hanselman", () => {
result = replacements.HanselFormat(mask);
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
suite.AddTest("james", () => {
result = mask.JamesFormat(replacements);
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
suite.AddTest("regular", () => {
foreach (var pair in replacementDict) {
result = result.Replace(pair.Key, (string)pair.Value);
}
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
suite.AddTest("zausobject", () => {
result = mask.ZausFormatObject(replacements);
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
//build replacement string list
List<string> zausTokens = new List<string>();
foreach (var pair in replacements) {
zausTokens.Add(pair.Key);
zausTokens.Add(pair.Value.ToString());
}
var zausTokenArray = zausTokens.ToArray();
suite.AddTest("zaus", () => {
result = mask.ZausFormat(zausTokenArray );
}, after: (id, n) => Console.WriteLine("Test {0}: {1}", id, result));
Console.WriteLine(suite);
}
Tests ordered by duration, normalized to quickest:
1. numerical in 100.00%
2. regular in 409.40%
3. henri in 619.61%
4. haacked in 716.91%
5. hanselman in 758.82%
6. james in 1244.77%
7. zaus in 1276.26%
8. zausobject in 1379.84%
Tests ordered by duration, normalized to quickest:
1. numerical in 100.00%
2. regular in 294.07%
3. zaus in 824.25%
4. henri in 903.84%
5. zausobject in 1337.37%
6. haacked in 1418.82%
7. james in 2645.47%
8. hanselman in 2863.87%
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment