public void TimeSpanDateTime() { var simple = FSBuilder.Take <TimeSpanObject>("|", typeof(TimeSpanObject).GetProperty("A")).TakeRest(typeof(TimeSpanObject).GetField("B")).Seal(); var span1 = System.TimeSpan.FromDays(1); var span2 = System.TimeSpan.FromMilliseconds((new Random()).Next(1000000)); var obj = new TimeSpanObject(); simple(span1 + "|" + span2, obj); Assert.AreEqual(span1, obj.A); Assert.AreEqual(span2, obj.B.Value); var complex = FSBuilder.Take <TimeSpanObject>("|", typeof(TimeSpanObject).GetProperty("A"), format: "G").TakeRest(typeof(TimeSpanObject).GetField("B"), format: "g").Seal(); complex(span2.ToString("G") + "|" + span1.ToString("g"), obj); Assert.AreEqual(span2, obj.A); Assert.AreEqual(span1, obj.B.Value); var date = FSBuilder.Take <TimeSpanObject>("|", "C").Seal(); var newDate = DateTime.UtcNow; date(newDate + "|", obj); Assert.AreEqual(newDate.ToString(), obj.C.ToString()); }
public void NumberAsEnum() { var simple = FSBuilder.Take <EnumObject>("|", "A").Else((s, o) => { throw new InvalidOperationException(); }).Seal(); var obj = new EnumObject(); simple("2|", obj); Assert.AreEqual(EnumObject.Blah.Bar, obj.A); }
public void StandAloneTakeN() { var parser = FSBuilder.Take <DecimalObject>(4, typeof(DecimalObject).GetProperty("A")).Seal(); var obj = new DecimalObject(); parser("12345678", obj); Assert.AreEqual(1234m, obj.A); }
public void Overflows() { var parse = FSBuilder .Take <ValueObject>(",", "A") .Take(",", "B") .Take(",", "C") .TakeRest("D") .Else((s, o) => { throw new Exception(); }) .Seal(); var obj = new ValueObject(); parse("1,2,3,4", obj); Assert.AreEqual(1, obj.A); Assert.AreEqual(2, obj.B); Assert.AreEqual(3, obj.C); Assert.AreEqual(4, obj.D); try { parse(byte.MaxValue + ",1,2,3", obj); Assert.Fail("byte should be exceeded"); } catch (Exception) { } try { parse("1," + ushort.MaxValue + ",2,3", obj); Assert.Fail("short should be exceeded"); } catch (Exception) { } try { parse("1,2," + uint.MaxValue + ",3", obj); Assert.Fail("int should be exceeded"); } catch (Exception) { } try { parse("1,2,3," + ulong.MaxValue, obj); Assert.Fail("long should be exceeded"); } catch (Exception) { } parse(sbyte.MaxValue + "," + short.MaxValue + "," + int.MaxValue + "," + long.MaxValue, obj); Assert.AreEqual(sbyte.MaxValue, obj.A); Assert.AreEqual(short.MaxValue, obj.B); Assert.AreEqual(int.MaxValue, obj.C); Assert.AreEqual(long.MaxValue, obj.D); }
public void FloatsDoubles() { var parse = FSBuilder.Take <FloatAndDouble>(",", "A").TakeRest("B").Seal(); var rand = new Random(); var a = (float)rand.NextDouble(); var b = rand.NextDouble(); var obj = new FloatAndDouble(); parse(a + "," + b, obj); Assert.AreEqual(a.ToString(), obj.A.ToString()); Assert.AreEqual(b.ToString(), obj.B.ToString()); }
public void Decimals() { var parser = FSBuilder .Take <DecimalObject>(",", typeof(DecimalObject).GetProperty("A")) .TakeRest(typeof(DecimalObject).GetProperty("B")) .Seal(); var obj = new DecimalObject(); parser("123.45,8675309", obj); Assert.AreEqual(123.45m, obj.A); Assert.AreEqual(8675309m, obj.B); }
public void Bools() { var parser = FSBuilder .Take <BoolObject>(",", "A") .Take(",", "B") .TakeRest("C") .Seal(); var obj = new BoolObject(); parser("True,1,false", obj); Assert.IsTrue(obj.A); Assert.IsTrue(obj.B); Assert.IsFalse(obj.C.Value); }
public void NullableSkip() { var parser = FSBuilder .Take <BoolObject>(",", "A") .Take(",", "C") .TakeRest("B") .Seal(); var obj = new BoolObject(); parser("True,,false", obj); Assert.IsTrue(obj.A); Assert.IsFalse(obj.B); Assert.IsNull(obj.C); }
public void FixedSteps() { var parse = FSBuilder .Take <UnsignedObject>(4, "A") .Back(2) .Take(",", "B") .Skip(2) .TakeRest("C") .Seal(); var obj = new UnsignedObject(); parse("1234,5678", obj); Assert.AreEqual((ulong)1234, obj.A); Assert.AreEqual((uint)34, obj.B); Assert.AreEqual((ushort)78, obj.C); }
public void Unsigned() { var parse = FSBuilder .Take <UnsignedObject>(",", "A") .Take(",", "B") .Take(",", "C") .TakeRest("D") .Seal(); var obj = new UnsignedObject(); parse(ulong.MaxValue + "," + uint.MaxValue + "," + ushort.MaxValue + "," + byte.MaxValue, obj); Assert.AreEqual(ulong.MaxValue, obj.A); Assert.AreEqual(uint.MaxValue, obj.B); Assert.AreEqual(ushort.MaxValue, obj.C); Assert.AreEqual(byte.MaxValue, obj.D); }
public void Guids() { var parser = FSBuilder .Take <GuidObj>(",", "A") .TakeRest("B", "X") .Else((s, o) => { throw new Exception(); }) .Seal(); var a = Guid.NewGuid(); var b = Guid.NewGuid(); var obj = new GuidObj(); parser(a + "," + b.ToString("X"), obj); Assert.AreEqual(obj.A, a); Assert.AreEqual(obj.B.Value, b); }
public void Errors() { var left = FSBuilder.Take <UnsignedObject>("|", "A").Else((s, o) => { }); var right = FSBuilder.Take <UnsignedObject>("|", "B").Else((s, o) => { }); try { left.Append(right); Assert.Fail("Shouldn't be legal to append two else directives"); } catch (Exception) { } left = FSBuilder.Skip <UnsignedObject>(1).TakeRest("A"); right = FSBuilder.Skip <UnsignedObject>(1).TakeRest("B"); try { left.Append(right); Assert.Fail("Shouldn't be legal to append two take rest directives"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>(5, "HelloWorld"); Assert.Fail("Property does not exist"); } catch (Exception) { } // These *shouldn't* throw exceptions FSBuilder.Take <UnsignedObject>("|", "A").Seal()("345212", new UnsignedObject()); FSBuilder.Take <UnsignedObject>(4, "A").Seal()("1", new UnsignedObject()); FSBuilder.Take <UnsignedObject>(1, "A").Take("|", "B").Seal()("asdf", new UnsignedObject()); try { FSBuilder.Skip <UnsignedObject>(1).Back(-4); Assert.Fail("Back shouldn't accept negatives"); } catch (Exception) { } try { FSBuilder.Skip <UnsignedObject>(-4); Assert.Fail("Skip shouldn't accept negatives"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>(-4, "A"); Assert.Fail("Take shouldn't accept negatives"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>(4, "Bad"); Assert.Fail("Bad should not be deserializable"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>(4, typeof(string).GetMember("Length")[0]); Assert.Fail("Length is not on UnsignedObject"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>(4, typeof(UnsignedObject).GetMember("ToString")[0]); Assert.Fail("ToString is not a field or property"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>(4, "Hidden"); Assert.Fail("Hidden is not settable"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>(4, "Static"); Assert.Fail("Statis is not an instance property"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>(4, "StaticField"); Assert.Fail("StaticField is not an instance field"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>(4, "A", format: "yyyy-mm-dd"); Assert.Fail("A is not a DateTime or TimeSpan"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>(",", "DT", format: "asdf"); Assert.Fail("DateTime format string is invalid"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>(",", "TS", format: "asdf"); Assert.Fail("TimeSpan format string is invalid"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>(",", "GD", format: "sadf"); Assert.Fail("Guid format string is invalid"); } catch (Exception) { } try { FSBuilder.Take <UnsignedObject>("", "TS"); Assert.Fail("An empty until is invalid"); } catch (Exception) { } }
static Tests() { var step1 = FSBuilder .Until <LogRow>(" "); var step2 = FSBuilder .Take <LogRow>(":", "ClientIp") .Until("[") .Take("]", LogProp("CreationDate"), format: "dd/MMM/yyyy:HH:mm:ss.fff") .Until(" ") .Take(" ", "FrontEnd") .Take("/", LogProp("BackEnd")) .Take(" ", "Server") .Take("/", LogProp("Tq")) .Take("/", "Tw") .Take("/", LogProp("Tc")) .Take("/", "Tr") .Take(" ", LogProp("Tt")) .Take(" ", "ResponseCode") .Take(" ", LogProp("Bytes")) .Until("- ") .Until("- ") .Take(4, "TermState") .Until(" "); var step3 = FSBuilder .Take <LogRow>("/", LogProp("ActConn")) .Take("/", "FeConn") .Take("/", LogProp("BeConn")) .Take("/", "SrvConn") .Take(" ", LogProp("Retries")) .Take("/", "SrvQueue") .Take(" ", LogProp("BackEndQueue")) .Until("{") .Take("|", "Referer") .Take("|", LogProp("UserAgent")) .Take("|", "Host") .Take("|", LogProp("ForwardFor")) .Take("}", "AcceptEncoding") .Until("{") .Take("|", LogProp("ContentEncoding")) .Take("|", "IsPageView") .Take("|", LogProp("SqlDurationMs")) .Take("|", "AccountId") .Take("}", LogProp("RouteName")) .Until("\"") .Take(" ", "Method") .Take(" ", LogProp("Uri")) .Take("\"", "HttpVersion"); FTemplate = step1.Append(step2).Append(step3) .Else( (str, row) => { throw new Exception("Couldn't parse: " + str); } ) .Seal(); }
public void SimpleStringPerf() { // THIS TEST IS EXPECTED TO FAIL // String performance in the hand written case is *very good*, if you // can gin up better code for this case in the FSP, submit a patch. // It's an interesting project. var regex = new Regex(@"([^,]*?),([^,]*?),([^,]*?),([^,]*)", RegexOptions.Compiled); var parserTask = FSBuilder .Take <StringPerfObject>(",", "A") .Take(",", "B") .Take(",", "C") .TakeRest("D") .Seal(); Action ghettoGC = () => { GC.Collect(); Thread.Sleep(100); }; Action <string, StringPerfObject> regexTask = delegate(string str, StringPerfObject obj) { var matches = regex.Match(str); obj.A = matches.Groups[1].Value; obj.B = matches.Groups[2].Value; obj.C = matches.Groups[3].Value; obj.D = matches.Groups[4].Value; }; Action <string, StringPerfObject> handTask = delegate(string str, StringPerfObject obj) { int a = str.IndexOf(','); obj.A = str.Substring(0, a); int b = str.IndexOf(',', a + 1); obj.B = str.Substring(a + 1, b - (a + 1)); int c = str.IndexOf(',', b + 1); obj.C = str.Substring(b + 1, c - (b + 1)); obj.D = str.Substring(c + 1, str.Length - (c + 1)); }; var rand = new Random(); var data = new List <string>(); for (int i = 0; i < 1000000; i++) { data.Add(Guid.NewGuid() + "," + Guid.NewGuid() + "," + Guid.NewGuid() + "," + Guid.NewGuid()); } // Equivalence check foreach (var str in data) { var o1 = new StringPerfObject(); var o2 = new StringPerfObject(); var o3 = new StringPerfObject(); parserTask(str, o1); regexTask(str, o2); handTask(str, o3); if (o1.A != o2.A || o2.A != o3.A) { throw new Exception(); } if (o1.B != o2.B || o2.B != o3.B) { throw new Exception(); } if (o1.C != o2.C || o2.C != o3.C) { throw new Exception(); } if (o1.D != o2.D || o2.D != o3.D) { throw new Exception(); } } var results = new Dictionary <int, List <long> >(); results[0] = new List <long>(); // regex results[1] = new List <long>(); // hand results[2] = new List <long>(); // parser var timer = new Stopwatch(); var speedObj = new StringPerfObject(); for (int i = 0; i < 5; i++) { ghettoGC(); timer.Restart(); foreach (var str in data) { regexTask(str, speedObj); } timer.Stop(); results[0].Add(timer.ElapsedMilliseconds); ghettoGC(); timer.Restart(); foreach (var str in data) { handTask(str, speedObj); } timer.Stop(); results[1].Add(timer.ElapsedMilliseconds); ghettoGC(); timer.Restart(); foreach (var str in data) { parserTask(str, speedObj); } timer.Stop(); results[2].Add(timer.ElapsedMilliseconds); } var medianRegex = results[0].OrderBy(o => o).ElementAt(results[0].Count / 2); var medianHand = results[1].OrderBy(o => o).ElementAt(results[1].Count / 2); var medianParser = results[2].OrderBy(o => o).ElementAt(results[2].Count / 2); Assert.IsTrue(medianRegex > medianHand, "Regex faster than hand rolled; invalid test"); Assert.IsTrue(medianHand > medianParser, "Hand [" + medianHand + "] faster than generated [" + medianParser + "]; bad parser"); }
public void SimpleIntPerf() { var regex = new Regex(@"(\d+),(\d+),(\d+),(\d+)", RegexOptions.Compiled); var parserTask = FSBuilder .Take <IntPerfObject>(",", "A") .Take(",", "B") .Take(",", "C") .TakeRest("D") .Seal(); Action ghettoGC = () => { GC.Collect(); Thread.Sleep(100); }; Action <string, IntPerfObject> regexTask = delegate(string str, IntPerfObject obj) { var matches = regex.Match(str); obj.A = int.Parse(matches.Groups[1].Value); obj.B = int.Parse(matches.Groups[2].Value); obj.C = int.Parse(matches.Groups[3].Value); obj.D = int.Parse(matches.Groups[4].Value); }; Action <string, IntPerfObject> handTask = delegate(string str, IntPerfObject obj) { int a = str.IndexOf(','); obj.A = int.Parse(str.Substring(0, a)); int b = str.IndexOf(',', a + 1); obj.B = int.Parse(str.Substring(a + 1, b - (a + 1))); int c = str.IndexOf(',', b + 1); obj.C = int.Parse(str.Substring(b + 1, c - (b + 1))); obj.D = int.Parse(str.Substring(c + 1, str.Length - (c + 1))); }; var rand = new Random(); var data = new List <string>(); for (int i = 0; i < 1000000; i++) { data.Add(rand.Next() + "," + rand.Next() + "," + rand.Next() + "," + rand.Next()); } // Equivalence check foreach (var str in data) { var o1 = new IntPerfObject(); var o2 = new IntPerfObject(); var o3 = new IntPerfObject(); parserTask(str, o1); regexTask(str, o2); handTask(str, o3); if (o1.A != o2.A || o2.A != o3.A) { throw new Exception(); } if (o1.B != o2.B || o2.B != o3.B) { throw new Exception(); } if (o1.C != o2.C || o2.C != o3.C) { throw new Exception(); } if (o1.D != o2.D || o2.D != o3.D) { throw new Exception(); } } var results = new Dictionary <int, List <long> >(); results[0] = new List <long>(); // regex results[1] = new List <long>(); // hand results[2] = new List <long>(); // parser var timer = new Stopwatch(); var speedObj = new IntPerfObject(); for (int i = 0; i < 5; i++) { ghettoGC(); timer.Restart(); foreach (var str in data) { regexTask(str, speedObj); } timer.Stop(); results[0].Add(timer.ElapsedMilliseconds); ghettoGC(); timer.Restart(); foreach (var str in data) { handTask(str, speedObj); } timer.Stop(); results[1].Add(timer.ElapsedMilliseconds); ghettoGC(); timer.Restart(); foreach (var str in data) { parserTask(str, speedObj); } timer.Stop(); results[2].Add(timer.ElapsedMilliseconds); } var medianRegex = results[0].OrderBy(o => o).ElementAt(results[0].Count / 2); var medianHand = results[1].OrderBy(o => o).ElementAt(results[1].Count / 2); var medianParser = results[2].OrderBy(o => o).ElementAt(results[2].Count / 2); Assert.IsTrue(medianRegex > medianHand); Assert.IsTrue(medianHand > medianParser); }