#!/usr/bin/env ruby

require 'reap/task'
require 'facet/string/margin'

#  _____       _     ___     _       _____        _
# |_   _|__ __| |_  | __|_ _| |_    |_   _|_ _ __| |__
#   | |/ -_|_-<  _| | _|\ \ /  _|_    | |/ _` (_-< / /
#   |_|\___/__/\__| |___/_\_\\__(_)   |_|\__,_/__/_\_\
#

# = Test Extraction Task
#
# The Reap extract test task scans every package script
# looking for =begin testing ... =end sections.
# With appropriat headers, it copies these sections
# to files in the test dir, which then can be run
# using the Reap test taks.
#
class Reap::TestExt < Reap::Task

  task_desc "Extract unit-tests from lib scripts."

  task_help %{

    reap testext

    Extracts embedded tests from program files and places them
    in the test directory. The exact layout of files is reflected
    in the test directory. You can then use Reap's test task to
    run the tests.

      dir        Specify the test directory.
                 Default is 'test'.

      files      Specify files to extract.
                 Default is 'lib/**/*.rb'.

  }

  #attr_accessor :dir, :files, :options

  task_attr :tst

  def init
    tst.dir    ||= 'test'
    tst.files  ||= [ 'lib/**/*.rb' ]
    #tst.options
  end

  def run
    #test_libs = tst.libs.join(':')
    files = FileList.new
    files.include(*tst.files)
    if files.empty?
      puts "No script files found."
      return
    end
    print "Reap is scanning and copying embedded tests..."

    if tst.dir.strip.empty?
      puts "Test directory must be specified."
      return
    end

    unless File.directory?(tst.dir)
      puts "Test directory doesn't exist: #{File.expand_path( tst.dir )}"
      return
    end

    files.each { |file|
      $stdout << '.'; $stdout.flush
      testing = extract( file )
      unless testing.strip.empty?
        complete_test = create( testing, file )
        libpath = File.dirname( file )
        testfile = "test_" + File.basename( file )
        fp = File.join(tst.dir,libpath,testfile)
        unless File.directory?( File.dirname( fp ) )
          FileUtils.mkdir_p( File.dirname(fp) )
        end
        File.open( fp, "w" ) { |fw| fw << complete_test }
      end
    }
    puts "done."
  end

private

  def extract( file )
    return nil if ! File.file?( file )
    tests = ""; inside = false
    fstr = File.read( file )
    fstr.split(/\n/).each do |l|
      if l =~ /^=begin[ ]*test/i
        tests << "\n"
        inside = true
        next
      elsif inside and l =~ /^=[ ]*end/
        inside = false
        next
      end
      if inside
        tests << l << "\n"
      end
    end
    tests
  end

  def create( testing, file )
    fp = file.split(/[\/]/)
    if fp[0] == 'lib'
      reqf = "require '#{fp[1..-1].join('/')}'"
    else
      reqf = ''
    end

    teststr = <<-HERE.margin
      `#  _____         _
      `# |_   _|__  ___| |_
      `#   | |/ _ \\/ __| __|
      `#   | |  __/\\__ \\ |_
      `#   |_|\\___||___/\\__|
      `#
      `# for #{file}
      `#
      `# Extracted #{Time.now}
      `# Unit Tools Reap Test Extractor
      `#
      `
      `#{reqf}
      `
    HERE
    teststr << testing << "\n"
    teststr
  end

end