private static ZumoTest CreateSetupSchemaTest() { return(new ZumoTest("Setup dynamic schema", async delegate(ZumoTest test) { var client = ZumoTestGlobals.Instance.Client; Random rndGen = new Random(1); try { if (!ZumoTestGlobals.Instance.IsNetRuntime) { var table = client.GetTable <RoundTripTableItem>(); RoundTripTableItem item = new RoundTripTableItem { Bool1 = true, ComplexType1 = new ComplexType[] { new ComplexType(rndGen) }, ComplexType2 = new ComplexType2(rndGen), Date1 = DateTime.Now, Double1 = 123.456, EnumType = EnumType.First, Int1 = 1, Long1 = 1, String1 = "hello", }; await table.InsertAsync(item); test.AddLog("Inserted item to create schema on the int id table"); } var table2 = client.GetTable <StringIdRoundTripTableItem>(); var item2 = new StringIdRoundTripTableItem { Bool = true, Name = "hello", Number = 1.23, ComplexType = "a b c".Split(), Date = DateTime.UtcNow }; await table2.InsertAsync(item2); test.AddLog("Inserted item to create schema on the string id table"); return true; } catch (Exception ex) { test.AddLog("Error setting up the dynamic schema: {0}", ex); return false; } }, ZumoTestGlobals.RuntimeFeatureNames.INT_ID_TABLES, ZumoTestGlobals.RuntimeFeatureNames.STRING_ID_TABLES)); }
public static ZumoTestGroup CreateTests() { ZumoTestGroup result = new ZumoTestGroup("Round trip tests"); result.AddTest(CreateSetupSchemaTest()); DateTime now = DateTime.UtcNow; int seed = now.Year * 10000 + now.Month * 100 + now.Day; Random rndGen = new Random(seed); result.AddTest(CreateSimpleTypedRoundTripTest("String: Empty", RoundTripTestType.String, "")); result.AddTest(CreateSimpleTypedRoundTripTest("String: null", RoundTripTestType.String, null)); result.AddTest(CreateSimpleTypedRoundTripTest("String: random value", RoundTripTestType.String, Util.CreateSimpleRandomString(rndGen, 10))); result.AddTest(CreateSimpleTypedRoundTripTest("String: large (1000 characters)", RoundTripTestType.String, new string('*', 1000))); result.AddTest(CreateSimpleTypedRoundTripTest("String: large (64k+1 characters)", RoundTripTestType.String, new string('*', 65537))); result.AddTest(CreateSimpleTypedRoundTripTest("String: non-ASCII characters - Latin", RoundTripTestType.String, "ãéìôü ÇñÑ")); result.AddTest(CreateSimpleTypedRoundTripTest("String: non-ASCII characters - Arabic", RoundTripTestType.String, "الكتاب على الطاولة")); result.AddTest(CreateSimpleTypedRoundTripTest("String: non-ASCII characters - Chinese", RoundTripTestType.String, "这本书在桌子上")); result.AddTest(CreateSimpleTypedRoundTripTest("String: non-ASCII characters - Chinese 2", RoundTripTestType.String, "⒈①Ⅻㄨㄩ 啊阿鼾齄 丂丄狚狛 狜狝﨨﨩 ˊˋ˙–〇 㐀㐁䶴䶵")); result.AddTest(CreateSimpleTypedRoundTripTest("String: non-ASCII characters - Japanese", RoundTripTestType.String, "本は机の上に")); result.AddTest(CreateSimpleTypedRoundTripTest("String: non-ASCII characters - Hebrew", RoundTripTestType.String, "הספר הוא על השולחן")); result.AddTest(CreateSimpleTypedRoundTripTest("String: non-ASCII characters - Russian", RoundTripTestType.String, "Книга лежит на столе")); result.AddTest(CreateSimpleTypedRoundTripTest("Date: now", RoundTripTestType.Date, Util.TrimSubMilliseconds(DateTime.Now))); result.AddTest(CreateSimpleTypedRoundTripTest("Date: now (UTC)", RoundTripTestType.Date, Util.TrimSubMilliseconds(DateTime.UtcNow))); result.AddTest(CreateSimpleTypedRoundTripTest("Date: null", RoundTripTestType.Date, null)); result.AddTest(CreateSimpleTypedRoundTripTest("Date: min date", RoundTripTestType.Date, DateTime.MinValue)); result.AddTest(CreateSimpleTypedRoundTripTest("Date: specific date, before unix 0", RoundTripTestType.Date, new DateTime(1901, 1, 1))); result.AddTest(CreateSimpleTypedRoundTripTest("Date: specific date, after unix 0", RoundTripTestType.Date, new DateTime(2000, 12, 31))); result.AddTest(CreateSimpleTypedRoundTripTest("Bool: true", RoundTripTestType.Bool, true)); result.AddTest(CreateSimpleTypedRoundTripTest("Bool: false", RoundTripTestType.Bool, false)); result.AddTest(CreateSimpleTypedRoundTripTest("Bool: null", RoundTripTestType.Bool, null)); result.AddTest(CreateSimpleTypedRoundTripTest("Int: zero", RoundTripTestType.Int, 0)); result.AddTest(CreateSimpleTypedRoundTripTest("Int: MaxValue", RoundTripTestType.Int, int.MaxValue)); result.AddTest(CreateSimpleTypedRoundTripTest("Int: MinValue", RoundTripTestType.Int, int.MinValue)); result.AddTest(CreateSimpleTypedRoundTripTest("Long: zero", RoundTripTestType.Long, 0L)); long maxAllowedValue = 0x0020000000000000; long minAllowedValue = 0; unchecked { minAllowedValue = (long)0xFFE0000000000000; } result.AddTest(CreateSimpleTypedRoundTripTest("Long: max allowed", RoundTripTestType.Long, maxAllowedValue)); result.AddTest(CreateSimpleTypedRoundTripTest("Long: min allowed", RoundTripTestType.Long, minAllowedValue)); long largePositiveValue = maxAllowedValue - rndGen.Next(0, int.MaxValue); long largeNegativeValue = minAllowedValue + rndGen.Next(0, int.MaxValue); result.AddTest(CreateSimpleTypedRoundTripTest("Long: large value, less than max allowed (" + largePositiveValue + ")", RoundTripTestType.Long, largePositiveValue)); result.AddTest(CreateSimpleTypedRoundTripTest("Long: large negative value, more than min allowed (" + largeNegativeValue + ")", RoundTripTestType.Long, largeNegativeValue)); result.AddTest(CreateSimpleTypedRoundTripTest <InvalidOperationException>("(Neg) Long: more than max allowed", RoundTripTestType.Long, maxAllowedValue + 1)); result.AddTest(CreateSimpleTypedRoundTripTest <InvalidOperationException>("(Neg) Long: less than min allowed", RoundTripTestType.Long, minAllowedValue - 1)); result.AddTest(CreateSimpleTypedRoundTripTest("Enum (with JSON converter): simple value", RoundTripTestType.Enum, EnumType.Second)); result.AddTest(CreateSimpleTypedRoundTripTest( "Complex type (custom table serialization): simple value", RoundTripTestType.ComplexWithCustomSerialization, new ComplexType2(rndGen))); result.AddTest(CreateSimpleTypedRoundTripTest( "Complex type (custom table serialization): null", RoundTripTestType.ComplexWithCustomSerialization, null)); result.AddTest(CreateSimpleTypedRoundTripTest( "Complex type (converter): empty array", RoundTripTestType.ComplexWithConverter, new ComplexType[0])); result.AddTest(CreateSimpleTypedRoundTripTest( "Complex type (converter): 1-element array", RoundTripTestType.ComplexWithConverter, new ComplexType[] { new ComplexType(rndGen) })); result.AddTest(CreateSimpleTypedRoundTripTest( "Complex type (converter): multi-element array", RoundTripTestType.ComplexWithConverter, new ComplexType[] { new ComplexType(rndGen), null, new ComplexType(rndGen) })); result.AddTest(CreateSimpleTypedRoundTripTest( "Complex type (converter): null array", RoundTripTestType.ComplexWithConverter, null)); result.AddTest( CreateSimpleTypedRoundTripTest <ArgumentException>( "(Neg) Insert item with non-default id", RoundTripTestType.Id, 1)); var uniqueId = Environment.TickCount.ToString(CultureInfo.InvariantCulture); var differentIds = new Dictionary <string, string> { { "none", null }, { "ascii", "myid" }, { "latin", "ãéìôü ÇñÑ" }, { "arabic", "الكتاب على الطاولة" }, { "chinese", "这本书在桌子上" }, { "hebrew", "הספר הוא על השולחן" } }; foreach (var name in differentIds.Keys) { var id = differentIds[name]; result.AddTest(new ZumoTest("String id - " + name + " id on insert", async delegate(ZumoTest test) { var item = new StringIdRoundTripTableItem(rndGen); var itemId = id; if (itemId != null) { itemId = itemId + "-" + Guid.NewGuid().ToString(); } item.Id = itemId; var client = ZumoTestGlobals.Instance.Client; var table = client.GetTable <StringIdRoundTripTableItem>(); await table.InsertAsync(item); test.AddLog("Inserted item with id = {0}", item.Id); if (id != null && itemId != item.Id) { test.AddLog("Error, id passed to insert is not the same ({0}) as the id returned by the server ({1})", id, item.Id); return(false); } var retrieved = await table.LookupAsync(item.Id); test.AddLog("Retrieved item: {0}", retrieved); if (!item.Equals(retrieved)) { test.AddLog("Error, round-tripped item is different"); return(false); } test.AddLog("Now trying to insert an item with an existing id (should fail)"); try { await table.InsertAsync(new StringIdRoundTripTableItem { Id = retrieved.Id, Name = "should not work" }); test.AddLog("Error, insertion succeeded but it should have failed"); return(false); } catch (MobileServiceInvalidOperationException e) { test.AddLog("Caught expected exception: {0}", e); } test.AddLog("Cleaning up..."); await table.DeleteAsync(retrieved); test.AddLog("Removed the inserted item"); return(true); })); } var invalidIds = new string[] { ".", "..", "control\u0010characters", "large id " + new string('*', 260) }; foreach (var id in invalidIds) { result.AddTest(new ZumoTest("(Neg) string id - insert with invalid id: " + (id.Length > 30 ? (id.Substring(0, 30) + "...") : id), async delegate(ZumoTest test) { var client = ZumoTestGlobals.Instance.Client; var table = client.GetTable <StringIdRoundTripTableItem>(); var item = new StringIdRoundTripTableItem { Id = id, Name = "should not work" }; try { await table.InsertAsync(item); test.AddLog("Error, insert operation should have failed. Inserted id = {0}", item.Id); return(false); } catch (InvalidOperationException ex) { test.AddLog("Caught expected exception: {0}", ex); return(true); } })); } // Untyped overloads result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped String: Empty", "string1", "")); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped String: null", "string1", null)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped String: random value", "string1", Util.CreateSimpleRandomString(rndGen, 10))); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped String: large (1000 characters)", "string1", new string('*', 1000))); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped String: large (64k+1 characters)", "string1", new string('*', 65537))); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped String: non-ASCII characters - Latin", "string1", "ãéìôü ÇñÑ")); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped String: non-ASCII characters - Arabic", "string1", "الكتاب على الطاولة")); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped String: non-ASCII characters - Chinese", "string1", "这本书在桌子上")); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped String: non-ASCII characters - Chinese 2", "string1", "⒈①Ⅻㄨㄩ 啊阿鼾齄 丂丄狚狛 狜狝﨨﨩 ˊˋ˙–〇 㐀㐁䶴䶵")); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped String: non-ASCII characters - Japanese", "string1", "本は机の上に")); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped String: non-ASCII characters - Hebrew", "string1", "הספר הוא על השולחן")); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped String: non-ASCII characters - Russian", "string1", "Книга лежит на столе")); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Date: now", "date1", Util.TrimSubMilliseconds(DateTime.Now))); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Date: now (UTC)", "date1", Util.TrimSubMilliseconds(DateTime.UtcNow))); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Date: null", "date1", null)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Date: min date", "date1", DateTime.MinValue)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Date: specific date, before unix 0", "date1", new DateTime(1901, 1, 1))); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Date: specific date, after unix 0", "date1", new DateTime(2000, 12, 31))); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Bool: true", "bool1", true)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Bool: false", "bool1", false)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Bool: null", "bool1", null)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Int: zero", "int1", 0)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Int: MaxValue", "int1", int.MaxValue)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Int: MinValue", "int1", int.MinValue)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Long: zero", "long1", 0L)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Long: max allowed", "long1", maxAllowedValue)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Long: min allowed", "long1", minAllowedValue)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Long: more than max allowed (positive) for typed", "long1", maxAllowedValue + 1)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped Long: more than max allowed (negative) for typed", "long1", minAllowedValue - 1)); result.AddTest(CreateSimpleUntypedRoundTripTest("Untyped complex (object): simple value", JObject.Parse(@"{""complexType2"":{""Name"":""John Doe"",""Age"":33,""Friends"":[""Jane Roe"", ""John Smith""]}}"))); result.AddTest(CreateSimpleUntypedRoundTripTest( "Untyped complex (object): null", JObject.Parse(@"{""complexType2"":null}"))); result.AddTest(CreateSimpleUntypedRoundTripTest( "Untyped complex (array): simple value", JObject.Parse(@"{""complexType1"":[{""Name"":""Scooby"",""Age"":10}, {""Name"":""Shaggy"",""Age"":19}]}"))); result.AddTest(CreateSimpleUntypedRoundTripTest( "Untyped complex (array): empty array", JObject.Parse(@"{""complexType1"":[]}"))); result.AddTest(CreateSimpleUntypedRoundTripTest( "Untyped complex (array): null", JObject.Parse(@"{""complexType1"":null}"))); result.AddTest(CreateSimpleUntypedRoundTripTest( "Untyped complex (array): array with null elements", JObject.Parse(@"{""complexType1"":[{""Name"":""Scooby"",""Age"":10}, null, {""Name"":""Shaggy"",""Age"":19}]}"))); result.AddTest(CreateSimpleUntypedRoundTripTest <ArgumentException>("(Neg) Insert item with non-default 'id' property", JObject.Parse("{\"id\":1,\"value\":2}"), false)); result.AddTest(CreateSimpleUntypedRoundTripTest <ArgumentException>("(Neg) Insert item with non-default 'ID' property", JObject.Parse("{\"ID\":1,\"value\":2}"), false)); result.AddTest(CreateSimpleUntypedRoundTripTest <ArgumentException>("(Neg) Insert item with non-default 'Id' property", JObject.Parse("{\"Id\":1,\"value\":2}"), false)); uniqueId = (Environment.TickCount + 1).ToString(CultureInfo.InvariantCulture); var obj = new StringIdRoundTripTableItem(rndGen); var properties = new Dictionary <string, object> { { "name", obj.Name }, { "date1", obj.Date }, { "bool", obj.Bool }, { "number", obj.Number }, { "complex", obj.ComplexType }, }; foreach (var name in differentIds.Keys) { foreach (var property in properties.Keys) { var testName = "String id (untyped) - " + name + " id on insert - " + property; var item = JObjectFromValue(property, properties[property]); var id = differentIds[name]; if (id != null) { item.Add("id", id + "-" + property + "-" + Guid.NewGuid().ToString()); } result.AddTest(CreateSimpleUntypedRoundTripTest(testName, item, true)); } } foreach (var id in invalidIds) { var testName = "(Neg) [string id] Insert item with invalid 'id' property: " + (id.Length > 30 ? (id.Substring(0, 30) + "...") : id); JObject jo = new JObject(new JProperty("id", id), new JProperty("name", "should not work")); result.AddTest(CreateSimpleUntypedRoundTripTest <InvalidOperationException>(testName, jo, true)); } return(result); }