<commit_before>
module TestHexIdHelpers # mix-in

  def hex_test_kata_id
    ENV['CYBER_DOJO_TEST_ID']
  end

  def hex_setup
  end

  def hex_teardown
  end

  # - - - - - - - - - - - - - - - -

  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods

    # ARGV[0] == module name
    @@args = ARGV[1..-1].sort.uniq.map(&:upcase)  # eg 2DD6F3 eg 2dd
    @@seen_ids = []
    @@timings = {}

    def test(id, *words, &block)
      id = hex_prefix + id
      name = words.join(' ')
      # check hex-id is well-formed
      diagnostic = "'#{id}',#{name}"
      hex_chars = '0123456789ABCDEF'
      is_hex_id = id.chars.all? { |ch| hex_chars.include? ch }
      raise  "no hex-ID: #{diagnostic}" if id == ''
      raise "bad hex-ID: #{diagnostic}" unless is_hex_id
      # if no hex-id supplied, or test method matches any supplied hex-id
      # then define a mini_test method using the hex-id
      no_args = @@args == []
      any_arg_is_part_of_id = @@args.any?{ |arg| id.include?(arg) }
      if no_args || any_arg_is_part_of_id
        raise "duplicate hex_ID: #{diagnostic}" if @@seen_ids.include?(id)
        @@seen_ids << id
        block_with_test_id = lambda {
          ENV['CYBER_DOJO_TEST_ID'] = id
          hex_setup
          t1 = Time.now
          self.instance_eval &block
          t2 = Time.now
          @@timings[id+':'+name] = (t2 - t1)
          hex_teardown
        }
        define_method("test_'#{id}',\n #{name}\n".to_sym, &block_with_test_id)
      end
    end

    ObjectSpace.define_finalizer(self, proc {
      sorted = Hash[@@timings.sort_by{ |name,secs| -secs}]
      sorted.each_with_index { |(name,secs),index|
        puts "%3.2f - %s" % [secs,name.truncate(72)]
        break if index == 5
      }
    })

    ObjectSpace.define_finalizer(self, proc {
      # complain about any unfound hex-id args
      unseen_arg = lambda { |arg|
        @@seen_ids.none? { |id|
          id.include?(arg)
        }
      }
      unseen_args = @@args.find_all { |arg|
        unseen_arg.call(arg)
      }
      unless unseen_args == []<commit_msg>refactoring; added heading to test-output for slowest tests<commit_after>
module TestHexIdHelpers # mix-in

  def hex_test_kata_id
    ENV['CYBER_DOJO_TEST_ID']
  end

  def hex_setup
  end

  def hex_teardown
  end

  # - - - - - - - - - - - - - - - -

  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods

    # ARGV[0] == module name
    @@args = ARGV[1..-1].sort.uniq.map(&:upcase)  # eg 2DD6F3 eg 2dd
    @@seen_ids = []
    @@timings = {}

    def test(id, *words, &block)
      id = hex_prefix + id
      name = words.join(' ')
      # check hex-id is well-formed
      diagnostic = "'#{id}',#{name}"
      hex_chars = '0123456789ABCDEF'
      is_hex_id = id.chars.all? { |ch| hex_chars.include? ch }
      raise  "no hex-ID: #{diagnostic}" if id == ''
      raise "bad hex-ID: #{diagnostic}" unless is_hex_id
      # if no hex-id supplied, or test method matches any supplied hex-id
      # then define a mini_test method using the hex-id
      no_args = @@args == []
      any_arg_is_part_of_id = @@args.any?{ |arg| id.include?(arg) }
      if no_args || any_arg_is_part_of_id
        raise "duplicate hex_ID: #{diagnostic}" if @@seen_ids.include?(id)
        @@seen_ids << id
        block_with_test_id = lambda {
          ENV['CYBER_DOJO_TEST_ID'] = id
          hex_setup
          t1 = Time.now
          self.instance_eval &block
          t2 = Time.now
          @@timings[id+':'+name] = (t2 - t1)
          hex_teardown
        }
        define_method("test_'#{id}',\n #{name}\n".to_sym, &block_with_test_id)
      end
    end

    ObjectSpace.define_finalizer(self, proc {
      puts
      puts 'Slowest 5 tests are...'
      sorted = Hash[@@timings.sort_by{ |name,secs| -secs}]
      sorted.each_with_index { |(name,secs),index|
        puts "%3.2f - %s" % [secs,name.truncate(72)]
        break if index == 5
      }
    })

    ObjectSpace.define_finalizer(self, proc {
      # complain about any unfound hex-id args
      unseen_arg = lambda { |arg|
        @@seen_ids.none? { |id|
          id.include?(arg)
        }
      }
      unseen_args = @@args.find_all { |arg|
        unseen_arg.call(arg)
      }
      unless unseen_args == []
{'fraction_non_alphanumeric': 0.13773013283616872, 'fraction_numerical': 0.012351433232346772, 'mean_word_length': 2.1605301914580264, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2460368', 'n_tokens_mistral': 1605, 'n_tokens_neox': 1550, 'n_words': 327}