module SomhairlesDream.Modeling.Tests.BridgeTests open System open System.IO open Xunit open SomhairlesDream.Modeling let private withTempDirectory action = let path = Path.Combine(Path.GetTempPath(), "somhairles-dream-bridge-" + Guid.NewGuid().ToString("N")) Directory.CreateDirectory(path) |> ignore try action path finally if Directory.Exists(path) then Directory.Delete(path, true) let private fixtureScript = [| "import argparse" "import json" "import os" "" "parser = argparse.ArgumentParser()" "parser.add_argument('--step-id', required=True)" "parser.add_argument('--output', required=True)" "parser.add_argument('--render-output')" "parser.add_argument('--result-output')" "args = parser.parse_args()" "os.makedirs(os.path.dirname(args.output), exist_ok=True)" "with open(args.output, 'wb') as stream:" " stream.write(b'glTF')" "result_path = args.result_output or args.output + '.result.json'" "with open(result_path, 'w', encoding='utf-8') as stream:" " json.dump({" " 'ok': True," " 'blenderVersion': 'test'," " 'exportedAt': '2026-09-20T12:00:05Z'," " 'objectIds': ['heritage.foundation', 'heritage.deck']," " 'verifiedObjectIds': ['heritage.foundation', 'heritage.deck']," " 'glbBytes': 4" " }, stream)" "with open(args.output + '.log', 'w', encoding='utf-8') as stream:" " stream.write('fixture log retained separately\\n')" "print('Blender informational output')" |] |> String.concat Environment.NewLine [] let ``bridge reads result file instead of polluted stdout and retains process log`` () = withTempDirectory (fun root -> let blenderRoot = Path.Combine(root, "stage", "blender") Directory.CreateDirectory(blenderRoot) |> ignore File.WriteAllText(Path.Combine(blenderRoot, "fixture.py"), fixtureScript) let output = Path.Combine(root, "run", "step.glb") let request = { Step = Design.steps[0] GlbPath = output RenderPath = None ResultPath = output + ".result.json" LogPath = output + ".log" } let result = (BlenderProcessBridge("python3", Path.Combine(root, "stage")) :> IArtifactBridge) .Export(request, ignore) match result with | Error message -> failwith message | Ok value -> Assert.Equal("test", value.BlenderVersion) Assert.Equal(4L, value.GlbBytes) Assert.True(File.Exists(output + ".log")) Assert.Contains("Blender informational output", File.ReadAllText(output + ".log")))