/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.google.security.zynamics.binnavi.disassembly.types;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.security.zynamics.binnavi.Database.Exceptions.CouldntLoadDataException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.Iterator;
import java.util.List;
/**
* Tests all methods related to {@link BaseType base types} without going through the type manager.
*/
@RunWith(JUnit4.class)
public class BaseTypeTest {
private TestTypeSystem typeSystem;
private BaseType testStruct;
private TypeMember testMember0;
private TypeMember testMember1;
private TypeMember testMember2;
private TypeMember testMember3;
private static final String NAME = "NAME";
private void addMembersAndVerifyOperation() {
final List<TypeMember> members =
Lists.newArrayList(testMember0, testMember1, testMember2, testMember3);
for (TypeMember member : members) {
testStruct.addMember(member);
}
assertEquals(testMember0.getBitSize() + testMember1.getBitSize() + testMember2.getBitSize()
+ testMember3.getBitSize(), testStruct.getBitSize());
assertEquals(4, testStruct.getMemberCount());
assertEquals(testMember3, testStruct.getLastMember());
}
@Before
public void initializeTypeSystem() throws CouldntLoadDataException {
typeSystem = new TestTypeSystem(new TypeManager(new TypeManagerMockBackend()));
// Note: type ids must not collide with the ones from RawTestTypeSystem so we start at 100.
int typeId = 100;
testStruct = new BaseType(++typeId, "test_struct", 0, false, BaseTypeCategory.STRUCT);
testMember0 = TypeMember.createStructureMember(++typeId, testStruct, typeSystem.uintType,
"testMember0", 0);
testMember1 = TypeMember.createStructureMember(++typeId, testStruct, typeSystem.uintType,
"testMember1", typeSystem.uintType.getBitSize());
testMember2 = TypeMember.createStructureMember(++typeId, testStruct, typeSystem.uintType,
"testMember2", testMember1.getBitOffset().get() + typeSystem.uintType.getBitSize());
testMember3 = TypeMember.createStructureMember(++typeId, testStruct, typeSystem.uintType,
"testMember3", testMember2.getBitOffset().get() + typeSystem.uintType.getBitSize());
}
@Test(expected = NullPointerException.class)
public void testAddMember_NullMember() {
testStruct.addMember(null);
}
@Test(expected = IllegalArgumentException.class)
public void testAddMember_OtherParent() {
testStruct.addMember(typeSystem.ssIntMember);
}
@Test
public void testAddMember3() {
testStruct.addMember(testMember0);
assertEquals(testMember0.getBitSize(), testStruct.getBitSize());
assertEquals(1, testStruct.getMemberCount());
assertEquals(testMember0, testStruct.getLastMember());
}
@Test
public void testAddMember4() {
testStruct.addMember(testMember0);
testStruct.addMember(testMember0);
testStruct.addMember(testMember0);
testStruct.addMember(testMember0);
assertEquals(testMember0.getBitSize(), testStruct.getBitSize());
assertEquals(1, testStruct.getMemberCount());
assertEquals(testMember0, testStruct.getLastMember());
}
@Test
public void testAddMember5() {
testStruct.addMember(testMember0);
testStruct.addMember(testMember1);
testStruct.addMember(testMember2);
testStruct.addMember(testMember3);
assertEquals(testMember0.getBitSize() + testMember1.getBitSize() + testMember2.getBitSize()
+ testMember3.getBitSize(), testStruct.getBitSize());
assertEquals(4, testStruct.getMemberCount());
assertEquals(testMember3, testStruct.getLastMember());
}
@Test
public void testAddMembers3() {
addMembersAndVerifyOperation();
}
@Test(expected = NullPointerException.class)
public void testAppendToPointerHierarchy1() {
BaseType.appendToPointerHierarchy(null, null);
}
@Test(expected = NullPointerException.class)
public void testAppendToPointerHierarchy2() {
BaseType.appendToPointerHierarchy(typeSystem.uintType, null);
}
@Test
public void testAppendToPointerHierarchy3() {
assertEquals(0, typeSystem.uintType.getPointerLevel());
assertEquals(0, typeSystem.intType.getPointerLevel());
BaseType.appendToPointerHierarchy(typeSystem.uintType, typeSystem.intType);
assertEquals(typeSystem.uintType, typeSystem.intType.pointsTo());
assertEquals(typeSystem.intType, typeSystem.uintType.pointedToBy());
assertEquals(1, typeSystem.intType.getPointerLevel());
assertEquals(0, typeSystem.uintType.getPointerLevel());
}
@Test(expected = IllegalArgumentException.class)
public void testAppendToPointerHierarchy4() {
assertEquals(0, typeSystem.uintType.getPointerLevel());
assertEquals(0, typeSystem.intType.getPointerLevel());
BaseType.appendToPointerHierarchy(typeSystem.uintType, typeSystem.intType);
assertEquals(typeSystem.uintType, typeSystem.intType.pointsTo());
assertEquals(typeSystem.intType, typeSystem.uintType.pointedToBy());
assertEquals(1, typeSystem.intType.getPointerLevel());
assertEquals(0, typeSystem.uintType.getPointerLevel());
BaseType.appendToPointerHierarchy(typeSystem.intType, typeSystem.uintType);
}
@Test(expected = IllegalArgumentException.class)
public void testBaseTypeConstructor1() {
new BaseType(-1, null, -1, false, BaseTypeCategory.ATOMIC);
}
@Test(expected = IllegalArgumentException.class)
public void testBaseTypeConstructor2() {
new BaseType(0, null, -1, false, BaseTypeCategory.ATOMIC);
}
@Test(expected = NullPointerException.class)
public void testBaseTypeConstructor3() {
new BaseType(1, null, -1, false, BaseTypeCategory.ATOMIC);
}
@Test(expected = IllegalArgumentException.class)
public void testBaseTypeConstructor4() {
new BaseType(1, NAME, -1, false, BaseTypeCategory.ATOMIC);
}
@Test
public void testBaseTypeConstructor5() {
final BaseType baseType = new BaseType(1, NAME, 4, false, BaseTypeCategory.ATOMIC);
// explicit
assertEquals(1, baseType.getId());
assertEquals(NAME, baseType.getName());
assertEquals(4, baseType.getBitSize());
assertEquals(1, baseType.getByteSize());
assertEquals(false, baseType.isSigned());
// implicit
assertNull(baseType.pointedToBy());
assertNull(baseType.pointsTo());
assertFalse(baseType.isStackFrame());
}
@Test
public void testDeleteMember1() {
addMembersAndVerifyOperation();
testStruct.deleteMember(testMember0);
assertEquals(testMember0.getBaseType().getBitSize() + testMember1.getBaseType().getBitSize()
+ testMember2.getBaseType().getBitSize() + testMember3.getBaseType().getBitSize(),
testStruct.getBitSize());
assertEquals(3, testStruct.getMemberCount());
}
@Test(expected = NullPointerException.class)
public void testDeleteMember2() {
addMembersAndVerifyOperation();
testStruct.deleteMember(null);
}
@Test
public void testSetSize_Atomic() {
typeSystem.intType.setSize(123);
assertEquals(123, typeSystem.intType.getBitSize());
}
@Test
public void testSetSize_Pointer() {
typeSystem.uintPointerType.setSize(123);
assertEquals(123, typeSystem.uintPointerType.getBitSize());
}
@Test(expected = IllegalArgumentException.class)
public void testSetSize_Array() {
typeSystem.uintArrayType.setSize(100);
}
@Test(expected = IllegalArgumentException.class)
public void testSetSize_Struct() {
typeSystem.simpleStruct.setSize(123);
}
@Test(expected = IllegalArgumentException.class)
public void testSetSize_Union() {
typeSystem.simpleUnion.setSize(123);
}
@Test(expected = IllegalArgumentException.class)
public void testSetSize_Prototype() {
typeSystem.voidFunctionPrototype.setSize(123);
}
@Test(expected = IllegalArgumentException.class)
public void testSetSize_Negative() {
typeSystem.uintType.setSize(-1);
}
@Test
public void testSetSize_Zero() {
typeSystem.uintType.setSize(0);
assertEquals(0, typeSystem.uintType.getBitSize());
}
@Test
public void testGetBitSize_Atomic() {
assertEquals(32, typeSystem.intType.getBitSize());
}
@Test
public void testGetBitSize_Pointer() {
assertEquals(32, typeSystem.uintPointerType.getBitSize());
}
@Test
public void testGetBitSize_Array() {
assertEquals(10 * 32, typeSystem.uintArrayType.getBitSize());
}
@Test
public void testGetBitSize_Struct() {
assertEquals(10 * 32 + 32 + 32, typeSystem.simpleStruct.getBitSize());
}
@Test
public void testGetBitSize_Union() {
assertEquals(typeSystem.uintArrayType.getBitSize(), typeSystem.simpleUnion.getBitSize());
assertEquals(typeSystem.doubleNestedStruct.getBitSize(), typeSystem.complexUnion.getBitSize());
}
@Test
public void testGetBitSize_Prototype() {
assertEquals(0, typeSystem.voidFunctionPrototype.getBitSize());
}
@Test
public void testGetByteSize() {
assertEquals(4, typeSystem.uintType.getByteSize());
}
@Test
public void testGetLastMember1() {
assertNull(typeSystem.uintType.getLastMember());
}
@Test
public void testGetLastMember2() {
addMembersAndVerifyOperation();
assertEquals(testMember3, testStruct.getLastMember());
}
@Test
public void testGetMemberCount() {
assertEquals(0, typeSystem.uintType.getMemberCount());
addMembersAndVerifyOperation();
assertEquals(4, testStruct.getMemberCount());
}
@Test
public void testGetPointerLevel() {
assertEquals(0, typeSystem.uintType.getPointerLevel());
assertEquals(0, typeSystem.intType.getPointerLevel());
BaseType.appendToPointerHierarchy(typeSystem.uintType, typeSystem.intType);
assertEquals(0, typeSystem.uintType.getPointerLevel());
assertEquals(1, typeSystem.intType.getPointerLevel());
}
@Test(expected = NullPointerException.class)
public void testGetPointerTypeName1() {
BaseType.getPointerTypeName(null, 0);
}
@Test(expected = IllegalArgumentException.class)
public void testGetPointerTypeName2() {
BaseType.getPointerTypeName(typeSystem.uintType, 0);
}
@Test
public void testGetPointerTypeName3() {
final String pointerName = BaseType.getPointerTypeName(typeSystem.uintType, 10);
assertEquals(typeSystem.uintType.getName() + " " + Strings.repeat("*", 10), pointerName);
}
@Test(expected = NullPointerException.class)
public void testGetValueType1() {
BaseType.getValueType(null);
}
@Test
public void testGetValueType2() {
BaseType.appendToPointerHierarchy(typeSystem.uintType, typeSystem.intType);
assertEquals(typeSystem.uintType, BaseType.getValueType(typeSystem.intType));
}
@Test(expected = NullPointerException.class)
public void testGetValueTypeName1() {
BaseType.getValueTypeName(null);
}
@Test
public void testGetValueTypeName2() {
BaseType.appendToPointerHierarchy(typeSystem.uintType, typeSystem.intType);
assertEquals(typeSystem.uintType.getName(), BaseType.getValueTypeName(typeSystem.intType));
}
@Test
public void testGetValueTypeName3() {
assertEquals(typeSystem.intType.getName(), BaseType.getValueTypeName(typeSystem.intType));
}
@Test
public void testHasMembers() {
assertEquals(false, testStruct.hasMembers());
addMembersAndVerifyOperation();
assertEquals(true, testStruct.hasMembers());
}
@Test
public void testIterator() {
addMembersAndVerifyOperation();
int offset = 0;
for (final TypeMember member : testStruct) {
Preconditions.checkArgument(member.getBitOffset().get() >= offset);
offset = member.getBitOffset().get();
}
}
@Test
public void testMoveMemberInBetween() {
typeSystem.simpleStruct.moveMembers(Sets.newTreeSet(typeSystem.ssIntMember), 32);
assertEquals(Integer.valueOf(0), typeSystem.ssUintMember.getBitOffset().get());
assertEquals(Integer.valueOf(32), typeSystem.ssIntMember.getBitOffset().get());
assertEquals(Integer.valueOf(64), typeSystem.ssArrayMember.getBitOffset().get());
}
@Test(expected = IllegalArgumentException.class)
public void testMoveMemberInvalid1() {
typeSystem.simpleStruct.moveMembers(Sets.newTreeSet(typeSystem.ssIntMember), -100);
}
@Test(expected = IllegalArgumentException.class)
public void testMoveMemberInvalid2() {
typeSystem.simpleStruct.moveMembers(
Sets.newTreeSet(typeSystem.ssIntMember, typeSystem.ssUintMember), 999);
}
@Test
public void testMoveMembersToBeginning() {
typeSystem.simpleStruct.moveMembers(
Sets.newTreeSet(typeSystem.ssUintMember, typeSystem.ssArrayMember), -32);
assertEquals(Integer.valueOf(0), typeSystem.ssUintMember.getBitOffset().get());
assertEquals(Integer.valueOf(32), typeSystem.ssArrayMember.getBitOffset().get());
assertEquals(Integer.valueOf(352), typeSystem.ssIntMember.getBitOffset().get());
}
@Test
public void testMoveMembersToBeginningReverse() {
typeSystem.simpleStruct.moveMembers(
Sets.newTreeSet(typeSystem.ssArrayMember, typeSystem.ssUintMember), -32);
assertEquals(Integer.valueOf(0), typeSystem.ssUintMember.getBitOffset().get());
assertEquals(Integer.valueOf(32), typeSystem.ssArrayMember.getBitOffset().get());
assertEquals(Integer.valueOf(352), typeSystem.ssIntMember.getBitOffset().get());
}
@Test
public void testMoveMembersToEnd() {
typeSystem.simpleStruct.moveMembers(
Sets.<TypeMember>newTreeSet(typeSystem.ssIntMember, typeSystem.ssUintMember), 320);
assertEquals(Integer.valueOf(320), typeSystem.ssIntMember.getBitOffset().get());
assertEquals(Integer.valueOf(352), typeSystem.ssUintMember.getBitOffset().get());
assertEquals(Integer.valueOf(0), typeSystem.ssArrayMember.getBitOffset().get());
}
@Test
public void testMoveMembersToEndReverse() {
typeSystem.simpleStruct.moveMembers(
Sets.newTreeSet(typeSystem.ssUintMember, typeSystem.ssIntMember), 320);
assertEquals(Integer.valueOf(320), typeSystem.ssIntMember.getBitOffset().get());
assertEquals(Integer.valueOf(352), typeSystem.ssUintMember.getBitOffset().get());
assertEquals(Integer.valueOf(0), typeSystem.ssArrayMember.getBitOffset().get());
}
@Test
public void testMoveMemberToBeginning() {
typeSystem.simpleStruct.moveMembers(Sets.newTreeSet(typeSystem.ssUintMember), -32);
assertEquals(Integer.valueOf(0), typeSystem.ssUintMember.getBitOffset().get());
assertEquals(Integer.valueOf(32), typeSystem.ssIntMember.getBitOffset().get());
assertEquals(Integer.valueOf(64), typeSystem.ssArrayMember.getBitOffset().get());
}
@Test
public void testMoveMemberToEnd() {
typeSystem.simpleStruct.moveMembers(Sets.newTreeSet(typeSystem.ssIntMember), 64);
assertEquals(Integer.valueOf(0), typeSystem.ssUintMember.getBitOffset().get());
assertEquals(Integer.valueOf(32), typeSystem.ssArrayMember.getBitOffset().get());
assertEquals(Integer.valueOf(64), typeSystem.ssIntMember.getBitOffset().get());
}
@Test
public void testSetIsStackFrame() {
typeSystem.uintType.setIsStackFrame(true);
assertEquals(true, typeSystem.uintType.isStackFrame());
typeSystem.uintType.setIsStackFrame(false);
assertEquals(false, typeSystem.uintType.isStackFrame());
}
@Test(expected = NullPointerException.class)
public void testSetName1() {
typeSystem.uintType.setName(null);
}
@Test
public void testSetName2() {
typeSystem.uintType.setName("NEW NAME");
assertEquals("NEW NAME", typeSystem.uintType.getName());
}
@Test
public void testSetSigned() {
typeSystem.uintType.setSigned(true);
assertEquals(true, typeSystem.uintType.isSigned());
typeSystem.uintType.setSigned(false);
assertEquals(false, typeSystem.uintType.isSigned());
}
@Test(expected = IllegalArgumentException.class)
public void testGetSubsequentMembers_Underflow() {
typeSystem.simpleStruct.getSubsequentMembersInclusive(-1);
}
@Test
public void testGetSubsequentMembers_FirstMember() {
ImmutableList<TypeMember> expectedMembers = ImmutableList.<TypeMember>of(typeSystem.ssIntMember,
typeSystem.ssUintMember, typeSystem.ssArrayMember);
assertEquals(expectedMembers, typeSystem.simpleStruct.getSubsequentMembersInclusive(0));
}
@Test
public void testGetSubsequentMembers_SecondMember() {
final ImmutableList<TypeMember> members = typeSystem.simpleStruct.getSubsequentMembersInclusive(
typeSystem.ssUintMember.getBitOffset().get());
final ImmutableList<TypeMember> expectedMembers =
ImmutableList.<TypeMember>of(typeSystem.ssUintMember, typeSystem.ssArrayMember);
assertEquals(expectedMembers, members);
}
@Test
public void testGetSubsequentMembers_ThirdMember() {
final ImmutableList<TypeMember> members = typeSystem.simpleStruct.getSubsequentMembersInclusive(
typeSystem.ssArrayMember.getBitOffset().get());
final ImmutableList<TypeMember> expectedMembers =
ImmutableList.<TypeMember>of(typeSystem.ssArrayMember);
assertEquals(expectedMembers, members);
}
@Test
public void testGetSubsequentMembers_PastEnd() {
final ImmutableList<TypeMember> members =
typeSystem.simpleStruct.getSubsequentMembersInclusive(typeSystem.simpleStruct.getBitSize());
assertEquals(ImmutableList.<TypeMember>of(), members);
}
@Test
public void testMemberOrderingConsistency0() {
typeSystem.ssIntMember.setOffset(Optional.<Integer>of(typeSystem.simpleStruct.getBitSize()));
final Iterator<TypeMember> iterator = typeSystem.simpleStruct.iterator();
assertEquals(typeSystem.ssUintMember, iterator.next());
assertEquals(typeSystem.ssArrayMember, iterator.next());
assertEquals(typeSystem.ssIntMember, iterator.next());
}
@Test
public void testMemberOrderingConsistency1() {
typeSystem.ssUintMember.setOffset(Optional.<Integer>of(typeSystem.simpleStruct.getBitSize()));
final Iterator<TypeMember> iterator = typeSystem.simpleStruct.iterator();
assertEquals(typeSystem.ssIntMember, iterator.next());
assertEquals(typeSystem.ssArrayMember, iterator.next());
assertEquals(typeSystem.ssUintMember, iterator.next());
}
@Test
public void testMemberOrderingConsistency2() {
typeSystem.ssArrayMember.setOffset(Optional.<Integer>of(typeSystem.simpleStruct.getBitSize()));
final Iterator<TypeMember> iterator = typeSystem.simpleStruct.iterator();
assertEquals(typeSystem.ssIntMember, iterator.next());
assertEquals(typeSystem.ssUintMember, iterator.next());
assertEquals(typeSystem.ssArrayMember, iterator.next());
}
}