package com.google.jstestdriver.idea.assertFramework.jstd;
import com.google.common.collect.Maps;
import com.intellij.javascript.testFramework.Annotation;
import com.intellij.lang.javascript.psi.JSCallExpression;
import com.intellij.lang.javascript.psi.JSFile;
import com.intellij.openapi.util.TextRange;
import com.intellij.util.ObjectUtils;
import junit.framework.Assert;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class MarkedJstdTestStructureUtils {
private static final Pattern TEST_CASE_PATTERN = Pattern.compile("/\\*TestCase (.+?)\\*/");
private static final Pattern TEST_CASE_END_PATTERN = Pattern.compile("/\\*TestCaseEnd id:(\\d+?)\\*/");
private static final Pattern TEST_PATTERN = Pattern.compile("/\\*Test (.+?)\\*/");
private static final Pattern TEST_END_PATTERN = Pattern.compile("/\\*TestEnd (.+?)\\*/");
private MarkedJstdTestStructureUtils() {}
public static MarkedJsTestFileStructure buildMarkedJsTestFileStructureByFileText(@NotNull String fileText, @NotNull JSFile jsFile) throws Exception {
MarkedJsTestFileStructure markedJsTestFileStructure = new MarkedJsTestFileStructure();
handleBeginOfMarkedTestCase(markedJsTestFileStructure, fileText);
handleEndOfMarkedTestCase(markedJsTestFileStructure, fileText, jsFile);
validateMarkedTestCases(markedJsTestFileStructure.getMarkedTestCaseStructures());
Collection<MarkedTestStructure> markedTestStructures = buildMarkedTestStructures(fileText, jsFile);
assignTestsToTestCases(markedJsTestFileStructure, markedTestStructures);
return markedJsTestFileStructure;
}
private static void handleBeginOfMarkedTestCase(MarkedJsTestFileStructure markedJsTestFileStructure, String fileText) {
Matcher testCaseMatcher = TEST_CASE_PATTERN.matcher(fileText);
while (testCaseMatcher.find()) {
Annotation annotation = new Annotation("TestCase", testCaseMatcher.start(), testCaseMatcher.end(), testCaseMatcher.group(1));
int id = MarkedTestCaseStructure.getIdAndValidate(annotation);
MarkedTestCaseStructure markedTestCaseStructure = markedJsTestFileStructure.findById(id);
if (markedTestCaseStructure != null) {
throw new RuntimeException("Duplicated TestCase with id " + id + " found");
}
markedTestCaseStructure = new MarkedTestCaseStructure(annotation);
markedJsTestFileStructure.addMarkedTestCaseStructure(markedTestCaseStructure);
}
}
private static void handleEndOfMarkedTestCase(MarkedJsTestFileStructure markedJsTestFileStructure, String fileText, JSFile jsFile) {
Matcher testCaseEndMatcher = TEST_CASE_END_PATTERN.matcher(fileText);
while (testCaseEndMatcher.find()) {
String testCaseIdStr = testCaseEndMatcher.group(1);
int testCaseId = Integer.parseInt(testCaseIdStr);
MarkedTestCaseStructure markedTestCaseStructure = markedJsTestFileStructure.findById(testCaseId);
if (markedTestCaseStructure == null) {
throw new RuntimeException("'" + testCaseEndMatcher.group() + "' references undefined TestCase");
}
markedTestCaseStructure.endEncountered(TextRange.create(testCaseEndMatcher.start(), testCaseEndMatcher.end()), jsFile);
}
}
private static void validateMarkedTestCases(List<MarkedTestCaseStructure> markedTestCaseStructures) {
for (MarkedTestCaseStructure markedTestCaseStructure : markedTestCaseStructures) {
if (markedTestCaseStructure.getPsiElement() == null) {
throw new RuntimeException("End was not found for " + markedTestCaseStructure);
}
JSCallExpression jsCallExpression = ObjectUtils.tryCast(markedTestCaseStructure.getPsiElement(), JSCallExpression.class);
if (jsCallExpression == null) {
Assert.fail("Unable to find underlying " + JSCallExpression.class + " for " + markedTestCaseStructure);
}
}
}
private static void assignTestsToTestCases(MarkedJsTestFileStructure markedJsTestFileStructure,
Collection<MarkedTestStructure> markedTestStructures) {
for (MarkedTestStructure markedTestStructure : markedTestStructures) {
MarkedTestCaseStructure markedTestCaseStructure = markedJsTestFileStructure.findById(markedTestStructure.getTestCaseId());
markedTestCaseStructure.addTestStructureInfo(markedTestStructure);
}
}
private static Collection<MarkedTestStructure> buildMarkedTestStructures(@NotNull String fileText, @NotNull JSFile jsFile) {
Map<String, MarkedTestStructure> markedTestStructureMap = Maps.newHashMap();
handleBeginOfMarkedTest(markedTestStructureMap, fileText);
handleEndOfMarkedTest(markedTestStructureMap, fileText, jsFile);
Collection<MarkedTestStructure> markedTestStructures = markedTestStructureMap.values();
for (MarkedTestStructure markedTestStructure : markedTestStructures) {
markedTestStructure.validateBuiltTest();
}
return markedTestStructures;
}
private static void handleBeginOfMarkedTest(Map<String, MarkedTestStructure> markedTestStructureMap, String fileText) {
Matcher testMatcher = TEST_PATTERN.matcher(fileText);
while (testMatcher.find()) {
Annotation annotation = new Annotation("Test", testMatcher.start(), testMatcher.end(), testMatcher.group(1));
String testId = MarkedTestStructure.getIdAndValidate(annotation);
MarkedTestStructure markedTestStructure = markedTestStructureMap.get(testId);
if (markedTestStructure == null) {
markedTestStructure = new MarkedTestStructure(annotation);
markedTestStructureMap.put(testId, markedTestStructure);
}
markedTestStructure.handleBeginAnnotation(annotation);
}
}
private static void handleEndOfMarkedTest(Map<String, MarkedTestStructure> markedTestStructureMap, String fileText, JSFile jsFile) {
Matcher endOfTestMatcher = TEST_END_PATTERN.matcher(fileText);
while (endOfTestMatcher.find()) {
Annotation annotation = new Annotation("TestEnd", endOfTestMatcher.start(), endOfTestMatcher.end(), endOfTestMatcher.group(1));
String testId = annotation.getValue("id");
MarkedTestStructure markedTestStructure = markedTestStructureMap.get(testId);
if (markedTestStructure == null) {
throw new RuntimeException("'" + endOfTestMatcher.group() + "' references undefined Test");
}
markedTestStructure.handleEndAnnotation(annotation, jsFile);
}
}
}