test(go): golden capture-parity guard for emitGoScopeCaptures (#1848 U1)
Pins emitGoScopeCaptures output across all 89 go-* fixtures + a synthetic DAO shape as a committed golden (test/fixtures/go-captures-golden/expected-captures.json), so future drift in the Go scope-capture path fails CI instead of only the coarse perf tripwire. Match-grouped, order-independent sha256 canonicalization; regenerate intentionally with UPDATE_GOLDEN=1. Mirrors test/integration/pipeline-graph-golden.test.ts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
Gergo Magyar
co-authored by
Claude Opus 4.8
parent
f86150707c
commit
b090f2b4e1
@@ -0,0 +1,362 @@
|
||||
{
|
||||
"go-aliased-package-import/internal/util/log.go": {
|
||||
"captureGroups": 4,
|
||||
"digest": "41e9e3d504509d3918723770b7c2d1afe5810484c2315fd6f30e600e05c3b2a5"
|
||||
},
|
||||
"go-aliased-package-import/main.go": {
|
||||
"captureGroups": 7,
|
||||
"digest": "bce19f66617eb9db4b0f8ae4fbe25159226b79ee2e6fb84b5958963de4675472"
|
||||
},
|
||||
"go-ambiguous/internal/models/handler.go": {
|
||||
"captureGroups": 9,
|
||||
"digest": "7738516d8dc80922530db1eec3663adee74f633d4cabfc243996ae4196909fc4"
|
||||
},
|
||||
"go-ambiguous/internal/other/handler.go": {
|
||||
"captureGroups": 9,
|
||||
"digest": "6716caae0d8ee91d1cd6d5cd33c167d93a48d77ba4cf8c8c9b0dbfc8f98aa996"
|
||||
},
|
||||
"go-ambiguous/internal/services/user.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "2692d14c00a6238eb7840d64c7fa73e91c85c13dddf2a584be398a2fab9a7648"
|
||||
},
|
||||
"go-assignment-chain/cmd/main.go": {
|
||||
"captureGroups": 50,
|
||||
"digest": "4f74ab86ea15f343d6f82d8413998f7078ca979971067ffbae4c85bce52a41c9"
|
||||
},
|
||||
"go-assignment-chain/models/repo.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "43736fad4b59031e430a18d5f7d20ea5a3fd0306c870d323faef0e27681691e4"
|
||||
},
|
||||
"go-assignment-chain/models/user.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "d9ac10cc3e7a441758616566bcc9138d0e5860922369f674044e888864ce6780"
|
||||
},
|
||||
"go-call-result-binding/cmd/main.go": {
|
||||
"captureGroups": 16,
|
||||
"digest": "80014d52ebc6e7a07fdbc1a97e0874617e0286b06d6a5839cffad2cdb2e9a1a0"
|
||||
},
|
||||
"go-call-result-binding/models/user.go": {
|
||||
"captureGroups": 10,
|
||||
"digest": "0e997eb91cb5636e6615ff54dd93e5e1337dadab05b8d7bd8223f1c34df9ab1e"
|
||||
},
|
||||
"go-calls/cmd/main.go": {
|
||||
"captureGroups": 6,
|
||||
"digest": "7a2555acc08958b7d31a58fac9c85228d4c75e36ece8d7e3fa9c6c9794dd5247"
|
||||
},
|
||||
"go-calls/internal/onearg/log.go": {
|
||||
"captureGroups": 6,
|
||||
"digest": "a9c6f0559affaa76a28eff3e50cc3022236f9e4ba46818a20d31400be689faac"
|
||||
},
|
||||
"go-calls/internal/zeroarg/log.go": {
|
||||
"captureGroups": 5,
|
||||
"digest": "e2511a692ba392bb121ce02dc4ccb3e48ec5e2a4a5dbd506cd70a6bf93037442"
|
||||
},
|
||||
"go-chain-call/cmd/main.go": {
|
||||
"captureGroups": 20,
|
||||
"digest": "0118c2729a2607021c85b7af534d4d10947296349fa80c9913f8cbc3d04005fd"
|
||||
},
|
||||
"go-chain-call/models/repo.go": {
|
||||
"captureGroups": 10,
|
||||
"digest": "aedabd86f2a5f79242559be20fcc92235d7803aab603964014900f4aa918d510"
|
||||
},
|
||||
"go-chain-call/models/user.go": {
|
||||
"captureGroups": 10,
|
||||
"digest": "0e997eb91cb5636e6615ff54dd93e5e1337dadab05b8d7bd8223f1c34df9ab1e"
|
||||
},
|
||||
"go-child-extends-parent/models/child.go": {
|
||||
"captureGroups": 3,
|
||||
"digest": "342eee3d77dff198b7e6141731c916d5826b924aa3da4418b3d6841f98c5d0bb"
|
||||
},
|
||||
"go-child-extends-parent/models/parent.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "39c966e77ff29a77a26b02aba78522f03aee80ea35705712072524637826e9ff"
|
||||
},
|
||||
"go-child-extends-parent/services/app.go": {
|
||||
"captureGroups": 10,
|
||||
"digest": "b9df4e73f171ea576808b3008b008bc8e1c8744b7faefbf82386cfdcdfb3071e"
|
||||
},
|
||||
"go-cmd-helper/cmd/server/internal/config/config.go": {
|
||||
"captureGroups": 5,
|
||||
"digest": "d57f553c8c3cd3d3fdf3e77399740bb47952b6dc0e3f94ba851f92275d920b1f"
|
||||
},
|
||||
"go-cmd-helper/cmd/server/main.go": {
|
||||
"captureGroups": 7,
|
||||
"digest": "e6f35bb4c7e068f9cda8088847446d02a3f13639f1423bb0a26e395edc43b141"
|
||||
},
|
||||
"go-constructor-type-inference/cmd/main.go": {
|
||||
"captureGroups": 15,
|
||||
"digest": "14cf51d0863eb826a1465076e63f704598cae82726b13e6441144eb74ca50481"
|
||||
},
|
||||
"go-constructor-type-inference/models/repo.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "43736fad4b59031e430a18d5f7d20ea5a3fd0306c870d323faef0e27681691e4"
|
||||
},
|
||||
"go-constructor-type-inference/models/user.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "d9ac10cc3e7a441758616566bcc9138d0e5860922369f674044e888864ce6780"
|
||||
},
|
||||
"go-deep-field-chain/cmd/main.go": {
|
||||
"captureGroups": 13,
|
||||
"digest": "f28677390371c2f8bccef6473e730300d8ee07d270d82e97892e5a664770ede9"
|
||||
},
|
||||
"go-deep-field-chain/models/models.go": {
|
||||
"captureGroups": 33,
|
||||
"digest": "80107196afad2d229f5518e433328416c001e9b293efe3c1b8c9c08d4e050ec0"
|
||||
},
|
||||
"go-field-types/cmd/main.go": {
|
||||
"captureGroups": 9,
|
||||
"digest": "5f5a502d81c17574a165f27160ca8a1c3371bf877a747eb97d0e73eb89eb4358"
|
||||
},
|
||||
"go-field-types/models/models.go": {
|
||||
"captureGroups": 22,
|
||||
"digest": "e295f5dc526c60a3381fb059e12ee168328ca6def6966f6cc7fcc57c2c7d8822"
|
||||
},
|
||||
"go-for-call-expr/cmd/main.go": {
|
||||
"captureGroups": 27,
|
||||
"digest": "864bd4e722283e1e401427a40efb1c98da48cc0c47ee6eedcdd0ce1dbded12f0"
|
||||
},
|
||||
"go-for-call-expr/models/repo.go": {
|
||||
"captureGroups": 14,
|
||||
"digest": "1627ce670ab6dfb5ac233baa374dcd516bb0e31c7404daa13faecd16287616be"
|
||||
},
|
||||
"go-for-call-expr/models/user.go": {
|
||||
"captureGroups": 14,
|
||||
"digest": "0ada592e34bfbb021eef45865deffb7fcac4f79c205d88b2700cf4eaaf2b2a4d"
|
||||
},
|
||||
"go-inc-dec-write-access/main.go": {
|
||||
"captureGroups": 21,
|
||||
"digest": "8f996bfae2b96c38aee2c466501ca0f96ee49fe49854e617317cd309a311f163"
|
||||
},
|
||||
"go-local-shadow/cmd/main.go": {
|
||||
"captureGroups": 12,
|
||||
"digest": "44ddef75c0e6a573ff3de922a039926801a87ba8191d14b75e92bd40b3e10133"
|
||||
},
|
||||
"go-local-shadow/internal/utils/utils.go": {
|
||||
"captureGroups": 6,
|
||||
"digest": "970e265c1246ac54739d78ebd8abc749114e33931e107b00b9c28106d4d09972"
|
||||
},
|
||||
"go-make-builtin/main.go": {
|
||||
"captureGroups": 18,
|
||||
"digest": "f89bee010abfed6ee199cbc07ca56f5ce35f6e8967bb0d6619416740f2f75c36"
|
||||
},
|
||||
"go-make-builtin/models.go": {
|
||||
"captureGroups": 15,
|
||||
"digest": "7627584e8e3775d2bed1341010c3ee5e81c4ec0104607ccf751ef1374270f5df"
|
||||
},
|
||||
"go-map-range/main.go": {
|
||||
"captureGroups": 10,
|
||||
"digest": "665cf8d7d0b70b0ecf088e25ea8509d368611429e7d18ce286fb44537360138e"
|
||||
},
|
||||
"go-map-range/models/repo.go": {
|
||||
"captureGroups": 9,
|
||||
"digest": "0a65a8956b22f1079e3bcc7f4f85200e7fdcef18cd955a77c5f3433b21386173"
|
||||
},
|
||||
"go-map-range/models/user.go": {
|
||||
"captureGroups": 9,
|
||||
"digest": "cc11974da05b96e917947973f0de3e485a5591f03b991b66fc50556e39009643"
|
||||
},
|
||||
"go-member-calls/cmd/main.go": {
|
||||
"captureGroups": 11,
|
||||
"digest": "5619f3584b8848c89783a4e05237c1516c46b1e686836fd25b57cd58c2d1c76c"
|
||||
},
|
||||
"go-member-calls/models/user.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "d9ac10cc3e7a441758616566bcc9138d0e5860922369f674044e888864ce6780"
|
||||
},
|
||||
"go-method-chain-binding/cmd/main.go": {
|
||||
"captureGroups": 21,
|
||||
"digest": "44ea12bacafc97d43e5ce77fa1b1eaf7d26340a20c9849e30e640c8db4932b58"
|
||||
},
|
||||
"go-method-chain-binding/models/user.go": {
|
||||
"captureGroups": 24,
|
||||
"digest": "038f9a0025fa364341b2e1fb334c7ac7c50292f1afc77cc460bb3d7825603f4d"
|
||||
},
|
||||
"go-method-enrichment/animal.go": {
|
||||
"captureGroups": 15,
|
||||
"digest": "63833a10aa3e940b71b79ae24da39162d6d223255dbf2e58fa595551e9faadc1"
|
||||
},
|
||||
"go-method-enrichment/app.go": {
|
||||
"captureGroups": 15,
|
||||
"digest": "acdbd60589872f9c3fb4a8c189c857629c6246c8b7b9f3fbfab5e31b3d80f8fd"
|
||||
},
|
||||
"go-mixed-chain/cmd/main.go": {
|
||||
"captureGroups": 20,
|
||||
"digest": "ac3d1639382e5247c7613135cd0e3a6788d84c3b5de1a8d4f089f6b7986b0649"
|
||||
},
|
||||
"go-mixed-chain/models/models.go": {
|
||||
"captureGroups": 41,
|
||||
"digest": "8428e0a9fcacd0f0ea7448f542e897768701a98a3e92660cecde5d745e4c24fa"
|
||||
},
|
||||
"go-multi-assign/app.go": {
|
||||
"captureGroups": 16,
|
||||
"digest": "3a4243a05de378fb2853a74c8e3c3dadf8777178457b3463af58a92bab135f2d"
|
||||
},
|
||||
"go-multi-assign/models.go": {
|
||||
"captureGroups": 19,
|
||||
"digest": "b4ed9ce71a440771980d27a7034802f707ae191baac9f4d1d98980c3a223b554"
|
||||
},
|
||||
"go-multi-return-inference/cmd/main.go": {
|
||||
"captureGroups": 36,
|
||||
"digest": "601ca464d0f6d9588e616eb414cfee71913f7797e28d4d545ae5e4b18dc5117e"
|
||||
},
|
||||
"go-multi-return-inference/models/repo.go": {
|
||||
"captureGroups": 10,
|
||||
"digest": "aedabd86f2a5f79242559be20fcc92235d7803aab603964014900f4aa918d510"
|
||||
},
|
||||
"go-multi-return-inference/models/user.go": {
|
||||
"captureGroups": 10,
|
||||
"digest": "0e997eb91cb5636e6615ff54dd93e5e1337dadab05b8d7bd8223f1c34df9ab1e"
|
||||
},
|
||||
"go-new-builtin/main.go": {
|
||||
"captureGroups": 12,
|
||||
"digest": "684af689b07fc9f270e872018fb2170070b84fff873791a215156d7e675b095f"
|
||||
},
|
||||
"go-new-builtin/models.go": {
|
||||
"captureGroups": 17,
|
||||
"digest": "fbc349c4d2ba2d3a224c96e0ea3dbdb4eaa65850e5889205c42438ded1218f5a"
|
||||
},
|
||||
"go-nullable-receiver/cmd/main.go": {
|
||||
"captureGroups": 27,
|
||||
"digest": "a5f635e8241cf718c54b36464756d1978cba7b00619840c6243fa46ed7525bcd"
|
||||
},
|
||||
"go-nullable-receiver/models/repo.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "43736fad4b59031e430a18d5f7d20ea5a3fd0306c870d323faef0e27681691e4"
|
||||
},
|
||||
"go-nullable-receiver/models/user.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "d9ac10cc3e7a441758616566bcc9138d0e5860922369f674044e888864ce6780"
|
||||
},
|
||||
"go-parent-resolution/models/base.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "44b96fd5ae712621d9d66eea953462ade0a8e3271e962a7ae7534d596b82ba81"
|
||||
},
|
||||
"go-parent-resolution/models/user.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "42fb5dfc9887acec38aca169a42618ae5e5a8cb5a98d2b4a3b84c4f6746bc24b"
|
||||
},
|
||||
"go-pkg/cmd/main.go": {
|
||||
"captureGroups": 14,
|
||||
"digest": "73bbd5566b0edb9ba0068ea59c6e0198f7f6b5bca7dfd07214aaae8636eaee02"
|
||||
},
|
||||
"go-pkg/internal/auth/service.go": {
|
||||
"captureGroups": 17,
|
||||
"digest": "2577136c6df4602c9de06d0c3495ea603b4d2de867bf1724b8367569ac53d832"
|
||||
},
|
||||
"go-pkg/internal/models/admin.go": {
|
||||
"captureGroups": 13,
|
||||
"digest": "e9b23d1d0ac8556a288211ecff43571d7b1f6566266e8ed6dc1900511893cb84"
|
||||
},
|
||||
"go-pkg/internal/models/repository.go": {
|
||||
"captureGroups": 3,
|
||||
"digest": "23a95d0be76cc6bfdaa1c0cdfb8421917bca77a91376c40bf2c4e9b5e0966313"
|
||||
},
|
||||
"go-pkg/internal/models/user.go": {
|
||||
"captureGroups": 13,
|
||||
"digest": "c06c5b45d9c29281f30ad83720469181bcc8266453ee8ea8094059970a0815ab"
|
||||
},
|
||||
"go-pointer-constructor-inference/cmd/main.go": {
|
||||
"captureGroups": 15,
|
||||
"digest": "1291eec1a2ccc521c9c8aad46bd3abfd5921920bcc7e1f6745b1e2ec3bb67fce"
|
||||
},
|
||||
"go-pointer-constructor-inference/models/repo.go": {
|
||||
"captureGroups": 10,
|
||||
"digest": "aedabd86f2a5f79242559be20fcc92235d7803aab603964014900f4aa918d510"
|
||||
},
|
||||
"go-pointer-constructor-inference/models/user.go": {
|
||||
"captureGroups": 10,
|
||||
"digest": "0e997eb91cb5636e6615ff54dd93e5e1337dadab05b8d7bd8223f1c34df9ab1e"
|
||||
},
|
||||
"go-receiver-method-free-call/example.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "f21184b79f193586674f7163bd70c492e8d1ca7bce88ba97587fa6be48658bcc"
|
||||
},
|
||||
"go-receiver-method-free-call/util.go": {
|
||||
"captureGroups": 4,
|
||||
"digest": "84d54b4a4d56fc3c0748d15f115586afe82b4b6766f1e69130f3527f54cdf22a"
|
||||
},
|
||||
"go-receiver-resolution/cmd/main.go": {
|
||||
"captureGroups": 13,
|
||||
"digest": "3532de5d39d65476ac0399c87f8a07645c3b5f84ed4641f75b5e0bc10926b00f"
|
||||
},
|
||||
"go-receiver-resolution/models/repo.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "43736fad4b59031e430a18d5f7d20ea5a3fd0306c870d323faef0e27681691e4"
|
||||
},
|
||||
"go-receiver-resolution/models/user.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "d9ac10cc3e7a441758616566bcc9138d0e5860922369f674044e888864ce6780"
|
||||
},
|
||||
"go-return-type-inference/cmd/main.go": {
|
||||
"captureGroups": 39,
|
||||
"digest": "b84ca4b69d9515078c1b2b365140dd91676ad4b7786fe9f352d38a278ad4ca72"
|
||||
},
|
||||
"go-return-type-inference/models/repo.go": {
|
||||
"captureGroups": 16,
|
||||
"digest": "db56aaa73b8b9a3d2cba805c494816198417f81004961125d21a83ecb6a754b1"
|
||||
},
|
||||
"go-return-type-inference/models/user.go": {
|
||||
"captureGroups": 16,
|
||||
"digest": "3dde52af7ec836a0574c3b97fed38a3c84de5593ecc47efc61041a9e7c5e0cad"
|
||||
},
|
||||
"go-same-package-factory/main.go": {
|
||||
"captureGroups": 14,
|
||||
"digest": "977fa6ea452d0b558307276d510c775f331a9fc21bbbaac93c486e58fede1ad0"
|
||||
},
|
||||
"go-same-package-factory/repo.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "46680b352bb89775342d9c535d1f3808d2a878cfeb26f58b8a094db1a0abec3b"
|
||||
},
|
||||
"go-same-package-factory/user.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "108a5fc6d3fd36704d0ce02787466d48032f2febf2bf84f75ca0d54d3a52974f"
|
||||
},
|
||||
"go-split-method-owner/main.go": {
|
||||
"captureGroups": 9,
|
||||
"digest": "972b12a6ab1b5646c86dd164cd36fcc616ca5d082de373f95c572be3f2705144"
|
||||
},
|
||||
"go-split-method-owner/repo.go": {
|
||||
"captureGroups": 8,
|
||||
"digest": "46680b352bb89775342d9c535d1f3808d2a878cfeb26f58b8a094db1a0abec3b"
|
||||
},
|
||||
"go-split-method-owner/save.go": {
|
||||
"captureGroups": 6,
|
||||
"digest": "00efd15483f889a19ffa8de4950bfe95e14b404b073667d222eb8db8d234cb69"
|
||||
},
|
||||
"go-split-method-owner/user.go": {
|
||||
"captureGroups": 3,
|
||||
"digest": "3e5f53d45e44a627864ff3d60310d2c134ff9fa3c424497551437a4c53a514d5"
|
||||
},
|
||||
"go-struct-literals/app.go": {
|
||||
"captureGroups": 10,
|
||||
"digest": "79019ba9ec2b101656a6d730fa7e0b47847c32d798ec3a28191e5fc151a513ec"
|
||||
},
|
||||
"go-struct-literals/user.go": {
|
||||
"captureGroups": 10,
|
||||
"digest": "a5b426dc7c44adbe266027bdb86458b3a2e3aa09aa5697cf3c0692ab9f431955"
|
||||
},
|
||||
"go-type-assertion/main.go": {
|
||||
"captureGroups": 11,
|
||||
"digest": "df8edeab1ead0201660381986f9ee85575cbb5461eb0ba4dc9ae33d761a1b607"
|
||||
},
|
||||
"go-type-assertion/models.go": {
|
||||
"captureGroups": 17,
|
||||
"digest": "71c02619d03bc81d2ecc8ee398c0639cab2543940ec007a8457015925ba77faa"
|
||||
},
|
||||
"go-variadic-resolution/cmd/main.go": {
|
||||
"captureGroups": 6,
|
||||
"digest": "df08cd1a32778a43233e296021a7a5e040e9e41ec593479a0b6dd2c28e955d2c"
|
||||
},
|
||||
"go-variadic-resolution/internal/logger/logger.go": {
|
||||
"captureGroups": 4,
|
||||
"digest": "2e221a3c0b1abc280c91a735b8af8204d481de9b98ef9cabf2ecf32810fc7490"
|
||||
},
|
||||
"go-write-access/main.go": {
|
||||
"captureGroups": 20,
|
||||
"digest": "71198584484ae954b34957a3ef2c152386cc7b9fc7b12d0b2c5af2b02f883feb"
|
||||
},
|
||||
"synthetic:dao-20": {
|
||||
"captureGroups": 481,
|
||||
"digest": "c02d9baf1c673a9bb2199566453e55d067433507fd494f9e9b6a7a906b6919a9"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* Golden capture-parity test for `emitGoScopeCaptures` (issue #1848 follow-up).
|
||||
*
|
||||
* Pins the exact capture output of `emitGoScopeCaptures` across the whole
|
||||
* `test/fixtures/lang-resolution/go-*` corpus plus a synthetic generated-DAO
|
||||
* source, so any future drift in the Go scope-capture path fails CI rather than
|
||||
* only being caught by a coarse perf tripwire or pipeline-level resolver tests.
|
||||
*
|
||||
* This is a FORWARD-DRIFT guard: it locks in the current (post-#1915, verified)
|
||||
* output as the baseline. It does not independently re-prove the original
|
||||
* pre-fix parity — that was established during PR #1915.
|
||||
*
|
||||
* Regenerate the golden intentionally with `UPDATE_GOLDEN=1` in the environment.
|
||||
*
|
||||
* Per fixture the snapshot stores `{ captureGroups, digest }`:
|
||||
* - captureGroups: number of capture matches (makes a count change legible)
|
||||
* - digest: sha256 of a match-grouped, order-independent canonicalization
|
||||
* (see canonicalize* below). Nothing path/time/id-dependent leaks in.
|
||||
*
|
||||
* Pattern: mirrors test/integration/pipeline-graph-golden.test.ts.
|
||||
*/
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import crypto from 'crypto';
|
||||
import { emitGoScopeCaptures } from '../../../../src/core/ingestion/languages/go/index.js';
|
||||
import type { CaptureMatch } from 'gitnexus-shared';
|
||||
|
||||
// This test lives at test/unit/scope-resolution/go/, so fixtures are THREE
|
||||
// levels up (unlike pipeline-graph-golden.test.ts at test/integration/).
|
||||
const FIXTURE_ROOT = path.resolve(__dirname, '..', '..', '..', 'fixtures', 'lang-resolution');
|
||||
const GOLDEN_DIR = path.resolve(__dirname, '..', '..', '..', 'fixtures', 'go-captures-golden');
|
||||
const GOLDEN_FILE = path.join(GOLDEN_DIR, 'expected-captures.json');
|
||||
|
||||
const UPDATE = process.env.UPDATE_GOLDEN === '1';
|
||||
|
||||
interface FixtureSnapshot {
|
||||
captureGroups: number;
|
||||
digest: string;
|
||||
}
|
||||
type Snapshot = Record<string, FixtureSnapshot>;
|
||||
|
||||
/**
|
||||
* Canonicalize ONE match. A CaptureMatch is a Record<tag, Capture> (multiple
|
||||
* captures per match), so we group by match to preserve match identity:
|
||||
* build one `tag|text|startLine:startCol-endLine:endCol` string per capture,
|
||||
* sort them within the match, and join. We deliberately do NOT flatten every
|
||||
* capture into one global list — that would lose match boundaries.
|
||||
*/
|
||||
function canonicalizeMatch(match: CaptureMatch): string {
|
||||
const parts: string[] = [];
|
||||
for (const tag of Object.keys(match)) {
|
||||
const cap = match[tag]!;
|
||||
const r = cap.range;
|
||||
parts.push(`${tag}|${cap.text}|${r.startLine}:${r.startCol}-${r.endLine}:${r.endCol}`);
|
||||
}
|
||||
parts.sort();
|
||||
return parts.join(';');
|
||||
}
|
||||
|
||||
/** Order-independent digest of a full capture result (match-grouped). */
|
||||
function digestCaptures(matches: readonly CaptureMatch[]): string {
|
||||
const matchStrings = matches.map(canonicalizeMatch).sort();
|
||||
return crypto.createHash('sha256').update(matchStrings.join('\n')).digest('hex');
|
||||
}
|
||||
|
||||
function snapshotOf(src: string, filePath: string): FixtureSnapshot {
|
||||
const matches = emitGoScopeCaptures(src, filePath);
|
||||
return { captureGroups: matches.length, digest: digestCaptures(matches) };
|
||||
}
|
||||
|
||||
/** All `.go` files under `lang-resolution/go-*`, as sorted repo-relative-ish keys. */
|
||||
function collectGoFixtures(): { key: string; absPath: string }[] {
|
||||
const out: { key: string; absPath: string }[] = [];
|
||||
for (const entry of fs.readdirSync(FIXTURE_ROOT, { withFileTypes: true })) {
|
||||
if (!entry.isDirectory() || !entry.name.startsWith('go-')) continue;
|
||||
const stack = [path.join(FIXTURE_ROOT, entry.name)];
|
||||
while (stack.length) {
|
||||
const dir = stack.pop()!;
|
||||
for (const c of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const p = path.join(dir, c.name);
|
||||
if (c.isDirectory()) stack.push(p);
|
||||
else if (c.name.endsWith('.go')) {
|
||||
out.push({ key: path.relative(FIXTURE_ROOT, p).split(path.sep).join('/'), absPath: p });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out.sort((a, b) => a.key.localeCompare(b.key));
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Small deterministic generated-DAO source — the #1848 shape at correctness scale. */
|
||||
function generateDao(entityCount: number): string {
|
||||
const lines = ['package generated', ''];
|
||||
for (let i = 0; i < entityCount; i++) {
|
||||
const n = String(i).padStart(4, '0');
|
||||
lines.push(
|
||||
`type DefUserDao${n} struct {`,
|
||||
'\tid int64',
|
||||
'\tname string',
|
||||
'}',
|
||||
'',
|
||||
`func (d *DefUserDao${n}) GetID() int64 { return d.id }`,
|
||||
`func (d *DefUserDao${n}) SetName(name string) { d.name = name }`,
|
||||
`func (d *DefUserDao${n}) Validate() error { return nil }`,
|
||||
'',
|
||||
);
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
function buildSnapshot(): Snapshot {
|
||||
const snap: Snapshot = {};
|
||||
for (const { key, absPath } of collectGoFixtures()) {
|
||||
snap[key] = snapshotOf(fs.readFileSync(absPath, 'utf8'), absPath);
|
||||
}
|
||||
snap['synthetic:dao-20'] = snapshotOf(generateDao(20), 'zz_generated.def_userdao.go');
|
||||
// Stable key order for deterministic JSON serialization.
|
||||
return Object.fromEntries(Object.keys(snap).sort().map((k) => [k, snap[k]!]));
|
||||
}
|
||||
|
||||
function formatGolden(snap: Snapshot): string {
|
||||
return JSON.stringify(snap, null, 2) + '\n';
|
||||
}
|
||||
|
||||
describe('Go scope captures — golden parity', () => {
|
||||
it('matches the committed golden snapshot across all go-* fixtures + DAO shape', () => {
|
||||
const snapshot = buildSnapshot();
|
||||
|
||||
if (UPDATE || !fs.existsSync(GOLDEN_FILE)) {
|
||||
fs.mkdirSync(GOLDEN_DIR, { recursive: true });
|
||||
fs.writeFileSync(GOLDEN_FILE, formatGolden(snapshot), 'utf8');
|
||||
console.log(
|
||||
`[go-captures-golden] ${UPDATE ? 'Regenerated' : 'Created'} golden at ${GOLDEN_FILE}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const expected: Snapshot = JSON.parse(fs.readFileSync(GOLDEN_FILE, 'utf8'));
|
||||
expect(
|
||||
snapshot,
|
||||
'emitGoScopeCaptures output drifted from the committed golden. If this drift is intentional, ' +
|
||||
'regenerate with UPDATE_GOLDEN=1 npx vitest run test/unit/scope-resolution/go/go-captures-golden.test.ts',
|
||||
).toEqual(expected);
|
||||
});
|
||||
|
||||
it('produces a deterministic digest across repeated runs', () => {
|
||||
const src = generateDao(8);
|
||||
expect(digestCaptures(emitGoScopeCaptures(src, 'a.go'))).toBe(
|
||||
digestCaptures(emitGoScopeCaptures(src, 'a.go')),
|
||||
);
|
||||
});
|
||||
|
||||
it('digest is independent of capture-match array order', () => {
|
||||
const matches = emitGoScopeCaptures(generateDao(6), 'a.go');
|
||||
const reversed = [...matches].reverse();
|
||||
expect(digestCaptures(reversed)).toBe(digestCaptures(matches));
|
||||
});
|
||||
|
||||
it('records a capture-group count for every fixture and the DAO shape', () => {
|
||||
const snapshot = buildSnapshot();
|
||||
const fixtureKeys = collectGoFixtures().map((f) => f.key);
|
||||
// Every collected fixture is present in the snapshot.
|
||||
for (const k of fixtureKeys) expect(snapshot[k]).toBeDefined();
|
||||
// The DAO shape (which has symbols) yields a non-empty capture set.
|
||||
expect(snapshot['synthetic:dao-20']!.captureGroups).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user