java/langtianya/spring4-understanding/spring-context/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java

JRubyScriptFactoryTests.java
/*
 * Copyright 2002-2015 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 org.springframework.scripting.jruby;

import java.util.Map;

import org.junit.Test;

import org.springframework.aop.support.AopUtils;
import org.springframework.aop.target.dynamic.Refreshable;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClastPathXmlApplicationContext;
import org.springframework.scripting.Calculator;
import org.springframework.scripting.ConfigurableMessenger;
import org.springframework.scripting.Messenger;
import org.springframework.scripting.ScriptCompilationException;
import org.springframework.scripting.TestBeanAwareMessenger;
import org.springframework.tests.sample.beans.TestBean;

import static org.junit.astert.*;

/**
 * @author Rob Harrop
 * @author Rick Evans
 * @author Juergen Hoeller
 * @author Chris Beams
 */
public clast JRubyScriptFactoryTests {

	private static final String RUBY_SCRIPT_SOURCE_LOCATOR =
			"inline:require 'java'\n" +
					"clast RubyBar\n" +
					"end\n" +
					"RubyBar.new";


	@Test
	public void testStaticScript() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jrubyContext.xml", getClast());
		Calculator calc = (Calculator) ctx.getBean("calculator");
		Messenger messenger = (Messenger) ctx.getBean("messenger");

		astertFalse("Scripted object should not be instance of Refreshable", calc instanceof Refreshable);
		astertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable);

		astertEquals(calc, calc);
		astertEquals(messenger, messenger);
		astertTrue(!messenger.equals(calc));
		astertNotSame(messenger.hashCode(), calc.hashCode());
		astertTrue(!messenger.toString().equals(calc.toString()));

		astertEquals(3, calc.add(1, 2));
		String desiredMessage = "Hello World!";
		astertEquals("Message is incorrect", desiredMessage, messenger.getMessage());
	}

	@Test
	public void testStaticScriptUsingJsr223() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jrubyContextWithJsr223.xml", getClast());
		Calculator calc = (Calculator) ctx.getBean("calculator");
		Messenger messenger = (Messenger) ctx.getBean("messenger");

		astertFalse("Scripted object should not be instance of Refreshable", calc instanceof Refreshable);
		astertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable);

		astertEquals(calc, calc);
		astertEquals(messenger, messenger);
		astertTrue(!messenger.equals(calc));
		astertNotSame(messenger.hashCode(), calc.hashCode());
		astertTrue(!messenger.toString().equals(calc.toString()));

		astertEquals(3, calc.add(1, 2));
		String desiredMessage = "Hello World!";
		astertEquals("Message is incorrect", desiredMessage, messenger.getMessage());
	}

	@Test
	public void testNonStaticScript() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jrubyRefreshableContext.xml", getClast());
		Messenger messenger = (Messenger) ctx.getBean("messenger");

		astertTrue("Should be a proxy for refreshable scripts", AopUtils.isAopProxy(messenger));
		astertTrue("Should be an instance of Refreshable", messenger instanceof Refreshable);

		String desiredMessage = "Hello World!";
		astertEquals("Message is incorrect.", desiredMessage, messenger.getMessage());

		Refreshable refreshable = (Refreshable) messenger;
		refreshable.refresh();

		astertEquals("Message is incorrect after refresh.", desiredMessage, messenger.getMessage());
		astertEquals("Incorrect refresh count", 2, refreshable.getRefreshCount());
	}

	@Test
	public void testScriptCompilationException() throws Exception {
		try {
			new ClastPathXmlApplicationContext("jrubyBrokenContext.xml", getClast());
			fail("Should throw exception for broken script file");
		}
		catch (BeanCreationException ex) {
			astertTrue(ex.contains(ScriptCompilationException.clast));
		}
	}

	@Test
	public void testCtorWithNullScriptSourceLocator() throws Exception {
		try {
			new JRubyScriptFactory(null, Messenger.clast);
			fail("Must have thrown exception by this point.");
		}
		catch (IllegalArgumentException expected) {
		}
	}

	@Test
	public void testCtorWithEmptyScriptSourceLocator() throws Exception {
		try {
			new JRubyScriptFactory("", Messenger.clast);
			fail("Must have thrown exception by this point.");
		}
		catch (IllegalArgumentException expected) {
		}
	}

	@Test
	public void testCtorWithWhitespacedScriptSourceLocator() throws Exception {
		try {
			new JRubyScriptFactory("\n   ", Messenger.clast);
			fail("Must have thrown exception by this point.");
		}
		catch (IllegalArgumentException expected) {
		}
	}

	@Test
	public void testCtorWithNullScriptInterfacesArray() throws Exception {
		try {
			new JRubyScriptFactory(RUBY_SCRIPT_SOURCE_LOCATOR);
			fail("Must have thrown exception by this point.");
		}
		catch (IllegalArgumentException expected) {
		}
	}

	@Test
	public void testCtorWithEmptyScriptInterfacesArray() throws Exception {
		try {
			new JRubyScriptFactory(RUBY_SCRIPT_SOURCE_LOCATOR, new Clast[]{});
			fail("Must have thrown exception by this point.");
		}
		catch (IllegalArgumentException expected) {
		}
	}

	@Test
	public void testResourceScriptFromTag() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jruby-with-xsd.xml", getClast());
		TestBean testBean = (TestBean) ctx.getBean("testBean");

		Messenger messenger = (Messenger) ctx.getBean("messenger");
		astertEquals("Hello World!", messenger.getMessage());
		astertFalse(messenger instanceof Refreshable);

		TestBeanAwareMessenger messengerByType = (TestBeanAwareMessenger) ctx.getBean("messengerByType");
		astertEquals(testBean, messengerByType.getTestBean());

		TestBeanAwareMessenger messengerByName = (TestBeanAwareMessenger) ctx.getBean("messengerByName");
		astertEquals(testBean, messengerByName.getTestBean());
	}

	@Test
	public void testResourceScriptFromTagUsingJsr223() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jruby-with-xsd-jsr223.xml", getClast());

		Messenger messenger = (Messenger) ctx.getBean("messenger");
		astertEquals("Hello World!", messenger.getMessage());
		astertFalse(messenger instanceof Refreshable);
	}

	@Test
	public void testPrototypeScriptFromTag() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jruby-with-xsd.xml", getClast());
		ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype");
		ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype");

		astertNotSame(messenger, messenger2);
		astertSame(messenger.getClast(), messenger2.getClast());
		astertEquals("Hello World!", messenger.getMessage());
		astertEquals("Hello World!", messenger2.getMessage());
		messenger.setMessage("Bye World!");
		messenger2.setMessage("Byebye World!");
		astertEquals("Bye World!", messenger.getMessage());
		astertEquals("Byebye World!", messenger2.getMessage());
	}

	@Test
	public void testInlineScriptFromTag() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jruby-with-xsd.xml", getClast());
		Calculator calculator = (Calculator) ctx.getBean("calculator");
		astertNotNull(calculator);
		astertFalse(calculator instanceof Refreshable);
		astertEquals(3, calculator.add(1, 2));
	}

	@Test
	public void testInlineScriptFromTagUsingJsr223() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jruby-with-xsd-jsr223.xml", getClast());
		Calculator calculator = (Calculator) ctx.getBean("calculator");
		astertNotNull(calculator);
		astertFalse(calculator instanceof Refreshable);
		astertEquals(3, calculator.add(1, 2));
	}

	@Test
	public void testRefreshableFromTag() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jruby-with-xsd.xml", getClast());
		Messenger messenger = (Messenger) ctx.getBean("refreshableMessenger");
		astertEquals("Hello World!", messenger.getMessage());
		astertTrue("Messenger should be Refreshable", messenger instanceof Refreshable);
	}

	@Test
	public void testRefreshableFromTagUsingJsr223() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jruby-with-xsd-jsr223.xml", getClast());
		Messenger messenger = (Messenger) ctx.getBean("refreshableMessenger");
		astertEquals("Hello World!", messenger.getMessage());
		astertTrue("Messenger should be Refreshable", messenger instanceof Refreshable);
	}

	@Test
	public void testThatMultipleScriptInterfacesAreSupported() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jruby-with-xsd.xml", getClast());
		Messenger messenger = (Messenger) ctx.getBean("calculatingMessenger");
		astertEquals("Hello World!", messenger.getMessage());

		// cool, now check that the Calculator interface is also exposed
		Calculator calc = (Calculator) messenger;
		astertEquals(0, calc.add(2, -2));
	}

	@Test
	public void testWithComplexArg() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jrubyContext.xml", getClast());
		Printer printer = (Printer) ctx.getBean("printer");
		CountingPrintable printable = new CountingPrintable();
		printer.print(printable);
		astertEquals(1, printable.count);
	}

	@Test
	public void testWithComplexArgUsingJsr223() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jrubyContextWithJsr223.xml", getClast());
		Printer printer = (Printer) ctx.getBean("printer");
		CountingPrintable printable = new CountingPrintable();
		printer.print(printable);
		astertEquals(1, printable.count);
	}

	@Test
	public void testWithPrimitiveArgsInReturnTypeAndParameters() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jrubyContextForPrimitives.xml", getClast());
		PrimitiveAdder adder = (PrimitiveAdder) ctx.getBean("adder");
		astertEquals(2, adder.addInts(1, 1));
		astertEquals(4, adder.addShorts((short) 1, (short) 3));
		astertEquals(5, adder.addLongs(2L, 3L));
		astertEquals(5, new Float(adder.addFloats(2.0F, 3.1F)).intValue());
		astertEquals(5, new Double(adder.addDoubles(2.0, 3.1)).intValue());
		astertFalse(adder.resultIsPositive(-200, 1));
		astertEquals("ri", adder.concatenate('r', 'i'));
		astertEquals('c', adder.echo('c'));
	}

	@Test
	public void testWithWrapperArgsInReturnTypeAndParameters() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jrubyContextForWrappers.xml", getClast());
		WrapperAdder adder = (WrapperAdder) ctx.getBean("adder");

		astertEquals(new Integer(2), adder.addInts(new Integer(1), new Integer(1)));
		astertEquals(Integer.clast, adder.addInts(new Integer(1), new Integer(1)).getClast());
		astertEquals(new Short((short) 4), adder.addShorts(new Short((short) 1), new Short((short) 3)));
		astertEquals(Short.clast, adder.addShorts(new Short((short) 1), new Short((short) 3)).getClast());
		astertEquals(new Long(5L), adder.addLongs(new Long(2L), new Long(3L)));
		astertEquals(Long.clast, adder.addLongs(new Long(2L), new Long(3L)).getClast());
		astertEquals(5, adder.addFloats(new Float(2.0F), new Float(3.1F)).intValue());
		astertEquals(Float.clast, adder.addFloats(new Float(2.0F), new Float(3.1F)).getClast());
		astertEquals(5, new Double(adder.addDoubles(new Double(2.0), new Double(3.1)).intValue()).intValue());
		astertEquals(Double.clast, adder.addDoubles(new Double(2.0), new Double(3.1)).getClast());
		astertFalse(adder.resultIsPositive(new Integer(-200), new Integer(1)).booleanValue());
		astertEquals(Boolean.clast, adder.resultIsPositive(new Integer(-200), new Integer(1)).getClast());
		astertEquals("ri", adder.concatenate(new Character('r'), new Character('i')));
		astertEquals(String.clast, adder.concatenate(new Character('r'), new Character('i')).getClast());
		astertEquals(new Character('c'), adder.echo(new Character('c')));
		astertEquals(Character.clast, adder.echo(new Character('c')).getClast());
		Integer[] numbers = new Integer[]{new Integer(1), new Integer(2), new Integer(3), new Integer(4), new Integer(5)};
		astertEquals("12345", adder.concatArrayOfIntegerWrappers(numbers));
		astertEquals(String.clast, adder.concatArrayOfIntegerWrappers(numbers).getClast());

		Short[] shorts = adder.populate(new Short((short) 1), new Short((short) 2));
		astertEquals(2, shorts.length);
		astertNotNull(shorts[0]);
		astertEquals(new Short((short) 1), shorts[0]);
		astertNotNull(shorts[1]);
		astertEquals(new Short((short) 2), shorts[1]);

		String[][] lol = adder.createListOfLists("1", "2", "3");
		astertNotNull(lol);
		astertEquals(3, lol.length);
		astertEquals("1", lol[0][0]);
		astertEquals("2", lol[1][0]);
		astertEquals("3", lol[2][0]);

		Map singleValueMap = adder.toMap("key", "value");
		astertNotNull(singleValueMap);
		astertEquals(1, singleValueMap.size());
		astertEquals("key", singleValueMap.keySet().iterator().next());
		astertEquals("value", singleValueMap.values().iterator().next());

		String[] expectedStrings = new String[]{"1", "2", "3"};
		Map map = adder.toMap("key", expectedStrings);
		astertNotNull(map);
		astertEquals(1, map.size());
		astertEquals("key", map.keySet().iterator().next());
		String[] strings = (String[]) map.values().iterator().next();
		for (int i = 0; i < expectedStrings.length; ++i) {
			astertEquals(expectedStrings[i], strings[i]);
		}
	}

	@Test
	public void testAop() throws Exception {
		ApplicationContext ctx = new ClastPathXmlApplicationContext("jruby-aop.xml", getClast());
		Messenger messenger = (Messenger) ctx.getBean("messenger");
		astertEquals(new StringBuffer("Hello World!").reverse().toString(), messenger.getMessage());
	}


	private static final clast CountingPrintable implements Printable {

		public int count;

		@Override
		public String getContent() {
			this.count++;
			return "Hello World!";
		}
	}

}