require 'test/unit'

class TestBlockPrivate < Test::Unit::TestCase
  module TestModule
  end

  def test_public_method_def
    assert compile_in_safe_class("def foo\nend").public_instance_methods.include?("foo")
  end

  def test_blocked_private_method_def
    test_class = compile_in_safe_class("def bar\nend\nclass_eval do;private;def foo;end;end;def pub;end")
    assert test_class.private_instance_methods.include?("foo"), "foo not private"
    assert test_class.public_instance_methods.include?("pub"), "pub not public"
  end

  def test_blocked_private_stays_private
    test_class = compile_in_safe_class("private\ndef foo\nend")
    compile_in_class(test_class, "class_eval do;private;def foo;end;end")
    assert test_class.private_instance_methods.include?("foo"), "foo not private"
  end

  def test_with_private_protected_becomes_private
    test_class = compile_in_safe_class("protected;def foo;end")
    compile_in_class(test_class, "class_eval do;private;def foo;end;end")
    assert !test_class.protected_instance_methods.include?("foo"), "foo is protected"
    assert test_class.private_instance_methods.include?("foo"), "foo not private"
  end

  def self.safe_class_name
    @class_ctr ||= 0
    @class_ctr += 1
    puts "class_ctr is #@class_ctr"
    "ClassForTest#{@class_ctr}"
  end

  private
  def compile_in_safe_class(string)
    compile_in_class_name(self.class.safe_class_name, string)
  end

  def compile_in_class_name(class_name, string)
    TestModule.module_eval "class #{class_name}\n#{string}\nend"
    TestModule.const_get(class_name.to_sym)
  end

  def compile_in_class(klass, string)
    compile_in_class_name(klass.name.sub("#{TestModule.name}::",""), string)
  end

end

