@@ -282,6 +282,147 @@ func TestToolsCall_UploadDatasetScoped(t *testing.T) {
282282 }
283283}
284284
285+ func TestToolsCall_IndoorImportBuildingUsesMultipartUpload (t * testing.T ) {
286+ tmpDir := t .TempDir ()
287+ filePath := filepath .Join (tmpDir , "campus.ifc" )
288+ if err := os .WriteFile (filePath , []byte ("ISO-10303-21;" ), 0o600 ); err != nil {
289+ t .Fatalf ("write temp indoor file: %v" , err )
290+ }
291+
292+ mux := http .NewServeMux ()
293+ mux .HandleFunc ("POST /api/indoor/import" , func (w http.ResponseWriter , r * http.Request ) {
294+ if err := r .ParseMultipartForm (1 << 20 ); err != nil {
295+ w .WriteHeader (http .StatusBadRequest )
296+ fmt .Fprintf (w , `{"error":"parse=%v"}` , err )
297+ return
298+ }
299+ file , header , err := r .FormFile ("file" )
300+ if err != nil {
301+ w .WriteHeader (http .StatusBadRequest )
302+ fmt .Fprintf (w , `{"error":"file=%v"}` , err )
303+ return
304+ }
305+ defer file .Close ()
306+ if header .Filename != "campus.ifc" {
307+ w .WriteHeader (http .StatusBadRequest )
308+ fmt .Fprintf (w , `{"error":"filename=%s"}` , header .Filename )
309+ return
310+ }
311+ w .Header ().Set ("Content-Type" , "application/json" )
312+ w .WriteHeader (http .StatusCreated )
313+ fmt .Fprint (w , `{"id":"building-1","name":"HQ"}` )
314+ })
315+ srv := testServer (t , mux )
316+
317+ resp := sendRequest (t , srv , "tools/call" , 241 , map [string ]interface {}{
318+ "name" : "indoor_api" ,
319+ "arguments" : map [string ]interface {}{
320+ "operation" : "import_building" ,
321+ "file_path" : filePath ,
322+ "confirm" : true ,
323+ },
324+ })
325+
326+ if resp .Error != nil {
327+ t .Fatalf ("unexpected error: %v" , resp .Error )
328+ }
329+ result , _ := resp .Result .(map [string ]interface {})
330+ if isErr , _ := result ["isError" ].(bool ); isErr {
331+ t .Fatalf ("expected success result, got error: %+v" , result )
332+ }
333+ }
334+
335+ func TestToolsCall_IndoorUploadFloorPlanUsesMultipartBounds (t * testing.T ) {
336+ tmpDir := t .TempDir ()
337+ filePath := filepath .Join (tmpDir , "floor.png" )
338+ if err := os .WriteFile (filePath , []byte ("png-bytes" ), 0o600 ); err != nil {
339+ t .Fatalf ("write temp plan file: %v" , err )
340+ }
341+
342+ mux := http .NewServeMux ()
343+ mux .HandleFunc ("POST /api/indoor/buildings/{id}/floors/{fid}/plan" , func (w http.ResponseWriter , r * http.Request ) {
344+ if got := r .PathValue ("id" ); got != "building-1" {
345+ w .WriteHeader (http .StatusBadRequest )
346+ fmt .Fprintf (w , `{"error":"building=%s"}` , got )
347+ return
348+ }
349+ if got := r .PathValue ("fid" ); got != "floor-2" {
350+ w .WriteHeader (http .StatusBadRequest )
351+ fmt .Fprintf (w , `{"error":"floor=%s"}` , got )
352+ return
353+ }
354+ if err := r .ParseMultipartForm (1 << 20 ); err != nil {
355+ w .WriteHeader (http .StatusBadRequest )
356+ fmt .Fprintf (w , `{"error":"parse=%v"}` , err )
357+ return
358+ }
359+ if got := r .FormValue ("bounds" ); got != "[[1,2],[3,4]]" {
360+ w .WriteHeader (http .StatusBadRequest )
361+ fmt .Fprintf (w , `{"error":"bounds=%s"}` , got )
362+ return
363+ }
364+ w .Header ().Set ("Content-Type" , "application/json" )
365+ fmt .Fprint (w , `{"status":"uploaded","floor_id":"floor-2"}` )
366+ })
367+ srv := testServer (t , mux )
368+
369+ resp := sendRequest (t , srv , "tools/call" , 242 , map [string ]interface {}{
370+ "name" : "indoor_api" ,
371+ "arguments" : map [string ]interface {}{
372+ "operation" : "upload_floor_plan" ,
373+ "building_id" : "building-1" ,
374+ "floor_id" : "floor-2" ,
375+ "file_path" : filePath ,
376+ "bounds" : []interface {}{[]interface {}{1.0 , 2.0 }, []interface {}{3.0 , 4.0 }},
377+ "confirm" : true ,
378+ },
379+ })
380+
381+ if resp .Error != nil {
382+ t .Fatalf ("unexpected error: %v" , resp .Error )
383+ }
384+ result , _ := resp .Result .(map [string ]interface {})
385+ if isErr , _ := result ["isError" ].(bool ); isErr {
386+ t .Fatalf ("expected success result, got error: %+v" , result )
387+ }
388+ }
389+
390+ func TestToolsCall_IndoorGetScenario (t * testing.T ) {
391+ mux := http .NewServeMux ()
392+ mux .HandleFunc ("GET /api/indoor/buildings/{id}/scenarios/{sid}" , func (w http.ResponseWriter , r * http.Request ) {
393+ if got := r .PathValue ("id" ); got != "building-1" {
394+ w .WriteHeader (http .StatusBadRequest )
395+ fmt .Fprintf (w , `{"error":"building=%s"}` , got )
396+ return
397+ }
398+ if got := r .PathValue ("sid" ); got != "scenario-1" {
399+ w .WriteHeader (http .StatusBadRequest )
400+ fmt .Fprintf (w , `{"error":"scenario=%s"}` , got )
401+ return
402+ }
403+ w .Header ().Set ("Content-Type" , "application/json" )
404+ fmt .Fprint (w , `{"id":"scenario-1","name":"Evacuation Drill"}` )
405+ })
406+ srv := testServer (t , mux )
407+
408+ resp := sendRequest (t , srv , "tools/call" , 243 , map [string ]interface {}{
409+ "name" : "indoor_api" ,
410+ "arguments" : map [string ]interface {}{
411+ "operation" : "get_scenario" ,
412+ "building_id" : "building-1" ,
413+ "scenario_id" : "scenario-1" ,
414+ },
415+ })
416+
417+ if resp .Error != nil {
418+ t .Fatalf ("unexpected error: %v" , resp .Error )
419+ }
420+ result , _ := resp .Result .(map [string ]interface {})
421+ if isErr , _ := result ["isError" ].(bool ); isErr {
422+ t .Fatalf ("expected success result, got error: %+v" , result )
423+ }
424+ }
425+
285426func TestToolsCall_ExecuteSQL (t * testing.T ) {
286427 mux := http .NewServeMux ()
287428 mux .HandleFunc ("POST /api/query/sql" , func (w http.ResponseWriter , r * http.Request ) {
0 commit comments