mirror of
				https://gitea.invidious.io/iv-org/shard-spectator.git
				synced 2024-08-15 00:53:35 +00:00 
			
		
		
		
	Refactor UnorderedArrayMatcher
This commit is contained in:
		
							parent
							
								
									3ae16c6ec1
								
							
						
					
					
						commit
						9bffb30041
					
				
					 1 changed files with 37 additions and 84 deletions
				
			
		| 
						 | 
					@ -3,18 +3,45 @@ require "./value_matcher"
 | 
				
			||||||
module Spectator::Matchers
 | 
					module Spectator::Matchers
 | 
				
			||||||
  # Matcher for checking that the contents of one array (or similar type)
 | 
					  # Matcher for checking that the contents of one array (or similar type)
 | 
				
			||||||
  # has the exact same contents as another, but in any order.
 | 
					  # has the exact same contents as another, but in any order.
 | 
				
			||||||
  struct UnorderedArrayMatcher(ExpectedType) < ValueMatcher(Enumerable(ExpectedType))
 | 
					  struct UnorderedArrayMatcher(ExpectedType) < Matcher
 | 
				
			||||||
    # Determines whether the matcher is satisfied with the partial given to it.
 | 
					    private getter expected
 | 
				
			||||||
    def match(partial, negated = false)
 | 
					
 | 
				
			||||||
      expected_elements = expected.to_a
 | 
					    def initialize(@expected : TestValue(Enumerable(ExpectedType)))
 | 
				
			||||||
      actual = partial.actual.to_a
 | 
					    end
 | 
				
			||||||
      missing, extra = array_diff(expected, actual)
 | 
					
 | 
				
			||||||
 | 
					    def description
 | 
				
			||||||
 | 
					      "contains #{expected.label} in any order"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def match(actual)
 | 
				
			||||||
 | 
					      actual_elements = actual.value.to_a
 | 
				
			||||||
 | 
					      expected_elements = expected.value.to_a
 | 
				
			||||||
 | 
					      missing, extra = array_diff(expected_elements, actual_elements)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      values = ExpectedActual.new(expected_elements, label, actual, partial.label)
 | 
					 | 
				
			||||||
      if missing.empty? && extra.empty?
 | 
					      if missing.empty? && extra.empty?
 | 
				
			||||||
        IdenticalMatchData.new(values)
 | 
					        SuccessfulMatchData.new
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
        ContentMatchData.new(values, missing, extra)
 | 
					        FailedMatchData.new("#{actual_label} does not contain #{expected.label} (unordered)",
 | 
				
			||||||
 | 
					          expected: expected_elements.inspect,
 | 
				
			||||||
 | 
					          actual: actual_elements.inspect,
 | 
				
			||||||
 | 
					          missing: missing.inspect,
 | 
				
			||||||
 | 
					          extra: extra.inspect,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def negated_match(actual)
 | 
				
			||||||
 | 
					      actual_elements = actual.value.to_a
 | 
				
			||||||
 | 
					      expected_elements = expected.value.to_a
 | 
				
			||||||
 | 
					      missing, extra = array_diff(expected_elements, actual_elements)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if missing.empty? && extra.empty?
 | 
				
			||||||
 | 
					        FailedMatchData.new("#{actual_label} contains #{expected.label} (unordered)",
 | 
				
			||||||
 | 
					          expected: "Not #{expected_elements.inspect}",
 | 
				
			||||||
 | 
					          actual: actual_elements.inspect,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        SuccessfulMatchData.new
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,7 +51,7 @@ module Spectator::Matchers
 | 
				
			||||||
      extra = actual.dup
 | 
					      extra = actual.dup
 | 
				
			||||||
      missing = [] of ExpectedType
 | 
					      missing = [] of ExpectedType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # TODO: OPTIMIZE
 | 
					      # OPTIMIZE: Not very efficient at finding the difference.
 | 
				
			||||||
      expected.each do |item|
 | 
					      expected.each do |item|
 | 
				
			||||||
        index = extra.index(item)
 | 
					        index = extra.index(item)
 | 
				
			||||||
        if index
 | 
					        if index
 | 
				
			||||||
| 
						 | 
					@ -36,79 +63,5 @@ module Spectator::Matchers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {missing, extra}
 | 
					      {missing, extra}
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Creates the value matcher.
 | 
					 | 
				
			||||||
    # The label should be a string representation of the expectation.
 | 
					 | 
				
			||||||
    # The expected value is stored for later use.
 | 
					 | 
				
			||||||
    def initialize(expected : Enumerable(ExpectedType), label : String)
 | 
					 | 
				
			||||||
      super
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Creates the value matcher.
 | 
					 | 
				
			||||||
    # The label is generated by calling `#to_s` on the expected value.
 | 
					 | 
				
			||||||
    # The expected value is stored for later use.
 | 
					 | 
				
			||||||
    def initialize(expected : Enumerable(ExpectedType))
 | 
					 | 
				
			||||||
      super
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Common functionality for all match data for this matcher.
 | 
					 | 
				
			||||||
    private abstract struct CommonMatchData(ExpectedType, ActualType) < MatchData
 | 
					 | 
				
			||||||
      # Creates the match data.
 | 
					 | 
				
			||||||
      def initialize(matched, @values : ExpectedActual(Array(ExpectedType), Array(ActualType)))
 | 
					 | 
				
			||||||
        super(matched)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # Basic information about the match.
 | 
					 | 
				
			||||||
      def named_tuple
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          expected: NegatableMatchDataValue.new(@values.expected),
 | 
					 | 
				
			||||||
          actual:   @values.actual,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # Describes the condition that satisfies the matcher.
 | 
					 | 
				
			||||||
      # This is informational and displayed to the end-user.
 | 
					 | 
				
			||||||
      def message
 | 
					 | 
				
			||||||
        "#{@values.actual_label} contains #{@values.expected_label} (unordered)"
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Match data specific to this matcher.
 | 
					 | 
				
			||||||
    # This type is used when the actual value matches the expected value.
 | 
					 | 
				
			||||||
    private struct IdenticalMatchData(ExpectedType, ActualType) < CommonMatchData(ExpectedType, ActualType)
 | 
					 | 
				
			||||||
      # Creates the match data.
 | 
					 | 
				
			||||||
      def initialize(values : ExpectedActual(Array(ExpectedType), Array(ActualType)))
 | 
					 | 
				
			||||||
        super(true, values)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # Describes the condition that won't satsify the matcher.
 | 
					 | 
				
			||||||
      # This is informational and displayed to the end-user.
 | 
					 | 
				
			||||||
      def negated_message
 | 
					 | 
				
			||||||
        "#{@values.actual_label} does not contain #{@values.expected_label} (unordered)"
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Match data specific to this matcher.
 | 
					 | 
				
			||||||
    # This type is used when the actual contents differs from the expected contents.
 | 
					 | 
				
			||||||
    private struct ContentMatchData(ExpectedType, ActualType) < CommonMatchData(ExpectedType, ActualType)
 | 
					 | 
				
			||||||
      # Creates the match data.
 | 
					 | 
				
			||||||
      def initialize(values : ExpectedActual(Array(ExpectedType), Array(ActualType)), @missing : Array(ExpectedType), @extra : Array(ActualType))
 | 
					 | 
				
			||||||
        super(false, values)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # Information about the match.
 | 
					 | 
				
			||||||
      def named_tuple
 | 
					 | 
				
			||||||
        super.merge({
 | 
					 | 
				
			||||||
          missing: @missing,
 | 
					 | 
				
			||||||
          extra:   @extra,
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # Describes the condition that won't satsify the matcher.
 | 
					 | 
				
			||||||
      # This is informational and displayed to the end-user.
 | 
					 | 
				
			||||||
      def negated_message
 | 
					 | 
				
			||||||
        "#{@values.actual_label} does not contain #{@values.expected_label} (content differs)"
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue