/*
* Copyright 2017-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.js;
import static org.hamcrest.Matchers.everyItem;
import static org.hamcrest.Matchers.in;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetFactory;
import com.facebook.buck.model.Flavor;
import com.facebook.buck.parser.NoSuchBuildTargetException;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.util.RichStream;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
public class JsBundleDescriptionTest {
private static final BuildTarget directDependencyTarget =
BuildTargetFactory.newInstance("//libs:direct");
private static final BuildTarget level2 = BuildTargetFactory.newInstance("//libs:level2");
private static final BuildTarget level1_1 = BuildTargetFactory.newInstance("//libs:level1.1");
private static final BuildTarget level1_2 = BuildTargetFactory.newInstance("//libs:level1.2");
private final BuildTarget bundleTarget = BuildTargetFactory.newInstance("//bundle:target");
private JsTestScenario.Builder scenarioBuilder;
private JsTestScenario scenario;
static Collection<BuildTarget> allLibaryTargets(Flavor... flavors) {
return Stream.of(level2, level1_1, level1_2, directDependencyTarget)
.map(t -> t.withAppendedFlavors(flavors))
.collect(Collectors.toList());
}
@Before
public void setUp() throws NoSuchBuildTargetException {
scenarioBuilder = JsTestScenario.builder();
scenarioBuilder
.library(level2)
.library(level1_1, level2)
.library(level1_2, level2)
.library(directDependencyTarget, level1_1, level1_2)
.bundleWithDeps(bundleTarget, directDependencyTarget);
scenario = scenarioBuilder.build();
}
@Test
public void testTransitiveLibraryDependencies() throws NoSuchBuildTargetException {
BuildRule jsBundle = scenario.resolver.requireRule(bundleTarget);
assertThat(allLibaryTargets(), everyItem(in(dependencyTargets(jsBundle))));
}
@Test
public void testTransitiveLibraryDependenciesWithFlavors() throws NoSuchBuildTargetException {
final Flavor[] flavors = {JsFlavors.IOS, JsFlavors.RELEASE};
BuildRule jsBundle = scenario.resolver.requireRule(bundleTarget.withFlavors(flavors));
assertThat(allLibaryTargets(flavors), everyItem(in(dependencyTargets(jsBundle))));
}
@Test
public void testFlavoredBundleDoesNotDependOnUnflavoredLibs() throws NoSuchBuildTargetException {
BuildRule jsBundle =
scenario.resolver.requireRule(bundleTarget.withFlavors(JsFlavors.IOS, JsFlavors.RELEASE));
assertThat(allLibaryTargets(), everyItem(not(in(dependencyTargets(jsBundle)))));
}
@Test
public void testFlavoredBundleWithoutReleaseFlavorDependOnFlavoredLibs()
throws NoSuchBuildTargetException {
Flavor[] flavors = {JsFlavors.IOS, JsFlavors.RAM_BUNDLE_INDEXED};
BuildRule jsBundle = scenario.resolver.requireRule((bundleTarget.withFlavors(flavors)));
assertThat(allLibaryTargets(JsFlavors.IOS), everyItem(in(dependencyTargets(jsBundle))));
assertThat(allLibaryTargets(flavors), everyItem(not(in(dependencyTargets(jsBundle)))));
}
@Test
public void testFlavoredReleaseBundleDoesNotPropagateRamBundleFlavors()
throws NoSuchBuildTargetException {
Flavor[] bundleFlavors = {JsFlavors.IOS, JsFlavors.RAM_BUNDLE_INDEXED, JsFlavors.RELEASE};
Flavor[] flavorsToBePropagated = {JsFlavors.IOS, JsFlavors.RELEASE};
BuildRule jsBundle = scenario.resolver.requireRule((bundleTarget.withFlavors(bundleFlavors)));
assertThat(allLibaryTargets(flavorsToBePropagated), everyItem(in(dependencyTargets(jsBundle))));
assertThat(allLibaryTargets(bundleFlavors), everyItem(not(in(dependencyTargets(jsBundle)))));
}
@Test
public void testFlavoredReleaseBundleDoesNotPropagateRamBundleFlavorsAndroid()
throws NoSuchBuildTargetException {
Flavor[] bundleFlavors = {JsFlavors.ANDROID, JsFlavors.RAM_BUNDLE_INDEXED, JsFlavors.RELEASE};
Flavor[] flavorsToBePropagated = {JsFlavors.ANDROID, JsFlavors.RELEASE};
BuildRule jsBundle = scenario.resolver.requireRule((bundleTarget.withFlavors(bundleFlavors)));
assertThat(allLibaryTargets(flavorsToBePropagated), everyItem(in(dependencyTargets(jsBundle))));
assertThat(allLibaryTargets(bundleFlavors), everyItem(not(in(dependencyTargets(jsBundle)))));
}
@Test
public void testTransitiveLibraryDependenciesWithFlavorsForAndroid()
throws NoSuchBuildTargetException {
final Flavor[] flavors = {JsFlavors.ANDROID, JsFlavors.RELEASE};
BuildRule jsBundle = scenario.resolver.requireRule(bundleTarget.withFlavors(flavors));
assertThat(allLibaryTargets(flavors), everyItem(in(dependencyTargets(jsBundle))));
}
@Test
public void testJsLibraryInDeps() throws NoSuchBuildTargetException {
final BuildTarget bundleTarget = BuildTargetFactory.newInstance("//the:bundle");
final JsTestScenario testScenario =
JsTestScenario.builder(scenario)
.bundleWithDeps(bundleTarget, directDependencyTarget)
.build();
BuildRule jsBundle = testScenario.resolver.requireRule(bundleTarget);
assertThat(allLibaryTargets(), everyItem(in(dependencyTargets(jsBundle))));
}
@Test
public void testTransitiveDependenciesAcrossSubGraph() throws NoSuchBuildTargetException {
final BuildTarget firstLevelA = BuildTargetFactory.newInstance("//:firstA");
final BuildTarget firstLevelB = BuildTargetFactory.newInstance("//:firstB");
final BuildTarget secondLevelA = BuildTargetFactory.newInstance("//:secondA");
final BuildTarget secondLevelB = BuildTargetFactory.newInstance("//:secondB");
final BuildTarget bundleTarget = BuildTargetFactory.newInstance("//the:bundle");
final JsTestScenario.Builder builder = JsTestScenario.builder(scenario);
final JsTestScenario testScenario =
builder
.appleLibraryWithDeps(firstLevelA, level1_1)
.library(secondLevelA)
.appleLibraryWithDeps(secondLevelB, level1_2, secondLevelA)
.appleLibraryWithDeps(firstLevelB, secondLevelB)
.bundleWithDeps(bundleTarget, firstLevelA, firstLevelB)
.build();
final Flavor[] flavors = {JsFlavors.IOS, JsFlavors.RELEASE};
final BuildRule jsBundle = testScenario.resolver.requireRule(bundleTarget.withFlavors(flavors));
final List<BuildTarget> expectedLibDeps =
Stream.of(level1_1, level1_2, level2, secondLevelA)
.map(t -> t.withAppendedFlavors(flavors))
.collect(Collectors.toList());
assertThat(expectedLibDeps, everyItem(in(dependencyTargets(jsBundle))));
}
private static Collection<BuildTarget> dependencyTargets(BuildRule rule) {
if (rule instanceof JsBundleAndroid) {
final JsBundle jsBundle =
RichStream.from(rule.getBuildDeps()).filter(JsBundle.class).findFirst().get();
return dependencyTargets(jsBundle);
} else {
return rule.getBuildDeps()
.stream()
.map(BuildRule::getBuildTarget)
.collect(Collectors.toSet());
}
}
}