public static Uri AsRelativeUri(this string @this, AppFileListingOptions options,
            IEnumerable<AppIdentifier> context = null)
        {
            var parameters = new List<string>();

            parameters.AddRange(options.Filter.Select(f => $"f={WebUtility.UrlEncode(f)}"));

            if (options.From.HasValue)
                parameters.Add($"_from={WebUtility.UrlEncode(options.From.ToString())}");

            if (options.To.HasValue)
                parameters.Add($"_to={WebUtility.UrlEncode(options.To.ToString())}");

            if (options.Content)
                parameters.Add("content=true");

            if (context != null)
                parameters.Add("context=" + string.Join("/", context));

            return AsRelativeUri(@this, parameters);
        }
        public async Task List_files_with_all_parameters()
        {
            // Arrange
            var files = new[]
            {
                new File("foo.txt", "abc", 8, "some foo", ContentEncoding.Utf8),
                new File("bar.txt", "def", 8, "some bar", ContentEncoding.Utf8)
            };
            var expected = new PagedResponse<File>(files, new RangeResponse(1, 2, 2));
            var options = new AppFileListingOptions(new[] {"a", "b"}, 1, 2, true);
            var connector = Mock.Of<IGalleryConnector>()
                .ThatGetsJson("/acme/sandboxes/john/vanilla/1.2.3/files/front?f=a&f=b&_from=1&_to=2&content=true",
                    expected);
            var client = new SandboxesClient(connector);

            // Act
            var result = await client.ListFilesAsync("acme", "john", "vanilla", "1.2.3", "front", options, None);

            // Assert
            result.ShouldBe(expected);
        }
        public async Task<PagedResponse<File>> ListFilesAsync(string vendor, string sandbox, string app, string version,
            string service, AppFileListingOptions options, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(vendor))
                throw new ArgumentNullException(nameof(vendor), $"{nameof(vendor)} cannot be null or white space");

            if (string.IsNullOrWhiteSpace(sandbox))
                throw new ArgumentNullException(nameof(sandbox), $"{nameof(sandbox)} cannot be null or white space");

            if (string.IsNullOrWhiteSpace(app))
                throw new ArgumentNullException(nameof(app), $"{nameof(app)} cannot be null or white space");

            if (string.IsNullOrWhiteSpace(service))
                throw new ArgumentNullException(nameof(service), $"{nameof(service)} cannot be null or white space");

            options = options ?? AppFileListingOptions.Default;
            try
            {
                var url = Routes.Files(vendor, sandbox, app, version, service).AsRelativeUri(options);
                return await _connector.GetJsonAsync<PagedResponse<File>>(url, null, cancellationToken)
                    .ConfigureAwait(false);
            }
            catch (ResourceNotFoundException e)
            {
                throw e.WithSandbox(vendor, sandbox, app);
            }
        }
        public async Task<PagedResponse<File>> ListFilesAsync(string account, string workspace, AppIdentifier app,
            IEnumerable<AppIdentifier> context, string service, AppFileListingOptions options,
            CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(account))
                throw new ArgumentNullException(nameof(account), $"{nameof(account)} cannot be null or white space");

            if (string.IsNullOrWhiteSpace(workspace))
                throw new ArgumentNullException(nameof(workspace), $"{nameof(workspace)} cannot be null or white space");

            if (app == null)
                throw new ArgumentNullException(nameof(app));

            if (string.IsNullOrWhiteSpace(service))
                throw new ArgumentNullException(nameof(service), $"{nameof(service)} cannot be null or white space");

            options = options ?? AppFileListingOptions.Default;
            var url = Routes.Files(account, workspace, app, service).AsRelativeUri(options, context);
            try
            {
                return await _connector.GetJsonAsync<PagedResponse<File>>(url, null, cancellationToken)
                    .ConfigureAwait(false);
            }
            catch (ResourceNotFoundException e)
            {
                throw e.WithWorkspace(account, workspace, app, service);
            }
        }