22
33Guards the fix for issue #636 / #357 (landed on main via #700) at the product
44surface (real codebase-memory-mcp process, real SQLite DB, real stdio). Two
5- byte-identical TypeScript fixtures are indexed: one under an ASCII parent path,
6- one under a non-ASCII parent path. The invariant under test:
5+ byte-identical polyglot fixtures (TypeScript + Go, #1959) are indexed: one under
6+ an ASCII parent path, one under a non-ASCII parent path. The invariant under test:
77
88 A byte-identical fixture must produce equivalent graph counts regardless of
99 whether its absolute path contains non-ASCII characters.
5454 "run();\n "
5555)
5656
57+ # Dummy Go package covering the shapes the Go/cgo extraction work (#1932
58+ # family) showed were previously invisible to CI: struct fields and a method,
59+ # a build-tag twin pair sharing one function name, a cgo file (C preamble,
60+ # `C.` call, `//export` directive), and a channel producer/consumer pair
61+ # (#1959). Go qualified names embed the containing directory, so these also
62+ # put non-ASCII repo paths through the Go pipeline passes.
63+ GO_MOD = "module example.com/fixture\n \n go 1.22\n "
64+
65+ GO_STORE = """package gopkg
66+
67+ type Store struct {
68+ Total int
69+ Name string
70+ }
71+
72+ func (s *Store) Push(x int) {
73+ s.Total = s.Total + x
74+ }
75+
76+ func NewStore(name string) *Store {
77+ return &Store{Name: name}
78+ }
79+ """
80+
81+ GO_FLUSH_LINUX = """//go:build linux
82+
83+ package gopkg
84+
85+ func FlushDisk() int { return 1 }
86+ """
87+
88+ GO_FLUSH_WINDOWS = """//go:build windows
89+
90+ package gopkg
91+
92+ func FlushDisk() int { return 2 }
93+ """
94+
95+ GO_BRIDGE = """package gopkg
96+
97+ /*
98+ #include <stdio.h>
99+ static void announce(void) { puts("hi"); }
100+ */
101+ import "C"
102+
103+ //export FixtureReady
104+ func FixtureReady() int { return 3 }
105+
106+ func Announce() {
107+ C.announce()
108+ }
109+ """
110+
111+ GO_EVENTS = """package gopkg
112+
113+ func Produce(events chan string) {
114+ events <- "tick"
115+ }
116+
117+ func Drain(events chan string) string {
118+ v := <-events
119+ return v
120+ }
121+ """
122+
123+ GO_FILES = (
124+ ("go.mod" , GO_MOD ),
125+ ("gopkg/store.go" , GO_STORE ),
126+ ("gopkg/flush_linux.go" , GO_FLUSH_LINUX ),
127+ ("gopkg/flush_windows.go" , GO_FLUSH_WINDOWS ),
128+ ("gopkg/bridge.go" , GO_BRIDGE ),
129+ ("gopkg/events.go" , GO_EVENTS ),
130+ )
131+
57132# Distinct non-ASCII scripts — each must behave like the ASCII baseline.
58133NON_ASCII_SEGMENTS = {
59134 "latin1_accents" : "café_repo" ,
@@ -244,6 +319,11 @@ def make_fixture(root):
244319 for name , text in (("math.ts" , MATH_TS ), ("main.ts" , MAIN_TS )):
245320 with open (os .path .join (src , name ), "wb" ) as f :
246321 f .write (text .encode ("utf-8" )) # exact bytes, identical across copies
322+ for rel , text in GO_FILES :
323+ path = os .path .join (root , rel .replace ("/" , os .sep ))
324+ os .makedirs (os .path .dirname (path ) or root , exist_ok = True )
325+ with open (path , "wb" ) as f :
326+ f .write (text .encode ("utf-8" ))
247327
248328
249329def no_project_error (index_txt , repo , cache ):
@@ -323,6 +403,25 @@ def index_and_count(binary, repo, cache):
323403 except Exception :
324404 pass
325405 out ["definition_nodes" ] = defs
406+ # Go-file definitions separately: the Go passes derive qualified names
407+ # from the containing directory, so they meet non-ASCII paths on a
408+ # different route than the TS passes; a Go-specific count catches a
409+ # regression that total counts could mask (#1959).
410+ go_defs = 0
411+ for label in ("Function" , "Method" ):
412+ q = ("MATCH (n:%s) WHERE n.file_path CONTAINS '.go' "
413+ "RETURN count(n)" % label )
414+ r = s .call_tool ("query_graph" ,
415+ {"query" : q , "project" : name , "format" : "json" },
416+ timeout = 60 )
417+ t , _ = s .tool_text (r )
418+ try :
419+ rows = json .loads (t ).get ("rows" ) or []
420+ if rows and rows [0 ]:
421+ go_defs += int (rows [0 ][0 ])
422+ except Exception :
423+ pass
424+ out ["go_definition_nodes" ] = go_defs
326425 return out
327426
328427
@@ -363,11 +462,16 @@ def main():
363462 if base .get ("error" ) or not base .get ("nodes" ):
364463 print ("SETUP FAIL: ASCII baseline did not index: %r" % base )
365464 return 2
366- print ("baseline (ASCII): nodes=%s edges=%s definitions=%s" %
367- (base ["nodes" ], base ["edges" ], base ["definition_nodes" ]))
465+ print ("baseline (ASCII): nodes=%s edges=%s definitions=%s go=%s" %
466+ (base ["nodes" ], base ["edges" ], base ["definition_nodes" ],
467+ base ["go_definition_nodes" ]))
368468 if base ["definition_nodes" ] < 1 :
369469 print ("SETUP FAIL: ASCII baseline produced no definitions: %r" % base )
370470 return 2
471+ if base ["go_definition_nodes" ] < 1 :
472+ print ("SETUP FAIL: ASCII baseline extracted no Go definitions: %r"
473+ % base )
474+ return 2
371475
372476 for key , seg in NON_ASCII_SEGMENTS .items ():
373477 repo = os .path .join (work , seg )
@@ -376,13 +480,15 @@ def main():
376480 ok = (not got .get ("error" )
377481 and got .get ("nodes" ) == base ["nodes" ]
378482 and got .get ("edges" ) == base ["edges" ]
379- and got .get ("definition_nodes" ) == base ["definition_nodes" ])
483+ and got .get ("definition_nodes" ) == base ["definition_nodes" ]
484+ and got .get ("go_definition_nodes" ) == base ["go_definition_nodes" ])
380485 status = "PASS" if ok else "FAIL"
381- print ("[%s] non-ascii/%-14s nodes=%s edges=%s definitions=%s "
382- "(baseline %s/%s/%s) name=%r" %
486+ print ("[%s] non-ascii/%-14s nodes=%s edges=%s definitions=%s go=%s "
487+ "(baseline %s/%s/%s/%s ) name=%r" %
383488 (status , key , got .get ("nodes" ), got .get ("edges" ),
384- got .get ("definition_nodes" ), base ["nodes" ], base ["edges" ],
385- base ["definition_nodes" ], got .get ("name" )))
489+ got .get ("definition_nodes" ), got .get ("go_definition_nodes" ),
490+ base ["nodes" ], base ["edges" ], base ["definition_nodes" ],
491+ base ["go_definition_nodes" ], got .get ("name" )))
386492 if not ok :
387493 # The counts alone cannot explain a venue-specific failure;
388494 # surface the captured error verbatim so CI logs carry the
@@ -400,7 +506,9 @@ def main():
400506 if (not retry .get ("error" )
401507 and retry .get ("nodes" ) == base ["nodes" ]
402508 and retry .get ("edges" ) == base ["edges" ]
403- and retry .get ("definition_nodes" ) == base ["definition_nodes" ]):
509+ and retry .get ("definition_nodes" ) == base ["definition_nodes" ]
510+ and retry .get ("go_definition_nodes" )
511+ == base ["go_definition_nodes" ]):
404512 print (" %s retry matched baseline -- order-dependent, "
405513 "not path-dependent" % key )
406514 else :
0 commit comments