blob: 4fa73028ece16ce9fbf17f1051866793af051a1d [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* 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.android.server.integrity.model;
import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START;
import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END;
import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START;
import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS;
import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS;
import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS;
import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS;
import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
import static com.android.server.integrity.utils.TestUtils.getBits;
import static com.android.server.integrity.utils.TestUtils.getBytes;
import static com.android.server.integrity.utils.TestUtils.getValueBits;
import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.assertThrows;
import android.content.integrity.AtomicFormula;
import android.content.integrity.CompoundFormula;
import android.content.integrity.Rule;
import com.android.server.integrity.parser.BinaryFileOperations;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.io.IOException;
@RunWith(JUnit4.class)
public class BitTrackedInputStreamTest {
private static final String COMPOUND_FORMULA_START_BITS =
getBits(COMPOUND_FORMULA_START, SEPARATOR_BITS);
private static final String COMPOUND_FORMULA_END_BITS =
getBits(COMPOUND_FORMULA_END, SEPARATOR_BITS);
private static final String ATOMIC_FORMULA_START_BITS =
getBits(ATOMIC_FORMULA_START, SEPARATOR_BITS);
private static final String NOT = getBits(CompoundFormula.NOT, CONNECTOR_BITS);
private static final String PACKAGE_NAME = getBits(AtomicFormula.PACKAGE_NAME, KEY_BITS);
private static final String EQ = getBits(AtomicFormula.EQ, OPERATOR_BITS);
private static final String DENY = getBits(Rule.DENY, EFFECT_BITS);
private static final String IS_NOT_HASHED = "0";
private static final String START_BIT = "1";
private static final String END_BIT = "1";
@Test
public void testBitOperationsCountBitsCorrectly() throws IOException {
String packageName = "com.test.app";
byte[] testInput =
getBytes(
START_BIT
+ COMPOUND_FORMULA_START_BITS
+ NOT
+ ATOMIC_FORMULA_START_BITS
+ PACKAGE_NAME
+ EQ
+ IS_NOT_HASHED
+ getBits(packageName.length(), VALUE_SIZE_BITS)
+ getValueBits(packageName)
+ COMPOUND_FORMULA_END_BITS
+ DENY
+ END_BIT);
BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(testInput);
// Right after construction, the read bits count should be 0.
assertThat(bitTrackedInputStream.getReadBitsCount()).isEqualTo(0);
// Get next 10 bits should result with 10 bits read.
bitTrackedInputStream.getNext(10);
assertThat(bitTrackedInputStream.getReadBitsCount()).isEqualTo(10);
// When we move the cursor 8 bytes, we should point to 64 bits.
bitTrackedInputStream.setCursorToByteLocation(8);
assertThat(bitTrackedInputStream.getReadBitsCount()).isEqualTo(64);
// Read until the end and the total size of the input stream should be available.
while (bitTrackedInputStream.hasNext()) {
bitTrackedInputStream.getNext(1);
}
assertThat(bitTrackedInputStream.getReadBitsCount()).isEqualTo(128);
}
@Test
public void testBitInputStreamOperationsStillWork() throws IOException {
String packageName = "com.test.app";
byte[] testInput =
getBytes(
IS_NOT_HASHED
+ getBits(packageName.length(), VALUE_SIZE_BITS)
+ getValueBits(packageName));
BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(testInput);
assertThat(bitTrackedInputStream.getReadBitsCount()).isEqualTo(0);
// Read until the string parameter.
String stringValue = BinaryFileOperations.getStringValue(bitTrackedInputStream);
// Verify that the read bytes are counted.
assertThat(stringValue).isEqualTo(packageName);
assertThat(bitTrackedInputStream.getReadBitsCount()).isGreaterThan(0);
}
@Test
public void testBitTrackedInputStream_canReadMoreRules() throws IOException {
String packageName = "com.test.app";
byte[] testInput =
getBytes(
IS_NOT_HASHED
+ getBits(packageName.length(), VALUE_SIZE_BITS)
+ getValueBits(packageName));
BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(testInput);
assertThat(bitTrackedInputStream.canReadMoreRules(2)).isTrue();
// Read until the string parameter.
String stringValue = BinaryFileOperations.getStringValue(bitTrackedInputStream);
// Verify that the read bytes are counted.
assertThat(stringValue).isEqualTo(packageName);
assertThat(bitTrackedInputStream.canReadMoreRules(2)).isFalse();
}
@Test
public void testBitTrackedInputStream_moveCursorForwardFailsIfAlreadyRead() throws IOException {
String packageName = "com.test.app";
byte[] testInput =
getBytes(
IS_NOT_HASHED
+ getBits(packageName.length(), VALUE_SIZE_BITS)
+ getValueBits(packageName));
BitTrackedInputStream bitTrackedInputStream = new BitTrackedInputStream(testInput);
// Read more than two bytes.
bitTrackedInputStream.getNext(20);
// Ask to move the cursor to the second byte.
assertThrows(
IllegalStateException.class,
() -> bitTrackedInputStream.setCursorToByteLocation(2));
}
}