Switch to new parameter syntax

The new syntax is:
.param p1, firstParamName

which is closer to the existing local syntax:
.local v0, someLocal:I
This commit is contained in:
Ben Gruver 2013-04-16 00:24:46 -07:00
parent 4a2b9ef40c
commit ec28400394
11 changed files with 394 additions and 66 deletions

View File

@ -756,14 +756,13 @@ the annotations. If it turns out that they are parameter annotations, we include
add them to the $statements_and_directives::methodAnnotations list*/
parameter_directive
@init {List<CommonTree> annotations = new ArrayList<CommonTree>();}
: PARAMETER_DIRECTIVE
STRING_LITERAL?
: PARAMETER_DIRECTIVE REGISTER COMMA simple_name
({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})*
( END_PARAMETER_DIRECTIVE
-> ^(I_PARAMETER[$start, "I_PARAMETER"] STRING_LITERAL? ^(I_ANNOTATIONS annotation*))
-> ^(I_PARAMETER[$start, "I_PARAMETER"] REGISTER simple_name ^(I_ANNOTATIONS annotation*))
| /*epsilon*/ {$statements_and_directives::methodAnnotations.addAll(annotations);}
-> ^(I_PARAMETER[$start, "I_PARAMETER"] STRING_LITERAL? ^(I_ANNOTATIONS))
-> ^(I_PARAMETER[$start, "I_PARAMETER"] REGISTER simple_name ^(I_ANNOTATIONS))
);
ordered_debug_directive

View File

