use std::collections::BTreeMap;
const SPEC: &str = "../../spec/openapi.json";
fn covered_paths() -> BTreeMap<&'static str, &'static str> {
BTreeMap::from([
("/actionUri", "action_uris"),
("/appointment", "appointments"),
("/appointment/{id}", "appointments.get_by_id"),
("/appointmentCategory", "appointment_categories"),
("/appointmentcontent", "appointment_contents"),
("/appointmentContainer", "appointment_containers"),
("/appointmentDependency", "appointment_dependencies"),
("/appointmentField", "appointment_fields"),
("/appointmentFieldValue", "appointment_field_values"),
("/appointmentImportance", "appointment_importances"),
("/appointmentLocked", "appointment_locked"),
(
"/appointmentPlanningQuantity",
"appointment_planning_quantities",
),
("/appointmentRecurring", "recurring_appointments"),
("/appointmentTimeMarker", "appointment_time_markers"),
("/appointmentUri", "appointment_uris"),
("/assignment", "assignments"),
("/calendar", "calendars"),
("/caption", "captions"),
("/category", "categories"),
("/connector", "connectors"),
("/container", "containers"),
("/filterGroup", "filter_groups"),
("/filterValue", "filter_values"),
("/geocode", "geocoding"),
("/import", "imports.run"),
("/import/setup", "imports.setup"),
("/job", "jobs"),
("/job/{jobNo}", "jobs.get"),
("/message", "messages"),
("/notification", "notifications"),
("/optimization/dailyRoute", "optimization.daily_route"),
("/optimization/fieldService", "optimization.field_service"),
(
"/optimization/professionalServices",
"optimization.professional_services",
),
("/pin", "pins"),
("/projectMember", "project_members"),
("/recommendation", "recommendation.get"),
("/recommendation/scorers", "recommendation.scorers"),
("/resource", "resources"),
("/resourceCalendar", "resource_calendars"),
("/resourceCapacity", "resource_capacities"),
("/resourceCertificate", "resource_certificates"),
("/resourceFilterValue", "resource_filter_values"),
("/resourceGpsTracking", "resource_gps_trackings"),
("/resourcetype", "resource_types"),
("/resourceUri", "resource_uris"),
("/tag", "tags"),
("/task", "tasks"),
("/taskAssignment", "task_assignments"),
("/taskBudgetEntry", "task_budget_entries"),
("/taskContainer", "task_containers"),
("/taskDependency", "task_dependencies"),
("/taskFilterValue", "task_filter_values"),
("/taskLocked", "task_locked"),
("/taskUri", "task_uris"),
("/timeEntry", "time_entries"),
("/timeMarker", "time_markers"),
("/timeSession", "time_sessions"),
("/user", "users"),
])
}
fn intentionally_uncovered() -> BTreeMap<&'static str, &'static str> {
BTreeMap::from([(
"/tokens",
"auth/login flow; the SDK takes a pre-issued API key",
)])
}
#[test]
fn every_spec_path_is_accounted_for() {
let raw = std::fs::read_to_string(SPEC).expect("read spec");
let spec: serde_json::Value = serde_json::from_str(&raw).expect("parse spec");
let paths = spec["paths"].as_object().expect("paths object");
let covered = covered_paths();
let uncovered = intentionally_uncovered();
let missing: Vec<&str> = paths
.keys()
.map(String::as_str)
.filter(|p| !covered.contains_key(p) && !uncovered.contains_key(p))
.collect();
let stale: Vec<&str> = covered
.keys()
.chain(uncovered.keys())
.copied()
.filter(|p| !paths.contains_key(*p))
.collect();
assert!(
missing.is_empty(),
"spec paths without an accessor: {missing:?}. Add one on DimeSchedulerClient and list it in covered_paths."
);
assert!(
stale.is_empty(),
"paths listed here but gone from the spec: {stale:?}"
);
for p in covered.keys() {
assert!(
!uncovered.contains_key(p),
"{p} is both covered and intentionally uncovered"
);
}
}