From 0ad890be00741f1cb095d9126e3ceaab17d9ab0b Mon Sep 17 00:00:00 2001 From: Victor Payno Date: Thu, 21 Sep 2023 22:34:48 -0700 Subject: [PATCH] awk/all-your-base: 1st iteration --- awk/README.md | 1 + awk/all-your-base/.lint_default_vars | 1 + awk/all-your-base/README.md | 9 +- awk/all-your-base/all-your-base.awk | 114 +++++++++++++- awk/all-your-base/all-your-base_test.awk | 101 +++++++++++++ awk/all-your-base/awkunit.awk | 1 + awk/all-your-base/run-tests-awk.txt | 185 +++++++++++++++++++++++ awk/all-your-base/test-cases.awk | 20 +++ 8 files changed, 427 insertions(+), 5 deletions(-) create mode 100644 awk/all-your-base/.lint_default_vars create mode 100644 awk/all-your-base/all-your-base_test.awk create mode 120000 awk/all-your-base/awkunit.awk create mode 100644 awk/all-your-base/run-tests-awk.txt create mode 100644 awk/all-your-base/test-cases.awk diff --git a/awk/README.md b/awk/README.md index e4cf788f..5c138902 100644 --- a/awk/README.md +++ b/awk/README.md @@ -32,3 +32,4 @@ - [scrabble-score](./scrabble-score/README.md) - [etl](./etl/README.md) - [space-age](./space-age/README.md) +- [all-your-base](./all-your-base/README.md) diff --git a/awk/all-your-base/.lint_default_vars b/awk/all-your-base/.lint_default_vars new file mode 100644 index 00000000..5d2e8fd9 --- /dev/null +++ b/awk/all-your-base/.lint_default_vars @@ -0,0 +1 @@ +-v obase=10 \ No newline at end of file diff --git a/awk/all-your-base/README.md b/awk/all-your-base/README.md index 12ea3aeb..ce4242a1 100644 --- a/awk/all-your-base/README.md +++ b/awk/all-your-base/README.md @@ -41,4 +41,11 @@ I think you got the idea! ### Created by -- @IsaacG \ No newline at end of file +- @IsaacG + +### My Solution + +- [my solution](./all-your-base.awk) +- [awkunit tests](./all-your-base_test.awk) +- [test cases](./test-cases.awk) +- [run-tests](./run-tests-awk.txt) diff --git a/awk/all-your-base/all-your-base.awk b/awk/all-your-base/all-your-base.awk index 436b7834..779a32f5 100644 --- a/awk/all-your-base/all-your-base.awk +++ b/awk/all-your-base/all-your-base.awk @@ -1,8 +1,114 @@ +#!/usr/bin/gawk --bignum --lint --file + +@load "ordchr" + # These variables are initialized on the command line (using '-v'): -# - ibase -# - obase +# - ibase -> uint +# - obase -> uint + +function to_base_10(input_base, input_digits) { + base_ten = 0 + + _ = split(input_digits, digits, " ") + + for (i in digits) { + # print "digit: [" digits[i] "]" + + base_ten *= input_base + base_ten += digits[i] + } + + # print "base_ten: [" base_ten "]" + + return base_ten +} + +function from_base_10(output_base, number) { + output_digits = "" + + # if number isn't an int here, it will keep aproaching zero for more than a few iterations + while (number > 0) { + # print "number: [" number "]" + + tmp = number % output_base + tmp = int(tmp) + + if (output_digits == "") { + output_digits = tmp + } else { + output_digits = tmp " " output_digits + } + + number /= output_base + number = int(number) + } + + return output_digits +} + +function allYourBase(input_base, output_base, input_digits) { + # print "ibase: [" input_base "]" + # print "obase: [" output_base "]" + # print "input_digits: [" input_digits "]" + + if (int(input_base) <= 1) { + return "error:input base, " input_base ", is less than or equal to 1" + } + + if (int(output_base) <= 1) { + return "error:output base, " output_base ", is less than or equal to 1" + } + + if (length(input_digits) == 0) { + # return "error:input digits list is empty" + # the test expects no output + return "" + } + + _ = split(input_digits, digits, " ") + + for (i in digits) { + if (int(digits[i]) >= int(input_base)) { + return "error:found input digit, " digits[i] ", that is larger than input base, " input_base + } + + if (int(digits[i]) < 0) { + return "error:found negative input digit, " digits[i] + } + } + + return from_base_10(output_base, to_base_10(input_base, input_digits)) +} BEGIN { - print "Implement this solution" > "/dev/stderr" - exit 1 +} + +{ + # let's make sure ibase isn't being used to inject code + if (! match(ibase, /^([0-9]+)$/)) { + print "error: invalid input base [" ibase "], expecting unsigned integer" #> /dev/stderr + exit 1 + } + + # let's make sure obase isn't being used to inject code + if (! match(obase, /^([0-9]+)$/)) { + print "error: invalid output base [" obase "], expecting unsigned integer" #> /dev/stderr + exit 1 + } + + result = allYourBase(ibase, obase, $0) + + if (match(result, /^error:/)) { + _ = split(result, parts, ":") + level = parts[1] + message = parts[2] + + print "[" level "]: " message #> /dev/stderr + exit 1 + } + + print result +} + +END { } diff --git a/awk/all-your-base/all-your-base_test.awk b/awk/all-your-base/all-your-base_test.awk new file mode 100644 index 00000000..01d53d68 --- /dev/null +++ b/awk/all-your-base/all-your-base_test.awk @@ -0,0 +1,101 @@ +#!/usr/bin/gawk --bignum --lint --file + +@include "awkunit" +@include "test-cases" +@include "all-your-base" + +passed = 0 +testCount = 0 + +function _debugTestPre() { + printf "Test %s:\n", (passed + 1) + printf " input -> [%s]\n", input_base + printf " digits -> [%s]\n", input_digits +} + +function _debugTestPost() { + passed = passed + 1 + printf " output -> [%s]\n", got + printf " result -> passed\n\n" +} + +function testAllYourBase_2to10() { + input_base = "2" + output_base = "10" + input_digits = "1 0 1" + want = "5" + + # _ = split(input, a, " ") + + _debugTestPre() + got = allYourBase(input_base, output_base, input_digits) + + assertEquals(got, want) + _debugTestPost() +} + +function testAllYourBase_10to2() { + input_base = "10" + output_base = "2" + input_digits = "5" + want = "1 0 1" + + # _ = split(input, a, " ") + + _debugTestPre() + got = allYourBase(input_base, output_base, input_digits) + + assertEquals(got, want) + _debugTestPost() +} + +function casesAllYourBase() { + printf "Running %d test cases\n\n", length(cases) + caseNum = 0 + + # orders array by index in for loop + PROCINFO["sorted_in"] = "@ind_str_asc" + + # Associative arrays don't preserve insert order. + for (key in cases) { + input = key + want = cases[key] + + _ = split(input, a, ":") + + input_base = a[1] + output_base = a[2] + input_digits = a[3] + + _debugTestPre() + got = allYourBase(input_base, output_base, input_digits) + + assertEquals(got, want) + _debugTestPost() + } +} + +BEGIN { + exit 0 +} + +END { + cmd = "grep --no-filename --count ^function\\ test *_test.awk" + cmd | getline testCount + + printf "\nRunning %d tests...\n\n", testCount + + testCount = testCount + length(cases) + + # running tests with a lot of duplication + testAllYourBase_2to10() + testAllYourBase_10to2() + + # running tests with reduced duplication + casesAllYourBase() + + print "\n" passed " out of " testCount " tests passed!" + + # add exit here to keep it from looping + exit 0 +} diff --git a/awk/all-your-base/awkunit.awk b/awk/all-your-base/awkunit.awk new file mode 120000 index 00000000..38a08adf --- /dev/null +++ b/awk/all-your-base/awkunit.awk @@ -0,0 +1 @@ +../.lib/awkunit.awk \ No newline at end of file diff --git a/awk/all-your-base/run-tests-awk.txt b/awk/all-your-base/run-tests-awk.txt new file mode 100644 index 00000000..c667579d --- /dev/null +++ b/awk/all-your-base/run-tests-awk.txt @@ -0,0 +1,185 @@ +Running automated test file(s): + + +=============================================================================== + +AWKLIBPATH=/usr/lib/x86_64-linux-gnu/gawk:../.lib + +/usr/lib/x86_64-linux-gnu/gawk +filefuncs.so +fnmatch.so +fork.so +inplace.so +intdiv.so +ordchr.so +readdir.so +readfile.so +revoutput.so +revtwoway.so +rwarray.so +time.so + +../.lib +awkunit.awk +awkunit.so + +gawk -v obase=10 --lint --file=./all-your-base.awk < /dev/null > /dev/null +gawk: ./all-your-base.awk:3: warning: `load' is a gawk extension + +real 0m0.005s +user 0m0.002s +sys 0m0.003s + +gawk -v obase=10 --lint --file=./awkunit.awk < /dev/null > /dev/null +gawk: ./awkunit.awk:3: warning: `load' is a gawk extension +gawk: warning: function `assertEquals' defined but never called directly +gawk: warning: function `assert' defined but never called directly +gawk: ./awkunit.awk:26: warning: reference to uninitialized variable `_assert_exit' + +real 0m0.005s +user 0m0.001s +sys 0m0.004s + +gawk -v obase=10 --lint --file=./test-cases.awk < /dev/null > /dev/null + +real 0m0.005s +user 0m0.000s +sys 0m0.004s + +exit 0 + +=============================================================================== + +Running: bats ./test-all-your-base.bats +1..21 +ok 1 single bit to one decimal +ok 2 binary to single decimal +ok 3 single decimal to binary +ok 4 binary to multiple decimal +ok 5 decimal to binary +ok 6 trinary to hexadecimal +ok 7 hexadecimal to trinary +ok 8 15 bit integer +ok 9 empty list +ok 10 single zero +ok 11 multiple zeroes +ok 12 leading zeros +ok 13 input base is one +ok 14 input base is zero +ok 15 input base is negative +ok 16 negative digit +ok 17 invalid positive digit +ok 18 output base is one +ok 19 output base is zero +ok 20 output base is negative +ok 21 both bases are negative + +real 0m0.817s +user 0m0.547s +sys 0m0.287s + +exit 0 + +=============================================================================== + +AWKLIBPATH=/usr/lib/x86_64-linux-gnu/gawk:../.lib + +/usr/lib/x86_64-linux-gnu/gawk +filefuncs.so +fnmatch.so +fork.so +inplace.so +intdiv.so +ordchr.so +readdir.so +readfile.so +revoutput.so +revtwoway.so +rwarray.so +time.so + +../.lib +awkunit.awk +awkunit.so + +Running: gawk -v obase=10 --file ./all-your-base_test.awk && printf \n%s\n Tests Passed! || printf \n%s\n Tests Failed! + +Running 2 tests... + +Test 1: + input -> [2] + digits -> [1 0 1] + output -> [5] + result -> passed + +Test 2: + input -> [10] + digits -> [5] + output -> [1 0 1] + result -> passed + +Running 7 test cases + +Test 3: + input -> [10] + digits -> [] + output -> [error:output base, 1, is less than or equal to 1] + result -> passed + +Test 4: + input -> [10] + digits -> [] + output -> [] + result -> passed + +Test 5: + input -> [10] + digits -> [5] + output -> [1 0 1] + result -> passed + +Test 6: + input -> [1] + digits -> [] + output -> [error:input base, 1, is less than or equal to 1] + result -> passed + +Test 7: + input -> [2] + digits -> [1 -1 1] + output -> [error:found negative input digit, -1] + result -> passed + +Test 8: + input -> [2] + digits -> [1 0 1] + output -> [5] + result -> passed + +Test 9: + input -> [2] + digits -> [1 2 1] + output -> [error:found input digit, 2, that is larger than input base, 2] + result -> passed + + +9 out of 9 tests passed! + +real 0m0.010s +user 0m0.003s +sys 0m0.008s + +Tests Passed! + +exit 0 + +=============================================================================== + +Running: misspell . + +real 0m0.037s +user 0m0.036s +sys 0m0.019s + +=============================================================================== + diff --git a/awk/all-your-base/test-cases.awk b/awk/all-your-base/test-cases.awk new file mode 100644 index 00000000..bd889a43 --- /dev/null +++ b/awk/all-your-base/test-cases.awk @@ -0,0 +1,20 @@ +#!/usr/bin/gawk --lint --file +# test-cases.awk + +# key: input +# value: output + +BEGIN { + cases["2:10:1 0 1"]="5" + cases["10:2:5"]="1 0 1" + + cases["2:10:1 2 1"]="error:found input digit, 2, that is larger than input base, 2" + cases["2:10:1 -1 1"]="error:found negative input digit, -1" + + cases["1:10:"]="error:input base, 1, is less than or equal to 1" + cases["10:1:"]="error:output base, 1, is less than or equal to 1" + cases["10:2:"]="" + + # add exit here to keep it from waiting for input + exit 0 +}