Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions src/cli/auth/oauth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package auth

import (
"encoding/base64"
"testing"
)

func TestHashSha256(t *testing.T) {
input := "hello world"
// echo -n "hello world" | openssl sha256 -binary | base64
// uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=
expectedBase64 := "uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="

got := hash_sha256(input)
gotBase64 := base64.StdEncoding.EncodeToString(got)

if gotBase64 != expectedBase64 {
t.Errorf("hash_sha256(%q) = %q, want %q", input, gotBase64, expectedBase64)
}
}

func TestGenerateCodeVerifier(t *testing.T) {
u := &User{}
u.generate_code_verifier()

if len(u.Code_verifier) < 43 || len(u.Code_verifier) > 128 {
t.Errorf("generate_code_verifier() length = %d, want between 43 and 128", len(u.Code_verifier))
}

// Check for invalid characters
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
for _, char := range u.Code_verifier {
isAllowed := false
for _, a := range allowed {
if char == a {
isAllowed = true
break
}
}
if !isAllowed {
t.Errorf("generate_code_verifier() contains invalid character: %c", char)
}
}
}

func TestGenerateCodeChallenge(t *testing.T) {
u := &User{}
// Set a fixed verifier for reproducibility
u.Code_verifier = "hello_world_verifier_1234567890"

// sha256("hello_world_verifier_1234567890")
// echo -n "hello_world_verifier_1234567890" | openssl sha256 -binary | base64
// hash = 84c3c33379967676e828114f851080d859e3557451965b1285268c375531d041
// Base64URL(hash) (without padding)

u.generate_code_challenge()

// Verify the result
// The implementation calls hash_sha256 then Base64 RawURL encoding
hash := hash_sha256(u.Code_verifier)
expected := base64.RawURLEncoding.EncodeToString(hash)

if u.Code_challenge != expected {
t.Errorf("generate_code_challenge() = %q, want %q", u.Code_challenge, expected)
}
}

func TestGenerateState(t *testing.T) {
u := &User{}
length := 127
u.generate_state(length)

// The implementation generates random bytes of 'length' then Base64 URL encodes them.
// So the resulting string length will be roughly length * 4/3.

if u.State == "" {
t.Error("generate_state() produced empty state")
}

// Decode back to check byte length
decoded, err := base64.URLEncoding.DecodeString(u.State)
if err != nil {
t.Errorf("generate_state() produced invalid base64: %v", err)
}

if len(decoded) != length {
t.Errorf("generate_state() decoded length = %d, want %d", len(decoded), length)
}
}
36 changes: 36 additions & 0 deletions src/cli/auth/url_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package auth

import (
"strings"
"testing"
)

func TestGenerateAuthUrl(t *testing.T) {
u := &User{
State: "test_state",
Code_challenge: "test_challenge",
}

u.generate_auth_url()

if u.Auth_URL == "" {
t.Error("generate_auth_url() resulted in empty Auth_URL")
}

expectedParts := []string{
"https://twitter.com/i/oauth2/authorize",
"response_type=code",
"client_id=emJHZzZHMUdHMF9QRlRIdk45QjY6MTpjaQ",
"redirect_uri=https://x-blush.vercel.app/api/auth",
"scope=tweet.read%20tweet.write%20users.read%20users.read%20follows.read%20follows.write%20offline.access",
"state=test_state",
"code_challenge=test_challenge",
"code_challenge_method=S256",
}

for _, part := range expectedParts {
if !strings.Contains(u.Auth_URL, part) {
t.Errorf("Auth_URL missing part: %s", part)
}
}
}
10 changes: 10 additions & 0 deletions src/cli/auth/validate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package auth

import "testing"

func TestIsAuthenticated(t *testing.T) {
got := IsAuthenticated()
if got != false {
t.Errorf("IsAuthenticated() = %v, want false", got)
}
}
71 changes: 71 additions & 0 deletions src/cli/lock/file_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package lock

import (
"os"
"path/filepath"
"testing"
)

func TestLicenseFileOperations(t *testing.T) {
// Create a temporary directory to act as HOME
tempDir, err := os.MkdirTemp("", "locktest")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tempDir)

// Set HOME environment variable to tempDir
originalHome := os.Getenv("HOME")
defer os.Setenv("HOME", originalHome)
os.Setenv("HOME", tempDir)

licenseKey := "test-license-key-123"

// Test WriteLicenseKeyToFile
t.Run("WriteLicenseKeyToFile", func(t *testing.T) {
err := WriteLicenseKeyToFile(licenseKey)
if err != nil {
t.Errorf("WriteLicenseKeyToFile() error = %v", err)
}

// Verify file exists
expectedPath := filepath.Join(tempDir, ".tempxcli")
content, err := os.ReadFile(expectedPath)
if err != nil {
t.Errorf("Failed to read license file: %v", err)
}
if string(content) != licenseKey {
t.Errorf("File content = %q, want %q", string(content), licenseKey)
}
})

// Test ReadLicenseKeyFromFile
t.Run("ReadLicenseKeyFromFile", func(t *testing.T) {
readKey, err := ReadLicenseKeyFromFile()
if err != nil {
t.Errorf("ReadLicenseKeyFromFile() error = %v", err)
}
if readKey != licenseKey {
t.Errorf("ReadLicenseKeyFromFile() = %q, want %q", readKey, licenseKey)
}
})

// Test ClearLicenseFile
t.Run("ClearLicenseFile", func(t *testing.T) {
err := ClearLicenseFile()
if err != nil {
t.Errorf("ClearLicenseFile() error = %v", err)
}

// Verify file is gone
_, err = ReadLicenseKeyFromFile()
if err == nil {
t.Error("ReadLicenseKeyFromFile() should fail after clear, but it succeeded")
}

expectedPath := filepath.Join(tempDir, ".tempxcli")
if _, err := os.Stat(expectedPath); !os.IsNotExist(err) {
t.Error("License file should not exist after clear")
}
})
}
Loading