Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add AndroidImportOrganizer to support Android import formatting
Browse files Browse the repository at this point in the history
Supports both android-static-first and android-static-last as the
Android Code Style does not specify how static imports should be
ordered relative to non-static imports.

Refactors the ImportOrganizer interface and existing implementations
to provide a better abstraction of an import and the results of
organizing the imports.

Added tests for BasicImportOrganizer to ensure that behavior did
not change.

RELNOTES: Updated options so order can be selected using:
   -XepPatchImportOrder:android-static-first
   -XepPatchImportOrder:android-static-last

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=155603065
paulduffin authored and ronshapiro committed May 23, 2017
1 parent bb3c426 commit ea720d4
Showing 11 changed files with 701 additions and 89 deletions.
Original file line number Diff line number Diff line change
@@ -32,6 +32,10 @@ public static ImportOrganizer getImportOrganizer(String importOrder) {
return ImportOrganizer.STATIC_FIRST_ORGANIZER;
case "static-last":
return ImportOrganizer.STATIC_LAST_ORGANIZER;
case "android-static-first":
return ImportOrganizer.ANDROID_STATIC_FIRST_ORGANIZER;
case "android-static-last":
return ImportOrganizer.ANDROID_STATIC_LAST_ORGANIZER;
default:
throw new IllegalStateException("Unknown import order: '" + importOrder + "'");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2017 Google Inc. 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.errorprone.apply;

import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Ordering;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
* Organizes imports based on Android Code Style
*
* <p>As the style rules do not specify where static imports are placed this supports first or last.
*
* <p>The imports are partitioned into groups in two steps, each step sub-partitions all groups from
* the previous step. The steps are:
*
* <ol>
* <li>Split into static and non-static, the static imports come before or after the non static
* imports depending on the {@link StaticOrder} specified.
* <li>The groups are then partitioned based on a prefix of the type, the groups are ordered by
* prefix as follows:
* <ol>
* <li>{@code android.}
* <li>{@code com.android.}
* <li>A group for each root package, in alphabetical order.
* <li>{@code java.}
* <li>{@code javax.}
* </ol>
* </ol>
*
* <p>Each group is separate from the previous/next groups with a blank line.
*/
class AndroidImportOrganizer implements ImportOrganizer {

private static final String ANDROID = "android";

private static final String COM_ANDROID = "com.android";

private static final String JAVA = "java";

private static final String JAVAX = "javax";

private static final ImmutableSet<String> SPECIAL_ROOTS =
ImmutableSet.of(ANDROID, COM_ANDROID, JAVA, JAVAX);

private final StaticOrder order;

AndroidImportOrganizer(StaticOrder order) {
this.order = order;
}

@Override
public OrganizedImports organizeImports(List<Import> imports) {
OrganizedImports organized = new OrganizedImports();

// Group into static and non-static.
Map<Boolean, List<Import>> partionedByStatic =
imports.stream().collect(Collectors.partitioningBy(Import::isStatic));

for (Boolean key : order.groupOrder()) {
organizePartition(organized, partionedByStatic.get(key));
}

return organized;
}

private void organizePartition(OrganizedImports organized, List<Import> imports) {

Map<String, ImmutableSortedSet<Import>> groupedByRoot =
imports
.stream()
.collect(
Collectors.groupingBy(
// Group by root package.
AndroidImportOrganizer::rootPackage,
// Ensure that the results are sorted.
TreeMap::new,
// Each group is a set sorted by type.
toImmutableSortedSet(Comparator.comparing(Import::getType))));

// Get the third party roots by removing the roots that are handled specially and sorting.
Set<String> thirdParty =
groupedByRoot
.keySet()
.stream()
.filter(r -> !SPECIAL_ROOTS.contains(r))
.collect(toImmutableSortedSet(Ordering.natural()));

// Construct a list of the possible roots in the correct order.
List<String> roots =
ImmutableList.<String>builder()
.add(ANDROID)
.add(COM_ANDROID)
.addAll(thirdParty)
.add(JAVA)
.add(JAVAX)
.build();

organized.addGroups(groupedByRoot, roots);
}

private static String rootPackage(Import anImport) {
String type = anImport.getType();

if (type.startsWith("com.android.")) {
return "com.android";
}

int index = type.indexOf('.');
if (index == -1) {
// Treat the default package as if it has an empty root.
return "";
} else {
return type.substring(0, index);
}
}
}
Original file line number Diff line number Diff line change
@@ -15,84 +15,39 @@
*/
package com.google.errorprone.apply;

import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
import java.util.ArrayList;
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;

import com.google.common.collect.ImmutableSortedSet;
import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Map;
import java.util.stream.Collectors;

/**
* Sorts imports according to a supplied {@link Comparator} and separates static and non-static with
* a blank line.
* Sorts imports according to a supplied {@link StaticOrder} and separates static and non-static
* with a blank line.
*/
public class BasicImportOrganizer implements ImportOrganizer {

private final Comparator<String> comparator;

BasicImportOrganizer(Comparator<String> comparator) {
this.comparator = comparator;
}

private static boolean isStatic(String importString) {
return importString.startsWith("import static ");
}
class BasicImportOrganizer implements ImportOrganizer {

/**
* A {@link Comparator} that sorts import statements so that all static imports come before all
* non-static imports and otherwise sorted alphabetically.
*/
static Comparator<String> staticFirst() {
return new Ordering<String>() {
@Override
public int compare(String s1, String s2) {
return ComparisonChain.start()
.compareTrueFirst(isStatic(s1), isStatic(s2))
.compare(s1, s2)
.result();
}
};
}
private final StaticOrder order;

/**
* A {@link Comparator} that sorts import statements so that all static imports come after all
* non-static imports and otherwise sorted alphabetically.
*/
static Comparator<String> staticLast() {
return new Ordering<String>() {
@Override
public int compare(String s1, String s2) {
return ComparisonChain.start()
.compareFalseFirst(isStatic(s1), isStatic(s2))
.compare(s1, s2)
.result();
}
};
BasicImportOrganizer(StaticOrder order) {
this.order = order;
}

@Override
public Iterable<String> organizeImports(Iterable<String> importStrings) {
SortedSet<String> sorted = new TreeSet<>(comparator);
Iterables.addAll(sorted, importStrings);

List<String> organized = new ArrayList<>();

// output sorted imports, with a line break between static and non-static imports
boolean first = true;
boolean prevIsStatic = true;
for (String importString : sorted) {
boolean isStatic = isStatic(importString);
if (!first && prevIsStatic != isStatic) {
// Add a blank line.
organized.add("");
}
organized.add(importString);
prevIsStatic = isStatic;
first = false;
}

return organized;
public OrganizedImports organizeImports(List<Import> imports) {

// Group into static and non-static. Each group is a set sorted by type.
Map<Boolean, ImmutableSortedSet<Import>> partionedByStatic =
imports
.stream()
.collect(
Collectors.partitioningBy(
Import::isStatic, toImmutableSortedSet(Comparator.comparing(Import::getType))));

return new OrganizedImports()
// Add groups, in the appropriate order.
.addGroups(partionedByStatic, order.groupOrder());
}
}
Original file line number Diff line number Diff line change
@@ -15,29 +15,174 @@
*/
package com.google.errorprone.apply;

import com.google.auto.value.AutoValue;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/** Organizes import statements when patching files. */
public interface ImportOrganizer {

/**
* Organize the imports supplied, e.g. insert blank lines between various groups.
*
* @param importStrings the imports to organize, the order is undefined. Each string is of the
* format {@code import( static)? <identifier>}.
* @return the list of organized imports, an empty string represents a blank line.
* @param imports the imports to organize, the order is undefined.
* @return the list of organized imports.
*/
Iterable<String> organizeImports(Iterable<String> importStrings);
OrganizedImports organizeImports(List<Import> imports);

/**
* An {@link ImportOrganizer} that sorts import statements according to the Google Java Style
* Guide, i.e. static first, static and non-static separated by blank line.
*/
ImportOrganizer STATIC_FIRST_ORGANIZER =
new BasicImportOrganizer(BasicImportOrganizer.staticFirst());
ImportOrganizer STATIC_FIRST_ORGANIZER = new BasicImportOrganizer(StaticOrder.STATIC_FIRST);

/**
* An {@link ImportOrganizer} that sorts import statements so that non-static imports come first,
* and static and non-static separated by blank line.
*/
ImportOrganizer STATIC_LAST_ORGANIZER =
new BasicImportOrganizer(BasicImportOrganizer.staticLast());
ImportOrganizer STATIC_LAST_ORGANIZER = new BasicImportOrganizer(StaticOrder.STATIC_LAST);

/**
* An {@link ImportOrganizer} that sorts import statements according to Android Code Style, with
* static imports first.
*
* <p>The imports are partitioned into groups in two steps, each step sub-partitions all groups
* from the previous step. The steps are:
*
* <ol>
* <li>Split into static and non-static, the static imports come before the non static imports.
* <li>The groups are then partitioned based on a prefix of the type, the groups are ordered by
* prefix as follows:
* <ol>
* <li>{@code android.}
* <li>{@code com.android.}
* <li>A group for each root package, in alphabetical order.
* <li>{@code java.}
* <li>{@code javax.}
* </ol>
* </ol>
*/
ImportOrganizer ANDROID_STATIC_FIRST_ORGANIZER =
new AndroidImportOrganizer(StaticOrder.STATIC_FIRST);

/**
* An {@link ImportOrganizer} that sorts import statements according to Android Code Style, with
* static imports last.
*
* <p>The imports are partitioned into groups in two steps, each step sub-partitions all groups
* from the previous step. The steps are:
*
* <ol>
* <li>Split into static and non-static, the static imports come after the non static imports.
* <li>The groups are then partitioned based on a prefix of the type, the groups are ordered by
* prefix as follows:
* <ol>
* <li>{@code android.}
* <li>{@code com.android.}
* <li>A group for each root package, in alphabetical order.
* <li>{@code java.}
* <li>{@code javax.}
* </ol>
* </ol>
*/
ImportOrganizer ANDROID_STATIC_LAST_ORGANIZER =
new AndroidImportOrganizer(StaticOrder.STATIC_LAST);

/** Represents an import. */
@AutoValue
abstract class Import {
/** True if the import is static, false otherwise. */
public abstract boolean isStatic();

/** Return the type to import. */
public abstract String getType();

/**
* Create an {@link Import}
*
* @param importString in the format {@code import( static)? <type>}.
* @return the newly created {@link Import}
*/
static Import importOf(String importString) {
boolean isStatic = (importString.startsWith("import static "));
String type =
isStatic
? importString.substring("import static ".length())
: importString.substring("import ".length());
return new AutoValue_ImportOrganizer_Import(isStatic, type);
}

@Override
public String toString() {
return String.format("import%s %s", isStatic() ? " static" : "", getType());
}
}

/**
* Provides support for building a list of imports from groups and formatting it as a block of
* imports.
*/
class OrganizedImports {

private final StringBuilder importBlock = new StringBuilder();

private int importCount;

/**
* Add a group of already sorted imports.
*
* <p>If there are any other imports in the list then this will add a newline separator before
* this group is added.
*
* @param imports the imports in the group.
*/
private void addGroup(Collection<Import> imports) {
if (imports.isEmpty()) {
return;
}

if (importBlock.length() != 0) {
importBlock.append('\n');
}

importCount += imports.size();
imports.forEach(i -> importBlock.append(i).append(";\n"));
}

/**
* Get the organized imports as a block of imports, with blank links between the separate
* groups.
*/
public String asImportBlock() {
return importBlock.toString();
}

/**
* Add groups of already sorted imports.
*
* <p>If there are any other imports in the list then this will add a newline separator before
* any groups are added. It will also add a newline separate between each group.
*
* @param groups the imports in the group.
* @param keys the keys to add, in order, if a key is not in the groups then it is ignored.
* @return this for chaining.
*/
public <K> OrganizedImports addGroups(
Map<K, ? extends Collection<Import>> groups, Iterable<K> keys) {
for (K key : keys) {
Collection<Import> imports = groups.get(key);
if (imports != null) {
addGroup(imports);
}
}

return this;
}

/** The number of imports added, excludes blank lines. */
int getImportCount() {
return importCount;
}
}
}
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
* Represents a list of import statements. Supports adding and removing import statements and pretty
@@ -106,16 +107,12 @@ public String apply(JCImport input) {
}));
}

/**
* Return the start position of the import statements.
*/
/** Return the start position of the import statements. */
public int getStartPos() {
return startPos;
}

/**
* Return the end position of the import statements.
*/
/** Return the end position of the import statements. */
public int getEndPos() {
return endPos;
}
@@ -178,14 +175,25 @@ public String toString() {
result.append('\n');
}

// output organized imports
for (String importString : importOrganizer.organizeImports(importStrings)) {
if (!importString.isEmpty()) {
result.append(importString).append(';');
}
result.append('\n');
List<ImportOrganizer.Import> imports =
importStrings.stream().map(ImportOrganizer.Import::importOf).collect(Collectors.toList());

// Organize the imports.
ImportOrganizer.OrganizedImports organizedImports = importOrganizer.organizeImports(imports);

// Make sure that every import was organized.
int expectedImportCount = imports.size();
int importCount = organizedImports.getImportCount();
if (importCount != expectedImportCount) {
throw new IllegalStateException(
String.format(
"Expected %d import(s) in the organized imports but it contained %d",
expectedImportCount, importCount));
}

// output organized imports
result.append(organizedImports.asImportBlock());

String replacementString = result.toString();
if (!hasExistingImports) {
return replacementString;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2017 Google Inc. 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.errorprone.apply;

import com.google.common.collect.ImmutableList;

/** The different ways to order static imports. */
enum StaticOrder {
/**
* Sorts import statements so that all static imports come before all non-static imports and
* otherwise sorted alphabetically.
*/
STATIC_FIRST(ImmutableList.of(Boolean.TRUE, Boolean.FALSE)),

/**
* Sorts import statements so that all static imports come after all non-static imports and
* otherwise sorted alphabetically.
*/
STATIC_LAST(ImmutableList.of(Boolean.FALSE, Boolean.TRUE));

private final Iterable<Boolean> groupOrder;

StaticOrder(Iterable<Boolean> groupOrder) {
this.groupOrder = groupOrder;
}

public Iterable<Boolean> groupOrder() {
return groupOrder;
}
}
Original file line number Diff line number Diff line change
@@ -194,4 +194,20 @@ public void importOrder_staticLast() {
assertThat(options.patchingOptions().importOrganizer())
.isSameAs(ImportOrganizer.STATIC_LAST_ORGANIZER);
}

@Test
public void importOrder_androidStaticFirst() {
ErrorProneOptions options =
ErrorProneOptions.processArgs(new String[] {"-XepPatchImportOrder:android-static-first"});
assertThat(options.patchingOptions().importOrganizer())
.isSameAs(ImportOrganizer.ANDROID_STATIC_FIRST_ORGANIZER);
}

@Test
public void importOrder_androidStaticLast() {
ErrorProneOptions options =
ErrorProneOptions.processArgs(new String[] {"-XepPatchImportOrder:android-static-last"});
assertThat(options.patchingOptions().importOrganizer())
.isSameAs(ImportOrganizer.ANDROID_STATIC_LAST_ORGANIZER);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright 2017 Google Inc. 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.errorprone.apply;

import static org.junit.Assert.assertEquals;

import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Unit tests for {@link AndroidImportOrganizer} */
@RunWith(JUnit4.class)
public class AndroidImportOrganizerTest {

private static final List<ImportOrganizer.Import> IMPORTS =
ImmutableList.of(
"import com.android.blah",
"import android.foo",
"import java.ping",
"import javax.pong",
"import unknown.fred",
"import unknown.barney",
"import net.wilma",
"import static com.android.blah.blah",
"import static android.foo.bar",
"import static java.ping.pong",
"import static javax.pong.ping",
"import static unknown.fred.flintstone",
"import static net.wilma.flintstone")
.stream()
.map(ImportOrganizer.Import::importOf)
.collect(Collectors.toList());

@Test
public void testStaticFirstOrdering() {
AndroidImportOrganizer organizer = new AndroidImportOrganizer(StaticOrder.STATIC_FIRST);
ImportOrganizer.OrganizedImports organized = organizer.organizeImports(IMPORTS);
assertEquals(
"import static android.foo.bar;\n"
+ "\n"
+ "import static com.android.blah.blah;\n"
+ "\n"
+ "import static net.wilma.flintstone;\n"
+ "\n"
+ "import static unknown.fred.flintstone;\n"
+ "\n"
+ "import static java.ping.pong;\n"
+ "\n"
+ "import static javax.pong.ping;\n"
+ "\n"
+ "import android.foo;\n"
+ "\n"
+ "import com.android.blah;\n"
+ "\n"
+ "import net.wilma;\n"
+ "\n"
+ "import unknown.barney;\n"
+ "import unknown.fred;\n"
+ "\n"
+ "import java.ping;\n"
+ "\n"
+ "import javax.pong;\n",
organized.asImportBlock());
}

@Test
public void testStaticLastOrdering() {
AndroidImportOrganizer organizer = new AndroidImportOrganizer(StaticOrder.STATIC_LAST);
ImportOrganizer.OrganizedImports organized = organizer.organizeImports(IMPORTS);
assertEquals(
"import android.foo;\n"
+ "\n"
+ "import com.android.blah;\n"
+ "\n"
+ "import net.wilma;\n"
+ "\n"
+ "import unknown.barney;\n"
+ "import unknown.fred;\n"
+ "\n"
+ "import java.ping;\n"
+ "\n"
+ "import javax.pong;\n"
+ "\n"
+ "import static android.foo.bar;\n"
+ "\n"
+ "import static com.android.blah.blah;\n"
+ "\n"
+ "import static net.wilma.flintstone;\n"
+ "\n"
+ "import static unknown.fred.flintstone;\n"
+ "\n"
+ "import static java.ping.pong;\n"
+ "\n"
+ "import static javax.pong.ping;\n",
organized.asImportBlock());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright 2017 Google Inc. 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.errorprone.apply;

import static org.junit.Assert.assertEquals;

import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Unit tests for {@link BasicImportOrganizer} */
@RunWith(JUnit4.class)
public class BasicImportOrganizerTest {

private static final List<ImportOrganizer.Import> IMPORTS =
ImmutableList.of(
"import com.android.blah",
"import android.foo",
"import java.ping",
"import javax.pong",
"import unknown.fred",
"import unknown.barney",
"import net.wilma",
"import static com.android.blah.blah",
"import static android.foo.bar",
"import static java.ping.pong",
"import static javax.pong.ping",
"import static unknown.fred.flintstone",
"import static net.wilma.flintstone")
.stream()
.map(ImportOrganizer.Import::importOf)
.collect(Collectors.toList());

@Test
public void testStaticFirstOrdering() {
BasicImportOrganizer organizer = new BasicImportOrganizer(StaticOrder.STATIC_FIRST);
ImportOrganizer.OrganizedImports organized = organizer.organizeImports(IMPORTS);
assertEquals(
"import static android.foo.bar;\n"
+ "import static com.android.blah.blah;\n"
+ "import static java.ping.pong;\n"
+ "import static javax.pong.ping;\n"
+ "import static net.wilma.flintstone;\n"
+ "import static unknown.fred.flintstone;\n"
+ "\n"
+ "import android.foo;\n"
+ "import com.android.blah;\n"
+ "import java.ping;\n"
+ "import javax.pong;\n"
+ "import net.wilma;\n"
+ "import unknown.barney;\n"
+ "import unknown.fred;\n",
organized.asImportBlock());
}

@Test
public void testStaticLastOrdering() {
BasicImportOrganizer organizer = new BasicImportOrganizer(StaticOrder.STATIC_LAST);
ImportOrganizer.OrganizedImports organized = organizer.organizeImports(IMPORTS);
assertEquals(
"import android.foo;\n"
+ "import com.android.blah;\n"
+ "import java.ping;\n"
+ "import javax.pong;\n"
+ "import net.wilma;\n"
+ "import unknown.barney;\n"
+ "import unknown.fred;\n"
+ "\n"
+ "import static android.foo.bar;\n"
+ "import static com.android.blah.blah;\n"
+ "import static java.ping.pong;\n"
+ "import static javax.pong.ping;\n"
+ "import static net.wilma.flintstone;\n"
+ "import static unknown.fred.flintstone;\n",
organized.asImportBlock());
}
}
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.expectThrows;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -434,4 +435,24 @@ public void addingToEmptyImportListInDefaultPackage() {
assertEquals(0, imports.getStartPos());
assertEquals("\nimport java.util.List;\n", imports.toString());
}

@Test
public void addsAllImports() {
ImportStatements imports =
new ImportStatements(
null,
new ArrayList<>(),
FAKE_END_POS_MAP,
new ImportOrganizer() {
@Override
public OrganizedImports organizeImports(List<Import> imports) {
return new OrganizedImports();
}
});

imports.add("import java.util.List");
IllegalStateException exception = expectThrows(IllegalStateException.class, imports::toString);
assertEquals(
"Expected 1 import(s) in the organized imports but it contained 0", exception.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2017 Google Inc. 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.errorprone.apply;

import static org.junit.Assert.assertEquals;

import com.google.common.collect.ImmutableSortedSet;
import com.google.errorprone.apply.ImportOrganizer.Import;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** */
@RunWith(JUnit4.class)
public class OrganizedImportsTest {

private static final Comparator<Import> IMPORT_COMPARATOR =
Comparator.comparing(Import::isStatic).thenComparing(Import::getType);

@Test
public void emptyList() {
ImportOrganizer.OrganizedImports organizedImports = new ImportOrganizer.OrganizedImports();
assertEquals("", organizedImports.asImportBlock());
}

private ImmutableSortedSet<Import> buildSortedImportSet(Import... element) {
return ImmutableSortedSet.orderedBy(IMPORT_COMPARATOR).add(element).build();
}

@Test
public void singleGroup() {
Map<String, Set<Import>> groups = new TreeMap<>();
groups.put("first", buildSortedImportSet(Import.importOf("import first")));
ImportOrganizer.OrganizedImports organizedImports =
new ImportOrganizer.OrganizedImports().addGroups(groups, groups.keySet());
assertEquals("import first;\n", organizedImports.asImportBlock());
}

@Test
public void multipleGroups() {
Map<String, Set<Import>> groups = new TreeMap<>();
groups.put("first", buildSortedImportSet(Import.importOf("import first")));
groups.put("second", buildSortedImportSet(Import.importOf("import second")));
ImportOrganizer.OrganizedImports organizedImports =
new ImportOrganizer.OrganizedImports().addGroups(groups, groups.keySet());
assertEquals("import first;\n\nimport second;\n", organizedImports.asImportBlock());
}

@Test
public void importCount() {
Map<String, Set<Import>> groups = new TreeMap<>();
groups.put("first", buildSortedImportSet(Import.importOf("import first")));
groups.put("second", buildSortedImportSet(Import.importOf("import second")));
ImportOrganizer.OrganizedImports organizedImports =
new ImportOrganizer.OrganizedImports().addGroups(groups, groups.keySet());
assertEquals(2, organizedImports.getImportCount());
}
}

0 comments on commit ea720d4

Please sign in to comment.