Browse Source

Provided tests for functions that can be tested (Closes #20).

Sacha Ligthert 1 year ago
parent
commit
c1f2a28ac1

+ 1 - 1
README.md

@@ -62,7 +62,7 @@ For a long running (~1 hours 15 minutes) example:
 
 The outpot (of the short running parameters) will look something like this:
 ```
-./sudoku-funpark -row1 769104802 -row2 154800060 -row3 832700154 -row4 600900328 -row5 045328670 -row6 328670945 -row7 597410280 -row8 006283090 -row9 200590006 
+./sudoku-funpark -row1 769104802 -row2 154800060 -row3 832700154 -row4 600900328 -row5 045328670 -row6 328670945 -row7 597410280 -row8 006283090 -row9 200590006
 Loading blocks... Done! (38.957376ms)
 Populating blocks... Done! (92.087174ms)
 Number of (potential) solutions: 26542080

+ 90 - 0
export/Export_test.go

@@ -0,0 +1,90 @@
+package export
+
+import (
+	"testing"
+
+	"gitea.ligthert.net/golang/sudoku-funpark/controller"
+	"gitea.ligthert.net/golang/sudoku-funpark/outputter"
+)
+
+// This function will test the Export function.
+// Starts off by creating all the structs and intefaces needed.
+// Set all the needed values.
+// Execute the Export function.
+// Check if the output is a string.
+// Check if the output for "human" "flat" and "json" are valid.
+func TestExport(t *testing.T) {
+
+	// Create a new Export struct.
+	export := Export{}
+
+	// Create a new outputter struct.
+	outp := outputter.Outputter{}
+
+	// Set output type to "short".
+	outp.OutputType = "short"
+
+	// Create a new Controller struct and set the outputter.
+	controller := controller.Controller{Outputter: &outp}
+
+	// Set the Controller in the Export struct.
+	export.Controller = &controller
+
+	// Populate the Solutions slice.
+	controller.Solutions = append(controller.Solutions, []string{"123456789", "987654321", "123456789", "987654321", "123456789", "987654321", "123456789", "987654321", "123456789"})
+
+	// Set output type to "human".
+	controller.Output = "human"
+
+	// Execute the Export function.
+	render := export.Export()
+
+	// Check if the output is a string and not empty.
+	if render == "" {
+		t.Error("Expected a non-empty string, string was empty")
+	}
+
+	// Set the expected variable.
+	expected := "\nSolution #1:\n╔═══════════╗\n║123│456│789╢\n║987│654│321╢\n║123│456│789╢\n╟───┼───┼───╢\n║987│654│321╢\n║123│456│789╢\n║987│654│321╢\n╟───┼───┼───╢\n║123│456│789╢\n║987│654│321╢\n║123│456│789╢\n╚═══════════╝\n"
+
+	// Check if the output is the same as the expected variable.
+	if render != expected {
+		t.Error("Expected a ", expected, ", got", render)
+	}
+
+	// Set output type to "flat".
+	controller.Output = "flat"
+
+	// Execute the Export function.
+	render = export.Export()
+
+	// Check if the output for "flat" is non-empty.
+	if render == "" {
+		t.Error("Expected a non-empty string, string was empty")
+	}
+
+	expected = "\nSolution #1:\n[123456789 987654321 123456789 987654321 123456789 987654321 123456789 987654321 123456789]\n"
+
+	if render != expected {
+		t.Error("Expected a ", expected, ", got", render)
+	}
+
+	// Set output type to "json".
+	controller.Output = "json"
+
+	// Execute the Export function.
+	render = export.Export()
+
+	// Check if the output for "json" is valid.
+	if render == "" {
+		t.Error("Expected a non-empty string, got empty string")
+	}
+
+	// Set the expected variable.
+	expected = "[{\"order\":0,\"row1\":\"123456789\",\"row2\":\"987654321\",\"row3\":\"123456789\",\"row4\":\"987654321\",\"row5\":\"123456789\",\"row6\":\"987654321\",\"row7\":\"123456789\",\"row8\":\"987654321\",\"row9\":\"123456789\"}]"
+
+	// Check if what is rendered is the same as the expected variable.
+	if render != expected {
+		t.Error("Expected a ", expected, ", got", render)
+	}
+}

+ 39 - 0
export/renderFlat_test.go

@@ -0,0 +1,39 @@
+package export
+
+import (
+	"testing"
+
+	"gitea.ligthert.net/golang/sudoku-funpark/controller"
+	"gitea.ligthert.net/golang/sudoku-funpark/outputter"
+)
+
+// This function will test the renderFlat function.
+// Then it will execute the renderFlat function.
+// Check if the output is a string.
+func TestRenderFlat(t *testing.T) {
+
+	// Create a new Export struct.
+	export := Export{}
+
+	// Create a new Controller struct.
+	// Set output type to "human".
+	outp := outputter.Outputter{}
+	outp.OutputType = "short"
+	controller := controller.Controller{Outputter: &outp}
+	export.Controller = &controller
+	controller.Solutions = append(controller.Solutions, []string{"123456789", "987654321", "123456789", "987654321", "123456789", "987654321", "123456789", "987654321", "123456789"})
+
+	// Execute the renderFlat function.
+	render := export.renderFlat()
+
+	// Check if the output is a string and not empty.
+	if render == "" {
+		t.Error("Expected a non-empty string, got", render)
+	}
+
+	// Check if the output is a string.
+	if render != "\nSolution #1:\n[123456789 987654321 123456789 987654321 123456789 987654321 123456789 987654321 123456789]\n" {
+		t.Error("Expected a string, got", render)
+	}
+
+}

+ 45 - 0
export/renderHumanReadable_test.go

@@ -0,0 +1,45 @@
+package export
+
+import (
+	"strings"
+	"testing"
+
+	"gitea.ligthert.net/golang/sudoku-funpark/controller"
+	"gitea.ligthert.net/golang/sudoku-funpark/outputter"
+)
+
+// This function will test the renderHumanReadable function.
+// Starts off by creating a new Export struct.
+// Creates a new Controller struct.
+// Adds a solution to the Controller struct.
+// Then it will execute the renderHumanReadable function.
+// Check if the output is a string.
+func TestRenderHumanReadable(t *testing.T) {
+
+	// Create a new Export struct.
+	export := Export{}
+
+	// Create a new Controller struct.
+	// Set output type to "human".
+	outp := outputter.Outputter{}
+	outp.OutputType = "short"
+	controller := controller.Controller{Outputter: &outp}
+	export.Controller = &controller
+	controller.Solutions = append(controller.Solutions, []string{"123456789", "987654321", "123456789", "987654321", "123456789", "987654321", "123456789", "987654321", "123456789"})
+
+	// Execute the renderHumanReadable function.
+	render := export.renderHumanReadable()
+
+	expected := "\nSolution #1:\n╔═══════════╗\n║123│456│789╢\n║987│654│321╢\n║123│456│789╢\n╟───┼───┼───╢\n║987│654│321╢\n║123│456│789╢\n║987│654│321╢\n╟───┼───┼───╢\n║123│456│789╢\n║987│654│321╢\n║123│456│789╢\n╚═══════════╝\n"
+
+	// Check if the output is a string and not empty.
+	if render == "" {
+		t.Error("Expected a non-empty string, got", render)
+	}
+
+	// Check if the output is a string.
+	if strings.TrimSpace(render) != strings.TrimSpace(expected) {
+		t.Error("Expected a string, got", render)
+	}
+
+}

+ 54 - 0
export/renderJSON_test.go

@@ -0,0 +1,54 @@
+package export
+
+import (
+	"encoding/json"
+	"testing"
+
+	"gitea.ligthert.net/golang/sudoku-funpark/controller"
+	"gitea.ligthert.net/golang/sudoku-funpark/outputter"
+)
+
+// This function will test the renderJSON function.
+// Starts off by creating a new Export struct.
+// Creates a new Controller struct.
+// Adds a solution to the Controller struct.
+// Then it will execute the renderJSON function.
+// Check if the output is a JSON string.
+func TestRenderJSON(t *testing.T) {
+
+	// Create a new Export struct.
+	export := Export{}
+	outp := outputter.Outputter{}
+	outp.OutputType = "short"
+	export.Controller = &controller.Controller{Outputter: &outp}
+
+	// Create a new Controller struct.
+	controller := controller.Controller{}
+	controller.Solutions = append(controller.Solutions, []string{"123456789", "987654321", "123456789", "987654321", "123456789", "987654321", "123456789", "987654321", "123456789"})
+
+	// Add a solution to the Controller struct.
+	export.Controller = &controller
+
+	// Execute the renderJSON function.
+	render := export.renderJSON()
+
+	// Check if the output is a JSON string and not empty.
+	if render == "" {
+		t.Error("Expected a non-empty JSON string, got", render)
+	}
+
+	// Check if the output is a JSON string.\
+	if render != "[{\"order\":0,\"row1\":\"123456789\",\"row2\":\"987654321\",\"row3\":\"123456789\",\"row4\":\"987654321\",\"row5\":\"123456789\",\"row6\":\"987654321\",\"row7\":\"123456789\",\"row8\":\"987654321\",\"row9\":\"123456789\"}]" {
+		t.Error("Expected a JSON string, got", render)
+	}
+
+	// Check if the outpt is a valid JSON string.
+	// Check using the json.Unmarshal function.
+	// If the output is not a valid JSON string, the Unmarshal function will throw an error.
+	var result []map[string]interface{}
+	err := json.Unmarshal([]byte(render), &result)
+	if err != nil {
+		t.Error("Expected a valid JSON string, got", render)
+	}
+
+}

+ 39 - 0
flags/validChar_test.go

@@ -0,0 +1,39 @@
+package flags
+
+import "testing"
+
+func TestValidChar(t *testing.T) {
+	tests := []struct {
+		name  string
+		char  rune
+		valid bool
+	}{
+		{
+			name:  "Valid char",
+			char:  '1',
+			valid: true,
+		},
+		{
+			name:  "Invalid char",
+			char:  'a',
+			valid: false,
+		},
+		{
+			name:  "Valid char but not relevant",
+			char:  '0',
+			valid: true,
+		},
+	}
+
+	flags := Flags{}
+
+	// Run tests
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := flags.validChar(tt.char); got != tt.valid {
+				t.Errorf("validChar() = %v, want %v", got, tt.valid)
+			}
+		})
+	}
+
+}

+ 40 - 0
solver/LoadBlocks_test.go

@@ -0,0 +1,40 @@
+package solver
+
+import (
+	"testing"
+
+	"gitea.ligthert.net/golang/sudoku-funpark/controller"
+	"gitea.ligthert.net/golang/sudoku-funpark/outputter"
+)
+
+// This function will test the loadBlocks function.
+// Starts off by creating a new Solver struct.
+// Then it will execute the loadBlocks function.
+// Check if there are 9! blocks loaded.
+// Check if the first block is "123456789".
+// check if the last block is "987654321".
+func TestLoadBlocks(t *testing.T) {
+
+	// Do all the necesarry steps to initialize the solver.
+	solver := Solver{}
+	outp := outputter.Outputter{}
+	outp.OutputType = "short"
+	solver.Outp = &outp
+	controller := controller.Controller{}
+	solver.Controller = &controller
+	solver.LoadBlocks()
+
+	// Check if there are 9! blocks loaded.
+	if len(solver.Controller.Blocks) != 362880 {
+		t.Error("Expected 362880, got", len(solver.Controller.Blocks))
+	}
+	// Check if the first block is "123456789".
+	if solver.Controller.Blocks[0] != "123456789" {
+		t.Error("Expected 123456789, got", solver.Controller.Blocks[0])
+	}
+	// Check if the last block is "987654321".
+	if solver.Controller.Blocks[362879] != "987654321" {
+		t.Error("Expected 987654321, got", solver.Controller.Blocks[362879])
+	}
+
+}

+ 90 - 0
solver/PopulateBlocks_test.go

@@ -0,0 +1,90 @@
+package solver
+
+import (
+	"slices"
+	"testing"
+
+	"gitea.ligthert.net/golang/sudoku-funpark/controller"
+	"gitea.ligthert.net/golang/sudoku-funpark/outputter"
+)
+
+// This functions tests the PopulateBlocks function.
+// It does this by creating a small set of rows and then
+// calling the PopulateBlocks function. It then checks
+// if the number of blocks is as expected.
+func TestPopulateBlocks(t *testing.T) {
+	// Do all the necesarry steps to initialize the solver.
+	solver := Solver{}
+	outp := outputter.Outputter{}
+	outp.OutputType = "short"
+	solver.Outp = &outp
+	controller := controller.Controller{}
+	solver.Controller = &controller
+	solver.LoadBlocks()
+
+	// Create a set of rows
+	// Using the following values: [769154832 154832769 832769154 671945328 945328671 328671945 597416283 416283597 283597416]
+	solver.Controller.Row1 = "769154800"
+	solver.Controller.Row2 = "154832700"
+	solver.Controller.Row3 = "832769100"
+	solver.Controller.Row4 = "671945300"
+	solver.Controller.Row5 = "945328600"
+	solver.Controller.Row6 = "328671900"
+	solver.Controller.Row7 = "597416200"
+	solver.Controller.Row8 = "416283500"
+	solver.Controller.Row9 = "283597400"
+
+	// Call the PopulateBlocks function
+	solver.PopulateBlocks()
+
+	// Check if the number of blocks is as expected
+	if solver.Iter != 512 {
+		t.Errorf("Expected 19683 blocks, got %d", solver.Iter)
+	}
+
+	// Check if solver.row1s is as expected
+	if slices.Compare(solver.row1s, []string{"769154823", "769154832"}) != 0 {
+		t.Errorf("Expected [769154832, 769154823], got %s", solver.row1s)
+	}
+
+	// check if solver.row2s is as expected
+	if slices.Compare(solver.row2s, []string{"154832769", "154832796"}) != 0 {
+		t.Errorf("Expected [154832769, 154832796], got %s", solver.row2s)
+	}
+
+	// check if solver.row3s is as expected
+	if slices.Compare(solver.row3s, []string{"832769145", "832769154"}) != 0 {
+		t.Errorf("Expected [832769154, 832769145], got %s", solver.row3s)
+	}
+
+	// check if solver.row4s is as expected
+	if slices.Compare(solver.row4s, []string{"671945328", "671945382"}) != 0 {
+		t.Errorf("Expected [671945328, 671945382], got %s", solver.row4s)
+	}
+
+	// check if solver.row5s is as expected
+	if slices.Compare(solver.row5s, []string{"945328617", "945328671"}) != 0 {
+		t.Errorf("Expected [945328617, 945328671], got %s", solver.row5s)
+	}
+
+	// check if solver.row6s is as expected
+	if slices.Compare(solver.row6s, []string{"328671945", "328671954"}) != 0 {
+		t.Errorf("Expected [328671945, 328671954], got %s", solver.row6s)
+	}
+
+	// check if solver.row7s is as expected
+	if slices.Compare(solver.row7s, []string{"597416238", "597416283"}) != 0 {
+		t.Errorf("Expected [597416238, 597416283], got %s", solver.row7s)
+	}
+
+	// check if solver.row8s is as expected
+	if slices.Compare(solver.row8s, []string{"416283579", "416283597"}) != 0 {
+		t.Errorf("Expected [416283579, 416283597], got %s", solver.row8s)
+	}
+
+	// check if solver.row9s is as expected
+	if slices.Compare(solver.row9s, []string{"283597416", "283597461"}) != 0 {
+		t.Errorf("Expected [283597416, 283597461], got %s", solver.row9s)
+	}
+
+}

+ 33 - 0
solver/calcAVG_test.go

@@ -0,0 +1,33 @@
+package solver
+
+import (
+	"testing"
+)
+
+// Test the calcAVG function.
+func TestCalcAVG(t *testing.T) {
+
+	// Create a new Solver struct.
+	solver := Solver{}
+	// Populate the solver.rates[] slice with some values and check if the average is calculated correctly.
+	solver.rates = []uint64{1, 2, 3, 4, 5}
+	if solver.calcAVG() != 3 {
+		t.Error("Expected 3, got", solver.calcAVG())
+	}
+	// Populate the solver.Rate[] slice with some values and check if the average is calculated correctly.
+	solver.rates = []uint64{1, 2, 3, 4, 5, 6}
+	if solver.calcAVG() != 3 {
+		t.Error("Expected 3, got", solver.calcAVG())
+	}
+	// Populate the solver.Rate[] slice with some values and check if the average is calculated correctly.
+	solver.rates = []uint64{1, 2, 3, 4, 5, 6, 7}
+	if solver.calcAVG() != 4 {
+		t.Error("Expected 4, got", solver.calcAVG())
+	}
+	// Populate the solver.Rate[] slice with some values and check if the average is calculated correctly.
+	solver.rates = []uint64{1, 2, 3, 4, 5, 6, 7, 8}
+	if solver.calcAVG() != 4 {
+		t.Error("Expected 4, got", solver.calcAVG())
+	}
+
+}

+ 53 - 0
solver/findBlocks_test.go

@@ -0,0 +1,53 @@
+package solver
+
+import (
+	"slices"
+	"testing"
+
+	"gitea.ligthert.net/golang/sudoku-funpark/controller"
+	"gitea.ligthert.net/golang/sudoku-funpark/outputter"
+)
+
+// TestfindBlocks tests the findBlocks function.
+// It defines the solver struct
+// and calls the findBlocks function with a row and a slice of rows.
+// It then checks if the slice of rows is as expected.
+func TestFindBlocks(t *testing.T) {
+
+	// Create a new Solver struct.
+	solver := Solver{}
+
+	// Create outputter struct.
+	outp := outputter.Outputter{}
+
+	// Set the output type to human.
+	outp.OutputType = "human"
+
+	// Set the outputter of the solver to the outputter.
+	solver.Outp = &outp
+
+	// Create a controller struct.
+	controller := controller.Controller{}
+
+	// Set the controller of the solver to the controller.
+	solver.Controller = &controller
+
+	// Execute the loadBlocks function.
+	solver.LoadBlocks()
+
+	// Provide controller.row1 with a value.
+	// This is the row that will be used in the findBlocks function.
+	controller.Row1 = "769104802"
+
+	// Call the findBlocks function with the row and the slice of rows.
+	solver.findBlocks(&controller.Row1, &solver.row1s)
+
+	// A slice with the expected results.
+	expected := []string{"769154832", "769134852"}
+
+	// Check if the slice of rows1 is same as expected variable.
+	if slices.Equal(solver.row1s, expected) {
+		t.Errorf("Expected %v, got %v", expected, solver.row1s)
+	}
+
+}

+ 72 - 0
solver/setWorkload_test.go

@@ -0,0 +1,72 @@
+package solver
+
+import (
+	"testing"
+
+	"gitea.ligthert.net/golang/sudoku-funpark/controller"
+	"gitea.ligthert.net/golang/sudoku-funpark/outputter"
+)
+
+// Function to test the setWorkload function.
+func TestSetWorkload(t *testing.T) {
+	// Create a new Solver struct.
+	solver := Solver{}
+
+	// Create outputter struct.
+	outp := outputter.Outputter{}
+
+	// Set the output type to human.
+	outp.OutputType = "short"
+
+	// Set the outputter of the solver to the outputter.
+	solver.Outp = &outp
+
+	// Create a controller struct.
+	controller := controller.Controller{}
+
+	// Set the controller of the solver to the controller.
+	solver.Controller = &controller
+
+	// Execute the loadBlocks function.
+	solver.LoadBlocks()
+
+	// Provide controller.row1 with a value.
+	// This is the row that will be used in the findBlocks function.
+	controller.Row1 = "769104802"
+
+	// Fill the other rows with values.
+	solver.row2s = []string{"769104802"}
+	solver.row3s = []string{"769104802"}
+	solver.row4s = []string{"769104802"}
+	solver.row5s = []string{"769104802"}
+	solver.row6s = []string{"769104802"}
+	solver.row7s = []string{"769104802"}
+	solver.row8s = []string{"769104802"}
+	solver.row9s = []string{"769104802"}
+
+	// Call the findBlocks function with the row and the slice of rows.
+	solver.findBlocks(&controller.Row1, &solver.row1s)
+
+	// Divide the work between two agents.
+	solver.Controller.Split = 2
+
+	// Set the part of the workload that the first agent will do.
+	solver.Controller.Part = 1
+
+	// Call the splitWorkload function.
+	agents := solver.splitWorkload()
+
+	// Run the setWorkload function.
+	solver.setWorkload(agents)
+
+	// Check if the solver.row1s slice is as expected.
+	if len(solver.row1s) != 1 {
+		t.Errorf("Expected 1, got %v", len(solver.row1s))
+	}
+
+	// Check if the solver.Iter value is as expected.
+	if solver.Iter != 1 {
+		t.Errorf("Expected 9, got %v", solver.Iter)
+	}
+
+}

+ 51 - 0
solver/splitWorkload_test.go

@@ -0,0 +1,51 @@
+package solver
+
+import (
+	"testing"
+
+	"gitea.ligthert.net/golang/sudoku-funpark/controller"
+	"gitea.ligthert.net/golang/sudoku-funpark/outputter"
+)
+
+// Test the splitWorkload function.
+func TestSplitWorkload(t *testing.T) {
+	// Create a new Solver struct.
+	solver := Solver{}
+
+	// Create outputter struct.
+	outp := outputter.Outputter{}
+
+	// Set the output type to human.
+	outp.OutputType = "human"
+
+	// Set the outputter of the solver to the outputter.
+	solver.Outp = &outp
+
+	// Create a controller struct.
+	controller := controller.Controller{}
+
+	// Set the controller of the solver to the controller.
+	solver.Controller = &controller
+
+	// Execute the loadBlocks function.
+	solver.LoadBlocks()
+
+	// Provide controller.row1 with a value.
+	// This is the row that will be used in the findBlocks function.
+	controller.Row1 = "769104802"
+
+	// Call the findBlocks function with the row and the slice of rows.
+	solver.findBlocks(&controller.Row1, &solver.row1s)
+
+	// Divide the work between two agents.
+	solver.Controller.Split = 2
+
+	// Call the splitWorkload function.
+	agents := solver.splitWorkload()
+
+	// Check if the agents slice is as expected.
+	if agents[0] != 1 || agents[1] != 1 {
+		t.Errorf("Expected [1, 1], got %v", agents)
+	}
+
+}

+ 16 - 0
solver/validateCombination_test.go

@@ -0,0 +1,16 @@
+package solver
+
+import (
+	"testing"
+)
+
+// TestValidateCombination tests the validateCombination function.
+func TestValidateCombination(t *testing.T) {
+	// Create a new solver
+	solver := Solver{}
+
+	// Test the validateCombination function
+	if !solver.validateCombination("769154832", "154832769", "832769154", "671945328", "945328671", "328671945", "597416283", "416283597", "283597416") {
+		t.Error("validateCombination failed")
+	}
+}

+ 53 - 0
solver/validator_test.go

@@ -0,0 +1,53 @@
+package solver
+
+import (
+	"testing"
+
+	"gitea.ligthert.net/golang/sudoku-funpark/controller"
+	"gitea.ligthert.net/golang/sudoku-funpark/outputter"
+)
+
+// This function will test the validator function.
+// It will create all the structs, and set required values
+// Load the blocks, populate the blocks, and then run the validator
+func TestValidator(t *testing.T) {
+	// Do all the necesarry steps to initialize the solver.
+	solver := Solver{}
+	outp := outputter.Outputter{}
+	outp.OutputType = "short"
+	solver.Outp = &outp
+	controller := controller.Controller{}
+	solver.Controller = &controller
+	solver.LoadBlocks()
+
+	// Fill the slices of solver.rows with the following values:
+	// [769154832 154832769 832769154 671945328 945328671 328671945 597416283 416283597 283597416]
+	solver.row1s = []string{"769154832"}
+	solver.row2s = []string{"154832769"}
+	solver.row3s = []string{"832769154"}
+	solver.row4s = []string{"671945328"}
+	solver.row5s = []string{"945328671"}
+	solver.row6s = []string{"328671945"}
+	solver.row7s = []string{"597416283"}
+	solver.row8s = []string{"416283597"}
+	solver.row9s = []string{"283597416"}
+
+	// Set the rows to validate
+	rows1Index := 0
+	rows2Index := 0
+	rows3Index := 0
+	rows4Index := 0
+	rows5Index := 0
+	rows6Index := 0
+	rows7Index := 0
+	rows8Index := 0
+	rows9Index := 0
+
+	// Run the validator
+	solver.validator(rows1Index, rows2Index, rows3Index, rows4Index, rows5Index, rows6Index, rows7Index, rows8Index, rows9Index)
+
+	// Check the number of solutions
+	if len(controller.Solutions) != 1 {
+		t.Errorf("Expected 1 solution, got %d", len(controller.Solutions))
+	}
+}