Ticket #13240: patch-test-mapcss-condition.patch

File patch-test-mapcss-condition.patch, 20.9 KB (added by michael2402, 7 years ago)
  • src/org/openstreetmap/josm/data/osm/OsmUtils.java

    diff --git a/src/org/openstreetmap/josm/data/osm/OsmUtils.java b/src/org/openstreetmap/josm/data/osm/OsmUtils.java
    index 9e7a9dd..62de4ed 100644
    a b public final class OsmUtils { 
    7474        if (p == null) {
    7575            throw new IllegalArgumentException("Expecting n/node/w/way/r/relation/area, but got '" + x[0] + '\'');
    7676        }
    77         for (final Map.Entry<String, String> i : TextTagParser.readTagsFromText(x[1]).entrySet()) {
    78             p.put(i.getKey(), i.getValue());
     77        if (x.length > 1) {
     78            for (final Map.Entry<String, String> i : TextTagParser.readTagsFromText(x[1]).entrySet()) {
     79                p.put(i.getKey(), i.getValue());
     80            }
    7981        }
    8082        return p;
    8183    }
  • test/performance/org/openstreetmap/josm/PerformanceTestUtils.java

    diff --git a/test/performance/org/openstreetmap/josm/PerformanceTestUtils.java b/test/performance/org/openstreetmap/josm/PerformanceTestUtils.java
    index d1deee9..c7ec73a 100644
    a b  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm;
    33
     4import java.util.ArrayList;
     5import java.util.Collections;
     6
    47import org.openstreetmap.josm.io.XmlWriter;
    58
    69import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
    import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 
    1013 * @author Michael Zangl
    1114 */
    1215public final class PerformanceTestUtils {
     16    private static final int TIMES_WARMUP = 2;
     17    private static final int TIMES_RUN = 8;
     18
     19    /**
     20     * A helper class that captures the time from object creation until #done() was called.
     21     * @author Michael Zangl
     22     * @since xxx
     23     */
     24    public static class PerformanceTestTimerCapture {
     25        private final long time;
     26
     27        protected PerformanceTestTimerCapture() {
     28            time = System.nanoTime();
     29        }
     30
     31        /**
     32         * Get the time since this object was created.
     33         * @return The time.
     34         */
     35        public long getTimeSinceCreation() {
     36            return (System.nanoTime() - time) / 1000000;
     37        }
     38    }
    1339    /**
    1440     * A timer that measures the time from it's creation to the {@link #done()} call.
    1541     * @author Michael Zangl
    1642     */
    17     public static class PerformanceTestTimer {
     43    public static class PerformanceTestTimer extends PerformanceTestTimerCapture {
    1844        private final String name;
    19         private final long time;
    20         private boolean measurementPlotsPlugin = false;
     45        private boolean measurementPlotsPlugin = true;
    2146
    2247        protected PerformanceTestTimer(String name) {
    2348            this.name = name;
    24             time = System.nanoTime();
    2549        }
    2650
    2751        /**
    public final class PerformanceTestUtils { 
    3660         * Prints the time since this timer was created.
    3761         */
    3862        public void done() {
    39             long dTime = (System.nanoTime() - time) / 1000000;
     63            long dTime = getTimeSinceCreation();
    4064            if (measurementPlotsPlugin) {
    4165                measurementPlotsPluginOutput(name + "(ms)", dTime);
    4266            } else {
    public final class PerformanceTestUtils { 
    4569        }
    4670    }
    4771
     72
    4873    private PerformanceTestUtils() {
    4974    }
    5075
    5176    /**
    52      * Starts a new performance timer.
     77     * Starts a new performance timer. The timer will output the measurements in a format understood by Jenkins.
     78     * <p>
     79     * The timer can only be used to meassure one value.
    5380     * @param name The name/description of the timer.
    5481     * @return A {@link PerformanceTestTimer} object of which you can call {@link PerformanceTestTimer#done()} when done.
    5582     */
    5683    @SuppressFBWarnings(value = "DM_GC", justification = "Performance test code")
    5784    public static PerformanceTestTimer startTimer(String name) {
     85        cleanSystem();
     86        return new PerformanceTestTimer(name);
     87    }
     88
     89    /**
     90     * Runs the given performance test several (approx. 10) times and prints the median run time.
     91     * @param name The name to use in the output
     92     * @param testRunner The test to run
     93     */
     94    public static void runPerformanceTest(String name, Runnable testRunner) {
     95        for (int i = 0; i < TIMES_WARMUP; i++) {
     96            cleanSystem();
     97            PerformanceTestTimerCapture capture = new PerformanceTestTimerCapture();
     98            testRunner.run();
     99            capture.getTimeSinceCreation();
     100        }
     101        ArrayList<Long> times = new ArrayList<>();
     102        for (int i = 0; i < TIMES_RUN; i++) {
     103            cleanSystem();
     104            PerformanceTestTimerCapture capture = new PerformanceTestTimerCapture();
     105            testRunner.run();
     106            times.add(capture.getTimeSinceCreation());
     107        }
     108        System.out.println(times);
     109        Collections.sort(times);
     110        // Sort out e.g. GC during test run.
     111        double avg = times.subList(2, times.size() - 2).stream().mapToLong(l -> l).average().getAsDouble();
     112        measurementPlotsPluginOutput(name, avg);
     113    }
     114
     115    private static void cleanSystem() {
    58116        System.gc();
    59117        System.runFinalization();
    60         return new PerformanceTestTimer(name);
    61118    }
    62119
    63120    /**
    public final class PerformanceTestUtils { 
    67124     *
    68125     * @param name the name / title of the measurement
    69126     * @param value the value
    70      * @see https://wiki.jenkins-ci.org/display/JENKINS/Measurement+Plots+Plugin
     127     * @see "https://wiki.jenkins-ci.org/display/JENKINS/Measurement+Plots+Plugin"
    71128     */
    72129    public static void measurementPlotsPluginOutput(String name, double value) {
    73130        System.err.println("<measurement><name>"+XmlWriter.encode(name)+"</name><value>"+value+"</value></measurement>");
  • new file test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSConditionPerformanceTest.java

    diff --git a/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSConditionPerformanceTest.java b/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSConditionPerformanceTest.java
    new file mode 100644
    index 0000000..97ff6fe
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.mappaint.mapcss;
     3
     4import java.util.EnumSet;
     5
     6import org.junit.Test;
     7import org.openstreetmap.josm.PerformanceTestUtils;
     8import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Op;
     9
     10/**
     11 * Performance test of MapCSS Condition objects.
     12 * @author Michael Zangl
     13 * @since xxx
     14 */
     15public class MapCSSConditionPerformanceTest {
     16    /**
     17     * Test the performance of all OP entries.
     18     */
     19    @Test
     20    public void testAllOps() {
     21        // The JIT does some really heavy optimisations if it notices that other values are not used.
     22        // If we want to simulate a real scenario, we need to invoke every op several times to let the compiler
     23        // build the jump tables.
     24        for (Op op : Op.values()) {
     25            getRunner(op).run();
     26        }
     27        for (Op op : Op.values()) {
     28            runTest(op);
     29        }
     30    }
     31
     32    private void runTest(Op op) {
     33        Runnable r = getRunner(op);
     34        PerformanceTestUtils.runPerformanceTest("Condition.Op." + op, r);
     35    }
     36
     37    private Runnable getRunner(Op op) {
     38        Runnable r;
     39        if (EnumSet.of(Op.LESS, Op.LESS_OR_EQUAL, Op.GREATER, Op.GREATER_OR_EQUAL).contains(op)) {
     40            r = () -> {
     41                for (int i = 0; i < 10000; i++) {
     42                        op.eval(null, "0.2");
     43                        op.eval("nan", "0.1");
     44                        op.eval("0.2983", "192.312");
     45                        op.eval("0.2983", "0.2983");
     46                        op.eval("2983", "1000");
     47                        op.eval("1000", "1000");
     48                }
     49            };
     50        } else {
     51            // regexp are slow
     52            int runs = EnumSet.of(Op.ONE_OF, Op.REGEX, Op.NREGEX).contains(op) ? 10000 : 100000;
     53            r = () -> {
     54                for (int i = 0; i < runs; i++) {
     55                    op.eval("k1", "v1");
     56                    op.eval("k1", "k1");
     57                    op.eval("", "v1");
     58                    op.eval(null, "abc");
     59                    op.eval("extreamlylongkeyextreamlylongkeyextreamlylongkeyextreamlylongkey",
     60                            "longvaluelongvaluelongvaluelongvalue");
     61                    op.eval("0.2983", "192.312");
     62                    op.eval("0.2983", "0.2983");
     63                    op.eval("2983", "\\d+");
     64                }
     65            };
     66        }
     67        return r;
     68    }
     69}
  • test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSourceFilterTest.java

    diff --git a/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSourceFilterTest.java b/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSourceFilterTest.java
    index 9f7a24a..424a73f 100644
    a b public class MapCSSStyleSourceFilterTest { 
    103103        KeyValueDataGenerator data = OsmDataGenerator.getKeyValue();
    104104        data.generateDataSet();
    105105        CssGenerator css = new CssGenerator(data).addKeyValueRules(TEST_RULE_COUNT);
    106         runTest(data, css, "only key=value rules", false);
     106        runTest(data, css, "only key=value rules");
    107107    }
    108108
    109109    /**
    public class MapCSSStyleSourceFilterTest { 
    114114        KeyValueDataGenerator data = OsmDataGenerator.getKeyValue();
    115115        data.generateDataSet();
    116116        CssGenerator css = new CssGenerator(data).addHasKeyRules(TEST_RULE_COUNT);
    117         runTest(data, css, "only has key rules", false);
     117        runTest(data, css, "only has key rules");
    118118    }
    119119
    120120    /**
    public class MapCSSStyleSourceFilterTest { 
    125125        KeyValueDataGenerator data = OsmDataGenerator.getKeyValue();
    126126        data.generateDataSet();
    127127        CssGenerator css = new CssGenerator(data).addKeyRegexpRules(TEST_RULE_COUNT);
    128         runTest(data, css, "regular expressions", true);
     128        runTest(data, css, "regular expressions");
    129129    }
    130130
    131131    /**
    public class MapCSSStyleSourceFilterTest { 
    136136        KeyValueDataGenerator data = OsmDataGenerator.getKeyValue();
    137137        data.generateDataSet();
    138138        CssGenerator css = new CssGenerator(data).addIsTrueRules(TEST_RULE_COUNT);
    139         runTest(data, css, "is true", false);
     139        runTest(data, css, "is true");
    140140    }
    141141
    142     private void runTest(KeyValueDataGenerator data, CssGenerator css, String description, boolean measurementPlotsPlugin) {
     142    private void runTest(KeyValueDataGenerator data, CssGenerator css, String description) {
    143143        MapCSSStyleSource source = new MapCSSStyleSource(css.getCss());
    144144        PerformanceTestTimer timer = PerformanceTestUtils.startTimer("MapCSSStyleSource#loadStyleSource(...) for " + description);
    145145        source.loadStyleSource();
    146146        timer.done();
    147147
    148         if (measurementPlotsPlugin) {
    149             timer = PerformanceTestUtils.startTimer(description);
    150             timer.setMeasurementPlotsPluginOutput(true);
    151         } else {
    152             timer = PerformanceTestUtils.startTimer(APPLY_CALLS + "x MapCSSStyleSource#apply(...) for " + description);
    153         }
     148        timer = PerformanceTestUtils.startTimer(APPLY_CALLS + "x MapCSSStyleSource#apply(...) for " + description);
    154149        for (int i = 0; i < APPLY_CALLS; i++) {
    155150            MultiCascade mc = new MultiCascade();
    156151            source.apply(mc, data.randomNode(), 1, false);
  • new file test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionTest.java

    diff --git a/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionTest.java b/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionTest.java
    new file mode 100644
    index 0000000..4ebe152
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.mappaint.mapcss;
     3
     4import static org.junit.Assert.assertEquals;
     5import static org.junit.Assert.assertFalse;
     6import static org.junit.Assert.assertTrue;
     7
     8import org.junit.Before;
     9import org.junit.Rule;
     10import org.junit.Test;
     11import org.openstreetmap.josm.data.osm.OsmPrimitive;
     12import org.openstreetmap.josm.data.osm.OsmUtils;
     13import org.openstreetmap.josm.gui.mappaint.Environment;
     14import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context;
     15import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Op;
     16import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.SimpleKeyValueCondition;
     17import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.ToTagConvertable;
     18import org.openstreetmap.josm.testutils.JOSMTestRules;
     19
     20import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
     21
     22/**
     23 * This test universally tests all {@link Condition}s.
     24 * @author Michael Zangl
     25 * @since xxx
     26 */
     27public class ConditionTest {
     28    /**
     29     * We need prefs for nodes.
     30     */
     31    @Rule
     32    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
     33    public JOSMTestRules test = new JOSMTestRules().preferences();
     34    private OsmPrimitive node0;
     35    private OsmPrimitive node1;
     36    private OsmPrimitive node2;
     37    private OsmPrimitive node3;
     38    private OsmPrimitive node4;
     39
     40    /**
     41     * Set up some useful test data.
     42     */
     43    @Before
     44    public void setUp() {
     45        node0 = OsmUtils.createPrimitive("n");
     46        node1 = OsmUtils.createPrimitive("n k1=v1 k2=v1 f1=0.2 r1=ababx c1=xya one=a;b");
     47        node2 = OsmUtils.createPrimitive("n k1=v1 k2=v1a f1=0.8 r1=abxabxab c1=xy one=a;;x");
     48        node3 = OsmUtils.createPrimitive("n k1=v1 f1=-100 c1=axy one=x;y;z");
     49        node4 = OsmUtils.createPrimitive("n k1=v2a k2=v3 f1=x r1=abab c1=axya one=x;a;y");
     50    }
     51
     52    /**
     53     * Test {@link Op#EQ}.
     54     */
     55    @Test
     56    public void testKeyValueEq() {
     57        Condition op = Condition.createKeyValueCondition("k1", "v1", Op.EQ, Context.PRIMITIVE, false);
     58        assertFalse(op.applies(genEnv(node0)));
     59        assertTrue(op.applies(genEnv(node1)));
     60        assertTrue(op.applies(genEnv(node2)));
     61        assertTrue(op.applies(genEnv(node3)));
     62        assertFalse(op.applies(genEnv(node4)));
     63
     64        assertTrue(op instanceof SimpleKeyValueCondition);
     65        assertEquals("[k1=v1]", op.toString());
     66        assertEquals("k1", ((ToTagConvertable) op).asTag(null).getKey());
     67        assertEquals("v1", ((ToTagConvertable) op).asTag(null).getValue());
     68    }
     69
     70    /**
     71     * Test {@link Op#EQ} and interpetation as key
     72     */
     73    @Test
     74    public void testKeyValueEqAsKey() {
     75        Condition op = Condition.createKeyValueCondition("k1", "k2", Op.EQ, Context.PRIMITIVE, true);
     76        assertFalse(op.applies(genEnv(node0)));
     77        assertTrue(op.applies(genEnv(node1)));
     78        assertFalse(op.applies(genEnv(node2)));
     79        assertFalse(op.applies(genEnv(node3)));
     80        assertFalse(op.applies(genEnv(node4)));
     81
     82        assertEquals("k1", ((ToTagConvertable) op).asTag(null).getKey());
     83        assertEquals("k2", ((ToTagConvertable) op).asTag(null).getValue());
     84    }
     85    /**
     86     * Test {@link Op#NEQ}
     87     */
     88    @Test
     89    public void testKeyValueNeq() {
     90        Condition op = Condition.createKeyValueCondition("k1", "v1", Op.NEQ, Context.PRIMITIVE, false);
     91        assertTrue(op.applies(genEnv(node0)));
     92        assertFalse(op.applies(genEnv(node1)));
     93        assertFalse(op.applies(genEnv(node2)));
     94        assertFalse(op.applies(genEnv(node3)));
     95        assertTrue(op.applies(genEnv(node4)));
     96    }
     97
     98    /**
     99     * Test {@link Op#GREATER_OR_EQUAL}
     100     */
     101    @Test
     102    public void testKeyValueGreatherEq() {
     103        Condition op = Condition.createKeyValueCondition("f1", "0.2", Op.GREATER_OR_EQUAL, Context.PRIMITIVE, false);
     104        assertFalse(op.applies(genEnv(node0)));
     105        assertTrue(op.applies(genEnv(node1)));
     106        assertTrue(op.applies(genEnv(node2)));
     107        assertFalse(op.applies(genEnv(node3)));
     108        assertFalse(op.applies(genEnv(node4)));
     109    }
     110
     111    /**
     112     * Test {@link Op#GREATER}
     113     */
     114    @Test
     115    public void testKeyValueGreather() {
     116        Condition op = Condition.createKeyValueCondition("f1", "0.2", Op.GREATER, Context.PRIMITIVE, false);
     117        assertFalse(op.applies(genEnv(node0)));
     118        assertFalse(op.applies(genEnv(node1)));
     119        assertTrue(op.applies(genEnv(node2)));
     120        assertFalse(op.applies(genEnv(node3)));
     121        assertFalse(op.applies(genEnv(node4)));
     122    }
     123
     124    /**
     125     * Test {@link Op#LESS_OR_EQUAL}
     126     */
     127    @Test
     128    public void testKeyValueLessEq() {
     129        Condition op = Condition.createKeyValueCondition("f1", "0.2", Op.LESS_OR_EQUAL, Context.PRIMITIVE, false);
     130        assertFalse(op.applies(genEnv(node0)));
     131        assertTrue(op.applies(genEnv(node1)));
     132        assertFalse(op.applies(genEnv(node2)));
     133        assertTrue(op.applies(genEnv(node3)));
     134        assertFalse(op.applies(genEnv(node4)));
     135    }
     136
     137    /**
     138     * Test {@link Op#LESS}
     139     */
     140    @Test
     141    public void testKeyValueLess() {
     142        Condition op = Condition.createKeyValueCondition("f1", "0.2", Op.LESS, Context.PRIMITIVE, false);
     143        assertFalse(op.applies(genEnv(node0)));
     144        assertFalse(op.applies(genEnv(node1)));
     145        assertFalse(op.applies(genEnv(node2)));
     146        assertTrue(op.applies(genEnv(node3)));
     147        assertFalse(op.applies(genEnv(node4)));
     148    }
     149
     150    /**
     151     * Test {@link Op#REGEX}
     152     */
     153    @Test
     154    public void testKeyValueRegex() {
     155        Condition op = Condition.createKeyValueCondition("r1", "(ab){2}", Op.REGEX, Context.PRIMITIVE, false);
     156        assertFalse(op.applies(genEnv(node0)));
     157        assertTrue(op.applies(genEnv(node1)));
     158        assertFalse(op.applies(genEnv(node2)));
     159        assertFalse(op.applies(genEnv(node3)));
     160        assertTrue(op.applies(genEnv(node4)));
     161    }
     162
     163    /**
     164     * Test {@link Op#NREGEX}
     165     */
     166    @Test
     167    public void testKeyValueNregex() {
     168        Condition op = Condition.createKeyValueCondition("r1", "(ab){2}", Op.NREGEX, Context.PRIMITIVE, false);
     169        assertTrue(op.applies(genEnv(node0)));
     170        assertFalse(op.applies(genEnv(node1)));
     171        assertTrue(op.applies(genEnv(node2)));
     172        assertTrue(op.applies(genEnv(node3)));
     173        assertFalse(op.applies(genEnv(node4)));
     174    }
     175
     176    /**
     177     * Test {@link Op#ONE_OF}
     178     */
     179    @Test
     180    public void testKeyValueOneOf() {
     181        Condition op = Condition.createKeyValueCondition("one", "a", Op.ONE_OF, Context.PRIMITIVE, false);
     182        assertFalse(op.applies(genEnv(node0)));
     183        assertTrue(op.applies(genEnv(node1)));
     184        assertTrue(op.applies(genEnv(node2)));
     185        assertFalse(op.applies(genEnv(node3)));
     186        assertTrue(op.applies(genEnv(node4)));
     187    }
     188
     189    /**
     190     * Test {@link Op#BEGINS_WITH}
     191     */
     192    @Test
     193    public void testKeyValueBeginsWith() {
     194        Condition op = Condition.createKeyValueCondition("c1", "xy", Op.BEGINS_WITH, Context.PRIMITIVE, false);
     195        assertFalse(op.applies(genEnv(node0)));
     196        assertTrue(op.applies(genEnv(node1)));
     197        assertTrue(op.applies(genEnv(node2)));
     198        assertFalse(op.applies(genEnv(node3)));
     199        assertFalse(op.applies(genEnv(node4)));
     200    }
     201
     202    /**
     203     * Test {@link Op#ENDS_WITH}
     204     */
     205    @Test
     206    public void testKeyValueEndsWith() {
     207        Condition op = Condition.createKeyValueCondition("c1", "xy", Op.ENDS_WITH, Context.PRIMITIVE, false);
     208        assertFalse(op.applies(genEnv(node0)));
     209        assertFalse(op.applies(genEnv(node1)));
     210        assertTrue(op.applies(genEnv(node2)));
     211        assertTrue(op.applies(genEnv(node3)));
     212        assertFalse(op.applies(genEnv(node4)));
     213    }
     214
     215    /**
     216     * Test {@link Op#CONTAINS}
     217     */
     218    @Test
     219    public void testKeyValueContains() {
     220        Condition op = Condition.createKeyValueCondition("c1", "xy", Op.CONTAINS, Context.PRIMITIVE, false);
     221        assertFalse(op.applies(genEnv(node0)));
     222        assertTrue(op.applies(genEnv(node1)));
     223        assertTrue(op.applies(genEnv(node2)));
     224        assertTrue(op.applies(genEnv(node3)));
     225        assertTrue(op.applies(genEnv(node4)));
     226    }
     227
     228    /**
     229     * Test of {@link Condition#createRegexpKeyRegexpValueCondition(String, String, Op)}
     230     */
     231    @Test
     232    public void testRegexpKeyValueRegexpCondition() {
     233        Condition op = Condition.createRegexpKeyRegexpValueCondition("^k", "\\da", Op.REGEX);
     234        assertFalse(op.applies(genEnv(node0)));
     235        assertFalse(op.applies(genEnv(node1)));
     236        assertTrue(op.applies(genEnv(node2)));
     237        assertFalse(op.applies(genEnv(node3)));
     238        assertTrue(op.applies(genEnv(node4)));
     239
     240        Condition notOp = Condition.createRegexpKeyRegexpValueCondition("^k", "\\da", Op.NREGEX);
     241        assertTrue(notOp.applies(genEnv(node0)));
     242        assertTrue(notOp.applies(genEnv(node1)));
     243        assertFalse(notOp.applies(genEnv(node2)));
     244        assertTrue(notOp.applies(genEnv(node3)));
     245        assertFalse(notOp.applies(genEnv(node4)));
     246    }
     247
     248    private Environment genEnv(OsmPrimitive primitive) {
     249        return new Environment(primitive);
     250    }
     251}