package main
import (
"errors"
"testing"
)
type MockCommand struct {
output string
err error
}
func NewMockCommand(output string) *MockCommand {
return &MockCommand{output: output}
}
func NewMockCommandWithError(err error) *MockCommand {
return &MockCommand{err: err}
}
func (m *MockCommand) Execute(binary string, args ...string) ([]byte, error) {
if m.err != nil {
return nil, m.err
}
return []byte(m.output), nil
}
func TestGetGPUInfo(t *testing.T) {
mockOutput := `Graphics/Displays:
Apple M2:
Total Number of Cores: 10`
cmd := NewMockCommand(mockOutput)
result, err := getGPUInfo(cmd)
if err != nil {
t.Fatalf("Expected no error, got: %v", err)
}
expected := CoreCount(10)
if result != expected {
t.Errorf("Expected %d GPU cores, got %d", expected, result)
}
}
func TestGetGPUInfoNotFound(t *testing.T) {
mockOutput := `Graphics/Displays:
Apple M2:
Some other field: 10`
cmd := NewMockCommand(mockOutput)
_, err := getGPUInfo(cmd)
if err == nil {
t.Fatal("Expected error when GPU cores not found, got nil")
}
}
func TestGetCPUInfoSuccess(t *testing.T) {
mockOutput := "Apple M2\n8\n4\n4\n"
cmd := NewMockCommand(mockOutput)
brand, cores, pCores, eCores, err := getCPUInfo(cmd)
if err != nil {
t.Fatalf("Expected no error, got: %v", err)
}
if brand != "Apple M2" {
t.Errorf("Expected brand 'Apple M2', got '%s'", brand)
}
if cores != 8 {
t.Errorf("Expected 8 cores, got %d", cores)
}
if pCores != 4 {
t.Errorf("Expected 4 performance cores, got %d", pCores)
}
if eCores != 4 {
t.Errorf("Expected 4 efficiency cores, got %d", eCores)
}
}
func TestGetCPUInfoMissingCoreCount(t *testing.T) {
mockOutput := "Apple M2\n"
cmd := NewMockCommand(mockOutput)
_, _, _, _, err := getCPUInfo(cmd)
if err == nil {
t.Fatal("Expected error with insufficient output, got nil")
}
}
func TestGetCPUInfoInvalidCoreCount(t *testing.T) {
mockOutput := "Apple M2\ninvalid\n4\n4\n"
cmd := NewMockCommand(mockOutput)
_, _, _, _, err := getCPUInfo(cmd)
if err == nil {
t.Fatal("Expected error with invalid core count, got nil")
}
}
func TestFromBrandString(t *testing.T) {
tests := []struct {
brand string
expected AppleChip
}{
{"Apple M1", M1},
{"Apple M1 Pro", M1Pro},
{"Apple M1 Max", M1Max},
{"Apple M1 Ultra", M1Ultra},
{"Apple M2", M2},
{"Apple M2 Pro", M2Pro},
{"Apple M2 Max", M2Max},
{"Apple M2 Ultra", M2Ultra},
{"Apple M3", M3},
{"Apple M3 Pro", M3Pro},
{"Apple M3 Max", M3Max},
{"Intel Core i7", Unknown},
}
for _, test := range tests {
result := fromBrandString(test.brand)
if result != test.expected {
t.Errorf("For brand '%s', expected %v, got %v", test.brand, test.expected, result)
}
}
}
func TestChipGetSpecs(t *testing.T) {
tests := []struct {
chip AppleChip
expected ChipSpecs
}{
{M1, ChipSpecs{CPUTDP: 20, GPUTDP: 20, CPUBW: 70, GPUBW: 70}},
{M1Pro, ChipSpecs{CPUTDP: 30, GPUTDP: 30, CPUBW: 200, GPUBW: 200}},
{M2, ChipSpecs{CPUTDP: 25, GPUTDP: 15, CPUBW: 100, GPUBW: 100}},
{Unknown, ChipSpecs{CPUTDP: 0, GPUTDP: 0, CPUBW: 0, GPUBW: 0}},
}
for _, test := range tests {
result := test.chip.getSpecs()
if result != test.expected {
t.Errorf("For chip %v, expected %+v, got %+v", test.chip, test.expected, result)
}
}
}
func TestNewSocInfoWithCommand(t *testing.T) {
sysctlOutput := "Apple M2\n8\n4\n4\n"
profilerOutput := `Graphics/Displays:
Apple M2:
Total Number of Cores: 10`
cmd := &MockCommandMultiple{
outputs: map[string]string{
"/usr/sbin/sysctl": sysctlOutput,
"/usr/sbin/system_profiler": profilerOutput,
},
}
socInfo, err := NewSocInfoWithCommand(cmd)
if err != nil {
t.Fatalf("Expected no error, got: %v", err)
}
if socInfo.CPUBrandName != "Apple M2" {
t.Errorf("Expected CPU brand 'Apple M2', got '%s'", socInfo.CPUBrandName)
}
if socInfo.NumCPUCores != 8 {
t.Errorf("Expected 8 CPU cores, got %d", socInfo.NumCPUCores)
}
if socInfo.NumGPUCores != 10 {
t.Errorf("Expected 10 GPU cores, got %d", socInfo.NumGPUCores)
}
if socInfo.CPUMaxPower == nil || *socInfo.CPUMaxPower != 25 {
t.Errorf("Expected CPU max power 25W, got %v", socInfo.CPUMaxPower)
}
}
type MockCommandMultiple struct {
outputs map[string]string
err error
}
func (m *MockCommandMultiple) Execute(binary string, args ...string) ([]byte, error) {
if m.err != nil {
return nil, m.err
}
output, exists := m.outputs[binary]
if !exists {
return nil, errors.New("binary not found in mock")
}
return []byte(output), nil
}