diff --git a/.golangci.yml b/.golangci.yml index d69946c..7056efe 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,5 +1,5 @@ run: - go: 1.19 + go: 1.24.3 timeout: 10m linters: disable-all: true diff --git a/Makefile b/Makefile index c05f9ff..aa27084 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ -EXCLUDE_FOLDER = "basic\|intermediate\|utilities" -TEST_PACKAGE := $(shell go list ./... | grep -v $(EXCLUDE_FOLDER)) +# EXCLUDE_FOLDER = "basic\|intermediate\|utilities" +# TEST_PACKAGE := $(shell go list ./... | grep -v $(EXCLUDE_FOLDER)) +TEST_PACKAGE := $(shell go list ./tests/...) .DEFAULT_GOAL := test diff --git a/math/prima/cek_prima.go b/math/prima/cek_prima.go index da8dcfa..f8330e0 100644 --- a/math/prima/cek_prima.go +++ b/math/prima/cek_prima.go @@ -3,17 +3,19 @@ package prima // PembagianTrial memeriksa apakah sebuah bilangan dari n adalah // bilangan prima // Parameter: -// n - bilangan bulat bertipe integer 64 +// +// n - bilangan bulat bertipe integer 64 // // Return: +// // bool - true jika n adalah bilangan prima, false jika tidak prima func PembagianTrial(n int64) bool { if n < 2 { return false } - + for i := int64(2); i < n; i++ { - if n % i == 0 { + if n%i == 0 { return false } } diff --git a/math_implementation/armstrong/is_armstrong.go b/math_implementation/armstrong/is_armstrong.go index cebc338..d296b83 100644 --- a/math_implementation/armstrong/is_armstrong.go +++ b/math_implementation/armstrong/is_armstrong.go @@ -11,7 +11,7 @@ import ( "strconv" ) -func cekArmstrong(angka int) bool { +func CekArmstrong(angka int) bool { var digit_kanan int var sum int = 0 var tempNum int = angka diff --git a/searching/interpolation.go b/searching/interpolation.go index 99c4e13..4fd0325 100644 --- a/searching/interpolation.go +++ b/searching/interpolation.go @@ -11,7 +11,7 @@ package searching // Return: // - indeks pertama dari nilai yang cocok // - error jika tidak ditemukan atau kondisi input tidak valid -func pencarianInterpolasi(sortedData []int, tebakan int) (int, error) { +func PencarianInterpolasi(sortedData []int, tebakan int) (int, error) { // jika data kosong, langsung return error karena tidak ada data yang dicari if len(sortedData) == 0 { return -1, ErrorMessage diff --git a/searching/linear_searching.go b/searching/linear_searching.go index 4116683..eed2864 100644 --- a/searching/linear_searching.go +++ b/searching/linear_searching.go @@ -11,7 +11,7 @@ package searching // Return: // - int: indeks pertama tempat query ditemukan // - error: jika query tidak ditemukan, maka throw error -func linearSearching(array []int, query int) (int, error) { +func LinearSearching(array []int, query int) (int, error) { // melakukan iterasi terhadap array menggunakan array // dimana `i` adalah indeks dan `item` adalah nilai pada posisi tersebut for i, item := range array { diff --git a/searching/ternary_searching.go b/searching/ternary_searching.go index 139f0a6..8dc6e45 100644 --- a/searching/ternary_searching.go +++ b/searching/ternary_searching.go @@ -23,7 +23,7 @@ import ( // Return: // float64 - nilai maks dari f(x) dalam unterval [a, b] // error - error jika input tidak valid atau terjadi masalah selama eksekusi -func ternaryMaxSearching(a, b, epsilon float64, f func(x float64) float64) (float64, error) { +func TernaryMaxSearching(a, b, epsilon float64, f func(x float64) float64) (float64, error) { if a == math.Inf(-1) || b == math.Inf(1) { return -1, fmt.Errorf("interval harus memiliki angka float64") } @@ -34,10 +34,10 @@ func ternaryMaxSearching(a, b, epsilon float64, f func(x float64) float64) (floa kiri := (2*a + b) / 3 kanan := (a + 2*b) / 3 if f(kiri) < f(kanan) { - return ternaryMaxSearching(kiri, b, epsilon, f) + return TernaryMaxSearching(kiri, b, epsilon, f) } - return ternaryMaxSearching(a, kanan, epsilon, f) + return TernaryMaxSearching(a, kanan, epsilon, f) } // ternaryMinSearching mencari nilai minimum lokal dari fungsi(x) dalam interval [a, b] @@ -47,7 +47,7 @@ func ternaryMaxSearching(a, b, epsilon float64, f func(x float64) float64) (floa // - evaluasi nilai f(x) pada dua titik tengah: kiri dan kanan // - jika f(kiri) > f(kanan), maka nilai minimum berbeda di sisi kanan // proses berlanjut secara rekursif hingga interval lebih kecil dari epsilon -func ternaryMinSearching(a, b, epsilon float64, f func(x float64) float64) (float64, error) { +func TernaryMinSearching(a, b, epsilon float64, f func(x float64) float64) (float64, error) { if a == math.Inf(-1) || b == math.Inf(1) { return -1, fmt.Errorf("interval harus memiliki angka float64") } @@ -59,7 +59,7 @@ func ternaryMinSearching(a, b, epsilon float64, f func(x float64) float64) (floa kiri := (2*a + b) / 3 kanan := (a + 2*b) / 3 if f(kiri) > f(kanan) { - return ternaryMinSearching(kiri, b, epsilon, f) + return TernaryMinSearching(kiri, b, epsilon, f) } - return ternaryMinSearching(a, kanan, epsilon, f) + return TernaryMinSearching(a, kanan, epsilon, f) } diff --git a/searching/interpolation_test.go b/tests/algorithm/searching/interpolation_test.go similarity index 68% rename from searching/interpolation_test.go rename to tests/algorithm/searching/interpolation_test.go index 6e1e4ae..1f3b90a 100644 --- a/searching/interpolation_test.go +++ b/tests/algorithm/searching/interpolation_test.go @@ -1,10 +1,14 @@ package searching -import "testing" +import ( + "testing" + + "github.com/bellshade/Golang/searching" +) func TestInterpolasi(t *testing.T) { for _, test := range searchTests { - valueAktual, _ := pencarianInterpolasi(test.data, test.key) + valueAktual, _ := searching.PencarianInterpolasi(test.data, test.key) if valueAktual != test.ekspetasi { t.Errorf("test '%s' gagal: input array `%v` dengan key `%d`, ekspetasi `%d`, aktual: `%d`", test.name, test.data, test.key, test.ekspetasi, valueAktual) } diff --git a/searching/linear_searching_test.go b/tests/algorithm/searching/linear_searching_test.go similarity index 69% rename from searching/linear_searching_test.go rename to tests/algorithm/searching/linear_searching_test.go index 7232fb7..3b0cbd1 100644 --- a/searching/linear_searching_test.go +++ b/tests/algorithm/searching/linear_searching_test.go @@ -1,10 +1,14 @@ package searching -import "testing" +import ( + "testing" + + "github.com/bellshade/Golang/searching" +) func TestLinearSearching(t *testing.T) { for _, test := range searchTests { - valueAktual, _ := linearSearching(test.data, test.key) + valueAktual, _ := searching.LinearSearching(test.data, test.key) if valueAktual != test.ekspetasi { t.Errorf("test `%s` gagal: input array `%v` dengan key `%d`, ekspetasi: `%d`, aktual: `%d`", test.name, test.data, test.key, test.ekspetasi, valueAktual) } diff --git a/searching/ternary_searching_test.go b/tests/algorithm/searching/ternary_searching_test.go similarity index 82% rename from searching/ternary_searching_test.go rename to tests/algorithm/searching/ternary_searching_test.go index 2bd4c70..4e83c18 100644 --- a/searching/ternary_searching_test.go +++ b/tests/algorithm/searching/ternary_searching_test.go @@ -3,6 +3,8 @@ package searching import ( "math" "testing" + + "github.com/bellshade/Golang/searching" ) const EPS = 1e-6 @@ -12,7 +14,7 @@ func equal(a, b float64) bool { } func TestTernaryMax(t *testing.T) { - var tests = []struct { + tests := []struct { f func(x float64) float64 a float64 b float64 @@ -22,7 +24,7 @@ func TestTernaryMax(t *testing.T) { } for _, test := range tests { - hasil, error := ternaryMaxSearching(test.a, test.b, EPS, test.f) + hasil, error := searching.TernaryMaxSearching(test.a, test.b, EPS, test.f) if error != nil { t.Errorf("error, data: `%v`", error) } @@ -34,7 +36,7 @@ func TestTernaryMax(t *testing.T) { } func TestTernaryMin(t *testing.T) { - var tests = []struct { + tests := []struct { f func(x float64) float64 a float64 b float64 @@ -45,7 +47,7 @@ func TestTernaryMin(t *testing.T) { } for _, test := range tests { - hasil, error := ternaryMinSearching(test.a, test.b, EPS, test.f) + hasil, error := searching.TernaryMinSearching(test.a, test.b, EPS, test.f) if error != nil { t.Errorf("error, data: `%v`", error) } diff --git a/tests/algorithm/searching/test_data_search.go b/tests/algorithm/searching/test_data_search.go new file mode 100644 index 0000000..878f278 --- /dev/null +++ b/tests/algorithm/searching/test_data_search.go @@ -0,0 +1,26 @@ +package searching + +import "errors" + +var ErrorMessage = errors.New("target tidak terdapat pada array") + +type searchTest struct { + data []int + key int + ekspetasi int + ekspetasiError error + name string +} + +var searchTests = []searchTest{ + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 9, 8, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 8, 7, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 7, 6, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 6, 5, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 4, 3, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 3, 2, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 2, 1, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, nil, "Sanity"}, +} diff --git a/math/prima/cek_prima_test.go b/tests/math/cek_prima_test.go similarity index 74% rename from math/prima/cek_prima_test.go rename to tests/math/cek_prima_test.go index 0e386b4..4bd863e 100644 --- a/math/prima/cek_prima_test.go +++ b/tests/math/cek_prima_test.go @@ -1,7 +1,9 @@ -package prima +package math_test import ( "testing" + + "github.com/bellshade/Golang/math/prima" ) func TestPembagianTrial(t *testing.T) { @@ -17,7 +19,7 @@ func TestPembagianTrial(t *testing.T) { for _, testingTest := range testingData { t.Run(testingTest.name, func(t *testing.T) { - if getData := PembagianTrial(testingTest.n); getData != testingTest.ekspetasi { + if getData := prima.PembagianTrial(testingTest.n); getData != testingTest.ekspetasi { t.Errorf("PembagianTrial(%v) = %v; ekspetasi %v", testingTest.n, getData, testingTest.ekspetasi) } }) diff --git a/math/cos_test.go b/tests/math/cos_test.go similarity index 100% rename from math/cos_test.go rename to tests/math/cos_test.go diff --git a/math_implementation/faktorial/faktorial_test.go b/tests/math/implementation/faktorial_test.go similarity index 70% rename from math_implementation/faktorial/faktorial_test.go rename to tests/math/implementation/faktorial_test.go index 974695c..0d3dd30 100644 --- a/math_implementation/faktorial/faktorial_test.go +++ b/tests/math/implementation/faktorial_test.go @@ -1,19 +1,21 @@ -package faktorial +package math_implementation import ( "fmt" "testing" + + "github.com/bellshade/Golang/math_implementation/faktorial" ) type fungsiFaktorial func(int) (int, error) var implementasi = map[string]fungsiFaktorial{ - "Iterasi": Iterasi, - "Rekursif": Rekursif, - "Tree": TreeBin, + "Iterasi": faktorial.Iterasi, + "Rekursif": faktorial.Rekursif, + "Tree": faktorial.TreeBin, } -var testCase = []struct { +var testCaseFactorial = []struct { n int ekspetasi int }{ @@ -27,12 +29,12 @@ func TestFaktorial(t *testing.T) { for implName, implFunction := range implementasi { t.Run(implName+" error input negatif", func(t *testing.T) { _, error := implFunction(-1) - if error != ArgumentNegatif { + if error != faktorial.ArgumentNegatif { t.Errorf("tidak ada error dari input negatif") } }) - for _, tc := range testCase { + for _, tc := range testCaseFactorial { t.Run(fmt.Sprintf("%s dengan input %d", implName, tc.n), func(t *testing.T) { aktual, err := implFunction(tc.n) if err != nil { diff --git a/math_implementation/armstrong/is_armstrong_test.go b/tests/math/implementation/is_armstrong_test.go similarity index 80% rename from math_implementation/armstrong/is_armstrong_test.go rename to tests/math/implementation/is_armstrong_test.go index 5c9fc55..ee85b9d 100644 --- a/math_implementation/armstrong/is_armstrong_test.go +++ b/tests/math/implementation/is_armstrong_test.go @@ -1,6 +1,10 @@ -package armstrong +package math_implementation -import "testing" +import ( + "testing" + + "github.com/bellshade/Golang/math_implementation/armstrong" +) var testCase = []struct { name string @@ -37,7 +41,7 @@ var testCase = []struct { func TestArmstrong(t *testing.T) { for _, test := range testCase { t.Run(test.name, func(t *testing.T) { - funcResult := cekArmstrong(test.input) + funcResult := armstrong.CekArmstrong(test.input) if test.expected != funcResult { t.Errorf("expect jawaban '%t' untuk nomor '%d' tapi jawaban yang diberikan %t", test.expected, test.input, funcResult) } diff --git a/math_implementation/logaritma/logaritma_test.go b/tests/math/implementation/logaritma_test.go similarity index 68% rename from math_implementation/logaritma/logaritma_test.go rename to tests/math/implementation/logaritma_test.go index ee689dc..50fa44c 100644 --- a/math_implementation/logaritma/logaritma_test.go +++ b/tests/math/implementation/logaritma_test.go @@ -1,7 +1,9 @@ -package logaritma +package math_implementation import ( "testing" + + "github.com/bellshade/Golang/math_implementation/logaritma" ) func TestLogBase32(t *testing.T) { @@ -15,7 +17,7 @@ func TestLogBase32(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - if dapat := LogBase2(test.n); dapat != test.want { + if dapat := logaritma.LogBase2(test.n); dapat != test.want { t.Errorf("logBase2() = %v, harusnya %v", dapat, test.want) } }) diff --git a/math/sin_test.go b/tests/math/sin_test.go similarity index 93% rename from math/sin_test.go rename to tests/math/sin_test.go index cfcb80e..59b0814 100644 --- a/math/sin_test.go +++ b/tests/math/sin_test.go @@ -31,13 +31,13 @@ func TestSin(t *testing.T) { } func BenchmarkSin(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { algmath.Sin(180) } } func BenchmarkMathSin(b *testing.B) { - for i := 0; i < b.N; i++ { + for b.Loop() { stdmath.Sin(180) } } diff --git a/tests/test_utils.go b/tests/test_utils.go new file mode 100644 index 0000000..d869ce8 --- /dev/null +++ b/tests/test_utils.go @@ -0,0 +1,33 @@ +package tests + +import ( + "reflect" + "testing" +) + +// assert fails the test if the condition is false. +// assert: Gagal jika kondisi yang diberikan bernilai false (tidak terpenuhi). +func Assert(tb testing.TB, condition bool, msg string, v ...any) { + tb.Helper() + if !condition { + tb.Fatalf(msg, v...) + } +} + +// ok fails the test if an err is not nil. +// ok: Gagal jika error tidak bernilai nil (artinya terjadi kesalahan). +func OK(tb testing.TB, err error) { + tb.Helper() // print runtime caller err + if err != nil { + tb.Fatalf("unexpected error: %s", err.Error()) + } +} + +// equals fails the test if exp is not equal to act. +// equals: Gagal jika nilai yang diharapkan (exp) tidak sama dengan nilai aktual (act). +func Equals(tb testing.TB, exp, act any) { + tb.Helper() + if !reflect.DeepEqual(exp, act) { + tb.Fatalf("exp: %#v\n\n\tgot: %#v", exp, act) + } +}