class Slacker::QueryResultMatcher

Public Class Methods

new(golden_master) click to toggle source
# File lib/slacker/query_result_matcher.rb, line 7
def initialize(golden_master)
  @golden_master = golden_master
  @failure_message = ''
end

Public Instance Methods

failure_message() click to toggle source
# File lib/slacker/query_result_matcher.rb, line 26
def failure_message
  @failure_message
end
matches?(subject) click to toggle source
# File lib/slacker/query_result_matcher.rb, line 12
def matches?(subject)
  does_match = false

  subject = normalize_query_result_subject(subject)

  catch :no_match do
    test_type_match(subject)
    test_value_match(subject)
    does_match = true
  end
  
  does_match
end

Private Instance Methods

is_well_formed_query_result?(arr) click to toggle source
# File lib/slacker/query_result_matcher.rb, line 157
def is_well_formed_query_result?(arr)
  return false unless arr.kind_of? Array
  header =[]
  arr.find{|row| !row.kind_of?(Hash) || (header = header.empty? ? row.keys : header) != row.keys || row.keys.empty?}.nil?
end
match_types?(master_val, subject_val) click to toggle source
# File lib/slacker/query_result_matcher.rb, line 92
def match_types?(master_val, subject_val)
  subject_val.kind_of? master_val.class
end
match_values?(master_val, subject_val) click to toggle source
# File lib/slacker/query_result_matcher.rb, line 96
def match_values?(master_val, subject_val)
  if master_val.nil?
    master_val == subject_val
  elsif master_val.kind_of?(String)
    case subject_val
    when ODBC::TimeStamp
      # Convert master string value to date-time and compare.
      ((subject_val_time = Time.parse(master_val)) rescue false) && subject_val_time == ODBC::to_time(subject_val)
    # Time is the class returned by tiny_tds when the resultset includes datetime or time.
    when Time
      # Convert master string value to date-time and compare.
      ((subject_val_time = Time.parse(master_val)) rescue false) && subject_val_time == subject_val
    when Float
      (!!Float(master_val) rescue false) && Float(master_val) == subject_val
    when BigDecimal
      (!!BigDecimal(master_val) rescue false) && BigDecimal(master_val) == BigDecimal(subject_val)
    else
      subject_val.to_s == master_val.to_s
    end
  else
    subject_val.to_s == master_val.to_s
  end
end
normalize_query_result_subject(subject) click to toggle source

In case of a multi-resultset subject, extract the first result set

# File lib/slacker/query_result_matcher.rb, line 176
def normalize_query_result_subject(subject)
  subject.kind_of?(Array) && !subject.empty? && is_well_formed_query_result?(subject[0]) ? subject[0] : subject
end
test_array_match(subject) click to toggle source
# File lib/slacker/query_result_matcher.rb, line 120
def test_array_match(subject)
  # Compare the fields
  if !(subject.empty? || @golden_master.empty?)
    subject_fields = subject[0].keys
    master_fields = @golden_master[0].keys

    if subject_fields.count != master_fields.count
      throw_no_match "Expected #{master_fields.count} field(s), got #{subject_fields.count}"
    end

    master_fields.each_with_index do |column, index|
      if column != subject_fields[index]
        throw_no_match "Expected field \"#{column}\", got field \"#{subject_fields[index]}\""
      end
    end
  end

  # Compare the number of records
  subject_record_count = subject.count
  master_record_count = @golden_master.count
  if subject_record_count != master_record_count
    throw_no_match "Expected #{master_record_count} record(s), got #{subject_record_count}"
  end

  # Compare the values of the golden master with the subject
  current_row = 0
  @golden_master.each do |row|
    row.each do |field, master_value|
      subject_value = subject[current_row][field]
      if !match_values?(master_value, subject_value)
        throw_no_match "Field \"#{field}\", Record #{current_row + 1}: Expected value #{master_value.nil? ? '<NULL>' : "\"#{master_value}\""}, got #{subject_value.nil? ? '<NULL>' : "\"#{subject_value}\""}"
      end
    end
    current_row += 1
  end
end
test_csv_table_match(subject) click to toggle source

Compare the golden master CSV table with the subject query result

# File lib/slacker/query_result_matcher.rb, line 55
def test_csv_table_match(subject)
  # Compare the fields
  if !subject.empty?
    subject_fields = subject[0].keys
    master_fields = @golden_master.headers

    if subject_fields.count != master_fields.count
      throw_no_match "Expected #{master_fields.count} field(s), got #{subject_fields.count}"
    end

    master_fields.each_with_index do |column, index|
      if column != subject_fields[index]
        throw_no_match "Expected field \"#{column}\", got field \"#{subject_fields[index]}\""
      end
    end
  end

  # Compare the number of records
  subject_record_count = subject.count
  master_record_count = @golden_master.inject(0){|count| count += 1}
  if subject_record_count != master_record_count
    throw_no_match "Expected #{master_record_count} record(s), got #{subject_record_count}"
  end

  # Compare the values of the golden master with the subject
  current_row = 0
  @golden_master.each do |row|
    row.each do |field, master_string|
      subject_value = subject[current_row][field]
      if !match_values?(master_string, subject_value)
        throw_no_match "Field \"#{field}\", Record #{current_row + 1}: Expected value #{master_string.nil? ? '<NULL>' : "\"#{master_string}\""}, got #{subject_value.nil? ? '<NULL>' : "\"#{subject_value}\""}"
      end
    end
    current_row += 1
  end
end
test_single_value_match(subject) click to toggle source
# File lib/slacker/query_result_matcher.rb, line 163
def test_single_value_match(subject)
  subject_value = subject[0].values[0]
  subject_field = subject[0].keys[0]
  if !match_types?(@golden_master, subject_value)
    throw_no_match "Field \"#{subject_field}\", Record 1: Expected type \"#{@golden_master.class}\", got \"#{subject_value.class}\""
  end

  if !match_values?(@golden_master, subject_value)
    throw_no_match "Field \"#{subject_field}\", Record 1: Expected value #{@golden_master.nil? ? '<NULL>' : "\"#{@golden_master}\""}, got #{subject_value.nil? ? '<NULL>' : "\"#{subject_value}\""}"
  end
end
test_type_match(subject) click to toggle source

test if the subject type is consistent with the golden master

# File lib/slacker/query_result_matcher.rb, line 33
def test_type_match(subject)
  if !is_well_formed_query_result?(subject)
    throw_no_match "Can perform query matches only against a well formed query result subject"
  end
  
  if (@golden_master.kind_of? Array) && !is_well_formed_query_result?(@golden_master)
    throw_no_match "Cannot match against a non-well formed golden master array"
  end
end
test_value_match(subject) click to toggle source
# File lib/slacker/query_result_matcher.rb, line 43
def test_value_match(subject)
  case @golden_master
  when CSV::Table
    test_csv_table_match(subject)
  when Array
    test_array_match(subject)
  else
    test_single_value_match(subject)
  end
end
throw_no_match(message) click to toggle source
# File lib/slacker/query_result_matcher.rb, line 180
def throw_no_match(message)
  @failure_message = message
  throw :no_match
end