| /* |
| * Copyright 2016 The Bazel Authors. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.google.idea.blaze.base.projectview.parser; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import com.google.common.base.Joiner; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Maps; |
| import com.google.idea.blaze.base.BlazeTestCase; |
| import com.google.idea.blaze.base.model.primitives.TargetExpression; |
| import com.google.idea.blaze.base.model.primitives.WorkspacePath; |
| import com.google.idea.blaze.base.model.primitives.WorkspaceRoot; |
| import com.google.idea.blaze.base.model.primitives.WorkspaceType; |
| import com.google.idea.blaze.base.projectview.ProjectView; |
| import com.google.idea.blaze.base.projectview.ProjectViewSet; |
| import com.google.idea.blaze.base.projectview.ProjectViewStorageManager; |
| import com.google.idea.blaze.base.projectview.section.ListSection; |
| import com.google.idea.blaze.base.projectview.section.ScalarSection; |
| import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry; |
| import com.google.idea.blaze.base.projectview.section.sections.DirectorySection; |
| import com.google.idea.blaze.base.projectview.section.sections.ImportSection; |
| import com.google.idea.blaze.base.projectview.section.sections.TargetSection; |
| import com.google.idea.blaze.base.projectview.section.sections.TextBlock; |
| import com.google.idea.blaze.base.projectview.section.sections.TextBlockSection; |
| import com.google.idea.blaze.base.projectview.section.sections.WorkspaceTypeSection; |
| import com.google.idea.blaze.base.scope.BlazeContext; |
| import com.google.idea.blaze.base.scope.ErrorCollector; |
| import com.google.idea.blaze.base.scope.output.IssueOutput; |
| import com.google.idea.blaze.base.sync.BlazeSyncPlugin; |
| import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl; |
| import com.google.idea.common.experiments.ExperimentService; |
| import com.google.idea.common.experiments.MockExperimentService; |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.Collection; |
| import java.util.Map; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** Tests for the project view parser */ |
| @RunWith(JUnit4.class) |
| public class ProjectViewParserTest extends BlazeTestCase { |
| private ProjectViewParser projectViewParser; |
| private BlazeContext context; |
| private ErrorCollector errorCollector; |
| private WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File("/")); |
| private MockProjectViewStorageManager projectViewStorageManager; |
| |
| static class MockProjectViewStorageManager extends ProjectViewStorageManager { |
| Map<String, String> projectViewFiles = Maps.newHashMap(); |
| |
| @Nullable |
| @Override |
| public String loadProjectView(@NotNull File projectViewFile) throws IOException { |
| return projectViewFiles.get(projectViewFile.getPath()); |
| } |
| |
| @Override |
| public void writeProjectView(@NotNull String projectViewText, @NotNull File projectViewFile) |
| throws IOException { |
| // no-op |
| } |
| |
| void add(String name, String... text) { |
| projectViewFiles.put(name, Joiner.on('\n').join(text)); |
| } |
| } |
| |
| @Override |
| protected void initTest( |
| @NotNull Container applicationServices, @NotNull Container projectServices) { |
| super.initTest(applicationServices, projectServices); |
| context = new BlazeContext(); |
| errorCollector = new ErrorCollector(); |
| context.addOutputSink(IssueOutput.class, errorCollector); |
| projectViewParser = |
| new ProjectViewParser(context, new WorkspacePathResolverImpl(workspaceRoot)); |
| projectViewStorageManager = new MockProjectViewStorageManager(); |
| applicationServices.register(ProjectViewStorageManager.class, projectViewStorageManager); |
| applicationServices.register(ExperimentService.class, new MockExperimentService()); |
| registerExtensionPoint(BlazeSyncPlugin.EP_NAME, BlazeSyncPlugin.class); |
| } |
| |
| @Test |
| public void testDirectoriesAndTargets() throws Exception { |
| projectViewStorageManager.add( |
| ".blazeproject", |
| "directories:", |
| " java/com/google", |
| " java/com/google/android", |
| " -java/com/google/android/notme", |
| "", |
| "targets:", |
| " //java/com/google:all", |
| " //java/com/google/...:all", |
| " -//java/com/google:thistarget"); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertNoIssues(); |
| |
| ProjectViewSet projectViewSet = projectViewParser.getResult(); |
| ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile(); |
| assertThat(projectViewFile).isNotNull(); |
| assertThat(projectViewFile.projectViewFile).isEqualTo(new File(".blazeproject")); |
| assertThat(projectViewSet.getProjectViewFiles()).containsExactly(projectViewFile); |
| |
| ProjectView projectView = projectViewFile.projectView; |
| assertThat(projectView.getSectionsOfType(DirectorySection.KEY).get(0).items()) |
| .containsExactly( |
| new DirectoryEntry(new WorkspacePath("java/com/google"), true), |
| new DirectoryEntry(new WorkspacePath("java/com/google/android"), true), |
| new DirectoryEntry(new WorkspacePath("java/com/google/android/notme"), false)); |
| assertThat(projectView.getSectionsOfType(TargetSection.KEY).get(0).items()) |
| .containsExactly( |
| TargetExpression.fromString("//java/com/google:all"), |
| TargetExpression.fromString("//java/com/google/...:all"), |
| TargetExpression.fromString("-//java/com/google:thistarget")); |
| } |
| |
| @Test |
| public void testRootDirectory() throws Exception { |
| projectViewStorageManager.add( |
| ".blazeproject", |
| "directories:", |
| " .", |
| " -java/com/google/android/notme", |
| "", |
| "targets:", |
| " //java/com/google:all"); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertNoIssues(); |
| |
| ProjectViewSet projectViewSet = projectViewParser.getResult(); |
| ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile(); |
| assertThat(projectViewFile).isNotNull(); |
| assertThat(projectViewFile.projectViewFile).isEqualTo(new File(".blazeproject")); |
| assertThat(projectViewSet.getProjectViewFiles()).containsExactly(projectViewFile); |
| |
| ProjectView projectView = projectViewFile.projectView; |
| assertThat(projectView.getSectionsOfType(DirectorySection.KEY).get(0).items()) |
| .containsExactly( |
| new DirectoryEntry(new WorkspacePath(""), true), |
| new DirectoryEntry(new WorkspacePath("java/com/google/android/notme"), false)); |
| assertThat(projectView.getSectionsOfType(TargetSection.KEY).get(0).items()) |
| .containsExactly(TargetExpression.fromString("//java/com/google:all")); |
| |
| String text = ProjectViewParser.projectViewToString(projectView); |
| assertThat(text) |
| .isEqualTo( |
| Joiner.on('\n') |
| .join( |
| "directories:", |
| " .", |
| " -java/com/google/android/notme", |
| "", |
| "targets:", |
| " //java/com/google:all")); |
| } |
| |
| @Test |
| public void testPrint() { |
| ProjectView projectView = |
| ProjectView.builder() |
| .add( |
| ListSection.builder(DirectorySection.KEY) |
| .add(DirectoryEntry.include(new WorkspacePath("java/com/google/one"))) |
| .add(DirectoryEntry.exclude(new WorkspacePath("java/com/google/two")))) |
| .add( |
| ListSection.builder(TargetSection.KEY) |
| .add(TargetExpression.fromString("//java/com/google:one")) |
| .add(TargetExpression.fromString("//java/com/google:two"))) |
| .add( |
| ScalarSection.builder(ImportSection.KEY) |
| .set(new WorkspacePath("some/file.blazeproject"))) |
| .build(); |
| String text = ProjectViewParser.projectViewToString(projectView); |
| assertThat(text) |
| .isEqualTo( |
| Joiner.on('\n') |
| .join( |
| "directories:", |
| " java/com/google/one", |
| " -java/com/google/two", |
| "targets:", |
| " //java/com/google:one", |
| " //java/com/google:two", |
| "import some/file.blazeproject")); |
| } |
| |
| @Test |
| public void testImport() { |
| projectViewStorageManager.add("/parent.blazeproject", "directories:", " parent", ""); |
| projectViewStorageManager.add( |
| ".blazeproject", "import parent.blazeproject", "directories:", " child", ""); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertNoIssues(); |
| |
| ProjectViewSet projectViewSet = projectViewParser.getResult(); |
| assertThat(projectViewSet.getProjectViewFiles()).hasSize(2); |
| Collection<DirectoryEntry> entries = projectViewSet.listItems(DirectorySection.KEY); |
| assertThat(entries) |
| .containsExactly( |
| new DirectoryEntry(new WorkspacePath("parent"), true), |
| new DirectoryEntry(new WorkspacePath("child"), true)); |
| } |
| |
| @Test |
| public void testMultipleImports() { |
| projectViewStorageManager.add("/grandparent.blazeproject", "directories:", " grandparent"); |
| projectViewStorageManager.add( |
| "/mother.blazeproject", "import grandparent.blazeproject", "directories:", " mother"); |
| projectViewStorageManager.add( |
| "/father.blazeproject", "import grandparent.blazeproject", "directories:", " father"); |
| projectViewStorageManager.add( |
| "/child.blazeproject", |
| "import mother.blazeproject", |
| "directories:", |
| " child1", |
| "import father.blazeproject", |
| "directories:", |
| " child2"); |
| projectViewParser.parseProjectView(new File("/child.blazeproject")); |
| errorCollector.assertNoIssues(); |
| |
| ProjectViewSet projectViewSet = projectViewParser.getResult(); |
| |
| // Ensures we don't parse grandfather twice |
| assertThat(projectViewSet.getProjectViewFiles()).hasSize(4); |
| Collection<DirectoryEntry> entries = projectViewSet.listItems(DirectorySection.KEY); |
| |
| // All imports' contributions appear before the children, no matter where they appear |
| assertThat(entries) |
| .containsExactly( |
| new DirectoryEntry(new WorkspacePath("grandparent"), true), |
| new DirectoryEntry(new WorkspacePath("mother"), true), |
| new DirectoryEntry(new WorkspacePath("father"), true), |
| new DirectoryEntry(new WorkspacePath("child1"), true), |
| new DirectoryEntry(new WorkspacePath("child2"), true)) |
| .inOrder(); |
| } |
| |
| @Test |
| public void testMinimumIndentRequired() { |
| projectViewStorageManager.add( |
| ".blazeproject", "directories:", " java/com/google", "java/com/google2", ""); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertIssues("Could not parse: 'java/com/google2'"); |
| } |
| |
| @Test |
| public void testIncorrectIndentationResultsInIssue() { |
| projectViewStorageManager.add( |
| ".blazeproject", "directories:", " java/com/google", " java/com/google2", ""); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertIssues("Invalid indentation on line: 'java/com/google2'"); |
| } |
| |
| @Test |
| public void testCanParseWithMissingCarriageReturnAtEndOfSection() { |
| projectViewStorageManager.add(".blazeproject", "directories:", " java/com/google"); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| ProjectView projectView = |
| projectViewParser.getResult().getTopLevelProjectViewFile().projectView; |
| assertThat(projectView.getSectionsOfType(DirectorySection.KEY).get(0).items()) |
| .containsExactly(new DirectoryEntry(new WorkspacePath("java/com/google"), true)); |
| } |
| |
| @Test |
| public void testImportMissingFileResultsInIssue() { |
| projectViewStorageManager.add(".blazeproject", "import parent.blazeproject"); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertIssues("Could not load project view file: '/parent.blazeproject'"); |
| } |
| |
| @Test |
| public void testMissingSectionResultsInIssue() { |
| projectViewStorageManager.add(".blazeproject", "nosuchsection:", " java/com/google"); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertIssues("Could not parse: 'nosuchsection:'"); |
| } |
| |
| @Test |
| public void testMissingColonResultInIssue() { |
| projectViewStorageManager.add(".blazeproject", "directories", " java/com/google"); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertIssues("Could not parse: 'directories'"); |
| } |
| |
| @Test |
| public void testEmptySectionYieldsError() { |
| projectViewStorageManager.add(".blazeproject", "directories:", ""); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertIssues("Empty section: 'directories'"); |
| } |
| |
| @Test |
| public void testCommentsAreParsed() throws Exception { |
| projectViewStorageManager.add( |
| ".blazeproject", |
| "# comment", |
| "directories:", |
| " # another comment", |
| " java/com/google", |
| " # comment", |
| " java/com/google/android", |
| ""); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertNoIssues(); |
| |
| ProjectViewSet projectViewSet = projectViewParser.getResult(); |
| ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile(); |
| ProjectView projectView = projectViewFile.projectView; |
| assertThat(projectView.getSectionsOfType(TextBlockSection.KEY).get(0).getTextBlock()) |
| .isEqualTo(new TextBlock(ImmutableList.of("# comment"))); |
| assertThat(projectView.getSectionsOfType(DirectorySection.KEY).get(0).items()) |
| .containsExactly( |
| new DirectoryEntry(new WorkspacePath("java/com/google"), true), |
| new DirectoryEntry(new WorkspacePath("java/com/google/android"), true)); |
| } |
| |
| @Test |
| public void testMultipleSections() throws Exception { |
| projectViewStorageManager.add( |
| ".blazeproject", |
| "directories:", |
| " java/com/google", |
| "directories:", |
| " java/com/google2", |
| "", |
| "workspace_type: java", |
| "workspace_type: android"); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertNoIssues(); |
| |
| ProjectViewSet projectViewSet = projectViewParser.getResult(); |
| assertThat(projectViewSet.listItems(DirectorySection.KEY)) |
| .containsExactly( |
| new DirectoryEntry(new WorkspacePath("java/com/google"), true), |
| new DirectoryEntry(new WorkspacePath("java/com/google2"), true)); |
| assertThat(projectViewSet.listScalarItems(WorkspaceTypeSection.KEY)) |
| .containsExactly(WorkspaceType.JAVA, WorkspaceType.ANDROID); |
| } |
| |
| @Test |
| public void testListParserAcceptsWhitespace() throws Exception { |
| String text = |
| Joiner.on('\n') |
| .join( |
| "directories:", |
| " dir0", |
| " ", |
| "", |
| " dir1", |
| " ", |
| " ", |
| "# comment", |
| " dir2", |
| "", |
| " # commented out dir", |
| " ", |
| "# comment", |
| "# comment"); |
| projectViewStorageManager.add(".blazeproject", text); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertNoIssues(); |
| |
| ProjectViewSet projectViewSet = projectViewParser.getResult(); |
| ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile(); |
| assert projectViewFile != null; |
| ProjectView projectView = projectViewFile.projectView; |
| |
| assertThat(projectView) |
| .isEqualTo( |
| ProjectView.builder() |
| .add( |
| ListSection.builder(DirectorySection.KEY) |
| .add(DirectoryEntry.include(new WorkspacePath("dir0"))) |
| .add(TextBlock.of(" ")) |
| .add(TextBlock.of("")) |
| .add(DirectoryEntry.include(new WorkspacePath("dir1"))) |
| .add(TextBlock.of(" ", " ")) |
| .add(TextBlock.of("# comment")) |
| .add(DirectoryEntry.include(new WorkspacePath("dir2"))) |
| .add(TextBlock.of("")) |
| .add(TextBlock.of(" # commented out dir")) |
| .add(TextBlock.of(" "))) |
| .add(TextBlockSection.of(TextBlock.of("# comment", "# comment"))) |
| .build()); |
| |
| String outputString = ProjectViewParser.projectViewToString(projectView); |
| assertThat(outputString).isEqualTo(text); |
| } |
| |
| @Test |
| public void testCommentsAndWhitespacePreserved() throws Exception { |
| String text = |
| Joiner.on('\n') |
| .join( |
| "", |
| "# comment", |
| " ", |
| " ", |
| "directories:", |
| " # another comment", |
| " java/com/google", |
| " # comment", |
| "#unindented comment", |
| " java/com/google/android", |
| "", |
| " # needlessly indented comment", |
| "", |
| "directories:", |
| " java/com/google", |
| " # trailing comment", |
| "directories:", |
| " java/com/google"); |
| projectViewStorageManager.add(".blazeproject", text); |
| projectViewParser.parseProjectView(new File(".blazeproject")); |
| errorCollector.assertNoIssues(); |
| |
| ProjectViewSet projectViewSet = projectViewParser.getResult(); |
| ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile(); |
| ProjectView projectView = projectViewFile.projectView; |
| String outputString = ProjectViewParser.projectViewToString(projectView); |
| assertThat(outputString).isEqualTo(text); |
| } |
| } |