Package com.asakusafw.compiler.operator

Source Code of com.asakusafw.compiler.operator.OperatorCompilerTestRoot

/**
* Copyright 2011-2014 Asakusa Framework Team.
*
* 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 com.asakusafw.compiler.operator;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.Processor;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;

import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.After;

import com.asakusafw.utils.collections.Lists;
import com.asakusafw.utils.collections.Sets;
import com.asakusafw.utils.graph.Graph;
import com.asakusafw.utils.graph.Graphs;
import com.asakusafw.utils.java.jsr199.testing.SafeProcessor;
import com.asakusafw.utils.java.jsr199.testing.VolatileCompiler;
import com.asakusafw.utils.java.jsr199.testing.VolatileJavaFile;
import com.asakusafw.utils.java.model.syntax.ModelFactory;
import com.asakusafw.utils.java.model.util.Models;
import com.asakusafw.vocabulary.flow.Source;
import com.asakusafw.vocabulary.flow.graph.FlowElement;
import com.asakusafw.vocabulary.flow.graph.FlowElementInput;
import com.asakusafw.vocabulary.flow.graph.FlowElementOutput;
import com.asakusafw.vocabulary.flow.graph.FlowIn;
import com.asakusafw.vocabulary.flow.graph.PortConnection;
import com.asakusafw.vocabulary.flow.testing.MockIn;

/**
* 演算子コンパイラに関するテストの基底。
*/
public class OperatorCompilerTestRoot {

    ModelFactory f = Models.getModelFactory();

    private final VolatileCompiler compiler = new VolatileCompiler();

    private final List<JavaFileObject> sources = Lists.create();

    /**
     * コンパイル時に{@code true}になっていたらソースのダンプを表示する。
     */
    protected boolean dump = true;

    /**
     * テストの情報を破棄する。
     * @throws Exception 例外が発生した場合
     */
    @After
    public void tearDown() throws Exception {
        compiler.close();
    }

    /**
     * 指定のクラスローダーからクラスをロードし、そのクラスのインスタンスを生成して返す。
     * @param loader クラスローダー
     * @param name クラスの名前
     * @return 生成したインスタンス
     */
    protected Object create(ClassLoader loader, String name) {
        try {
            Class<?> loaded = loader.loadClass(name);
            return loaded.newInstance();
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }

    /**
     * 指定の名前を持つメソッドを起動した結果を返す。
     * @param object 対象のオブジェクト
     * @param name メソッドの名前
     * @param arguments 引数の一覧
     * @return 起動結果
     */
    protected Object invoke(Object object, String name, Object... arguments) {
        try {
            for (Method method : object.getClass().getMethods()) {
                if (method.getName().equals(name)) {
                    return method.invoke(object, arguments);
                }
            }
        } catch (Exception e) {
            throw new AssertionError(e);
        }
        throw new AssertionError(name);
    }

    /**
     * 指定の名前を持つフィールドの内容を返す。
     * @param object 対象のオブジェクト
     * @param name フィールドの名前
     * @return 参照結果
     */
    protected Object access(Object object, String name) {
        try {
            for (Field field : object.getClass().getFields()) {
                if (field.getName().equals(name)) {
                    return field.get(object);
                }
            }
        } catch (Exception e) {
            throw new AssertionError(e);
        }
        throw new AssertionError(name);
    }

    /**
     * 指定の名前を持つフィールドの内容を演算子の出力として返す。
     * @param dataType データの種類
     * @param object 対象のオブジェクト
     * @param name フィールドの名前
     * @param <T> データの種類
     * @return 参照結果
     */
    @SuppressWarnings("unchecked")
    protected <T> Source<T> output(Class<T> dataType, Object object, String name) {
        try {
            for (Field field : object.getClass().getFields()) {
                if (field.getName().equals(name)) {
                    return (Source<T>) field.get(object);
                }
            }
        } catch (Exception e) {
            throw new AssertionError(e);
        }
        throw new AssertionError(name);
    }

    /**
     * 文字列の集合との比較を行う述語を返す。
     * @param names 対象の文字列の一覧
     * @return 述語
     */
    protected Matcher<? super Set<String>> isJust(String... names) {
        return Matchers.<Set<String>>is(Sets.from(names));
    }

    /**
     * 指定の入力から辿れるすべての要素のグラフを返す。
     * @param inputs 入力
     * @return グラフ
     */
    protected Graph<String> toGraph(MockIn<?>...inputs) {
        FlowElement[] elements = new FlowElement[inputs.length];
        for (int i = 0; i < inputs.length; i++) {
            elements[i] = inputs[i].toElement();
        }
        return toGraph(elements);
    }

    /**
     * 指定の入力から辿れるすべての要素のグラフを返す。
     * @param inputs 入力
     * @return グラフ
     */
    protected Graph<String> toGraph(List<FlowIn<?>> inputs) {
        FlowElement[] elements = new FlowElement[inputs.size()];
        for (int i = 0, n = inputs.size(); i < n; i++) {
            elements[i] = inputs.get(i).getFlowElement();
        }
        return toGraph(elements);
    }

    /**
     * 指定の入力から辿れるすべての要素のグラフを返す。
     * @param startingElements 開始要素の一覧
     * @return グラフ
     */
    protected Graph<String> toGraph(FlowElement... startingElements) {
        Set<String> saw = Sets.create();
        LinkedList<FlowElement> work = new LinkedList<FlowElement>();
        for (FlowElement elem : startingElements) {
            work.add(elem);
        }
        Graph<String> graph = Graphs.newInstance();

        while (work.isEmpty() == false) {
            FlowElement elem = work.removeFirst();

            String self = elem.getDescription().getName();
            if (saw.contains(self)) {
                continue;
            }
            saw.add(self);

            // 逆辺をキューに追加
            for (FlowElementInput input : elem.getInputPorts()) {
                for (PortConnection conn : input.getConnected()) {
                    work.add(conn.getUpstream().getOwner());
                }
            }

            // 順辺をグラフに追加
            for (FlowElementOutput output : elem.getOutputPorts()) {
                for (PortConnection conn : output.getConnected()) {
                    FlowElement opposite = conn.getDownstream().getOwner();
                    work.add(opposite);
                    String dest = opposite.getDescription().getName();
                    graph.addEdge(self, dest);
                }
            }
        }

        return graph;
    }

    /**
     * 指定のクラス名のファイルを追加する。
     * @param name クラス名
     */
    protected void add(String name) {
        Class<?> aClass = getClass();
        String file = MessageFormat.format(
                "{0}.files/{1}.java.txt",
                aClass.getSimpleName(),
                name.replace('.', '/'));
        StringBuilder buf = new StringBuilder();
        InputStream in = aClass.getResourceAsStream(file);
        assertThat(file, in, not(nullValue()));
        try {
            Reader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
            while (true) {
                int c = reader.read();
                if (c == -1) {
                    break;
                }
                buf.append((char) c);
            }
        } catch (IOException e) {
            throw new AssertionError(e);
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                throw new AssertionError(e);
            }
        }
        sources.add(new VolatileJavaFile(
                name.replace('.', '/'),
                buf.toString()));
    }

