Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Programmatic Test Cases #49

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ jobs:
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
run: ./gradlew publish -PossrhToken="${SONATYPE_USERNAME}" -PossrhTokenPassword="${SONATYPE_PASSWORD}" -PsigningKey="${SIGNING_KEY}" -PsigningPassword="${SIGNING_PASSWORD}" -PideaVersion=IC-2020.3 -PlibraryVersion=$GITHUB_REF_NAME
run: ./gradlew publish -PossrhToken="${SONATYPE_USERNAME}" -PossrhTokenPassword="${SONATYPE_PASSWORD}" -PsigningKey="${SIGNING_KEY}" -PsigningPassword="${SIGNING_PASSWORD}" -PideaVersion=IC-2020.3 -PlibraryVersion=$GITHUB_REF_NAME
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
grammar Issue2;

@header {
package org.antlr.intellij.adaptor.issue2;
package org.antlr.intellij.adaptor.test.testcases;
}

block
Expand All @@ -15,4 +15,4 @@ usesList
;

ID: [a-zA-Z]+;
WS: [\t\r\n ]+ -> skip;
WS: [\t\r\n ]+ -> skip;
40 changes: 0 additions & 40 deletions src/test/java/issue2/Issue2FileType.java

This file was deleted.

12 changes: 0 additions & 12 deletions src/test/java/issue2/Issue2Language.java

This file was deleted.

85 changes: 0 additions & 85 deletions src/test/java/issue2/Issue2ParserDefinition.java

This file was deleted.

19 changes: 0 additions & 19 deletions src/test/java/issue2/Issue2ParserTest.java

This file was deleted.

45 changes: 45 additions & 0 deletions src/test/java/org/antlr/intellij/adaptor/test/AntlrTestCase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.antlr.intellij.adaptor.test;

import com.intellij.lang.Language;
import com.intellij.testFramework.ParsingTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.util.Arrays;

@RunWith(Parameterized.class)
public class AntlrTestCase extends ParsingTestCase{

private final String name;

@Parameterized.Parameters(name = "{index}: {2} for {0}/{1}")
public static Iterable<Object> parameters(){
return Arrays.asList((Object[]) new Object[][]{
{ "Issue2", "block", "issue2" },
{ "Issue2", "block", "straightforward" }
});
}

public AntlrTestCase(String lang, String root, String name){
this(lang, root, name, TestLanguage.synthesizeTestLanguage(lang));
}

private AntlrTestCase(String lang, String root, String name, Language language){
super(lang, lang, TestParserDefinition.byName(lang, root, language, new TestFileType(lang, language)));
this.name = name;
}

public String getName(){
return name;
}

protected String getTestDataPath(){
return "src/test/resources/testData";
}

@Test
public void test(){
doTest(true);
}
}
35 changes: 35 additions & 0 deletions src/test/java/org/antlr/intellij/adaptor/test/TestFileType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.antlr.intellij.adaptor.test;

import com.intellij.lang.Language;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.util.NlsContexts;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;

public class TestFileType extends LanguageFileType{

private final String name;

public TestFileType(String name, Language language){
super(language);
this.name = name;
}

public @NonNls @NotNull String getName(){
return name;
}

public @NlsContexts.Label @NotNull String getDescription(){
return name;
}

public @NotNull String getDefaultExtension(){
return name;
}

public Icon getIcon(){
return null;
}
}
69 changes: 69 additions & 0 deletions src/test/java/org/antlr/intellij/adaptor/test/TestLanguage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.antlr.intellij.adaptor.test;

import com.intellij.lang.Language;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.org.objectweb.asm.ClassWriter;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
import org.jetbrains.org.objectweb.asm.Opcodes;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
* A generic class for testing languages. Note that multiple instances of a language class cannot be used
* and will be rejected by the IntelliJ runtime; instead, a subclass must be generated for each test case,
* hence the <code>abstract</code> label.
*/
public abstract class TestLanguage extends Language{

protected TestLanguage(@NonNls @NotNull String lang){
super(lang);
}

private static final Map<String, TestLanguage> languageCache = new HashMap<>();

/**
* Generates a new subclass of {@linkplain TestLanguage}, and returns the canonical instance.
*/
public static TestLanguage synthesizeTestLanguage(@NotNull String lang){
if(languageCache.containsKey(lang))
return languageCache.get(lang);

// Create a subclass of TestLanguage...
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
long l = System.currentTimeMillis();
writer.visit(
Opcodes.V1_8,
Opcodes.ACC_SUPER | Opcodes.ACC_PUBLIC,
"org/antlr/intellij/adaptor/test/$Lang" + lang,
"",
"org/antlr/intellij/adaptor/test/TestLanguage",
new String[0]
);

// ...with one constructor that takes 0 parameters and has no type variables...
MethodVisitor ctor = writer.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", "", new String[0]);
ctor.visitCode();
// ...that invokes the super constructor with itself and the language name...
ctor.visitVarInsn(Opcodes.ALOAD, 0);
ctor.visitLdcInsn(lang);
ctor.visitMethodInsn(Opcodes.INVOKESPECIAL, "org/antlr/intellij/adaptor/test/TestLanguage", "<init>", "(Ljava/lang/String;)V", false);
ctor.visitInsn(Opcodes.RETURN);
ctor.visitMaxs(0, 0);
ctor.visitEnd();
writer.visitEnd();

try{
// ...then define this class and return one instance.
Class<?> cls = MethodHandles.lookup().defineClass(writer.toByteArray());
TestLanguage language = (TestLanguage)cls.getConstructor().newInstance();
languageCache.put(lang, language);
return language;
}catch(IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchMethodException e){
throw new RuntimeException(e);
}
}
}
Loading