Add missing Good/Bad/Ugly test triplets per RFC section 22: - stats_test.go: OnAccept/OnReject/Tick/OnLogin/OnClose tests with concurrency race test and top-10 diff slot verification - ratelimit_test.go: full Good/Bad/Ugly set including ban persistence and disabled-limiter edge case - customdiff_test.go: renamed to Apply_Good/Bad/Ugly convention per RFC - storage_test.go: full Add_Good/Bad/Ugly set including 256-slot fill, overflow rejection, and dead-slot reclamation via SetJob - job_test.go: added Good/Bad/Ugly for BlobWithFixedByte, DifficultyFromTarget, and IsValid Add Miner.Diff() public getter for the last difficulty sent to miner. Add AX-compliant usage-example comments (principle 2) to all Miner accessors, Proxy query methods, EffectiveShareDifficulty, targetFromDifficulty, MinerSnapshot, and RateLimiter.IsActive. Co-Authored-By: Virgil <virgil@lethean.io>
116 lines
3.5 KiB
Go
116 lines
3.5 KiB
Go
package proxy
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestJob_BlobWithFixedByte_Good verifies nonce patching on a full 160-char blob.
|
|
//
|
|
// job := proxy.Job{Blob: strings.Repeat("0", 160)}
|
|
// result := job.BlobWithFixedByte(0x2A) // chars 78-79 become "2a"
|
|
func TestJob_BlobWithFixedByte_Good(t *testing.T) {
|
|
job := Job{Blob: strings.Repeat("0", 160)}
|
|
got := job.BlobWithFixedByte(0x2A)
|
|
if len(got) != 160 {
|
|
t.Fatalf("expected length 160, got %d", len(got))
|
|
}
|
|
if got[78:80] != "2a" {
|
|
t.Fatalf("expected fixed byte patch, got %q", got[78:80])
|
|
}
|
|
}
|
|
|
|
// TestJob_BlobWithFixedByte_Bad verifies a short blob is returned unchanged.
|
|
//
|
|
// job := proxy.Job{Blob: "0000"}
|
|
// result := job.BlobWithFixedByte(0x2A) // too short, returned as-is
|
|
func TestJob_BlobWithFixedByte_Bad(t *testing.T) {
|
|
shortBlob := "0000"
|
|
job := Job{Blob: shortBlob}
|
|
got := job.BlobWithFixedByte(0x2A)
|
|
if got != shortBlob {
|
|
t.Fatalf("expected short blob to be returned unchanged, got %q", got)
|
|
}
|
|
}
|
|
|
|
// TestJob_BlobWithFixedByte_Ugly verifies fixedByte 0xFF renders as lowercase "ff".
|
|
//
|
|
// job := proxy.Job{Blob: strings.Repeat("0", 160)}
|
|
// result := job.BlobWithFixedByte(0xFF) // chars 78-79 become "ff" (not "FF")
|
|
func TestJob_BlobWithFixedByte_Ugly(t *testing.T) {
|
|
job := Job{Blob: strings.Repeat("0", 160)}
|
|
got := job.BlobWithFixedByte(0xFF)
|
|
if got[78:80] != "ff" {
|
|
t.Fatalf("expected lowercase 'ff', got %q", got[78:80])
|
|
}
|
|
if len(got) != 160 {
|
|
t.Fatalf("expected blob length preserved, got %d", len(got))
|
|
}
|
|
}
|
|
|
|
// TestJob_DifficultyFromTarget_Good verifies a known target converts to the expected difficulty.
|
|
//
|
|
// job := proxy.Job{Target: "b88d0600"}
|
|
// diff := job.DifficultyFromTarget() // 10000
|
|
func TestJob_DifficultyFromTarget_Good(t *testing.T) {
|
|
job := Job{Target: "b88d0600"}
|
|
if got := job.DifficultyFromTarget(); got != 10000 {
|
|
t.Fatalf("expected difficulty 10000, got %d", got)
|
|
}
|
|
}
|
|
|
|
// TestJob_DifficultyFromTarget_Bad verifies a zero target produces difficulty 0 without panic.
|
|
//
|
|
// job := proxy.Job{Target: "00000000"}
|
|
// diff := job.DifficultyFromTarget() // 0 (no divide-by-zero)
|
|
func TestJob_DifficultyFromTarget_Bad(t *testing.T) {
|
|
job := Job{Target: "00000000"}
|
|
if got := job.DifficultyFromTarget(); got != 0 {
|
|
t.Fatalf("expected difficulty 0 for zero target, got %d", got)
|
|
}
|
|
}
|
|
|
|
// TestJob_DifficultyFromTarget_Ugly verifies the maximum target "ffffffff" yields difficulty 1.
|
|
//
|
|
// job := proxy.Job{Target: "ffffffff"}
|
|
// diff := job.DifficultyFromTarget() // 1
|
|
func TestJob_DifficultyFromTarget_Ugly(t *testing.T) {
|
|
job := Job{Target: "ffffffff"}
|
|
if got := job.DifficultyFromTarget(); got != 1 {
|
|
t.Fatalf("expected minimum difficulty 1, got %d", got)
|
|
}
|
|
}
|
|
|
|
// TestJob_IsValid_Good verifies a job with blob and job ID is valid.
|
|
//
|
|
// job := proxy.Job{Blob: "abc", JobID: "job-1"}
|
|
// job.IsValid() // true
|
|
func TestJob_IsValid_Good(t *testing.T) {
|
|
job := Job{Blob: "abc", JobID: "job-1"}
|
|
if !job.IsValid() {
|
|
t.Fatalf("expected job with blob and job id to be valid")
|
|
}
|
|
}
|
|
|
|
// TestJob_IsValid_Bad verifies a job with empty blob or job ID is invalid.
|
|
//
|
|
// job := proxy.Job{Blob: "", JobID: "job-1"}
|
|
// job.IsValid() // false
|
|
func TestJob_IsValid_Bad(t *testing.T) {
|
|
if (Job{Blob: "", JobID: "job-1"}).IsValid() {
|
|
t.Fatalf("expected empty blob to be invalid")
|
|
}
|
|
if (Job{Blob: "abc", JobID: ""}).IsValid() {
|
|
t.Fatalf("expected empty job id to be invalid")
|
|
}
|
|
}
|
|
|
|
// TestJob_IsValid_Ugly verifies a zero-value job is invalid.
|
|
//
|
|
// job := proxy.Job{}
|
|
// job.IsValid() // false
|
|
func TestJob_IsValid_Ugly(t *testing.T) {
|
|
if (Job{}).IsValid() {
|
|
t.Fatalf("expected zero-value job to be invalid")
|
|
}
|
|
}
|