    /**
     * コンパイルを指定の注釈プロセッサを利用して実行し、コンパイル結果のローダーを返す。
     * @param processor 利用する注釈プロセッサ
     * @return コンパイル結果
     */
    protected ClassLoader start(Processor processor) {
        SafeProcessor safe = new SafeProcessor(processor);
        compiler.addProcessor(safe);
        ClassLoader loader = start();
        safe.rethrow();
        return loader;
    }

    /**
     * コンパイルを指定のコールバックを利用して実行し、コンパイル結果のローダーを返す。
     * @param callback 利用するコールバック
     * @return コンパイル結果
     */
    protected ClassLoader start(Callback callback) {
        compiler.addProcessor(new DelegateProcessor(callback));
        ClassLoader loader = start();
        callback.rethrow();
        return loader;
    }

    /**
     * コンパイルを指定の演算子プロセッサを利用して実行し、コンパイル結果のローダーを返す。
     * @param procs 利用する演算子プロセッサの一覧
     * @return コンパイル結果
     */
    protected ClassLoader start(final OperatorProcessor... procs) {
        return start(new OperatorCompiler() {
            @Override
            protected Iterable<OperatorProcessor> findOperatorProcessors(OperatorCompilingEnvironment env) {
                return Arrays.asList(procs);
            }
        });
    }

    /**
     * コンパイルを実行し、エラーが発生することを確認する。
     * @param procs 利用する演算子プロセッサの一覧
     */
    protected void error(final OperatorProcessor... procs) {
        SafeProcessor proc = new SafeProcessor(new OperatorCompiler() {
            @Override
            protected Iterable<OperatorProcessor> findOperatorProcessors(OperatorCompilingEnvironment env) {
                return Arrays.asList(procs);
            }
        });
        compiler.addProcessor(proc);
        List<Diagnostic<? extends JavaFileObject>> diagnostics = doCompile();
        proc.rethrow();
        assertThat(diagnostics.isEmpty(), is(false));
    }

    /**
     * コンパイルを実行し、エラーが発生することを確認する。
     * @param callback 呼び戻される
     */
    protected void error(Callback callback) {
        compiler.addProcessor(new DelegateProcessor(callback));
        List<Diagnostic<? extends JavaFileObject>> diagnostics = doCompile();
        callback.rethrow();
        assertThat(diagnostics.isEmpty(), is(false));
    }

    private ClassLoader start() {
        List<Diagnostic<? extends JavaFileObject>> diagnostics = doCompile();
        for (Diagnostic<?> d : diagnostics) {
            if (d.getKind() != Diagnostic.Kind.NOTE) {
                throw new AssertionError(diagnostics);
            }
        }
        return compiler.getClassLoader();
    }

    private List<Diagnostic<? extends JavaFileObject>> doCompile() {
        if (dump) {
            for (JavaFileObject java : sources) {
                try {
                    System.out.println("====" + java.getName());
                    System.out.println(java.getCharContent(true));
                } catch (IOException e) {
                    // ignore.
                }
            }
        }

        compiler.addArguments("-Xlint:unchecked");
        for (JavaFileObject java : sources) {
            compiler.addSource(java);
        }
        if (sources.isEmpty()) {
            compiler.addSource(new VolatileJavaFile("A", "public class A {}"));
        }
        List<Diagnostic<? extends JavaFileObject>> diagnostics = compiler.doCompile();
        for (JavaFileObject java : compiler.getSources()) {
            try {
                System.out.println("====" + java.getName());
                System.out.println(java.getCharContent(true));
            } catch (IOException e) {
                // ignore.
            }
        }
        if (dump) {
            for (Diagnostic<? extends JavaFileObject> d : diagnostics) {
                System.out.println("====");
                System.out.println(d);
            }
        }
        return diagnostics;
    }
}
TOP

Related Classes of com.asakusafw.compiler.operator.OperatorCompilerTestRoot

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.