app
SOLIDWORKS Bridge
Public Made by Adomby adom
Launch, model and quit SOLIDWORKS from any Adom container. Nothing is ever lost.
main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
//! `swx_render_image` (0.9.18) in the simulator. The simulated viewport keeps
//! its DISPLAY STATE in the data root (`mock-display-state.json`) so every test
//! can compare it before and after: whatever the render applies is restored,
//! on success and on error. The COM side (com.rs) is UNMEASURED.
mod common;
use common::{Bridge, TempDir};
use serde_json::{json, Value};
fn s(v: &Value) -> String {
serde_json::to_string_pretty(v).unwrap_or_default()
}
fn session(scratch: &TempDir) {
std::fs::write(
scratch.join("mock-solidworks-open-docs.json"),
json!({"running": true, "untitled": 0, "active": "C:\\Users\\Public\\adom-hero\\Moveo.SLDASM",
"docs": [{"docType": "assembly", "path": "C:\\Users\\Public\\adom-hero\\Moveo.SLDASM",
"title": "Moveo.SLDASM", "saved": true, "dirty": false}],
"files": {}}).to_string(),
)
.unwrap();
}
fn display(scratch: &TempDir) -> Value {
std::fs::read_to_string(scratch.join("mock-display-state.json"))
.ok()
.and_then(|t| serde_json::from_str(&t).ok())
.unwrap_or(Value::Null)
}
const USERS_VIEW: &str = r#"{"displayMode":5,"perspective":false,"realView":false,"shadows":false,"ambientOcclusion":false,"backgroundAppearance":3,"backgroundColor":13421772,"orientation":"user-view","scale":1.0}"#;
fn boot(tag: &str) -> (Bridge, TempDir) {
let scratch = TempDir::new(tag);
session(&scratch);
std::fs::write(scratch.join("mock-display-state.json"), USERS_VIEW).unwrap();
let b = Bridge::start_in(TempDir::borrowed(&scratch.0), &[]);
b.call("swx_start", json!({}));
(b, scratch)
}
fn hero(extra: Value) -> Value {
let mut a = json!({"width": 64, "height": 48, "view": "isometric", "displayStyle": "shaded",
"perspective": true, "realView": true, "ambientOcclusion": true, "shadows": true,
"background": "white", "zoomToFit": true, "reason": "a hero shot of the Moveo assembly"});
if let (Value::Object(m), Value::Object(e)) = (&mut a, extra) {
m.extend(e);
}
a
}
#[test]
fn a_render_writes_a_png_of_the_asked_size_and_restores_every_setting() {
let (b, scratch) = boot("render-ok");
let before = display(&scratch);
let r = b.call("swx_render_image", hero(json!({})));
check!(b, "the render succeeds", r["success"] == true, s(&r));
let path = r["path"].as_str().unwrap_or("").to_string();
let bytes = std::fs::read(&path).unwrap_or_default();
check!(
b,
"the default path is in the data root's exports folder, named for the document, view and size",
path.contains("exports") && path.contains("Moveo-isometric-64x48-") && path.ends_with(".png"),
path.clone()
);
check!(b, "the file is a PNG (signature)", bytes.starts_with(b"\x89PNG\r\n\x1a\n"), format!("{} bytes", bytes.len()));
let (w, h) = (u32::from_be_bytes([bytes[16], bytes[17], bytes[18], bytes[19]]), u32::from_be_bytes([bytes[20], bytes[21], bytes[22], bytes[23]]));
check!(
b,
"width/height in the reply are the PNG header's, and they are what was asked",
(w, h) == (64, 48) && r["width"] == 64 && r["height"] == 48 && r["capped"] == false && r["bytes"] == bytes.len(),
s(&r)
);
let restored = r["restoredSettings"].as_object().cloned().unwrap_or_default();
check!(
b,
"every setting the render changed is listed as restored, with its read-back",
["displayMode", "perspective", "realView", "shadows", "ambientOcclusion", "backgroundColor", "orientation", "scale"]
.iter()
.all(|k| restored.get(*k).map(|v| v["restored"] == true).unwrap_or(false))
&& r["restoreIncomplete"] == false,
s(&r["restoredSettings"])
);
check!(b, "THE USER'S VIEW IS EXACTLY AS IT WAS", display(&scratch) == before, format!("{} vs {}", display(&scratch), before));
check!(b, "the temporary BMP is gone", !std::fs::read_dir(scratch.join("exports")).unwrap().flatten().any(|e| e.file_name().to_string_lossy().ends_with(".bmp")), String::new());
}
#[test]
fn a_failed_render_restores_every_setting_too() {
let (b, scratch) = boot("render-fails");
let before = display(&scratch);
std::fs::write(scratch.join("mock-render-fails"), "").unwrap();
let r = b.call("swx_render_image", hero(json!({})));
check!(
b,
"SaveBMP failed: render_failed, with what was applied and what was restored",
r["errorCode"] == "render_failed" && r["appliedSettings"]["realView"].is_object()
&& r["restoredSettings"]["realView"]["restored"] == true,
s(&r)
);
check!(b, "...and the user's view is exactly as it was", display(&scratch) == before, display(&scratch).to_string());
}
#[test]
fn a_restore_that_did_not_take_is_said_loudly() {
let (b, scratch) = boot("render-norestore");
std::fs::write(scratch.join("mock-render-skips-restore"), "").unwrap();
let r = b.call("swx_render_image", hero(json!({})));
check!(
b,
"restoreIncomplete:true, the settings named, the hint says so",
r["restoreIncomplete"] == true && r["restoreFailures"].as_array().map(|a| !a.is_empty()).unwrap_or(false)
&& r["_hint"].as_str().unwrap_or("").contains("NOT EVERY DISPLAY SETTING"),
s(&r)
);
}
#[test]
fn a_window_capped_export_says_so() {
let (b, scratch) = boot("render-capped");
std::fs::write(scratch.join("mock-render-capped"), "").unwrap();
let r = b.call("swx_render_image", hero(json!({"width": 2000, "height": 1000})));
check!(
b,
"capped:true, with the size actually in the file (read back), not the size asked",
r["success"] == true && r["capped"] == true && r["width"] == 1568 && r["height"] == 882
&& r["requested"]["width"] == 2000,
s(&r)
);
}
#[test]
fn bad_destinations_and_options_are_refused_before_anything_changes() {
let (b, scratch) = boot("render-refusals");
let before = display(&scratch);
let out = TempDir::new("render-out");
let missing = format!("{}/no-such-folder/hero.png", out.path());
let r = b.call("swx_render_image", hero(json!({"path": missing})));
check!(b, "a folder that does not exist: output_dir_missing (never created)", r["errorCode"] == "output_dir_missing" && !out.join("no-such-folder").exists(), s(&r));
let existing = out.join("taken.png");
std::fs::write(&existing, "x").unwrap();
let r = b.call("swx_render_image", hero(json!({"path": existing.to_string_lossy()})));
check!(b, "an existing file: output_exists (never written over)", r["errorCode"] == "output_exists" && std::fs::read(&existing).unwrap() == b"x", s(&r));
let r = b.call("swx_render_image", hero(json!({"background": "transparent"})));
check!(b, "transparent: render_option_unsupported, said plainly", r["errorCode"] == "render_option_unsupported", s(&r));
let r = b.call("swx_render_image", hero(json!({"path": "relative.png"})));
check!(b, "a relative path: unsafe_path", r["errorCode"] == "unsafe_path", s(&r));
let r = b.call("swx_render_image", hero(json!({"width": 100000})));
check!(b, "an absurd size: bad_size", r["errorCode"] == "bad_size", s(&r));
let r = b.call("swx_render_image", json!({"width": 64, "height": 48}));
check!(b, "no reason: reason_required", r["errorCode"] == "reason_required", s(&r));
check!(b, "...and NONE of those changed the user's view", display(&scratch) == before, display(&scratch).to_string());
// A path that IS valid: written exactly there.
let good = out.join("hero.png");
let r = b.call("swx_render_image", hero(json!({"path": good.to_string_lossy()})));
check!(b, "a valid path: written there", r["success"] == true && good.is_file(), s(&r));
}
#[test]
fn an_unreadable_enum_id_refuses_before_changing_anything() {
let (b, scratch) = boot("render-enum");
let before = display(&scratch);
std::fs::write(scratch.join("mock-render-enum-unresolved"), "").unwrap();
let r = b.call("swx_render_image", hero(json!({})));
check!(b, "render_enum_unresolved — the bridge never guesses a swconst id", r["errorCode"] == "render_enum_unresolved", s(&r));
check!(b, "...and nothing changed", display(&scratch) == before, display(&scratch).to_string());
}
#[test]
fn a_render_that_changes_the_screen_respects_the_user_at_the_keyboard() {
let scratch = TempDir::new("render-presence");
session(&scratch);
std::fs::write(scratch.join("mock-display-state.json"), USERS_VIEW).unwrap();
let machine = TempDir::new("render-presence-m");
std::fs::write(machine.join("windows.json"), "[]").unwrap();
std::fs::write(machine.join("last-input-secs"), "2").unwrap();
let b = Bridge::start_in(TempDir::borrowed(&scratch.0), &[("SWX_LAUNCH_FAKE_DIR", &machine.path())]);
b.call("swx_start", json!({}));
let pid = b.call("swx_get_app_state", json!({}))["processId"].as_u64().unwrap();
std::fs::write(machine.join("foreground.json"), json!({"hwnd": 4242, "pid": pid, "title": "SOLIDWORKS", "className": "Afx"}).to_string()).unwrap();
let r = b.call("swx_render_image", hero(json!({})));
check!(b, "a render that changes the view, the user at the keyboard: user_is_active", r["errorCode"] == "user_is_active", s(&r));
let r = b.call("swx_render_image", json!({"width": 64, "height": 48, "reason": "the current view, as it is"}));
check!(
b,
"an export of the CURRENT view changes nothing on screen: allowed, and nothing was applied",
r["success"] == true && r["appliedSettings"].as_object().map(|m| m.is_empty()).unwrap_or(false),
s(&r)
);
}
/// EVERY REQUESTED SETTING IS ACCOUNTED FOR (0.9.19). Measured 2026-10-05:
/// `shadows:true` appeared in neither applied nor restored — already on, or not
/// applied? `settings` says which, for every setting asked for.
#[test]
fn every_requested_setting_says_what_happened_to_it() {
let scratch = TempDir::new("render-settings");
session(&scratch);
// Shadows ALREADY on in the user's view.
std::fs::write(scratch.join("mock-display-state.json"), USERS_VIEW.replace(r#""shadows":false"#, r#""shadows":true"#)).unwrap();
// ...and ambient occlusion unreadable on this machine.
std::fs::write(scratch.join("mock-render-unreadable-ambientOcclusion"), "").unwrap();
let b = Bridge::start_in(TempDir::borrowed(&scratch.0), &[]);
b.call("swx_start", json!({}));
let r = b.call("swx_render_image", hero(json!({"zoomFactor": 2.5})));
let st = &r["settings"];
let names = ["view", "displayStyle", "perspective", "realView", "ambientOcclusion", "shadows", "background", "zoomToFit", "zoomFactor"];
check!(
b,
"every requested setting has a row {requested, before, after, changed, restored, why}",
names.iter().all(|n| ["requested", "before", "after", "changed", "restored", "why"].iter().all(|k| st[*n].get(*k).is_some())),
s(st)
);
check!(
b,
"shadows: already on — changed false, restored null, why alreadyAsRequested",
st["shadows"]["changed"] == false && st["shadows"]["restored"].is_null() && st["shadows"]["why"] == "alreadyAsRequested"
&& st["shadows"]["before"] == true,
s(&st["shadows"])
);
check!(
b,
"ambient occlusion: unreadable — said so, not silently absent",
st["ambientOcclusion"]["why"] == "unreadable" && st["ambientOcclusion"]["changed"] == false,
s(&st["ambientOcclusion"])
);
check!(
b,
"realView: applied and restored",
st["realView"]["changed"] == true && st["realView"]["restored"] == true && st["realView"]["before"] == false && st["realView"]["after"] == true,
s(&st["realView"])
);
check!(
b,
"zoomFactor: applied after the fit (scale 0.42 x 2.5) and restored",
st["zoomFactor"]["changed"] == true && st["zoomFactor"]["restored"] == true && st["zoomFactor"]["after"] == json!(1.05),
s(&st["zoomFactor"])
);
check!(b, "the swconst ids are reported for the record", r["enumIds"].is_object(), s(&r["enumIds"]));
let bad = b.call("swx_render_image", hero(json!({"zoomFactor": 0})));
check!(b, "a zoomFactor out of range: bad_zoom_factor", bad["errorCode"] == "bad_zoom_factor", s(&bad));
}
/// MEASURED 2026-10-05: RealView's put returned OK and the read-back was still
/// FALSE (uncertified GPU). A set SOLIDWORKS ignored is NOT "applied": why
/// setIgnored, changed false, restored null — and a `notes` line says so.
#[test]
fn a_setting_solidworks_ignores_is_not_reported_as_applied() {
let scratch = TempDir::new("render-ignored");
session(&scratch);
std::fs::write(scratch.join("mock-render-ignores-realView"), "").unwrap();
let b = Bridge::start_in(TempDir::borrowed(&scratch.0), &[]);
b.call("swx_start", json!({}));
let r = b.call("swx_render_image", hero(json!({})));
let rv = &r["settings"]["realView"];
check!(b, "the render itself still succeeded", r["success"] == true, s(&r));
check!(
b,
"realView: why setIgnored, changed false, restored null, before=after=false",
rv["why"] == "setIgnored" && rv["changed"] == false && rv["restored"].is_null()
&& rv["before"] == false && rv["after"] == false,
s(rv)
);
check!(
b,
"not in appliedSettings, not in restoredSettings",
r["appliedSettings"].get("realView").is_none() && r["restoredSettings"].get("realView").is_none(),
s(&r)
);
let notes = r["notes"].as_array().cloned().unwrap_or_default();
check!(
b,
"a notes line says RealView was requested but left off, and why",
notes.iter().any(|n| {
let n = n.as_str().unwrap_or("");
n.starts_with("RealView was requested but SOLIDWORKS left it off") && n.contains("certified graphics card")
&& n.contains("minimized")
}),
s(&r["notes"])
);
check!(
b,
"the other settings were applied as usual",
r["settings"]["shadows"]["why"] == "applied" && r["settings"]["ambientOcclusion"]["why"] == "applied",
s(&r["settings"])
);
std::fs::remove_file(scratch.join("mock-render-ignores-realView")).unwrap();
let clean = b.call("swx_render_image", hero(json!({})));
check!(b, "with nothing ignored, notes is empty", clean["notes"] == json!([]), s(&clean["notes"]));
}