changeset 385:55a0d7fe2040

OptionBuilder.parent() to fallback to parent if some options are not specified.
author shade
date Tue, 11 Feb 2014 18:58:52 +0400
parents f2e982b7c51b
children ba51dff93e4b
files jmh-api-samples/src/main/java/org/openjdk/jmh/SimpleTest.java jmh-core/src/main/java/org/openjdk/jmh/runner/options/ChainedOptionsBuilder.java jmh-core/src/main/java/org/openjdk/jmh/runner/options/OptionsBuilder.java jmh-core/src/main/java/org/openjdk/jmh/util/internal/Optional.java jmh-core/src/test/java/org/openjdk/jmh/runner/options/TestParentOptions.java
diffstat 5 files changed, 676 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/jmh-api-samples/src/main/java/org/openjdk/jmh/SimpleTest.java	Fri Jan 31 12:46:38 2014 +0400
+++ b/jmh-api-samples/src/main/java/org/openjdk/jmh/SimpleTest.java	Tue Feb 11 18:58:52 2014 +0400
@@ -28,6 +28,8 @@
 import org.openjdk.jmh.logic.results.RunResult;
 import org.openjdk.jmh.runner.Runner;
 import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.CommandLineOptionException;
+import org.openjdk.jmh.runner.options.CommandLineOptions;
 import org.openjdk.jmh.runner.options.Options;
 import org.openjdk.jmh.runner.options.OptionsBuilder;
 import org.openjdk.jmh.runner.parameters.TimeValue;
@@ -38,8 +40,9 @@
      * This sample uses VERY EXPERIMENTAL API; use with care!
      */
 
