Package net.sourceforge.marathon.ruby

Source Code of net.sourceforge.marathon.ruby.RubyScriptModel

/*******************************************************************************
*  Copyright (C) 2010 Jalian Systems Private Ltd.
*  Copyright (C) 2010 Contributors to Marathon OSS Project
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Library General Public
*  License as published by the Free Software Foundation; either
*  version 2 of the License, or (at your option) any later version.
*
*  This library is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*  Library General Public License for more details.
*
*  You should have received a copy of the GNU Library General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*  Project website: http://www.marathontesting.com
*  Help: Marathon help forum @ http://groups.google.com/group/marathon-testing
*
*******************************************************************************/
package net.sourceforge.marathon.ruby;

import java.awt.Point;
import java.awt.dnd.DnDConstants;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.JDialog;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;

import jay.yydebug.yyDebug;
import net.sourceforge.marathon.Constants;
import net.sourceforge.marathon.action.ClickAction;
import net.sourceforge.marathon.action.WindowState;
import net.sourceforge.marathon.api.ComponentId;
import net.sourceforge.marathon.api.IScript;
import net.sourceforge.marathon.api.IScriptModelClientPart;
import net.sourceforge.marathon.api.IScriptModelServerPart;
import net.sourceforge.marathon.api.MarathonAppType;
import net.sourceforge.marathon.api.WindowId;
import net.sourceforge.marathon.api.module.Argument;
import net.sourceforge.marathon.api.module.Argument.Type;
import net.sourceforge.marathon.api.module.Function;
import net.sourceforge.marathon.api.module.Module;
import net.sourceforge.marathon.component.ComponentFinder;
import net.sourceforge.marathon.component.MComponent;
import net.sourceforge.marathon.mpf.ISubPropertiesPanel;
import net.sourceforge.marathon.recorder.WindowMonitor;
import net.sourceforge.marathon.script.FixturePropertyHelper;
import net.sourceforge.marathon.util.ClassPathHelper;
import net.sourceforge.marathon.util.FileUtils;
import net.sourceforge.marathon.util.KeyStrokeParser;
import net.sourceforge.marathon.util.OSUtils;

import org.jruby.Ruby;
import org.jruby.RubyInstanceConfig;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jrubyparser.Parser;

public class RubyScriptModel implements IScriptModelClientPart, IScriptModelServerPart {

    private static final String MARATHON_RT_RUBY = locateRTJar();
    private static final String EOL = System.getProperty("line.separator");
    public static final String MARATHON_START_MARKER = "#{{{ Marathon";
    public static final String MARATHON_END_MARKER = "#}}} Marathon";

    private static Ruby ruby;
    private int lastModuleInsertionPoint;

    static {
        RubyInstanceConfig.FULL_TRACE_ENABLED = true;
        ruby = JavaEmbedUtils.initialize(new ArrayList<String>());
    }

