Compare commits

..
1 Commits
Author SHA1 Message Date
TakshakRamteke 28acfd8d7e Merge pull request 'Merging into main' (#1) from dev into main
Reviewed-on: #1
2026-07-25 07:59:52 +00:00
7 changed files with 30 additions and 178 deletions
-6
View File
@@ -37,10 +37,6 @@ func Run() {
fmt.Println("Syntax error, could not parse statement") fmt.Println("Syntax error, could not parse statement")
case PrepareUnrecognised: case PrepareUnrecognised:
fmt.Printf("Unrecognised keyword at the start of '%s'.\n", inputBuffer.Buffer) fmt.Printf("Unrecognised keyword at the start of '%s'.\n", inputBuffer.Buffer)
case PrepareTooManyArgs:
fmt.Printf("Too many arguments in the insert statement '%v'\n", inputBuffer.Buffer)
case PrepareValueTooLong:
fmt.Printf("Values for either username or email are too long\n")
} }
switch statement.ExecuteStatement(table) { switch statement.ExecuteStatement(table) {
@@ -48,8 +44,6 @@ func Run() {
fmt.Println("Executed.") fmt.Println("Executed.")
case ExecuteTableFull: case ExecuteTableFull:
fmt.Println("Error: Table is full") fmt.Println("Error: Table is full")
case ExecuteFail:
//todo
} }
} }
-8
View File
@@ -1,8 +0,0 @@
package repl
// TODO
// in trying to implement unit test for Run we would kinda endup implementing a test which would be somewhat similar to
// e2e test which we already have in place under ../tests directory
// PrintConsole simply prints godb > to the console, so not sure if we would need a test for that
// Skipping unit test for this, while marking it as a TODO
+11 -45
View File
@@ -4,8 +4,6 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"os" "os"
"slices"
"strconv"
"strings" "strings"
. "godb/internals/buffer" . "godb/internals/buffer"
@@ -23,8 +21,6 @@ type PrepareResults int
const ( const (
PrepareSuccess PrepareResults = iota PrepareSuccess PrepareResults = iota
PrepareUnrecognised PrepareUnrecognised
PrepareTooManyArgs
PrepareValueTooLong
PrepareSyntaxError PrepareSyntaxError
) )
@@ -33,7 +29,6 @@ type statementType int
const ( const (
StatementSelect statementType = iota StatementSelect statementType = iota
StatementInsert StatementInsert
StatementUnrecognized
) )
const ( const (
@@ -57,7 +52,6 @@ type ExecuteResult int
const ( const (
ExecuteSuccess ExecuteResult = iota ExecuteSuccess ExecuteResult = iota
ExecuteTableFull ExecuteTableFull
ExecuteFail
) )
type row struct { type row struct {
@@ -77,8 +71,7 @@ type Table struct {
} }
func NewStatement() *Statement { func NewStatement() *Statement {
statement := &Statement{} return &Statement{0, row{0, "", ""}}
return statement
} }
func NewTable() *Table { func NewTable() *Table {
@@ -155,47 +148,20 @@ func DoMetaCommands(inputBuffer *InputBuffer) MetaCommandResults {
return metacommand return metacommand
} }
func (statement *Statement) perpareInsert(inputBuffer *InputBuffer) PrepareResults { func (statement *Statement) PrepareStatements(inputBuffer *InputBuffer) PrepareResults {
inputs := strings.Split(inputBuffer.Buffer, " ")[1:] if strings.HasPrefix(inputBuffer.Buffer, "insert") {
if len(inputs) < 3 { argsAssigned, err := fmt.Sscanf(inputBuffer.Buffer, "insert %d %s %s", &statement.row.id, &statement.row.username, &statement.row.email)
// if err != nil {
// fmt.Println("error parsing insert statement")
// fmt.Println(err.Error())
// }
if err != nil || argsAssigned > 3 {
return PrepareSyntaxError return PrepareSyntaxError
} }
if len(inputs) > 3 {
return PrepareTooManyArgs
}
if slices.Contains(inputs, "null") || slices.Contains(inputs, "NULL") || slices.Contains(inputs, "Null") || slices.Contains(inputs, " ") {
return PrepareSyntaxError
}
tid, err := strconv.ParseUint(inputs[0], 10, 0)
if err != nil {
// fmt.Printf("supplied ID: %v isn't acceptable, please correct and retry\n", inputs[0])
return PrepareSyntaxError
}
id := uint(tid)
if len(inputs[1]) > usernameSize {
// fmt.Printf("%v is too long for username\n", inputs[1])
return PrepareValueTooLong
}
if len(inputs[2]) > emailSize {
// fmt.Printf("%v is too long for email\n", inputs[2])
return PrepareValueTooLong
}
statement.row.id = id
statement.row.username = inputs[1]
statement.row.email = inputs[2]
statement.stype = StatementInsert statement.stype = StatementInsert
return PrepareSuccess return PrepareSuccess
}
func (statement *Statement) PrepareStatements(inputBuffer *InputBuffer) PrepareResults {
statement.stype = StatementUnrecognized
if strings.HasPrefix(inputBuffer.Buffer, "insert") {
return statement.perpareInsert(inputBuffer)
} }
if inputBuffer.Buffer == "select" { if strings.HasPrefix(inputBuffer.Buffer, "select") {
statement.stype = StatementSelect statement.stype = StatementSelect
return PrepareSuccess return PrepareSuccess
} }
@@ -203,7 +169,7 @@ func (statement *Statement) PrepareStatements(inputBuffer *InputBuffer) PrepareR
} }
func (statement *Statement) ExecuteStatement(table *Table) ExecuteResult { func (statement *Statement) ExecuteStatement(table *Table) ExecuteResult {
var result ExecuteResult = ExecuteFail var result ExecuteResult
switch statement.stype { switch statement.stype {
case StatementInsert: case StatementInsert:
result = statement.execInsert(table) result = statement.execInsert(table)
-54
View File
@@ -1,54 +0,0 @@
package vm
import (
"godb/internals/buffer"
"testing"
)
var inputBuffer = buffer.NewInputBuffer()
var statement = NewStatement()
func TestVM(t *testing.T) {
tests := []struct {
name string
input string
prepareStatusExpected PrepareResults
statementResultExpected statementType
}{
{
name: "Testing Select Statement",
input: "select",
prepareStatusExpected: PrepareSuccess,
statementResultExpected: StatementSelect,
},
{
name: "Testing Insert Statement",
input: "insert 0 hello hello.com",
prepareStatusExpected: PrepareSuccess,
statementResultExpected: StatementInsert,
},
{
name: "Testing Unrecognized Statement",
input: "something",
prepareStatusExpected: PrepareUnrecognised,
statementResultExpected: StatementUnrecognized,
},
{
name: "Testing Syntax Errors",
input: "insert 0 hello",
prepareStatusExpected: PrepareSyntaxError,
statementResultExpected: StatementUnrecognized,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
inputBuffer.Buffer = test.input
result := statement.PrepareStatements(inputBuffer)
if result != test.prepareStatusExpected && statement.stype == test.statementResultExpected {
t.Errorf("Expected prepareResult and stype to be: (%v, %v), got: (%v,%v)\n", test.prepareStatusExpected, test.statementResultExpected, result, statement.stype)
}
})
}
}
-6
View File
@@ -21,9 +21,3 @@ Start
Cleanup Cleanup
```make clean``` ```make clean```
Test
```make test```
-3
View File
@@ -1,3 +0,0 @@
package tests
// implement benchmark test for the main loop
+16 -53
View File
@@ -35,21 +35,15 @@ func runner(commands []string, t *testing.T) []string {
go func() { go func() {
defer stdin.Close() defer stdin.Close()
for _, c := range commands { for _, c := range commands {
_, err = io.WriteString(stdin, c+"\n") _, _ = io.WriteString(stdin, c+"\n")
if err != nil {
t.Errorf("Failed to execute %v because of %q\n", c, err)
break
}
} }
}() }()
reader := bufio.NewReader(stdout) reader := bufio.NewReader(stdout)
for { for {
// fmt.Printf("reading command outputs...\n")
line, err := reader.ReadString('\n') line, err := reader.ReadString('\n')
if line != "" { if line != "" {
formattedline := fmt.Sprintf("%v", strings.Trim(strings.ReplaceAll(line, "\x00", ""), "\n")) formattedline := fmt.Sprintf("%v", strings.Trim(strings.ReplaceAll(line, "\x00", ""), "\n"))
// fmt.Printf("formatting and appending result: %v\n", formattedline)
results = append(results, formattedline) results = append(results, formattedline)
} }
if err != nil { if err != nil {
@@ -66,57 +60,26 @@ func runner(commands []string, t *testing.T) []string {
return results return results
} }
func TestE2E(t *testing.T) { func TestMain(t *testing.T) {
tests := []struct { commands := []string{
name string "insert 1 user1 person1@example.com",
commands []string "select",
expected []string ".exit",
}{
{
name: "Test Main Loop",
commands: []string{"insert 1 user1 person1@example.com", "select", ".exit"},
expected: []string{"godb > Executed.", "godb > {1 user1 person1@example.com}", "Executed.", "godb > bye!"},
},
{
name: "Test Maximum Length For Values",
commands: []string{"insert 0 " + strings.Repeat("n", 32) + " " + strings.Repeat("n", 255), ".exit"},
expected: []string{"godb > Executed.", "godb > bye!"},
},
{
name: "Test Over Maximum Length For Values",
commands: []string{"insert 0 " + strings.Repeat("n", 42) + " " + strings.Repeat("n", 275), ".exit"},
expected: []string{"godb > Values for either username or email are too long", "godb > bye!"},
},
} }
for _, test := range tests { expected := []string{
t.Run(test.name, func(t *testing.T) { "godb > Executed.",
results := runner(test.commands, t) "godb > {1 user1 person1@example.com}",
"Executed.",
"godb > bye!",
}
results := runner(commands, t)
for i := range results { for i := range results {
results[i] = strings.ReplaceAll(results[i], "\n", "") results[i] = strings.ReplaceAll(results[i], "\n", "")
} }
if !slices.Equal(test.expected, results) { if !slices.Equal(expected, results) {
t.Errorf("Output Mismatch\nExpected: %v\nGot: %v\n", test.expected, results) t.Errorf("Output Mismatch\nExpected: %v\nGot: %v\n", expected, results)
}
})
}
}
func TestTableFull(t *testing.T) {
maxRows := 1400
commands := make([]string, 0)
for i := range maxRows {
c := fmt.Sprintf("insert %d user%d person%d@example.com", i, i, i)
commands = append(commands, c)
}
commands = append(commands, ".exit")
results := runner(commands, t)
if results[1300] != "godb > Error: Table is full" {
t.Errorf("Our Tables max capacity is 1300 rows, but we're able to insert %v\n", len(results))
} }
} }