private static ZumoTest CreateJTokenApiTest(ApiPermissions apiPermission, bool isAuthenticated, Random seedGenerator)
        {
            string testName = string.Format(CultureInfo.InvariantCulture, "JToken overload - {0}{1}",
                apiPermission, isAuthenticated ? " (user authenticated)" : "");
            var expecting401 = apiPermission == ApiPermissions.Admin || apiPermission == ApiPermissions.User && !isAuthenticated;
            return new ZumoTest(testName, async delegate(ZumoTest test)
            {
                var client = ZumoTestGlobals.Instance.Client;
                if (apiPermission == ApiPermissions.Public)
                {
                    test.AddLog("Public permission, using a client without an application key");
                    client = new MobileServiceClient(client.ApplicationUri);
                }

                var testResult = true;

                for (int i = 0; i < 10; i++)
                {
                    int seed = seedGenerator.Next();
                    test.AddLog("Test with seed = {0}", seed);
                    Random rndGen = new Random(seed);
                    var method = CreateHttpMethod(rndGen);
                    JToken body = null;
                    if (method.Method != "GET" && method.Method != "DELETE")
                    {
                        if (method.Method == "PATCH" || method.Method == "PUT")
                        {
                            // verbs which require a body
                            body = CreateJson(rndGen, 0, false);
                        }
                        else if (rndGen.Next(4) > 0)
                        {
                            body = CreateJson(rndGen);
                        }
                    }

                    var query = CreateQueryParams(rndGen);

                    JToken apiResult = null;
                    MobileServiceInvalidOperationException exception = null;
                    try
                    {
                        if (body == null && method == HttpMethod.Post && query == null)
                        {
                            test.AddLog("  -> Using the InvokeApiAsync(string) overload");
                            apiResult = await client.InvokeApiAsync(apiNames[apiPermission]);
                        }
                        else if (method == HttpMethod.Post && query == null)
                        {
                            test.AddLog("  -> Using the InvokeApiAsync(string, JToken) overload");
                            apiResult = await client.InvokeApiAsync(apiNames[apiPermission], body);
                        }
                        else if (body == null)
                        {
                            test.AddLog("  -> Using the InvokeApiAsync(string, HttpMethod ({0}), Dictionary<string, string>) overload", method.Method);
                            apiResult = await client.InvokeApiAsync(apiNames[apiPermission], method, query);
                        }
                        else
                        {
                            test.AddLog("  -> Using the InvokeApiAsync(string, JToken, HttpMethod ({0}), Dictionary<string, string>) overload", method.Method);
                            apiResult = await client.InvokeApiAsync(apiNames[apiPermission], body, method, query);
                        }
                    }
                    catch (MobileServiceInvalidOperationException ex)
                    {
                        exception = ex;
                    }

                    if (expecting401 && exception == null)
                    {
                        throw new InvalidOperationException("Test should have failed, but didn't - result = " + apiResult);
                    }

                    if (expecting401)
                    {
                        if (exception.Response.StatusCode == HttpStatusCode.Unauthorized)
                        {
                            test.AddLog("  -> Succeeded");
                        }
                        else
                        {
                            test.AddLog("Unexpected exception: {0}", exception);
                            test.AddLog("Response: {0}", exception.Response);
                            var respBody = await exception.Response.Content.ReadAsStringAsync();
                            test.AddLog("Response body: {0}", respBody);
                            testResult = false;
                            break;
                        }
                    }
                    else
                    {
                        if (exception != null)
                        {
                            test.AddLog("Unexpected exception: {0}", exception);
                            test.AddLog("Response: {0}", exception.Response);
                            var respBody = await exception.Response.Content.ReadAsStringAsync();
                            test.AddLog("Response body: {0}", respBody);
                            testResult = false;
                            break;
                        }

                        JObject expectedResult = new JObject();
                        expectedResult.Add("user", GetUserObject(client));
                        if (query != null && query.Count > 0)
                        {
                            expectedResult.Add("query", GetQueryObject(query));
                        }

                        List<string> errors = new List<string>();
                        if (Util.CompareJson(expectedResult, apiResult, errors))
                        {
                            test.AddLog("  -> Succeeded");
                        }
                        else
                        {
                            test.AddLog("Results are different");
                            foreach (var error in errors)
                            {
                                test.AddLog("{0}", error);
                            }

                            testResult = false;
                            break;
                        }
                    }
                }

                return testResult;
            });
        }
        private static ZumoTest CreateJTokenApiTest(ApiPermissions apiPermission, bool isAuthenticated, Random seedGenerator)
        {
            string testName = string.Format(CultureInfo.InvariantCulture, "JToken overload - {0}{1}",
                                            apiPermission, isAuthenticated ? " (user authenticated)" : "");
            var expecting401 = apiPermission == ApiPermissions.Admin || apiPermission == ApiPermissions.User && !isAuthenticated;

            return(new ZumoTest(testName, async delegate(ZumoTest test)
            {
                var client = ZumoTestGlobals.Instance.Client;
                if (apiPermission == ApiPermissions.Public)
                {
                    test.AddLog("Public permission, using a client without an application key");
                    client = new MobileServiceClient(client.ApplicationUri);
                }

                var testResult = true;

                for (int i = 0; i < 10; i++)
                {
                    int seed = seedGenerator.Next();
                    test.AddLog("Test with seed = {0}", seed);
                    Random rndGen = new Random(seed);
                    var method = CreateHttpMethod(rndGen);
                    JToken body = null;
                    if (method.Method != "GET" && method.Method != "DELETE")
                    {
                        if (method.Method == "PATCH" || method.Method == "PUT")
                        {
                            // verbs which require a body
                            body = CreateJson(rndGen, 0, false);
                        }
                        else if (rndGen.Next(4) > 0)
                        {
                            body = CreateJson(rndGen);
                        }
                    }

                    var query = CreateQueryParams(rndGen);

                    JToken apiResult = null;
                    MobileServiceInvalidOperationException exception = null;
                    try
                    {
                        if (body == null && method == HttpMethod.Post && query == null)
                        {
                            test.AddLog("  -> Using the InvokeApiAsync(string) overload");
                            apiResult = await client.InvokeApiAsync(apiNames[apiPermission]);
                        }
                        else if (method == HttpMethod.Post && query == null)
                        {
                            test.AddLog("  -> Using the InvokeApiAsync(string, JToken) overload");
                            apiResult = await client.InvokeApiAsync(apiNames[apiPermission], body);
                        }
                        else if (body == null)
                        {
                            test.AddLog("  -> Using the InvokeApiAsync(string, HttpMethod ({0}), Dictionary<string, string>) overload", method.Method);
                            apiResult = await client.InvokeApiAsync(apiNames[apiPermission], method, query);
                        }
                        else
                        {
                            test.AddLog("  -> Using the InvokeApiAsync(string, JToken, HttpMethod ({0}), Dictionary<string, string>) overload", method.Method);
                            apiResult = await client.InvokeApiAsync(apiNames[apiPermission], body, method, query);
                        }
                    }
                    catch (MobileServiceInvalidOperationException ex)
                    {
                        exception = ex;
                    }

                    if (expecting401 && exception == null)
                    {
                        throw new InvalidOperationException("Test should have failed, but didn't - result = " + apiResult);
                    }

                    if (expecting401)
                    {
                        if (exception.Response.StatusCode == HttpStatusCode.Unauthorized)
                        {
                            test.AddLog("  -> Succeeded");
                        }
                        else
                        {
                            test.AddLog("Unexpected exception: {0}", exception);
                            test.AddLog("Response: {0}", exception.Response);
                            var respBody = await exception.Response.Content.ReadAsStringAsync();
                            test.AddLog("Response body: {0}", respBody);
                            testResult = false;
                            break;
                        }
                    }
                    else
                    {
                        if (exception != null)
                        {
                            test.AddLog("Unexpected exception: {0}", exception);
                            test.AddLog("Response: {0}", exception.Response);
                            var respBody = await exception.Response.Content.ReadAsStringAsync();
                            test.AddLog("Response body: {0}", respBody);
                            testResult = false;
                            break;
                        }

                        JObject expectedResult = new JObject();
                        expectedResult.Add("user", GetUserObject(client));
                        if (query != null && query.Count > 0)
                        {
                            expectedResult.Add("query", GetQueryObject(query));
                        }

                        List <string> errors = new List <string>();
                        if (Util.CompareJson(expectedResult, apiResult, errors))
                        {
                            test.AddLog("  -> Succeeded");
                        }
                        else
                        {
                            test.AddLog("Results are different");
                            foreach (var error in errors)
                            {
                                test.AddLog("{0}", error);
                            }

                            testResult = false;
                            break;
                        }
                    }
                }

                return testResult;
            }));
        }