1use crate::{BenchError, BenchSpec};
9use thiserror::Error;
10
11#[derive(Debug, Error)]
13pub enum BrowserRunnerError {
14 #[error("failed to parse BenchSpec JSON: {0}")]
16 InvalidSpec(serde_json::Error),
17 #[error("failed to run benchmark: {0}")]
19 Benchmark(#[from] BenchError),
20 #[error("failed to serialize RunnerReport JSON: {0}")]
22 SerializeReport(serde_json::Error),
23}
24
25pub fn run_benchmark_json(spec_json: &str) -> Result<String, BrowserRunnerError> {
31 let spec =
32 serde_json::from_str::<BenchSpec>(spec_json).map_err(BrowserRunnerError::InvalidSpec)?;
33 let report = crate::run_benchmark(spec)?;
34 serde_json::to_string(&report).map_err(BrowserRunnerError::SerializeReport)
35}
36
37#[cfg(target_arch = "wasm32")]
41#[wasm_bindgen::prelude::wasm_bindgen(js_name = runBenchmarkJson)]
42pub fn run_benchmark_json_wasm(spec_json: &str) -> Result<String, wasm_bindgen::JsValue> {
43 run_benchmark_json(spec_json)
44 .map_err(|error| wasm_bindgen::JsValue::from_str(&error.to_string()))
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50 use crate::timing::{BenchReport, TimingError, run_closure};
51
52 fn run_test_benchmark(spec: BenchSpec) -> Result<BenchReport, TimingError> {
53 run_closure(spec, || {
54 std::hint::black_box(21_u64.saturating_mul(2));
55 Ok(())
56 })
57 }
58
59 inventory::submit! {
60 crate::registry::BenchFunction {
61 name: "mobench_sdk::web::tests::browser_json_contract",
62 runner: run_test_benchmark,
63 }
64 }
65
66 #[test]
67 fn returns_runner_report_json() {
68 let result =
69 run_benchmark_json(r#"{"name":"browser_json_contract","iterations":2,"warmup":1}"#)
70 .expect("browser benchmark should run");
71 let report: crate::RunnerReport =
72 serde_json::from_str(&result).expect("valid RunnerReport JSON");
73
74 assert_eq!(report.spec.name, "browser_json_contract");
75 assert_eq!(report.samples.len(), 2);
76 }
77
78 #[test]
79 fn rejects_invalid_spec_json() {
80 let error = run_benchmark_json("{not json}").expect_err("invalid JSON should fail");
81
82 assert!(matches!(error, BrowserRunnerError::InvalidSpec(_)));
83 assert!(error.to_string().contains("failed to parse BenchSpec JSON"));
84 }
85
86 #[test]
87 fn reports_unknown_benchmark() {
88 let error = run_benchmark_json(
89 r#"{"name":"definitely_missing_browser_benchmark","iterations":1,"warmup":0}"#,
90 )
91 .expect_err("unknown function should fail");
92
93 assert!(matches!(
94 error,
95 BrowserRunnerError::Benchmark(BenchError::UnknownFunction(_, _))
96 ));
97 }
98}