Files
RASCSI/cpp/test/device_factory_test.cpp
T
Daniel Markstedt e57893893c restore support for SASI disk drive device
Introduce a SASI controller and SAHD disk implementation alongside the existing SCSI path. Select the appropriate controller when attaching a device, prevent SASI and SCSI devices from sharing a target ID, and implement SASI-specific selection, message, status, timing, and LUN handling.

Restore SAHD in the protocol and expose it consistently through the device factory, command-line client, configuration validation, web interface, drive profiles, and manual. Enforce the two-LUN limit for SASI targets wherever device definitions are created or parsed.

Bring back handling of the hdf image format and map it to the SAHD device type. The hdf file ending is the established one for SASI raw disk images used in the X68000 emulation community, however it is a raw data format without any special header.

Add focused C++ and Go coverage for SASI devices, controller selection, LUN validation, and web-facing behavior.
2026-08-30 08:27:35 +02:00

262 lines
8.8 KiB
C++

//---------------------------------------------------------------------------
//
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "shared/piscsi_exceptions.h"
#include "shared/piscsi_version.h"
#include "controllers/controller_manager.h"
#include "devices/device.h"
#include "devices/device_factory.h"
#include <unordered_map>
TEST(DeviceFactoryTest, GetTypeForFile)
{
DeviceFactory device_factory;
EXPECT_EQ(device_factory.GetTypeForFile("test.hdf"), SAHD);
EXPECT_EQ(device_factory.GetTypeForFile("test.HDF"), SAHD);
EXPECT_EQ(device_factory.GetTypeForFile("test.hd1"), SCHD);
EXPECT_EQ(device_factory.GetTypeForFile("test.hds"), SCHD);
EXPECT_EQ(device_factory.GetTypeForFile("test.HDS"), SCHD);
EXPECT_EQ(device_factory.GetTypeForFile("test.hda"), SCHD);
EXPECT_EQ(device_factory.GetTypeForFile("test.hdn"), SCHD);
EXPECT_EQ(device_factory.GetTypeForFile("test.hdi"), SCHD);
EXPECT_EQ(device_factory.GetTypeForFile("test.nhd"), SCHD);
EXPECT_EQ(device_factory.GetTypeForFile("test.hdr"), SCRM);
EXPECT_EQ(device_factory.GetTypeForFile("test.mos"), SCMO);
EXPECT_EQ(device_factory.GetTypeForFile("test.iso"), SCCD);
EXPECT_EQ(device_factory.GetTypeForFile("test.is1"), SCCD);
EXPECT_EQ(device_factory.GetTypeForFile("test.cdr"), SCCD);
EXPECT_EQ(device_factory.GetTypeForFile("test.toast"), SCCD);
EXPECT_EQ(device_factory.GetTypeForFile("test.suffix.iso"), SCCD);
EXPECT_EQ(device_factory.GetTypeForFile("test.tar"), SCTP);
EXPECT_EQ(device_factory.GetTypeForFile("test.tap"), SCTP);
EXPECT_EQ(device_factory.GetTypeForFile("daynaport"), SCDP);
EXPECT_EQ(device_factory.GetTypeForFile("printer"), SCLP);
EXPECT_EQ(device_factory.GetTypeForFile("services"), SCHS);
EXPECT_EQ(device_factory.GetTypeForFile("unknown"), UNDEFINED);
EXPECT_EQ(device_factory.GetTypeForFile("test.iso.suffix"), UNDEFINED);
}
TEST(DeviceFactoryTest, GetExtensionMapping)
{
DeviceFactory device_factory;
auto mapping = device_factory.GetExtensionMapping();
EXPECT_EQ(15, mapping.size());
EXPECT_EQ(SAHD, mapping["hdf"]);
EXPECT_EQ(SCHD, mapping["hd1"]);
EXPECT_EQ(SCHD, mapping["hds"]);
EXPECT_EQ(SCHD, mapping["hda"]);
EXPECT_EQ(SCHD, mapping["hdn"]);
EXPECT_EQ(SCHD, mapping["hdi"]);
EXPECT_EQ(SCHD, mapping["nhd"]);
EXPECT_EQ(SCRM, mapping["hdr"]);
EXPECT_EQ(SCMO, mapping["mos"]);
EXPECT_EQ(SCCD, mapping["iso"]);
EXPECT_EQ(SCCD, mapping["is1"]);
EXPECT_EQ(SCCD, mapping["cdr"]);
EXPECT_EQ(SCCD, mapping["toast"]);
EXPECT_EQ(SCTP, mapping["tar"]);
EXPECT_EQ(SCTP, mapping["tap"]);
}
TEST(DeviceFactoryTest, UnknownDeviceType)
{
DeviceFactory device_factory;
auto device1 = device_factory.CreateDevice(UNDEFINED, 0, "test");
EXPECT_EQ(nullptr, device1);
auto device2 = device_factory.CreateDevice(SAHD, 0, "test");
EXPECT_NE(nullptr, device2);
EXPECT_EQ(SAHD, device2->GetType());
auto device3 = device_factory.CreateDevice(UNDEFINED, 0, "test.hdf");
EXPECT_NE(nullptr, device3);
EXPECT_EQ(SAHD, device3->GetType());
}
TEST(DeviceFactoryTest, SCHD_Device_Defaults)
{
DeviceFactory device_factory;
auto device = device_factory.CreateDevice(UNDEFINED, 0, "test.hda");
EXPECT_NE(nullptr, device);
EXPECT_EQ(SCHD, device->GetType());
EXPECT_TRUE(device->SupportsFile());
EXPECT_FALSE(device->SupportsParams());
EXPECT_TRUE(device->IsProtectable());
EXPECT_FALSE(device->IsProtected());
EXPECT_FALSE(device->IsReadOnly());
EXPECT_FALSE(device->IsRemovable());
EXPECT_FALSE(device->IsRemoved());
EXPECT_FALSE(device->IsLockable());
EXPECT_FALSE(device->IsLocked());
EXPECT_TRUE(device->IsStoppable());
EXPECT_FALSE(device->IsStopped());
EXPECT_EQ("QUANTUM", device->GetVendor()) << "Invalid default vendor for Apple drive";
EXPECT_EQ("FIREBALL", device->GetProduct()) << "Invalid default vendor for Apple drive";
EXPECT_EQ(string(piscsi_get_version_string()).substr(0, 2) + string(piscsi_get_version_string()).substr(3, 2),
device->GetRevision());
device = device_factory.CreateDevice(UNDEFINED, 0, "test.hds");
EXPECT_NE(nullptr, device);
EXPECT_EQ(SCHD, device->GetType());
device = device_factory.CreateDevice(UNDEFINED, 0, "test.hdi");
EXPECT_NE(nullptr, device);
EXPECT_EQ(SCHD, device->GetType());
device = device_factory.CreateDevice(UNDEFINED, 0, "test.nhd");
EXPECT_NE(nullptr, device);
EXPECT_EQ(SCHD, device->GetType());
}
void TestRemovableDrive(PbDeviceType type, const string& filename, const string& product)
{
DeviceFactory device_factory;
auto device = device_factory.CreateDevice(UNDEFINED, 0, filename);
EXPECT_NE(nullptr, device);
EXPECT_EQ(type, device->GetType());
EXPECT_TRUE(device->SupportsFile());
EXPECT_FALSE(device->SupportsParams());
EXPECT_TRUE(device->IsProtectable());
EXPECT_FALSE(device->IsProtected());
EXPECT_FALSE(device->IsReadOnly());
EXPECT_TRUE(device->IsRemovable());
EXPECT_FALSE(device->IsRemoved());
EXPECT_TRUE(device->IsLockable());
EXPECT_FALSE(device->IsLocked());
EXPECT_TRUE(device->IsStoppable());
EXPECT_FALSE(device->IsStopped());
EXPECT_EQ("PiSCSI", device->GetVendor());
EXPECT_EQ(product, device->GetProduct());
EXPECT_EQ(string(piscsi_get_version_string()).substr(0, 2) + string(piscsi_get_version_string()).substr(3, 2),
device->GetRevision());
}
TEST(DeviceFactoryTest, SCRM_Device_Defaults)
{
TestRemovableDrive(SCRM, "test.hdr", "SCSI HD (REM.)");
}
TEST(DeviceFactoryTest, SCMO_Device_Defaults)
{
TestRemovableDrive(SCMO, "test.mos", "SCSI MO");
}
TEST(DeviceFactoryTest, SCCD_Device_Defaults)
{
DeviceFactory device_factory;
auto device = device_factory.CreateDevice(UNDEFINED, 0, "test.iso");
EXPECT_NE(nullptr, device);
EXPECT_EQ(SCCD, device->GetType());
EXPECT_TRUE(device->SupportsFile());
EXPECT_FALSE(device->SupportsParams());
EXPECT_FALSE(device->IsProtectable());
EXPECT_FALSE(device->IsProtected());
EXPECT_TRUE(device->IsReadOnly());
EXPECT_TRUE(device->IsRemovable());
EXPECT_FALSE(device->IsRemoved());
EXPECT_TRUE(device->IsLockable());
EXPECT_FALSE(device->IsLocked());
EXPECT_TRUE(device->IsStoppable());
EXPECT_FALSE(device->IsStopped());
EXPECT_EQ("PiSCSI", device->GetVendor());
EXPECT_EQ("SCSI CD-ROM", device->GetProduct());
EXPECT_EQ(string(piscsi_get_version_string()).substr(0, 2) + string(piscsi_get_version_string()).substr(3, 2),
device->GetRevision());
}
TEST(DeviceFactoryTest, SCDP_Device_Defaults)
{
DeviceFactory device_factory;
auto device = device_factory.CreateDevice(UNDEFINED, 0, "daynaport");
EXPECT_NE(nullptr, device);
EXPECT_EQ(SCDP, device->GetType());
EXPECT_FALSE(device->SupportsFile());
EXPECT_TRUE(device->SupportsParams());
EXPECT_FALSE(device->IsProtectable());
EXPECT_FALSE(device->IsProtected());
EXPECT_FALSE(device->IsReadOnly());
EXPECT_FALSE(device->IsRemovable());
EXPECT_FALSE(device->IsRemoved());
EXPECT_FALSE(device->IsLockable());
EXPECT_FALSE(device->IsLocked());
EXPECT_FALSE(device->IsStoppable());
EXPECT_FALSE(device->IsStopped());
EXPECT_EQ("Dayna", device->GetVendor());
EXPECT_EQ("SCSI/Link", device->GetProduct());
EXPECT_EQ("1.4a", device->GetRevision());
}
TEST(DeviceFactoryTest, SCHS_Device_Defaults)
{
DeviceFactory device_factory;
auto device = device_factory.CreateDevice(UNDEFINED, 0, "services");
EXPECT_NE(nullptr, device);
EXPECT_EQ(SCHS, device->GetType());
EXPECT_FALSE(device->SupportsFile());
EXPECT_FALSE(device->SupportsParams());
EXPECT_FALSE(device->IsProtectable());
EXPECT_FALSE(device->IsProtected());
EXPECT_FALSE(device->IsReadOnly());
EXPECT_FALSE(device->IsRemovable());
EXPECT_FALSE(device->IsRemoved());
EXPECT_FALSE(device->IsLockable());
EXPECT_FALSE(device->IsLocked());
EXPECT_FALSE(device->IsStoppable());
EXPECT_FALSE(device->IsStopped());
EXPECT_EQ("PiSCSI", device->GetVendor());
EXPECT_EQ("Host Services", device->GetProduct());
EXPECT_EQ(string(piscsi_get_version_string()).substr(0, 2) + string(piscsi_get_version_string()).substr(3, 2),
device->GetRevision());
}
TEST(DeviceFactoryTest, SCLP_Device_Defaults)
{
DeviceFactory device_factory;
auto device = device_factory.CreateDevice(UNDEFINED, 0, "printer");
EXPECT_NE(nullptr, device);
EXPECT_EQ(SCLP, device->GetType());
EXPECT_FALSE(device->SupportsFile());
EXPECT_TRUE(device->SupportsParams());
EXPECT_FALSE(device->IsProtectable());
EXPECT_FALSE(device->IsProtected());
EXPECT_FALSE(device->IsReadOnly());
EXPECT_FALSE(device->IsRemovable());
EXPECT_FALSE(device->IsRemoved());
EXPECT_FALSE(device->IsLockable());
EXPECT_FALSE(device->IsLocked());
EXPECT_FALSE(device->IsStoppable());
EXPECT_FALSE(device->IsStopped());
EXPECT_EQ("PiSCSI", device->GetVendor());
EXPECT_EQ("SCSI PRINTER", device->GetProduct());
EXPECT_EQ(string(piscsi_get_version_string()).substr(0, 2) + string(piscsi_get_version_string()).substr(3, 2),
device->GetRevision());
}
TEST(DeviceFactoryTest, SCTP_Device_Defaults)
{
TestRemovableDrive(SCTP, "test.tap", "SCSI TAPE");
}