blob: 057a7b7319838a343cc9ad6f494455d7272b0af0 [file] [log] [blame]
brandjon60be5312017-10-04 23:06:41 +02001// Copyright 2017 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.packages;
16
17import static com.google.common.truth.Truth.assertThat;
18
shahanfae34b92018-02-13 10:08:47 -080019import com.google.common.collect.ImmutableMap;
20import com.google.devtools.build.lib.skyframe.serialization.DeserializationContext;
21import com.google.devtools.build.lib.skyframe.serialization.SerializationContext;
brandjon60be5312017-10-04 23:06:41 +020022import com.google.devtools.build.lib.skyframe.serialization.testutils.TestUtils;
23import com.google.devtools.build.lib.syntax.SkylarkSemantics;
brandjon60be5312017-10-04 23:06:41 +020024import com.google.devtools.common.options.Options;
25import com.google.devtools.common.options.OptionsParser;
26import java.util.Arrays;
27import java.util.Random;
28import org.junit.Test;
29import org.junit.runner.RunWith;
30import org.junit.runners.JUnit4;
31
32/**
33 * Tests for the flow of flags from {@link SkylarkSemanticsOptions} to {@link SkylarkSemantics}, and
34 * to and from {@code SkylarkSemantics}' serialized representation.
35 *
36 * <p>When adding a new option, it is trivial to make a transposition error or a copy/paste error.
37 * These tests guard against such errors. The following possible bugs are considered:
38 * <ul>
39 * <li>If a new option is added to {@code SkylarkSemantics} but not to {@code
40 * SkylarkSemanticsOptions}, or vice versa, then the programmer will either be unable to
41 * implement its behavior, or unable to test it from the command line and add user
42 * documentation. We hope that the programmer notices this on their own.
43 *
44 * <li>If {@link SkylarkSemanticsOptions#toSkylarkSemantics} or {@link
45 * SkylarkSemanticsCodec#deserialize} is not updated to set all fields of {@code
46 * SkylarkSemantics}, then it will fail immediately because all fields of {@link
47 * SkylarkSemantics.Builder} are mandatory.
48 *
49 * <li>To catch a copy/paste error where the wrong field's data is threaded through {@code
50 * toSkylarkSemantics()} or {@code deserialize(...)}, we repeatedly generate matching random
51 * instances of the input and expected output objects.
52 *
53 * <li>The {@link #checkDefaultsMatch} test ensures that there is no divergence between the
54 * default values of the two classes.
55 *
56 * <li>There is no test coverage for failing to update the non-generated webpage documentation.
57 * So don't forget that!
58 * </ul>
59 */
60@RunWith(JUnit4.class)
61public class SkylarkSemanticsConsistencyTest {
62
63 private static final int NUM_RANDOM_TRIALS = 10;
64
65 /**
66 * Checks that a randomly generated {@link SkylarkSemanticsOptions} object can be converted to a
67 * {@link SkylarkSemantics} object with the same field values.
68 */
69 @Test
70 public void optionsToSemantics() throws Exception {
71 for (int i = 0; i < NUM_RANDOM_TRIALS; i++) {
72 long seed = i;
73 SkylarkSemanticsOptions options = buildRandomOptions(new Random(seed));
74 SkylarkSemantics semantics = buildRandomSemantics(new Random(seed));
75 SkylarkSemantics semanticsFromOptions = options.toSkylarkSemantics();
76 assertThat(semanticsFromOptions).isEqualTo(semantics);
77 }
78 }
79
brandjon6ac92f92017-12-06 13:57:15 -080080 /**
brandjon60be5312017-10-04 23:06:41 +020081 * Checks that a randomly generated {@link SkylarkSemantics} object can be serialized and
82 * deserialized to an equivalent object.
83 */
84 @Test
85 public void serializationRoundTrip() throws Exception {
86 SkylarkSemanticsCodec codec = new SkylarkSemanticsCodec();
87 for (int i = 0; i < NUM_RANDOM_TRIALS; i++) {
88 SkylarkSemantics semantics = buildRandomSemantics(new Random(i));
89 SkylarkSemantics deserialized =
shahanfae34b92018-02-13 10:08:47 -080090 TestUtils.fromBytes(
91 new DeserializationContext(ImmutableMap.of()),
92 codec,
93 TestUtils.toBytes(new SerializationContext(ImmutableMap.of()), codec, semantics));
brandjon60be5312017-10-04 23:06:41 +020094 assertThat(deserialized).isEqualTo(semantics);
95 }
96 }
97
98 @Test
99 public void checkDefaultsMatch() {
100 SkylarkSemanticsOptions defaultOptions = Options.getDefaults(SkylarkSemanticsOptions.class);
101 SkylarkSemantics defaultSemantics = SkylarkSemantics.DEFAULT_SEMANTICS;
102 SkylarkSemantics semanticsFromOptions = defaultOptions.toSkylarkSemantics();
103 assertThat(semanticsFromOptions).isEqualTo(defaultSemantics);
104 }
105
brandjon6ac92f92017-12-06 13:57:15 -0800106 @Test
107 public void canGetBuilderFromInstance() {
108 SkylarkSemantics original = SkylarkSemantics.DEFAULT_SEMANTICS;
109 assertThat(original.internalSkylarkFlagTestCanary()).isFalse();
110 SkylarkSemantics modified = original.toBuilder().internalSkylarkFlagTestCanary(true).build();
111 assertThat(modified.internalSkylarkFlagTestCanary()).isTrue();
112 }
113
brandjon60be5312017-10-04 23:06:41 +0200114 /**
115 * Constructs a {@link SkylarkSemanticsOptions} object with random fields. Must access {@code
116 * rand} using the same sequence of operations (for the same fields) as {@link
117 * #buildRandomSemantics}.
118 */
119 private static SkylarkSemanticsOptions buildRandomOptions(Random rand) throws Exception {
120 return parseOptions(
121 // <== Add new options here in alphabetic order ==>
122 "--incompatible_bzl_disallow_load_after_statement=" + rand.nextBoolean(),
brandjon60be5312017-10-04 23:06:41 +0200123 "--incompatible_depset_is_not_iterable=" + rand.nextBoolean(),
laurentlb2bbda4a2017-12-07 10:38:46 -0800124 "--incompatible_depset_union=" + rand.nextBoolean(),
laurentlbd7f87aa2017-12-12 07:55:15 -0800125 "--incompatible_disable_glob_tracking=" + rand.nextBoolean(),
cparsons99be8b42018-03-01 15:16:46 -0800126 "--incompatible_disable_objc_provider_resources=" + rand.nextBoolean(),
brandjon60be5312017-10-04 23:06:41 +0200127 "--incompatible_disallow_dict_plus=" + rand.nextBoolean(),
tomlubeafd7e2018-04-05 15:03:19 -0700128 "--incompatible_disallow_old_style_args_add=" + rand.nextBoolean(),
laurentlbc381cf12018-04-11 04:12:14 -0700129 "--incompatible_disallow_slash_operator=" + rand.nextBoolean(),
brandjon60be5312017-10-04 23:06:41 +0200130 "--incompatible_new_actions_api=" + rand.nextBoolean(),
laurentlb1cbce0f2018-03-27 12:43:22 -0700131 "--incompatible_package_name_is_a_function=" + rand.nextBoolean(),
Klaus Aehligddd1c9a2018-03-01 05:54:39 -0800132 "--incompatible_remove_native_git_repository=" + rand.nextBoolean(),
Klaus Aehliga7b34a12018-02-20 09:31:37 -0800133 "--incompatible_remove_native_http_archive=" + rand.nextBoolean(),
brandjon60be5312017-10-04 23:06:41 +0200134 "--incompatible_string_is_not_iterable=" + rand.nextBoolean(),
vladmos9bb93ee2017-11-21 04:40:08 -0800135 "--internal_skylark_flag_test_canary=" + rand.nextBoolean());
brandjon60be5312017-10-04 23:06:41 +0200136 }
137
138 /**
139 * Constructs a {@link SkylarkSemantics} object with random fields. Must access {@code rand} using
140 * the same sequence of operations (for the same fields) as {@link #buildRandomOptions}.
141 */
142 private static SkylarkSemantics buildRandomSemantics(Random rand) {
143 return SkylarkSemantics.builder()
144 // <== Add new options here in alphabetic order ==>
145 .incompatibleBzlDisallowLoadAfterStatement(rand.nextBoolean())
brandjon60be5312017-10-04 23:06:41 +0200146 .incompatibleDepsetIsNotIterable(rand.nextBoolean())
laurentlb2bbda4a2017-12-07 10:38:46 -0800147 .incompatibleDepsetUnion(rand.nextBoolean())
laurentlbd7f87aa2017-12-12 07:55:15 -0800148 .incompatibleDisableGlobTracking(rand.nextBoolean())
cparsons99be8b42018-03-01 15:16:46 -0800149 .incompatibleDisableObjcProviderResources(rand.nextBoolean())
brandjon60be5312017-10-04 23:06:41 +0200150 .incompatibleDisallowDictPlus(rand.nextBoolean())
tomlubeafd7e2018-04-05 15:03:19 -0700151 .incompatibleDisallowOldStyleArgsAdd(rand.nextBoolean())
laurentlbc381cf12018-04-11 04:12:14 -0700152 .incompatibleDisallowSlashOperator(rand.nextBoolean())
brandjon60be5312017-10-04 23:06:41 +0200153 .incompatibleNewActionsApi(rand.nextBoolean())
laurentlb1cbce0f2018-03-27 12:43:22 -0700154 .incompatiblePackageNameIsAFunction(rand.nextBoolean())
Klaus Aehligddd1c9a2018-03-01 05:54:39 -0800155 .incompatibleRemoveNativeGitRepository(rand.nextBoolean())
Klaus Aehliga7b34a12018-02-20 09:31:37 -0800156 .incompatibleRemoveNativeHttpArchive(rand.nextBoolean())
brandjon60be5312017-10-04 23:06:41 +0200157 .incompatibleStringIsNotIterable(rand.nextBoolean())
brandjon60be5312017-10-04 23:06:41 +0200158 .internalSkylarkFlagTestCanary(rand.nextBoolean())
159 .build();
160 }
161
162 private static SkylarkSemanticsOptions parseOptions(String... args) throws Exception {
163 OptionsParser parser = OptionsParser.newOptionsParser(SkylarkSemanticsOptions.class);
164 parser.setAllowResidue(false);
165 parser.parse(Arrays.asList(args));
166 return parser.getOptions(SkylarkSemanticsOptions.class);
167 }
168}