Skip to main content

wowlab_parsers/parsers/transform/
spec.rs

1use wowlab_types::data::SpecDataFlat;
2
3#[cfg(feature = "dbc")]
4use super::{super::dbc::DbcData, super::errors::TransformError, resolve_icon_file_name};
5
6/// Convert a single `ChrSpecialization` row into a flat `SpecDataFlat` (with class name and icon resolved).
7///
8/// # Errors
9///
10/// Returns [`TransformError`] when `spec_id` is absent from the DBC data.
11pub fn transform_spec(dbc: &DbcData, spec_id: i32) -> Result<SpecDataFlat, TransformError> {
12    let spec = dbc
13        .chr_specialization
14        .get(&spec_id)
15        .ok_or_else(|| TransformError::spec_not_found(spec_id))?;
16
17    let class_name = spec
18        .ClassID
19        .and_then(|class_id| dbc.chr_classes.get(&class_id))
20        .and_then(|c| c.Name_lang.clone())
21        .unwrap_or_default();
22
23    let file_name = resolve_icon_file_name(dbc, spec.SpellIconFileID);
24
25    Ok(SpecDataFlat {
26        id: spec.ID,
27        name: spec.Name_lang.clone().unwrap_or_default().into(),
28        description: spec.Description_lang.clone().unwrap_or_default(),
29        class_id: spec.ClassID.unwrap_or(0),
30        class_name: class_name.into(),
31        role: spec.Role,
32        order_index: spec.OrderIndex.unwrap_or(0),
33        icon_file_id: spec.SpellIconFileID,
34        file_name: file_name.into(),
35        primary_stat_priority: spec.PrimaryStatPriority,
36        mastery_spell_id_0: spec.MasterySpellID_0,
37        mastery_spell_id_1: spec.MasterySpellID_1,
38    })
39}
40
41/// Transform every `ChrSpecialization` row in the DBC dataset into `SpecDataFlat` records.
42#[must_use]
43pub fn transform_all_specs(dbc: &DbcData) -> Vec<SpecDataFlat> {
44    super::transform_all(dbc.chr_specialization.keys().copied(), "spec", |spec_id| {
45        transform_spec(dbc, spec_id)
46    })
47}
48
49#[cfg(test)]
50mod tests {
51    use googletest::prelude::*;
52
53    use super::*;
54    use crate::parsers::{
55        dbc::rows::{ChrClassesRow, ChrSpecializationRow},
56        transform::fixtures::{class_row, dbc, spec_row},
57    };
58
59    #[gtest]
60    fn transform_spec_missing_errors() -> Result<()> {
61        let dbc = dbc();
62
63        verify_that!(
64            transform_spec(&dbc, 260).unwrap_err().to_string(),
65            eq("Spec 260 not found in DBC cache")
66        )
67    }
68
69    #[gtest]
70    fn transform_spec_joins_class_name() -> Result<()> {
71        let mut dbc = dbc();
72
73        dbc.chr_classes.insert(
74            4,
75            ChrClassesRow {
76                Name_lang: Some("Rogue".to_string()),
77                ..class_row(4)
78            },
79        );
80        dbc.chr_specialization.insert(
81            260,
82            ChrSpecializationRow {
83                ClassID: Some(4),
84                OrderIndex: Some(2),
85                MasterySpellID_0: 76806,
86                MasterySpellID_1: 0,
87                ..spec_row(260)
88            },
89        );
90
91        let flat = transform_spec(&dbc, 260)?;
92
93        verify_that!(flat.class_id, eq(4))?;
94        verify_that!(flat.class_name.as_str(), eq("Rogue"))?;
95        verify_that!(flat.order_index, eq(2))?;
96
97        verify_that!(flat.mastery_spell_id_0, eq(76806))
98    }
99
100    #[gtest]
101    fn transform_spec_no_class_id_defaults() -> Result<()> {
102        let mut dbc = dbc();
103
104        dbc.chr_specialization.insert(
105            260,
106            ChrSpecializationRow {
107                ClassID: None,
108                ..spec_row(260)
109            },
110        );
111
112        let flat = transform_spec(&dbc, 260)?;
113
114        verify_that!(flat.class_id, eq(0))?;
115
116        verify_that!(flat.class_name.as_str(), eq(""))
117    }
118
119    #[gtest]
120    fn transform_spec_class_join_miss() -> Result<()> {
121        let mut dbc = dbc();
122
123        dbc.chr_specialization.insert(
124            260,
125            ChrSpecializationRow {
126                ClassID: Some(4),
127                OrderIndex: Some(1),
128                MasterySpellID_1: 999,
129                ..spec_row(260)
130            },
131        );
132
133        let flat = transform_spec(&dbc, 260)?;
134
135        verify_that!(flat.class_id, eq(4))?;
136        verify_that!(flat.class_name.as_str(), eq(""))?;
137        verify_that!(flat.order_index, eq(1))?;
138
139        verify_that!(flat.mastery_spell_id_1, eq(999))
140    }
141}