package perspective import ( "context" "testing" "4vif5i.gitea.cloud/numenor-labs/discourse/backend/ipfs" "github.com/go-redis/redismock/v8" "github.com/stretchr/testify/assert" "gorm.io/driver/sqlite" "gorm.io/gorm" ) // Setup test dependencies func setupTestDependencies(t *testing.T) (*PerspectiveService, redismock.ClientMock) { // Setup mock Redis client, mock := redismock.NewClientMock() // Setup in-memory SQLite database db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) if err != nil { t.Fatalf("Failed to open in-memory database: %v", err) } // Create a mock IPFS service ipfsService := ipfs.NewMockIPFSService() // Create the service with our mocks service := NewPerspectiveService(client, db, ipfsService) return service, mock } func TestSubmitPerspective_Success(t *testing.T) { service, mock := setupTestDependencies(t) ctx := context.Background() // Setup Redis mock expectations for unverified user mock.ExpectExists("user:0x1234:submissions").SetVal(0) mock.ExpectSet("user:0x1234:submissions", 1, RedisTTL).SetVal("OK") // Call the service method ipfsHash, err := service.SubmitPerspective( ctx, "issue123", "This is a test perspective", "", "0x1234", false, ValidCaptchaToken, ) // Verify the results assert.NoError(t, err) assert.NotEmpty(t, ipfsHash) // Verify Redis mock expectations were met if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("Redis expectations were not met: %v", err) } // Verify perspective was stored in the database var perspective Perspective err = service.db.Where("ipfs_hash = ?", ipfsHash).First(&perspective).Error assert.NoError(t, err) assert.Equal(t, "issue123", perspective.IssueID) assert.Equal(t, "0x1234", perspective.UserAddress) assert.Equal(t, false, perspective.IsVerified) } func TestSubmitPerspective_VerifiedUser(t *testing.T) { service, mock := setupTestDependencies(t) ctx := context.Background() // No need to mock Redis for verified user // Call the service method ipfsHash, err := service.SubmitPerspective( ctx, "issue123", "This is a test perspective from a verified user", "", "0x5678", true, // Verified user "", // No captcha needed ) // Verify the results assert.NoError(t, err) assert.NotEmpty(t, ipfsHash) // Verify Redis mock expectations were met if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("Redis expectations were not met: %v", err) } // Verify perspective was stored in the database var perspective Perspective err = service.db.Where("ipfs_hash = ?", ipfsHash).First(&perspective).Error assert.NoError(t, err) assert.Equal(t, "issue123", perspective.IssueID) assert.Equal(t, "0x5678", perspective.UserAddress) assert.Equal(t, true, perspective.IsVerified) } func TestSubmitPerspective_RateLimit(t *testing.T) { service, mock := setupTestDependencies(t) ctx := context.Background() // Setup Redis mock expectations for rate-limited user mock.ExpectGet("user:0x1234:submissions").SetVal("5") // Rate limit reached // Call the service method _, err := service.SubmitPerspective( ctx, "issue123", "This is a test perspective that should be rate limited", "", "0x1234", false, ValidCaptchaToken, ) // Verify the results assert.Error(t, err) assert.Contains(t, err.Error(), "rate limit exceeded") // Verify Redis mock expectations were met if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("Redis expectations were not met: %v", err) } } func TestSubmitPerspective_InvalidCaptcha(t *testing.T) { service, _ := setupTestDependencies(t) ctx := context.Background() // Call the service method with invalid captcha _, err := service.SubmitPerspective( ctx, "issue123", "This is a test perspective with invalid captcha", "", "0x1234", false, "invalid-token", ) // Verify the results assert.Error(t, err) assert.Contains(t, err.Error(), "invalid CAPTCHA token") } func TestSubmitPerspective_OversizedText(t *testing.T) { service, _ := setupTestDependencies(t) ctx := context.Background() // Generate a text that exceeds the maximum length oversizedText := "" for i := 0; i < MaxTextLength+100; i++ { oversizedText += "a" } // Call the service method with oversized text _, err := service.SubmitPerspective( ctx, "issue123", oversizedText, "", "0x1234", true, "", ) // Verify the results assert.Error(t, err) assert.Contains(t, err.Error(), "exceeds maximum length") } func TestGetPerspectivesByIssue(t *testing.T) { service, _ := setupTestDependencies(t) ctx := context.Background() // Insert test perspectives for the issue testIssueID := "issue456" // Create and store a few test perspectives for i := 0; i < 3; i++ { ipfsHash, err := service.SubmitPerspective( ctx, testIssueID, "Test perspective", "", "0xABCD", true, "", ) assert.NoError(t, err) assert.NotEmpty(t, ipfsHash) } // Also create a perspective for a different issue _, err := service.SubmitPerspective( ctx, "different-issue", "Different issue perspective", "", "0xABCD", true, "", ) assert.NoError(t, err) // Get perspectives for the test issue perspectives, err := service.GetPerspectivesByIssue(testIssueID) // Verify the results assert.NoError(t, err) assert.Len(t, perspectives, 3) // Should only find the 3 perspectives for this issue // Verify each perspective has the correct issue ID for _, p := range perspectives { assert.Equal(t, testIssueID, p.IssueID) } }