require 'crypto_methods'
ENV['PYTHONPATH']= File.dirname(__FILE__)

def python expr
  require 'open3'
  Open3.popen3('python') do |stdin,stdout,stderr|
    stdin.puts "from util import *\nprint #{expr}"
    stdin.close; STDERR.write stderr.read; stdout.read.chomp
  end
end

require 'test/unit'
class TestOpenIdUtil < Test::Unit::TestCase
  include DiffieHellman::DEFAULT

  def test_mod_exp
    n = Time.now.to_i
    assert_equal python("pow(#{GEN}, #{n}, #{MOD})").to_i,
      GEN.mod_exp(n, MOD)
  end

  def test_btwoc
    assert_equal python("long2a(#{MOD})"), MOD.btwoc
  end

  def test_unbtwoc
    assert_equal MOD, MOD.btwoc.unbtwoc
    assert_equal [], (-256..256).to_a.reject {|i| i==i.btwoc.unbtwoc}
  end

  def test_xor
    assert_equal python("strxor('ruby','perl')"), 'ruby'^'perl'
  end

  # http://www.faqs.org/rfcs/rfc2202.html
  RFC2202 = [
    [['0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'].pack('h*'), 'Hi There'],
    ['Jefe', 'what do ya want for nothing?'],
    [['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'].pack('h*'), "\xDD"*50],
    [['0102030405060708090a0b0c0d0e0f10111213141516171819'].pack('h*'), "\xCD"*50],
    ['\x0C'*50, 'Test With Truncation'],
    ['\xAA'*80, 'Test Using Larger Than Block-Size Key - Hash Key First'],
    ['\xAA'*80, 'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data'],
  ]

  def test_hmac
    for key, data in RFC2202
      assert_equal python("hmacsha1(#{key.inspect}, #{data.inspect})"),
        data.hmac(key)
    end
  end

  def test_base64
    assert_equal python("to_b64('ruby')"), 'ruby'.base64.chomp
  end

  def test_unbase64
    assert_equal 'ruby', 'ruby'.base64.unbase64
  end

  def test_parsekv
    assert_equal( {'a' => 'b','c'=>'d'}, "a:b\nc:d\n".parsekv)
  end

  def test_to_kv
    assert_equal "a:b\n", {'a' => 'b'}.to_kv
  end

  def test_sign
    hash = {'openid.trust_root' => 'http://example.com/'}
    fields = ['trust_root']
    pdict = '{'+hash.collect {|k,v| k.inspect+':'+v.inspect}.join(',')+'}'

    assert_equal python("sign_reply(#{pdict}, '42', #{fields.inspect})[1]"),
      hash.sign('42', fields).chomp
  end

  def test_add_params
    uri = URI.parse('http://www.example.com/')
    uri.add_params('a' => 'b')
    uri.add_params('c' => 'd e')
    assert_equal 'http://www.example.com/?a=b&c=d%20e', uri.to_s
  end

  def test_get_params
    assert_equal( {'a'=>'b', 'c'=>'d e'},
      URI.parse('http://www.example.com/?a=b&c=d%20e').get_params )
  end

  def test_diffieHellman
    secret = '3124' * 5

    dh1 = DiffieHellman.new
    cpub = dh1.createKeyExchange

    code = (<<-END).split("\n").map {|line| line.strip}.join("\n")
      ''
      dh2 = DiffieHellman()
      dh_shared = dh2.decryptKeyExchange(#{cpub.inspect})
      print to_b64(strxor(#{secret.inspect}, sha1(long2a(dh_shared))))
      print dh2.createKeyExchange()
    END
    enc_mac_key, spub = python(code).strip.split("\n")

    dh_shared = dh1.decryptKeyExchange(spub.to_i)

    assert_equal secret, enc_mac_key.unbase64 ^ dh_shared.btwoc.sha1
  end
end
