/*
* Copyright 2013-present Facebook, Inc.
*
* 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.facebook.buck.android;
import static com.facebook.buck.util.Verbosity.COMMANDS_AND_SPECIAL_OUTPUT;
import static org.junit.Assert.assertTrue;
import com.facebook.buck.android.DxStep.Option;
import com.facebook.buck.cli.VerbosityParser;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.step.ExecutionContext;
import com.facebook.buck.step.TestExecutionContext;
import com.facebook.buck.testutil.FakeProjectFilesystem;
import com.facebook.buck.testutil.MoreAsserts;
import com.facebook.buck.testutil.TestConsole;
import com.facebook.buck.util.Verbosity;
import com.google.common.base.Joiner;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.EnumSet;
import java.util.Optional;
import org.easymock.EasyMock;
import org.easymock.EasyMockSupport;
import org.junit.Before;
import org.junit.Test;
public class DxStepTest extends EasyMockSupport {
private static final String BASE_DX_PREFIX = Paths.get("/usr/bin/dx").toString();
private static final String EXPECTED_DX_PREFIX = Paths.get("/usr/bin/dx") + " --dex";
private static final Path SAMPLE_OUTPUT_PATH =
Paths.get(".").toAbsolutePath().normalize().resolve("buck-out/gen/classes.dex");
private static final ImmutableSet<Path> SAMPLE_FILES_TO_DEX =
ImmutableSet.of(Paths.get("buck-out/gen/foo.dex.jar"), Paths.get("buck-out/gen/bar.dex.jar"));
private AndroidPlatformTarget androidPlatformTarget;
@Before
public void setUp() {
androidPlatformTarget = createMock(AndroidPlatformTarget.class);
EasyMock.expect(androidPlatformTarget.getDxExecutable()).andReturn(Paths.get("/usr/bin/dx"));
replayAll();
}
@Test
public void testDxCommandNoOptimizeNoJumbo() throws InterruptedException, IOException {
// Context with --verbose 2.
try (ExecutionContext context = createExecutionContext(2)) {
ProjectFilesystem filesystem = FakeProjectFilesystem.createJavaOnlyFilesystem();
DxStep dx =
new DxStep(
filesystem, SAMPLE_OUTPUT_PATH, SAMPLE_FILES_TO_DEX, EnumSet.of(Option.NO_OPTIMIZE));
String expected =
String.format(
"%s --no-optimize --output %s %s",
EXPECTED_DX_PREFIX,
SAMPLE_OUTPUT_PATH,
Joiner.on(' ').join(Iterables.transform(SAMPLE_FILES_TO_DEX, filesystem::resolve)));
MoreAsserts.assertShellCommands(
"--no-optimize should be present, but --force-jumbo should not.",
ImmutableList.of(expected),
ImmutableList.of(dx),
context);
verifyAll();
}
}
@Test
public void testDxCommandOptimizeNoJumbo() throws InterruptedException, IOException {
// Context with --verbose 2.
try (ExecutionContext context = createExecutionContext(2)) {
ProjectFilesystem filesystem = FakeProjectFilesystem.createJavaOnlyFilesystem();
DxStep dx = new DxStep(filesystem, SAMPLE_OUTPUT_PATH, SAMPLE_FILES_TO_DEX);
String expected =
String.format(
"%s --output %s %s",
EXPECTED_DX_PREFIX,
SAMPLE_OUTPUT_PATH,
Joiner.on(' ').join(Iterables.transform(SAMPLE_FILES_TO_DEX, filesystem::resolve)));
MoreAsserts.assertShellCommands(
"Neither --no-optimize nor --force-jumbo should be present.",
ImmutableList.of(expected),
ImmutableList.of(dx),
context);
verifyAll();
}
}
@Test
public void testDxCommandNoOptimizeForceJumbo() throws InterruptedException, IOException {
// Context with --verbose 2.
try (ExecutionContext context = createExecutionContext(2)) {
ProjectFilesystem filesystem = FakeProjectFilesystem.createJavaOnlyFilesystem();
DxStep dx =
new DxStep(
filesystem,
SAMPLE_OUTPUT_PATH,
SAMPLE_FILES_TO_DEX,
EnumSet.of(DxStep.Option.NO_OPTIMIZE, DxStep.Option.FORCE_JUMBO));
String expected =
String.format(
"%s --no-optimize --force-jumbo --output %s %s",
EXPECTED_DX_PREFIX,
SAMPLE_OUTPUT_PATH,
Joiner.on(' ').join(Iterables.transform(SAMPLE_FILES_TO_DEX, filesystem::resolve)));
MoreAsserts.assertShellCommands(
"Both --no-optimize and --force-jumbo should be present.",
ImmutableList.of(expected),
ImmutableList.of(dx),
context);
verifyAll();
}
}
@Test
public void testVerbose3AddsStatisticsFlag() throws InterruptedException, IOException {
// Context with --verbose 3.
try (ExecutionContext context = createExecutionContext(COMMANDS_AND_SPECIAL_OUTPUT.ordinal())) {
ProjectFilesystem filesystem = FakeProjectFilesystem.createJavaOnlyFilesystem();
DxStep dx = new DxStep(filesystem, SAMPLE_OUTPUT_PATH, SAMPLE_FILES_TO_DEX);
String expected =
String.format(
"%s --statistics --output %s %s",
EXPECTED_DX_PREFIX,
SAMPLE_OUTPUT_PATH,
Joiner.on(' ').join(Iterables.transform(SAMPLE_FILES_TO_DEX, filesystem::resolve)));
MoreAsserts.assertShellCommands(
"Ensure that the --statistics flag is present.",
ImmutableList.of(expected),
ImmutableList.of(dx),
context);
assertTrue(
"Should print stdout to show statistics.", dx.shouldPrintStdout(context.getVerbosity()));
assertTrue(
"Should print stderr to show statistics.", dx.shouldPrintStderr(context.getVerbosity()));
verifyAll();
}
}
@Test
public void testVerbose10AddsVerboseFlagToDx() throws InterruptedException, IOException {
// Context with --verbose 10.
try (ExecutionContext context = createExecutionContext(10)) {
ProjectFilesystem filesystem = FakeProjectFilesystem.createJavaOnlyFilesystem();
DxStep dx = new DxStep(filesystem, SAMPLE_OUTPUT_PATH, SAMPLE_FILES_TO_DEX);
String expected =
String.format(
"%s --statistics --verbose --output %s %s",
EXPECTED_DX_PREFIX,
SAMPLE_OUTPUT_PATH,
Joiner.on(' ').join(Iterables.transform(SAMPLE_FILES_TO_DEX, filesystem::resolve)));
MoreAsserts.assertShellCommands(
"Ensure that the --statistics flag is present.",
ImmutableList.of(expected),
ImmutableList.of(dx),
context);
assertTrue(
"Should print stdout since `dx --verbose` is enabled.",
dx.shouldPrintStdout(context.getVerbosity()));
assertTrue(
"Should print stdout since `dx --verbose` is enabled.",
dx.shouldPrintStderr(context.getVerbosity()));
verifyAll();
}
}
@Test
public void testOverridenMaxHeapSize() throws InterruptedException, IOException {
try (ExecutionContext context = createExecutionContext(2)) {
ProjectFilesystem filesystem = FakeProjectFilesystem.createJavaOnlyFilesystem();
DxStep dx =
new DxStep(
filesystem,
SAMPLE_OUTPUT_PATH,
SAMPLE_FILES_TO_DEX,
EnumSet.noneOf(DxStep.Option.class),
Optional.of("2g"));
String expected =
String.format(
"%s -JXmx2g --dex --output %s %s",
BASE_DX_PREFIX,
SAMPLE_OUTPUT_PATH,
Joiner.on(' ').join(Iterables.transform(SAMPLE_FILES_TO_DEX, filesystem::resolve)));
MoreAsserts.assertShellCommands(
"Ensure that the -JXmx flag is present.",
ImmutableList.of(expected),
ImmutableList.of(dx),
context);
verifyAll();
}
}
private ExecutionContext createExecutionContext(int verbosityLevel) throws IOException {
Verbosity verbosity = VerbosityParser.getVerbosityForLevel(verbosityLevel);
TestConsole console = new TestConsole(verbosity);
return TestExecutionContext.newBuilder()
.setConsole(console)
.setAndroidPlatformTargetSupplier(Suppliers.ofInstance(androidPlatformTarget))
.build();
}
}