public void You_cannot_log_a_finished_operation_when_the_last_operation_has_already_been_logged_as_finished()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Throws <InvalidOperationException>(() => sut.OperationFinished(new FakeOperation(), TimeSpan.Zero));
            }
        }
        public void Logging_an_operation_starting_and_finishing_within_another_operation_start_and_finish_writes_the_inner_operation_type_name_nested_in_braces_to_the_output()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  FakeOperation [duration: 0ms]{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void Behaviors_are_correctly_indented_after_a_sibling_operation()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.BehaviorWasApplied(new FakeOperation(), new FakeOperationBehavior(), "DESCRIPTION");
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  FakeOperation [duration: 0ms]{NL}{NL}  FakeOperationBehavior: DESCRIPTION{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void Failures_are_correctly_indented_after_a_sibling_operation()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.OperationFailed(new FakeOperation(), new InvalidOperationException("MESSAGE"));
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  FakeOperation [duration: 0ms]{NL}{NL}  Error [InvalidOperationException]: MESSAGE{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void Logging_multiple_operation_on_the_same_level_adds_a_seperation_line_between_them()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  FakeOperation [duration: 0ms]{NL}{NL}  FakeOperation [duration: 0ms]{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void Nested_operations_are_correctly_indented()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationStarted(new FakeOperation());
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  FakeOperation {{{NL}    FakeOperation [duration: 0ms]{NL}  }} [duration: 0ms]{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void You_cannot_log_a_finished_operation_without_a_started_operation()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                Assert.Throws <InvalidOperationException>(() => sut.OperationFinished(new FakeOperation(), TimeSpan.Zero));
            }
        }
        public void You_cannot_log_a_behavior_when_the_last_operation_has_been_logged_as_finished()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Throws <InvalidOperationException>(() => sut.BehaviorWasApplied(new FakeOperation(), new FakeOperationBehavior(), "DESCRIPTION"));
            }
        }
        public void The_execution_duration_is_added_in_milliseconds()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.FromMilliseconds(15));

                Assert.Equal("FakeOperation [duration: 15ms]", sw.ToString());
            }
        }
        public void The_execution_duration_is_added_in_milliseconds()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.FromMilliseconds(15));

                Assert.Equal("FakeOperation [duration: 15ms]", sw.ToString());
            }
        }
        public void Logging_an_operation_start_and_finish_writes_the_operation_type_to_the_output()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal("FakeOperation [duration: 0ms]", sw.ToString());
            }
        }
        public void Logging_an_operation_start_and_finish_writes_the_operation_type_to_the_output()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal("FakeOperation [duration: 0ms]", sw.ToString());
            }
        }
        public void Log_durations_are_properly_formatted_according_to_cultures_using_comma_as_thousands_seperator()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);
                Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.FromMilliseconds(1500000));

                Assert.Equal("FakeOperation [duration: 1,500,000ms]", sw.ToString());
            }
        }
        public void Behaviors_are_logged_nested_between_braces()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.BehaviorWasApplied(new FakeOperation(), new FakeOperationBehavior(), "DESCRIPTION");
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  FakeOperationBehavior: DESCRIPTION{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void Failures_are_logged_nested_between_braces()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationFailed(new FakeOperation(), new InvalidOperationException("MESSAGE"));
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  Error [InvalidOperationException]: MESSAGE{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void Log_durations_are_properly_formatted_according_to_cultures_using_period_as_thousands_seperator()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);
                Thread.CurrentThread.CurrentCulture = new CultureInfo("da-DK");

                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.FromMilliseconds(1500000));

                Assert.Equal("FakeOperation [duration: 1.500.000ms]", sw.ToString());
            }
        }
        public void Logging_an_operation_starting_and_finishing_within_another_operation_start_and_finish_writes_the_inner_operation_type_name_nested_in_braces_to_the_output()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  FakeOperation [duration: 0ms]{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void Failures_are_logged_nested_between_braces()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationFailed(new FakeOperation(), new InvalidOperationException("MESSAGE"));
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  Error [InvalidOperationException]: MESSAGE{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void Logging_multiple_operation_on_the_same_level_adds_a_seperation_line_between_them()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  FakeOperation [duration: 0ms]{NL}{NL}  FakeOperation [duration: 0ms]{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void You_cannot_log_a_behavior_when_the_last_operation_has_been_logged_as_finished()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Throws<InvalidOperationException>(() => sut.BehaviorWasApplied(new FakeOperation(), new FakeOperationBehavior(), "DESCRIPTION"));
            }
        }
        public void Nested_operations_are_correctly_indented()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationStarted(new FakeOperation());
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  FakeOperation {{{NL}    FakeOperation [duration: 0ms]{NL}  }} [duration: 0ms]{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void Behaviors_are_correctly_indented_after_a_sibling_operation()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.BehaviorWasApplied(new FakeOperation(), new FakeOperationBehavior(), "DESCRIPTION");
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  FakeOperation [duration: 0ms]{NL}{NL}  FakeOperationBehavior: DESCRIPTION{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void Behaviors_are_logged_nested_between_braces()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.BehaviorWasApplied(new FakeOperation(), new FakeOperationBehavior(), "DESCRIPTION");
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  FakeOperationBehavior: DESCRIPTION{NL}}} [duration: 0ms]", sw.ToString());
            }
        }
        public void You_cannot_log_a_finished_operation_when_the_last_operation_has_already_been_logged_as_finished()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Throws<InvalidOperationException>(() => sut.OperationFinished(new FakeOperation(), TimeSpan.Zero));
            }
        }
        public void You_cannot_log_a_finished_operation_without_a_started_operation()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                Assert.Throws<InvalidOperationException>(() => sut.OperationFinished(new FakeOperation(), TimeSpan.Zero));
            }
        }
        public void Failures_are_correctly_indented_after_a_sibling_operation()
        {
            using (var sw = new StringWriter())
            {
                var sut = new TextWriterWorkflowLogger(sw);

                sut.OperationStarted(new FakeOperation());
                sut.OperationStarted(new FakeOperation());
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);
                sut.OperationFailed(new FakeOperation(), new InvalidOperationException("MESSAGE"));
                sut.OperationFinished(new FakeOperation(), TimeSpan.Zero);

                Assert.Equal($"FakeOperation {{{NL}  FakeOperation [duration: 0ms]{NL}{NL}  Error [InvalidOperationException]: MESSAGE{NL}}} [duration: 0ms]", sw.ToString());
            }
        }