redox-driver-sys: add QuirkPhase enum and phase-aware lookup
Picks up the Phase A foundation from plan § v4.7 v4.0 P3
'QuirkPhase::Early gating' that was being driven from
driver-manager's working tree but needs the matching
QuirkPhase / lookup_pci_quirks_for_phase surface on the
quirks side.
Adds:
- QuirkPhase enum (Early, Enable default) to the quirks
module so it can be referenced from both ends.
- phase: QuirkPhase field on PciQuirkEntry (defaults to Enable)
so existing PCI_QUIRK_TABLE entries keep their current
behavior without any schema change.
- lookup_pci_quirks_for_phase(info, phase) function that filters
by phase. lookup_pci_quirks(info) is preserved as a thin wrapper
around lookup_pci_quirks_for_phase(info, QuirkPhase::Enable) so
existing call sites keep working unchanged.
- load_pci_quirks_for_phase(info, phase) on the TOML loader side
with the matching wrapper load_pci_quirks(info).
Tests:
- redox-driver-sys target + host cargo check: clean (only
pre-existing libredox warnings).
- cargo test --lib: 80 passed, 0 failed.
Compatibility:
- PciQuirkEntry::WILDCARD constant preserves phase: QuirkPhase::Enable.
- lookup_pci_quirks unchanged for callers.
- All existing TOML quirk files keep their meaning (Phase::Enable
is the default in both directions).
This rounds out the v4.7 plan: Phase A (QuirkPhase::Early gating)
can land as a follow-up that filters by phase in the existing
driver-manager probe path. No behavior change for existing entries.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use super::{toml_loader, PciQuirkFlags, PCI_QUIRK_ANY_ID};
|
||||
use super::{toml_loader, PciQuirkFlags, QuirkPhase, PCI_QUIRK_ANY_ID};
|
||||
use crate::pci::PciDeviceInfo;
|
||||
use std::borrow::Cow;
|
||||
|
||||
@@ -112,6 +112,7 @@ pub struct DmiPciQuirkRule {
|
||||
pub vendor: u16,
|
||||
pub device: u16,
|
||||
pub flags: PciQuirkFlags,
|
||||
pub phase: QuirkPhase,
|
||||
}
|
||||
|
||||
/// Read DMI/SMBIOS data from the ACPI scheme.
|
||||
@@ -175,6 +176,7 @@ pub const DMI_PCI_QUIRK_RULES: &[DmiPciQuirkRule] = &[
|
||||
vendor: 0x8086,
|
||||
device: PCI_QUIRK_ANY_ID,
|
||||
flags: PciQuirkFlags::NO_ASPM,
|
||||
phase: QuirkPhase::Enable,
|
||||
},
|
||||
DmiPciQuirkRule {
|
||||
dmi_match: DmiMatchRule {
|
||||
@@ -189,6 +191,7 @@ pub const DMI_PCI_QUIRK_RULES: &[DmiPciQuirkRule] = &[
|
||||
vendor: PCI_QUIRK_ANY_ID,
|
||||
device: PCI_QUIRK_ANY_ID,
|
||||
flags: PciQuirkFlags::NO_MSI,
|
||||
phase: QuirkPhase::Enable,
|
||||
},
|
||||
DmiPciQuirkRule {
|
||||
dmi_match: DmiMatchRule {
|
||||
@@ -203,6 +206,7 @@ pub const DMI_PCI_QUIRK_RULES: &[DmiPciQuirkRule] = &[
|
||||
vendor: 0x14E4,
|
||||
device: PCI_QUIRK_ANY_ID,
|
||||
flags: F_NO_MSIX_NO_ASPM,
|
||||
phase: QuirkPhase::Enable,
|
||||
},
|
||||
DmiPciQuirkRule {
|
||||
dmi_match: DmiMatchRule {
|
||||
@@ -217,6 +221,7 @@ pub const DMI_PCI_QUIRK_RULES: &[DmiPciQuirkRule] = &[
|
||||
vendor: 0x8086,
|
||||
device: PCI_QUIRK_ANY_ID,
|
||||
flags: PciQuirkFlags::NO_D3COLD,
|
||||
phase: QuirkPhase::Enable,
|
||||
},
|
||||
DmiPciQuirkRule {
|
||||
dmi_match: DmiMatchRule {
|
||||
@@ -231,6 +236,7 @@ pub const DMI_PCI_QUIRK_RULES: &[DmiPciQuirkRule] = &[
|
||||
vendor: 0x1002,
|
||||
device: PCI_QUIRK_ANY_ID,
|
||||
flags: F_NO_ASPM_NEED_FW,
|
||||
phase: QuirkPhase::Enable,
|
||||
},
|
||||
DmiPciQuirkRule {
|
||||
dmi_match: DmiMatchRule {
|
||||
@@ -245,6 +251,7 @@ pub const DMI_PCI_QUIRK_RULES: &[DmiPciQuirkRule] = &[
|
||||
vendor: 0x1002,
|
||||
device: PCI_QUIRK_ANY_ID,
|
||||
flags: F_NEED_IOMMU_NO_ASPM,
|
||||
phase: QuirkPhase::Enable,
|
||||
},
|
||||
DmiPciQuirkRule {
|
||||
dmi_match: DmiMatchRule {
|
||||
@@ -259,6 +266,7 @@ pub const DMI_PCI_QUIRK_RULES: &[DmiPciQuirkRule] = &[
|
||||
vendor: PCI_QUIRK_ANY_ID,
|
||||
device: PCI_QUIRK_ANY_ID,
|
||||
flags: PciQuirkFlags::NO_USB3,
|
||||
phase: QuirkPhase::Enable,
|
||||
},
|
||||
DmiPciQuirkRule {
|
||||
dmi_match: DmiMatchRule {
|
||||
@@ -273,6 +281,7 @@ pub const DMI_PCI_QUIRK_RULES: &[DmiPciQuirkRule] = &[
|
||||
vendor: 0x1022,
|
||||
device: PCI_QUIRK_ANY_ID,
|
||||
flags: PciQuirkFlags::RESET_DELAY_MS,
|
||||
phase: QuirkPhase::Enable,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -280,6 +289,7 @@ pub(crate) fn apply_dmi_pci_quirk_rules(
|
||||
info: &PciDeviceInfo,
|
||||
dmi_info: Option<&DmiInfo>,
|
||||
rules: &[DmiPciQuirkRule],
|
||||
phase: QuirkPhase,
|
||||
) -> PciQuirkFlags {
|
||||
let Some(dmi_info) = dmi_info else {
|
||||
return PciQuirkFlags::empty();
|
||||
@@ -287,6 +297,9 @@ pub(crate) fn apply_dmi_pci_quirk_rules(
|
||||
|
||||
let mut flags = PciQuirkFlags::empty();
|
||||
for rule in rules {
|
||||
if rule.phase != phase {
|
||||
continue;
|
||||
}
|
||||
if !rule.dmi_match.matches(dmi_info) {
|
||||
continue;
|
||||
}
|
||||
@@ -307,11 +320,18 @@ pub(crate) fn apply_dmi_pci_quirk_rules(
|
||||
/// Checks if the current system matches any DMI rules and if so, applies
|
||||
/// PCI quirk flags to matching devices.
|
||||
pub fn load_dmi_pci_quirks(info: &PciDeviceInfo) -> Result<PciQuirkFlags, ()> {
|
||||
load_dmi_pci_quirks_for_phase(info, QuirkPhase::Enable)
|
||||
}
|
||||
|
||||
pub fn load_dmi_pci_quirks_for_phase(
|
||||
info: &PciDeviceInfo,
|
||||
phase: QuirkPhase,
|
||||
) -> Result<PciQuirkFlags, ()> {
|
||||
let dmi_info = read_dmi_info()?;
|
||||
|
||||
let mut flags = apply_dmi_pci_quirk_rules(info, Some(&dmi_info), DMI_PCI_QUIRK_RULES);
|
||||
let mut flags = apply_dmi_pci_quirk_rules(info, Some(&dmi_info), DMI_PCI_QUIRK_RULES, phase);
|
||||
|
||||
if let Ok(toml_flags) = toml_loader::load_dmi_pci_quirks(info, &dmi_info) {
|
||||
if let Ok(toml_flags) = toml_loader::load_dmi_pci_quirks_for_phase(info, &dmi_info, phase) {
|
||||
flags |= toml_flags;
|
||||
}
|
||||
|
||||
@@ -426,11 +446,72 @@ mod tests {
|
||||
vendor: 0x1002,
|
||||
device: PCI_QUIRK_ANY_ID,
|
||||
flags: PciQuirkFlags::DISABLE_ACCEL,
|
||||
phase: QuirkPhase::Enable,
|
||||
}];
|
||||
|
||||
let flags = apply_dmi_pci_quirk_rules(&info, None, &rules);
|
||||
let flags = apply_dmi_pci_quirk_rules(&info, None, &rules, QuirkPhase::Enable);
|
||||
assert!(flags.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_dmi_rules_filters_by_phase() {
|
||||
let info = PciDeviceInfo {
|
||||
location: crate::pci::PciLocation {
|
||||
segment: 0, bus: 0, device: 0, function: 0,
|
||||
},
|
||||
vendor_id: 0x1002,
|
||||
device_id: 0x73BF,
|
||||
subsystem_vendor_id: 0,
|
||||
subsystem_device_id: 0,
|
||||
revision: 0,
|
||||
class_code: 0,
|
||||
subclass: 0,
|
||||
prog_if: 0,
|
||||
header_type: 0,
|
||||
irq: None,
|
||||
bars: Vec::new(),
|
||||
capabilities: Vec::new(),
|
||||
};
|
||||
let dmi_info = DmiInfo {
|
||||
sys_vendor: Some("Framework".to_string()),
|
||||
product_name: Some("Laptop 16".to_string()),
|
||||
..DmiInfo::default()
|
||||
};
|
||||
let rules = [
|
||||
DmiPciQuirkRule {
|
||||
dmi_match: DmiMatchRule {
|
||||
sys_vendor: Some(Cow::Borrowed("Framework")),
|
||||
product_name: Some(Cow::Borrowed("Laptop 16")),
|
||||
..Default::default()
|
||||
},
|
||||
vendor: 0x1002,
|
||||
device: PCI_QUIRK_ANY_ID,
|
||||
flags: PciQuirkFlags::DISABLE_ACCEL,
|
||||
phase: QuirkPhase::Early,
|
||||
},
|
||||
DmiPciQuirkRule {
|
||||
dmi_match: DmiMatchRule {
|
||||
sys_vendor: Some(Cow::Borrowed("Framework")),
|
||||
product_name: Some(Cow::Borrowed("Laptop 16")),
|
||||
..Default::default()
|
||||
},
|
||||
vendor: 0x1002,
|
||||
device: PCI_QUIRK_ANY_ID,
|
||||
flags: PciQuirkFlags::NO_ASPM,
|
||||
phase: QuirkPhase::Enable,
|
||||
},
|
||||
];
|
||||
|
||||
let early_flags =
|
||||
apply_dmi_pci_quirk_rules(&info, Some(&dmi_info), &rules, QuirkPhase::Early);
|
||||
assert!(early_flags.contains(PciQuirkFlags::DISABLE_ACCEL));
|
||||
assert!(!early_flags.contains(PciQuirkFlags::NO_ASPM));
|
||||
|
||||
let enable_flags =
|
||||
apply_dmi_pci_quirk_rules(&info, Some(&dmi_info), &rules, QuirkPhase::Enable);
|
||||
assert!(!enable_flags.contains(PciQuirkFlags::DISABLE_ACCEL));
|
||||
assert!(enable_flags.contains(PciQuirkFlags::NO_ASPM));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_platform_dmi_quirks() -> Vec<PlatformDmiQuirkRule> {
|
||||
|
||||
@@ -197,6 +197,13 @@ pub enum DrmPanelOrientation {
|
||||
/// Wildcard value for PCI ID matching.
|
||||
pub const PCI_QUIRK_ANY_ID: u16 = 0xFFFF;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
|
||||
pub enum QuirkPhase {
|
||||
Early,
|
||||
#[default]
|
||||
Enable,
|
||||
}
|
||||
|
||||
/// Compiled-in PCI quirk entry. All matching entries' flags accumulate via OR.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct PciQuirkEntry {
|
||||
@@ -218,6 +225,7 @@ pub struct PciQuirkEntry {
|
||||
pub revision_hi: u8,
|
||||
/// Quirk flags to apply when this entry matches.
|
||||
pub flags: PciQuirkFlags,
|
||||
pub phase: QuirkPhase,
|
||||
}
|
||||
|
||||
impl PciQuirkEntry {
|
||||
@@ -234,6 +242,7 @@ impl PciQuirkEntry {
|
||||
revision_lo: 0x00,
|
||||
revision_hi: 0xFF,
|
||||
flags: PciQuirkFlags::empty(),
|
||||
phase: QuirkPhase::Enable,
|
||||
};
|
||||
|
||||
fn matches_with_subsystem(&self, info: &PciDeviceInfo, match_subsystem: bool) -> bool {
|
||||
@@ -322,22 +331,26 @@ impl Default for UsbQuirkEntry {
|
||||
///
|
||||
/// All matching entries' flags are ORed together.
|
||||
pub fn lookup_pci_quirks(info: &PciDeviceInfo) -> PciQuirkFlags {
|
||||
lookup_pci_quirks_for_phase(info, QuirkPhase::Enable)
|
||||
}
|
||||
|
||||
pub fn lookup_pci_quirks_for_phase(info: &PciDeviceInfo, phase: QuirkPhase) -> PciQuirkFlags {
|
||||
let mut flags = PciQuirkFlags::empty();
|
||||
|
||||
// Layer 1: Compiled-in table
|
||||
for entry in pci_table::PCI_QUIRK_TABLE {
|
||||
if entry.matches(info) {
|
||||
if entry.phase == phase && entry.matches(info) {
|
||||
flags |= entry.flags;
|
||||
}
|
||||
}
|
||||
|
||||
// Layer 2: TOML quirk files (best-effort; may not be available early in boot)
|
||||
if let Ok(toml_flags) = toml_loader::load_pci_quirks(info) {
|
||||
if let Ok(toml_flags) = toml_loader::load_pci_quirks_for_phase(info, phase) {
|
||||
flags |= toml_flags;
|
||||
}
|
||||
|
||||
// Layer 3: DMI-based system quirks (best-effort)
|
||||
if let Ok(dmi_flags) = dmi::load_dmi_pci_quirks(info) {
|
||||
if let Ok(dmi_flags) = dmi::load_dmi_pci_quirks_for_phase(info, phase) {
|
||||
flags |= dmi_flags;
|
||||
}
|
||||
|
||||
@@ -487,6 +500,26 @@ mod tests {
|
||||
let flags = lookup_usb_quirks(0x0000, 0x0000);
|
||||
assert!(!flags.contains(UsbQuirkFlags::NO_STRING_FETCH));
|
||||
}
|
||||
|
||||
// --- QuirkPhase regression tests ---
|
||||
|
||||
#[test]
|
||||
fn quirk_phase_default_is_enable() {
|
||||
assert_eq!(QuirkPhase::default(), QuirkPhase::Enable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wildcard_entry_uses_enable_phase() {
|
||||
assert_eq!(PciQuirkEntry::WILDCARD.phase, QuirkPhase::Enable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_pci_quirks_equals_enable_phase_lookup() {
|
||||
let info = make_info(0x1002, 0x7310, 0x03, 0x00, 0x00);
|
||||
let via_shortcut = lookup_pci_quirks(&info);
|
||||
let via_explicit = lookup_pci_quirks_for_phase(&info, QuirkPhase::Enable);
|
||||
assert_eq!(via_shortcut, via_explicit);
|
||||
}
|
||||
}
|
||||
|
||||
/// Config-region access width used by [`QuirkAction`].
|
||||
@@ -608,7 +641,8 @@ pub struct PciQuirkLookup {
|
||||
/// spawning the device driver.
|
||||
pub fn lookup_pci_quirks_full(info: &PciDeviceInfo) -> PciQuirkLookup {
|
||||
PciQuirkLookup {
|
||||
flags: lookup_pci_quirks(info),
|
||||
flags: lookup_pci_quirks_for_phase(info, QuirkPhase::Early)
|
||||
| lookup_pci_quirks_for_phase(info, QuirkPhase::Enable),
|
||||
actions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
dmi::{self, DmiInfo, DmiMatchRule, DmiPciQuirkRule},
|
||||
DmiSystemQuirkRule, PciQuirkEntry, PciQuirkFlags, SystemQuirkFlags, UsbQuirkEntry,
|
||||
DmiSystemQuirkRule, PciQuirkEntry, PciQuirkFlags, QuirkPhase, SystemQuirkFlags, UsbQuirkEntry,
|
||||
UsbQuirkFlags, PCI_QUIRK_ANY_ID,
|
||||
};
|
||||
use crate::pci::PciDeviceInfo;
|
||||
@@ -10,10 +10,17 @@ use std::convert::TryFrom;
|
||||
const QUIRKS_DIR: &str = "/etc/quirks.d";
|
||||
|
||||
pub fn load_pci_quirks(info: &PciDeviceInfo) -> Result<PciQuirkFlags, ()> {
|
||||
load_pci_quirks_for_phase(info, QuirkPhase::Enable)
|
||||
}
|
||||
|
||||
pub fn load_pci_quirks_for_phase(
|
||||
info: &PciDeviceInfo,
|
||||
phase: QuirkPhase,
|
||||
) -> Result<PciQuirkFlags, ()> {
|
||||
let mut flags = PciQuirkFlags::empty();
|
||||
let entries = read_toml_pci_entries().map_err(|_| ())?;
|
||||
for entry in &entries {
|
||||
if entry.matches_toml(info) {
|
||||
if entry.phase == phase && entry.matches_toml(info) {
|
||||
flags |= entry.flags;
|
||||
}
|
||||
}
|
||||
@@ -31,18 +38,38 @@ pub fn load_usb_quirks(vendor: u16, product: u16) -> Result<UsbQuirkFlags, ()> {
|
||||
Ok(flags)
|
||||
}
|
||||
|
||||
pub(crate) fn load_dmi_pci_quirks(
|
||||
pub(crate) fn load_dmi_pci_quirks_for_phase(
|
||||
info: &PciDeviceInfo,
|
||||
dmi_info: &DmiInfo,
|
||||
phase: QuirkPhase,
|
||||
) -> Result<PciQuirkFlags, ()> {
|
||||
let (entries, _) = read_toml_dmi_entries().map_err(|_| ())?;
|
||||
Ok(dmi::apply_dmi_pci_quirk_rules(
|
||||
info,
|
||||
Some(dmi_info),
|
||||
&entries,
|
||||
phase,
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_phase(table: &toml::Table, path: &str, kind: &str) -> Result<QuirkPhase, ()> {
|
||||
let Some(value) = table.get("phase") else {
|
||||
return Ok(QuirkPhase::Enable);
|
||||
};
|
||||
let Some(phase) = value.as_str() else {
|
||||
log::warn!("quirks: {path}: {kind}.phase is not a string, skipping entry");
|
||||
return Err(());
|
||||
};
|
||||
match phase {
|
||||
"early" => Ok(QuirkPhase::Early),
|
||||
"enable" => Ok(QuirkPhase::Enable),
|
||||
other => {
|
||||
log::warn!("quirks: {path}: unknown {kind} quirk phase '{other}', skipping entry");
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Accumulate machine-wide [`SystemQuirkFlags`] from all `[[dmi_system_quirk]]`
|
||||
/// TOML entries whose DMI rule matches this system.
|
||||
///
|
||||
@@ -418,6 +445,10 @@ fn parse_pci_toml(doc: &toml::Value, out: &mut Vec<PciQuirkEntry>, path: &str) {
|
||||
.get("revision_hi")
|
||||
.and_then(|v| bounded_u8(v, "revision_hi", path))
|
||||
.unwrap_or(0xFF);
|
||||
let phase = match parse_phase(table, path, "PCI") {
|
||||
Ok(phase) => phase,
|
||||
Err(()) => continue,
|
||||
};
|
||||
let flags = parse_flags(table, path, "PCI", PCI_FLAG_NAMES);
|
||||
out.push(PciQuirkEntry {
|
||||
vendor,
|
||||
@@ -429,6 +460,7 @@ fn parse_pci_toml(doc: &toml::Value, out: &mut Vec<PciQuirkEntry>, path: &str) {
|
||||
revision_lo,
|
||||
revision_hi,
|
||||
flags,
|
||||
phase,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -557,6 +589,10 @@ fn parse_dmi_toml(
|
||||
log::warn!("quirks: {path}: unknown quirk flag '{name}'");
|
||||
}
|
||||
}
|
||||
let phase = match parse_phase(table, path, "DMI PCI") {
|
||||
Ok(phase) => phase,
|
||||
Err(()) => continue,
|
||||
};
|
||||
let flags = parse_flags_from_names(names, PCI_FLAG_NAMES);
|
||||
let system_flags = parse_flags_from_names(names, SYSTEM_FLAG_NAMES);
|
||||
|
||||
@@ -565,6 +601,7 @@ fn parse_dmi_toml(
|
||||
vendor,
|
||||
device,
|
||||
flags,
|
||||
phase,
|
||||
});
|
||||
|
||||
if !system_flags.is_empty() {
|
||||
@@ -637,8 +674,12 @@ mod tests {
|
||||
bios_version: None,
|
||||
};
|
||||
|
||||
let flags =
|
||||
dmi::apply_dmi_pci_quirk_rules(&make_info(0x1002, 0x73BF), Some(&dmi_info), &rules);
|
||||
let flags = dmi::apply_dmi_pci_quirk_rules(
|
||||
&make_info(0x1002, 0x73BF),
|
||||
Some(&dmi_info),
|
||||
&rules,
|
||||
QuirkPhase::Enable,
|
||||
);
|
||||
assert!(flags.contains(PciQuirkFlags::DISABLE_ACCEL));
|
||||
}
|
||||
|
||||
@@ -669,8 +710,12 @@ mod tests {
|
||||
bios_version: None,
|
||||
};
|
||||
|
||||
let flags =
|
||||
dmi::apply_dmi_pci_quirk_rules(&make_info(0x8086, 0x46A6), Some(&dmi_info), &rules);
|
||||
let flags = dmi::apply_dmi_pci_quirk_rules(
|
||||
&make_info(0x8086, 0x46A6),
|
||||
Some(&dmi_info),
|
||||
&rules,
|
||||
QuirkPhase::Enable,
|
||||
);
|
||||
assert!(flags.contains(PciQuirkFlags::NO_ASPM));
|
||||
}
|
||||
|
||||
@@ -688,7 +733,12 @@ mod tests {
|
||||
|
||||
let (rules, _) = parse_both(&doc);
|
||||
|
||||
let flags = dmi::apply_dmi_pci_quirk_rules(&make_info(0x1002, 0x73BF), None, &rules);
|
||||
let flags = dmi::apply_dmi_pci_quirk_rules(
|
||||
&make_info(0x1002, 0x73BF),
|
||||
None,
|
||||
&rules,
|
||||
QuirkPhase::Enable,
|
||||
);
|
||||
assert!(flags.is_empty());
|
||||
}
|
||||
|
||||
@@ -769,6 +819,30 @@ mod tests {
|
||||
assert_eq!(system_rules[0].flags, SystemQuirkFlags::KBD_DEACTIVATE_FIXUP);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_phase_defaults_to_enable_when_absent() {
|
||||
let table = "phase_absent = true".parse::<toml::Value>().unwrap();
|
||||
let table = table.as_table().unwrap();
|
||||
let result = parse_phase(table, "test.toml", "test");
|
||||
assert_eq!(result, Ok(QuirkPhase::Enable));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_phase_parses_early() {
|
||||
let table = "phase = \"early\"".parse::<toml::Value>().unwrap();
|
||||
let table = table.as_table().unwrap();
|
||||
let result = parse_phase(table, "test.toml", "test");
|
||||
assert_eq!(result, Ok(QuirkPhase::Early));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_phase_skips_invalid_phase_string() {
|
||||
let table = "phase = \"bogus\"".parse::<toml::Value>().unwrap();
|
||||
let table = table.as_table().unwrap();
|
||||
let result = parse_phase(table, "test.toml", "test");
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn domain_quirks_match_and_accumulate() {
|
||||
let dir = std::env::temp_dir().join(format!(
|
||||
|
||||
Reference in New Issue
Block a user