From ece18eddf67a67a4f200cef50b8765e5b51e7f43 Mon Sep 17 00:00:00 2001 From: ammar68 <ammaa@stud.ntnu.no> Date: Tue, 29 Oct 2024 12:19:18 +0100 Subject: [PATCH] all modules connected (except database) --- behavior-testing/go.mod | 3 + behavior-testing/main.go | 100 ++++++++++++++++++ llama/compiler/compiler.go | 10 -- llama/go_compiler/go_compiler.go | 91 ++++++++++++++++ llama/go_compiler/go_compiler_test.go | 59 +++++++++++ llama/go_compiler/should_compile | 7 ++ .../go_compiler/should_compile_and_run_tests | 48 +++++++++ .../should_compile_with_external_dependencies | 37 +++++++ .../should_compile_with_faulty_test | 39 +++++++ ...compile_with_standard_library_dependencies | 19 ++++ llama/go_compiler/should_not_compile | 8 ++ llama/main.go | 10 +- 12 files changed, 416 insertions(+), 15 deletions(-) create mode 100644 behavior-testing/go.mod create mode 100644 behavior-testing/main.go delete mode 100644 llama/compiler/compiler.go create mode 100644 llama/go_compiler/go_compiler.go create mode 100644 llama/go_compiler/go_compiler_test.go create mode 100644 llama/go_compiler/should_compile create mode 100644 llama/go_compiler/should_compile_and_run_tests create mode 100644 llama/go_compiler/should_compile_with_external_dependencies create mode 100644 llama/go_compiler/should_compile_with_faulty_test create mode 100644 llama/go_compiler/should_compile_with_standard_library_dependencies create mode 100644 llama/go_compiler/should_not_compile diff --git a/behavior-testing/go.mod b/behavior-testing/go.mod new file mode 100644 index 0000000..400bb0a --- /dev/null +++ b/behavior-testing/go.mod @@ -0,0 +1,3 @@ +module behavior-testing + +go 1.23.1 diff --git a/behavior-testing/main.go b/behavior-testing/main.go new file mode 100644 index 0000000..5f5b1a4 --- /dev/null +++ b/behavior-testing/main.go @@ -0,0 +1,100 @@ +package main + +import ( + "fmt" + "testing" +) + +type NumberGenerator interface { + generateEvenNumbers() []int +} + +type EvenNumber struct{} + +func (e *EvenNumber) generateEvenNumbers() []int { + evenNumbers := make([]int, 5) + for i := 0; i < 5; i++ { + evenNumbers[i] = 2 * (i + 1) + } + return evenNumbers +} + +type TestNumberGenerator struct{} + +func (t *TestNumberGenerator) generateEvenNumbers() []int { + evenNumbers := make([]int, 10) + for i := 0; i < 5; i++ { + evenNumbers[i] = 2 * (i + 1) + } + return evenNumbers +} + +type BrokenNumberGenerator struct{} + +func (b *BrokenNumberGenerator) generateEvenNumbers() []int { + // This function will not generate even numbers but it won't panic either + return make([]int, 0) +} + +func main() { + evenNumber := &EvenNumber{} + generatedNumbers := evenNumber.generateEvenNumbers() + fmt.Println(generatedNumbers) + + brokenNumberGenerator := &BrokenNumberGenerator{} + generatedNumbers = brokenNumberGenerator.generateEvenNumbers() + fmt.Println(generatedNumbers) + + testNumberGenerator := &TestNumberGenerator{} + generatedNumbers = testNumberGenerator.generateEvenNumbers() + fmt.Println(generatedNumbers) +} + +func TestGenerateEvenNumbers(t *testing.T) { + evenNumber := &EvenNumber{} + generatedNumbers := evenNumber.generateEvenNumbers() + + if len(generatedNumbers) != 5 { + t.Errorf("Expected 5 numbers but got %d", len(generatedNumbers)) + } + for _, number := range generatedNumbers { + if number%2 == 1 { + t.Errorf("Expected all numbers to be even but got an odd number: %d", number) + } + } + + testNumberGenerator := &TestNumberGenerator{} + generatedNumbers = testNumberGenerator.generateEvenNumbers() + if len(generatedNumbers) != 10 { + t.Errorf("Expected 10 numbers but got %d", len(generatedNumbers)) + } + for _, number := range generatedNumbers[:5] { + if number%2 == 1 { + t.Errorf("Expected all first 5 numbers to be even but got an odd number: %d", number) + } + } + + brokenNumberGenerator := &BrokenNumberGenerator{} + generatedNumbers = brokenNumberGenerator.generateEvenNumbers() + if len(generatedNumbers) != 0 { + t.Errorf("Expected zero numbers but got %d", len(generatedNumbers)) + } +} + +func TestGenerateEvenNumbersSize(t *testing.T) { + evenNumber := &EvenNumber{} + generatedNumbers := evenNumber.generateEvenNumbers() + + if len(generatedNumbers) == 5 && generatedNumbers[4] != 10 { + t.Errorf("Expected last number to be 10 but got %d", generatedNumbers[4]) + } +} + +func TestGenerateEvenNumbersBroken(t *testing.T) { + brokenNumberGenerator := &BrokenNumberGenerator{} + generatedNumbers := brokenNumberGenerator.generateEvenNumbers() + + if len(generatedNumbers) != 0 { + t.Errorf("Expected zero numbers but got %d", len(generatedNumbers)) + } +} \ No newline at end of file diff --git a/llama/compiler/compiler.go b/llama/compiler/compiler.go deleted file mode 100644 index 41da418..0000000 --- a/llama/compiler/compiler.go +++ /dev/null @@ -1,10 +0,0 @@ -package compiler - -// CompileStringToGo tries to compile a string of go code to a go executable, and returns the compiler output and an error. -// The function does not produce any executables, since they are deleted after the function ends. -func CompileStringToGo(code string) (string, error) { - - var output string = "" - // SetupEnvironment - return output, nil -} diff --git a/llama/go_compiler/go_compiler.go b/llama/go_compiler/go_compiler.go new file mode 100644 index 0000000..c9de3d7 --- /dev/null +++ b/llama/go_compiler/go_compiler.go @@ -0,0 +1,91 @@ +package go_compiler + +import ( + "os" + "os/exec" + "runtime" +) + +const TempOutputDir = "tempOutput/" +const fileName = "main.go" + +type GoCompiler struct{} + +// NewGoCompiler creates a new GoCompiler +func NewGoCompiler() *GoCompiler { + return &GoCompiler{} +} + +// OS Operating system type +type OS = string + +// Platform enums +const ( + Windows OS = "windows" + Linux OS = "linux" + MacOS OS = "darwin" +) + + +// MakeCommand creates a command based on the runtime platform +func MakeCommand(cmd string) *exec.Cmd { + platform := runtime.GOOS + switch platform { + case Windows: + return exec.Command("cmd", "/c", cmd) + case Linux, MacOS: + return exec.Command("bash", "-c", cmd) + default: + panic("Unsupported platform") + } +} + +// SetupTempFolders creates the temp output directory for compiled files, panics if it fails +func SetupTempFolders(tempOutputDir string) { + // 0777 are the permissions for the directory, everyone can read, write and execute + err := os.MkdirAll(tempOutputDir, os.ModePerm) + if err != nil { + panic("Error creating temp output directory:\n\n" + err.Error()) + } +} + +// RemoveTempFolders removes the temp output directory for compiled files, panics if it fails +func RemoveTempFolders(tempOutputDir string) { + err := os.RemoveAll(tempOutputDir) + if err != nil { + panic("Error removing temp output directory:\n\n" + err.Error()) + } +} + + + +// CheckCompileErrors takes Go source code and checks for compile errors. +// +// The dependencies are handled automatically by go mod and go tidy. +// +// NOTE: Make sure you have an up-to-date Go installed on the system +// +// Returns the output of the compilation and an error if any +func (gb *GoCompiler) CheckCompileErrors(srcCode []byte) ([]byte, error) { + // Make temp folders + SetupTempFolders(TempOutputDir) + defer RemoveTempFolders(TempOutputDir) + + // Write code to file + err := os.WriteFile(TempOutputDir+fileName, srcCode, 0644) + if err != nil { + return nil, err + } + // Init go mod and tidy + cmdString := "go mod init tempOutput && go mod tidy " + + // Run go build + cmdString += " && go build -o main " + fileName + + // Run tests + cmdString += " && go test " + fileName + + cmd := MakeCommand(cmdString) + cmd.Dir = TempOutputDir + return cmd.CombinedOutput() +} diff --git a/llama/go_compiler/go_compiler_test.go b/llama/go_compiler/go_compiler_test.go new file mode 100644 index 0000000..eef1365 --- /dev/null +++ b/llama/go_compiler/go_compiler_test.go @@ -0,0 +1,59 @@ +package go_compiler + +import ( + "os" + "testing" +) + +func TestCompileStringToGo(t *testing.T) { + + tests := []struct { + filename string + shouldCompile bool + }{ + { + filename: "should_compile", + shouldCompile: true, + }, + { + filename: "should_not_compile", + shouldCompile: false, + }, + { + filename: "should_compile_with_standard_library_dependencies", + shouldCompile: true, + }, + { + filename: "should_compile_with_external_dependencies", + shouldCompile: true, + }, + { + filename: "should_compile_and_run_tests", + shouldCompile: true, + }, + { + filename: "should_compile_with_faulty_test", + shouldCompile: true, + }, + } + + for _, test := range tests { + t.Run(test.filename, func(t *testing.T) { + // Read the code from the file + code, err := os.ReadFile(test.filename) + + output, err := NewGoCompiler().CheckCompileErrors(code) + + if err != nil && test.shouldCompile { + t.Errorf("Expected the code to compile, but got an output: %v \n error: %v", string(output), err) + } else if err == nil && !test.shouldCompile { + t.Errorf("Expected the code to not compile, but got no error") + } + + // Check if the output is empty when the code shouldn't compile + if output == nil && !test.shouldCompile { + t.Errorf("Expected compiler error output, but got none") + } + }) + } +} diff --git a/llama/go_compiler/should_compile b/llama/go_compiler/should_compile new file mode 100644 index 0000000..2d35af1 --- /dev/null +++ b/llama/go_compiler/should_compile @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("Hello, World!") +} \ No newline at end of file diff --git a/llama/go_compiler/should_compile_and_run_tests b/llama/go_compiler/should_compile_and_run_tests new file mode 100644 index 0000000..32c15ee --- /dev/null +++ b/llama/go_compiler/should_compile_and_run_tests @@ -0,0 +1,48 @@ +package main + +import ( + "errors" + "fmt" + "testing" +) + +// Divide divides two numbers and returns the result. +// Returns an error if division by zero is attempted. +func Divide(a, b float64) (float64, error) { + if b == 0 { + return 0, errors.New("cannot divide by zero") + } + return a / b, nil +} + +// Test cases for Divide function +func TestDivide(t *testing.T) { + // Test case 1: Normal division + result, err := Divide(10, 2) + if err != nil || result != 5 { + t.Errorf("Expected 5, got %v, error: %v", result, err) + } + + // Test case 2: Division by zero + _, err = Divide(10, 0) + if err == nil { + t.Error("Expected error for division by zero, got nil") + } + + // Test case 3: Division with negative numbers + result, err = Divide(-10, 2) + if err != nil || result != -5 { + t.Errorf("Expected -5, got %v, error: %v", result, err) + } +} + +// main function for demonstration purposes +func main() { + a, b := 10.0, 2.0 + result, err := Divide(a, b) + if err != nil { + fmt.Println("Error:", err) + } else { + fmt.Printf("Result of %.2f / %.2f = %.2f\n", a, b, result) + } +} diff --git a/llama/go_compiler/should_compile_with_external_dependencies b/llama/go_compiler/should_compile_with_external_dependencies new file mode 100644 index 0000000..3a047ae --- /dev/null +++ b/llama/go_compiler/should_compile_with_external_dependencies @@ -0,0 +1,37 @@ +// These are dependencies that are **NOT** part of the standard library +package main + +import ( + "fmt" + "golang.org/x/net/http2" + "golang.org/x/crypto/bcrypt" + "net/http" +) + +func main() { + // Setting up a simple HTTP/2 server + srv := &http.Server{ + Addr: ":8080", + } + + // Register a simple handler + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + // Hashing a password + password := "mysecretpassword" + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + http.Error(w, "Could not hash password", http.StatusInternalServerError) + return + } + fmt.Fprintf(w, "Hashed Password: %s\n", hashedPassword) + }) + + // Enable HTTP/2 + http2.ConfigureServer(srv, nil) + + // Start the server + fmt.Println("Starting server on https://localhost:8080") + if err := srv.ListenAndServeTLS("server.crt", "server.key"); err != nil { + fmt.Println("Error starting server:", err) + } +} diff --git a/llama/go_compiler/should_compile_with_faulty_test b/llama/go_compiler/should_compile_with_faulty_test new file mode 100644 index 0000000..a988911 --- /dev/null +++ b/llama/go_compiler/should_compile_with_faulty_test @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "testing" +) + +// Add adds two integers and returns the result. +func Add(a, b int) int { + return a + b +} + +// Test cases for Add function +func TestAdd(t *testing.T) { + // Test case 1: Normal addition + result := Add(2, 3) + if result != 5 { + t.Errorf("Expected 5, got %v", result) + } + + // Faulty Test case 2: Incorrect expected result + result = Add(2, 2) + if result != 5 { // This is faulty, it should expect 4, not 5 + t.Errorf("Expected 5, got %v", result) + } + + // Test case 3: Adding negative numbers + result = Add(-2, -3) + if result != -5 { + t.Errorf("Expected -5, got %v", result) + } +} + +// main function for demonstration purposes +func main() { + a, b := 2, 3 + result := Add(a, b) + fmt.Printf("Result of %d + %d = %d\n", a, b, result) +} diff --git a/llama/go_compiler/should_compile_with_standard_library_dependencies b/llama/go_compiler/should_compile_with_standard_library_dependencies new file mode 100644 index 0000000..7134eea --- /dev/null +++ b/llama/go_compiler/should_compile_with_standard_library_dependencies @@ -0,0 +1,19 @@ +// These are dependencies that are part of the standard library +package main + +import ( + "fmt" + "math/rand" + "time" +) + +func main() { + // Seed the random number generator + rand.Seed(time.Now().UnixNano()) + + // Generate a random number between 1 and 100 + randomNum := rand.Intn(100) + 1 // rand.Intn(100) generates a number from 0 to 99 + + // Print the random number + fmt.Println("Random Number:", randomNum) +} \ No newline at end of file diff --git a/llama/go_compiler/should_not_compile b/llama/go_compiler/should_not_compile new file mode 100644 index 0000000..8c5b2be --- /dev/null +++ b/llama/go_compiler/should_not_compile @@ -0,0 +1,8 @@ +package main + +import "fmt" + +func main() { + fmt.Println("Hello, World!") + } +} \ No newline at end of file diff --git a/llama/main.go b/llama/main.go index 7e2b774..742d82f 100644 --- a/llama/main.go +++ b/llama/main.go @@ -3,9 +3,9 @@ package main import ( "bufio" "fmt" - "llama/compiler" displayindicator "llama/display-indicator" "llama/extraction" + "llama/go_compiler" ollamaimplementation "llama/ollama-implementation" "os" "strings" @@ -58,14 +58,14 @@ func main() { fmt.Println("Ollama's response:", generatedCode) - output, err := compiler.CompileStringToGo(generatedCode) + output, err := go_compiler.NewGoCompiler().CheckCompileErrors([]byte(generatedCode)) if err != nil { - userPrompt = output + "\nFollowing are the errors, please fix the code. Write it again, and write only source code along with same test cases with no further explanation. The format should be ```rust <yourcode + testcases> ```" + fmt.Printf("The code did not compile and contains the following errors: %v\n", string(output)) + userPrompt = "Following are the errors, please fix the code. Write it again, and write only source code along with same test cases with no further explanation. The format should be ```rust <yourcode + testcases> ``` :\n" + string(output) } else { - fmt.Printf("Compiled successfully. Here is the output: %v", output) + fmt.Printf("Compiled successfully. Here is the output: %v", string(output)) userPrompt = "exit" } - } } -- GitLab