@ -63,6 +63,7 @@ import org.jf.dexlib2.immutable.instruction.*;
import org.jf.dexlib2.immutable.reference.*;
import org.jf.dexlib2.immutable.value.*;
import org.jf.dexlib2.util.MethodUtil;
import org.jf.util.LinearSearch;
}
@ -341,6 +342,7 @@ method returns[Method ret]
int currentAddress;
HashMap<Integer, Integer> packedSwitchDeclarations;
HashMap<Integer, Integer> sparseSwitchDeclarations;
boolean isStatic;
int totalMethodRegisters;
int methodParameterRegisters;
}
@ -349,11 +351,11 @@ method returns[Method ret]
$method::totalMethodRegisters = 0;
$method::methodParameterRegisters = 0;
int accessFlags = 0;
boolean isStatic = false;
$method::labels = new HashMap<String, Integer>();
$method::currentAddress = 0;
$method::packedSwitchDeclarations = new HashMap<Integer, Integer>();
$method::sparseSwitchDeclarations = new HashMap<Integer, Integer>();
$method::isStatic = false;
}
:
^(I_METHOD
@ -361,8 +363,9 @@ method returns[Method ret]
access_list
{
accessFlags = $access_list.value;
isStatic = AccessFlags.STATIC.isSet(accessFlags);
$method::methodParameterRegisters = MethodUtil.getParameterRegisterCount($method_name_and_prototype.parameters, isStatic);
$method::isStatic = AccessFlags.STATIC.isSet(accessFlags);
$method::methodParameterRegisters =
MethodUtil.getParameterRegisterCount($method_name_and_prototype.parameters, $method::isStatic);
}
(registers_directive
{
@ -456,7 +459,7 @@ method returns[Method ret]
$ret = new ImmutableMethod(
classType,
$method_name_and_prototype.name,
$parameters.parameters,
$method_name_and_prototype.parameters,
$method_name_and_prototype.returnType,
accessFlags,
$annotations.annotations,
@ -470,11 +473,20 @@ method_prototype returns[List<String> parameters, String returnType]
$parameters = $field_type_list.types;
};
method_name_and_prototype returns[String name, List<String> parameters, String returnType]
method_name_and_prototype returns[String name, List<SmaliMethodParameter> parameters, String returnType]
: SIMPLE_NAME method_prototype
{
$name = $SIMPLE_NAME.text;
$parameters = $method_prototype.parameters;
$parameters = Lists.newArrayList();
int paramRegister = 0;
for (String type: $method_prototype.parameters) {
$parameters.add(new SmaliMethodParameter(paramRegister++, type));
char c = type.charAt(0);
if (c == 'J' || c == 'J') {
paramRegister++;
}
}
$returnType = $method_prototype.returnType;
};
@ -594,34 +606,42 @@ address returns[int address]
$address = Integer.parseInt($I_ADDRESS.text);
};
parameters[List<String> parameterTypes] returns[List<MethodParameter> parameters]
@init
{
Iterator<String> parameterIter = parameterTypes.iterator();
$parameters = Lists.newArrayList();
}
: ^(I_PARAMETERS (parameter[parameterIter] { $parameters.add($parameter.parameter); })*)
{
String paramType;
while (parameterIter.hasNext()) {
paramType = parameterIter.next();
$parameters.add(new ImmutableMethodParameter(paramType, null, null));
}
};
parameters[List<SmaliMethodParameter> parameters]
: ^(I_PARAMETERS (parameter[parameters])*);
parameter[Iterator<String> parameterTypes] returns[MethodParameter parameter]
: ^(I_PARAMETER string_literal? annotations
{
if (!$parameterTypes.hasNext()) {
throw new SemanticException(input, $I_PARAMETER, "Too many .parameter directives specified.");
}
String type = $parameterTypes.next();
String name = $string_literal.value;
Set<Annotation> annotations = $annotations.annotations;
parameter[List<SmaliMethodParameter> parameters]
: ^(I_PARAMETER REGISTER SIMPLE_NAME annotations)
{
final int registerNumber = parseRegister_short($REGISTER.text);
int totalMethodRegisters = $method::totalMethodRegisters;
int methodParameterRegisters = $method::methodParameterRegisters;
$parameter = new ImmutableMethodParameter(type, annotations, name);
if (registerNumber >= totalMethodRegisters) {
throw new SemanticException(input, $I_PARAMETER, "Register \%s is larger than the maximum register v\%d " +
"for this method", $REGISTER.text, totalMethodRegisters-1);
}
);
final int indexGuess = registerNumber - (totalMethodRegisters - methodParameterRegisters) - ($method::isStatic?0:1);
if (indexGuess < 0) {
throw new SemanticException(input, $I_PARAMETER, "Register \%s is not a parameter register.",
$REGISTER.text);
}
int parameterIndex = LinearSearch.linearSearch(parameters, SmaliMethodParameter.COMPARATOR,
new WithRegister() { public int getRegister() { return indexGuess; } },
indexGuess);
if (parameterIndex < 0) {
throw new SemanticException(input, $I_PARAMETER, "Register \%s is the second half of a wide parameter.",
$REGISTER.text);
}
SmaliMethodParameter methodParameter = parameters.get(parameterIndex);
methodParameter.name = $SIMPLE_NAME.text;
if ($annotations.annotations != null && $annotations.annotations.size() > 0) {
methodParameter.annotations = $annotations.annotations;
}
};
ordered_debug_directives returns[List<DebugItem> debugItems]
@init {debugItems = Lists.newArrayList();}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.smali;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Ints;
import org.jf.dexlib2.base.BaseMethodParameter;
import org.jf.dexlib2.iface.Annotation;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Comparator;
import java.util.Set;
public class SmaliMethodParameter extends BaseMethodParameter implements WithRegister {
public final int register;
@Nonnull public final String type;
@Nonnull public Set<? extends Annotation> annotations;
@Nullable public String name;
public SmaliMethodParameter(int register, @Nonnull String type) {
this.register = register;
this.type = type;
this.annotations = ImmutableSet.of();
}
@Override public int getRegister() { return register; }
@Nonnull @Override public String getType() { return type; }
@Nonnull @Override public Set<? extends Annotation> getAnnotations() { return annotations; }
@Nullable @Override public String getName() { return name; }
@Nullable @Override public String getSignature() { return null; }
public static final Comparator<WithRegister> COMPARATOR = new Comparator<WithRegister>() {
@Override public int compare(WithRegister o1, WithRegister o2) {
return Ints.compare(o1.getRegister(), o2.getRegister());
}
};
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.smali;
public interface WithRegister {
int getRegister();
}

View File

@ -254,8 +254,8 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
".catch" { return newToken(CATCH_DIRECTIVE); }
".catchall" { return newToken(CATCHALL_DIRECTIVE); }
".line" { return newToken(LINE_DIRECTIVE); }
".parameter" { return newToken(PARAMETER_DIRECTIVE); }
".end parameter" { return newToken(END_PARAMETER_DIRECTIVE); }
".param" { return newToken(PARAMETER_DIRECTIVE); }
".end param" { return newToken(END_PARAMETER_DIRECTIVE); }
".local" { return newToken(LOCAL_DIRECTIVE); }
".end local" { return newToken(END_LOCAL_DIRECTIVE); }
".restart local" { return newToken(RESTART_LOCAL_DIRECTIVE); }

View File

@ -23,8 +23,8 @@
.catch
.catchall
.line
.parameter
.end parameter
.param
.end param
.local
.end local
.restart local
@ -52,5 +52,7 @@
.
.1234.1234
.
.parameter
.end parameter

View File

@ -22,8 +22,8 @@ END_SPARSE_SWITCH_DIRECTIVE(".end sparse-switch")
CATCH_DIRECTIVE(".catch")
CATCHALL_DIRECTIVE(".catchall")
LINE_DIRECTIVE(".line")
PARAMETER_DIRECTIVE(".parameter")
END_PARAMETER_DIRECTIVE(".end parameter")
PARAMETER_DIRECTIVE(".param")
END_PARAMETER_DIRECTIVE(".end param")
LOCAL_DIRECTIVE(".local")
END_LOCAL_DIRECTIVE(".end local")
RESTART_LOCAL_DIRECTIVE(".restart local")
@ -61,4 +61,6 @@ INVALID_TOKEN(".end")
INVALID_TOKEN(".")
DOUBLE_LITERAL(".1234")
DOUBLE_LITERAL(".1234")
INVALID_TOKEN(".")
INVALID_TOKEN(".")
INVALID_TOKEN(".parameter")
INVALID_TOKEN(".end parameter")

View File

@ -100,7 +100,7 @@
# direct methods
.method constructor <init>(Lcom/android/internal/telephony/cdma/CDMAPhone;)V
.registers 2
.parameter "phone"
.param p1, phone
.prologue
.line 42
@ -112,7 +112,7 @@
.method protected getEFPath(I)Ljava/lang/String;
.registers 3
.parameter "efid"
.param p1, efid
.prologue
.line 71
@ -145,7 +145,7 @@
.method CardStateFromRILInt(I)Lcom/android/internal/telephony/IccCardStatus$CardState;
.registers 6
.parameter "state"
.param p1, state
.prologue
.line 59
@ -214,11 +214,11 @@
.method public setCallForwardingOption(IILjava/lang/String;ILandroid/os/Message;)V
.registers 13
.parameter "commandInterfaceCFAction"
.parameter "commandInterfaceCFReason"
.parameter "dialingNumber"
.parameter "timerSeconds"
.parameter "onComplete"
.param p1, commandInterfaceCFAction
.param p2, commandInterfaceCFReason
.param p3, dialingNumber
.param p4, timerSeconds
.param p5, onComplete
.prologue
const/4 v3, 0x1

View File

@ -266,8 +266,10 @@ CLOSE_PAREN(")")
VOID_TYPE("V")
REGISTERS_DIRECTIVE(".registers")
POSITIVE_INTEGER_LITERAL("2")
PARAMETER_DIRECTIVE(".parameter")
STRING_LITERAL("\"phone\"")
PARAMETER_DIRECTIVE(".param")
REGISTER("p1")
COMMA(",")
SIMPLE_NAME("phone")
PROLOGUE_DIRECTIVE(".prologue")
LINE_DIRECTIVE(".line")
POSITIVE_INTEGER_LITERAL("42")
@ -298,8 +300,10 @@ CLOSE_PAREN(")")
CLASS_DESCRIPTOR("Ljava/lang/String;")
REGISTERS_DIRECTIVE(".registers")
POSITIVE_INTEGER_LITERAL("3")
PARAMETER_DIRECTIVE(".parameter")
STRING_LITERAL("\"efid\"")
PARAMETER_DIRECTIVE(".param")
REGISTER("p1")
COMMA(",")
SIMPLE_NAME("efid")
PROLOGUE_DIRECTIVE(".prologue")
LINE_DIRECTIVE(".line")
POSITIVE_INTEGER_LITERAL("71")
@ -369,8 +373,10 @@ CLOSE_PAREN(")")
CLASS_DESCRIPTOR("Lcom/android/internal/telephony/IccCardStatus$CardState;")
REGISTERS_DIRECTIVE(".registers")
POSITIVE_INTEGER_LITERAL("6")
PARAMETER_DIRECTIVE(".parameter")
STRING_LITERAL("\"state\"")
PARAMETER_DIRECTIVE(".param")
REGISTER("p1")
COMMA(",")
SIMPLE_NAME("state")
PROLOGUE_DIRECTIVE(".prologue")
LINE_DIRECTIVE(".line")
POSITIVE_INTEGER_LITERAL("59")
@ -551,16 +557,26 @@ CLOSE_PAREN(")")
VOID_TYPE("V")
REGISTERS_DIRECTIVE(".registers")
POSITIVE_INTEGER_LITERAL("13")
PARAMETER_DIRECTIVE(".parameter")
STRING_LITERAL("\"commandInterfaceCFAction\"")
PARAMETER_DIRECTIVE(".parameter")
STRING_LITERAL("\"commandInterfaceCFReason\"")
PARAMETER_DIRECTIVE(".parameter")
STRING_LITERAL("\"dialingNumber\"")
PARAMETER_DIRECTIVE(".parameter")
STRING_LITERAL("\"timerSeconds\"")
PARAMETER_DIRECTIVE(".parameter")
STRING_LITERAL("\"onComplete\"")
PARAMETER_DIRECTIVE(".param")
REGISTER("p1")
COMMA(",")
SIMPLE_NAME("commandInterfaceCFAction")
PARAMETER_DIRECTIVE(".param")
REGISTER("p2")
COMMA(",")
SIMPLE_NAME("commandInterfaceCFReason")
PARAMETER_DIRECTIVE(".param")
REGISTER("p3")
COMMA(",")
SIMPLE_NAME("dialingNumber")
PARAMETER_DIRECTIVE(".param")
REGISTER("p4")
COMMA(",")
SIMPLE_NAME("timerSeconds")
PARAMETER_DIRECTIVE(".param")
REGISTER("p5")
COMMA(",")
SIMPLE_NAME("onComplete")
PROLOGUE_DIRECTIVE(".prologue")
INSTRUCTION_FORMAT11n("const/4")
REGISTER("v3")

View File

@ -0,0 +1,85 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.util;
import java.util.Comparator;
import java.util.List;
public class LinearSearch {
/**
* Performs a linear search in a sorted list for key, starting at initialGuess
*
* @param list The sorted list to search
* @param comparator The comparator to use
* @param key The key to search for
* @param initialGuess An initial guess of the location.
* @return If found, the index of the item. If not found, -return + 1 is the index at which the item would be
* inserted
*/
public static <T> int linearSearch(List<? extends T> list, Comparator<T> comparator, T key, int initialGuess) {
int guess = initialGuess;
if (guess >= list.size()) {
guess = list.size()-1;
}
int comparison = comparator.compare(list.get(guess), key);
if (comparison == 0) {
return guess;
}
if (comparison < 0) {
guess++;
while (guess < list.size()) {
comparison = comparator.compare(list.get(guess), key);
if (comparison == 0) {
return guess;
}
if (comparison > 0) {
return -(guess+1);
}
guess++;
}
return -(list.size()+1);
} else {
guess--;
while (guess >= 0) {
comparison = comparator.compare(list.get(guess), key);
if (comparison == 0) {
return guess;
}
if (comparison < 0) {
return -(guess+2);
}
guess--;
}
return -1;
}
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.util;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import junit.framework.Assert;
import org.junit.Test;
import java.util.List;
public class LinearSearchTest {
@Test
public void testLinearSearch() {
List<Integer> list = Lists.newArrayList(0, 1, 3, 4);
doTest(list, 5, 10);
doTest(list, 5, 4);
doTest(list, 5, 3);
doTest(list, 5, 2);
doTest(list, 5, 1);
doTest(list, 5, 0);
doTest(list, 4, 10);
doTest(list, 4, 4);
doTest(list, 4, 3);
doTest(list, 4, 2);
doTest(list, 4, 1);
doTest(list, 4, 0);
doTest(list, 3, 10);
doTest(list, 3, 4);
doTest(list, 3, 3);
doTest(list, 3, 2);
doTest(list, 3, 1);
doTest(list, 3, 0);
doTest(list, 2, 10);
doTest(list, 2, 4);
doTest(list, 2, 3);
doTest(list, 2, 2);
doTest(list, 2, 1);
doTest(list, 2, 0);
doTest(list, 1, 10);
doTest(list, 1, 4);
doTest(list, 1, 3);
doTest(list, 1, 2);
doTest(list, 1, 1);
doTest(list, 1, 0);
doTest(list, 0, 10);
doTest(list, 0, 4);
doTest(list, 0, 3);
doTest(list, 0, 2);
doTest(list, 0, 1);
doTest(list, 0, 0);
doTest(list, -1, 10);
doTest(list, -1, 4);
doTest(list, -1, 3);
doTest(list, -1, 2);
doTest(list, -1, 1);
doTest(list, -1, 0);
}
private void doTest(List<Integer> list, int key, int guess) {
int expectedIndex = Ordering.natural().binarySearch(list, key);
Assert.assertEquals(expectedIndex, LinearSearch.linearSearch(list, Ordering.<Integer>natural(), key, guess));
}
}