test: add aaruf_identify and aaruf_identify_stream tests

15 tests covering the image identification API:

- Happy path: valid V1 and V2 images via both file path and stream
- Error handling: NULL stream, empty file, truncated header
- Format validation: wrong magic bytes, future version, legacy DIC_MAGIC
- Stream behavior: mid-position seek-to-zero before reading
- File path errors: non-existent path, non-Aaru file, NULL path

Uses existing V1/V2 .aif fixtures from tests/data/ plus crafted
in-memory headers via tmpfile() for edge cases.
This commit is contained in:
Kevin Bortis
2026-04-02 07:49:51 +02:00
parent 62202a5c29
commit 2a2db120cf
2 changed files with 189 additions and 0 deletions

View File

@@ -91,6 +91,7 @@ add_executable(tests_run
open_image.cpp
create_image.cpp
verify_image.cpp
identify.cpp
ps3_aes.cpp
ps3_crypto.cpp
ps3_encryption_map.cpp

188
tests/identify.cpp Normal file
View File

@@ -0,0 +1,188 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2026 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <cerrno>
#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include "../include/aaruformat.h"
#include "gtest/gtest.h"
// Helper: create a tmpfile containing a crafted AaruHeader with the given magic and version.
// Returns the FILE* rewound to position 0. Caller must fclose().
static FILE *make_header_stream(uint64_t magic, uint8_t major_version)
{
FILE *f = tmpfile();
EXPECT_NE(f, nullptr);
if(f == nullptr) return nullptr;
AaruHeader hdr;
memset(&hdr, 0, sizeof(hdr));
hdr.identifier = magic;
hdr.imageMajorVersion = major_version;
fwrite(&hdr, sizeof(hdr), 1, f);
rewind(f);
return f;
}
class IdentifyFixture : public testing::Test
{
public:
IdentifyFixture() = default;
protected:
char path[PATH_MAX];
char filename[PATH_MAX];
void SetUp() override { getcwd(path, PATH_MAX); }
};
// ---------------------------------------------------------------------------
// aaruf_identify_stream() tests
// ---------------------------------------------------------------------------
TEST_F(IdentifyFixture, StreamValidV2)
{
snprintf(filename, PATH_MAX, "%s/data/mf2hd.aif", path);
FILE *f = fopen(filename, "rb");
ASSERT_NE(f, nullptr) << "Failed to open mf2hd.aif";
EXPECT_EQ(aaruf_identify_stream(f), 100);
fclose(f);
}
TEST_F(IdentifyFixture, StreamValidV1)
{
snprintf(filename, PATH_MAX, "%s/data/mf2hd_v1.aif", path);
FILE *f = fopen(filename, "rb");
ASSERT_NE(f, nullptr) << "Failed to open mf2hd_v1.aif";
EXPECT_EQ(aaruf_identify_stream(f), 100);
fclose(f);
}
TEST_F(IdentifyFixture, StreamNull)
{
EXPECT_EQ(aaruf_identify_stream(nullptr), 0);
}
TEST_F(IdentifyFixture, StreamNonAaru)
{
snprintf(filename, PATH_MAX, "%s/data/random", path);
FILE *f = fopen(filename, "rb");
ASSERT_NE(f, nullptr) << "Failed to open random data file";
EXPECT_EQ(aaruf_identify_stream(f), 0);
fclose(f);
}
TEST_F(IdentifyFixture, StreamEmptyFile)
{
FILE *f = tmpfile();
ASSERT_NE(f, nullptr);
EXPECT_EQ(aaruf_identify_stream(f), 0);
fclose(f);
}
TEST_F(IdentifyFixture, StreamTruncatedHeader)
{
// Write only the 8-byte magic — not enough for a full AaruHeader (104 bytes)
FILE *f = tmpfile();
ASSERT_NE(f, nullptr);
const uint64_t magic = AARU_MAGIC;
fwrite(&magic, sizeof(magic), 1, f);
rewind(f);
EXPECT_EQ(aaruf_identify_stream(f), 0);
fclose(f);
}
TEST_F(IdentifyFixture, StreamInvalidMagic)
{
FILE *f = make_header_stream(0xDEADBEEFDEADBEEFULL, 2);
ASSERT_NE(f, nullptr);
EXPECT_EQ(aaruf_identify_stream(f), 0);
fclose(f);
}
TEST_F(IdentifyFixture, StreamFutureVersion)
{
FILE *f = make_header_stream(AARU_MAGIC, 255);
ASSERT_NE(f, nullptr);
EXPECT_EQ(aaruf_identify_stream(f), 0);
fclose(f);
}
TEST_F(IdentifyFixture, StreamDicMagic)
{
FILE *f = make_header_stream(DIC_MAGIC, 1);
ASSERT_NE(f, nullptr);
EXPECT_EQ(aaruf_identify_stream(f), 100);
fclose(f);
}
TEST_F(IdentifyFixture, StreamMidPosition)
{
// Verify identify_stream seeks to 0 even when stream is positioned elsewhere
snprintf(filename, PATH_MAX, "%s/data/mf2hd.aif", path);
FILE *f = fopen(filename, "rb");
ASSERT_NE(f, nullptr) << "Failed to open mf2hd.aif";
fseek(f, 50, SEEK_SET);
EXPECT_EQ(aaruf_identify_stream(f), 100);
fclose(f);
}
// ---------------------------------------------------------------------------
// aaruf_identify() tests
// ---------------------------------------------------------------------------
TEST_F(IdentifyFixture, FileValidV2)
{
snprintf(filename, PATH_MAX, "%s/data/mf2hd.aif", path);
EXPECT_EQ(aaruf_identify(filename), 100);
}
TEST_F(IdentifyFixture, FileValidV1)
{
snprintf(filename, PATH_MAX, "%s/data/mf2hd_v1.aif", path);
EXPECT_EQ(aaruf_identify(filename), 100);
}
TEST_F(IdentifyFixture, FileNull)
{
EXPECT_EQ(aaruf_identify(nullptr), EINVAL);
}
TEST_F(IdentifyFixture, FileNonExistent)
{
EXPECT_EQ(aaruf_identify("/tmp/aaruf_test_nonexistent_identify.aif"), ENOENT);
}
TEST_F(IdentifyFixture, FileNonAaru)
{
snprintf(filename, PATH_MAX, "%s/data/random", path);
EXPECT_EQ(aaruf_identify(filename), 0);
}