diff --git a/src/spectator/example.cr b/src/spectator/example.cr index c210d2b..b048469 100644 --- a/src/spectator/example.cr +++ b/src/spectator/example.cr @@ -16,11 +16,9 @@ module Spectator # Indicates whether the example already ran. getter? finished : Bool = false - # Retrieves the result of the last time the example ran. - def result : Result - # TODO: Set to pending immediately (requires circular dependency between Example <-> Result removed). - @result ||= PendingResult.new(self) - end + # Result of the last time the example ran. + # Is pending if the example hasn't run. + getter result : Result = PendingResult.new # Creates the example. # An instance to run the test code in is given by *context*. @@ -62,7 +60,7 @@ module Spectator if pending? Log.debug { "Skipping example #{self} - marked pending" } - return @result = PendingResult.new(self) + return @result = PendingResult.new end previous_example = @@current diff --git a/src/spectator/fail_result.cr b/src/spectator/fail_result.cr index dfe8937..c28aa6d 100644 --- a/src/spectator/fail_result.cr +++ b/src/spectator/fail_result.cr @@ -11,8 +11,8 @@ module Spectator # Creates a failure result. # The *elapsed* argument is the length of time it took to run the example. # The *error* is the exception raised that caused the failure. - def initialize(example, elapsed, @error, expectations = [] of Expectation) - super(example, elapsed, expectations) + def initialize(elapsed, @error, expectations = [] of Expectation) + super(elapsed, expectations) end # Calls the `failure` method on *visitor*. diff --git a/src/spectator/formatting/document_formatter.cr b/src/spectator/formatting/document_formatter.cr index 331fb13..77cf23a 100644 --- a/src/spectator/formatting/document_formatter.cr +++ b/src/spectator/formatting/document_formatter.cr @@ -27,9 +27,9 @@ module Spectator::Formatting end # Produces a single character output based on a result. - def end_example(result) + def end_example(example) @previous_hierarchy.size.times { @io.print INDENT } - @io.puts result.accept(Color) { result.example } + @io.puts example.result.accept(Color) { example } end # Produces a list of groups making up the hierarchy for an example. diff --git a/src/spectator/formatting/dots_formatter.cr b/src/spectator/formatting/dots_formatter.cr index 1fd35c6..15dbbc4 100644 --- a/src/spectator/formatting/dots_formatter.cr +++ b/src/spectator/formatting/dots_formatter.cr @@ -20,8 +20,8 @@ module Spectator::Formatting end # Produces a single character output based on a result. - def end_example(result) - @io.print result.accept(Character) + def end_example(example) + @io.print example.result.accept(Character) end # Interface for `Result` to pick a character for output. diff --git a/src/spectator/formatting/error_junit_test_case.cr b/src/spectator/formatting/error_junit_test_case.cr index f1a12ce..41f71d1 100644 --- a/src/spectator/formatting/error_junit_test_case.cr +++ b/src/spectator/formatting/error_junit_test_case.cr @@ -7,7 +7,9 @@ module Spectator::Formatting private getter result # Creates the JUnit test case. - def initialize(@result : ErrorResult) + def initialize(example : Example) + super + @result = example.result.as(ErrorResult) end # Adds the exception to the XML block. diff --git a/src/spectator/formatting/failure_block.cr b/src/spectator/formatting/failure_block.cr index e1eb053..4af0c0e 100644 --- a/src/spectator/formatting/failure_block.cr +++ b/src/spectator/formatting/failure_block.cr @@ -15,8 +15,13 @@ module Spectator::Formatting private struct FailureBlock # Creates the failure block. # The *index* uniquely identifies the failure in the output. - # The *result* is the outcome of the failed example. - def initialize(@index : Int32, @result : FailResult) + # The *example* is the failed example. + def initialize(@index : Int32, @example : Example) + end + + # Retrieves the failed result. + private def result + @example.result.as(FailResult) end # Creates the block of text describing the failure. @@ -39,7 +44,7 @@ module Spectator::Formatting # 1) Example name # ``` private def title(indent) - indent.line(NumberedItem.new(@index, @result.example)) + indent.line(NumberedItem.new(@index, @example)) end # Produces the main content of the failure block. @@ -47,12 +52,12 @@ module Spectator::Formatting # then an error stacktrace if an error occurred. private def content(indent) unsatisfied_expectations(indent) - error_stacktrace(indent) if @result.is_a?(ErrorResult) + error_stacktrace(indent) if result.is_a?(ErrorResult) end # Produces a list of unsatisfied expectations and their values. private def unsatisfied_expectations(indent) - @result.expectations.reject(&.satisfied?).each do |expectation| + result.expectations.reject(&.satisfied?).each do |expectation| indent.line(Color.failure(LabeledText.new("Failure", expectation.failure_message))) indent.line indent.increase do @@ -76,7 +81,7 @@ module Spectator::Formatting # Produces the stack trace for an errored result. private def error_stacktrace(indent) - error = @result.error + error = result.error first_line = error.message.try(&.lines).try(&.first) indent.line(Color.error(LabeledText.new("Error", first_line))) indent.line @@ -105,7 +110,7 @@ module Spectator::Formatting # Produces the location line of the failure block. private def location(indent) - indent.line(Comment.color(@result.example.location)) + indent.line(Comment.color(@example.location)) end # Gets the number of characters a positive integer spans in base 10. diff --git a/src/spectator/formatting/failure_command.cr b/src/spectator/formatting/failure_command.cr index 27c6896..34f8bea 100644 --- a/src/spectator/formatting/failure_command.cr +++ b/src/spectator/formatting/failure_command.cr @@ -12,8 +12,8 @@ module Spectator::Formatting end # Colorizes the command instance based on the result. - def self.color(result) - result.accept(Color) { new(result.example) } + def self.color(example) + example.result.accept(Color) { new(example) } end end end diff --git a/src/spectator/formatting/failure_junit_test_case.cr b/src/spectator/formatting/failure_junit_test_case.cr index 99181ea..37f0823 100644 --- a/src/spectator/formatting/failure_junit_test_case.cr +++ b/src/spectator/formatting/failure_junit_test_case.cr @@ -7,7 +7,9 @@ module Spectator::Formatting private getter result # Creates the JUnit test case. - def initialize(@result : FailResult) + def initialize(example : Example) + super + @result = example.result.as(FailResult) end # Status string specific to the result type. diff --git a/src/spectator/formatting/formatter.cr b/src/spectator/formatting/formatter.cr index 9efd800..ac37fef 100644 --- a/src/spectator/formatting/formatter.cr +++ b/src/spectator/formatting/formatter.cr @@ -21,7 +21,7 @@ module Spectator::Formatting abstract def start_example(example : Example) # Called when a test finishes. - # The result of the test is provided. - abstract def end_example(result : Result) + # The result of the test is available through *example*. + abstract def end_example(example : Example) end end diff --git a/src/spectator/formatting/json_formatter.cr b/src/spectator/formatting/json_formatter.cr index 369a896..36fd746 100644 --- a/src/spectator/formatting/json_formatter.cr +++ b/src/spectator/formatting/json_formatter.cr @@ -36,8 +36,8 @@ module Spectator::Formatting # Called when a test finishes. # The result of the test is provided. - def end_example(result : Result) - result.to_json(@json) + def end_example(example : Example) + example.result.to_json(@json, example) end # Adds the totals section of the document. @@ -84,11 +84,11 @@ module Spectator::Formatting end # Adds a profile entry to the document. - private def profile_entry(result) + private def profile_entry(example) @json.object do - @json.field("example", result.example) - @json.field("time", result.elapsed.total_seconds) - @json.field("location", result.example.location) + @json.field("example", example) + @json.field("time", example.result.elapsed.total_seconds) + @json.field("location", example.location) end end end diff --git a/src/spectator/formatting/junit_formatter.cr b/src/spectator/formatting/junit_formatter.cr index f1dd60e..c523072 100644 --- a/src/spectator/formatting/junit_formatter.cr +++ b/src/spectator/formatting/junit_formatter.cr @@ -37,8 +37,8 @@ module Spectator::Formatting end # Called when a test finishes. - # The result of the test is provided. - def end_example(result : Result) + # The result of the test is provided by *example*. + def end_example(example : Example) end # Creates the "testsuites" block in the XML. @@ -55,8 +55,8 @@ module Spectator::Formatting # Adds all of the individual test suite blocks. private def add_test_suites(report) - report.group_by(&.example.location.path).each do |path, results| - JUnitTestSuite.new(path, results).to_xml(@xml) + report.group_by(&.location.path).each do |path, examples| + JUnitTestSuite.new(path, examples).to_xml(@xml) end end end diff --git a/src/spectator/formatting/junit_test_case.cr b/src/spectator/formatting/junit_test_case.cr index 30eacb3..223942a 100644 --- a/src/spectator/formatting/junit_test_case.cr +++ b/src/spectator/formatting/junit_test_case.cr @@ -1,6 +1,10 @@ module Spectator::Formatting # Base type for all JUnit test case results. private abstract class JUnitTestCase + # Creates the JUnit test case. + def initialize(@example : Example) + end + # Produces the test case XML element. def to_xml(xml : ::XML::Builder) xml.element("testcase", **attributes) do @@ -11,7 +15,7 @@ module Spectator::Formatting # Attributes that go in the "testcase" XML element. private def attributes { - name: result.example, + name: example, status: status, classname: classname, } @@ -23,6 +27,9 @@ module Spectator::Formatting # Status string specific to the result type. private abstract def status : String + # Example for this test case. + private getter example : Example + # Adds additional content to the "testcase" XML block. # Override this to add more content. private def content(xml) @@ -31,7 +38,7 @@ module Spectator::Formatting # Java-ified class name created from the spec. private def classname - path = result.example.location.path + path = example.location.path file = File.basename(path) ext = File.extname(file) name = file[0...-(ext.size)] diff --git a/src/spectator/formatting/junit_test_suite.cr b/src/spectator/formatting/junit_test_suite.cr index f7abc4b..73e4e34 100644 --- a/src/spectator/formatting/junit_test_suite.cr +++ b/src/spectator/formatting/junit_test_suite.cr @@ -3,9 +3,9 @@ module Spectator::Formatting private struct JUnitTestSuite # Creates the JUnit test suite. # The *path* should be the file that all results are from. - # The *results* is a subset of all results that share the path. - def initialize(@path : String, results : Array(Result)) - @report = Report.new(results) + # The *examples* is a subset of all examples that share the path. + def initialize(@path : String, examples : Array(Example)) + @report = Report.new(examples) end # Generates the XML for the test suite (and all nested test cases). @@ -24,8 +24,8 @@ module Spectator::Formatting # Adds the test case elements to the XML. private def add_test_cases(xml) - @report.each do |result| - test_case = result.accept(JUnitTestCaseSelector) { |r| r } + @report.each do |example| + test_case = example.result.accept(JUnitTestCaseSelector) { example } test_case.to_xml(xml) end end @@ -50,23 +50,23 @@ module Spectator::Formatting extend self # Creates a successful JUnit test case. - def pass(result) - SuccessfulJUnitTestCase.new(result.as(PassResult)) + def pass(example) + SuccessfulJUnitTestCase.new(example) end # Creates a failure JUnit test case. - def failure(result) - FailureJUnitTestCase.new(result.as(FailResult)) + def failure(example) + FailureJUnitTestCase.new(example) end # Creates an error JUnit test case. - def error(result) - ErrorJUnitTestCase.new(result.as(ErrorResult)) + def error(example) + ErrorJUnitTestCase.new(example) end # Creates a skipped JUnit test case. - def pending(result) - SkippedJUnitTestCase.new(result.as(PendingResult)) + def pending(example) + SkippedJUnitTestCase.new(example) end end end diff --git a/src/spectator/formatting/profile_block.cr b/src/spectator/formatting/profile_block.cr index ba7943f..319705d 100644 --- a/src/spectator/formatting/profile_block.cr +++ b/src/spectator/formatting/profile_block.cr @@ -11,17 +11,17 @@ module Spectator::Formatting indent = Indent.new(io) indent.increase do - @profile.each do |result| - entry(indent, result) + @profile.each do |example| + entry(indent, example) end end end # Adds a result entry to the output. - private def entry(indent, result) - indent.line(result.example) + private def entry(indent, example) + indent.line(example) indent.increase do - indent.line(LocationTiming.new(result.elapsed, result.example.location)) + indent.line(LocationTiming.new(example.result.elapsed, example.location)) end end end diff --git a/src/spectator/formatting/silent_formatter.cr b/src/spectator/formatting/silent_formatter.cr index 2098480..1556534 100644 --- a/src/spectator/formatting/silent_formatter.cr +++ b/src/spectator/formatting/silent_formatter.cr @@ -19,8 +19,8 @@ module Spectator::Formatting end # Called when a test finishes. - # The result of the test is provided. - def end_example(result : Result) + # The result of the test is provided by *example*. + def end_example(example : Example) # ... crickets ... end end diff --git a/src/spectator/formatting/skipped_junit_test_case.cr b/src/spectator/formatting/skipped_junit_test_case.cr index 6b90b4d..0c0c383 100644 --- a/src/spectator/formatting/skipped_junit_test_case.cr +++ b/src/spectator/formatting/skipped_junit_test_case.cr @@ -7,7 +7,9 @@ module Spectator::Formatting private getter result # Creates the JUnit test case. - def initialize(@result : PendingResult) + def initialize(example : Example) + super + @result = example.result.as(PendingResult) end # Status string specific to the result type. diff --git a/src/spectator/formatting/successful_junit_test_case.cr b/src/spectator/formatting/successful_junit_test_case.cr index 803ea6e..cb4e85f 100644 --- a/src/spectator/formatting/successful_junit_test_case.cr +++ b/src/spectator/formatting/successful_junit_test_case.cr @@ -5,7 +5,9 @@ module Spectator::Formatting private getter result # Creates the JUnit test case. - def initialize(@result : PassResult) + def initialize(example : Example) + super + @result = example.result.as(PassResult) end # Status string specific to the result type. diff --git a/src/spectator/formatting/suite_summary.cr b/src/spectator/formatting/suite_summary.cr index 183a78e..cf733f5 100644 --- a/src/spectator/formatting/suite_summary.cr +++ b/src/spectator/formatting/suite_summary.cr @@ -33,8 +33,8 @@ module Spectator::Formatting private def failures(failures) @io.puts "Failures:" @io.puts - failures.each_with_index do |result, index| - @io.puts FailureBlock.new(index + 1, result) + failures.each_with_index do |example, index| + @io.puts FailureBlock.new(index + 1, example) end end @@ -68,10 +68,10 @@ module Spectator::Formatting @io.puts @io.puts "Failed examples:" @io.puts - failures.each do |result| - @io << FailureCommand.color(result) + failures.each do |example| + @io << FailureCommand.color(example) @io << ' ' - @io.puts Comment.color(result.example) + @io.puts Comment.color(example) end end end diff --git a/src/spectator/formatting/tap_formatter.cr b/src/spectator/formatting/tap_formatter.cr index 018d879..2c7c810 100644 --- a/src/spectator/formatting/tap_formatter.cr +++ b/src/spectator/formatting/tap_formatter.cr @@ -27,9 +27,9 @@ module Spectator::Formatting end # Called when a test finishes. - # The result of the test is provided. - def end_example(result : Result) - @io.puts TAPTestLine.new(@index, result) + # The result of the test is provided by *example*. + def end_example(example : Example) + @io.puts TAPTestLine.new(@index, example) @index += 1 end @@ -39,19 +39,19 @@ module Spectator::Formatting indent = Indent.new(@io) indent.increase do - profile.each do |result| - profile_entry(indent, result) + profile.each do |example| + profile_entry(indent, example) end end end # Adds a profile result entry to the output. - private def profile_entry(indent, result) + private def profile_entry(indent, example) @io << "# " - indent.line(result.example) + indent.line(example) indent.increase do @io << "# " - indent.line(LocationTiming.new(result.elapsed, result.example.location)) + indent.line(LocationTiming.new(example.result.elapsed, example.location)) end end end diff --git a/src/spectator/formatting/tap_test_line.cr b/src/spectator/formatting/tap_test_line.cr index 089031b..dd55523 100644 --- a/src/spectator/formatting/tap_test_line.cr +++ b/src/spectator/formatting/tap_test_line.cr @@ -2,7 +2,7 @@ module Spectator::Formatting # Produces a formatted TAP test line. private struct TAPTestLine # Creates the test line. - def initialize(@index : Int32, @result : Result) + def initialize(@index : Int32, @example : Example) end # Appends the line to the output. @@ -11,23 +11,23 @@ module Spectator::Formatting io << ' ' io << @index io << " - " - io << example + io << @example io << " # skip" if pending? end # The text "ok" or "not ok" depending on the result. private def status - @result.is_a?(FailResult) ? "not ok" : "ok" + result.is_a?(FailResult) ? "not ok" : "ok" end - # The example that was tested. - private def example - @result.example + # The result of running the example. + private def result + @example.result end # Indicates whether this test was skipped. private def pending? - @result.is_a?(PendingResult) + result.is_a?(PendingResult) end end end diff --git a/src/spectator/harness.cr b/src/spectator/harness.cr index 59e8975..34bd070 100644 --- a/src/spectator/harness.cr +++ b/src/spectator/harness.cr @@ -94,14 +94,13 @@ module Spectator # Takes the *elapsed* time and a possible *error* from the test. # Returns a type of `Result`. private def translate(elapsed, error) : Result - example = Example.current # TODO: Remove this. case error when nil - PassResult.new(example, elapsed, @expectations) + PassResult.new(elapsed, @expectations) when ExpectationFailed - FailResult.new(example, elapsed, error, @expectations) + FailResult.new(elapsed, error, @expectations) else - ErrorResult.new(example, elapsed, error, @expectations) + ErrorResult.new(elapsed, error, @expectations) end end diff --git a/src/spectator/pending_result.cr b/src/spectator/pending_result.cr index 4ff64e6..6d68e19 100644 --- a/src/spectator/pending_result.cr +++ b/src/spectator/pending_result.cr @@ -7,7 +7,7 @@ module Spectator class PendingResult < Result # Creates the result. # *elapsed* is the length of time it took to run the example. - def initialize(example, elapsed = Time::Span::ZERO, expectations = [] of Expectation) + def initialize(elapsed = Time::Span::ZERO, expectations = [] of Expectation) super end diff --git a/src/spectator/profile.cr b/src/spectator/profile.cr index 0067f7a..c4021e2 100644 --- a/src/spectator/profile.cr +++ b/src/spectator/profile.cr @@ -1,14 +1,14 @@ module Spectator # Information about the runtimes of examples. class Profile - include Indexable(Result) + include Indexable(Example) # Total length of time it took to run all examples in the test suite. getter total_time : Time::Span # Creates the profiling information. # The *slowest* results must already be sorted, longest time first. - private def initialize(@slowest : Array(Result), @total_time) + private def initialize(@slowest : Array(Example), @total_time) end # Number of results in the profile. @@ -23,7 +23,7 @@ module Spectator # Length of time it took to run the results in the profile. def time - @slowest.sum(&.elapsed) + @slowest.sum(&.result.elapsed) end # Percentage (from 0 to 1) of time the results in this profile took compared to all examples. @@ -33,9 +33,9 @@ module Spectator # Produces the profile from a report. def self.generate(report, size = 10) - results = report.to_a - sorted_results = results.sort_by(&.elapsed) - slowest = sorted_results.last(size).reverse + examples = report.to_a + sorted_examples = examples.sort_by(&.result.elapsed) + slowest = sorted_examples.last(size).reverse self.new(slowest, report.example_runtime) end end diff --git a/src/spectator/report.cr b/src/spectator/report.cr index e295b5b..996fb58 100644 --- a/src/spectator/report.cr +++ b/src/spectator/report.cr @@ -3,7 +3,7 @@ require "./result" module Spectator # Outcome of all tests in a suite. class Report - include Enumerable(Result) + include Enumerable(Example) # Total length of time it took to execute the test suite. # This includes examples, hooks, and framework processes. @@ -29,14 +29,14 @@ module Spectator getter! random_seed : UInt64? # Creates the report. - # The *results* are from running the examples in the test suite. + # The *examples* are all examples in the test suite. # The *runtime* is the total time it took to execute the suite. # The *remaining_count* is the number of tests skipped due to fail-fast. # The *fail_blank* flag indicates whether it is a failure if there were no tests run. # The *random_seed* is the seed used for random number generation. - def initialize(@results : Array(Result), @runtime, @remaining_count = 0, @fail_blank = false, @random_seed = nil) - @results.each do |result| - case result + def initialize(@examples : Array(Example), @runtime, @remaining_count = 0, @fail_blank = false, @random_seed = nil) + @examples.each do |example| + case example.result when PassResult @successful_count += 1 when ErrorResult @@ -55,23 +55,28 @@ module Spectator # Creates the report. # This constructor is intended for reports of subsets of results. - # The *results* are from running the examples in the test suite. + # The *examples* are all examples in the test suite. # The runtime is calculated from the *results*. - def initialize(results : Array(Result)) - runtime = results.sum(&.elapsed) - initialize(results, runtime) + def initialize(examples : Array(Example)) + runtime = examples.sum(&.result.elapsed) + initialize(examples, runtime) end - # Yields each result in turn. + # Yields each example in turn. def each - @results.each do |result| - yield result + @examples.each do |example| + yield example end end + # Retrieves results of all examples. + def results + @examples.each.map(&.result) + end + # Number of examples. def example_count - @results.size + @examples.size end # Number of examples run (not skipped or pending). @@ -90,21 +95,21 @@ module Spectator remaining_count > 0 end - # Returns a set of results for all failed examples. + # Returns a set of all failed examples. def failures - @results.each.compact_map(&.as?(FailResult)) + @examples.select(&.result.is_a?(FailResult)) end - # Returns a set of results for all errored examples. + # Returns a set of all errored examples. def errors - @results.each.compact_map(&.as?(ErrorResult)) + @examples.select(&.result.is_a?(ErrorResult)) end # Length of time it took to run just example code. # This does not include hooks, # but it does include pre- and post-conditions. def example_runtime - @results.sum(&.elapsed) + results.sum(&.elapsed) end # Length of time spent in framework processes and hooks. diff --git a/src/spectator/result.cr b/src/spectator/result.cr index 2c775ef..f20f483 100644 --- a/src/spectator/result.cr +++ b/src/spectator/result.cr @@ -2,10 +2,6 @@ module Spectator # Base class that represents the outcome of running an example. # Sub-classes contain additional information specific to the type of result. abstract class Result - # Example that generated the result. - # TODO: Remove this. - getter example : Example - # Length of time it took to run the example. getter elapsed : Time::Span @@ -14,7 +10,7 @@ module Spectator # Creates the result. # *elapsed* is the length of time it took to run the example. - def initialize(@example, @elapsed, @expectations = [] of Expectation) + def initialize(@elapsed, @expectations = [] of Expectation) end # Calls the corresponding method for the type of result. @@ -22,14 +18,14 @@ module Spectator abstract def accept(visitor) # Creates a JSON object from the result information. - def to_json(json : ::JSON::Builder) + def to_json(json : ::JSON::Builder, example) json.object do - add_json_fields(json) + add_json_fields(json, example) end end # Adds the common fields for a result to a JSON builder. - private def add_json_fields(json : ::JSON::Builder) + private def add_json_fields(json : ::JSON::Builder, example) json.field("name", example) json.field("location", example.location) json.field("result", to_s) diff --git a/src/spectator/spec/runner.cr b/src/spectator/spec/runner.cr index 99ce35b..f5ccf8f 100644 --- a/src/spectator/spec/runner.cr +++ b/src/spectator/spec/runner.cr @@ -16,25 +16,25 @@ module Spectator @config.each_formatter(&.start_suite(@suite)) # Run all examples and capture the results. - results = Array(Result).new(@suite.size) + examples = Array(Example).new(@suite.size) elapsed = Time.measure do - collect_results(results) + collect_results(examples) end # Generate a report and pass it along to the formatter. - remaining = @suite.size - results.size + remaining = @suite.size - examples.size seed = (@config.random_seed if @config.randomize?) - report = Report.new(results, elapsed, remaining, @config.fail_blank?, seed) + report = Report.new(examples, elapsed, remaining, @config.fail_blank?, seed) @config.each_formatter(&.end_suite(report, profile(report))) !report.failed? end - # Runs all examples and adds results to a list. - private def collect_results(results) + # Runs all examples and adds them to a list. + private def collect_results(examples) example_order.each do |example| - result = run_example(example).as(Result) - results << result + result = run_example(example) + examples << example if @config.fail_fast? && result.is_a?(FailResult) example.group.call_once_after_all break @@ -60,14 +60,14 @@ module Spectator else example.run end - @config.each_formatter(&.end_example(result)) + @config.each_formatter(&.end_example(example)) result end # Creates a fake result for an example. private def dry_run_result(example) expectations = [] of Expectation - PassResult.new(example, Time::Span.zero, expectations) + PassResult.new(Time::Span.zero, expectations) end # Generates and returns a profile if one should be displayed.