blob: 422eac18bae77aa2faf52ba1a81340b152f5ce91 [file] [log] [blame]
// 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.assertAbout;
import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.android.ParsedAndroidDataBuilder.file;
import static com.google.devtools.build.android.ParsedAndroidDataBuilder.xml;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.jimfs.Jimfs;
import com.google.common.truth.Subject;
import com.google.devtools.build.android.AndroidDataBuilder.ResourceType;
import com.google.devtools.build.android.AndroidDataMerger.MergeConflictException;
import com.google.devtools.build.android.AndroidDataMerger.SourceChecker;
import com.google.devtools.build.android.xml.IdXmlResourceValue;
import com.google.devtools.build.android.xml.PublicXmlResourceValue;
import com.google.devtools.build.android.xml.SimpleXmlResourceValue;
import com.google.devtools.build.android.xml.StyleableXmlResourceValue;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link AndroidDataMerger}. */
@RunWith(JUnit4.class)
public class AndroidDataMergerTest {
static final String XLIFF_NAMESPACE = "urn:oasis:names:tc:xliff:document:1.2";
static final String XLIFF_PREFIX = "xliff";
private FileSystem fileSystem;
private FullyQualifiedName.Factory fqnFactory;
private TestLoggingHandler loggingHandler;
private Logger mergerLogger;
@Before
public void setUp() throws Exception {
fileSystem = Jimfs.newFileSystem();
fqnFactory = FullyQualifiedName.Factory.from(ImmutableList.<String>of());
mergerLogger = Logger.getLogger(AndroidDataMerger.class.getCanonicalName());
loggingHandler = new TestLoggingHandler();
mergerLogger.addHandler(loggingHandler);
}
@After
public void removeLoggingHandler() {
mergerLogger.removeHandler(loggingHandler);
}
@Test
public void mergeDirectDeps() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
DataSource primaryStrings = DataSource.of(primaryRoot.resolve("res/values/resources.xml"));
DataSource directStrings = DataSource.of(directRoot.resolve("res/values/strings.xml"));
ParsedAndroidData transitiveDependency = ParsedAndroidDataBuilder.empty();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.overwritable(
file("layout/exit").source("res/layout/exit.xml"),
xml("string/exit")
.source(directStrings)
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")))
.combining(xml("id/exit").source("values/ids.xml").value(IdXmlResourceValue.of()))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addResource(
"values/resources.xml", ResourceType.VALUE, "<string name='exit'>way out</string>")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData data =
merger.merge(transitiveDependency, directDependency, primary, false, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.buildOn(fqnFactory)
.overwritable(
xml("string/exit")
.source(primaryStrings.overwrite(directStrings))
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "way out")))
.build(),
ParsedAndroidDataBuilder.buildOn(fqnFactory)
.overwritable(file("layout/exit").root(directRoot).source("res/layout/exit.xml"))
.combining(
xml("id/exit")
.root(directRoot)
.source("values/ids.xml")
.value(IdXmlResourceValue.of()))
.build());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeDirectAndTransitiveDeps() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
DataSource directString = DataSource.of(directRoot.resolve("res/values/resources.xml"));
DataSource primaryString =
DataSource.of(primaryRoot.resolve("res").resolve("values/resources.xml"));
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
.overwritable(file("layout/enter").source("res/layout/enter.xml"))
.combining(xml("id/exit").source("values/ids.xml").value(IdXmlResourceValue.of()))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.overwritable(
file("layout/exit").source("res/layout/exit.xml"),
xml("string/exit")
.source(directString)
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")))
.combining(xml("id/exit").source("values/ids.xml").value(IdXmlResourceValue.of()))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addResource(
"values/resources.xml", ResourceType.VALUE, "<string name='exit'>way out</string>")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData data =
merger.merge(transitiveDependency, directDependency, primary, false, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.buildOn(fqnFactory)
.overwritable(
xml("string/exit")
.root(primaryRoot)
.source(primaryString.overwrite(directString))
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "way out")))
.build(),
ParsedAndroidDataBuilder.buildOn(fqnFactory)
.overwritable(
file("layout/enter").root(transitiveRoot).source("res/layout/enter.xml"),
file("layout/exit").root(directRoot).source("res/layout/exit.xml"))
.combining(
xml("id/exit")
.root(directRoot)
.source("values/ids.xml")
.value(IdXmlResourceValue.of()))
.build());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeWithOverwriteInTransitiveDeps() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
Path descendentRoot = fileSystem.getPath("descendent");
DataSource descendentLayout = DataSource.of(descendentRoot.resolve("res/layout/enter.xml"));
DataSource transitiveLayout = DataSource.of(transitiveRoot.resolve("res/layout/enter.xml"));
DataSource primaryString = DataSource.of(primaryRoot.resolve("res/values/resources.xml"));
DataSource directStrings = DataSource.of(directRoot.resolve("res/values/strings.xml"));
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
.overwritable(file("layout/enter").source(descendentLayout))
.overwritable(file("layout/enter").source(transitiveLayout.overwrite(descendentLayout)))
.combining(xml("id/exit").source("values/ids.xml").value(IdXmlResourceValue.of()))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.overwritable(
file("layout/exit").source("res/layout/exit.xml"),
xml("string/exit")
.source(directStrings)
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")))
.combining(xml("id/exit").source("values/ids.xml").value(IdXmlResourceValue.of()))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addResource(
"values/resources.xml", ResourceType.VALUE, "<string name='exit'>way out</string>")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData transitive =
merger.merge(transitiveDependency, directDependency, primary, false, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.buildOn(fqnFactory)
.overwritable(
xml("string/exit")
.source(primaryString.overwrite(directStrings))
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "way out")))
.build(),
ParsedAndroidDataBuilder.buildOn(fqnFactory)
.overwritable(
file("layout/enter").source(transitiveLayout.overwrite(descendentLayout)),
file("layout/exit").root(directRoot).source("res/layout/exit.xml"))
.combining(
xml("id/exit")
.root(directRoot)
.source("values/ids.xml")
.value(IdXmlResourceValue.of()))
.build());
assertAbout(unwrittenMergedAndroidData).that(transitive).isEqualTo(expected);
}
@Test
public void mergeDirectConflict() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
ParsedAndroidData transitiveDependency = ParsedAndroidDataBuilder.empty();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
// Two string/exit will create conflict.
.overwritable(
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "wrong way out")),
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
merger.merge(transitiveDependency, directDependency, primary, false, false);
assertThat(loggingHandler.warnings)
.containsExactly(
MergeConflict.of(
fqnFactory.parse("string/exit"),
DataResourceXml.createWithNoNamespace(
directRoot.resolve("res/values/strings.xml"),
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")),
DataResourceXml.createWithNoNamespace(
directRoot.resolve("res/values/strings.xml"),
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "wrong way out")))
.toConflictMessage());
}
@Test
public void mergeDirectConflictDuplicated() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
ParsedAndroidData transitiveDependency = ParsedAndroidDataBuilder.empty();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
// Two string/exit will create conflict.
.overwritable(
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "way out")),
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "way out")))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.buildUnvalidated();
AndroidDataMerger merger =
AndroidDataMerger.createWithDefaultThreadPool(
new SourceChecker() {
@Override
public boolean checkEquality(DataSource one, DataSource two) throws IOException {
return one.equals(two);
}
});
assertAbout(unwrittenMergedAndroidData)
.that(merger.merge(transitiveDependency, directDependency, primary, false, true))
.isEqualTo(
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.empty(),
ParsedAndroidDataBuilder.buildOn(fqnFactory)
.overwritable(
xml("string/exit")
.root(directRoot)
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "way out")))
.build()));
}
@Test
public void mergeDirectConflictDuplicatedWithDifferentSources() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
ParsedAndroidData transitiveDependency = ParsedAndroidDataBuilder.empty();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
// Two string/exit will create conflict.
.overwritable(
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "way out")),
xml("string/exit")
.source("values/more_strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "way out")),
xml("string/another_key")
.source("values/more_strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "another way out")))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
merger.merge(transitiveDependency, directDependency, primary, false, true);
assertThat(loggingHandler.warnings).isEmpty();
}
@Test
public void mergeDirectConflictWithPrimaryOverride() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
DataSource primaryStrings = DataSource.of(primaryRoot.resolve("res/values/strings.xml"));
DataSource directStrings = DataSource.of(directRoot.resolve("res/values/strings.xml"));
ParsedAndroidData transitiveDependency = ParsedAndroidDataBuilder.empty();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
// Two string/exit will create conflict.
.overwritable(
xml("string/exit")
.source(directStrings)
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "wrong way out")),
xml("string/exit")
.source(directStrings)
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addResource(
"values/strings.xml", ResourceType.VALUE, "<string name='exit'>way out</string>")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData data =
merger.merge(transitiveDependency, directDependency, primary, true, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.buildOn(fqnFactory)
.overwritable(
xml("string/exit")
.source(primaryStrings.overwrite(directStrings))
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "way out")))
.build(),
ParsedAndroidDataBuilder.empty());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeTransitiveConflict() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path transitiveRoot = fileSystem.getPath("transitive");
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
// Two string/exit will create conflict.
.overwritable(
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "wrong way out")),
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")))
.build();
ParsedAndroidData directDependency = ParsedAndroidDataBuilder.empty();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
merger.merge(transitiveDependency, directDependency, primary, false, false);
assertThat(loggingHandler.warnings)
.containsExactly(
MergeConflict.of(
fqnFactory.parse("string/exit"),
DataResourceXml.createWithNoNamespace(
transitiveRoot.resolve("res/values/strings.xml"),
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")),
DataResourceXml.createWithNoNamespace(
transitiveRoot.resolve("res/values/strings.xml"),
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "wrong way out")))
.toConflictMessage());
}
@Test
public void mergeTransitiveConflictWithPrimaryOverride() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
// Two string/exit will create conflict.
.overwritable(
xml("string/exit")
.root(transitiveRoot.resolve("1"))
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "wrong way out")),
xml("string/exit")
.root(transitiveRoot.resolve("2"))
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory).build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addResource(
"values/strings.xml", ResourceType.VALUE, "<string name='exit'>way out</string>")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData data =
merger.merge(transitiveDependency, directDependency, primary, true, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.buildOn(fqnFactory)
.overwritable(
xml("string/exit")
.root(primaryRoot)
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "way out")))
.build(),
ParsedAndroidDataBuilder.empty());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeDirectAndTransitiveConflict() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
.overwritable(
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.overwritable(
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "wrong way out")))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
merger.merge(transitiveDependency, directDependency, primary, false, false);
assertThat(loggingHandler.warnings)
.containsExactly(
MergeConflict.of(
fqnFactory.parse("string/exit"),
DataResourceXml.createWithNoNamespace(
directRoot.resolve("res/values/strings.xml"),
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")),
DataResourceXml.createWithNoNamespace(
transitiveRoot.resolve("res/values/strings.xml"),
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "wrong way out")))
.toConflictMessage());
}
@Test
public void mergeDirectTransitivePrimaryConflictWithoutPrimaryOverride() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
.overwritable(
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.overwritable(
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "wrong way out")))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addResource(
"values/strings.xml", ResourceType.VALUE, "<string name='exit'>way out</string>")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
merger.merge(transitiveDependency, directDependency, primary, false, false);
FullyQualifiedName fullyQualifiedName = fqnFactory.parse("string/exit");
assertThat(loggingHandler.warnings)
.containsExactly(
MergeConflict.of(
fullyQualifiedName,
DataResourceXml.createWithNoNamespace(
directRoot.resolve("res/values/strings.xml"),
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")),
DataResourceXml.createWithNoNamespace(
transitiveRoot.resolve("res/values/strings.xml"),
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "wrong way out")))
.toConflictMessage());
}
@Test
public void mergeDirectTransitivePrimaryConflictWithThrowOnConflict() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
.overwritable(
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.overwritable(
xml("string/exit")
.source("values/strings.xml")
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "wrong way out")))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addResource(
"values/strings.xml", ResourceType.VALUE, "<string name='exit'>way out</string>")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
try {
merger.merge(transitiveDependency, directDependency, primary, false, true);
throw new Exception("Expected a MergeConflictException!");
} catch (MergeConflictException e) {
return;
}
}
@Test
public void mergeDirectTransitivePrimaryConflictWithPrimaryOverride() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
DataSource primaryStrings = DataSource.of(primaryRoot.resolve("res/values/strings.xml"));
DataSource directStrings = DataSource.of(directRoot.resolve("res/values/strings.xml"));
DataSource transitiveStrings = DataSource.of(transitiveRoot.resolve("res/values/strings.xml"));
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
.overwritable(
xml("string/exit")
.source(transitiveStrings)
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "no way out")))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.overwritable(
xml("string/exit")
.source(directStrings)
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "wrong way out")))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addResource(
"values/strings.xml", ResourceType.VALUE, "<string name='exit'>way out</string>")
.buildUnvalidated();
UnwrittenMergedAndroidData data =
AndroidDataMerger.createWithDefaults()
.merge(transitiveDependency, directDependency, primary, true, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.buildOn(fqnFactory)
.overwritable(
xml("string/exit")
.source(primaryStrings.overwrite(directStrings))
.value(
SimpleXmlResourceValue.createWithValue(
SimpleXmlResourceValue.Type.STRING, "way out")))
.build(),
ParsedAndroidDataBuilder.empty());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeDirectAndTransitiveNinepatchConflict() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
// A drawable nine-patch png and plain png with the same base filename will conflict.
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
.overwritable(file("drawable/rounded_corners").source("drawable/rounded_corners.9.png"))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.overwritable(file("drawable/rounded_corners").source("drawable/rounded_corners.png"))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
merger.merge(transitiveDependency, directDependency, primary, false, false);
assertThat(loggingHandler.warnings)
.containsExactly(
MergeConflict.of(
fqnFactory.parse("drawable/rounded_corners"),
DataValueFile.of(directRoot.resolve("res/drawable/rounded_corners.png")),
DataValueFile.of(transitiveRoot.resolve("res/drawable/rounded_corners.9.png")))
.toConflictMessage());
}
@Test
public void mergeAssetsDirectDeps() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
ParsedAndroidData transitiveDependency = ParsedAndroidDataBuilder.empty();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot)
.assets(file().source("hunting/of/the/snark.txt"))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addAsset("bin/boojum")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData data =
merger.merge(transitiveDependency, directDependency, primary, false, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.builder()
.assets(file().root(primaryRoot).source("bin/boojum"))
.build(),
ParsedAndroidDataBuilder.builder()
.assets(file().root(directRoot).source("hunting/of/the/snark.txt"))
.build());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeCombiningResources() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
.combining(
xml("styleable/RubADubDub")
.source("values/attrs.xml")
.value(
StyleableXmlResourceValue.createAllAttrAsReferences(
fqnFactory.parse("attr/baker"))))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.combining(
xml("styleable/RubADubDub")
.source("values/attrs.xml")
.value(
StyleableXmlResourceValue.createAllAttrAsReferences(
fqnFactory.parse("attr/candlestickmaker"))))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addResource(
"values/attrs.xml",
ResourceType.VALUE,
"<declare-styleable name='RubADubDub'>",
" <attr name='butcher'/>",
"</declare-styleable>")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData data =
merger.merge(transitiveDependency, directDependency, primary, false, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.buildOn(primaryRoot, fqnFactory)
.combining(
xml("styleable/RubADubDub")
.source("values/attrs.xml")
.value(
StyleableXmlResourceValue.createAllAttrAsReferences(
fqnFactory.parse("attr/baker"),
fqnFactory.parse("attr/butcher"),
fqnFactory.parse("attr/candlestickmaker"))))
.build(),
ParsedAndroidDataBuilder.empty());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeCombiningResourcesWithNamespaces() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
// TODO(corysmith): Make conflict uris for a single prefix and error
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
.combining(
xml("styleable/RubADubDub")
.source("values/attrs.xml")
.namespace(XLIFF_PREFIX, XLIFF_NAMESPACE)
.namespace("tools", "http://schemas.android.com/tools")
.value(
StyleableXmlResourceValue.createAllAttrAsReferences(
fqnFactory.parse("attr/baker"))))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.combining(
xml("styleable/RubADubDub")
.source("values/attrs.xml")
.namespace(XLIFF_PREFIX, "wrong uri")
.value(
StyleableXmlResourceValue.createAllAttrAsReferences(
fqnFactory.parse("attr/candlestickmaker"))))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addResource(
"values/attrs.xml",
ResourceType.VALUE,
"<declare-styleable name='RubADubDub'>",
" <attr name='butcher'/>",
"</declare-styleable>")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData data =
merger.merge(transitiveDependency, directDependency, primary, false, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.buildOn(primaryRoot, fqnFactory)
.combining(
xml("styleable/RubADubDub")
.source("values/attrs.xml")
.namespace(XLIFF_PREFIX, "wrong uri")
.namespace("tools", "http://schemas.android.com/tools")
.value(
StyleableXmlResourceValue.createAllAttrAsReferences(
fqnFactory.parse("attr/baker"),
fqnFactory.parse("attr/butcher"),
fqnFactory.parse("attr/candlestickmaker"))))
.build(),
ParsedAndroidDataBuilder.empty());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeCombiningLayoutIDResources() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
DataSource transitiveLayout =
DataSource.of(transitiveRoot.resolve("res/layout/transitive.xml"));
DataSource directLayout = DataSource.of(directRoot.resolve("res/layout/direct.xml"));
DataSource primaryLayout = DataSource.of(primaryRoot.resolve("res/layout/primary.xml"));
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
.overwritable(file("layout/transitive").source(transitiveLayout))
.combining(
xml("id/back_door").source(transitiveLayout).value(IdXmlResourceValue.of()),
xml("id/door").source("values/ids.xml").value(IdXmlResourceValue.of()),
xml("id/slide").source(transitiveLayout).value(IdXmlResourceValue.of()))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.overwritable(file("layout/zzDirect").source(directLayout))
.combining(
xml("id/door").source(directLayout).value(IdXmlResourceValue.of()),
xml("id/slide").source(directLayout).value(IdXmlResourceValue.of()),
xml("id/window").source(directLayout).value(IdXmlResourceValue.of()))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addResource(
"layout/primary.xml",
ResourceType.LAYOUT,
"<TextView android:id=\"@+id/door\"",
" android:text=\"this way ---> \"",
" android:layout_width=\"wrap_content\"",
" android:layout_height=\"wrap_content\" />",
"<TextView android:id=\"@+id/window\"",
" android:text=\"no, not that way\"",
" android:layout_width=\"wrap_content\"",
" android:layout_height=\"wrap_content\" />")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData data =
merger.merge(transitiveDependency, directDependency, primary, false, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.buildOn(primaryRoot, fqnFactory)
.overwritable(file("layout/primary").source(primaryLayout))
.combining(
xml("id/window").source("layout/primary.xml").value(IdXmlResourceValue.of()),
xml("id/door")
.root(transitiveRoot)
.source("values/ids.xml")
.value(IdXmlResourceValue.of()))
.build(),
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.overwritable(
file("layout/transitive").source(transitiveLayout),
file("layout/zzDirect").source(directLayout))
.combining(
xml("id/back_door").source(transitiveLayout).value(IdXmlResourceValue.of()),
xml("id/slide").source(directLayout).value(IdXmlResourceValue.of()))
.build());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeCombiningPublicResources() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot, fqnFactory)
.combining(
xml("public/RubADubDub")
.source("values/public.xml")
.value(
PublicXmlResourceValue.create(
com.android.resources.ResourceType.STRING, Optional.of(0x7f040000))))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
.combining(
xml("public/RubADubDub")
.source("values/public.xml")
.value(
PublicXmlResourceValue.create(
com.android.resources.ResourceType.DIMEN, Optional.of(0x7f020000))))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addResource(
"values/public.xml",
ResourceType.VALUE,
"<public name='RubADubDub' type='color' id='0x7f030000' />")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData data =
merger.merge(transitiveDependency, directDependency, primary, false, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.buildOn(primaryRoot, fqnFactory)
.combining(
xml("public/RubADubDub")
.source("values/public.xml")
.value(
PublicXmlResourceValue.of(
ImmutableMap.of(
com.android.resources.ResourceType.COLOR,
Optional.of(0x7f030000),
com.android.resources.ResourceType.DIMEN,
Optional.of(0x7f020000),
com.android.resources.ResourceType.STRING,
Optional.of(0x7f040000)))))
.build(),
ParsedAndroidDataBuilder.empty());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeAssetsDirectAndTransitiveDeps() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot)
.assets(file().source("hunting/of/the/jubjub.bird"))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot)
.assets(file().source("hunting/of/the/snark.txt"))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addAsset("bin/boojum")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData data =
merger.merge(transitiveDependency, directDependency, primary, false, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.builder()
.assets(file().root(primaryRoot).source("bin/boojum"))
.build(),
ParsedAndroidDataBuilder.builder()
.assets(
file().root(directRoot).source("hunting/of/the/snark.txt"),
file().root(transitiveRoot).source("hunting/of/the/jubjub.bird"))
.build());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeAssetsDirectConflict() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRootOne = fileSystem.getPath("directOne");
Path directRootTwo = fileSystem.getPath("directTwo");
ParsedAndroidData transitiveDependency = ParsedAndroidDataBuilder.empty();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.builder()
.assets(
file().root(directRootOne).source("hunting/of/the/snark.txt"),
file().root(directRootTwo).source("hunting/of/the/snark.txt"))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
merger.merge(transitiveDependency, directDependency, primary, false, false);
assertThat(loggingHandler.warnings)
.containsExactly(
MergeConflict.of(
RelativeAssetPath.Factory.of(directRootOne.resolve("assets"))
.create(directRootOne.resolve("assets/hunting/of/the/snark.txt")),
DataValueFile.of(directRootOne.resolve("assets/hunting/of/the/snark.txt")),
DataValueFile.of(directRootTwo.resolve("assets/hunting/of/the/snark.txt")))
.toConflictMessage());
}
@Test
public void mergeAssetsDirectConflictWithPrimaryOverride() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRootOne = fileSystem.getPath("directOne");
Path directRootTwo = fileSystem.getPath("directTwo");
ParsedAndroidData transitiveDependency = ParsedAndroidDataBuilder.empty();
String assetFile = "hunting/of/the/snark.txt";
DataSource primarySource = DataSource.of(primaryRoot.resolve("assets/" + assetFile));
DataSource directSourceOne = DataSource.of(directRootOne.resolve("assets/" + assetFile));
DataSource directSourceTwo = DataSource.of(directRootTwo.resolve("assets/" + assetFile));
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.builder()
.assets(
file().root(directRootOne).source(directSourceOne),
file().root(directRootTwo).source(directSourceTwo))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addAsset(assetFile)
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData data =
merger.merge(transitiveDependency, directDependency, primary, true, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.builder()
.assets(
file()
.root(primaryRoot)
.source(primarySource.overwrite(directSourceOne, directSourceTwo)))
.build(),
ParsedAndroidDataBuilder.empty());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeAssetsTransitiveConflict() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path transitiveRootOne = fileSystem.getPath("transitiveOne");
Path transitiveRootTwo = fileSystem.getPath("transitiveTwo");
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.builder()
.assets(
file().root(transitiveRootOne).source("hunting/of/the/snark.txt"),
file().root(transitiveRootTwo).source("hunting/of/the/snark.txt"))
.build();
ParsedAndroidData directDependency = ParsedAndroidDataBuilder.empty();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
merger.merge(transitiveDependency, directDependency, primary, false, false);
assertThat(loggingHandler.warnings)
.containsExactly(
MergeConflict.of(
RelativeAssetPath.Factory.of(transitiveRootOne.resolve("assets"))
.create(transitiveRootOne.resolve("assets/hunting/of/the/snark.txt")),
DataValueFile.of(transitiveRootOne.resolve("assets/hunting/of/the/snark.txt")),
DataValueFile.of(transitiveRootTwo.resolve("assets/hunting/of/the/snark.txt")))
.toConflictMessage());
}
@Test
public void mergeAssetsTransitiveConflictWithPrimaryOverride() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path transitiveRoot = fileSystem.getPath("transitive");
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot)
.assets(file().source("hunting/of/the/snark.txt"))
.build();
ParsedAndroidData directDependency = ParsedAndroidDataBuilder.empty();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addAsset("hunting/of/the/snark.txt")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
UnwrittenMergedAndroidData data =
merger.merge(transitiveDependency, directDependency, primary, true, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.buildOn(primaryRoot)
.assets(file().source("hunting/of/the/snark.txt"))
.build(),
ParsedAndroidDataBuilder.empty());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
@Test
public void mergeAssetsDirectAndTransitiveConflict() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot)
.assets(file().source("hunting/of/the/snark.txt"))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot)
.assets(file().source("hunting/of/the/snark.txt"))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
merger.merge(transitiveDependency, directDependency, primary, false, false);
assertThat(loggingHandler.warnings)
.containsExactly(
MergeConflict.of(
RelativeAssetPath.Factory.of(directRoot.resolve("assets"))
.create(directRoot.resolve("assets/hunting/of/the/snark.txt")),
DataValueFile.of(directRoot.resolve("assets/hunting/of/the/snark.txt")),
DataValueFile.of(transitiveRoot.resolve("assets/hunting/of/the/snark.txt")))
.toConflictMessage());
}
@Test
public void mergeAssetsDirectTransitivePrimaryConflictWithoutPrimaryOverride() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot)
.assets(file().source("hunting/of/the/snark.txt"))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot)
.assets(file().source("hunting/of/the/snark.txt"))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addAsset("hunting/of/the/snark.txt")
.buildUnvalidated();
AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
merger.merge(transitiveDependency, directDependency, primary, false, false);
assertThat(loggingHandler.warnings)
.containsExactly(
MergeConflict.of(
RelativeAssetPath.Factory.of(directRoot.resolve("assets"))
.create(directRoot.resolve("assets/hunting/of/the/snark.txt")),
DataValueFile.of(directRoot.resolve("assets/hunting/of/the/snark.txt")),
DataValueFile.of(transitiveRoot.resolve("assets/hunting/of/the/snark.txt")))
.toConflictMessage());
}
@Test
public void mergeAssetsDirectTransitivePrimaryConflictWithPrimaryOverride() throws Exception {
Path primaryRoot = fileSystem.getPath("primary");
Path directRoot = fileSystem.getPath("direct");
Path transitiveRoot = fileSystem.getPath("transitive");
DataSource primarySource =
DataSource.of(primaryRoot.resolve("assets/hunting/of/the/snark.txt"));
DataSource directSource = DataSource.of(directRoot.resolve("assets/hunting/of/the/snark.txt"));
ParsedAndroidData transitiveDependency =
ParsedAndroidDataBuilder.buildOn(transitiveRoot)
.assets(file().source("hunting/of/the/snark.txt"))
.build();
ParsedAndroidData directDependency =
ParsedAndroidDataBuilder.buildOn(directRoot)
.assets(file().source("hunting/of/the/snark.txt"))
.build();
UnvalidatedAndroidData primary =
AndroidDataBuilder.of(primaryRoot)
.createManifest("AndroidManifest.xml", "com.google.mergetest")
.addAsset("hunting/of/the/snark.txt")
.buildUnvalidated();
UnwrittenMergedAndroidData data =
AndroidDataMerger.createWithDefaults()
.merge(transitiveDependency, directDependency, primary, true, true);
UnwrittenMergedAndroidData expected =
UnwrittenMergedAndroidData.of(
primary.getManifest(),
ParsedAndroidDataBuilder.buildOn(primaryRoot)
.assets(file().source(primarySource.overwrite(directSource)))
.build(),
ParsedAndroidDataBuilder.empty());
assertAbout(unwrittenMergedAndroidData).that(data).isEqualTo(expected);
}
final Subject.Factory<UnwrittenMergedAndroidDataSubject, UnwrittenMergedAndroidData>
unwrittenMergedAndroidData = UnwrittenMergedAndroidDataSubject::new;
private static final class TestLoggingHandler extends Handler {
public final List<String> warnings = new ArrayList<String>();
@Override
public void publish(LogRecord record) {
if (record.getLevel().equals(Level.WARNING)) {
warnings.add(record.getMessage());
}
}
@Override
public void flush() {}
@Override
public void close() throws SecurityException {}
}
}