-    public static void main(String[] args) throws RunnerException {
+    public static void main(String[] args) throws RunnerException, CommandLineOptionException {
         Options opts = new OptionsBuilder()
+                .parent(new CommandLineOptions(args))
                 .include(".*")
                 .warmupTime(TimeValue.milliseconds(100))
                 .measurementTime(TimeValue.milliseconds(100))
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/options/ChainedOptionsBuilder.java	Fri Jan 31 12:46:38 2014 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/ChainedOptionsBuilder.java	Tue Feb 11 18:58:52 2014 +0400
@@ -40,6 +40,15 @@
     Options build();
 
     /**
+     * Override the defaults from the given option.
+     * You may use this only once.
+     *
+     * @param other options to base on
+     * @return builder
+     */
+    ChainedOptionsBuilder parent(Options other);
+
+    /**
      * Include benchmark in the run
      * (Can be used multiple times)
      *
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/options/OptionsBuilder.java	Fri Jan 31 12:46:38 2014 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/OptionsBuilder.java	Tue Feb 11 18:58:52 2014 +0400
@@ -41,17 +41,18 @@
 
 public class OptionsBuilder implements Options, ChainedOptionsBuilder {
 
-    private boolean finalized;
-
-    private void checkFinalized() {
-        if (finalized) {
-            throw new IllegalStateException("The builder is already finalized");
-        }
+    @Override
+    public Options build() {
+        return this;
     }
 
+    // ---------------------------------------------------------------------------
+
+    private Options otherOptions;
+
     @Override
-    public Options build() {
-        finalized = true;
+    public ChainedOptionsBuilder parent(Options other) {
+        this.otherOptions = other;
         return this;
     }
 
@@ -61,17 +62,24 @@
 
     @Override
     public ChainedOptionsBuilder include(String regexp) {
-        checkFinalized();
         regexps.add(regexp);
         return this;
     }
 
     @Override
     public List<String> getIncludes() {
-        if (regexps.isEmpty()) {
+        List<String> result = new ArrayList<String>();
+
+        result.addAll(regexps);
+        if (otherOptions != null) {
+            result.addAll(otherOptions.getIncludes());
+        }
+
+        if (result.isEmpty()) {
             return Collections.singletonList(".*");
+        } else {
+            return result;
         }
-        return regexps;
     }
 
     // ---------------------------------------------------------------------------
@@ -86,7 +94,14 @@
 
     @Override
     public List<String> getExcludes() {
-        return excludes;
+        List<String> result = new ArrayList<String>();
+
+        result.addAll(excludes);
+        if (otherOptions != null) {
+            result.addAll(otherOptions.getExcludes());
+        }
+
+        return result;
     }
 
     // ---------------------------------------------------------------------------
@@ -101,7 +116,11 @@
 
     @Override
     public Optional<String> getOutput() {
-        return output;
+        if (otherOptions != null) {
+            return output.orAnother(otherOptions.getOutput());
+        } else {
+            return output;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -116,7 +135,11 @@
 
     @Override
     public Optional<ResultFormatType> getResultFormat() {
-        return rfType;
+        if (otherOptions != null) {
+            return rfType.orAnother(otherOptions.getResultFormat());
+        } else {
+            return rfType;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -131,7 +154,11 @@
 
     @Override
     public Optional<String> getResult() {
-        return result;
+        if (otherOptions != null) {
+            return result.orAnother(otherOptions.getResult());
+        } else {
+            return result;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -146,7 +173,11 @@
 
     @Override
     public Optional<Boolean> shouldDoGC() {
-        return shouldDoGC;
+        if (otherOptions != null) {
+            return shouldDoGC.orAnother(otherOptions.shouldDoGC());
+        } else {
+            return shouldDoGC;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -161,6 +192,9 @@
 
     @Override
     public Set<ProfilerType> getProfilers() {
+        if (otherOptions != null) {
+            profilers.addAll(otherOptions.getProfilers());
+        }
         return profilers;
     }
 
@@ -176,7 +210,11 @@
 
     @Override
     public Optional<VerboseMode> verbosity() {
-        return verbosity;
+        if (otherOptions != null) {
+            return verbosity.orAnother(otherOptions.verbosity());
+        } else {
+            return verbosity;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -191,7 +229,11 @@
 
     @Override
     public Optional<Boolean> shouldFailOnError() {
-        return shouldFailOnError;
+        if (otherOptions != null) {
+            return shouldFailOnError.orAnother(otherOptions.shouldFailOnError());
+        } else {
+            return shouldFailOnError;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -206,7 +248,11 @@
 
     @Override
     public Optional<Integer> getThreads() {
-        return threads;
+        if (otherOptions != null) {
+            return threads.orAnother(otherOptions.getThreads());
+        } else {
+            return threads;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -221,7 +267,11 @@
 
     @Override
     public Optional<int[]> getThreadGroups() {
-        return threadGroups;
+        if (otherOptions != null) {
+            return threadGroups.orAnother(otherOptions.getThreadGroups());
+        } else {
+            return threadGroups;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -236,7 +286,11 @@
 
     @Override
     public Optional<Boolean> shouldSyncIterations() {
-        return syncIterations;
+        if (otherOptions != null) {
+            return syncIterations.orAnother(otherOptions.shouldSyncIterations());
+        } else {
+            return syncIterations;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -251,7 +305,11 @@
 
     @Override
     public Optional<Integer> getWarmupIterations() {
-        return warmupIterations;
+        if (otherOptions != null) {
+            return warmupIterations.orAnother(otherOptions.getWarmupIterations());
+        } else {
+            return warmupIterations;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -266,7 +324,11 @@
 
     @Override
     public Optional<TimeValue> getWarmupTime() {
-        return warmupTime;
+        if (otherOptions != null) {
+            return warmupTime.orAnother(otherOptions.getWarmupTime());
+        } else {
+            return warmupTime;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -281,7 +343,11 @@
 
     @Override
     public Optional<WarmupMode> getWarmupMode() {
-        return warmupMode;
+        if (otherOptions != null) {
+            return warmupMode.orAnother(otherOptions.getWarmupMode());
+        } else {
+            return warmupMode;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -296,7 +362,12 @@
 
     @Override
     public List<String> getWarmupIncludes() {
-        return warmupMicros;
+        List<String> result = new ArrayList<String>();
+        result.addAll(warmupMicros);
+        if (otherOptions != null) {
+            result.addAll(otherOptions.getWarmupIncludes());
+        }
+        return result;
     }
 
     // ---------------------------------------------------------------------------
@@ -311,7 +382,11 @@
 
     @Override
     public Optional<Integer> getMeasurementIterations() {
-        return iterations;
+        if (otherOptions != null) {
+            return iterations.orAnother(otherOptions.getMeasurementIterations());
+        } else {
+            return iterations;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -326,7 +401,11 @@
 
     @Override
     public Optional<TimeValue> getMeasurementTime() {
-        return measurementTime;
+        if (otherOptions != null) {
+            return measurementTime.orAnother(otherOptions.getMeasurementTime());
+        } else {
+            return measurementTime;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -341,7 +420,11 @@
 
     @Override
     public Collection<Mode> getBenchModes() {
-        return benchModes;
+        if (otherOptions != null && benchModes.isEmpty()) {
+            return otherOptions.getBenchModes();
+        } else {
+            return benchModes;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -356,7 +439,11 @@
 
     @Override
     public Optional<TimeUnit> getTimeUnit() {
-        return timeUnit;
+        if (otherOptions != null) {
+            return timeUnit.orAnother(otherOptions.getTimeUnit());
+        } else {
+            return timeUnit;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -371,7 +458,11 @@
 
     @Override
     public Optional<Integer> getForkCount() {
-        return forks;
+        if (otherOptions != null) {
+            return forks.orAnother(otherOptions.getForkCount());
+        } else {
+            return forks;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -386,7 +477,11 @@
 
     @Override
     public Optional<Integer> getWarmupForkCount() {
-        return warmupForks;
+        if (otherOptions != null) {
+            return warmupForks.orAnother(otherOptions.getWarmupForkCount());
+        } else {
+            return warmupForks;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -401,7 +496,11 @@
 
     @Override
     public Optional<String> getJvm() {
-        return jvmBinary;
+        if (otherOptions != null) {
+            return jvmBinary.orAnother(otherOptions.getJvm());
+        } else {
+            return jvmBinary;
+        }
     }
 
     // ---------------------------------------------------------------------------
@@ -416,7 +515,11 @@
 
     @Override
     public Optional<Collection<String>> getJvmArgs() {
-        return jvmArgs;
+        if (otherOptions != null) {
+            return jvmArgs.orAnother(otherOptions.getJvmArgs());
+        } else {
+            return jvmArgs;
+        }
     }
 
 }
--- a/jmh-core/src/main/java/org/openjdk/jmh/util/internal/Optional.java	Fri Jan 31 12:46:38 2014 +0400
+++ b/jmh-core/src/main/java/org/openjdk/jmh/util/internal/Optional.java	Tue Feb 11 18:58:52 2014 +0400
@@ -53,6 +53,10 @@
         return (val == null) ? elseVal : val;
     }
 
+    public Optional<T> orAnother(Optional<T> alternative) {
+        return (val == null) ? alternative : this;
+    }
+
     /**
      * Produce empty Option
      * @param <T> type
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core/src/test/java/org/openjdk/jmh/runner/options/TestParentOptions.java	Tue Feb 11 18:58:52 2014 +0400
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.runner.options;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.output.results.ResultFormatType;
+import org.openjdk.jmh.profile.ProfilerType;
+import org.openjdk.jmh.runner.parameters.TimeValue;
+
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.concurrent.TimeUnit;
+
+public class TestParentOptions {
+
+    @Test
+    public void testIncludes_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(Arrays.asList(".*"), builder.getIncludes());
+    }
+
+    @Test
+    public void testIncludes_Parent() throws Exception {
+        Options parent = new OptionsBuilder().include(".*").build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(Arrays.asList(".*"), builder.getIncludes());
+    }
+
+    @Test
+    public void testIncludes_Merge() throws Exception {
+        Options parent = new OptionsBuilder().include(".*").build();
+        Options builder = new OptionsBuilder().parent(parent).include(".*test.*").build();
+        Assert.assertEquals(Arrays.asList(".*test.*", ".*"), builder.getIncludes());
+    }
+
+    @Test
+    public void testExcludes_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertTrue(builder.getExcludes().isEmpty());
+    }
+
+    @Test
+    public void testExcludes_Parent() throws Exception {
+        Options parent = new OptionsBuilder().include(".*").build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(Arrays.asList(".*"), builder.getIncludes());
+    }
+
+    @Test
+    public void testExcludes_Merge() throws Exception {
+        Options parent = new OptionsBuilder().exclude(".*").build();
+        Options builder = new OptionsBuilder().parent(parent).exclude(".*test.*").build();
+        Assert.assertEquals(Arrays.asList(".*test.*", ".*"), builder.getExcludes());
+    }
+
+    @Test
+    public void testProfiler_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertTrue(builder.getProfilers().isEmpty());
+    }
+
+    @Test
+    public void testProfiler_Parent() throws Exception {
+        Options parent = new OptionsBuilder().addProfiler(ProfilerType.CL).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(EnumSet.of(ProfilerType.CL), builder.getProfilers());
+    }
+
+    @Test
+    public void testProfiler_Merge() throws Exception {
+        Options parent = new OptionsBuilder().addProfiler(ProfilerType.CL).build();
+        Options builder = new OptionsBuilder().parent(parent).addProfiler(ProfilerType.COMP).build();
+        Assert.assertEquals(EnumSet.of(ProfilerType.COMP, ProfilerType.CL), builder.getProfilers());
+    }
+
+    @Test
+    public void testBenchModes_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertTrue(builder.getBenchModes().isEmpty());
+    }
+
+    @Test
+    public void testBenchModes_Parent() throws Exception {
+        Options parent = new OptionsBuilder().mode(Mode.AverageTime).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(EnumSet.of(Mode.AverageTime), builder.getBenchModes());
+    }
+
+    @Test
+    public void testBenchModes_Merge() throws Exception {
+        Options parent = new OptionsBuilder().mode(Mode.AverageTime).build();
+        Options builder = new OptionsBuilder().parent(parent).mode(Mode.SingleShotTime).build();
+        Assert.assertEquals(EnumSet.of(Mode.SingleShotTime), builder.getBenchModes());
+    }
+
+    @Test
+    public void testForks_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getForkCount().hasValue());
+    }
+
+    @Test
+    public void testForks_Parent() throws Exception {
+        Options parent = new OptionsBuilder().forks(42).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(Integer.valueOf(42), builder.getForkCount().get());
+    }
+
+    @Test
+    public void testForks_Merge() throws Exception {
+        Options parent = new OptionsBuilder().forks(42).build();
+        Options builder = new OptionsBuilder().parent(parent).forks(84).build();
+        Assert.assertEquals(Integer.valueOf(84), builder.getForkCount().get());
+    }
+
+    @Test
+    public void testGC_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.shouldDoGC().hasValue());
+    }
+
+    @Test
+    public void testGC_Parent() throws Exception {
+        Options parent = new OptionsBuilder().shouldDoGC(true).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(true, builder.shouldDoGC().get());
+    }
+
+    @Test
+    public void testGC_Merge() throws Exception {
+        Options parent = new OptionsBuilder().shouldDoGC(true).build();
+        Options builder = new OptionsBuilder().parent(parent).shouldDoGC(false).build();
+        Assert.assertEquals(false, builder.shouldDoGC().get());
+    }
+
+    @Test
+    public void testJVM_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getJvm().hasValue());
+    }
+
+    @Test
+    public void testJVM_Parent() throws Exception {
+        Options parent = new OptionsBuilder().jvm("path").build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals("path", builder.getJvm().get());
+    }
+
+    @Test
+    public void testJVM_Merge() throws Exception {
+        Options parent = new OptionsBuilder().jvm("path").build();
+        Options builder = new OptionsBuilder().parent(parent).jvm("path2").build();
+        Assert.assertEquals("path2", builder.getJvm().get());
+    }
+
+    @Test
+    public void testJVMArgs_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getJvmArgs().hasValue());
+    }
+
+    @Test
+    public void testJVMArgs_Parent() throws Exception {
+        Options parent = new OptionsBuilder().jvmArgs("opt1", "opt2").build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(Arrays.asList("opt1", "opt2"), builder.getJvmArgs().get());
+    }
+
+    @Test
+    public void testJVMArgs_Merge() throws Exception {
+        Options parent = new OptionsBuilder().jvmArgs("opt1", "opt2").build();
+        Options builder = new OptionsBuilder().parent(parent).jvmArgs("opt3", "opt4").build();
+        Assert.assertEquals(Arrays.asList("opt3", "opt4"), builder.getJvmArgs().get());
+    }
+
+    @Test
+    public void testOutput_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getOutput().hasValue());
+    }
+
+    @Test
+    public void testOutput_Parent() throws Exception {
+        Options parent = new OptionsBuilder().output("out1").build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals("out1", builder.getOutput().get());
+    }
+
+    @Test
+    public void testOutput_Merged() throws Exception {
+        Options parent = new OptionsBuilder().output("out1").build();
+        Options builder = new OptionsBuilder().parent(parent).output("out2").build();
+        Assert.assertEquals("out2", builder.getOutput().get());
+    }
+
+    @Test
+    public void testResult_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getResult().hasValue());
+    }
+
+    @Test
+    public void testResult_Parent() throws Exception {
+        Options parent = new OptionsBuilder().result("out1").build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals("out1", builder.getResult().get());
+    }
+
+    @Test
+    public void testResult_Merged() throws Exception {
+        Options parent = new OptionsBuilder().result("out1").build();
+        Options builder = new OptionsBuilder().parent(parent).result("out2").build();
+        Assert.assertEquals("out2", builder.getResult().get());
+    }
+
+    @Test
+    public void testResultFormat_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getResultFormat().hasValue());
+    }
+
+    @Test
+    public void testResultFormat_Parent() throws Exception {
+        Options parent = new OptionsBuilder().resultFormat(ResultFormatType.JSON).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(ResultFormatType.JSON, builder.getResultFormat().get());
+    }
+
+    @Test
+    public void testResultFormat_Merged() throws Exception {
+        Options parent = new OptionsBuilder().resultFormat(ResultFormatType.JSON).build();
+        Options builder = new OptionsBuilder().parent(parent).resultFormat(ResultFormatType.SCSV).build();
+        Assert.assertEquals(ResultFormatType.SCSV, builder.getResultFormat().get());
+    }
+
+    @Test
+    public void testRuntime_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getMeasurementTime().hasValue());
+    }
+
+    @Test
+    public void testRuntime_Parent() throws Exception {
+        Options parent = new OptionsBuilder().measurementTime(TimeValue.hours(42)).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(TimeValue.hours(42), builder.getMeasurementTime().get());
+    }
+
+    @Test
+    public void testRuntime_Merged() throws Exception {
+        Options parent = new OptionsBuilder().measurementTime(TimeValue.hours(42)).build();
+        Options builder = new OptionsBuilder().parent(parent).measurementTime(TimeValue.days(42)).build();
+        Assert.assertEquals(TimeValue.days(42), builder.getMeasurementTime().get());
+    }
+
+    @Test
+    public void testMeasureIters_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getMeasurementIterations().hasValue());
+    }
+
+    @Test
+    public void testMeasureIters_Parent() throws Exception {
+        Options parent = new OptionsBuilder().measurementIterations(42).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(Integer.valueOf(42), builder.getMeasurementIterations().get());
+    }
+
+    @Test
+    public void testMeasureIters_Merged() throws Exception {
+        Options parent = new OptionsBuilder().measurementIterations(42).build();
+        Options builder = new OptionsBuilder().parent(parent).measurementIterations(84).build();
+        Assert.assertEquals(Integer.valueOf(84), builder.getMeasurementIterations().get());
+    }
+
+    @Test
+    public void testSFOE_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.shouldFailOnError().hasValue());
+    }
+
+    @Test
+    public void testSFOE_Parent() throws Exception {
+        Options parent = new OptionsBuilder().shouldFailOnError(true).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(true, builder.shouldFailOnError().get());
+    }
+
+    @Test
+    public void testSFOE_Merged() throws Exception {
+        Options parent = new OptionsBuilder().shouldFailOnError(true).build();
+        Options builder = new OptionsBuilder().parent(parent).shouldFailOnError(false).build();
+        Assert.assertEquals(false, builder.shouldFailOnError().get());
+    }
+
+    @Test
+    public void testSyncIters_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.shouldSyncIterations().hasValue());
+    }
+
+    @Test
+    public void testSyncIters_Parent() throws Exception {
+        Options parent = new OptionsBuilder().syncIterations(true).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(true, builder.shouldSyncIterations().get());
+    }
+
+    @Test
+    public void testSyncIters_Merged() throws Exception {
+        Options parent = new OptionsBuilder().syncIterations(true).build();
+        Options builder = new OptionsBuilder().parent(parent).syncIterations(false).build();
+        Assert.assertEquals(false, builder.shouldSyncIterations().get());
+    }
+
+    @Test
+    public void testThreadGroups_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getThreadGroups().hasValue());
+    }
+
+    @Test
+    public void testThreadGroups_Parent() throws Exception {
+        Options parent = new OptionsBuilder().threadGroups(1, 2).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertArrayEquals(new int[]{1, 2}, builder.getThreadGroups().get());
+    }
+
+    @Test
+    public void testThreadGroups_Merged() throws Exception {
+        Options parent = new OptionsBuilder().threadGroups(1, 2).build();
+        Options builder = new OptionsBuilder().parent(parent).threadGroups(3, 4).build();
+        Assert.assertArrayEquals(new int[]{3, 4}, builder.getThreadGroups().get());
+    }
+
+    @Test
+    public void testThreads_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getThreads().hasValue());
+    }
+
+    @Test
+    public void testThreads_Parent() throws Exception {
+        Options parent = new OptionsBuilder().threads(42).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(Integer.valueOf(42), builder.getThreads().get());
+    }
+
+    @Test
+    public void testThreads_Merged() throws Exception {
+        Options parent = new OptionsBuilder().threads(42).build();
+        Options builder = new OptionsBuilder().parent(parent).threads(84).build();
+        Assert.assertEquals(Integer.valueOf(84), builder.getThreads().get());
+    }
+
+    @Test
+    public void testTimeUnit_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getTimeUnit().hasValue());
+    }
+
+    @Test
+    public void testTimeUnit_Parent() throws Exception {
+        Options parent = new OptionsBuilder().timeUnit(TimeUnit.DAYS).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(TimeUnit.DAYS, builder.getTimeUnit().get());
+    }
+
+    @Test
+    public void testTimeUnit_Merged() throws Exception {
+        Options parent = new OptionsBuilder().timeUnit(TimeUnit.DAYS).build();
+        Options builder = new OptionsBuilder().parent(parent).timeUnit(TimeUnit.HOURS).build();
+        Assert.assertEquals(TimeUnit.HOURS, builder.getTimeUnit().get());
+    }
+
+    @Test
+    public void testVerbose_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.verbosity().hasValue());
+    }
+
+    @Test
+    public void testVerbose_Parent() throws Exception {
+        Options parent = new OptionsBuilder().verbosity(VerboseMode.EXTRA).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(VerboseMode.EXTRA, builder.verbosity().get());
+    }
+
+    @Test
+    public void testVerbose_Merged() throws Exception {
+        Options parent = new OptionsBuilder().verbosity(VerboseMode.EXTRA).build();
+        Options builder = new OptionsBuilder().parent(parent).verbosity(VerboseMode.SILENT).build();
+        Assert.assertEquals(VerboseMode.SILENT, builder.verbosity().get());
+    }
+
+    @Test
+    public void testWarmupForks_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getWarmupForkCount().hasValue());
+    }
+
+    @Test
+    public void testWarmupForks_Parent() throws Exception {
+        Options parent = new OptionsBuilder().warmupForks(42).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(Integer.valueOf(42), builder.getWarmupForkCount().get());
+    }
+
+    @Test
+    public void testWarmupForks_Merge() throws Exception {
+        Options parent = new OptionsBuilder().warmupForks(42).build();
+        Options builder = new OptionsBuilder().parent(parent).warmupForks(84).build();
+        Assert.assertEquals(Integer.valueOf(84), builder.getWarmupForkCount().get());
+    }
+
+    @Test
+    public void testWarmupIters_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getWarmupIterations().hasValue());
+    }
+
+    @Test
+    public void testWarmupIters_Parent() throws Exception {
+        Options parent = new OptionsBuilder().warmupIterations(42).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(Integer.valueOf(42), builder.getWarmupIterations().get());
+    }
+
+    @Test
+    public void testWarmupIters_Merged() throws Exception {
+        Options parent = new OptionsBuilder().warmupIterations(42).build();
+        Options builder = new OptionsBuilder().parent(parent).warmupIterations(84).build();
+        Assert.assertEquals(Integer.valueOf(84), builder.getWarmupIterations().get());
+    }
+
+    @Test
+    public void testWarmupTime_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertFalse(builder.getWarmupTime().hasValue());
+    }
+
+    @Test
+    public void testWarmupTime_Parent() throws Exception {
+        Options parent = new OptionsBuilder().warmupTime(TimeValue.hours(42)).build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(TimeValue.hours(42), builder.getWarmupTime().get());
+    }
+
+    @Test
+    public void testWarmupTime_Merged() throws Exception {
+        Options parent = new OptionsBuilder().warmupTime(TimeValue.hours(42)).build();
+        Options builder = new OptionsBuilder().parent(parent).warmupTime(TimeValue.days(42)).build();
+        Assert.assertEquals(TimeValue.days(42), builder.getWarmupTime().get());
+    }
+
+    @Test
+    public void testWarmupMicros_Empty() throws Exception {
+        Options parent = new OptionsBuilder().build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertTrue(builder.getWarmupIncludes().isEmpty());
+    }
+
+    @Test
+    public void testWarmupMicros_Parent() throws Exception {
+        Options parent = new OptionsBuilder().includeWarmup(".*").build();
+        Options builder = new OptionsBuilder().parent(parent).build();
+        Assert.assertEquals(Arrays.asList(".*"), builder.getWarmupIncludes());
+    }
+
+    @Test
+    public void testWarmupMicros_Merged() throws Exception {
+        Options parent = new OptionsBuilder().includeWarmup(".*").build();
+        Options builder = new OptionsBuilder().parent(parent).includeWarmup(".*test.*").build();
+        Assert.assertEquals(Arrays.asList(".*test.*", ".*"), builder.getWarmupIncludes());
+    }
+
+}