package org.intellij.grammar;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
import org.intellij.grammar.inspection.*;
import java.io.File;
import java.io.IOException;
/**
* @author gregsh
*/
public class BnfHighlightingTest extends LightPlatformCodeInsightFixtureTestCase {
@Override
protected String getTestDataPath() {
return "testData/highlighting";
}
@Override
protected void setUp() throws Exception {
super.setUp();
VfsRootAccess.allowRootAccess(new File(getTestDataPath()).getAbsolutePath());
}
public void testSelfBnf() { doFileTest(); }
public void testSelfFlex() { doFileTest(); }
public void testEmpty() { doFileTest(); }
public void testDuplicateDefinition() { doTest("<warning>rule</warning>::= blablabla rule1" + "\n" + "<warning>rule</warning> ::=aaaaaaaaa"); }
public void testSuspiciousToken() { doTest("rule ::= <warning>suspicious_token</warning>"); }
public void testIdenticalBranchInChoice() { doTest("grammar ::= <warning>token</warning>|<warning>token</warning>"); }
public void testComplexIdenticalBranchInChoice() { doTest("grammar ::= a b (c | <warning>(d e*)</warning>|<warning>(d /* */ e*)</warning>)"); }
public void testLeftRecursion1() { doTest("<warning>grammar</warning> ::= grammar"); }
public void testLeftRecursion2() { doTest("<warning>grammar</warning> ::= [r] [(r | grammar)]"); }
public void testLeftRecursion3() { doTest("<warning>grammar</warning> ::= [r] [(r | rule)] <warning>rule</warning> ::= [r] ([r | grammar] r)"); }
public void testLeftRecursion4() { doTest("meta m ::= (<<p1>> | <<p2>>) <warning>r</warning> ::= <<m x r>>"); }
public void testUnreachableBranch1() { doTest("m ::= <warning>r</warning> | B | C r ::= A?"); }
public void testUnreachableBranch2() { doTest("m ::= A<warning>||</warning> B | C"); }
public void testUnreachableBranch3() { doTest("m ::=<warning>|</warning> B <warning>|</warning>"); }
public void testUnreachableBranch4() { doTest("m ::=(A | (<warning>|</warning> B<warning>|</warning>))"); }
public void testNeverMatchingBranch1() { doTest("m ::= <warning>! A r</warning> | B | C r ::= A"); }
public void testUnusedRule1() { doTest("r ::= <warning>A</warning> ::= 1 A"); }
public void testUnusedRule2() { doTest("r ::= B fake A ::= B ::= {extends=A}"); }
public void testUnusedRule3() { doTest("r ::= B fake <warning>A</warning> ::= B ::= "); }
public void testUnusedRule4() { doTest("r ::= {recoverWhile=A} private A ::= "); }
public void testUnusedRule5() { doTest("r ::= {recoverWhile=A} <warning>A</warning> ::= "); }
private void doFileTest() {
String name = getTestName(false) + ".bnf";
String adjusted;
if ("SelfBnf.bnf".equals(name)) adjusted = "../../grammars/Grammar.bnf";
else if ("SelfFlex.bnf".equals(name)) adjusted = "../../grammars/JFlex.bnf";
else adjusted = name;
boolean toggleSrc = !adjusted.equals(name);
try {
if (toggleSrc) toggleGrammarKitSrc(myModule, getTestDataPath());
VirtualFile file = myFixture.copyFileToProject(adjusted, new File(adjusted).getName());
myFixture.configureFromExistingVirtualFile(file);
doTest();
}
finally {
if (toggleSrc) toggleGrammarKitSrc(myModule, getTestDataPath());
}
}
private void doTest(String text) {
myFixture.configureByText("a.bnf", text);
doTest();
}
private void doTest() {
myFixture.enableInspections(BnfSuspiciousTokenInspection.class,
BnfDuplicateRuleInspection.class,
BnfIdenticalChoiceBranchesInspection.class,
BnfLeftRecursionInspection.class,
BnfUnreachableChoiceBranchInspection.class);
if ("JFlex.bnf".equals(myFixture.getFile().getName())) {
// todo remove when suppression is implemented
myFixture.disableInspections(new BnfSuspiciousTokenInspection());
}
myFixture.checkHighlighting(true, false, false);
}
@Override
protected boolean isWriteActionRequired() {
return false;
}
private static void toggleGrammarKitSrc(Module module, String testDataPath) {
String absolutePath = new File("").getAbsolutePath();
JavaPsiFacade facade = JavaPsiFacade.getInstance(module.getProject());
boolean add = facade.findPackage("org.intellij.grammar.psi") == null;
if (add) {
VfsRootAccess.allowRootAccess(absolutePath);
}
else {
VfsRootAccess.disallowRootAccess(absolutePath);
}
WriteAction.run(() -> {
ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
String supportUrl = getUrl(testDataPath + "/../../support");
String genUrl = getUrl(testDataPath + "/../../gen");
if (add) {
model.addContentEntry(supportUrl).addSourceFolder(supportUrl, false);
model.addContentEntry(genUrl).addSourceFolder(genUrl, false);
}
else {
for (ContentEntry entry : model.getContentEntries()) {
if (supportUrl.equals(entry.getUrl()) || genUrl.equals(entry.getUrl())) {
model.removeContentEntry(entry);
}
}
}
model.commit();
});
assertTrue("GrammarKit src problem", add == (null != facade.findPackage("org.intellij.grammar.psi")));
}
private static String getUrl(String path) {
try {
return VfsUtil.pathToUrl(FileUtil.toSystemIndependentName(new File(path).getCanonicalPath()));
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}