// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.gui.conflict.tags;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.openstreetmap.josm.data.osm.Tag;
import org.openstreetmap.josm.data.osm.TagCollection;
import org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.AutomaticChoice;
import org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.AutomaticChoiceGroup;
import org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.AutomaticCombine;
import org.openstreetmap.josm.testutils.JOSMTestRules;
import com.google.common.collect.Sets;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Unit tests of {@link TagConflictResolutionUtil} class.
*/
public class TagConflictResolutionUtilTest {
/**
* Setup test.
*/
@Rule
@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
public JOSMTestRules test = new JOSMTestRules();
/**
* Unit test of {@link TagConflictResolutionUtil#applyAutomaticTagConflictResolution}.
* assume predefined rules for US TIGER and French Cadastre.
*/
@Test
public void testApplyAutomaticTagConflictResolution() {
// Check that general tag conflict are not resolved
TagCollection tc = new TagCollection();
tc.add(new Tag("building", "school"));
tc.add(new Tag("building", "garage"));
TagConflictResolutionUtil.applyAutomaticTagConflictResolution(tc);
assertEquals(Sets.newHashSet("school", "garage"), new HashSet<>(tc.getValues("building")));
// Check US Tiger tag conflict resolution
tc = new TagCollection();
tc.add(new Tag("tiger:test", "A:B"));
tc.add(new Tag("tiger:test", "A"));
TagConflictResolutionUtil.applyAutomaticTagConflictResolution(tc);
assertEquals(Sets.newHashSet("A:B"), new HashSet<>(tc.getValues("tiger:test")));
// Check FR:cadastre source tag conflict resolution (most common values from taginfo except last one without accentuated characters)
tc = new TagCollection();
// CHECKSTYLE.OFF: LineLength
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre ; mise à jour : 2007"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre ; mise à jour : 2008"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre ; mise à jour : 2009"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre ; mise à jour : 2010"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre. Mise à jour : 2008"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre. Mise à jour : 2009"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre. Mise à jour : 2010"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre. Mise à jour : 2011"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre. Mise à jour : 2012"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre. Mise à jour : 2013"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre. Mise à jour : 2014"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Impôts - Cadas. Mise à jour : 2010"));
tc.add(new Tag("source", "extraction vectorielle v1 cadastre-dgi-fr source : Direction Générale des Impôts - Cadas. Mise à jour : 2010"));
tc.add(new Tag("source", "Direction Générale des Finances Publiques - Cadastre ; mise à jour : 2010"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Finances Publiques - Cadastre. Mise à jour : 2013"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Générale des Finances Publiques - Cadastre. Mise à jour : 2014"));
tc.add(new Tag("source", "cadastre-dgi-fr source : Direction Generale des Finances Publiques - Cadastre. Mise a jour : 2015"));
// CHECKSTYLE.ON: LineLength
Tag otherSource = new Tag("source", "other");
tc.add(otherSource); // other source should prevent resolution
TagConflictResolutionUtil.applyAutomaticTagConflictResolution(tc);
assertSame(18, tc.getValues("source").size());
tc.remove(otherSource);
TagConflictResolutionUtil.applyAutomaticTagConflictResolution(tc);
assertEquals(Sets.newHashSet("cadastre-dgi-fr source : Direction Generale des Finances Publiques - Cadastre. Mise a jour : 2015"),
new HashSet<>(tc.getValues("source")));
// Check CA:canvec source tag conflict resolution
tc = new TagCollection();
tc.add(new Tag("source", "CanVec_Import_2009"));
tc.add(new Tag("source", "CanVec 4.0 - NRCan"));
tc.add(new Tag("source", "CanVec 6.0 - NRCan"));
tc.add(new Tag("source", "NRCan-CanVec-7.0"));
tc.add(new Tag("source", "NRCan-CanVec-8.0"));
tc.add(new Tag("source", "NRCan-CanVec-10.0"));
tc.add(new Tag("source", "NRCan-CanVec-12.0"));
TagConflictResolutionUtil.applyAutomaticTagConflictResolution(tc);
assertEquals(Sets.newHashSet("NRCan-CanVec-12.0"), new HashSet<>(tc.getValues("source")));
}
/**
* Unit tests of {@link AutomaticCombine} class.
*/
public static class AutomaticCombineTest {
/**
* Return AutomaticCombine instantiated with the two possible constructors.
* @param ac a model for the constructed object.
* @return AutomaticCombine object constructed with the two different constructors.
*/
private static List<AutomaticCombine> differentlyConstructed(AutomaticCombine ac) {
AutomaticCombine fullyConstructed = new AutomaticCombine(ac.key, ac.description, ac.isRegex, ac.separator, ac.sort);
AutomaticCombine defaultConstructed = new AutomaticCombine();
defaultConstructed.key = ac.key;
defaultConstructed.description = ac.description;
defaultConstructed.isRegex = ac.isRegex;
defaultConstructed.separator = ac.separator;
defaultConstructed.sort = ac.sort;
return Arrays.asList(defaultConstructed, fullyConstructed);
}
/**
* Setup test.
*/
@Rule
@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
public JOSMTestRules test = new JOSMTestRules();
/**
* Unit test of {@link AutomaticCombine#matchesKey} with empty key.
*/
@Test
public void testMatchesKeyEmptyKey() {
for (AutomaticCombine resolver: differentlyConstructed(new AutomaticCombine("", "random description", true, ";", null))) {
assertFalse(resolver.matchesKey("a"));
assertTrue(resolver.matchesKey(""));
}
}
/**
* Unit test of {@link AutomaticCombine#matchesKey} when regex not used.
*/
@Test
public void testMatchesKeyNotRegex() {
for (AutomaticCombine resolver: differentlyConstructed(new AutomaticCombine(
"keyname", "random description", false, "|", null))) {
assertFalse(resolver.matchesKey("key"));
assertFalse(resolver.matchesKey("keyname2"));
assertFalse(resolver.matchesKey("name"));
assertFalse(resolver.matchesKey("key.*("));
assertTrue(resolver.matchesKey("keyname"));
}
}
/**
* Unit test of {@link AutomaticCombine#matchesKey} when regex used.
*/
@Test
public void testMatchesKeyRegex() {
for (AutomaticCombine resolver: differentlyConstructed(new AutomaticCombine("test[45].*", "", true, ";", "Integer"))) {
assertFalse(resolver.matchesKey("key"));
assertFalse(resolver.matchesKey("test[45].*"));
assertTrue(resolver.matchesKey("test400 !"));
}
}
/**
* Unit test of {@link AutomaticCombine} with invalid regex.
*/
@Test
public void testInvalidRegex() {
for (AutomaticCombine resolver: differentlyConstructed(new AutomaticCombine("invalidregex.(]", "", false, ";", null))) {
// Should not raise exception if the resolver.isRexEx == false:
assertTrue(resolver.matchesKey("invalidregex.(]"));
}
// Should not raise exception if isRexEx, invalid regex but only constructed:
for (AutomaticCombine resolver: differentlyConstructed(new AutomaticCombine("invalidregex.(]", "", true, ";", null))) {
assertTrue(resolver.isRegex);
}
}
/**
* Unit test of {@link AutomaticCombine} with invalid regex.
*/
@Test(expected = java.util.regex.PatternSyntaxException.class)
public void testInvalidRegexExceptionDefaultConstructed() {
AutomaticCombine resolver = new AutomaticCombine("AB.(]", "", true, ";", null);
resolver.matchesKey("AB");
}
/**
* Unit test of {@link AutomaticCombine} with invalid regex.
*/
@Test(expected = java.util.regex.PatternSyntaxException.class)
public void testInvalidRegexExceptionFullyConstructed() {
AutomaticCombine resolver = new AutomaticCombine();
resolver.key = "AB.(]";
resolver.isRegex = true;
resolver.matchesKey("AB");
}
/**
* Unit test of {@link AutomaticCombine#resolve}.
*/
@Test
public void testResolve() {
for (AutomaticCombine resolver: differentlyConstructed(new AutomaticCombine("random", "", true, "|", "String"))) {
assertEquals(resolver.resolve(Sets.newHashSet("value1", "value2")), "value1|value2");
assertEquals(resolver.resolve(Sets.newHashSet("3|1", "4|2|1", "6|05", "3;1")), "05|1|2|3|3;1|4|6");
}
for (AutomaticCombine resolver: differentlyConstructed(new AutomaticCombine("test[45].*", "", true, ";", "Integer"))) {
assertEquals(resolver.resolve(Sets.newHashSet("1254545;95;24", "25;24;3")), "3;24;25;95;1254545");
}
for (AutomaticCombine resolver: differentlyConstructed(new AutomaticCombine("AB", "", true, ";", null))) {
String resolution = resolver.resolve(Sets.newHashSet("3;x;1", "4;x"));
assertTrue(resolution.equals("3;x;1;4") || resolution.equals("4;x;3;1"));
}
}
}
/**
* Unit tests of {@link AutomaticChoice} class.
*/
public static class AutomaticChoiceTest {
/**
* Setup test.
*/
@Rule
@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
public JOSMTestRules test = new JOSMTestRules();
/**
* Return AutomaticCombine instantiated with the two possible constructors.
* @param ac a model for the constructed object.
* @return AutomaticCombine object constructed with the two different constructors.
*/
private static List<AutomaticChoice> differentlyConstructed(AutomaticChoice ac) {
AutomaticChoice fullyConstructed = new AutomaticChoice(ac.key, ac.group, ac.description, ac.isRegex, ac.value, ac.score);
AutomaticChoice defaultConstructed = new AutomaticChoice();
defaultConstructed.key = ac.key;
defaultConstructed.group = ac.group;
defaultConstructed.description = ac.description;
defaultConstructed.isRegex = ac.isRegex;
defaultConstructed.value = ac.value;
defaultConstructed.score = ac.score;
return Arrays.asList(defaultConstructed, fullyConstructed);
}
/**
* Unit test of {@link AutomaticChoice#matchesValue}.
*/
@Test
public void testMatchesValue() {
for (AutomaticChoice resolver: differentlyConstructed(new AutomaticChoice(
"random key", "random group", "random description", false, ".*valueToMatch", "Score$0\\1"))) {
assertTrue(resolver.matchesValue(".*valueToMatch"));
assertFalse(resolver.matchesValue(".*valueToMatch.*"));
assertFalse(resolver.matchesValue("test"));
assertFalse(resolver.matchesValue(""));
}
for (AutomaticChoice resolver: differentlyConstructed(new AutomaticChoice(
"", "", "", true, "test([ab].*)", "ok $1"))) {
assertTrue(resolver.matchesValue("testa"));
assertTrue(resolver.matchesValue("testb129"));
assertFalse(resolver.matchesValue("test[ab].*"));
assertFalse(resolver.matchesValue("test"));
assertFalse(resolver.matchesValue(""));
}
}
/**
* Unit test of {@link AutomaticChoice#computeScoreFromValue}.
*/
@Test
public void testComputeScoreFromValue() {
for (AutomaticChoice resolver: differentlyConstructed(new AutomaticChoice(
"random key", "random group", "random description", false, ".*valueToMatch", "Score$0\\1"))) {
assertEquals(resolver.computeScoreFromValue(".*valueToMatch"), "Score$0\\1");
}
for (AutomaticChoice resolver: differentlyConstructed(new AutomaticChoice(
"", "", "", true, "test([ab].*)", "ok $1"))) {
assertEquals(resolver.computeScoreFromValue("testa"), "ok a");
assertEquals(resolver.computeScoreFromValue("testb129"), "ok b129");
}
}
/**
* Unit test of {@link AutomaticChoice} when invalid regex is used.
*/
@Test
public void testInvalidRegex() {
for (AutomaticChoice resolver: differentlyConstructed(new AutomaticChoice(
"k", "g", "", false, "invalidregex.(]", "InvalidScore$0\\1$-4"))) {
// Should not raise exception if the resolver.isRexEx == false:
assertTrue(resolver.matchesValue("invalidregex.(]"));
assertFalse(resolver.matchesValue("test"));
assertEquals(resolver.computeScoreFromValue("invalidregex.(]"), "InvalidScore$0\\1$-4");
}
// Should not raise exception if isRexEx, invalid regex but only constructed:
for (AutomaticChoice resolver: differentlyConstructed(new AutomaticChoice(
"k", "g", "", true, "invalidregex.(]", "InvalidScore$0\\1$-4"))) {
assertTrue(resolver.isRegex);
}
}
/**
* Unit test of {@link AutomaticChoice} when invalid regex is used.
*/
@Test(expected = java.util.regex.PatternSyntaxException.class)
public void testMatchesValueInvalidRegex() {
AutomaticChoice resolver = new AutomaticChoice("k", "g", "", true, "invalidregex.(]", "InvalidScore$0\\1$-4");
resolver.matchesValue("test");
}
/**
* Unit test of {@link AutomaticChoice} when invalid regex is used.
*/
@Test(expected = java.util.regex.PatternSyntaxException.class)
public void testComputeScoreFromValueInvalidRegex() {
AutomaticChoice resolver = new AutomaticChoice("k", "g", "", true, "invalidregex.(]", "valid");
resolver.computeScoreFromValue("valid");
}
/**
* Unit test of {@link AutomaticChoice} when invalid score replacement is used.
*/
@Test
public void testComputeScoreFromValueInvalidReplacement() {
AutomaticChoice resolver = new AutomaticChoice("k", "g", "", true, "valid", "InvalidScore$0\\1$-4");
boolean exceptionThrown = false;
try {
resolver.computeScoreFromValue("valid");
} catch (Exception e) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
}
}
/**
* Unit tests of {@link AutomaticChoiceGroup} class.
*/
public static class AutomaticChoiceGroupTest {
/**
* Setup test.
*/
@Rule
@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
public JOSMTestRules test = new JOSMTestRules();
AutomaticChoice choiceKey1Group1 = new AutomaticChoice("Key1", "Group1", "", false, "value1", "score1");
AutomaticChoice choiceKey1Group1bis = new AutomaticChoice("Key1", "Group1", "", false, "value2", "score2");
AutomaticChoice choiceKey1Group2 = new AutomaticChoice("Key1", "Group2", "", false, "value1", "score1");
AutomaticChoice choiceKey1Group2bis = new AutomaticChoice("Key1", "Group2", "", false, "value2", "score2");
AutomaticChoice choiceKey2Group1 = new AutomaticChoice("test[45].*", "Group1", "", true, "value1", "score1");
AutomaticChoice choiceKey2Group1bis = new AutomaticChoice("test[45].*", "Group1", "", true, "value2", "score2");
AutomaticChoice choiceKey2Group2 = new AutomaticChoice("test[45].*", "Group2", "", true, "value1(.*)", "$1");
AutomaticChoice choiceKey2Group2bis = new AutomaticChoice("test[45].*", "Group2", "", true, "value2(.*)", "$1");
AutomaticChoice choiceEmpty = new AutomaticChoice();
/**
* Unit test of {@link AutomaticChoiceGroup#groupChoices}.
*/
@Test
public void testGroupChoices() {
Collection<AutomaticChoiceGroup> groups = AutomaticChoiceGroup.groupChoices(Arrays.asList(choiceKey1Group1, choiceKey1Group2));
assertSame(2, groups.size());
groups = AutomaticChoiceGroup.groupChoices(Arrays.asList(
choiceKey1Group1, choiceKey1Group2, choiceKey2Group1, choiceKey2Group2, choiceEmpty));
assertSame(5, groups.size());
groups = AutomaticChoiceGroup.groupChoices(Arrays.asList(choiceKey1Group1, choiceKey1Group1bis));
assertSame(1, groups.size());
AutomaticChoiceGroup group1 = groups.iterator().next();
assertEquals(group1.key, choiceKey1Group1.key);
assertEquals(group1.group, choiceKey1Group1.group);
assertEquals(new HashSet<>(group1.choices), Sets.newHashSet(choiceKey1Group1, choiceKey1Group1bis));
groups = AutomaticChoiceGroup.groupChoices(Arrays.asList(
choiceKey1Group1, choiceKey1Group1bis, choiceKey1Group2, choiceKey1Group2bis,
choiceKey2Group1, choiceKey2Group1bis, choiceKey2Group2, choiceKey2Group2bis));
assertSame(4, groups.size());
for (AutomaticChoiceGroup group: groups) {
for (AutomaticChoice choice: group.choices) {
assertEquals(choice.key, group.key);
assertEquals(choice.group, group.group);
assertEquals(choice.isRegex, group.isRegex);
}
}
}
/**
* Unit test of {@link AutomaticChoiceGroup#matchesKey}.
*/
@Test
public void testMatchesKey() {
AutomaticChoiceGroup group = new AutomaticChoiceGroup(
choiceKey1Group1.key, choiceKey1Group1.group, choiceKey1Group1.isRegex,
Arrays.asList(choiceKey1Group1, choiceKey1Group1bis));
assertFalse(group.matchesKey("key"));
assertFalse(group.matchesKey("keyname2"));
assertFalse(group.matchesKey("name"));
assertFalse(group.matchesKey("key.*("));
assertTrue(group.matchesKey(choiceKey1Group1.key));
group = new AutomaticChoiceGroup(
choiceKey2Group1.key, choiceKey2Group2.group, choiceKey2Group2.isRegex,
Arrays.asList(choiceKey2Group2, choiceKey2Group2bis));
assertFalse(group.matchesKey("key"));
assertFalse(group.matchesKey("test[45].*"));
assertTrue(group.matchesKey("test400 !"));
}
/**
* Unit test of {@link AutomaticChoiceGroup#resolve}.
*/
@Test
public void testResolve() {
AutomaticChoiceGroup group = new AutomaticChoiceGroup(
choiceKey1Group1.key, choiceKey1Group1.group, choiceKey1Group1.isRegex,
Arrays.asList(choiceKey1Group1, choiceKey1Group1bis));
assertEquals(group.resolve(Sets.newHashSet(choiceKey1Group1.value)), choiceKey1Group1.value);
assertEquals(group.resolve(Sets.newHashSet(choiceKey1Group1.value, choiceKey1Group1bis.value)), choiceKey1Group1bis.value);
assertNull(group.resolve(Sets.newHashSet("random", choiceKey1Group1.value, choiceKey1Group1bis.value)));
group = new AutomaticChoiceGroup(
choiceKey2Group1.key, choiceKey2Group2.group, choiceKey2Group2.isRegex,
Arrays.asList(choiceKey2Group2, choiceKey2Group2bis));
assertEquals(group.resolve(Sets.newHashSet("value1")), "value1");
assertEquals(group.resolve(Sets.newHashSet("value1Z", "value2A")), "value1Z");
assertEquals(group.resolve(Sets.newHashSet("value1A", "value2Z")), "value2Z");
assertNull(group.resolve(Sets.newHashSet("value1Z", "value2A", "other not matched value")));
}
}
}