Changeset 18475 in josm


Ignore:
Timestamp:
2022-06-08T19:09:15+02:00 (23 months ago)
Author:
taylor.smock
Message:

Fix #21794: Allow for cases where tags can be URL or key values in Tag2Link

This also adds a Pattern cache (memory only) to avoid many allocations for
the same pattern in Tag2Link.

Location:
trunk
Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/tools/Tag2Link.java

    r18208 r18475  
    1111import java.util.Arrays;
    1212import java.util.Collections;
    13 import java.util.HashMap;
     13import java.util.EnumMap;
    1414import java.util.List;
    1515import java.util.Map;
    1616import java.util.Objects;
    1717import java.util.Optional;
     18import java.util.Set;
    1819import java.util.function.Supplier;
    1920import java.util.function.UnaryOperator;
     
    6869    static final CachingProperty<List<String>> PREF_SEARCH_ENGINES = new ListProperty("tag2link.search",
    6970            Arrays.asList("https://duckduckgo.com/?q=$1", "https://www.google.com/search?q=$1")).cached();
     71    private static final Pattern PATTERN_DOLLAR_ONE = Pattern.compile("$1", Pattern.LITERAL);
    7072
    7173    private Tag2Link() {
     
    148150        }
    149151
    150         final HashMap<OsmPrimitiveType, Optional<ImageResource>> memoize = new HashMap<>();
     152        final Map<OsmPrimitiveType, Optional<ImageResource>> memoize = new EnumMap<>(OsmPrimitiveType.class);
    151153        final Supplier<ImageResource> imageResource = () -> memoize
    152154                .computeIfAbsent(OsmPrimitiveType.NODE, type -> OsmPrimitiveImageProvider.getResource(key, value, type))
     
    209211        }
    210212
    211         wikidataRules.getValues(key).forEach(urlFormatter -> {
     213        final Set<String> formatterUrls = wikidataRules.getValues(key);
     214        if (!formatterUrls.isEmpty()) {
    212215            final String formattedValue = valueFormatter.getOrDefault(key, x -> x).apply(value);
    213             final String url = urlFormatter.replace("$1", formattedValue);
    214             linkConsumer.acceptLink(getLinkName(url, key), url, imageResource.get());
    215         });
     216
     217            final String urlKey = formatterUrls.stream().map(urlFormatter -> PATTERN_DOLLAR_ONE.matcher(urlFormatter)
     218                            .replaceAll(Matcher.quoteReplacement("(.*)"))).map(PatternUtils::compile)
     219                            .map(pattern -> pattern.matcher(value)).filter(Matcher::matches)
     220                            .map(matcher -> matcher.group(1)).findFirst().orElse(formattedValue);
     221
     222            formatterUrls.forEach(urlFormatter -> {
     223                // Check if the current value matches the formatter pattern -- some keys can take a full url or a key for
     224                // the formatter. Example: https://wiki.openstreetmap.org/wiki/Key:contact:facebook
     225                final String url = PATTERN_DOLLAR_ONE.matcher(urlFormatter).replaceAll(urlKey);
     226                linkConsumer.acceptLink(getLinkName(url, key), url, imageResource.get());
     227            });
     228        }
    216229    }
    217230
  • trunk/test/unit/org/openstreetmap/josm/tools/Tag2LinkTest.java

    r18037 r18475  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.tools;
     3
     4import static org.junit.jupiter.api.Assertions.assertEquals;
     5import static org.junit.jupiter.api.Assertions.assertTrue;
    36
    47import java.util.ArrayList;
     
    69import java.util.List;
    710
    8 import org.junit.Assert;
    911import org.junit.jupiter.api.Test;
     12import org.junit.jupiter.params.ParameterizedTest;
     13import org.junit.jupiter.params.provider.ValueSource;
    1014import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
    1115
     
    2327
    2428    void checkLinks(String... expected) {
    25         Assert.assertEquals(Arrays.asList(expected), links);
     29        assertEquals(Arrays.asList(expected), this.links);
    2630    }
    2731
     
    3236    void testInitialize() {
    3337        Tag2Link.initialize();
    34         Assert.assertTrue("obtains at least 40 rules", Tag2Link.wikidataRules.size() > 40);
     38        assertTrue(Tag2Link.wikidataRules.size() > 40, "obtains at least 40 rules");
     39    }
     40
     41    /**
     42     * Unit test for links that may come in multiple forms.
     43     * Example: <a href="https://wiki.osm.org/wiki/Key:contact:facebook">https://wiki.openstreetmap.org/wiki/Key:contact:facebook</a>
     44     *
     45     * See also JOSM #21794
     46     * @param value The tag value for "contact:facebook"
     47     */
     48    @ParameterizedTest
     49    @ValueSource(strings = {"https://www.facebook.com/FacebookUserName", "FacebookUserName"})
     50    void testUrlKeyMultipleForms(final String value) {
     51        // We need the wikidata rules Since testInitialize tests initialization, reuse it.
     52        if (!Tag2Link.wikidataRules.containsKey("contact:facebook")) {
     53            this.testInitialize();
     54        }
     55        Tag2Link.getLinksForTag("contact:facebook", value, this::addLink);
     56        this.checkLinks("Open unavatar.now.sh // https://unavatar.now.sh/facebook/FacebookUserName",
     57                "Open facebook.com // https://www.facebook.com/FacebookUserName",
     58                "Open messenger.com // https://www.messenger.com/t/FacebookUserName");
    3559    }
    3660
Note: See TracChangeset for help on using the changeset viewer.