| // Copyright 2017 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.android; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static com.google.common.truth.Truth.assertWithMessage; |
| import static com.google.devtools.build.android.SplitConfigurationFilter.mapFilenamesToSplitFlags; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.testing.EqualsTester; |
| import com.google.common.truth.BooleanSubject; |
| import com.google.devtools.build.android.SplitConfigurationFilter.ResourceConfiguration; |
| import com.google.devtools.build.android.SplitConfigurationFilter.UnrecognizedSplitsException; |
| import javax.annotation.CheckReturnValue; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** Tests for {@link SplitConfigurationFilter}. */ |
| @RunWith(JUnit4.class) |
| public final class SplitConfigurationFilterTest { |
| |
| @Test |
| public void mapFilenamesToSplitFlagsShouldReturnEmptyMapForEmptyInput() |
| throws UnrecognizedSplitsException { |
| assertThat(mapFilenamesToSplitFlags(ImmutableList.<String>of(), ImmutableList.<String>of())) |
| .isEmpty(); |
| } |
| |
| @Test |
| public void mapFilenamesToSplitFlagsShouldMatchIdenticalFilenames() |
| throws UnrecognizedSplitsException { |
| assertThat(mapFilenamesToSplitFlags(ImmutableList.of("en"), ImmutableList.of("en"))) |
| .containsExactly("en", "en"); |
| assertThat(mapFilenamesToSplitFlags(ImmutableList.of("fr-v7"), ImmutableList.of("fr-v7"))) |
| .containsExactly("fr-v7", "fr-v7"); |
| assertThat(mapFilenamesToSplitFlags(ImmutableList.of("en_fr-v7"), ImmutableList.of("en,fr-v7"))) |
| .containsExactly("en_fr-v7", "en_fr-v7"); |
| assertThat( |
| mapFilenamesToSplitFlags( |
| ImmutableList.of("en", "fr-v7"), ImmutableList.of("en", "fr-v7"))) |
| .containsExactly("en", "en", "fr-v7", "fr-v7"); |
| assertThat( |
| mapFilenamesToSplitFlags( |
| ImmutableList.of("fr-v4", "fr-v7"), ImmutableList.of("fr-v4", "fr-v7"))) |
| .containsExactly("fr-v4", "fr-v4", "fr-v7", "fr-v7"); |
| } |
| |
| @Test |
| public void mapFilenamesToSplitFlagsShouldMatchReorderedFilenames() |
| throws UnrecognizedSplitsException { |
| assertThat(mapFilenamesToSplitFlags(ImmutableList.of("en_fr_ja"), ImmutableList.of("ja,fr,en"))) |
| .containsExactly("en_fr_ja", "ja_fr_en"); |
| assertThat( |
| mapFilenamesToSplitFlags( |
| ImmutableList.of("zu_12key", "zu"), ImmutableList.of("12key,zu", "zu"))) |
| .containsExactly("zu_12key", "12key_zu", "zu", "zu"); |
| assertThat( |
| mapFilenamesToSplitFlags( |
| ImmutableList.of("land_car", "round_port"), |
| ImmutableList.of("car,land", "port,round"))) |
| .containsExactly("land_car", "car_land", "round_port", "port_round"); |
| } |
| |
| @Test |
| public void mapFilenamesToSplitFlagsShouldMatchVersionUpgradedFilenames() |
| throws UnrecognizedSplitsException { |
| assertThat(mapFilenamesToSplitFlags(ImmutableList.of("round-v23"), ImmutableList.of("round"))) |
| .containsExactly("round-v23", "round"); |
| assertThat( |
| mapFilenamesToSplitFlags( |
| ImmutableList.of("watch-v20", "watch-v23"), ImmutableList.of("watch", "watch-v23"))) |
| .containsExactly("watch-v20", "watch", "watch-v23", "watch-v23"); |
| } |
| |
| @Test |
| public void equivalentFiltersShouldMatchFilterFromFilename() { |
| // identical inputs (barring commas -> underscores) should naturally match |
| assertMatchesFilterFromFilename("abc-def", "abc-def").isTrue(); |
| assertMatchesFilterFromFilename("abc-def-v5,ghi,jkl-lmno", "abc-def-v5_ghi_jkl-lmno").isTrue(); |
| // anything that results in matching sets should work, so case should be ignored |
| assertMatchesFilterFromFilename("abc-dEF", "aBC-def").isTrue(); |
| assertMatchesFilterFromFilename("aBC-def", "abc-dEF").isTrue(); |
| // additionally, order of elements in the set should be ignored |
| assertMatchesFilterFromFilename("abc,def", "def_abc").isTrue(); |
| assertMatchesFilterFromFilename("def,abc", "abc_def").isTrue(); |
| } |
| |
| @Test |
| public void matchingSpecifiersShouldMatchFilterFromFilenameWhenVersionsAreHigherNotWhenLower() { |
| // different (higher) versions, but same specifiers and same order |
| assertMatchesFilterFromFilename("x-v5,y-v6", "x-v7_y-v9").isTrue(); |
| assertMatchesFilterFromFilename("x-v7,y-v9", "x-v5_y-v6").isFalse(); |
| // order of sorted set changes but matching specifiers still match and filename version > flag |
| assertMatchesFilterFromFilename("x-v3,y-v6", "x-v23_y-v9").isTrue(); |
| assertMatchesFilterFromFilename("x-v23,y-v9", "x-v3_y-v6").isFalse(); |
| // specifier sets of multiple configs are the same |
| assertMatchesFilterFromFilename("x-v3,x-v17", "x-v3_x-v17").isTrue(); |
| assertMatchesFilterFromFilename("x-v3,x-v17", "x-v17_x-v3").isTrue(); |
| assertMatchesFilterFromFilename("x-v17,x-v3", "x-v17_x-v3").isTrue(); |
| assertMatchesFilterFromFilename("x-v17,x-v3", "x-v3_x-v17").isTrue(); |
| // specifier sets are the same, but one of them got a version bump |
| assertMatchesFilterFromFilename("x-v3,x-v17", "x-v14_x-v17").isTrue(); |
| assertMatchesFilterFromFilename("x-v14,x-v17", "x-v3_x-v17").isFalse(); |
| } |
| |
| @Test |
| public void nonMatchingSpecifiersShouldNotMatchFilterFromFilename() { |
| // completely disjoint specifier sets |
| assertMatchesFilterFromFilename("x,y,z", "a_b_c").isFalse(); |
| assertMatchesFilterFromFilename("a,b,c", "x_y_z").isFalse(); |
| // different number of specifier sets, which otherwise match |
| assertMatchesFilterFromFilename("x,y,z", "x_y").isFalse(); |
| assertMatchesFilterFromFilename("x,y", "x_y_z").isFalse(); |
| // same number of specifiers with one non-match |
| assertMatchesFilterFromFilename("x,y,z", "a_y_z").isFalse(); |
| assertMatchesFilterFromFilename("a,b,c", "a_b_z").isFalse(); |
| } |
| |
| @CheckReturnValue |
| private BooleanSubject assertMatchesFilterFromFilename(String flagFilter, String filenameFilter) { |
| return assertWithMessage( |
| "The split flag '%s' would be a match for a filename containing '%s'", |
| flagFilter, filenameFilter) |
| .that( |
| SplitConfigurationFilter.fromSplitFlag(flagFilter) |
| .matchesFilterFromFilename( |
| SplitConfigurationFilter.fromFilenameSuffix(filenameFilter))); |
| } |
| |
| @Test |
| public void splitConfigurationFilterShouldBeOrderedByConfigsThenFilename() { |
| assertThat( |
| ImmutableList.of( |
| // If all else is equal, break ties via filename (case does matter here) |
| SplitConfigurationFilter.fromFilenameSuffix("A"), |
| SplitConfigurationFilter.fromFilenameSuffix("a"), |
| // In filters with the same number of configs, the highest version wins |
| SplitConfigurationFilter.fromFilenameSuffix("d-v5_e-v5_f-v5"), |
| SplitConfigurationFilter.fromFilenameSuffix("a_b_c-v6"), |
| // It doesn't matter where in the input order that version is |
| SplitConfigurationFilter.fromFilenameSuffix("a-v7_b_c"), |
| // Specifiers break ties on number of configs + highest version |
| SplitConfigurationFilter.fromFilenameSuffix("d-v7_b_c"), |
| // Second highest version breaks ties (etc.) |
| SplitConfigurationFilter.fromFilenameSuffix("b-v2_d-v7_c"), |
| // Order doesn't matter but it does change the filename, hence sort order |
| SplitConfigurationFilter.fromFilenameSuffix("d-v7_b-v2_c"), |
| // Number of configs is the main criterion, so more sets of configs means later sort |
| SplitConfigurationFilter.fromFilenameSuffix("a_b_c_d_e_f_g_h_i_j_k_l_m"))) |
| .isInStrictOrder(); |
| |
| // if they are actually equal, they will compare equal |
| assertThat(SplitConfigurationFilter.fromFilenameSuffix("c-v13")) |
| .isEquivalentAccordingToCompareTo(SplitConfigurationFilter.fromFilenameSuffix("c-v13")); |
| |
| // if the only difference is split flag vs. filename suffix they will compare equal |
| assertThat(SplitConfigurationFilter.fromSplitFlag("split,split")) |
| .isEquivalentAccordingToCompareTo( |
| SplitConfigurationFilter.fromFilenameSuffix("split_split")); |
| } |
| |
| @Test |
| public void splitConfigurationFilterEqualsShouldPassEqualsTester() { |
| new EqualsTester() |
| .addEqualityGroup( |
| // base example |
| SplitConfigurationFilter.fromFilenameSuffix("abc-def_ghi_jkl"), |
| // identical clone |
| SplitConfigurationFilter.fromFilenameSuffix("abc-def_ghi_jkl"), |
| // commas are converted for split flags, the result is equal |
| SplitConfigurationFilter.fromSplitFlag("abc-def,ghi,jkl")) |
| .addEqualityGroup( |
| // case matters for filenames |
| SplitConfigurationFilter.fromFilenameSuffix("aBC-dEF_ghi_jkl")) |
| .addEqualityGroup( |
| // different filename producing equal set (elements parse the same) is still different |
| SplitConfigurationFilter.fromFilenameSuffix("abc-def-v0_ghi_jkl")) |
| .addEqualityGroup( |
| // different filename producing equal set (input order is different) is still different |
| SplitConfigurationFilter.fromFilenameSuffix("ghi_abc-def_jkl")) |
| .addEqualityGroup( |
| // totally different set is also very clearly different |
| SplitConfigurationFilter.fromFilenameSuffix("some-other_specifiers")) |
| .testEquals(); |
| } |
| |
| @Test |
| public void equalInputsShouldMatchConfigurationFromFilename() { |
| // identical inputs should naturally match |
| assertMatchesConfigurationFromFilename("abc-def", "abc-def").isTrue(); |
| assertMatchesConfigurationFromFilename("abc-def-v5", "abc-def-v5").isTrue(); |
| // case should be ignored |
| assertMatchesConfigurationFromFilename("abc-dEF", "aBC-def").isTrue(); |
| assertMatchesConfigurationFromFilename("aBC-def", "abc-dEF").isTrue(); |
| // wildcards should be ignored |
| assertMatchesConfigurationFromFilename("any-abc-def", "abc-any-def").isTrue(); |
| assertMatchesConfigurationFromFilename("abc-any-def", "any-abc-def").isTrue(); |
| // v0 should be ignored |
| assertMatchesConfigurationFromFilename("abc-def", "abc-def-v0").isTrue(); |
| assertMatchesConfigurationFromFilename("abc-def-v0", "abc-def").isTrue(); |
| } |
| |
| @Test |
| public void higherVersionSameSpecifiersShouldMatchConfigurationFromFilename() { |
| // any version is higher than the default v0 |
| assertMatchesConfigurationFromFilename("abc-def", "abc-def-v1").isTrue(); |
| assertMatchesConfigurationFromFilename("abc-def-v1", "abc-def").isFalse(); |
| // same deal for explicit v0 |
| assertMatchesConfigurationFromFilename("abc-def-v0", "abc-def-v1").isTrue(); |
| assertMatchesConfigurationFromFilename("abc-def-v1", "abc-def-v0").isFalse(); |
| // higher versions are better of course |
| assertMatchesConfigurationFromFilename("abc-def-v1", "abc-def-v999").isTrue(); |
| assertMatchesConfigurationFromFilename("abc-def-v999", "abc-def-v1").isFalse(); |
| } |
| |
| @Test |
| public void nonMatchingSpecifiersShouldNotMatchConfigurationFromFilename() { |
| // same version |
| assertMatchesConfigurationFromFilename("abc", "ghi").isFalse(); |
| assertMatchesConfigurationFromFilename("abc-v0", "ghi-v0").isFalse(); |
| assertMatchesConfigurationFromFilename("abc-v15", "ghi-v15").isFalse(); |
| // different version |
| assertMatchesConfigurationFromFilename("abc", "ghi-v15").isFalse(); |
| assertMatchesConfigurationFromFilename("abc-v0", "ghi-v15").isFalse(); |
| assertMatchesConfigurationFromFilename("abc-v15", "ghi-v19").isFalse(); |
| } |
| |
| @CheckReturnValue |
| private BooleanSubject assertMatchesConfigurationFromFilename( |
| String flagConfiguration, String fileConfiguration) { |
| return assertWithMessage( |
| "The split flag '%s' would be a match for a filename containing '%s'", |
| flagConfiguration, fileConfiguration) |
| .that( |
| ResourceConfiguration.fromString(flagConfiguration) |
| .matchesConfigurationFromFilename( |
| ResourceConfiguration.fromString(fileConfiguration))); |
| } |
| |
| @Test |
| public void resourceConfigurationShouldBeOrderedByApiVersionThenSpecifiers() { |
| assertThat( |
| ImmutableList.of( |
| // -v0 and no -v0 sort equal given the same specifiers, so it's a tie |
| ResourceConfiguration.fromString("a"), |
| // version ties are broken based on lexicographic string ordering |
| ResourceConfiguration.fromString("b-v0"), |
| // string ordering ignores case of the specifiers |
| ResourceConfiguration.fromString("Z"), |
| // higher API versions sort later regardless of the specifiers |
| ResourceConfiguration.fromString("z-v6"), |
| ResourceConfiguration.fromString("b-v13"), |
| // wildcards ("any") are ignored when considering specifier order |
| ResourceConfiguration.fromString("any-c-v13"))) |
| .isInStrictOrder(); |
| |
| // if they are actually equal, they will compare equal |
| assertThat(ResourceConfiguration.fromString("c-v13")) |
| .isEquivalentAccordingToCompareTo(ResourceConfiguration.fromString("c-v13")); |
| |
| // if the only difference is wildcards they will compare equal |
| assertThat(ResourceConfiguration.fromString("any-c-v13")) |
| .isEquivalentAccordingToCompareTo(ResourceConfiguration.fromString("c-v13")); |
| |
| // if the only difference is specifying (or not specifying) -v0 they will compare equal |
| assertThat(ResourceConfiguration.fromString("a-v0")) |
| .isEquivalentAccordingToCompareTo(ResourceConfiguration.fromString("a")); |
| |
| // if the only difference is case they will compare equal |
| assertThat(ResourceConfiguration.fromString("z")) |
| .isEquivalentAccordingToCompareTo(ResourceConfiguration.fromString("Z")); |
| } |
| |
| @Test |
| public void resourceConfigurationShouldPassEqualsTester() { |
| new EqualsTester() |
| .addEqualityGroup( |
| // base example |
| ResourceConfiguration.fromString("abc-def"), |
| // identical clone |
| ResourceConfiguration.fromString("abc-def"), |
| // case doesn't matter |
| ResourceConfiguration.fromString("aBC-dEF"), |
| // absent version code is equivalent to -v0 |
| ResourceConfiguration.fromString("abc-def-v0"), |
| // skip "any" |
| ResourceConfiguration.fromString("any-abc-any-def-any")) |
| .addEqualityGroup( |
| // order matters |
| ResourceConfiguration.fromString("def-abc")) |
| .addEqualityGroup( |
| // empty segments are not collapsed |
| ResourceConfiguration.fromString("abc---def")) |
| .addEqualityGroup( |
| // different version codes are parsed but result in a non-equal instance |
| ResourceConfiguration.fromString("abc-def-v15")) |
| .addEqualityGroup( |
| // two configurations with version codes must also have EQUAL version codes |
| ResourceConfiguration.fromString("abc-def-v12")) |
| .addEqualityGroup( |
| // empty strings are equal |
| ResourceConfiguration.fromString(""), |
| // yes, even if they have a v0 |
| ResourceConfiguration.fromString("v0"), |
| // or if there are some wildcards which will collapse to nothing |
| ResourceConfiguration.fromString("any"), |
| ResourceConfiguration.fromString("any-v0"), |
| ResourceConfiguration.fromString("any-any-any"), |
| ResourceConfiguration.fromString("any-any-any-v0")) |
| .addEqualityGroup( |
| // not if the version is nonzero though |
| ResourceConfiguration.fromString("v15"), ResourceConfiguration.fromString("any-v15")) |
| .testEquals(); |
| } |
| } |