1/* 2 [The "BSD licence"] 3 Copyright (c) 2009 Shaoting Cai 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions 8 are met: 9 1. Redistributions of source code must retain the above copyright 10 notice, this list of conditions and the following disclaimer. 11 2. Redistributions in binary form must reproduce the above copyright 12 notice, this list of conditions and the following disclaimer in the 13 documentation and/or other materials provided with the distribution. 14 3. The name of the author may not be used to endorse or promote products 15 derived from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27*/ 28package org.antlr.gunit.swingui.model; 29 30import org.antlr.gunit.swingui.parsers.ANTLRv3Lexer; 31import org.antlr.gunit.swingui.parsers.ANTLRv3Parser; 32import org.antlr.gunit.swingui.parsers.StGUnitLexer; 33import org.antlr.gunit.swingui.parsers.StGUnitParser; 34import org.antlr.gunit.swingui.runner.TestSuiteAdapter; 35import org.antlr.runtime.ANTLRReaderStream; 36import org.antlr.runtime.CommonTokenStream; 37import org.antlr.stringtemplate.StringTemplate; 38import org.antlr.stringtemplate.StringTemplateGroup; 39 40import java.io.*; 41import java.util.ArrayList; 42import java.util.List; 43 44public class TestSuiteFactory { 45 46 private static String TEMPLATE_FILE = "org/antlr/gunit/swingui/gunit.stg"; 47 private static StringTemplateGroup templates; 48 public static final String TEST_SUITE_EXT = ".gunit"; 49 public static final String GRAMMAR_EXT = ".g"; 50 51 static { 52 ClassLoader loader = TestSuiteFactory.class.getClassLoader(); 53 InputStream in = loader.getResourceAsStream(TEMPLATE_FILE); 54 if ( in == null ) { 55 throw new RuntimeException("internal error: Can't find templates "+TEMPLATE_FILE); 56 } 57 Reader rd = new InputStreamReader(in); 58 templates = new StringTemplateGroup(rd); 59 } 60 61 /** 62 * Factory method: create a testsuite from ANTLR grammar. Save the test 63 * suite file in the same directory of the grammar file. 64 * @param grammarFile ANTLRv3 grammar file. 65 * @return test suite object 66 */ 67 public static TestSuite createTestSuite(File grammarFile) { 68 if(grammarFile != null && grammarFile.exists() && grammarFile.isFile()) { 69 70 final String fileName = grammarFile.getName(); 71 final String grammarName = fileName.substring(0, fileName.lastIndexOf('.')); 72 final String grammarDir = grammarFile.getParent(); 73 final File testFile = new File(grammarDir + File.separator + grammarName + TEST_SUITE_EXT); 74 75 final TestSuite result = new TestSuite(grammarName, testFile); 76 result.rules = loadRulesFromGrammar(grammarFile); 77 78 if(saveTestSuite(result)) { 79 return result; 80 } else { 81 throw new RuntimeException("Can't save test suite file."); 82 } 83 } else { 84 throw new RuntimeException("Invalid grammar file."); 85 } 86 } 87 88 89 /* Load rules from an ANTLR grammar file. */ 90 private static List<Rule> loadRulesFromGrammar(File grammarFile) { 91 92 // get all the rule names 93 final List<String> ruleNames = new ArrayList<String>(); 94 try { 95 final Reader reader = new BufferedReader(new FileReader(grammarFile)); 96 final ANTLRv3Lexer lexer = new ANTLRv3Lexer(new ANTLRReaderStream(reader)); 97 final CommonTokenStream tokens = new CommonTokenStream(lexer); 98 final ANTLRv3Parser parser = new ANTLRv3Parser(tokens); 99 parser.rules = ruleNames; 100 parser.grammarDef(); 101 reader.close(); 102 } catch (Exception e) { 103 e.printStackTrace(); 104 } 105 106 // convert to rule object 107 final List<Rule> ruleList = new ArrayList<Rule>(); 108 for(String str: ruleNames) { 109 ruleList.add(new Rule(str)); 110 } 111 112 return ruleList; 113 } 114 115 /* Save testsuite to *.gunit file. */ 116 public static boolean saveTestSuite(TestSuite testSuite) { 117 final String data = getScript(testSuite); 118 try { 119 FileWriter fw = new FileWriter(testSuite.getTestSuiteFile()); 120 fw.write(data); 121 fw.flush(); 122 fw.close(); 123 } catch (IOException e) { 124 e.printStackTrace(); 125 return false; 126 } 127 return true; 128 } 129 130 /** 131 * Get the text script from the testSuite. 132 * @param testSuite 133 * @return test script 134 */ 135 public static String getScript(TestSuite testSuite) { 136 if(testSuite == null) return null; 137 StringTemplate gUnitScript = templates.getInstanceOf("gUnitFile"); 138 gUnitScript.setAttribute("testSuite", testSuite); 139 140 return gUnitScript.toString(); 141 } 142 143 /** 144 * From textual script to program model. 145 * @param file testsuite file (.gunit) 146 * @return test suite object 147 */ 148 public static TestSuite loadTestSuite(File file) { 149 if ( file.getName().endsWith(GRAMMAR_EXT) ) { 150 throw new RuntimeException(file.getName()+" is a grammar file not a gunit file"); 151 } 152 // check grammar file 153 final File grammarFile = getGrammarFile(file); 154 if(grammarFile == null) 155 throw new RuntimeException("Can't find grammar file associated with gunit file: "+file.getAbsoluteFile()); 156 157 TestSuite result = new TestSuite("", file); 158 159 // read in test suite 160 try { 161 final Reader reader = new BufferedReader(new FileReader(file)); 162 final StGUnitLexer lexer = new StGUnitLexer(new ANTLRReaderStream(reader)); 163 final CommonTokenStream tokens = new CommonTokenStream(lexer); 164 final StGUnitParser parser = new StGUnitParser(tokens); 165 final TestSuiteAdapter adapter = new TestSuiteAdapter(result); 166 parser.adapter = adapter; 167 parser.gUnitDef(); 168 result.setTokens(tokens); 169 reader.close(); 170 } catch (Exception ex) { 171 throw new RuntimeException("Error reading test suite file.\n" + ex.getMessage()); 172 } 173 174 // load un-tested rules from grammar 175 final List<Rule> completeRuleList = loadRulesFromGrammar(grammarFile); 176 for(Rule rule: completeRuleList) { 177 if(!result.hasRule(rule)) { 178 result.addRule(rule); 179 //System.out.println("Add rule:" + rule); 180 } 181 } 182 183 return result; 184 } 185 186 /** 187 * Get the grammar file of the testsuite file in the same directory. 188 * @param testsuiteFile 189 * @return grammar file or null 190 */ 191 private static File getGrammarFile(File testsuiteFile) { 192 String sTestFile; 193 try { 194 sTestFile = testsuiteFile.getCanonicalPath(); 195 } 196 catch (IOException e) { 197 return null; 198 } 199 // Try Foo.g from Foo.gunit 200 String fname = 201 sTestFile.substring(0, sTestFile.lastIndexOf('.')) + GRAMMAR_EXT; 202 File fileGrammar = new File(fname); 203 if(fileGrammar.exists() && fileGrammar.isFile()) return fileGrammar; 204 // Try FooParser.g from Foo.gunit 205 fname = sTestFile.substring(0, sTestFile.lastIndexOf('.'))+"Parser"+GRAMMAR_EXT; 206 if(fileGrammar.exists() && fileGrammar.isFile()) return fileGrammar; 207 return fileGrammar; 208 } 209} 210