Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
700 lines
18 KiB
Go
700 lines
18 KiB
Go
package intelligence
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
slurpContext "chorus/pkg/slurp/context"
|
|
)
|
|
|
|
func TestIntelligenceEngine_Integration(t *testing.T) {
|
|
// Create test configuration
|
|
config := &EngineConfig{
|
|
EnableRAG: false, // Disable RAG for testing
|
|
EnableGoalAlignment: true,
|
|
EnablePatternDetection: true,
|
|
EnableRoleAware: true,
|
|
MaxConcurrentAnalysis: 2,
|
|
AnalysisTimeout: 30 * time.Second,
|
|
CacheTTL: 5 * time.Minute,
|
|
MinConfidenceThreshold: 0.5,
|
|
}
|
|
|
|
// Create engine
|
|
engine := NewIntelligenceEngine(config)
|
|
ctx := context.Background()
|
|
|
|
// Create test context node
|
|
testNode := &slurpContext.ContextNode{
|
|
Path: "/test/example.go",
|
|
Summary: "A Go service implementing user authentication",
|
|
Purpose: "Handles user login and authentication for the web application",
|
|
Technologies: []string{"go", "jwt", "bcrypt"},
|
|
Tags: []string{"authentication", "security", "web"},
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
|
|
// Create test project goal
|
|
testGoal := &ProjectGoal{
|
|
ID: "auth_service",
|
|
Name: "Authentication Service",
|
|
Description: "Build secure user authentication system",
|
|
Keywords: []string{"authentication", "security", "user", "login"},
|
|
Priority: 1,
|
|
Phase: "development",
|
|
Deadline: nil,
|
|
CreatedAt: time.Now(),
|
|
}
|
|
|
|
t.Run("AnalyzeFile", func(t *testing.T) {
|
|
content := []byte(`
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"crypto/jwt"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
func authenticateUser(username, password string) error {
|
|
// Hash password and validate
|
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
`)
|
|
|
|
analysis, err := engine.AnalyzeFile(ctx, testNode.Path, content)
|
|
if err != nil {
|
|
t.Fatalf("AnalyzeFile failed: %v", err)
|
|
}
|
|
|
|
if analysis.Language != "go" {
|
|
t.Errorf("Expected language 'go', got '%s'", analysis.Language)
|
|
}
|
|
|
|
if len(analysis.Functions) == 0 {
|
|
t.Error("Expected to find functions")
|
|
}
|
|
|
|
if analysis.Complexity <= 0 {
|
|
t.Error("Expected positive complexity score")
|
|
}
|
|
})
|
|
|
|
t.Run("AssessGoalAlignment", func(t *testing.T) {
|
|
assessment, err := engine.AssessGoalAlignment(ctx, testNode, testGoal, "developer")
|
|
if err != nil {
|
|
t.Fatalf("AssessGoalAlignment failed: %v", err)
|
|
}
|
|
|
|
if assessment.OverallScore < 0 || assessment.OverallScore > 1 {
|
|
t.Errorf("Expected score between 0-1, got %f", assessment.OverallScore)
|
|
}
|
|
|
|
if len(assessment.DimensionScores) == 0 {
|
|
t.Error("Expected dimension scores")
|
|
}
|
|
|
|
if assessment.Confidence <= 0 {
|
|
t.Error("Expected positive confidence")
|
|
}
|
|
})
|
|
|
|
t.Run("ProcessForRole", func(t *testing.T) {
|
|
processedNode, err := engine.ProcessForRole(ctx, testNode, "developer")
|
|
if err != nil {
|
|
t.Fatalf("ProcessForRole failed: %v", err)
|
|
}
|
|
|
|
if processedNode.ProcessedForRole != "developer" {
|
|
t.Errorf("Expected processed for role 'developer', got '%s'", processedNode.ProcessedForRole)
|
|
}
|
|
|
|
if len(processedNode.RoleSpecificInsights) == 0 {
|
|
t.Error("Expected role-specific insights")
|
|
}
|
|
})
|
|
|
|
t.Run("DetectPatterns", func(t *testing.T) {
|
|
content := []byte(`
|
|
package main
|
|
|
|
import "sync"
|
|
|
|
type Singleton struct {
|
|
instance *Singleton
|
|
once sync.Once
|
|
}
|
|
|
|
func GetInstance() *Singleton {
|
|
s := &Singleton{}
|
|
s.once.Do(func() {
|
|
s.instance = &Singleton{}
|
|
})
|
|
return s.instance
|
|
}
|
|
`)
|
|
|
|
patterns, err := engine.DetectCodePatterns(ctx, "/test/singleton.go", content)
|
|
if err != nil {
|
|
t.Fatalf("DetectPatterns failed: %v", err)
|
|
}
|
|
|
|
foundSingleton := false
|
|
for _, pattern := range patterns {
|
|
if pattern.Pattern.Name == "Singleton" {
|
|
foundSingleton = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !foundSingleton {
|
|
t.Error("Expected to detect Singleton pattern")
|
|
}
|
|
})
|
|
|
|
t.Run("GenerateInsights", func(t *testing.T) {
|
|
insights, err := engine.GenerateInsights(ctx, testNode, "developer")
|
|
if err != nil {
|
|
t.Fatalf("GenerateInsights failed: %v", err)
|
|
}
|
|
|
|
if len(insights) == 0 {
|
|
t.Error("Expected to generate insights")
|
|
}
|
|
|
|
// Check insight quality
|
|
for _, insight := range insights {
|
|
if insight.Confidence <= 0 || insight.Confidence > 1 {
|
|
t.Errorf("Invalid confidence score: %f", insight.Confidence)
|
|
}
|
|
if insight.Priority <= 0 {
|
|
t.Errorf("Invalid priority: %d", insight.Priority)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestFileAnalyzer_LanguageDetection(t *testing.T) {
|
|
config := &EngineConfig{}
|
|
analyzer := NewDefaultFileAnalyzer(config)
|
|
ctx := context.Background()
|
|
|
|
tests := []struct {
|
|
filename string
|
|
content []byte
|
|
expected string
|
|
}{
|
|
{"test.go", []byte("package main\nfunc main() {}"), "go"},
|
|
{"test.js", []byte("function test() { return 42; }"), "javascript"},
|
|
{"test.py", []byte("def test():\n return 42"), "python"},
|
|
{"test.java", []byte("public class Test { public static void main() {} }"), "java"},
|
|
{"test.rs", []byte("fn main() { println!(\"Hello\"); }"), "rust"},
|
|
{"unknown.txt", []byte("some text content"), "text"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.filename, func(t *testing.T) {
|
|
analysis, err := analyzer.AnalyzeFile(ctx, tt.filename, tt.content)
|
|
if err != nil {
|
|
t.Fatalf("AnalyzeFile failed: %v", err)
|
|
}
|
|
|
|
if analysis.Language != tt.expected {
|
|
t.Errorf("Expected language '%s', got '%s'", tt.expected, analysis.Language)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPatternDetector_DetectDesignPatterns(t *testing.T) {
|
|
config := &EngineConfig{}
|
|
detector := NewDefaultPatternDetector(config)
|
|
ctx := context.Background()
|
|
|
|
tests := []struct {
|
|
name string
|
|
filename string
|
|
content []byte
|
|
expectedPattern string
|
|
}{
|
|
{
|
|
name: "Go Singleton Pattern",
|
|
filename: "singleton.go",
|
|
content: []byte(`
|
|
package main
|
|
import "sync"
|
|
var instance *Singleton
|
|
var once sync.Once
|
|
func GetInstance() *Singleton {
|
|
once.Do(func() {
|
|
instance = &Singleton{}
|
|
})
|
|
return instance
|
|
}
|
|
`),
|
|
expectedPattern: "Singleton",
|
|
},
|
|
{
|
|
name: "Go Factory Pattern",
|
|
filename: "factory.go",
|
|
content: []byte(`
|
|
package main
|
|
func NewUser(name string) *User {
|
|
return &User{Name: name}
|
|
}
|
|
func CreateConnection() Connection {
|
|
return &dbConnection{}
|
|
}
|
|
`),
|
|
expectedPattern: "Factory",
|
|
},
|
|
{
|
|
name: "JavaScript Observer Pattern",
|
|
filename: "observer.js",
|
|
content: []byte(`
|
|
class EventEmitter {
|
|
constructor() {
|
|
this.events = {};
|
|
}
|
|
on(event, listener) {
|
|
this.events[event] = this.events[event] || [];
|
|
this.events[event].push(listener);
|
|
}
|
|
emit(event, data) {
|
|
if (this.events[event]) {
|
|
this.events[event].forEach(listener => listener(data));
|
|
}
|
|
}
|
|
}
|
|
`),
|
|
expectedPattern: "Observer",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
patterns, err := detector.DetectCodePatterns(ctx, tt.filename, tt.content)
|
|
if err != nil {
|
|
t.Fatalf("DetectCodePatterns failed: %v", err)
|
|
}
|
|
|
|
found := false
|
|
for _, pattern := range patterns {
|
|
if pattern.Pattern.Name == tt.expectedPattern {
|
|
found = true
|
|
if pattern.Pattern.Confidence <= 0 {
|
|
t.Errorf("Expected positive confidence, got %f", pattern.Pattern.Confidence)
|
|
}
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
t.Errorf("Expected to find %s pattern", tt.expectedPattern)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGoalAlignment_DimensionCalculators(t *testing.T) {
|
|
config := &EngineConfig{}
|
|
engine := NewGoalAlignmentEngine(config)
|
|
ctx := context.Background()
|
|
|
|
testNode := &slurpContext.ContextNode{
|
|
Path: "/test/auth.go",
|
|
Summary: "User authentication service with JWT tokens",
|
|
Purpose: "Handles user login and token generation",
|
|
Technologies: []string{"go", "jwt", "bcrypt"},
|
|
Tags: []string{"authentication", "security"},
|
|
}
|
|
|
|
testGoal := &ProjectGoal{
|
|
ID: "auth_system",
|
|
Name: "Authentication System",
|
|
Description: "Secure user authentication with JWT",
|
|
Keywords: []string{"authentication", "jwt", "security", "user"},
|
|
Priority: 1,
|
|
Phase: "development",
|
|
}
|
|
|
|
t.Run("KeywordAlignment", func(t *testing.T) {
|
|
calculator := NewKeywordAlignmentCalculator()
|
|
score, err := calculator.Calculate(ctx, testNode, testGoal)
|
|
if err != nil {
|
|
t.Fatalf("Calculate failed: %v", err)
|
|
}
|
|
|
|
if score.Score <= 0 {
|
|
t.Error("Expected positive keyword alignment score")
|
|
}
|
|
|
|
if len(score.Evidence) == 0 {
|
|
t.Error("Expected evidence for keyword matches")
|
|
}
|
|
})
|
|
|
|
t.Run("TechnologyAlignment", func(t *testing.T) {
|
|
calculator := NewTechnologyAlignmentCalculator()
|
|
score, err := calculator.Calculate(ctx, testNode, testGoal)
|
|
if err != nil {
|
|
t.Fatalf("Calculate failed: %v", err)
|
|
}
|
|
|
|
if score.Score <= 0 {
|
|
t.Error("Expected positive technology alignment score")
|
|
}
|
|
})
|
|
|
|
t.Run("FullAssessment", func(t *testing.T) {
|
|
assessment, err := engine.AssessAlignment(ctx, testNode, testGoal, "developer")
|
|
if err != nil {
|
|
t.Fatalf("AssessAlignment failed: %v", err)
|
|
}
|
|
|
|
if assessment.OverallScore <= 0 {
|
|
t.Error("Expected positive overall score")
|
|
}
|
|
|
|
if len(assessment.DimensionScores) == 0 {
|
|
t.Error("Expected dimension scores")
|
|
}
|
|
|
|
// Verify all dimension scores are valid
|
|
for _, dimScore := range assessment.DimensionScores {
|
|
if dimScore.Score < 0 || dimScore.Score > 1 {
|
|
t.Errorf("Invalid dimension score: %f for %s", dimScore.Score, dimScore.Dimension)
|
|
}
|
|
if dimScore.Confidence <= 0 || dimScore.Confidence > 1 {
|
|
t.Errorf("Invalid confidence: %f for %s", dimScore.Confidence, dimScore.Dimension)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestRoleAwareProcessor_Integration(t *testing.T) {
|
|
config := &EngineConfig{}
|
|
processor := NewRoleAwareProcessor(config)
|
|
ctx := context.Background()
|
|
|
|
testNode := &slurpContext.ContextNode{
|
|
Path: "/src/auth/service.go",
|
|
Summary: "Authentication service with password hashing and JWT generation",
|
|
Purpose: "Provides secure user authentication for the application",
|
|
Technologies: []string{"go", "bcrypt", "jwt", "postgresql"},
|
|
Tags: []string{"authentication", "security", "database"},
|
|
Insights: []string{"Uses bcrypt for password hashing", "Implements JWT token generation"},
|
|
}
|
|
|
|
roles := []string{"architect", "developer", "security_analyst", "devops_engineer", "qa_engineer"}
|
|
|
|
for _, roleID := range roles {
|
|
t.Run("Role_"+roleID, func(t *testing.T) {
|
|
// Test role-specific processing
|
|
processedNode, err := processor.ProcessContextForRole(ctx, testNode, roleID)
|
|
if err != nil {
|
|
t.Fatalf("ProcessContextForRole failed for %s: %v", roleID, err)
|
|
}
|
|
|
|
if processedNode.ProcessedForRole != roleID {
|
|
t.Errorf("Expected processed for role '%s', got '%s'", roleID, processedNode.ProcessedForRole)
|
|
}
|
|
|
|
// Test role-specific insight generation
|
|
insights, err := processor.GenerateRoleSpecificInsights(ctx, testNode, roleID)
|
|
if err != nil {
|
|
t.Fatalf("GenerateRoleSpecificInsights failed for %s: %v", roleID, err)
|
|
}
|
|
|
|
if len(insights) == 0 {
|
|
t.Errorf("Expected insights for role %s", roleID)
|
|
}
|
|
|
|
// Validate insight properties
|
|
for _, insight := range insights {
|
|
if insight.RoleID != roleID {
|
|
t.Errorf("Expected insight for role %s, got %s", roleID, insight.RoleID)
|
|
}
|
|
if insight.Confidence <= 0 || insight.Confidence > 1 {
|
|
t.Errorf("Invalid confidence: %f", insight.Confidence)
|
|
}
|
|
}
|
|
|
|
// Test role-specific filtering
|
|
filteredNode, err := processor.FilterContextForRole(testNode, roleID)
|
|
if err != nil {
|
|
t.Fatalf("FilterContextForRole failed for %s: %v", roleID, err)
|
|
}
|
|
|
|
// Verify filtering applied
|
|
if filteredNode.Metadata == nil {
|
|
t.Error("Expected metadata after filtering")
|
|
} else {
|
|
if filteredNode.Metadata["filtered_for_role"] != roleID {
|
|
t.Errorf("Expected filtered_for_role to be %s", roleID)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRoleAwareProcessor_AccessControl(t *testing.T) {
|
|
config := &EngineConfig{}
|
|
processor := NewRoleAwareProcessor(config)
|
|
|
|
testCases := []struct {
|
|
roleID string
|
|
action string
|
|
resource string
|
|
expected bool
|
|
}{
|
|
{"architect", "context:read", "/src/architecture/design.go", true},
|
|
{"developer", "context:write", "/src/auth/service.go", true},
|
|
{"developer", "context:write", "/architecture/system.go", false},
|
|
{"security_analyst", "context:read", "/src/security/auth.go", true},
|
|
{"qa_engineer", "context:read", "/test/integration.go", true},
|
|
{"qa_engineer", "context:write", "/src/production.go", false},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.roleID+"_"+tc.action+"_"+filepath.Base(tc.resource), func(t *testing.T) {
|
|
err := processor.ValidateRoleAccess(tc.roleID, tc.action, tc.resource)
|
|
hasAccess := err == nil
|
|
|
|
if hasAccess != tc.expected {
|
|
t.Errorf("Expected access %v for role %s, action %s, resource %s, got %v",
|
|
tc.expected, tc.roleID, tc.action, tc.resource, hasAccess)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDirectoryAnalyzer_StructureAnalysis(t *testing.T) {
|
|
config := &EngineConfig{}
|
|
analyzer := NewDefaultDirectoryAnalyzer(config)
|
|
|
|
// Create temporary directory structure for testing
|
|
tempDir, err := os.MkdirTemp("", "test_structure")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
// Create test structure
|
|
testDirs := []string{
|
|
"src/main",
|
|
"src/lib",
|
|
"test/unit",
|
|
"test/integration",
|
|
"docs/api",
|
|
"config/dev",
|
|
"deploy/k8s",
|
|
}
|
|
|
|
for _, dir := range testDirs {
|
|
fullPath := filepath.Join(tempDir, dir)
|
|
if err := os.MkdirAll(fullPath, 0755); err != nil {
|
|
t.Fatalf("Failed to create directory %s: %v", fullPath, err)
|
|
}
|
|
|
|
// Create a dummy file in each directory
|
|
testFile := filepath.Join(fullPath, "test.txt")
|
|
if err := os.WriteFile(testFile, []byte("test content"), 0644); err != nil {
|
|
t.Fatalf("Failed to create test file %s: %v", testFile, err)
|
|
}
|
|
}
|
|
|
|
ctx := context.Background()
|
|
analysis, err := analyzer.AnalyzeDirectory(ctx, tempDir)
|
|
if err != nil {
|
|
t.Fatalf("AnalyzeDirectory failed: %v", err)
|
|
}
|
|
|
|
if analysis.TotalFiles <= 0 {
|
|
t.Error("Expected to find files")
|
|
}
|
|
|
|
if analysis.Depth <= 0 {
|
|
t.Error("Expected positive directory depth")
|
|
}
|
|
|
|
if len(analysis.Structure) == 0 {
|
|
t.Error("Expected directory structure information")
|
|
}
|
|
|
|
if len(analysis.Technologies) == 0 {
|
|
t.Log("No technologies detected (expected for simple test structure)")
|
|
}
|
|
}
|
|
|
|
// Benchmark tests for performance validation
|
|
func BenchmarkIntelligenceEngine_AnalyzeFile(b *testing.B) {
|
|
config := &EngineConfig{EnableRAG: false}
|
|
engine := NewIntelligenceEngine(config)
|
|
ctx := context.Background()
|
|
|
|
content := []byte(`
|
|
package main
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
)
|
|
|
|
func main() {
|
|
fmt.Println("Hello, World!")
|
|
}
|
|
|
|
func processData(data []string) error {
|
|
for _, item := range data {
|
|
if err := validateItem(item); err != nil {
|
|
return fmt.Errorf("validation failed: %w", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateItem(item string) error {
|
|
if len(item) == 0 {
|
|
return fmt.Errorf("empty item")
|
|
}
|
|
return nil
|
|
}
|
|
`)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := engine.AnalyzeFile(ctx, "test.go", content)
|
|
if err != nil {
|
|
b.Fatalf("AnalyzeFile failed: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkPatternDetector_DetectPatterns(b *testing.B) {
|
|
config := &EngineConfig{}
|
|
detector := NewDefaultPatternDetector(config)
|
|
ctx := context.Background()
|
|
|
|
content := []byte(`
|
|
package main
|
|
import "sync"
|
|
|
|
type Singleton struct {
|
|
value string
|
|
}
|
|
|
|
var instance *Singleton
|
|
var once sync.Once
|
|
|
|
func GetInstance() *Singleton {
|
|
once.Do(func() {
|
|
instance = &Singleton{value: "initialized"}
|
|
})
|
|
return instance
|
|
}
|
|
|
|
func NewUser(name string) *User {
|
|
return &User{Name: name}
|
|
}
|
|
|
|
func CreateDatabase() Database {
|
|
return &postgresDatabase{}
|
|
}
|
|
`)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := detector.DetectCodePatterns(ctx, "test.go", content)
|
|
if err != nil {
|
|
b.Fatalf("DetectCodePatterns failed: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkRoleAwareProcessor_ProcessForRole(b *testing.B) {
|
|
config := &EngineConfig{}
|
|
processor := NewRoleAwareProcessor(config)
|
|
ctx := context.Background()
|
|
|
|
testNode := &slurpContext.ContextNode{
|
|
Path: "/src/service.go",
|
|
Summary: "A service implementation",
|
|
Purpose: "Handles business logic",
|
|
Technologies: []string{"go", "postgresql"},
|
|
Tags: []string{"service", "database"},
|
|
Insights: []string{"Well structured code", "Good error handling"},
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := processor.ProcessContextForRole(ctx, testNode, "developer")
|
|
if err != nil {
|
|
b.Fatalf("ProcessContextForRole failed: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper functions for testing
|
|
|
|
func createTestContextNode(path, summary, purpose string, technologies, tags []string) *slurpContext.ContextNode {
|
|
return &slurpContext.ContextNode{
|
|
Path: path,
|
|
Summary: summary,
|
|
Purpose: purpose,
|
|
Technologies: technologies,
|
|
Tags: tags,
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
}
|
|
|
|
func createTestProjectGoal(id, name, description string, keywords []string, priority int, phase string) *ProjectGoal {
|
|
return &ProjectGoal{
|
|
ID: id,
|
|
Name: name,
|
|
Description: description,
|
|
Keywords: keywords,
|
|
Priority: priority,
|
|
Phase: phase,
|
|
CreatedAt: time.Now(),
|
|
}
|
|
}
|
|
|
|
func assertValidInsight(t *testing.T, insight *RoleSpecificInsight) {
|
|
if insight.ID == "" {
|
|
t.Error("Insight ID should not be empty")
|
|
}
|
|
if insight.RoleID == "" {
|
|
t.Error("Insight RoleID should not be empty")
|
|
}
|
|
if insight.Confidence <= 0 || insight.Confidence > 1 {
|
|
t.Errorf("Invalid confidence: %f", insight.Confidence)
|
|
}
|
|
if insight.Priority <= 0 {
|
|
t.Errorf("Invalid priority: %d", insight.Priority)
|
|
}
|
|
if insight.Content == "" {
|
|
t.Error("Insight content should not be empty")
|
|
}
|
|
}
|
|
|
|
func assertValidDimensionScore(t *testing.T, score *DimensionScore) {
|
|
if score.Dimension == "" {
|
|
t.Error("Dimension name should not be empty")
|
|
}
|
|
if score.Score < 0 || score.Score > 1 {
|
|
t.Errorf("Invalid dimension score: %f", score.Score)
|
|
}
|
|
if score.Confidence <= 0 || score.Confidence > 1 {
|
|
t.Errorf("Invalid confidence: %f", score.Confidence)
|
|
}
|
|
} |