blob: 6fb2234df9c230d0528b5443bffa5b62e71b1720 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![cfg(test)]
use {
assert_matches::assert_matches,
fidl_fuchsia_io as fio,
fuchsia_archive::{ChunkType, Error, Reader, DIR_CHUNK_TYPE, DIR_NAMES_CHUNK_TYPE},
std::{fs::File, path::Path},
};
const ALL_ZEROES_CHUNK_TYPE: ChunkType = [0u8; 8];
// Creates a test fn named after the first parameter that:
// 1. opens a FAR file named after the first parameter
// 2. calls fuchsia_archive::Reader::new on the file
// 3. asserts that the new() result matches the second parameter
// And also an async version of the same test using fuchsia_archive::AsyncReader.
macro_rules! tests {
( $( $fn:ident => $err:pat $(if $guard:expr)? , )+ ) => {
$(
#[test]
fn $fn() {
let mut filename = stringify!($fn).replace("_", "-");
filename.push_str(".far");
let file = File::open(Path::new("/pkg/data/invalid-fars").join(filename)).unwrap();
assert_matches!(Reader::new(file), $err $(if $guard)?);
}
)+
mod async_tests {
use {
super::*,
fuchsia_async as fasync,
fuchsia_archive::AsyncReader,
assert_matches::assert_matches,
};
$(
#[fasync::run_singlethreaded(test)]
async fn $fn() {
let mut filename = stringify!($fn).replace("_", "-");
filename.push_str(".far");
let path = Path::new("/pkg/data/invalid-fars").join(filename);
let file = fuchsia_fs::file::open_in_namespace(
path.to_str().unwrap(),
fio::OpenFlags::RIGHT_READABLE,
)
.unwrap();
let reader = fuchsia_fs::file::AsyncFile::from_proxy(file);
assert_matches!(AsyncReader::new(reader).await, $err $(if $guard)?);
}
)+
}
};
}
tests! {
invalid_magic_bytes => Err(Error::InvalidMagic([0, 0, 0, 0, 0, 0, 0, 0])),
index_entries_length_not_a_multiple_of_24_bytes => Err(Error::InvalidIndexEntriesLen(49)),
directory_names_index_entry_before_directory_index_entry =>
Err(Error::IndexEntriesOutOfOrder { prev: DIR_NAMES_CHUNK_TYPE, next: DIR_CHUNK_TYPE }),
two_directory_index_entries =>
Err(Error::IndexEntriesOutOfOrder { prev: DIR_CHUNK_TYPE, next: DIR_CHUNK_TYPE }),
two_directory_names_index_entries =>
Err(Error::IndexEntriesOutOfOrder {
prev: DIR_NAMES_CHUNK_TYPE,
next: DIR_NAMES_CHUNK_TYPE
}),
duplicate_index_entries_of_unknown_type =>
Err(Error::IndexEntriesOutOfOrder {
prev: ALL_ZEROES_CHUNK_TYPE,
next: ALL_ZEROES_CHUNK_TYPE
}),
no_index_entries => Err(Error::MissingDirectoryChunkIndexEntry),
no_directory_index_entry => Err(Error::MissingDirectoryChunkIndexEntry),
no_directory_names_index_entry => Err(Error::MissingDirectoryNamesChunkIndexEntry),
directory_chunk_length_not_a_multiple_of_32_bytes => Err(Error::InvalidDirectoryChunkLen(40)),
directory_chunk_not_tightly_packed =>
Err(Error::InvalidChunkOffset { chunk_type: DIR_CHUNK_TYPE, expected: 64, actual: 72 }),
path_data_offset_too_large =>
Err(Error::PathDataOffsetTooLarge { entry_index: 0, offset: 9, chunk_size: 8 }),
path_data_length_too_large =>
Err(Error::PathDataLengthTooLarge { entry_index: 0, offset: 0, length: 9, chunk_size: 8 }),
directory_entries_not_sorted =>
Err(Error::DirectoryEntriesOutOfOrder { entry_index: 1, name, previous_name})
if name == b"a" && previous_name == b"b",
directory_entries_with_same_name =>
Err(Error::DirectoryEntriesOutOfOrder { entry_index: 1, name, previous_name})
if name == b"a" && previous_name == b"a",
directory_names_chunk_length_not_a_multiple_of_8_bytes =>
Err(Error::InvalidDirectoryNamesChunkLen(1)),
directory_names_chunk_not_tightly_packed =>
Err(Error::InvalidChunkOffset {
chunk_type: DIR_NAMES_CHUNK_TYPE,
expected: 96,
actual: 104
}),
directory_names_chunk_before_directory_chunk =>
Err(Error::InvalidChunkOffset { chunk_type: DIR_CHUNK_TYPE, expected: 64, actual: 72 }),
directory_names_chunk_overlaps_directory_chunk =>
Err(Error::InvalidChunkOffset {
chunk_type: DIR_NAMES_CHUNK_TYPE,
expected: 96,
actual: 88
}),
zero_length_name => Err(Error::ZeroLengthName),
name_with_null_character => Err(Error::NameContainsNull(name)) if name == b"\0",
name_with_leading_slash => Err(Error::NameStartsWithSlash(name)) if name == b"/a",
name_with_trailing_slash => Err(Error::NameEndsWithSlash(name)) if name == b"a/",
name_with_empty_segment =>
Err(Error::NameContainsEmptySegment(name)) if name == b"a//a",
name_with_dot_segment =>
Err(Error::NameContainsDotSegment(name)) if name == b"a/./a",
name_with_dot_dot_segment =>
Err(Error::NameContainsDotDotSegment(name)) if name == b"a/../a",
content_chunk_starts_early =>
Err(Error::InvalidContentChunkOffset{name, expected: 4096, actual: 4095})
if name == b"a",
content_chunk_starts_late =>
Err(Error::InvalidContentChunkOffset{name, expected: 4096, actual: 4097})
if name == b"a",
second_content_chunk_starts_early =>
Err(Error::InvalidContentChunkOffset{name, expected: 8192, actual: 8191})
if name == b"b",
second_content_chunk_starts_late =>
Err(Error::InvalidContentChunkOffset{name, expected: 8192, actual: 8193})
if name == b"b",
content_chunk_not_zero_padded =>
Err(Error::ContentChunkBeyondArchive{name, lower_bound: 8192, archive_size: 4097})
if name == b"a",
content_chunk_overlap =>
Err(Error::InvalidContentChunkOffset{name, expected: 12288, actual: 8192})
if name == b"b",
content_chunk_not_tightly_packed =>
Err(Error::InvalidContentChunkOffset{name, expected: 4096, actual: 8192})
if name == b"a",
content_chunk_offset_past_end_of_file =>
Err(Error::ContentChunkBeyondArchive{
name,
lower_bound: 4096,
archive_size: 104})
if name == b"a",
}