项目文件夹

文件
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

268 行
8.4 KiB
Go

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
package clones
import (
"reflect"
"sort"
"testing"
)
// shinglesFrom builds a deterministic shingle-hash set from a slice of
// integer shingle ids. Using small distinct integers as the raw shingle
// hashes lets a test author dial in an exact Jaccard overlap between two
// items: |A ∩ B| / |A B| over the integer sets is what MinHash
// estimates, so near-duplicates and distinct items are constructed by
// choosing how many shingle ids two sets share.
func shinglesFrom(ids ...uint64) []uint64 {
out := make([]uint64, len(ids))
copy(out, ids)
sort.Slice(out, func(i, j int) bool { return out[i] < out[j] })
return out
}
// sigFromShingles is a test helper: SignatureFromShingles with no
// minimum-shingle floor, failing the test if the set is degenerate.
func sigFromShingles(t *testing.T, shingles []uint64) Signature {
t.Helper()
sig, ok := SignatureFromShingles(shingles, 0)
if !ok {
t.Fatalf("SignatureFromShingles failed for %v", shingles)
}
return sig
}
// makeShingleRange returns the shingle ids base, base+1, …, base+n-1 —
// a contiguous block, so two blocks overlap by a controllable amount.
func makeShingleRange(base, n uint64) []uint64 {
out := make([]uint64, 0, n)
for i := uint64(0); i < n; i++ {
out = append(out, base+i)
}
return out
}
// fixtureItems builds the deterministic correctness fixture:
// - a / b: a high-overlap near-duplicate pair in the small length class
// - c: distinct from a/b, same small length class (a non-clone neighbour)
// - d / e: a second high-overlap near-duplicate pair, sized so they sit
// in a different (larger) length class than a/b — exercising >1 class
// - f: distinct, in the large class (a non-clone neighbour for d/e)
//
// Overlaps are tuned so EstimateJaccard clears DefaultThreshold for the
// (a,b) and (d,e) pairs and stays well below it for everything else.
func fixtureItems(t *testing.T) []Item {
t.Helper()
// Small length class (TokenCount 60 → class 0 only, [0,80)).
// a and b share 116 of 120 shingles → exact Jaccard ≈ 0.967.
aSh := makeShingleRange(1000, 120)
bSh := makeShingleRange(1004, 120) // shifted by 4 → 116 shared
// c shares almost nothing with a/b.
cSh := makeShingleRange(9000, 120)
// Large length class (TokenCount 250 → class 3 only, [200,640)).
// d and e share 116 of 120 shingles → exact Jaccard ≈ 0.967.
dSh := makeShingleRange(2000, 120)
eSh := makeShingleRange(2004, 120)
// f shares almost nothing with d/e.
fSh := makeShingleRange(7000, 120)
return []Item{
{ID: "a", Sig: sigFromShingles(t, shinglesFrom(aSh...)), TokenCount: 60},
{ID: "b", Sig: sigFromShingles(t, shinglesFrom(bSh...)), TokenCount: 60},
{ID: "c", Sig: sigFromShingles(t, shinglesFrom(cSh...)), TokenCount: 60},
{ID: "d", Sig: sigFromShingles(t, shinglesFrom(dSh...)), TokenCount: 250},
{ID: "e", Sig: sigFromShingles(t, shinglesFrom(eSh...)), TokenCount: 250},
{ID: "f", Sig: sigFromShingles(t, shinglesFrom(fSh...)), TokenCount: 250},
}
}
// canonicalPairSet reduces a slice of Pairs to the set of canonical
// (A<B) id pairs, ignoring similarity — the unit of comparison between
// the batch and the maintained detection paths.
func canonicalPairSet(pairs []Pair) map[[2]string]struct{} {
set := make(map[[2]string]struct{}, len(pairs))
for _, p := range pairs {
a, b := p.A, p.B
if a > b {
a, b = b, a
}
set[[2]string{a, b}] = struct{}{}
}
return set
}
// populatedLengthClasses counts how many length classes hold ≥1 item
// from the fixture — used to assert the equivalence test is non-vacuous
// (more than one class actually exercised).
func populatedLengthClasses(items []Item) int {
hit := make(map[int]struct{})
for _, it := range items {
for _, c := range lengthClassesOf(it.TokenCount) {
hit[c] = struct{}{}
}
}
return len(hit)
}
// TestStratifiedIndexEquivalence proves the incrementally maintained
// per-item query reproduces the batch detection exactly: the union of
// QueryPairs over every item equals the canonical pair set the batch
// DetectPairsStratifiedWithStats produces over the same corpus.
func TestStratifiedIndexEquivalence(t *testing.T) {
items := fixtureItems(t)
const threshold = DefaultThreshold
batchPairs, _, _ := DetectPairsStratifiedWithStats(items, threshold)
batchSet := canonicalPairSet(batchPairs)
// Non-vacuous fixture: the batch must find at least one pair and the
// items must span more than one length class, else the equivalence
// is trivially satisfied by an empty set in a single bucket.
if len(batchSet) < 1 {
t.Fatalf("fixture vacuous: batch found no pairs")
}
if n := populatedLengthClasses(items); n <= 1 {
t.Fatalf("fixture vacuous: only %d length class populated, want >1", n)
}
s := NewStratifiedIndex()
for _, it := range items {
s.Add(it)
}
maintained := make(map[[2]string]struct{})
for _, it := range items {
for _, p := range s.QueryPairs(it, threshold) {
a, b := p.A, p.B
if a > b {
a, b = b, a
}
maintained[[2]string{a, b}] = struct{}{}
}
}
if !reflect.DeepEqual(batchSet, maintained) {
t.Fatalf("maintained query set != batch set\n batch=%v\n maintained=%v", batchSet, maintained)
}
}
// TestStratifiedIndexRemoveAndReadd proves Remove pulls a
// clone-participating id out of every candidate set, and that re-Adding
// it restores the original equivalence set.
func TestStratifiedIndexRemoveAndReadd(t *testing.T) {
items := fixtureItems(t)
const threshold = DefaultThreshold
batchPairs, _, _ := DetectPairsStratifiedWithStats(items, threshold)
batchSet := canonicalPairSet(batchPairs)
if len(batchSet) < 1 {
t.Fatalf("fixture vacuous: batch found no pairs")
}
s := NewStratifiedIndex()
for _, it := range items {
s.Add(it)
}
// "a" participates in the (a,b) clone pair.
const removed = "a"
var removedItem Item
for _, it := range items {
if it.ID == removed {
removedItem = it
}
}
s.Remove(removed)
// After removal no QueryPairs over the remaining items may yield a
// pair touching the removed id.
for _, it := range items {
if it.ID == removed {
continue
}
for _, p := range s.QueryPairs(it, threshold) {
if p.A == removed || p.B == removed {
t.Fatalf("pair %+v still references removed id %q", p, removed)
}
}
}
// The removed item must also produce no surviving pairs of its own,
// since its former partner can no longer be a live candidate for it.
if pairs := s.QueryPairs(removedItem, threshold); len(pairs) != 0 {
t.Fatalf("removed item still produced pairs: %+v", pairs)
}
// Re-Add restores the full equivalence set.
s.Add(removedItem)
restored := make(map[[2]string]struct{})
for _, it := range items {
for _, p := range s.QueryPairs(it, threshold) {
a, b := p.A, p.B
if a > b {
a, b = b, a
}
restored[[2]string{a, b}] = struct{}{}
}
}
if !reflect.DeepEqual(batchSet, restored) {
t.Fatalf("re-add did not restore equivalence set\n batch=%v\n restored=%v", batchSet, restored)
}
}
// TestCMSDecrementRoundTrip proves Decrement floors at 0 and that Count
// reflects the live multiset remainder after a subset is decremented:
// it stays an upper bound on the surviving true count and returns to the
// 0 floor for keys decremented down to nothing.
func TestCMSDecrementRoundTrip(t *testing.T) {
cms := NewCMS(4096, 4)
// A multiset of keys with known multiplicities.
multiset := map[uint64]int{
11: 3,
22: 5,
33: 1,
44: 2,
}
for key, n := range multiset {
for i := 0; i < n; i++ {
cms.Add(key)
}
}
// Decrement a subset: drop 33 entirely (1→0), drop two of 22 (5→3).
decrements := map[uint64]int{
33: 1,
22: 2,
}
remaining := make(map[uint64]int, len(multiset))
for key, n := range multiset {
remaining[key] = n - decrements[key]
}
for key, n := range decrements {
for i := 0; i < n; i++ {
cms.Decrement(key)
}
}
// Count is an upper bound on the live true count, and exactly the
// floor (0) for the fully-removed key.
for key, want := range remaining {
got := cms.Count(key)
if got < uint32(want) {
t.Fatalf("Count(%d)=%d below true remaining count %d (CMS must stay an upper bound)", key, got, want)
}
if want == 0 && got != 0 {
t.Fatalf("Count(%d)=%d, want 0 after full removal", key, got)
}
}
// Decrementing a never-added key is a no-op and never drives any
// counter negative — Count stays at the 0 floor.
const neverAdded = uint64(999)
cms.Decrement(neverAdded)
if got := cms.Count(neverAdded); got != 0 {
t.Fatalf("Count(neverAdded)=%d after no-op Decrement, want 0", got)
}
}