All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jvnet.hudson.test.JellyTestSuiteBuilder Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *
 * Copyright (c) 2004-2009, Oracle Corporation
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *
 *
 *
 *
 *******************************************************************************/ 

package org.jvnet.hudson.test;

import junit.framework.TestCase;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import org.apache.commons.io.FileUtils;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import org.jvnet.hudson.test.junit.GroupedTest;
import org.kohsuke.stapler.MetaClassLoader;
import org.kohsuke.stapler.jelly.JellyClassLoaderTearOff;

import java.io.File;
import java.net.URL;
import java.util.Collection;
import java.util.Enumeration;
import java.util.concurrent.Callable;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hudsonci.xpath.XPath;
import org.hudsonci.xpath.XPathException;

/**
 * Builds up a {@link TestSuite} for performing static syntax checks on Jelly
 * scripts.
 *
 * @author Kohsuke Kawaguchi
 */
public class JellyTestSuiteBuilder {

    /**
     * Given a jar file or a class file directory, recursively search all the
     * Jelly files and build a {@link TestSuite} that performs static syntax
     * checks.
     */
    public static TestSuite build(File res) throws Exception {
        TestSuite ts = new JellyTestSuite();

        final JellyClassLoaderTearOff jct = new MetaClassLoader(JellyTestSuiteBuilder.class.getClassLoader()).loadTearOff(JellyClassLoaderTearOff.class);

        if (res.isDirectory()) {
            for (final File jelly : (Collection) FileUtils.listFiles(res, new String[]{"jelly"}, true)) {
                ts.addTest(new JellyCheck(jelly.toURI().toURL(), jct));
            }
        }
        if (res.getName().endsWith(".jar")) {
            String jarUrl = res.toURI().toURL().toExternalForm();
            JarFile jf = new JarFile(res);
            Enumeration e = jf.entries();
            while (e.hasMoreElements()) {
                JarEntry ent = e.nextElement();
                if (ent.getName().endsWith(".jelly")) {
                    ts.addTest(new JellyCheck(new URL("jar:" + jarUrl + "!/" + ent.getName()), jct));
                }
            }
            jf.close();
        }
        return ts;
    }

    private static class JellyCheck extends TestCase {

        private final URL jelly;
        private final JellyClassLoaderTearOff jct;

        public JellyCheck(URL jelly, JellyClassLoaderTearOff jct) {
            super(jelly.getPath());
            this.jelly = jelly;
            this.jct = jct;
        }

        @Override
        protected void runTest() throws Exception {
            jct.createContext().compileScript(jelly);
            Document dom = new SAXReader().read(jelly);
            checkLabelFor(dom);
            // TODO: what else can we check statically? use of taglibs?
        }

        /**
         * Makes sure that <label for=...> is not used inside config.jelly
         * nor global.jelly
         */
        private void checkLabelFor(Document dom) {
            if (isConfigJelly() || isGlobalJelly()) {
              try {
                if (!new XPath("//label[@for]").selectNodes(dom).isEmpty()) {
                    throw new AssertionError("