summaryrefslogtreecommitdiffstats
path: root/integration
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2022-02-10 22:27:08 +0100
committerJon Bratseth <bratseth@gmail.com>2022-02-10 22:27:08 +0100
commitb2e547393fcb5c41c3657be7221ecef146ac9298 (patch)
treea45c8c9f1004646d2dcacd147a45a93e6f6a3330 /integration
parenta1ff60175c83e27d2ff36996abf90f318b709c6a (diff)
Unit test parent rank profiles
Diffstat (limited to 'integration')
-rw-r--r--integration/intellij/pom.xml2
-rw-r--r--integration/intellij/src/main/bnf/ai/vespa/intellij/schema/parser/sd.bnf31
-rw-r--r--integration/intellij/src/main/java/ai/vespa/intellij/schema/SdSyntaxHighlighter.java2
-rw-r--r--integration/intellij/src/main/java/ai/vespa/intellij/schema/SdUtil.java125
-rw-r--r--integration/intellij/src/main/java/ai/vespa/intellij/schema/model/RankProfile.java11
-rw-r--r--integration/intellij/src/main/java/ai/vespa/intellij/schema/model/Schema.java52
-rw-r--r--integration/intellij/src/main/jflex/ai/vespa/intellij/schema/lexer/sd.flex10
-rw-r--r--integration/intellij/src/test/applications/schemainheritance/child.sd5
-rw-r--r--integration/intellij/src/test/applications/simple/simple.sd15
-rw-r--r--integration/intellij/src/test/java/ai/vespa/intellij/model/MockProject.java147
-rw-r--r--integration/intellij/src/test/java/ai/vespa/intellij/model/RankProfileTest.java32
-rw-r--r--integration/intellij/src/test/java/ai/vespa/intellij/model/SchemaTest.java59
-rw-r--r--integration/intellij/src/test/java/ai/vespa/intellij/model/TestProjectDescriptor.java4
13 files changed, 270 insertions, 225 deletions
diff --git a/integration/intellij/pom.xml b/integration/intellij/pom.xml
index 94d8fd90f99..866f1887443 100644
--- a/integration/intellij/pom.xml
+++ b/integration/intellij/pom.xml
@@ -28,7 +28,7 @@
<skip>true</skip>
</configuration>
</plugin>
- <!-- Gradle is also responsible for creating javadoc such that this task is skipped here. -->
+ <!-- Gradle is also responsible for creating javadoc so this task is skipped here. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
diff --git a/integration/intellij/src/main/bnf/ai/vespa/intellij/schema/parser/sd.bnf b/integration/intellij/src/main/bnf/ai/vespa/intellij/schema/parser/sd.bnf
index 04368bf29af..cd5ce14ed89 100644
--- a/integration/intellij/src/main/bnf/ai/vespa/intellij/schema/parser/sd.bnf
+++ b/integration/intellij/src/main/bnf/ai/vespa/intellij/schema/parser/sd.bnf
@@ -30,7 +30,10 @@
ID_WITH_DASH_REG = 'regexp:[a-zA-Z_][a-zA-Z0-9_-]*'
WHITE_SPACE = 'regexp:\s+'
COMMENT = 'regexp:#.*'
- SYMBOL = 'regexp:[!$|:{}(),.\[\]]'
+ SYMBOL = 'regexp:[!$|:{}().\[\]]'
+ COMMA = 'regexp:[,]'
+ //BLOCK_START = '{'
+ //BLOCK_END = '}'
COMPARISON_OPERATOR = 'regexp:[<>]|(==)|(<=)|(>=)|(~=)'
ARITHMETIC_OPERATOR = 'regexp:[\-+*/%]'
INTEGER_REG = 'regexp:[0-9]+'
@@ -55,11 +58,11 @@ SchemaFieldDefinition ::= field IdentifierVal type FieldTypeName '{' SchemaField
}
FieldTypeName ::= ("array" '<' (FieldTypeName | IdentifierVal) '>') | ("weightedset" '<' SingleValueFieldTypeName '>') |
- ("map" '<' (FieldTypeName | IdentifierVal) ',' (FieldTypeName | IdentifierVal) '>') | TensorType |
+ ("map" '<' (FieldTypeName | IdentifierVal) COMMA (FieldTypeName | IdentifierVal) '>') | TensorType |
(SingleValueFieldTypeName '[' ']') | SingleValueFieldTypeName
private SingleValueFieldTypeName ::= "string" | "int" | "long" | "bool" | "byte" | "float" | "double" | "position" | "predicate" | "raw" | "uri" |
"reference" '<' IdentifierVal '>' | "annotationreference" '<' IdentifierVal '>' | IdentifierVal
-private TensorType ::= "tensor" ('<' ("float" | "double" | "int8" | "bfloat16") '>')? '(' TensorDimension (',' TensorDimension)* ')'
+private TensorType ::= "tensor" ('<' ("float" | "double" | "int8" | "bfloat16") '>')? '(' TensorDimension (COMMA TensorDimension)* ')'
private TensorDimension ::= WordWrapper (('{' '}') | ('[' INTEGER_REG ']'))
SchemaFieldBody ::= DocumentFieldBodyOptions* // Fields of schemas and documents defined the same way here
@@ -78,7 +81,7 @@ ImportFieldDefinition ::= import field IdentifierVal '.' IdentifierVal as Identi
FieldSetDefinition ::= fieldset IdentifierVal '{' FieldSetBody '}'
FieldSetBody ::= FieldSetBodyOptions*
-private FieldSetBodyOptions ::= (fields ':' IdentifierVal (',' IdentifierVal)*) | QueryCommandDefinition | MatchDefinition
+private FieldSetBodyOptions ::= (fields ':' IdentifierVal (COMMA IdentifierVal)*) | QueryCommandDefinition | MatchDefinition
ConstantDefinition ::= constant IdentifierVal '{' ConstantBody '}'
ConstantBody ::= ConstantBodyOptions*
@@ -111,8 +114,8 @@ RankingExpression ::= FilePathExpr | ParenthesisedExpr | BooleanExpr | Arithmeti
FilePathExpr ::= file ':' (FilePath | WordWrapper)
-IfFunctionExpr ::= "if" '(' (InListRankingExpr | RankingExpression) ',' RankingExpression ',' RankingExpression ')'
-InListRankingExpr ::= RankingExpression "in" '[' RankingExpression (',' RankingExpression)* ']'
+IfFunctionExpr ::= "if" '(' (InListRankingExpr | RankingExpression) COMMA RankingExpression COMMA RankingExpression ')'
+InListRankingExpr ::= RankingExpression "in" '[' RankingExpression (COMMA RankingExpression)* ']'
BooleanExpr ::= RankingExpression COMPARISON_OPERATOR RankingExpression
@@ -120,7 +123,7 @@ ArithmeticExpr ::= RankingExpression ARITHMETIC_OPERATOR RankingExpression
QueryDefinitionExpr ::= QueryDefinition | ItemRawScoreDefinition
-FunctionCallExpr ::= IdentifierWithDashVal '(' RankingExpression (',' RankingExpression)* ')' ('.' IdentifierWithDashVal)?
+FunctionCallExpr ::= IdentifierWithDashVal '(' RankingExpression (COMMA RankingExpression)* ')' ('.' IdentifierWithDashVal)?
ParenthesisedExpr ::= '(' RankingExpression ')'
@@ -129,7 +132,7 @@ PrimitiveExpr ::= (('-')? INTEGER_REG) | (('-')? FLOAT_REG) | IdentifierVal | Ra
//-------------------------
//-- Rank Profile rules ---
//-------------------------
-RankProfileDefinition ::= (rank-profile | model) IdentifierWithDashVal (inherits IdentifierWithDashVal (',' IdentifierWithDashVal)*)? '{' RankProfileBody '}'
+RankProfileDefinition ::= (rank-profile | model) IdentifierWithDashVal (inherits IdentifierWithDashVal (COMMA IdentifierWithDashVal)*)? '{' RankProfileBody '}'
{ mixin="ai.vespa.intellij.schema.psi.impl.SdNamedElementImpl"
implements=["ai.vespa.intellij.schema.psi.SdDeclaration"]
}
@@ -167,10 +170,10 @@ private SecondPhaseBodyOptions ::= (rerank-count ':' INTEGER_REG) | ExpressionDe
RankPropertiesDefinition ::= rank-properties '{' RankPropertiesBody '}'
RankPropertiesBody ::= (RankPropertiesKey ':' RankPropertiesValue)+
-RankPropertiesKey ::= (IdentifierWithDashVal | STRING_REG | '(' | ')' | '.' | ',' | '$' | INTEGER_REG)+
+RankPropertiesKey ::= (IdentifierWithDashVal | STRING_REG | '(' | ')' | '.' | COMMA | '$' | INTEGER_REG)+
RankPropertiesValue ::= (('-')? INTEGER_REG) | (('-')? FLOAT_REG) | WORD_REG | IdentifierVal | STRING_REG
-FunctionDefinition ::= (function | macro) inline? IdentifierVal ( '()' | '(' (ArgumentDefinition (',' ArgumentDefinition)*)? ')' )
+FunctionDefinition ::= (function | macro) inline? IdentifierVal ( '()' | '(' (ArgumentDefinition (COMMA ArgumentDefinition)*)? ')' )
'{' ExpressionDefinition '}'
{ mixin="ai.vespa.intellij.schema.psi.impl.SdNamedElementImpl"
implements=["ai.vespa.intellij.schema.psi.SdFunctionDefinitionInterface" "ai.vespa.intellij.schema.psi.SdNamedElement"]
@@ -201,7 +204,7 @@ ItemRawScoreDefinition ::= "itemRawScore" '(' IdentifierVal ')'
//-------------------------
//---- Document rules -----
//-------------------------
-DocumentDefinition ::= document (IdentifierVal (inherits IdentifierVal (',' IdentifierVal)*)?)? '{' DocumentBody '}'
+DocumentDefinition ::= document (IdentifierVal (inherits IdentifierVal (COMMA IdentifierVal)*)?)? '{' DocumentBody '}'
{ mixin="ai.vespa.intellij.schema.psi.impl.SdNamedElementImpl"
implements=["ai.vespa.intellij.schema.psi.SdDeclaration" "ai.vespa.intellij.schema.psi.SdNamedElement"]
}
@@ -281,10 +284,10 @@ QueryCommandDefinition ::= query-command ':' (IdentifierVal | STRING_REG | WordW
SummaryDefinition ::= summary IdentifierWithDashVal? (type FieldTypeName)? ((':' SummaryBodyOptions) | ( '{' SummaryBody '}'))
{ mixin="ai.vespa.intellij.schema.psi.impl.SdSummaryDefinitionMixin" }
SummaryBody ::= SummaryBodyOptions* // Does not support zero-or-one occurrences
-SummaryBodyOptions ::= full | static | dynamic | (source ':' (IdentifierVal ('.' IdentifierVal)?) (',' IdentifierVal ('.' IdentifierVal)?)*) |
- (to ':' IdentifierVal (',' IdentifierVal)*) | matched-elements-only | BoldingDefinition
+SummaryBodyOptions ::= full | static | dynamic | (source ':' (IdentifierVal ('.' IdentifierVal)?) (COMMA IdentifierVal ('.' IdentifierVal)?)*) |
+ (to ':' IdentifierVal (COMMA IdentifierVal)*) | matched-elements-only | BoldingDefinition
// Summary To
-SummaryToDefinition ::= summary-to ':' WordWrapper (',' WordWrapper)*
+SummaryToDefinition ::= summary-to ':' WordWrapper (COMMA WordWrapper)*
// Bolding
BoldingDefinition ::= bolding ':' (on | off | true | false)
// Index
diff --git a/integration/intellij/src/main/java/ai/vespa/intellij/schema/SdSyntaxHighlighter.java b/integration/intellij/src/main/java/ai/vespa/intellij/schema/SdSyntaxHighlighter.java
index 666687e56c1..de0d58c63a0 100644
--- a/integration/intellij/src/main/java/ai/vespa/intellij/schema/SdSyntaxHighlighter.java
+++ b/integration/intellij/src/main/java/ai/vespa/intellij/schema/SdSyntaxHighlighter.java
@@ -64,7 +64,7 @@ public class SdSyntaxHighlighter extends SyntaxHighlighterBase {
return IDENTIFIER_KEYS;
} else if (keyWordsSet.contains(tokenType)) {
return KEY_KEYS;
- } else if (tokenType.equals(SdTypes.SYMBOL)) {
+ } else if (tokenType.equals(SdTypes.SYMBOL) || tokenType.equals(SdTypes.COMMA)) {
return SYMBOL_KEYS;
} else if (tokenType.equals(SdTypes.STRING_REG)) {
return STRING_KEYS;
diff --git a/integration/intellij/src/main/java/ai/vespa/intellij/schema/SdUtil.java b/integration/intellij/src/main/java/ai/vespa/intellij/schema/SdUtil.java
index 2bc5fa80e18..c5f9c7fed35 100644
--- a/integration/intellij/src/main/java/ai/vespa/intellij/schema/SdUtil.java
+++ b/integration/intellij/src/main/java/ai/vespa/intellij/schema/SdUtil.java
@@ -9,8 +9,10 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.PsiReference;
+import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.search.FileTypeIndex;
import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import ai.vespa.intellij.schema.psi.SdAnnotationFieldDefinition;
import ai.vespa.intellij.schema.psi.SdArgumentDefinition;
@@ -62,26 +64,38 @@ public class SdUtil {
}
/**
- * @param baseRankProfile the rank-profile node to find its parent
- * @return the rank-profile that the baseRankProfile inherits from, or null if it doesn't exist
+ * Returns the profiles inherited by this.
+ *
+ * @param baseRankProfile the rank-profile node to find the parents of
+ * @return the profiles this inherits from, empty if none
*/
public static List<SdRankProfileDefinition> getRankProfileParents(SdRankProfileDefinition baseRankProfile) {
- if (baseRankProfile == null) return null;
+ if (baseRankProfile == null) return List.of();
ASTNode inheritsNode = baseRankProfile.getNode().findChildByType(SdTypes.INHERITS);
- if (inheritsNode == null) return null;
-
- return identifiersIn(inheritsNode).stream()
- .map(parentIdentifierAST -> parentIdentifierAST.getPsi().getReference())
- .filter(reference -> reference != null)
- .map(reference -> (SdRankProfileDefinition)reference.resolve())
- .collect(Collectors.toList());
+ if (inheritsNode == null) return List.of();
+ return inherits(baseRankProfile).stream()
+ .map(parentIdentifierAST -> parentIdentifierAST.getPsi().getReference())
+ .filter(reference -> reference != null)
+ .map(reference -> (SdRankProfileDefinition)reference.resolve())
+ .collect(Collectors.toList());
}
- private static List<ASTNode> identifiersIn(ASTNode inheritsNode) {
- return Arrays.stream(inheritsNode.getChildren(null))
- .filter(node -> node.getElementType() == SdTypes.IDENTIFIER_VAL ||
- node.getElementType() == SdTypes.IDENTIFIER_WITH_DASH_VAL)
- .collect(Collectors.toList());
+ private static List<ASTNode> inherits(SdRankProfileDefinition baseRankProfile) {
+ Tokens tokens = Tokens.of(baseRankProfile);
+ tokens.require(SdTypes.RANK_PROFILE);
+ tokens.requireWhitespace();
+ tokens.require(SdTypes.IDENTIFIER_VAL, SdTypes.IDENTIFIER_WITH_DASH_VAL);
+ if ( ! tokens.skipWhitespace()) return List.of();
+ if ( ! tokens.skip(SdTypes.INHERITS)) return List.of();
+ tokens.requireWhitespace();
+ List<ASTNode> inherited = new ArrayList<>();
+ do {
+ inherited.add(tokens.require(SdTypes.IDENTIFIER_VAL, SdTypes.IDENTIFIER_WITH_DASH_VAL));
+ tokens.skipWhitespace();
+ if ( ! tokens.skip(SdTypes.COMMA)) break;
+ tokens.skipWhitespace();
+ } while (true);
+ return inherited;
}
public static String createFunctionDescription(SdFunctionDefinition function) {
@@ -237,5 +251,84 @@ public class SdUtil {
public static List<PsiElement> findDocumentSummaryChildren(PsiElement element) {
return new ArrayList<>(PsiTreeUtil.collectElementsOfType(element, SdSummaryDefinition.class));
}
-
+
+ /** A collection of tokens with a current index. */
+ public static class Tokens {
+
+ private final ASTNode[] nodes;
+ private int i = 0;
+
+ private Tokens(PsiElement element) {
+ nodes = element.getNode().getChildren(null);
+ }
+
+ /**
+ * Advances to the next token, if it is of the given type.
+ *
+ * @return true if the current token was of the given type and we advanced it, false
+ * if it was not and nothing was changed
+ */
+ public boolean skip(IElementType ... tokenTypes) {
+ boolean is = is(tokenTypes);
+ if (is)
+ i++;
+ return is;
+ }
+
+ /**
+ * Advances beyond the next token, if it is whitespace.
+ *
+ * @return true if the current token was of the given type and we advanced it, false
+ * if it was not and nothing was changed
+ */
+ public boolean skipWhitespace() {
+ boolean is = isWhitespace();
+ if (is)
+ i++;
+ return is;
+ }
+
+ /** Returns whether the current token is of the given type */
+ public boolean is(IElementType ... tokenTypes) {
+ for (IElementType type : tokenTypes)
+ if (current().getElementType() == type) return true;
+ return false;
+ }
+
+ /** Returns whether the current token is whitespace */
+ public boolean isWhitespace() {
+ return current().getPsi() instanceof PsiWhiteSpace;
+ }
+
+ /** Returns the current token if it is of the required type and throws otherwise. */
+ public ASTNode require(IElementType ... tokenTypes) {
+ if ( ! is(tokenTypes) )
+ throw new IllegalArgumentException("Expected " + toString(tokenTypes) + " but got " + current());
+ ASTNode current = current();
+ i++;
+ return current;
+ }
+
+ public void requireWhitespace() {
+ if ( ! isWhitespace() )
+ throw new IllegalArgumentException("Expected whitespace, but got " + current());
+ i++;
+ }
+
+ /** Returns the current token (AST node), or null if we have reached the end. */
+ public ASTNode current() {
+ if (i >= nodes.length) return null;
+ return nodes[i];
+ }
+
+ private String toString(IElementType[] tokens) {
+ return Arrays.stream(tokens).map(token -> token.getDebugName()).collect(Collectors.joining(", "));
+ }
+
+ public static Tokens of(PsiElement element) {
+ return new Tokens(element);
+ }
+
+ }
+
}
diff --git a/integration/intellij/src/main/java/ai/vespa/intellij/schema/model/RankProfile.java b/integration/intellij/src/main/java/ai/vespa/intellij/schema/model/RankProfile.java
index fd30a0fbe53..5e927d669dc 100644
--- a/integration/intellij/src/main/java/ai/vespa/intellij/schema/model/RankProfile.java
+++ b/integration/intellij/src/main/java/ai/vespa/intellij/schema/model/RankProfile.java
@@ -5,6 +5,7 @@ import ai.vespa.intellij.schema.psi.SdFile;
import ai.vespa.intellij.schema.psi.SdRankProfileDefinition;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.FilenameIndex;
@@ -34,15 +35,9 @@ public class RankProfile {
* @throws IllegalArgumentException if not found
*/
public static RankProfile fromProjectFile(Project project, String filePath, String profileName) {
- PsiFile[] psiFile = FilenameIndex.getFilesByName(project, filePath, GlobalSearchScope.allScope(project));
- if (psiFile.length == 0)
- throw new IllegalArgumentException(filePath + " could not be opened");
- if (psiFile.length > 1)
- throw new IllegalArgumentException("Multiple files matches " + filePath);
- if ( ! (psiFile[0] instanceof SdFile))
- throw new IllegalArgumentException(filePath + " is not a schema or profile");
+ PsiElement root = Schema.load(project, filePath);
Optional<SdRankProfileDefinition> definition =
- PsiTreeUtil.collectElementsOfType(psiFile[0], SdRankProfileDefinition.class)
+ PsiTreeUtil.collectElementsOfType(root, SdRankProfileDefinition.class)
.stream()
.filter(p -> p.getName().equals(profileName))
.findAny();
diff --git a/integration/intellij/src/main/java/ai/vespa/intellij/schema/model/Schema.java b/integration/intellij/src/main/java/ai/vespa/intellij/schema/model/Schema.java
new file mode 100644
index 00000000000..3b67a5a0290
--- /dev/null
+++ b/integration/intellij/src/main/java/ai/vespa/intellij/schema/model/Schema.java
@@ -0,0 +1,52 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package ai.vespa.intellij.schema.model;
+
+import ai.vespa.intellij.schema.psi.SdFile;
+import ai.vespa.intellij.schema.psi.SdRankProfileDefinition;
+import ai.vespa.intellij.schema.psi.SdSchemaBody;
+import ai.vespa.intellij.schema.psi.SdSchemaDefinition;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.search.FilenameIndex;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiTreeUtil;
+
+import java.util.Optional;
+
+/**
+ * A schema.
+ *
+ * @author bratseth
+ */
+public class Schema {
+
+ private final SdFile definition;
+
+ public Schema(SdFile definition) {
+ this.definition = definition;
+ }
+
+ public SdFile definition() { return definition; }
+
+ /**
+ * Returns the profile of the given name from the given file.
+ *
+ * @throws IllegalArgumentException if not found
+ */
+ public static Schema fromProjectFile(Project project, String filePath) {
+ return new Schema((SdFile)load(project, filePath));
+ }
+
+ static PsiElement load(Project project, String filePath) {
+ PsiFile[] psiFile = FilenameIndex.getFilesByName(project, filePath, GlobalSearchScope.allScope(project));
+ if (psiFile.length == 0)
+ throw new IllegalArgumentException(filePath + " could not be opened");
+ if (psiFile.length > 1)
+ throw new IllegalArgumentException("Multiple files matches " + filePath);
+ if ( ! (psiFile[0] instanceof SdFile))
+ throw new IllegalArgumentException(filePath + " is not a schema file");
+ return psiFile[0];
+ }
+
+}
diff --git a/integration/intellij/src/main/jflex/ai/vespa/intellij/schema/lexer/sd.flex b/integration/intellij/src/main/jflex/ai/vespa/intellij/schema/lexer/sd.flex
index 78334de1961..f3064612b43 100644
--- a/integration/intellij/src/main/jflex/ai/vespa/intellij/schema/lexer/sd.flex
+++ b/integration/intellij/src/main/jflex/ai/vespa/intellij/schema/lexer/sd.flex
@@ -34,7 +34,10 @@ ID_WITH_DASH = [a-zA-Z_][a-zA-Z0-9_-]*
WHITE_SPACE=[ \t\n\x0B\f\r]+
COMMENT=#.*
-SYMBOL= [!$|:{}(),.\[\]]
+SYMBOL= [!$|:{}().\[\]]
+COMMA= [,]
+//BLOCK_START= \{
+//BLOCK_END= \}
INTEGER = [0-9]+
FLOAT = {INTEGER}[.][0-9]+[e]?
COMPARISON_OPERATOR = [<>]|(==)|(<=)|(>=)|(\~=)
@@ -217,7 +220,7 @@ WORD = \w+
"evaluation-point" { return EVALUATION_POINT; }
"pre-post-filter-tipping-point" { return PRE_POST_FILTER_TIPPING_POINT; }
- // In here, we check for character sequences which matches regular expressions defined above.
+ // Here we check for character sequences which matches regular expressions defined above.
{ID} { return ID_REG; }
{ID_WITH_DASH} { return ID_WITH_DASH_REG; }
@@ -225,6 +228,9 @@ WORD = \w+
{COMMENT} { return COMMENT; }
{SYMBOL} { return SYMBOL; }
+ {COMMA} { return COMMA; }
+ //{BLOCK_START} { return BLOCK_START; }
+ //{BLOCK_END} { return BLOCK_END; }
{INTEGER} { return INTEGER_REG; }
{FLOAT} { return FLOAT_REG; }
{ARITHMETIC_OPERATOR} { return ARITHMETIC_OPERATOR; }
diff --git a/integration/intellij/src/test/applications/schemainheritance/child.sd b/integration/intellij/src/test/applications/schemainheritance/child.sd
index a209919763d..e45f5cb3991 100644
--- a/integration/intellij/src/test/applications/schemainheritance/child.sd
+++ b/integration/intellij/src/test/applications/schemainheritance/child.sd
@@ -22,7 +22,10 @@ schema child inherits parent {
indexing: input pf1 | lowercase | index | attribute | summary
}
- rank-profile child_profile inherits parent_profile {
+ rank-profile child_profile inherits other_child_profile, parent_profile {
+ }
+
+ rank-profile other_child_profile {
}
constant child_constant {
diff --git a/integration/intellij/src/test/applications/simple/simple.sd b/integration/intellij/src/test/applications/simple/simple.sd
new file mode 100644
index 00000000000..21e683b3ee4
--- /dev/null
+++ b/integration/intellij/src/test/applications/simple/simple.sd
@@ -0,0 +1,15 @@
+schema simple {
+
+ document simple {
+ }
+
+ rank-profile simple-profile inherits parent-profile1, parent-profile2 {
+ }
+
+ rank-profile parent-profile1 {
+ }
+
+ rank-profile parent-profile2 {
+ }
+
+} \ No newline at end of file
diff --git a/integration/intellij/src/test/java/ai/vespa/intellij/model/MockProject.java b/integration/intellij/src/test/java/ai/vespa/intellij/model/MockProject.java
deleted file mode 100644
index f54dfdee2ef..00000000000
--- a/integration/intellij/src/test/java/ai/vespa/intellij/model/MockProject.java
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package ai.vespa.intellij.model;
-
-import com.intellij.diagnostic.ActivityCategory;
-import com.intellij.openapi.extensions.PluginDescriptor;
-import com.intellij.openapi.extensions.PluginId;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.util.Key;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.messages.MessageBus;
-import org.picocontainer.PicoContainer;
-
-import java.io.File;
-import java.util.Map;
-
-public class MockProject implements Project {
-
- private final File schemasDir;
-
- public MockProject(File schemasDir) {
- this.schemasDir = schemasDir;
- }
-
- @Override
- public String getName() { return "mock project"; }
-
- @Override
- public VirtualFile getBaseDir() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getBasePath() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public VirtualFile getProjectFile() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getProjectFilePath() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public VirtualFile getWorkspaceFile() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getLocationHash() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void save() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isOpen() { return true; }
-
- @Override
- public boolean isInitialized() { return true; }
-
- @Override
- public <T> T getComponent(Class<T> interfaceClass) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public <T> T[] getComponents(Class<T> baseClass) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public PicoContainer getPicoContainer() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isInjectionForExtensionSupported() { return false; }
-
- @Override
- public MessageBus getMessageBus() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isDisposed() { return false; }
-
- @Override
- public Condition<?> getDisposed() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public <T> T getService(Class<T> serviceClass) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public <T> T instantiateClassWithConstructorInjection(Class<T> aClass, Object key, PluginId pluginId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public RuntimeException createError(Throwable error, PluginId pluginId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public RuntimeException createError(String message, PluginId pluginId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public RuntimeException createError(String message, Throwable error, PluginId pluginId, Map<String, String> attachments) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public <T> Class<T> loadClass(String className, PluginDescriptor pluginDescriptor) throws ClassNotFoundException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public ActivityCategory getActivityCategory(boolean isExtension) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void dispose() {
- }
-
- @Override
- public <T> T getUserData(Key<T> key) { return null; }
-
- @Override
- public <T> void putUserData(Key<T> key, T value) {
- throw new UnsupportedOperationException();
- }
-
-}
diff --git a/integration/intellij/src/test/java/ai/vespa/intellij/model/RankProfileTest.java b/integration/intellij/src/test/java/ai/vespa/intellij/model/RankProfileTest.java
deleted file mode 100644
index c0b4902c002..00000000000
--- a/integration/intellij/src/test/java/ai/vespa/intellij/model/RankProfileTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package ai.vespa.intellij.model;
-
-import ai.vespa.intellij.schema.model.RankProfile;
-import com.intellij.testFramework.LightProjectDescriptor;
-import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
-import org.junit.Test;
-
-import java.io.File;
-
-/**
- * @author bratseth
- */
-public class RankProfileTest extends LightJavaCodeInsightFixtureTestCase {
-
- @Override
- protected LightProjectDescriptor getProjectDescriptor() {
- // Store the descriptor between tests to make this faster
- return new TestProjectDescriptor();
- }
-
- @Override
- protected String getTestDataPath() { return "."; }
-
- @Test
- public void testFindDefinition() {
- super.myFixture.copyDirectoryToProject("src/test/applications/schemainheritance", "/");
- RankProfile profile = RankProfile.fromProjectFile(getProject(), "child.sd", "child_profile");
- assertEquals("child_profile", profile.definition().getName());
- }
-
-}
diff --git a/integration/intellij/src/test/java/ai/vespa/intellij/model/SchemaTest.java b/integration/intellij/src/test/java/ai/vespa/intellij/model/SchemaTest.java
new file mode 100644
index 00000000000..38fd9a97a5b
--- /dev/null
+++ b/integration/intellij/src/test/java/ai/vespa/intellij/model/SchemaTest.java
@@ -0,0 +1,59 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package ai.vespa.intellij.model;
+
+import ai.vespa.intellij.schema.SdUtil;
+import ai.vespa.intellij.schema.model.RankProfile;
+import ai.vespa.intellij.schema.model.Schema;
+import ai.vespa.intellij.schema.psi.SdRankProfileDefinition;
+import com.intellij.testFramework.LightProjectDescriptor;
+import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * @author bratseth
+ */
+public class SchemaTest extends LightJavaCodeInsightFixtureTestCase {
+
+ private final TestProjectDescriptor descriptor;
+
+ public SchemaTest() {
+ descriptor = new TestProjectDescriptor(); // Expensive instance
+ }
+
+ @Override
+ protected LightProjectDescriptor getProjectDescriptor() { return descriptor; }
+
+ @Override
+ protected String getTestDataPath() { return "."; }
+
+ @Test
+ public void testSimple() {
+ super.myFixture.copyDirectoryToProject("src/test/applications/simple", "/");
+ Schema schema = Schema.fromProjectFile(getProject(), "simple.sd");
+ assertNotNull(schema);
+ assertEquals("simple.sd", schema.definition().getName());
+ RankProfile profile = RankProfile.fromProjectFile(getProject(), "simple.sd", "simple-profile");
+ assertEquals("simple-profile", profile.definition().getName());
+ List<SdRankProfileDefinition> parents = SdUtil.getRankProfileParents(profile.definition());
+ assertEquals(2, parents.size());
+ assertEquals("parent-profile1", parents.get(0).getName());
+ assertEquals("parent-profile2", parents.get(1).getName());
+ }
+
+ @Test
+ public void testSchemaInheritance() {
+ super.myFixture.copyDirectoryToProject("src/test/applications/schemainheritance", "/");
+ Schema schema = Schema.fromProjectFile(getProject(), "child.sd");
+ assertNotNull(schema);
+ assertEquals("child.sd", schema.definition().getName());
+ RankProfile profile = RankProfile.fromProjectFile(getProject(), "child.sd", "child_profile");
+ assertEquals("child_profile", profile.definition().getName());
+ List<SdRankProfileDefinition> parents = SdUtil.getRankProfileParents(profile.definition());
+ assertEquals(2, parents.size());
+ assertEquals("other_child_profile", parents.get(0).getName());
+ // assertEquals("parent-profile", parents.get(1).getName()); TODO
+ }
+
+}
diff --git a/integration/intellij/src/test/java/ai/vespa/intellij/model/TestProjectDescriptor.java b/integration/intellij/src/test/java/ai/vespa/intellij/model/TestProjectDescriptor.java
index ae36c16ce67..5952b17a642 100644
--- a/integration/intellij/src/test/java/ai/vespa/intellij/model/TestProjectDescriptor.java
+++ b/integration/intellij/src/test/java/ai/vespa/intellij/model/TestProjectDescriptor.java
@@ -3,8 +3,6 @@ package ai.vespa.intellij.model;
import com.intellij.testFramework.LightProjectDescriptor;
-import java.io.File;
-
/**
* Describes a project used in unit tests.
* https://plugins.jetbrains.com/docs/intellij/light-and-heavy-tests.html
@@ -12,5 +10,5 @@ import java.io.File;
* @author bratseth
*/
public class TestProjectDescriptor extends LightProjectDescriptor {
-
+
}