サンプル
github.com/google/go-cmp v0.6.0: cmp.Ignore
検証済みサンプル — golang github.com/google/go-cmp v0.6.0: cmp.Ignore. go 1.26 · linux debian/x64 · docker で contract を実行し、成功しました: cmp.Ignore is an Option that…
sha256:7b4a19968a08fc2b30a7abd2403e07df1690fec1d48e958b54781638bc0d2a16
このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。
合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。
MIT-0
実行証拠
宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。
- 証拠の基準
- 署名済みコントラクト合格
- 検証レシート
- 1
- ビルドした署名鍵
- 1
宣言された環境
linux 24 · ubuntu · glibc 2.39 x64 go
検証実行環境
| 環境 | コントラクト | ステージ | 実行日 |
|---|---|---|---|
| go 1.26 · linux debian/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · golang@1golang:1.26@sha256:e30143be198a… |
2026-09-15 |
ケース
HOW- ゴール
- verify github.com/google/go-cmp/cmp.Ignore in pkg:golang/github.com/google/go-cmp@v0.6.0
- シンボル
-
- github.com/google/go-cmp/cmp.Ignore
- 作成日
- 2026-09-15T21:27:51Z
コントラクト
- cmp.Ignore is an Option that causes all comparisons matching a filter to be ignored
- Passing an unfiltered cmp.Ignore directly to cmp.Equal panics with cannot use an unfiltered option: Ignore()
- cmp.FilterPath with cmp.Ignore ignores struct fields by name leaving non-ignored fields evaluated
- cmp.FilterPath with cmp.Ignore bypasses reflection panics on unexported struct fields without AllowUnexported
- cmp.FilterPath with cmp.Ignore ignores any node in the comparison path matching a specified reflect.Type
- cmp.FilterValues with cmp.Ignore conditionally ignores comparisons when a symmetric value predicate returns true
- cmp.FilterPath with cmp.Ignore ignores specific map keys or slice indices during container comparison
ファイル
- NOTES.md
- PROMPT.md
- csx.json
- go.mod
- go.sum
- ignore.go
- ignore_test.go
- spec.json
ソース
# google/go-cmp: Selective Comparison Filtering with cmp.Ignore
## Known Solutions Search
A search for `github.com/google/go-cmp/cmp.Ignore` in `pkg:golang/github.com/google/go-cmp@v0.6.0` returned `NO_SAFE_MATCH`.
This sample investigates and verifies the contract of `cmp.Ignore`, demonstrating:
1. Combining `cmp.Ignore()` with `cmp.FilterPath` to selectively ignore struct fields by name.
2. Bypassing unexported struct field reflection panics by applying `cmp.Ignore()` to unexported fields without requiring `cmp.AllowUnexported`.
3. Ignoring specific types across data structures using `reflect.Type` matching.
4. Ignoring matching value pairs using `cmp.FilterValues` and symmetric predicates.
5. Selectively ignoring slice indices and map keys during container comparison.
6. Verifying that passing an unfiltered `cmp.Ignore()` directly to `cmp.Equal` panics with `cannot use an unfiltered option: Ignore()`.
## Pinned Release
`github.com/google/go-cmp v0.6.0` declared in `go.mod` and verified in `go.sum`.
## Failure Modes
1. Direct use of unfiltered `cmp.Ignore()` panics at runtime with `cannot use an unfiltered option: Ignore()`.
2. Direct comparison of structs containing unexported private fields panics at runtime with `cannot handle unexported field` unless the unexported fields are ignored via `cmp.Ignore()` or permitted via `cmp.AllowUnexported`.
3. Partial unexported field filtering panics if any remaining unexported field is traversed without an ignore option or exporter.
## Observed Behaviour
1. `cmp.Ignore()` returns an `Option` that marks comparisons as ignored when combined with `cmp.FilterPath` or `cmp.FilterValues`.
2. Ignored fields produce no diff output in `cmp.Diff` and evaluate to equal in `cmp.Equal`.
Clean-room public code sample — generation instructions
Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.
A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.
Goal: verify github.com/google/go-cmp/cmp.Ignore in pkg:golang/github.com/google/go-cmp@v0.6.0
Kind: HOW
Use EXACTLY these public packages and versions:
- pkg:golang/github.com/google/go-cmp@v0.6.0
Demonstrate these symbols/APIs:
- github.com/google/go-cmp/cmp.Ignore
Rules:
- One focused purpose; the smallest project that proves the goal.
- Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
- Pin every dependency with a lockfile so resolution is reproducible.
- No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
- No personal names, emails, company names, or project identifiers of any kind.
- No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
- Keep it under 200 files and 256KB packed.
{"case":{"caseId":"case:sha256:69173f2a667e238a7eeaf15ac013b6fb1e139569375baeb3dfad9e781c02b536","contract":["cmp.Ignore is an Option that causes all comparisons matching a filter to be ignored","Passing an unfiltered cmp.Ignore directly to cmp.Equal panics with cannot use an unfiltered option: Ignore()","cmp.FilterPath with cmp.Ignore ignores struct fields by name leaving non-ignored fields evaluated","cmp.FilterPath with cmp.Ignore bypasses reflection panics on unexported struct fields without AllowUnexported","cmp.FilterPath with cmp.Ignore ignores any node in the comparison path matching a specified reflect.Type","cmp.FilterValues with cmp.Ignore conditionally ignores comparisons when a symmetric value predicate returns true","cmp.FilterPath with cmp.Ignore ignores specific map keys or slice indices during container comparison"],"goal":"verify github.com/google/go-cmp/cmp.Ignore in pkg:golang/github.com/google/go-cmp@v0.6.0","kind":"HOW","packages":["pkg:golang/github.com/google/go-cmp@v0.6.0"],"schemaVersion":1,"symbols":["github.com/google/go-cmp/cmp.Ignore"]},"contractCommand":["go","test","./..."],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"golang","libc":"glibc","libcVersion":"2.39","os":"linux","osVersionBucket":"24","packageManager":"go","schemaVersion":1},"license":"MIT-0","packages":["pkg:golang/github.com/google/go-cmp@v0.6.0"],"schemaVersion":1,"subject":"pkg:golang/github.com/google/go-cmp@v0.6.0","symbols":["github.com/google/go-cmp/cmp.Ignore"],"verifierAdapter":"golang@1"}
module example.com/ignorecmp
go 1.24
require github.com/google/go-cmp v0.6.0
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
package ignorecmp
import (
"reflect"
"unicode"
"github.com/google/go-cmp/cmp"
)
// IgnoreFieldByName returns an Option that ignores struct fields matching the specified field name.
func IgnoreFieldByName(name string) cmp.Option {
return cmp.FilterPath(func(p cmp.Path) bool {
sf, ok := p.Last().(cmp.StructField)
return ok && sf.Name() == name
}, cmp.Ignore())
}
// IgnoreUnexportedFields returns an Option that ignores all unexported struct fields,
// preventing reflection panics when comparing structs that contain private fields.
func IgnoreUnexportedFields() cmp.Option {
return cmp.FilterPath(func(p cmp.Path) bool {
sf, ok := p.Last().(cmp.StructField)
if !ok {
return false
}
name := sf.Name()
return len(name) > 0 && !unicode.IsUpper(rune(name[0]))
}, cmp.Ignore())
}
// IgnoreType returns an Option that ignores any node in the comparison path matching targetType.
func IgnoreType(targetType reflect.Type) cmp.Option {
return cmp.FilterPath(func(p cmp.Path) bool {
return p.Last().Type() == targetType
}, cmp.Ignore())
}
// IgnoreMapKey returns an Option that ignores map entries with the specified key value.
func IgnoreMapKey[K comparable](ignoredKey K) cmp.Option {
return cmp.FilterPath(func(p cmp.Path) bool {
mi, ok := p.Last().(cmp.MapIndex)
if !ok {
return false
}
keyVal := mi.Key()
if !keyVal.IsValid() || !keyVal.CanInterface() {
return false
}
if k, ok := keyVal.Interface().(K); ok {
return k == ignoredKey
}
return false
}, cmp.Ignore())
}
// IgnoreSliceIndex returns an Option that ignores slice elements at the specified zero-based index.
func IgnoreSliceIndex(ignoredIndex int) cmp.Option {
return cmp.FilterPath(func(p cmp.Path) bool {
si, ok := p.Last().(cmp.SliceIndex)
return ok && (si.Key() == ignoredIndex)
}, cmp.Ignore())
}
// IgnoreMatchingValues returns an Option using FilterValues that ignores comparison
// when the symmetric predicate func(T, T) bool returns true.
func IgnoreMatchingValues[T any](predicate func(x, y T) bool) cmp.Option {
return cmp.FilterValues(predicate, cmp.Ignore())
}
package ignorecmp
import (
"fmt"
"reflect"
"strings"
"testing"
"time"
"github.com/google/go-cmp/cmp"
)
type Account struct {
ID int
Username string
UpdatedAt time.Time
}
type TokenSession struct {
SessionID string
token string // single unexported field
}
type MultiSecretSession struct {
SessionID string
token string // unexported field
secretKey []byte // unexported field
}
func TestUnfilteredIgnorePanics(t *testing.T) {
defer func() {
r := recover()
if r == nil {
t.Fatal("expected unfiltered cmp.Ignore() to panic when passed to cmp.Equal")
}
errMsg := fmt.Sprint(r)
if !strings.Contains(errMsg, "cannot use an unfiltered option: Ignore()") {
t.Fatalf("unexpected panic message: %s", errMsg)
}
}()
_ = cmp.Equal(10, 20, cmp.Ignore())
}
func TestIgnoreFieldByName(t *testing.T) {
acc1 := Account{
ID: 1001,
Username: "alice",
UpdatedAt: time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC),
}
acc2 := Account{
ID: 1001,
Username: "alice",
UpdatedAt: time.Date(2026, 9, 15, 12, 0, 0, 0, time.UTC), // different timestamp
}
optIgnoreTimestamp := IgnoreFieldByName("UpdatedAt")
if !cmp.Equal(acc1, acc2, optIgnoreTimestamp) {
t.Fatalf("expected accounts to be equal when UpdatedAt is ignored, diff: %s", cmp.Diff(acc1, acc2, optIgnoreTimestamp))
}
diff := cmp.Diff(acc1, acc2, optIgnoreTimestamp)
if diff != "" {
t.Fatalf("expected empty diff when ignored field differs, got: %s", diff)
}
// Changing a non-ignored field causes inequality
acc2.Username = "bob"
if cmp.Equal(acc1, acc2, optIgnoreTimestamp) {
t.Fatal("expected accounts to differ when non-ignored field differs")
}
diffWithBob := cmp.Diff(acc1, acc2, optIgnoreTimestamp)
if !strings.Contains(diffWithBob, "Username") {
t.Fatalf("expected diff to show Username mismatch, got: %s", diffWithBob)
}
if strings.Contains(diffWithBob, "UpdatedAt") {
t.Fatalf("expected diff not to report UpdatedAt difference when ignored, got: %s", diffWithBob)
}
}
func TestIgnoreUnexportedFields(t *testing.T) {
t.Run("DirectComparisonPanicsOnUnexportedField", func(t *testing.T) {
a := MultiSecretSession{SessionID: "sess-1", token: "tok-aaa", secretKey: []byte{1, 2}}
b := MultiSecretSession{SessionID: "sess-1", token: "tok-bbb", secretKey: []byte{3, 4}}
defer func() {
r := recover()
if r == nil {
t.Fatal("expected unexported field comparison to panic without options")
}
msg := fmt.Sprint(r)
if !strings.Contains(msg, "cannot handle unexported field") {
t.Fatalf("unexpected panic message: %s", msg)
}
}()
_ = cmp.Equal(a, b)
})
t.Run("IgnoreUnexportedFieldsBypassesPanicAndIgnoresAllPrivateFields", func(t *testing.T) {
a := MultiSecretSession{SessionID: "sess-1", token: "tok-aaa", secretKey: []byte{1, 2}}
b := MultiSecretSession{SessionID: "sess-1", token: "tok-bbb", secretKey: []byte{3, 4}}
opt := IgnoreUnexportedFields()
if !cmp.Equal(a, b, opt) {
t.Fatalf("expected equality when unexported fields are ignored, diff: %s", cmp.Diff(a, b, opt))
}
diff := cmp.Diff(a, b, opt)
if diff != "" {
t.Fatalf("expected empty diff, got: %s", diff)
}
// When exported field differs, inequality is detected properly
b.SessionID = "sess-2"
if cmp.Equal(a, b, opt) {
t.Fatal("expected inequality when exported SessionID differs")
}
diffSess := cmp.Diff(a, b, opt)
if !strings.Contains(diffSess, "SessionID") {
t.Fatalf("expected diff to report SessionID mismatch, got: %s", diffSess)
}
})
t.Run("IgnoreSpecificUnexportedFieldByName", func(t *testing.T) {
a := TokenSession{SessionID: "sess-1", token: "tok-aaa"}
b := TokenSession{SessionID: "sess-1", token: "tok-bbb"}
opt := IgnoreFieldByName("token")
if !cmp.Equal(a, b, opt) {
t.Fatalf("expected equality when token is ignored, diff: %s", cmp.Diff(a, b, opt))
}
diff := cmp.Diff(a, b, opt)
if diff != "" {
t.Fatalf("expected empty diff when only unexported field is ignored, got: %s", diff)
}
})
t.Run("PartialIgnorePanicsOnRemainingUnexportedFields", func(t *testing.T) {
a := MultiSecretSession{SessionID: "sess-1", token: "tok-aaa", secretKey: []byte{1}}
b := MultiSecretSession{SessionID: "sess-1", token: "tok-bbb", secretKey: []byte{2}}
// Ignoring only 'token' leaves 'secretKey' unhandled
opt := IgnoreFieldByName("token")
defer func() {
r := recover()
if r == nil {
t.Fatal("expected panic on remaining unhandled unexported field secretKey")
}
msg := fmt.Sprint(r)
if !strings.Contains(msg, "cannot handle unexported field at {ignorecmp.MultiSecretSession}.secretKey") {
t.Fatalf("unexpected panic message: %s", msg)
}
}()
_ = cmp.Equal(a, b, opt)
})
}
func TestIgnoreType(t *testing.T) {
t1 := time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)
t2 := time.Date(2026, 12, 31, 23, 59, 59, 0, time.UTC)
optIgnoreTime := IgnoreType(reflect.TypeOf(time.Time{}))
if !cmp.Equal(t1, t2, optIgnoreTime) {
t.Fatalf("expected cmp.Equal to return true when time.Time is ignored")
}
acc1 := Account{ID: 5, Username: "user5", UpdatedAt: t1}
acc2 := Account{ID: 5, Username: "user5", UpdatedAt: t2}
if !cmp.Equal(acc1, acc2, optIgnoreTime) {
t.Fatalf("expected struct with differing time.Time field to match when time.Time is ignored")
}
}
func TestIgnoreMatchingValuesWithFilterValues(t *testing.T) {
// Ignore comparisons between strings if either string is the wildcard "*"
ignoreWildcard := IgnoreMatchingValues(func(x, y string) bool {
return x == "*" || y == "*"
})
type Config struct {
Host string
Port string
}
c1 := Config{Host: "localhost", Port: "8080"}
c2 := Config{Host: "*", Port: "8080"}
if !cmp.Equal(c1, c2, ignoreWildcard) {
t.Fatalf("expected Configs to match when Host has wildcard, diff: %s", cmp.Diff(c1, c2, ignoreWildcard))
}
c3 := Config{Host: "*", Port: "9090"}
if cmp.Equal(c1, c3, ignoreWildcard) {
t.Fatalf("expected Port mismatch to cause inequality")
}
}
func TestIgnoreMapKeyAndSliceIndex(t *testing.T) {
t.Run("IgnoreMapKey", func(t *testing.T) {
m1 := map[string]int{"status": 200, "cache_ttl": 60, "cluster": 1}
m2 := map[string]int{"status": 200, "cache_ttl": 9999, "cluster": 1}
opt := IgnoreMapKey("cache_ttl")
if !cmp.Equal(m1, m2, opt) {
t.Fatalf("expected maps to be equal when cache_ttl key is ignored, diff: %s", cmp.Diff(m1, m2, opt))
}
m3 := map[string]int{"status": 500, "cache_ttl": 9999, "cluster": 1}
if cmp.Equal(m1, m3, opt) {
t.Fatal("expected status mismatch to be detected")
}
})
t.Run("IgnoreSliceIndex", func(t *testing.T) {
s1 := []string{"commit-hash-abc", "active", "zone-us-east"}
s2 := []string{"commit-hash-xyz", "active", "zone-us-east"}
opt := IgnoreSliceIndex(0)
if !cmp.Equal(s1, s2, opt) {
t.Fatalf("expected slices to be equal when index 0 is ignored, diff: %s", cmp.Diff(s1, s2, opt))
}
s3 := []string{"commit-hash-xyz", "inactive", "zone-us-east"}
if cmp.Equal(s1, s3, opt) {
t.Fatal("expected index 1 mismatch to be detected")
}
})
}
{
"schemaVersion": 1,
"goal": "verify github.com/google/go-cmp/cmp.Ignore in pkg:golang/github.com/google/go-cmp@v0.6.0",
"kind": "HOW",
"packages": [
"pkg:golang/github.com/google/go-cmp@v0.6.0"
],
"symbols": [
"github.com/google/go-cmp/cmp.Ignore"
]
}
オリジンシーダー
匿名