package org.kohsuke.stapler.jelly.jruby;

import org.apache.commons.io.IOUtils;
import org.apache.commons.jelly.*;
import org.jruby.embed.LocalContextScope;
import org.jruby.embed.LocalVariableBehavior;
import org.jruby.embed.ScriptingContainer;
import org.jruby.runtime.backtrace.TraceType;
import org.kohsuke.stapler.MetaClass;
import org.kohsuke.stapler.StaplerTestCase;
import org.kohsuke.stapler.jelly.JellyClassLoaderTearOff;

import java.io.IOException;
import java.io.StringWriter;

/**
 * @author Hiroshi Nakamura
 */
public class JRubyJellyScriptTest extends StaplerTestCase {
    private ScriptingContainer ruby;
    private JellyContext context;

    public JRubyJellyScriptTest() {
        ruby = new ScriptingContainer(LocalContextScope.SINGLETHREAD, LocalVariableBehavior.TRANSIENT);
        ruby.setClassLoader(getClass().getClassLoader());
        ruby.getProvider().getRubyInstanceConfig().setTraceType(TraceType.traceTypeFor("raw"));
        ruby.setOutput(System.out);
        ruby.setError(System.err);
    }

    @Override
    public void setUp() throws Exception {
        super.setUp();
        MetaClass mc = webApp.getMetaClass(SanityTest.class);
        context = mc.classLoader.getTearOff(JellyClassLoaderTearOff.class).createContext();
    }

    public void testContext() throws Exception {
        Script script = getScript("test_context.erb");
        context.setVariable("name", "ERB");
        StringWriter out = new StringWriter();
        script.run(context, XMLOutput.createXMLOutput(out));
        assertEquals("ERB", out.toString());
    }

    public void testTaglib() throws Exception {
        Script script = getScript("test_taglib.erb");
        context.setVariable("name", "ERB");
        StringWriter out = new StringWriter();
        script.run(context, XMLOutput.createXMLOutput(out));
        assertEquals("<b>Hello from Jelly to ERB</b><i>\n" +
                "  47\n" +
                "</i>", out.toString());
    }

    public void testNoSuchTaglib() throws Exception {
        Script script = getScript("test_nosuch_taglib.erb");
        StringWriter out = new StringWriter();
        try {
            script.run(context, XMLOutput.createXMLOutput(out));
            fail("should raise JellyTagException");
        } catch (JellyTagException jte) {
            assertTrue(true);
        }
    }

    public void testNoSuchTagscript() throws Exception {
        Script script = getScript("test_nosuch_tagscript.erb");
        StringWriter out = new StringWriter();
        try {
            script.run(context, XMLOutput.createXMLOutput(out));
            fail("should raise JellyTagException");
        } catch (JellyTagException jte) {
            assertTrue(true);
        }
    }

    private Script getScript(String fixture) throws IOException {
        ruby.put("template", getTemplate(fixture));
        return (Script) ruby.runScriptlet(
                "require 'org/kohsuke/stapler/jelly/jruby/JRubyJellyScriptImpl'\n" +
                        "JRubyJellyScriptImpl::JRubyJellyERbScript.new(template)");

    }

    private String getTemplate(String fixture) throws IOException {
        return IOUtils.toString(getClass().getResource(fixture).openStream(), "UTF-8");
    }
}

@@ -1151,14 +1151,24 @@
 ass(
-Sanity
+JRubyJellyScript
 Test
@@ -1921,24 +1921,24 @@
  %22  47%5Cn%22 +%0A
-
             
@@ -1965,32 +1965,1385 @@
 ring());%0A    %7D%0A%0A
+    public void testThreadSafety() throws Exception %7B%0A        Script script = getScript(%22test_taglib.erb%22);%0A        int num = 100;%0A        EvaluatorThread%5B%5D threads = new EvaluatorThread%5Bnum%5D;%0A        for (int idx = 0; idx %3C num; ++idx) %7B%0A            threads%5Bidx%5D = new EvaluatorThread(script, idx);%0A            threads%5Bidx%5D.start();%0A        %7D%0A        for (int idx = 0; idx %3C num; ++idx) %7B%0A            threads%5Bidx%5D.join();%0A            System.out.println(threads%5Bidx%5D.result);%0A        %7D%0A    %7D%0A%0A    private class EvaluatorThread extends Thread %7B%0A        private final Script script;%0A        private final int idx;%0A        private String result = null;%0A%0A        private EvaluatorThread(Script script, int idx) %7B%0A            this.script = script;%0A            this.idx = idx;%0A        %7D%0A%0A        public void run() %7B%0A            try %7B%0A                MetaClass mc = webApp.getMetaClass(JRubyJellyScriptTest.class);%0A                JellyContext context = mc.classLoader.getTearOff(JellyClassLoaderTearOff.class).createContext();%0A                context.setVariable(%22name%22, %22ERB%22 + idx);%0A%0A                StringWriter out = new StringWriter();%0A                script.run(context, XMLOutput.createXMLOutput(out));%0A                result = out.toString();%0A            %7D catch (Exception e) %7B%0A                result = e.getMessage();%0A            %7D%0A        %7D%0A    %7D%0A%0A
     public void 

Add Thread isolation test (failing now)