public async Task CanUploadToDirectAndLatestWithLongOptions()
        {
            // Arrange
            using (var tc = new TestContext(_output))
            {
                // Act
                var actual = tc.ExecuteCommand(
                    new[]
                    {
                        "--connection-string", tc.ConnectionString,
                        "--container", tc.Container,
                        "--path-format", tc.PathFormat
                    },
                    tc.Content);

                // Assert
                await tc.VerifyContentAsync(actual, direct: true, latest: true);
            }
        }
        public void WritesHelpTextWithShortOptions()
        {
            // Arrange
            using (var tc = new TestContext(_output))
            {
                // Act
                var actual = tc.ExecuteCommand(
                    new[] { "-h" },
                    tc.Content);

                // Assert
                Assert.Equal(CommandStatus.Exited, actual.Status);
                Assert.Equal(0, actual.ExitCode);
                Assert.Contains("Usage: ToStorage [options]", actual.Output);
            }
        }
        public void RequiresContainerOption()
        {
            // Arrange
            using (var tc = new TestContext(_output))
            {
                // Act
                var actual = tc.ExecuteCommand(
                    new[]
                    {
                        "--connection-string", tc.ConnectionString,
                        "--path-format", tc.PathFormat
                    },
                    tc.Content);

                // Assert
                Assert.Equal(CommandStatus.Exited, actual.Status);
                Assert.Equal(1, actual.ExitCode);
                Assert.Contains("Error: required option -c, --container is missing.", actual.Error);
            }
        }
        public void RequiresConnectionStringAndContainerOptions()
        {
            // Arrange
            using (var tc = new TestContext(_output))
            {
                // Act
                var actual = tc.ExecuteCommand(
                    Enumerable.Empty<string>(),
                    tc.Content);

                // Assert
                Assert.Equal(CommandStatus.Exited, actual.Status);
                Assert.Equal(1, actual.ExitCode);
                Assert.Contains("Error: required option -s, --connection-string is missing.", actual.Error);
                Assert.Contains("Error: required option -c, --container is missing.", actual.Error);
            }
        }
        public async Task HasDefaultPathFormat()
        {
            // Arrange
            using (var tc = new TestContext(_output))
            {
                var minTimestamp = DateTimeOffset.UtcNow;

                // Act
                var actual = tc.ExecuteCommand(
                    new[]
                    {
                        "-s", tc.ConnectionString,
                        "-c", tc.Container
                    },
                    tc.Content);

                // Assert
                var maxTimestamp = DateTimeOffset.UtcNow;

                var result = await tc.VerifyContentAsync(actual, direct: true, latest: true);

                var directFileName = result.DirectUri.ToString().Split('/').Last();
                Assert.EndsWith(".txt", directFileName);
                var unparsedTimestamp = directFileName.Substring(0, directFileName.Length - ".txt".Length);
                var timestampLocal = DateTime.ParseExact(unparsedTimestamp, "yyyy.MM.dd.HH.mm.ss.fffffff", CultureInfo.InvariantCulture);
                var timestamp = new DateTimeOffset(timestampLocal, TimeSpan.Zero);
                Assert.True(timestamp >= minTimestamp, "The timestamp should be greater than or equal to the minimum.");
                Assert.True(timestamp <= maxTimestamp, "The timestamp should be less than or equal to the maximum.");

                Assert.EndsWith("/latest.txt", result.LatestUri.ToString());
            }
        }
        public async Task AllowsBothDirectAndLatestUploadToBeDisabled()
        {
            // Arrange
            using (var tc = new TestContext(_output))
            {
                // Act
                var actual = tc.ExecuteCommand(
                    new[]
                    {
                        "-s", tc.ConnectionString,
                        "-c", tc.Container,
                        "-f", tc.PathFormat,
                        "--no-direct",
                        "--no-latest"
                    },
                    tc.Content);

                // Assert
                await tc.VerifyContentAsync(actual, direct: false, latest: false);
            }
        }
        public async Task CanSetContentTypeWithLongOptions()
        {
            // Arrange
            using (var tc = new TestContext(_output))
            {
                tc.Content = "{\"foo\": 5}";
                tc.ContentType = "application/json";

                // Act
                var actual = tc.ExecuteCommand(
                    new[]
                    {
                        "--connection-string", tc.ConnectionString,
                        "--container", tc.Container,
                        "--path-format", tc.PathFormat,
                        "--content-type", tc.ContentType
                    },
                    tc.Content);

                // Assert
                await tc.VerifyContentAsync(actual, direct: true, latest: true);
            }
        }
        public async Task CanUploadOnlyLatestWithUniqueOnlyOption()
        {
            // Arrange
            using (var tc = new TestContext(_output))
            {
                tc.Content = "something";
                var initial = tc.ExecuteCommand(
                    new[]
                    {
                        "-s", tc.ConnectionString,
                        "-c", tc.Container,
                        "-f", tc.PathFormat,
                        "--no-direct"
                    },
                    tc.Content);

                tc.Content = "something else";

                // Act
                var actual = tc.ExecuteCommand(
                    new[]
                    {
                        "--connection-string", tc.ConnectionString,
                        "--container", tc.Container,
                        "--path-format", tc.PathFormat,
                        "--no-direct",
                        "--only-unique"
                    },
                    tc.Content);

                // Assert
                await tc.VerifyContentAsync(actual, direct: false, latest: true);
                Assert.Contains("Gettings the existing latest... different! The provided content will be uploaded.", actual.Output);
            }
        }
        public void CanUploadOnlyWhenUniqueWithLongOptions()
        {
            // Arrange
            using (var tc = new TestContext(_output))
            {
                var initial = tc.ExecuteCommand(
                    new[]
                    {
                        "-s", tc.ConnectionString,
                        "-c", tc.Container,
                        "-f", tc.PathFormat
                    },
                    tc.Content);

                // Act
                var actual = tc.ExecuteCommand(
                    new[]
                    {
                        "--connection-string", tc.ConnectionString,
                        "--container", tc.Container,
                        "--path-format", tc.PathFormat,
                        "--only-unique"
                    },
                    tc.Content);

                // Assert
                tc.VerifyCommandResult(actual);
                Assert.Equal("Gettings the existing latest... exactly the same! No upload required.", actual.Output.TrimEnd());
            }
        }