• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.caliper.runner;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.fail;
21 
22 import com.google.caliper.Benchmark;
23 import com.google.caliper.Param;
24 import com.google.caliper.config.InvalidConfigurationException;
25 import com.google.caliper.util.InvalidCommandException;
26 
27 import junit.framework.AssertionFailedError;
28 
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 import org.junit.runners.JUnit4;
32 
33 import java.io.PrintWriter;
34 import java.io.StringWriter;
35 
36 /**
37  * Unit test covering common user mistakes in benchmark classes.
38  */
39 @RunWith(JUnit4.class)
40 
41 public class MalformedBenchmarksTest {
42   // Put the expected messages together here, which may promote some kind of
43   // consistency in their wording. :)
44 
45   private static final String ABSTRACT =
46       "Class '%s' is abstract";
47   private static final String NO_CONSTRUCTOR =
48       "Benchmark class %s does not have a publicly visible default constructor";
49   private static final String NO_METHODS =
50       "There were no experiments to be performed for the class %s using the instruments " +
51       "[allocation, runtime]";
52   private static final String STATIC_BENCHMARK =
53       "Benchmark methods must not be static: timeIt";
54   private static final String WRONG_ARGUMENTS =
55       "Benchmark methods must have no arguments or accept a single int or long parameter: timeIt";
56   private static final String STATIC_PARAM =
57       "Parameter field 'oops' must not be static";
58   private static final String RESERVED_PARAM =
59       "Class '%s' uses reserved parameter name 'vm'";
60   private static final String NO_CONVERSION = "Type 'Object' of parameter field 'oops' "
61       + "has no recognized String-converting method; see <TODO> for details";
62   private static final String CONVERT_FAILED = // granted this one's a little weird (and brittle)
63       "Cannot convert value 'oops' to type 'int': For input string: \"oops\"";
64 
abstractBenchmark()65   @Test public void abstractBenchmark() throws Exception {
66     expectException(ABSTRACT, AbstractBenchmark.class);
67   }
68   abstract static class AbstractBenchmark {}
69 
noSuitableConstructor()70   @Test public void noSuitableConstructor() throws Exception {
71     expectException(String.format(NO_CONSTRUCTOR, BadConstructorBenchmark.class.getName()),
72         BadConstructorBenchmark.class);
73   }
74 
75   @SuppressWarnings("unused")
76   static class BadConstructorBenchmark {
BadConstructorBenchmark(String damnParam)77     BadConstructorBenchmark(String damnParam) {}
timeIt(int reps)78     @Benchmark void timeIt(int reps) {}
79   }
80 
noBenchmarkMethods()81   @Test public void noBenchmarkMethods() throws Exception {
82     expectException(NO_METHODS, NoMethodsBenchmark.class);
83   }
84 
85   @SuppressWarnings("unused")
86   static class NoMethodsBenchmark {
timeIt(int reps)87     void timeIt(int reps) {} // not annotated
88   }
89 
staticBenchmarkMethod()90   @Test public void staticBenchmarkMethod() throws Exception {
91     expectException(STATIC_BENCHMARK, StaticBenchmarkMethodBenchmark.class);
92   }
93 
94   @SuppressWarnings("unused")
95   static class StaticBenchmarkMethodBenchmark {
timeIt(int reps)96     @Benchmark public static void timeIt(int reps) {}
97   }
98 
wrongSignature()99   @Test public void wrongSignature() throws Exception {
100     expectException(WRONG_ARGUMENTS, BoxedParamBenchmark.class);
101     expectException(WRONG_ARGUMENTS, ExtraParamBenchmark.class);
102   }
103 
104   @SuppressWarnings("unused")
105   static class BoxedParamBenchmark {
timeIt(Integer reps)106     @Benchmark void timeIt(Integer reps) {}
107   }
108 
109   @SuppressWarnings("unused")
110   static class ExtraParamBenchmark {
timeIt(int reps, int what)111     @Benchmark void timeIt(int reps, int what) {}
112   }
113 
hasBenchmarkOverloads()114   @Test public void hasBenchmarkOverloads() throws Exception {
115     // N.B. baz is fine since although it has an overload, its overload is not a benchmark method.
116     expectException(
117         "Overloads are disallowed for benchmark methods, found overloads of [bar, foo] in "
118         + "benchmark OverloadsAnnotatedBenchmark",
119         OverloadsAnnotatedBenchmark.class);
120   }
121 
122   @SuppressWarnings("unused")
123   static class OverloadsAnnotatedBenchmark {
foo(long reps)124     @Benchmark public void foo(long reps) {}
foo(int reps)125     @Benchmark public void foo(int reps) {}
bar(long reps)126     @Benchmark public void bar(long reps) {}
bar(int reps)127     @Benchmark public void bar(int reps) {}
baz(int reps)128     @Benchmark public void baz(int reps) {}
baz(long reps, boolean thing)129     public void baz(long reps, boolean thing) {}
baz(long reps)130     public void baz(long reps) {}
131   }
132 
staticParam()133   @Test public void staticParam() throws Exception {
134     expectException(STATIC_PARAM, StaticParamBenchmark.class);
135   }
136   static class StaticParamBenchmark {
137     @Param static String oops;
138   }
139 
reservedParameterName()140   @Test public void reservedParameterName() throws Exception {
141     expectException(RESERVED_PARAM, ReservedParamBenchmark.class);
142   }
143   static class ReservedParamBenchmark {
144     @Param String vm;
145   }
146 
unparsableParamType()147   @Test public void unparsableParamType() throws Exception {
148     expectException(NO_CONVERSION, UnparsableParamTypeBenchmark.class);
149   }
150   static class UnparsableParamTypeBenchmark {
151     @Param Object oops;
152   }
153 
unparsableParamDefault()154   @Test public void unparsableParamDefault() throws Exception {
155     expectException(CONVERT_FAILED, UnparsableParamDefaultBenchmark.class);
156   }
157   static class UnparsableParamDefaultBenchmark {
158     @Param({"1", "2", "oops"}) int number;
159   }
160 
161   // end of tests
162 
expectException(String expectedMessageFmt, Class<?> benchmarkClass)163   private void expectException(String expectedMessageFmt, Class<?> benchmarkClass)
164       throws InvalidCommandException, InvalidConfigurationException {
165     try {
166       CaliperMain.exitlessMain(
167           new String[] {"--instrument=allocation,runtime", "--dry-run", benchmarkClass.getName()},
168           new PrintWriter(new StringWriter()), new PrintWriter(new StringWriter()));
169       fail("no exception thrown");
170     } catch (InvalidBenchmarkException e) {
171       try {
172         String expectedMessageText =
173             String.format(expectedMessageFmt, benchmarkClass.getSimpleName());
174         assertEquals(expectedMessageText, e.getMessage());
175 
176         // don't swallow our real stack trace
177       } catch (AssertionFailedError afe) {
178         afe.initCause(e);
179         throw afe;
180       }
181     }
182   }
183 }
184