blob: 4312cbff04d43a36d2eeaaa06c010db620eb41ca [file] [log] [blame]
/*
* Copyright 2004-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package groovy.lang
/**
* @author Graeme Rocher
*/
class ExpandoMetaClassTest extends GroovyTestCase {
void testOverrideStaticMethod() {
TestStatic.metaClass.'static'.f = { "first" }
TestStatic.metaClass.'static'.f = { "second" }
assertEquals "second",TestStatic.f("")
}
void testStaticBeanStyleProperties() {
def mc = new ExpandoMetaClass(TestInvokeMethod.class, true)
mc.initialize()
mc.allowChangesAfterInit = true
GroovySystem.metaClassRegistry.setMetaClass(TestInvokeMethod.class, mc)
mc.'static'.getHello = {-> "bar!"}
assertEquals "bar!", TestInvokeMethod.hello
}
void testOverrideInvokeStaticMethod() {
def mc = new ExpandoMetaClass(TestInvokeMethod.class, true)
mc.initialize()
mc.allowChangesAfterInit = true
GroovySystem.metaClassRegistry.setMetaClass(TestInvokeMethod.class, mc)
mc.'static'.invokeMethod = {String methodName, args ->
def metaMethod = mc.getStaticMetaMethod(methodName, args)
def result = null
if (metaMethod) result = metaMethod.invoke(delegate, args)
else {
result = "foo!"
}
result
}
assertEquals "bar!", TestInvokeMethod.myStaticMethod()
assertEquals "foo!", TestInvokeMethod.dynamicMethod()
}
void testOverrideInvokeMethod() {
def mc = new ExpandoMetaClass(TestInvokeMethod.class)
mc.initialize()
mc.allowChangesAfterInit = true
assert mc.hasMetaMethod("invokeMe", [String] as Class[])
mc.invokeMethod = {String name, args ->
def mm = delegate.metaClass.getMetaMethod(name, args)
mm ? mm.invoke(delegate, args) : "bar!!"
}
def t = new TestInvokeMethod()
t.metaClass = mc
assertEquals "bar!!", t.doStuff()
assertEquals "Foo!! hello", t.invokeMe("hello")
}
void testOverrideSetProperty() {
def mc = new ExpandoMetaClass(TestGetProperty.class)
mc.initialize()
mc.allowChangesAfterInit = true
assert mc.hasMetaProperty("name")
def testValue = null
mc.setProperty = {String name, value ->
def mp = delegate.metaClass.getMetaProperty(name)
if (mp) {mp.setProperty(delegate, value)} else {testValue = value}
}
def t = new TestGetProperty()
t.metaClass = mc
t.name = "Bob"
assertEquals "Bob", t.name
t.foo = "bar"
assertEquals "bar", testValue
}
void testOverrideGetProperty() {
def mc = new ExpandoMetaClass(TestGetProperty.class)
mc.initialize()
mc.allowChangesAfterInit = true
assert mc.hasMetaProperty("name")
mc.getProperty = {String name ->
def mp = delegate.metaClass.getMetaProperty(name)
mp ? mp.getProperty(delegate) : "foo $name"
}
def t = new TestGetProperty()
t.metaClass = mc
assertEquals "foo bar", t.getProperty("bar")
assertEquals "foo bar", t.bar
assertEquals "Fred", t.getProperty("name")
assertEquals "Fred", t.name
}
void testBooleanGetterWithClosure() {
def metaClass = new ExpandoMetaClass(Test.class)
metaClass.initialize()
metaClass.allowChangesAfterInit = true
metaClass.isValid = {-> true}
def t = new Test()
t.metaClass = metaClass
assert t.isValid()
assert t.valid
}
void testAllowAdditionOfProperties() {
def metaClass = new ExpandoMetaClass(Test.class)
metaClass.allowChangesAfterInit = true
metaClass.getOne << {->
"testme"
}
metaClass.initialize()
try {
metaClass.getTwo << {->
"testagain"
}
}
catch (RuntimeException e) {
fail("Should have allowed addition of new method")
}
def t = new Test()
t.metaClass = metaClass
assertEquals "testme", t.one
assertEquals "testagain", t.two
}
void testAllowAdditionOfMethods() {
def metaClass = new ExpandoMetaClass(Test.class)
metaClass.allowChangesAfterInit = true
metaClass.myMethod << {->
"testme"
}
metaClass.initialize()
try {
metaClass.mySecondMethod << {->
"testagain"
}
}
catch (RuntimeException e) {
fail("Should have allowed addition of new method")
}
def t = new Test()
t.metaClass = metaClass
assertEquals "testme", t.myMethod()
assertEquals "testagain", t.mySecondMethod()
}
void testForbiddenAdditionOfMethods() {
def metaClass = new ExpandoMetaClass(Test.class)
metaClass.myMethod << {
"testme"
}
metaClass.initialize()
def t = new Test()
try {
metaClass.mySecondMethod << {
"testagain"
}
fail("Should have thrown exception")
}
catch (RuntimeException e) {
// expected
}
}
void testPropertyGetterWithClosure() {
def metaClass = new ExpandoMetaClass(Test.class)
metaClass.getSomething = {-> "testme"}
metaClass.initialize()
def t = new Test()
t.metaClass = metaClass
assertEquals "testme", t.getSomething()
assertEquals "testme", t.something
}
void testPropertySetterWithClosure() {
def metaClass = new ExpandoMetaClass(Test.class)
def testSet = null
metaClass.setSomething = {String txt -> testSet = txt}
metaClass.initialize()
def t = new Test()
t.metaClass = metaClass
t.something = "testme"
assertEquals "testme", testSet
t.setSomething("test2")
assertEquals "test2", testSet
}
void testNewMethodOverloading() {
def metaClass = new ExpandoMetaClass(Test.class)
metaClass.overloadMe << {String txt -> txt} << {Integer i -> i}
metaClass.initialize()
def t = new Test()
t.metaClass = metaClass
assertEquals "test", t.overloadMe("test")
assertEquals 10, t.overloadMe(10)
}
void testOverloadExistingMethodAfterInitialize() {
def t = new Test()
assertEquals "test", t.doSomething("test")
def metaClass = new ExpandoMetaClass(Test.class)
metaClass.allowChangesAfterInit = true
metaClass.initialize()
metaClass.doSomething = {Integer i -> i + 1}
t.metaClass = metaClass
assertEquals "test", t.doSomething("test")
assertEquals 11, t.doSomething(10)
}
void testOverloadExistingMethodBeforeInitialize() {
def t = new Test()
assertEquals "test", t.doSomething("test")
def metaClass = new ExpandoMetaClass(Test.class)
metaClass.allowChangesAfterInit = true
metaClass.doSomething = {Integer i -> i + 1}
metaClass.initialize()
t.metaClass = metaClass
assertEquals "test", t.doSomething("test")
assertEquals 11, t.doSomething(10)
}
void testNewPropertyMethod() {
def metaClass = new ExpandoMetaClass(Test.class)
metaClass.something = "testme"
metaClass.initialize()
def t = new Test()
t.metaClass = metaClass
assertEquals "testme", t.getSomething()
assertEquals "testme", t.something
t.something = "test2"
assertEquals "test2", t.something
assertEquals "test2", t.getSomething()
def t2 = new Test()
t2.metaClass = metaClass
// now check that they're not sharing the same property!
assertEquals "testme", t2.something
assertEquals "test2", t.something
t2.setSomething("test3")
assertEquals "test3", t2.something
}
void testCheckFailOnExisting() {
def metaClass = new ExpandoMetaClass(Test.class)
try {
metaClass.existing << {->
"should fail. already exists!"
}
fail("Should have thrown exception when method already exists")
}
catch (Exception e) {
// expected
}
}
void testCheckFailOnExistingConstructor() {
def metaClass = new ExpandoMetaClass(Test.class)
try {
metaClass.constructor << {->
"should fail. already exists!"
}
fail("Should have thrown exception when method already exists")
}
catch (Exception e) {
// expected
}
}
void testCheckFailOnExistingStaticMethod() {
def metaClass = new ExpandoMetaClass(Test.class)
try {
metaClass.'static'.existingStatic << {->
"should fail. already exists!"
}
fail("Should have thrown exception when method already exists")
}
catch (Exception e) {
// expected
}
}
void testNewStaticMethod() {
def metaClass = new ExpandoMetaClass(Test.class, true)
metaClass.'static'.myStaticMethod << {String txt ->
"testme"
}
metaClass.initialize()
assertEquals "testme", Test.myStaticMethod("blah")
}
void testReplaceStaticMethod() {
def metaClass = new ExpandoMetaClass(Test.class, true)
metaClass.'static'.existingStatic = {->
"testme"
}
metaClass.initialize()
assertEquals "testme", Test.existingStatic()
}
void testNewZeroArgumentStaticMethod() {
def metaClass = new ExpandoMetaClass(Test.class, true)
metaClass.'static'.myStaticMethod = {->
"testme"
}
metaClass.initialize()
assertEquals "testme", Test.myStaticMethod()
}
void testNewInstanceMethod() {
def metaClass = new ExpandoMetaClass(Test.class)
metaClass.myMethod << {
"testme"
}
metaClass.initialize()
def t = new Test()
t.metaClass = metaClass
assertEquals "testme", t.myMethod()
}
void testNewConstructor() {
def metaClass = new ExpandoMetaClass(Test.class, true)
metaClass.constructor << {String txt ->
def t = Test.class.newInstance()
t.name = txt
return t
}
metaClass.initialize()
def t = new Test("testme")
assert t
assertEquals "testme", t.name
GroovySystem.metaClassRegistry.removeMetaClass(Test.class)
}
void testReplaceConstructor() {
def metaClass = new ExpandoMetaClass(Test.class, true)
metaClass.constructor = {->
"testme"
}
metaClass.initialize()
def t = new Test()
assert t
assertEquals "testme", t
GroovySystem.metaClassRegistry.removeMetaClass(Test.class)
}
void testReplaceInstanceMethod() {
def metaClass = new ExpandoMetaClass(Test.class)
metaClass.existing2 = {Object i ->
"testme"
}
metaClass.initialize()
def t = new Test()
t.metaClass = metaClass
def var = 1
assertEquals "testme", t.existing2(var)
}
void testBorrowMethodFromAnotherClass() {
def metaClass = new ExpandoMetaClass(Test.class)
def a = new Another()
metaClass.borrowMe = a.&another
metaClass.borrowMeToo = a.&noArgs
metaClass.initialize()
def t = new Test()
t.metaClass = metaClass
assertEquals "mine blah!", t.borrowMe("blah")
// GROOVY-1993
// assertEquals "no args here!", t.borrowMeToo()
}
void testBorrowByName() {
println 'testBorrowByName'
def metaClass = new ExpandoMetaClass(Test.class)
def a = new Another()
metaClass.borrowMe = a.&'another'
metaClass.borrowMeToo = a.&'noArgs'
metaClass.initialize()
def t = new Test()
t.metaClass = metaClass
assertEquals "mine blah!", t.borrowMe("blah")
// GROOVY-1993
// assertEquals "no args here!", t.borrowMeToo()
}
void testAddIdenticalPropertyToChildAndParent() {
ExpandoMetaClass.enableGlobally()
doMethods(SuperClass.class)
doMethods(ChildClass.class)
def child = new ChildClass()
def parent = new SuperClass()
assert parent.errors == null
parent.errors = [3, 2, 1, 0]
assert parent.errors.size() == 4
assert child.errors == null
child.errors = [1, 2, 3]
assert child.errors.size() == 3
//TODO disable ExpandoMetaClass
}
def doMethods(clazz) {
def metaClass = clazz.metaClass
metaClass.setErrors = {errors ->
thingo = errors
}
metaClass.getErrors = {->
return thingo
}
}
}
class SuperClass {
def thingo
}
class ChildClass extends SuperClass {
}
class TestInvokeMethod {
def invokeMe(String boo) {"Foo!! $boo"}
static myStaticMethod() {"bar!"}
}
class TestGetProperty {
String name = "Fred"
}
class Test {
String name
def existing2(obj) {
"hello2!"
}
def existing() {
"hello!"
}
def doSomething(Object txt) {txt}
static existingStatic() {
"I exist"
}
}
class Another {
def another(txt) {
"mine ${txt}!"
}
def noArgs() {
"no args here!"
}
}
class Child extends Test {
def aChildMethod() {
"hello children"
}
}
class TestStatic {}