Skip to content

Instantly share code, notes, and snippets.

@h0tw1r3
Last active February 4, 2024 16:27
Show Gist options
  • Save h0tw1r3/1250f41f9c365f47a23e18aa215463e5 to your computer and use it in GitHub Desktop.
Save h0tw1r3/1250f41f9c365f47a23e18aa215463e5 to your computer and use it in GitHub Desktop.

Revisions

  1. h0tw1r3 revised this gist Feb 4, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion spec_described.rb
    Original file line number Diff line number Diff line change
    @@ -83,7 +83,7 @@ def diff(a, b)

    puts colorize("spec describe coverage: #{colorize('%3.1f%%' % total_percent, :bold)}", total_color)

    if total_have < total_want || @unknown.values.flatten.size > 0
    if total_have < total_want || !@unknown.values.flatten.empty?
    (code.keys | @missing.keys).each do |res_type|
    want = (code[res_type]&.size || 0)
    missing = (@missing[res_type]&.size || 0)
  2. h0tw1r3 created this gist Feb 3, 2024.
    116 changes: 116 additions & 0 deletions spec_described.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,116 @@
    require 'rspec/core'

    namespace :check do
    desc "Check to ensure defined puppet code has been described in spec\n(defaults: coverage=100)"
    task :spec_described, [:coverage] do |_task, args|
    args.with_defaults(coverage: '100')
    def pluralize(string)
    string.end_with?('s') ? "#{string}es" : "#{string}s"
    end

    def colorize(msg, color)
    @colorizer ||= ::RSpec::Core::Formatters::ConsoleCodes
    @colorizer.wrap(msg, color)
    end

    def coverage_color(pct)
    if pct < 75
    :red
    elsif pct < 100
    :yellow
    else
    :green
    end
    end

    code = {}
    code_files = {} [43/9825]
    Dir.glob('{functions,manifests,types}/**/*.pp') do |fn|
    visible = true
    res_type = res_title = nil
    File.foreach(fn) do |line|
    if %r{^\s*#\s*@api private}.match?(line)
    visible = false
    elsif line =~ %r{^\s*(class|function|define|type|function)\s*([^=\{\s]+)}
    res_type = Regexp.last_match(1)
    res_type = 'type_alias' if res_type == 'type'
    res_title = Regexp.last_match(2)
    code[res_type] ||= []
    break
    end
    end
    if res_type && visible
    code[res_type] << res_title if res_type && visible
    code_files[res_title] = fn
    end
    end
    Dir.glob('lib/puppet/functions/**/*.rb') do |fn|
    File.foreach(fn) do |line|
    if line =~ %r{^\s*Puppet::Functions\.create_function\(:?['"]?([^']+)['"]?\)}
    code['function'] ||= []
    code['function'] << Regexp.last_match(1)
    code_files[Regexp.last_match(1)] = fn
    end
    end
    end

    test = {}
    test_files = {}
    Dir.glob('spec/{classes,defines,functions,type_aliases}/**/*rb') do |fn|
    resource_type = fn.split(File::SEPARATOR)[1].match(%r{(class|function|define|type_alias)}).captures[0]
    test[resource_type] ||= []
    File.foreach(fn) do |line|
    if (m = line.match(%r{^describe ["']([^'"\s]+)}))
    test[resource_type] << m.captures[0]
    test_files[m.captures[0]] = fn
    end
    end
    end

    def diff(a, b)
    a.merge(a) { |ka, va| va.reject { |v| b[ka]&.include?(v) } }
    end

    @missing = diff(code, test)
    @unknown = diff(test, code)

    total_want = code.values.flatten.size
    total_missing = @missing.values.flatten.size
    total_have = total_want - total_missing

    total_percent = total_have / total_want.to_f * 100
    total_color = coverage_color(total_percent)

    puts colorize("spec describe coverage: #{colorize('%3.1f%%' % total_percent, :bold)}", total_color)

    if total_have < total_want || @unknown.values.flatten.size > 0
    (code.keys | @missing.keys).each do |res_type|
    want = (code[res_type]&.size || 0)
    missing = (@missing[res_type]&.size || 0)
    unknown = (@unknown[res_type]&.size || 0)
    have = want - missing

    if (missing + unknown) > 0
    coverage = have / want.to_f * 100.0
    color = coverage_color(coverage)
    puts colorize(" * #{pluralize(res_type)}: #{colorize('%3.1f%%' % coverage, :bold)}", color)
    end

    ['missing', 'unknown'].each do |how|
    what = instance_variable_get("@#{how}")
    next if what[res_type].nil? || what[res_type].empty?
    puts " #{how}:"
    what[res_type].each do |r|
    info = " in #{test_files[r]}" if test_files[r]
    puts " - #{r}#{info}"
    end
    end
    end
    end
    abort if total_percent < args[:coverage].to_f
    end
    end

    Rake::Task['check'].enhance do
    Rake::Task['check:spec_described'].invoke
    end