blob: 3961fb5fe272a13d19809d698a2fec3377247881 [file] [log] [blame]
// Copyright 2019 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.devtools.build.lib.rules.python;
import static com.google.common.truth.Truth.assertThat;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.skylark.util.SkylarkTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link PyInfo}. */
@RunWith(JUnit4.class)
public class PyInfoTest extends SkylarkTestCase {
private Artifact dummyArtifact;
@Before
public void setUp() throws Exception {
dummyArtifact = getSourceArtifact("dummy");
update("PyInfo", PyInfo.PROVIDER);
update("dummy_file", dummyArtifact);
}
/** We need this because {@code NestedSet}s don't have value equality. */
private static void assertHasOrderAndContainsExactly(
NestedSet<?> set, Order order, Object... values) {
assertThat(set.getOrder()).isEqualTo(order);
assertThat(set.toList()).containsExactly(values);
}
/** Checks values set by the builder. */
@Test
public void builderExplicit() throws Exception {
NestedSet<Artifact> sources = NestedSetBuilder.create(Order.COMPILE_ORDER, dummyArtifact);
NestedSet<String> imports = NestedSetBuilder.create(Order.COMPILE_ORDER, "abc");
Location loc = Location.fromFileLineColumn("foo", 1, 2);
PyInfo info =
PyInfo.builder()
.setLocation(loc)
.setTransitiveSources(sources)
.setUsesSharedLibraries(true)
.setImports(imports)
.setHasPy2OnlySources(true)
.setHasPy3OnlySources(true)
.build();
assertThat(info.getCreationLoc()).isEqualTo(loc);
assertHasOrderAndContainsExactly(
info.getTransitiveSources().getSet(Artifact.class), Order.COMPILE_ORDER, dummyArtifact);
assertThat(info.getUsesSharedLibraries()).isTrue();
assertHasOrderAndContainsExactly(
info.getImports().getSet(String.class), Order.COMPILE_ORDER, "abc");
assertThat(info.getHasPy2OnlySources()).isTrue();
assertThat(info.getHasPy3OnlySources()).isTrue();
}
/** Checks the defaults set by the builder. */
@Test
public void builderDefaults() throws Exception {
// transitive_sources is mandatory, so create a dummy value but no need to assert on it.
NestedSet<Artifact> sources = NestedSetBuilder.create(Order.COMPILE_ORDER, dummyArtifact);
PyInfo info = PyInfo.builder().setTransitiveSources(sources).build();
assertThat(info.getCreationLoc()).isEqualTo(Location.BUILTIN);
assertThat(info.getUsesSharedLibraries()).isFalse();
assertHasOrderAndContainsExactly(info.getImports().getSet(String.class), Order.COMPILE_ORDER);
assertThat(info.getHasPy2OnlySources()).isFalse();
assertThat(info.getHasPy3OnlySources()).isFalse();
}
@Test
public void starlarkConstructor() throws Exception {
exec(
"info = PyInfo(",
" transitive_sources = depset(direct=[dummy_file]),",
" uses_shared_libraries = True,",
" imports = depset(direct=['abc']),",
" has_py2_only_sources = True,",
" has_py3_only_sources = True,",
")");
PyInfo info = (PyInfo) lookup("info");
assertThat(info.getCreationLoc().toString()).isEqualTo(":1:8");
assertHasOrderAndContainsExactly(
info.getTransitiveSources().getSet(Artifact.class), Order.STABLE_ORDER, dummyArtifact);
assertThat(info.getUsesSharedLibraries()).isTrue();
assertHasOrderAndContainsExactly(
info.getImports().getSet(String.class), Order.STABLE_ORDER, "abc");
assertThat(info.getHasPy2OnlySources()).isTrue();
assertThat(info.getHasPy3OnlySources()).isTrue();
}
@Test
public void starlarkConstructorDefaults() throws Exception {
exec("info = PyInfo(transitive_sources = depset(direct=[dummy_file]))");
PyInfo info = (PyInfo) lookup("info");
assertThat(info.getCreationLoc().toString()).isEqualTo(":1:8");
assertHasOrderAndContainsExactly(
info.getTransitiveSources().getSet(Artifact.class), Order.STABLE_ORDER, dummyArtifact);
assertThat(info.getUsesSharedLibraries()).isFalse();
assertHasOrderAndContainsExactly(info.getImports().getSet(String.class), Order.COMPILE_ORDER);
assertThat(info.getHasPy2OnlySources()).isFalse();
assertThat(info.getHasPy3OnlySources()).isFalse();
}
@Test
public void starlarkConstructorErrors_TransitiveSources() throws Exception {
checkEvalErrorContains(
"missing 1 required named argument: transitive_sources", //
"PyInfo()");
checkEvalErrorContains(
"got value of type 'string', want 'depset of Files'", "PyInfo(transitive_sources = 'abc')");
checkEvalErrorContains(
"got value of type 'depset', want 'depset of Files'",
"PyInfo(transitive_sources = depset(direct=['abc']))");
checkEvalErrorContains(
"'transitive_sources' field should be a postorder-compatible depset of Files",
"PyInfo(transitive_sources = depset(direct=[dummy_file], order='preorder'))");
}
@Test
public void starlarkConstructorErrors_UsesSharedLibraries() throws Exception {
checkEvalErrorContains(
"got value of type 'string', want 'bool'",
"PyInfo(transitive_sources = depset([]), uses_shared_libraries = 'abc')");
}
@Test
public void starlarkConstructorErrors_Imports() throws Exception {
checkEvalErrorContains(
"got value of type 'string', want 'depset of strings'",
"PyInfo(transitive_sources = depset([]), imports = 'abc')");
checkEvalErrorContains(
"got value of type 'depset', want 'depset of strings'",
"PyInfo(transitive_sources = depset([]), imports = depset(direct=[123]))");
}
@Test
public void starlarkConstructorErrors_HasPy2OnlySources() throws Exception {
checkEvalErrorContains(
"got value of type 'string', want 'bool'",
"PyInfo(transitive_sources = depset([]), has_py2_only_sources = 'abc')");
}
@Test
public void starlarkConstructorErrors_HasPy3OnlySources() throws Exception {
checkEvalErrorContains(
"got value of type 'string', want 'bool'",
"PyInfo(transitive_sources = depset([]), has_py3_only_sources = 'abc')");
}
}