/*
* 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.rules;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetPattern;
import com.facebook.buck.rules.coercer.CoercedTypeCache;
import com.facebook.buck.rules.coercer.DefaultTypeCoercerFactory;
import com.facebook.buck.util.HumanReadableException;
import com.facebook.buck.util.immutables.BuckStyleImmutable;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.immutables.value.Value;
import org.junit.Before;
import org.junit.Test;
public class BuckPyFunctionTest {
private BuckPyFunction buckPyFunction;
@Before
public void setUpMarshaller() {
buckPyFunction = new BuckPyFunction(new DefaultTypeCoercerFactory(), CoercedTypeCache.INSTANCE);
}
@BuckStyleImmutable
@Value.Immutable
abstract static class AbstractNoName {
abstract String getRandom();
}
@Test
public void nameWillBeAddedIfMissing() {
String definition = buckPyFunction.toPythonFunction(BuildRuleType.of("bad"), NoName.class);
assertTrue(definition.contains("name"));
}
@BuckStyleImmutable
@Value.Immutable
abstract static class AbstractNoVis {
abstract String getRandom();
}
@Test
public void visibilityWillBeAddedIfMissing() {
String definition = buckPyFunction.toPythonFunction(BuildRuleType.of("bad"), NoVis.class);
assertTrue(definition.contains("visibility=None"));
}
@BuckStyleImmutable
@Value.Immutable
abstract static class AbstractNamed {
abstract String getName();
}
@Test
public void shouldOnlyIncludeTheNameFieldOnce() {
String definition = buckPyFunction.toPythonFunction(BuildRuleType.of("named"), Named.class);
assertEquals(
Joiner.on("\n")
.join(
"@provide_for_build",
"def named(name, visibility=None, within_view=None, build_env=None):",
" add_rule({",
" 'buck.type': 'named',",
" 'name': name,",
" 'visibility': visibility,",
" 'within_view': within_view,",
" }, build_env)",
"",
""),
definition);
}
public static class BadName extends AbstractDescriptionArg {
public int name;
}
@Test(expected = HumanReadableException.class)
public void theNameFieldMustBeAString() {
buckPyFunction.toPythonFunction(BuildRuleType.of("nope"), BadName.class);
}
@BuckStyleImmutable
@Value.Immutable
abstract static class AbstractLotsOfOptions {
abstract Optional<String> getThing();
abstract Optional<List<BuildTarget>> getTargets();
@Value.Default
List<String> getStrings() {
return ImmutableList.of("123");
}
abstract Optional<Integer> getVersion();
abstract Optional<Boolean> isDoStuff();
@Value.Default
boolean isDoSomething() {
return true;
}
}
@Test
public void optionalFieldsDefaultToAbsent() {
String definition =
buckPyFunction.toPythonFunction(BuildRuleType.of("optional"), LotsOfOptions.class);
assertTrue(
definition,
definition.contains(
"do_something=None, do_stuff=None, strings=None, targets=None, "
+ "thing=None, version=None"));
}
@BuckStyleImmutable
@Value.Immutable
abstract static class AbstractEither {
// Alphabetical ordering is deliberate.
abstract Optional<String> getCat();
abstract String getDog();
@Value.Default
String getEgg() {
return "EGG";
}
abstract String getFake();
}
@Test
public void optionalFieldsAreListedAfterMandatoryOnes() {
String definition = buckPyFunction.toPythonFunction(BuildRuleType.of("either"), Either.class);
assertEquals(
Joiner.on("\n")
.join(
"@provide_for_build",
"def either(name, dog, fake, cat=None, egg=None, "
+ "visibility=None, within_view=None, build_env=None):",
" add_rule({",
" 'buck.type': 'either',",
" 'name': name,",
" 'dog': dog,",
" 'fake': fake,",
" 'cat': cat,",
" 'egg': egg,",
" 'visibility': visibility,",
" 'within_view': within_view,",
" }, build_env)",
"",
""),
definition);
}
@BuckStyleImmutable
@Value.Immutable
abstract static class AbstractVisible {
abstract Set<BuildTargetPattern> getVisibility();
}
@Test(expected = HumanReadableException.class)
public void visibilityOptionsMustNotBeSetAsTheyArePassedInBuildRuleParamsLater() {
buckPyFunction.toPythonFunction(BuildRuleType.of("nope"), Visible.class);
}
@BuckStyleImmutable
@Value.Immutable
abstract static class AbstractDto {
abstract String getSomeField();
}
@Test
public void shouldConvertCamelCaseFieldNameToSnakeCaseParameter() {
String definition = buckPyFunction.toPythonFunction(BuildRuleType.of("case"), Dto.class);
assertEquals(
Joiner.on("\n")
.join(
"@provide_for_build",
"def case(name, some_field, "
+ "visibility=None, within_view=None, build_env=None):",
" add_rule({",
" 'buck.type': 'case',",
" 'name': name,",
" 'someField': some_field,",
" 'visibility': visibility,",
" 'within_view': within_view,",
" }, build_env)",
"",
""),
definition);
}
}