agentleFS
hiromailyhiromaily/go-crypto-wallet/.cursor/rules/internal/mockery.mdc

go-crypto-wallet / internal

Cursor rule128 starsChanged 6 months agoMITView on GitHub

Mockery Mock Generation Rules

We split this mockery.mdc into the rules it gives an agent

8 rules. About 0 are common, 3 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Every interface defined under internal/application/ports/ MUST have a corresponding mockery-generated mock in the appropriate mocks/ …

    line 12
  2. Very specific:

    When a new interface is added to internal/application/ports/:

    line 33
  3. Very specific:

    Verify: Run make go-lint and make check-build.

    line 37
  4. Distinctive:

    Do these in the same commit or PR as the interface definition.

    line 39
  5. Very specific:

    Never: call mock.AssertExpectations(t) manually — the NewMock*(t) constructor registers cleanup automatically via t.Cleanup.

    line 76
  6. Very specific:

    Always regenerate with make mockery instead of editing manually.

    line 82
  7. Distinctive:

    When a use case declares a local unexported interface that composes two (or more) port interfaces (e.g.

    line 86
  8. Distinctive:

    Do not generate a mock for the composite local interface itself

    line 117

≈ “Common” is an estimate: at least 1 in 5 of the 6,350 Cursor rule files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
mockery.mdc
---
description: Mockery Mock Generation Rules
globs: ["internal/application/ports/**/*.go", "internal/infrastructure/**/*.go"]
alwaysApply: false
---


# Mockery Mock Generation Rules

## Overview

Every interface defined under `internal/application/ports/` MUST have a corresponding
mockery-generated mock in the appropriate `mocks/` subdirectory of the infrastructure layer.
Manually written mocks or stubs for these interfaces are **not allowed**.

## Placement Convention

Mocks are placed in the infrastructure layer alongside the concrete implementations:

| Interface package (`application/ports/`) | Mock directory (`infrastructure/`) |
|---|---|
| `ports/api/btc/` | `infrastructure/api/btc/mocks/` |
| `ports/api/eth/` | `infrastructure/api/eth/mocks/` |
| `ports/api/xrp/` | `infrastructure/api/xrp/mocks/` |
| `ports/file/` | `infrastructure/storage/file/transaction/mocks/` |
| `ports/repository/cold/` | `infrastructure/repository/cold/mocks/` |
| `ports/repository/watch/` | `infrastructure/repository/watch/mocks/` |

**Pattern**: `ports/<layer>/<pkg>/` → `infrastructure/<layer>/<pkg>/mocks/`

## Mandatory Steps When Adding a New Interface

When a new interface is added to `internal/application/ports/`:

1. **Add to `.mockery.yaml`**: Register the interface under its package entry with the correct `dir`.
2. **Run `make mockery`**: Regenerate all mocks.
3. **Verify**: Run `make go-lint` and `make check-build`.

Do these in the **same commit or PR** as the interface definition.

## `.mockery.yaml` Entry Format

```yaml
packages:
  github.com/hiromaily/go-crypto-wallet/internal/application/ports/<layer>/<pkg>:
    config:
      dir: "internal/infrastructure/<layer>/<pkg>/mocks"
      pkgname: "mocks"
    interfaces:
      MyNewInterface:
```

## Mock File Conventions (auto-applied by global config)

| Setting | Value |
|---|---|
| Filename | `mock_<interface_name_snakecase>.go` |
| Struct name | `Mock<InterfaceName>` |
| Constructor | `NewMock<InterfaceName>(t)` |
| Framework | `testify/mock` with `.EXPECT()` builder |

## Using Mocks in Tests

```go
import coldmocks "github.com/hiromaily/go-crypto-wallet/internal/infrastructure/repository/cold/mocks"

func TestFoo(t *testing.T) {
    repo := coldmocks.NewMockBTCAccountKeyRepositorier(t)
    repo.EXPECT().
        GetOneMaxID(domainAccount.AccountTypeDeposit).
        Return(key, nil)
    // ...
}
```

**Never** call `mock.AssertExpectations(t)` manually — the `NewMock*(t)` constructor registers
cleanup automatically via `t.Cleanup`.

## DO NOT Edit Generated Mock Files

Files in `mocks/` directories contain `// Code generated by mockery; DO NOT EDIT.`.
Always regenerate with `make mockery` instead of editing manually.

## Combined Mock Struct for Local Unexported Interfaces

When a use case declares a local unexported interface that composes two (or more) port interfaces
(e.g. `xrpSendTxClient` combining `TransactionSubmitter` + `LedgerPoller`), tests cannot directly
use a single generated mock because no single mock satisfies the composite type.

**Pattern**: embed the relevant mocks into a thin struct:

```go
// Production code (send_transaction.go)
type xrpSendTxClient interface {
    apixrp.TransactionSubmitter
    apixrp.LedgerPoller
}

// Test code (send_transaction_test.go)
type mockSendTxClient struct {
    *xrpapiamocks.MockTransactionSubmitter
    *xrpapiamocks.MockLedgerPoller
}

func createSendUseCase(deps *sendTestDependencies) watchusecase.SendTransactionUseCase {
    client := &mockSendTxClient{
        MockTransactionSubmitter: deps.submitter,
        MockLedgerPoller:         deps.ledgerPoller,
    }
    return xrp.NewSendTransactionUseCase(client, nil, deps.txDetailRepo, deps.txFileRepo)
}
```

Rules:
- The embedding struct lives in the **test file**, not in `mocks/`
- Each embedded field is still a `NewMock*(t)` instance with its own `.EXPECT()` setup
- Do **not** generate a mock for the composite local interface itself

## Exceptions

- **`Ethereumer` (ETH)**: DI-layer-only monolithic interface — do NOT add to `.mockery.yaml`.
- **`ETHTransactionSender`**: Type alias for `TxSender` — mockery cannot generate mocks for type aliases; mock `TxSender` instead.
- **Composed ETH interfaces** (`ETHKeygenSignClient`, `ETHWatchClient`, `WatchTxCreationDeps`, `KeygenSignTxDeps`): Leaf interface mocks satisfy all compositions implicitly — do NOT add composed interfaces to `.mockery.yaml`.
- **Use case interfaces** (`internal/application/usecase/*/interfaces.go`): These are NOT ports interfaces. Simple struct stubs are acceptable for testing use case orchestration.
- **Compile-time conformance stubs** in `*_test.go` files (e.g., in `ports/` packages): These are intentional type-check helpers, not test doubles — keep them as-is.

## Related Files

- `.mockery.yaml` — mockery configuration (SSOT for all mock generation)
- `Makefile` → `make mockery` — regenerates all mocks
- `@.claude/rules/internal/infrastructure-layer.md` — infrastructure layer rules
- `@.claude/rules/internal/application-layer.md` — application layer rules

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.