package com.google.jstestdriver.idea.assertFramework.jasmine; import com.google.common.collect.Maps; import com.google.jstestdriver.idea.assertFramework.Annotation; import com.google.jstestdriver.idea.assertFramework.CompoundId; import com.google.jstestdriver.idea.util.CastUtils; import com.intellij.lang.javascript.psi.JSFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; class MarkedJasmineFileStructureBuilder { private static final Pattern SUITE_START = Pattern.compile("/\\*suite .+?\\*/"); private static final Pattern SUITE_END = Pattern.compile("/\\*suiteEnd .+?\\*/"); private static final Pattern SPEC_START = Pattern.compile("/\\*spec .+?\\*/"); private static final Pattern SPEC_END = Pattern.compile("/\\*specEnd .+?\\*/"); private MarkedJasmineFileStructureBuilder() {} public static MarkedJasmineFileStructure buildMarkedJasmineFileStructure(@NotNull String fileText, @NotNull JSFile jsFile) { MarkedJasmineFileStructure markedJasmineFileStructure = new MarkedJasmineFileStructure(); handleBeginOfMarkedSuite(markedJasmineFileStructure, fileText); handleEndOfMarkedSuite(markedJasmineFileStructure, fileText, jsFile); validateMarkedSuites(markedJasmineFileStructure.getInnerSuiteStructures()); Collection<MarkedJasmineSpecStructure> markedJasmineSpecStructures = buildMarkedJasmineSpecStructures(fileText, jsFile); assignSpecsToSuites(markedJasmineFileStructure, markedJasmineSpecStructures); return markedJasmineFileStructure; } private static void assignSpecsToSuites(@NotNull MarkedJasmineFileStructure markedJasmineFileStructure, @NotNull Collection<MarkedJasmineSpecStructure> markedJasmineSpecStructures) { for (MarkedJasmineSpecStructure specStructure : markedJasmineSpecStructures) { CompoundId suiteId = specStructure.getSuiteId(); MarkedJasmineSuiteStructureContainer container = findContainerById(markedJasmineFileStructure, suiteId); MarkedJasmineSuiteStructure suiteStructure = CastUtils.tryCast(container, MarkedJasmineSuiteStructure.class); if (suiteStructure == null) { throw new RuntimeException("Suite structure was not found by id '" + suiteId + "'!"); } suiteStructure.addSpecStructure(specStructure); } } private static void validateMarkedSuites(Collection<MarkedJasmineSuiteStructure> suites) { for (MarkedJasmineSuiteStructure suite : suites) { suite.validate(); } } private static void handleBeginOfMarkedSuite(MarkedJasmineFileStructure markedJasmineFileStructure, String fileText) { Matcher suiteStartMatcher = SUITE_START.matcher(fileText); while (suiteStartMatcher.find()) { Annotation startAnnotation = Annotation.fromMatcher(suiteStartMatcher); CompoundId suiteId = startAnnotation.getCompoundId(); MarkedJasmineSuiteStructureContainer container = findContainerById(markedJasmineFileStructure, suiteId.getParentId()); if (container == null) { throw new RuntimeException("Can't find container for suite with " + suiteId); } MarkedJasmineSuiteStructure markedJasmineSuiteStructure = container.findSuiteStructureById(suiteId); if (markedJasmineSuiteStructure != null) { throw new RuntimeException("Duplicated suite with id " + suiteId + " found"); } markedJasmineSuiteStructure = new MarkedJasmineSuiteStructure(startAnnotation); container.addSuiteStructure(markedJasmineSuiteStructure); } } @Nullable private static MarkedJasmineSuiteStructureContainer findContainerById(MarkedJasmineSuiteStructureContainer rootContainer, CompoundId id) { if (!id.hasParent()) { return rootContainer; } MarkedJasmineSuiteStructureContainer parentContainer = findContainerById(rootContainer, id.getParentId()); if (parentContainer == null) { return null; } return parentContainer.findSuiteStructureById(id); } private static void handleEndOfMarkedSuite(@NotNull MarkedJasmineFileStructure markedJasmineFileStructure, @NotNull String fileText, @NotNull JSFile jsFile) { Matcher suiteEndMatcher = SUITE_END.matcher(fileText); while (suiteEndMatcher.find()) { Annotation endAnnotation = Annotation.fromMatcher(suiteEndMatcher); CompoundId suiteStructureId = endAnnotation.getCompoundId(); MarkedJasmineSuiteStructureContainer suiteStructureContainer = findContainerById(markedJasmineFileStructure, suiteStructureId); if (!(suiteStructureContainer instanceof MarkedJasmineSuiteStructure)) { throw new RuntimeException(suiteEndMatcher.group() + " references undefined suite!"); } MarkedJasmineSuiteStructure suiteStructure = (MarkedJasmineSuiteStructure)suiteStructureContainer; suiteStructure.endAnnotationEncountered(endAnnotation.getTextRange(), jsFile); } } private static Collection<MarkedJasmineSpecStructure> buildMarkedJasmineSpecStructures(String fileText, JSFile jsFile) { Map<CompoundId, MarkedJasmineSpecStructure> markedSpecStructureMap = Maps.newHashMap(); handleBeginOfMarkedJasmineSpec(markedSpecStructureMap, fileText); handleEndOfMarkedJasmineSpec(markedSpecStructureMap, fileText, jsFile); Collection<MarkedJasmineSpecStructure> markedSpecStructures = markedSpecStructureMap.values(); for (MarkedJasmineSpecStructure markedJasmineSpecStructure : markedSpecStructures) { markedJasmineSpecStructure.validate(); } return markedSpecStructures; } private static void handleBeginOfMarkedJasmineSpec(@NotNull Map<CompoundId, MarkedJasmineSpecStructure> markedSpecStructureMap, @NotNull String fileText) { Matcher specStartMatcher = SPEC_START.matcher(fileText); while (specStartMatcher.find()) { Annotation startAnnotation = Annotation.fromMatcher(specStartMatcher); CompoundId specId = startAnnotation.getCompoundId(); MarkedJasmineSpecStructure markedJasmineSpecStructure = markedSpecStructureMap.get(specId); if (markedJasmineSpecStructure != null) { throw new RuntimeException("Duplicated spec with id '" + specId + "'"); } markedJasmineSpecStructure = new MarkedJasmineSpecStructure(startAnnotation); markedSpecStructureMap.put(markedJasmineSpecStructure.getId(), markedJasmineSpecStructure); } } private static void handleEndOfMarkedJasmineSpec(@NotNull Map<CompoundId, MarkedJasmineSpecStructure> markedSpecStructureMap, @NotNull String fileText, @NotNull JSFile jsFile) { Matcher specEndMatcher = SPEC_END.matcher(fileText); while (specEndMatcher.find()) { Annotation endAnnotation = Annotation.fromMatcher(specEndMatcher); CompoundId specId = endAnnotation.getCompoundId(); MarkedJasmineSpecStructure markedJasmineSpecStructure = markedSpecStructureMap.get(specId); if (markedJasmineSpecStructure == null) { throw new RuntimeException(specEndMatcher.group() + " references undefined spec!"); } markedJasmineSpecStructure.endAnnotationEncountered(endAnnotation.getTextRange(), jsFile); } } }