package main import "testing" func TestOD_MeleeTetsubo(t *testing.T) { // 2H Cleaving baseline 45, name "Tetsubo", maxdmg 85 → clamp(85-45,1,10)=10. raw := map[string]any{"ObjectClass": 1.0, "Name": "Tetsubo", "IntValues": map[string]any{"218103840": 41.0, "353": 11.0, "218103842": 85.0}} if od, ok := computeOD(raw); !ok || od != 10 { t.Fatalf("Tetsubo OD=%v ok=%v want 10", od, ok) } } func TestOD_MeleeMidTier(t *testing.T) { // Heavy Axe baseline 74, name "War Axe", maxdmg 79 → clamp(79-74,1,10)=5. raw := map[string]any{"ObjectClass": 1.0, "Name": "Bronze War Axe", "IntValues": map[string]any{"218103840": 44.0, "353": 3.0, "218103842": 79.0}} if od, ok := computeOD(raw); !ok || od != 5 { t.Fatalf("War Axe OD=%v ok=%v want 5", od, ok) } } func TestOD_MeleeBelowBaselineNull(t *testing.T) { // Heavy Axe baseline 74, maxdmg 74 → stat-baseline=0 (<1) → null. raw := map[string]any{"ObjectClass": 1.0, "Name": "Bronze War Axe", "IntValues": map[string]any{"218103840": 44.0, "353": 3.0, "218103842": 74.0}} if _, ok := computeOD(raw); ok { t.Fatal("maxdmg == baseline must be null") } } func TestOD_MeleeNameGateNull(t *testing.T) { // Heavy Axe bucket requires name in {Silifi,Lugian,War Axe,Battle}. A skill-44 // mastery-3 item NOT matching any name and matching no other bucket → null. raw := map[string]any{"ObjectClass": 1.0, "Name": "Bronze Frobnicator", "IntValues": map[string]any{"218103840": 44.0, "353": 3.0, "218103842": 84.0}} if _, ok := computeOD(raw); ok { t.Fatal("name not matching the Heavy Axe filter must be null") } } func TestOD_Crossbow(t *testing.T) { // Xbow baseline 77, k839=89 → clamp(89-77,1,10)=10. raw := map[string]any{"ObjectClass": 9.0, "Name": "Fire Compound Crossbow", "IntValues": map[string]any{"218103840": 47.0, "353": 9.0, "218103839": 89.0}} if od, ok := computeOD(raw); !ok || od != 10 { t.Fatalf("Xbow OD=%v ok=%v want 10", od, ok) } } func TestOD_WarCaster(t *testing.T) { // War caster: elemVsMon 1.40 → clamp(round((1.40-1.18)*100),1,7)=clamp(22,1,7)=7. raw := map[string]any{"ObjectClass": 31.0, "Name": "Diamond Frost Baton", "IntValues": map[string]any{"159": 34.0}, "DoubleValues": map[string]any{"152": 1.40}} if od, ok := computeOD(raw); !ok || od != 7 { t.Fatalf("War caster OD=%v ok=%v want 7", od, ok) } } func TestOD_VoidCasterTier(t *testing.T) { // Void caster: name must contain "Nether"; elemVsMon 1.22 → round((1.22-1.18)*100)=4. raw := map[string]any{"ObjectClass": 31.0, "Name": "Silver Nether Staff", "IntValues": map[string]any{"159": 43.0}, "DoubleValues": map[string]any{"152": 1.22}} if od, ok := computeOD(raw); !ok || od != 4 { t.Fatalf("Void caster OD=%v ok=%v want 4", od, ok) } } func TestOD_BowDeferredNull(t *testing.T) { // Bows (mastery 8) are deferred → always null in this pass. raw := map[string]any{"ObjectClass": 9.0, "Name": "Corsair's Arc", "IntValues": map[string]any{"218103840": 47.0, "353": 8.0, "218103839": 70.0}} if _, ok := computeOD(raw); ok { t.Fatal("bows are deferred → null") } }