Skip to content
This repository
Fetching contributors…

Cannot retrieve contributors at this time

file 183 lines (150 sloc) 4.452 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
require 'fileutils'

namespace :spec do

  ROOT_DIR = File.expand_path("../../", __FILE__)
  TARGET_DIR = File.join(ROOT_DIR, %w( spec whois record parser responses ))

  SOURCE_DIR = File.join(ROOT_DIR, %w( spec fixtures responses ))
  SOURCE_PARTS = SOURCE_DIR.split("/")


  TPL_DESCRIBE = <<-RUBY.chomp!
# encoding: utf-8

# This file is autogenerated. Do not edit it manually.
# If you want change the content of this file, edit
#
# %{sfile}
#
# and regenerate the tests with the following rake task
#
# $ rake spec:generate
#

require 'spec_helper'
require 'whois/record/parser/%{khost}.rb'

describe %{klass}, "%{descr}" do

before(:each) do
file = fixture("responses", "%{fixture}")
part = Whois::Record::Part.new(:body => File.read(file))
@parser = klass.new(part)
end

%{contexts}
end
RUBY

  TPL_CONTEXT = <<-RUBY.chomp!
describe "#%{descr}" do
it do
%{examples}
end
end
RUBY

  TPL_MATCH = <<-RUBY.chomp!
@parser.%{subject}.%{should} %{match}
RUBY

  TPL_MATCH_RAISE = <<-RUBY.chomp!
lambda { @parser.%{subject} }.%{should} %{match}
RUBY

  def relativize(path)
    path.gsub(ROOT_DIR, "")
  end


  task :generate => :generate_parsers

  task :generate_parsers do
    Dir["#{SOURCE_DIR}/**/*.expected"].each do |source_path|

      # Generate the filename and klass name from the test file.
      parts = (source_path.split("/") - SOURCE_PARTS)
      khost = parts.first
      kfile = parts.last
      klass = Whois::Record::Parser.parser_klass(khost)

      target_path = File.join(TARGET_DIR, *parts).gsub(".expected", "_spec.rb")

      # Extract the tests from the test file
      # and generates a Hash.
      #
      # {
      # "domain" => [
      # ["%s", "should", "== \"google.biz\""]
      # ],
      # "created_on" => [
      # ["%s", "should", "be_a(Time)"],
      # ["%s", "should", "== Time.parse(\"2002-03-27 00:01:00 UTC\")"]
      # ]
      # }
      #
      tests = {}
      match = nil
      lines = File.open(source_path)
      lines.each do |line|
        line.chomp!
        case line
        when ""
          # skip empty line
        when /^\s*\/\//
          # skip comment line
        when /^#([^\s]+)/
          tests[match = $1] = []
        when /^\s+(.+?): (.+?) (.+)/
          tests[match] << _parse_assertion($2, $1, $3)
        else
          raise "Invalid Line `#{line}' in `#{source_path}'"
        end
      end

      # Generate the RSpec content and
      # write one file for every test.
      contexts = tests.map do |attr, specs|
        matches = specs.map do |method, should, condition|
          subject = method % attr
          if condition.index("raise_")
            TPL_MATCH_RAISE % { :subject => subject, :should => should, :match => condition }
          else
            TPL_MATCH % { :subject => subject, :should => should, :match => condition }
          end
        end.join("\n")
        TPL_CONTEXT % { :descr => attr, :examples => matches }
      end.join("\n")

      describe = <<-RUBY
#{TPL_DESCRIBE % {
:klass => klass,
:khost => khost,
:descr => kfile,
:sfile => relativize(source_path),
:fixture => parts.join("/").gsub(".expected", ".txt"),
:contexts => contexts
}}
RUBY

      print "Generating #{relativize(target_path)}... "
      File.dirname(target_path).tap { |d| File.exists?(d) || FileUtils.mkdir_p(d) }
      File.open(target_path, "w+") { |f| f.write(describe) }
      print "done!\n"
    end

  end


  def _parse_assertion(method, should, condition)
    m = method
    s = should
    c = condition

    case condition

    # should: %s CLASS(time)
    # ->
    # should: %s be_a(time)
    when /^CLASS\((.+)\)$/
      c = "be_a(#{_build_condition_typeof($1)})"

    # should: %s SIZE(3)
    # ->
    # should: %s have(3).items
    when /^SIZE\((.+)\)$/
      c = "have(#{$1}).items"
    end

    [m, s, c]
  end

  def _build_condition_typeof(klass)
    case klass
    when "array" then "Array"
    when "time" then "Time"
    when "contact" then "Whois::Record::Contact"
    when "registrar" then "Whois::Record::Registrar"
    when "nameserver" then "Whois::Record::Nameserver"
    else
      raise "Unknown class `#{klass}'"
    end
  end

  def _build_condition_typecast(klass, value)
    case klass
    when "time" then %Q{Time.parse("#{value}")}
    else
      raise "Unknown class `#{klass}'"
    end
  end

end
Something went wrong with that request. Please try again.