    public void createDefaultFixture(JDialog parent, Properties props, File fixtureDir, List<String> keys) {
        FixtureGenerator fixtureGenerator = getFixtureGenerator();
        File fixtureFile = new File(fixtureDir, "default.rb");
        if (fixtureFile.exists()) {
            int option = JOptionPane.showConfirmDialog(parent, "File " + fixtureFile + " exists\nDo you want to overwrite",
                    "File Exists", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE);
            if (option != JOptionPane.YES_OPTION)
                return;
        }
        PrintStream ps = null;
        try {
            ps = new PrintStream(new FileOutputStream(fixtureFile));
            String launcher = props.getProperty(Constants.PROP_PROJECT_LAUNCHER_MODEL);
            props.setProperty(Constants.FIXTURE_DESCRIPTION, props.getProperty(Constants.FIXTURE_DESCRIPTION, "Default Fixture"));
            fixtureGenerator.printFixture(props, ps, launcher, keys);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ps != null)
                ps.close();
        }
    }

    private static String locateRTJar() {
        String home = System.getProperty("marathon.home");
        if(home == null)
            home = "." ;
        File f = FileUtils.findFile(home, "marathon-rt-ruby.jar");
        if(f != null) {
            return f.getAbsolutePath();
        }
        return null;
    }

    protected FixtureGenerator getFixtureGenerator() {
        FixtureGenerator fixtureGenerator = new FixtureGenerator();
        return fixtureGenerator;
    }

    public String getClasspath() {
        StringBuffer sb = new StringBuffer();
        sb.append(getRubyJarPath()).append(File.pathSeparator);
        sb.append(ClassPathHelper.getClassPath(Parser.class)).append(File.pathSeparator);
        sb.append(ClassPathHelper.getClassPath(RubyScriptModel.class)).append(File.pathSeparator);
        sb.append(ClassPathHelper.getClassPath(yyDebug.class));
        return sb.toString();
    }

    public static String getRubyJarPath() {
        String property = System.getProperty(RubyScript.PROP_APPLICATION_RUBYHOME);
        if (property != null && !property.equals("")) {
            File file = new File(property, "lib");
            if (file.exists()) {
                file = new File(file, "jruby.jar");
                if (file.exists())
                    return file.getAbsolutePath();
            }
            System.err.println("Warning: Could not find ruby.jar in " + property);
        }
        String path;
        path = ClassPathHelper.getClassPath("org.jruby.Ruby");
        if (path != null)
            return path;
        path = ClassPathHelper.getClassPath(RubyScriptModel.class);
        if (new File(path).isFile()) {
            path = new File(path).getParentFile().getAbsolutePath();
        }
        StringBuffer sb = new StringBuffer();
        return sb.append(path).append(File.separator).append("jruby").append(File.separator).append("lib").append(File.separator)
                .append("jruby.jar").toString();
    }

    public String getDefaultFixtureHeader(Properties props, String launcher, List<String> keys) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(baos);
        new FixtureGenerator().printFixture(props, ps, launcher, keys);
        return baos.toString();
    }

    public String getDefaultTestHeader(String fixture) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(baos);
        ps.println(MARATHON_START_MARKER);
        ps.print("require_fixture '");
        ps.print(fixture);
        ps.println("'");
        ps.println(MARATHON_END_MARKER);
        ps.println();
        ps.println("def test");
        ps.println();
        ps.println();
        ps.println("end");

        return new String(baos.toByteArray());
    }

    public String getFixtureHeader(String fixture) {
        return "require_fixture '" + fixture + "'\n";
    }

    public String[] getFixtures() {
        File fixtureDir = new File(System.getProperty(Constants.PROP_FIXTURE_DIR));
        File[] fixtureFiles = fixtureDir.listFiles(new FileFilter() {
            public boolean accept(File pathname) {
                if (pathname.getName().endsWith(".rb")) {
                    return true;
                }
                return false;
            }
        });
        String[] fixtures = new String[fixtureFiles.length];
        for (int i = 0; i < fixtureFiles.length; i++) {
            File file = fixtureFiles[i];
            fixtures[i] = file.getName().substring(0, file.getName().length() - 3);
        }
        Arrays.sort(fixtures);
        return fixtures;
    }

    private String encodeArg(String text, Argument argument) {
        if (argument.getType() == Type.REGEX)
            return "/" + text + "/";
        String decoded = ruby.evalScriptlet("\"" + text + "\"").toString();
        return encode(decoded);
    }

    public String getFunctionCallForInsertDialog(Function function, String[] arguments) {
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < arguments.length - 1; i += 1) {
            buffer.append(encodeArg(arguments[i], function.getArguments().get(i)));
            buffer.append(", ");
        }
        if (arguments.length != 0) {
            buffer.append(encodeArg(arguments[arguments.length - 1], function.getArguments().get(arguments.length - 1)));
        }
        String require = getRequire(function);
        return require + function.getName() + "(" + buffer.toString() + ")";
    }

    private String getRequire(Function function) {
        StringBuilder require = new StringBuilder();

        Module parent = function.getParent();
        while (parent.getParent() != null) {
            require.insert(0, "/").insert(0, parent.getName());
            parent = parent.getParent();
        }
        return require.toString();
    }

    public String getModuleHeader(String moduleFunction, String description) {
        String prefix = "=begin" + EOL + description + EOL + "=end" + EOL + EOL + "def " + moduleFunction + "()" + EOL + EOL
                + "    ";
        lastModuleInsertionPoint = prefix.length();
        return prefix + EOL + "end" + EOL;
    }

    public ISubPropertiesPanel[] getSubPanels(JDialog parent) {
        return new ISubPropertiesPanel[] { new RubyPathPanel(parent) };
    }

    public IScript getScript(Writer out, Writer err, String script, String filename, ComponentFinder resolver, boolean isDebugging,
            WindowMonitor windowMonitor, MarathonAppType type) {
        return new RubyScript(out, err, script, filename, resolver, isDebugging, windowMonitor, type);
    }

    public String getScriptCodeForAssertContent(ComponentId componentId, String[][] arrayContent) {
        StringBuffer pythonizedString = new StringBuffer();
        pythonizedString.append("assert_content(").append(encode(componentId.getName()));
        pythonizedString.append(", [ ");
        for (int i = 0; i < arrayContent.length; i++) {
            pythonizedString.append("[");
            String[] data = arrayContent[i];
            for (int j = 0; j < data.length - 1; j++) {
                pythonizedString.append(encode(data[j])).append(", ");
            }
            if (data.length > 0)
                pythonizedString.append(encode(data[data.length - 1]));
            if (i == arrayContent.length - 1)
                pythonizedString.append("]\n");
            else
                pythonizedString.append("],\n");
        }
        pythonizedString.append("]").append(finish(componentId));
        return pythonizedString.toString();

    }

    private String finish(ComponentId componentId) {
        String finish;
        if (componentId.getComponentInfo() != null) {
            finish = ", " + encode(componentId.getComponentInfo()) + ")\n";
        } else {
            finish = ")\n";
        }
        return finish;
    }

    public String getScriptCodeForAssertProperty(ComponentId componentId, String property, String value) {
        return "assert_p(" + encode(componentId.getName()) + ", " + encode(property) + ", " + escape(encode(value))
                + finish(componentId);
    }

    public String getScriptCodeForWaitProperty(ComponentId componentId, String property, String value) {
        return "wait_p(" + encode(componentId.getName()) + ", " + encode(property) + ", " + escape(encode(value))
                + finish(componentId);
    }

    public static String escape(String encode) {
        if (encode.startsWith("/"))
            return "/" + encode;
        return encode;
    }

    public String getScriptCodeForCapture(String windowName, String fileName) {
        String result;
        if (windowName == null) {
            result = "screen_capture(" + encode(fileName) + ")\n";
        } else {
            result = "window_capture(" + encode(fileName) + ", " + encode(windowName) + ")\n";
        }
        return result;
    }

    public String getScriptCodeForClick(ComponentId componentId, int numberOfClicks, int modifiers, int record_click, Point position) {
        String modifiersText = ClickAction.getModifiersText(modifiers
                & ~(InputEvent.BUTTON1_DOWN_MASK | InputEvent.BUTTON3_DOWN_MASK));
        if (!modifiersText.equals(""))
            modifiersText = ", " + encode(modifiersText);
        String clickCountText = (numberOfClicks > 1) ? "" + numberOfClicks : "";
        if (!clickCountText.equals(""))
            clickCountText = ", " + clickCountText;
        String positionText = "";
        if (record_click != ClickAction.RECORD_CLICK) {
            positionText = ", " + position.x + ", " + position.y;
        }
        boolean popupTrigger = (modifiers & InputEvent.BUTTON3_DOWN_MASK) != 0;
        if (popupTrigger)
            return "rightclick" + "(" + encode(componentId.getName()) + clickCountText + positionText + modifiersText
                    + finish(componentId);
        else if (numberOfClicks == 2)
            return "doubleclick" + "(" + encode(componentId.getName()) + positionText + modifiersText + finish(componentId);
        else
            return "click" + "(" + encode(componentId.getName()) + clickCountText + positionText + modifiersText
                    + finish(componentId);
    }

    public String getScriptCodeForDragAndDrop(ComponentId source, ComponentId target, int action) {
        StringBuffer python = new StringBuffer();
        python.append("drag_and_drop(" + encode(source.getName()));
        if (source.getComponentInfo() != null) {
            python.append(", " + encode(source.getComponentInfo()) + ", ");
        } else
            python.append(", nil, ");
        python.append(encode(target.getName()));
        if (target.getComponentInfo() != null) {
            python.append(", " + encode(target.getComponentInfo()) + ", ");
        } else
            python.append(", nil, ");
        if (action == DnDConstants.ACTION_COPY)
            python.append(encode("copy"));
        else if (action == DnDConstants.ACTION_MOVE)
            python.append(encode("move"));
        else if (action == DnDConstants.ACTION_LINK)
            python.append(encode("link"));
        else {
            throw new RuntimeException("Unknown drag and drop operation - " + action);
        }
        python.append(")\n");
        return python.toString();
    }

    public String getScriptCodeForImportAction(String pkg, String function) {
        return "require '" + pkg + "'";
    }

    public String getScriptCodeForSelect(ComponentId componentId, String text) {
        return "select(" + encode(componentId.getName()) + ", " + encode(text) + finish(componentId);
    }

    public String getScriptCodeForSelectMenu(KeyStroke ks, ArrayList<Object> menuList) {
        StringBuffer python = new StringBuffer();
        if (ks == null) {
            for (int i = 0; i < menuList.size() - 1; i++) {
                python.append(((MComponent) menuList.get(i)).getComponentId().getName() + ">>");
            }
            python.append(((MComponent) menuList.get(menuList.size() - 1)).getComponentId().getName());
            return "select_menu(" + encode(python.toString()) + ")\n";
        } else {
            for (int i = 0; i < menuList.size() - 1; i++) {
                python.append(((JMenuItem) menuList.get(i)).getText() + ">>");
            }
            python.append(((JMenuItem) menuList.get(menuList.size() - 1)).getText());
            String keyText = KeyStrokeParser.getKeyModifierText(ks.getModifiers());
            keyText += OSUtils.keyEventGetKeyText(ks.getKeyCode());
            return "select_menu(" + encode(python.toString()) + ", " + encode(keyText) + ")\n";
        }
    }

    public String getScriptCodeForKeystroke(char keyChar, KeyStroke keyStroke, ComponentId componentId, String textForKeyChar) {
        if (keyChar != KeyEvent.CHAR_UNDEFINED
                && (keyStroke.getModifiers() & ~(KeyEvent.SHIFT_DOWN_MASK | KeyEvent.SHIFT_MASK)) == 0
                && !Character.isISOControl(keyChar)) {
            return "keystroke(" + encode(componentId.getName()) + ", " + encode("" + textForKeyChar) + finish(componentId);
        }
        String keyModifiersText = KeyStrokeParser.getKeyModifierText(keyStroke.getModifiers());
        return "keystroke(" + encode(componentId.getName()) + ", "
                + encode(keyModifiersText + OSUtils.keyEventGetKeyText(keyStroke.getKeyCode())) + finish(componentId);
    }

    public String getScriptCodeForWindow(WindowId windowId2) {
        if (windowId2.isFrame())
            return "with_frame(" + encode(windowId2.toString()) + ") {\n";
        return "with_window(" + encode(windowId2.toString()) + ") {\n";
    }

    public String getScriptCodeForWindowClose(WindowId windowId) {
        return "}\n";
    }

    public String getSuffix() {
        return ".rb";
    }

    public boolean isSourceFile(File f) {
        return f.getName().endsWith(".rb") && !f.getName().startsWith(".");
    }

    public String[] parseMessage(String msg) {
        Pattern p = Pattern.compile(".*\\((.*.rb):(.*)\\).*");
        Matcher matcher = p.matcher(msg);
        String[] elements = null;
        if (matcher.matches()) {
            elements = new String[2];
            elements[0] = matcher.group(1);
            elements[1] = matcher.group(2);
        }
        return elements;
    }

    public String getFunctionFromInsertDialog(String function) {
        String pkg = getPackageName(function);
        if (pkg != null)
            return function.substring(pkg.length() + 1);
        return function;
    }

    public String getPackageFromInsertDialog(String function) {
        return getPackageName(function);
    }

    private String getPackageName(String f) {
        int index = f.indexOf('(');
        if (index != -1)
            f = f.substring(0, index);
        f = f.trim();
        index = f.lastIndexOf('/');
        if (index == -1)
            return null;
        return f.substring(0, index);
    }

    public boolean isTestFile(File file) {
        try {
            BufferedReader reader = new BufferedReader(new FileReader(file));
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.matches(".*def.*test.*")) {
                    reader.close();
                    return true;
                }
            }
            reader.close();
        } catch (IOException e) {
        }
        return false;
    }

    public int getLinePositionForInsertion() {
        return 6;
    }

    public String getScriptCodeForWindowClosing(WindowId id) {
        return "window_closed(" + encode(id.toString()) + ")\n";
    }

    public String getScriptCodeForWindowState(WindowId id, WindowState state) {
        return "window_changed('" + state.toString() + "')\n";
    }

    public String getScriptCodeForInsertChecklist(String fileName) {
        return "accept_checklist(" + encode(fileName) + ")\n";
    }

    public String getScriptCodeForShowChecklist(String fileName) {
        return "show_checklist(" + encode(fileName) + ")\n";
    }

    public String getScriptCodeForCustom(ComponentId componentId, String fcall, Object[] objects) {
        return fcall + "(" + encode(componentId.getName()) + ", " + encodeParams(objects) + finish(componentId);
    }

    private String encodeParams(Object[] objects) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < objects.length; i++) {
            sb.append(encode(objects[i].toString()));
            if (i < objects.length - 1)
                sb.append(", ");
        }
        return sb.toString();
    }

    public String getScriptCodeForDrag(int modifiers, Point start, Point end, ComponentId componentId) {
        String positionText = ", " + start.x + ", " + start.y + ", " + end.x + ", " + end.y;
        boolean right = (modifiers & MouseEvent.BUTTON3_DOWN_MASK) != 0;
        if (right) // not yet supported
            return "rightdrag(" + encode(componentId.getName()) + positionText + /*
                                                                                  * modifiersText
                                                                                  * +
                                                                                  */finish(componentId);
        else
            return "drag(" + encode(componentId.getName()) + positionText + /*
                                                                             * modifiersText
                                                                             * +
                                                                             */finish(componentId);
    }

    public static String encode(String name) {
        if (name == null)
            name = "";
        return inspect(name);
    }

    public static String inspect(String string) {
        StringBuilder sb = new StringBuilder();
        sb.append("\"");
        char[] chars = string.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            if (c == '"' || c == '\\') {
                sb.append("\\").append(c);
            } else if (c == '#' && chars[i + 1] == '{') {
                sb.append("\\").append(c);
            } else if (c == '\n') {
                sb.append("\\").append('n');
            } else if (c == '\r') {
                sb.append("\\").append('r');
            } else if (c == '\t') {
                sb.append("\\").append('t');
            } else if (c == '\f') {
                sb.append("\\").append('f');
            } else if (c == '\013') {
                sb.append("\\").append('v');
            } else if (c == '\010') {
                sb.append("\\").append('b');
            } else if (c == '\007') {
                sb.append("\\").append('a');
            } else if (c == '\033') {
                sb.append("\\").append('e');
            } else {
                sb.append(c);
            }
        }
        sb.append("\"");
        return sb.toString();
    }

    public String[][] getCustomAssertions(IScript script, MComponent mcomponent) {
        return ((RubyScript) script).getCustomAssertions(mcomponent);
    }

    public int getLinePositionForInsertionModule() {
        return lastModuleInsertionPoint;
    }

    public String updateScriptWithImports(String text, HashSet<String> importStatements) {
        StringBuilder sb = new StringBuilder(text);
        int endOffset = sb.indexOf(RubyScriptModel.MARATHON_END_MARKER);
        if (endOffset == -1) {
            StringWriter sw = new StringWriter();
            PrintWriter ps = new PrintWriter(sw);
            ps.println(MARATHON_START_MARKER);
            for (String ims : importStatements) {
                ps.println(ims);
            }
            ps.println(MARATHON_END_MARKER);
            ps.close();
            sb.replace(0, 0, sw.toString());
        } else {
            int startOffset = sb.indexOf(MARATHON_START_MARKER);
            if (startOffset == -1)
                startOffset = 0;
            String header = text.substring(startOffset, endOffset);
            for (String ims : importStatements) {
                if (!header.contains(ims)) {
                    sb.replace(endOffset, endOffset, ims + EOL);
                    endOffset = sb.indexOf(MARATHON_END_MARKER);
                }
            }
        }
        return sb.toString();
    }

    public static Ruby getRubyInterpreter() {
        return ruby;
    }

    public String getJavaRecordedVersionTag() {
        return "$java_recorded_version=\"" + System.getProperty("java.version") + "\"";
    }

    public void fileUpdated(File file, SCRIPT_FILE_TYPE type) {
    }

    public String getMarathonStartMarker() {
        return MARATHON_START_MARKER;
    }

    public String getMarathonEndMarker() {
        return MARATHON_END_MARKER;
    }

    public String getPlaybackImportStatement() {
        return "";
    }

    private static final Pattern FIXTURE_IMPORT_MATCHER = Pattern.compile("\\s*require_fixture\\s\\s*['\"](.*)['\"].*");

    public Map<String, Object> getFixtureProperties(String script) {
        return new FixturePropertyHelper(this).getFixtureProperties(script, FIXTURE_IMPORT_MATCHER);
    }

    public Object eval(String script) {
        return ruby.evalScriptlet(script);
    }

    public String getAgentJar() {
        return MARATHON_RT_RUBY;
    }

}
TOP

Related Classes of net.sourceforge.marathon.ruby.RubyScriptModel

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.