Skip to content

Commit

Permalink
add base converter examples
Browse files Browse the repository at this point in the history
  • Loading branch information
aedlow committed Jan 7, 2024
1 parent b5c2644 commit 8df9eca
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 0 deletions.
116 changes: 116 additions & 0 deletions base_codecs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package xl8r

import (
"fmt"
"strconv"
"strings"
)

type baseContentData string

func (d baseContentData) String() string {
return strings.ToLower(strings.TrimSpace(string(d)))
}

type baseHubData int64

func (h baseHubData) AsBase(b int) (r string, e error) {
r = strconv.FormatInt(int64(h), b)
return
}

// generates many codecs for base to base conversions ...
func genBaseCodecs() (r []Codec[baseContentData, baseHubData]) {
aliases := make(map[int][]string)
aliases[2] = []string{"binary"}
aliases[10] = []string{"dec", "decimal"}
aliases[16] = []string{"hex", "hexadecimal"}

for i := 2; i < 37; i++ {
var ids []string
ids = append(ids, fmt.Sprintf("base%d", i))
if moreIds, exist := aliases[i]; exist {
ids = append(ids, moreIds...)
}

enc := testFetchBaseEnc(i)
dec := testFetchBaseDec(i)
chk := testFetchBaseChk(i)

for _, id := range ids {
r = append(r, &Spoke[baseContentData, baseHubData]{
Id: id,
Enc: enc,
Dec: dec,
Check: chk,
})
}
}

// add a special codec for base 1 ...
chkB1 := func(v baseContentData) (r bool) {
nStr := v.String()
if nStr = strings.ReplaceAll(nStr, "1", ""); len(nStr) == 0 {
r = true
}
return
}
encB1 := func(v baseContentData, _ ...Opts) (r baseHubData, e error) {
if chkB1(v) {
r = baseHubData(len(v.String()))
} else {
e = fmt.Errorf("invalid base 1 number [ %s ]",v.String())
}
return
}
decB1 := func(v baseHubData, _ ...Opts) (r baseContentData, e error) {
if num := int(v); num > 0 {
r = baseContentData(strings.Repeat("1", num))
return
} else if num == 0 {
r = baseContentData("")
return
}
e = fmt.Errorf("base 1 can only represent non-negative integers")
return
}

for _, b1Id := range []string{"base1", "unary"} {
r = append(r, &Spoke[baseContentData, baseHubData]{
Id: b1Id,
Enc: encB1,
Dec: decB1,
Check: chkB1,
})
}
return
}

func testFetchBaseEnc(b int) func(v baseContentData, _ ...Opts) (r baseHubData, e error) {
return func(v baseContentData, _ ...Opts) (r baseHubData, e error) {
hd, err := strconv.ParseInt(v.String(), b, 64)
r = baseHubData(hd)
e = err
return
}
}

func testFetchBaseDec(b int) func(v baseHubData, _ ...Opts) (r baseContentData, e error) {
return func(v baseHubData, _ ...Opts) (r baseContentData, e error) {
if result, err := v.AsBase(b); err == nil {
r = baseContentData(result)
} else {
e = err
}
return
}
}

func testFetchBaseChk(b int) func(v baseContentData) (r bool) {
return func(v baseContentData) (r bool) {
if _, err := strconv.ParseInt(v.String(), b, 64); err == nil {
r = true
}
return
}
}
88 changes: 88 additions & 0 deletions base_converter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package xl8r

import (
"fmt"
"strconv"
"strings"
"testing"
)

var definedBaseCodecs []Codec[baseContentData, baseHubData] = genBaseCodecs()

func TestDisplayIn_X_Base(t *testing.T) {

// a demo function that utilizes our Spoke-N-Hub Translator ...
displayNumberIn := func(requestedBase, originalBase string, numeral string, opts0 ...Opts) (r string, e error) {
const errMsgUnhandledFmt = "unknown base [ %s ]"
baseName := func(s string) (r string) {
r = strings.ToLower(strings.ReplaceAll(strings.TrimSpace(s), " ", ""))
if num, err := strconv.Atoi(r); err == nil {
r = fmt.Sprintf("base%d",num)
}
return
}

convertBase, err := New(definedBaseCodecs...)
if err != nil {
e = err
return
}

rqstdBase := baseName(requestedBase)
originBase := baseName(originalBase)

if !convertBase.Knows(rqstdBase) {
e = fmt.Errorf(errMsgUnhandledFmt, requestedBase)
return
}

if !convertBase.Knows(originBase) {
e = fmt.Errorf(errMsgUnhandledFmt, originalBase)
return
}
sourceContent := baseContentData(numeral)
if toR, toErr := convertBase.To(rqstdBase, originBase, sourceContent, opts0...); toErr == nil {
r = string(toR)
} else {
e = toErr
}
return
}


tt := []struct {
number, requestBase, originalBase, expected string
expectedErr error
useOpt *Opts
}{
{number: "32", requestBase: "10", originalBase: "-10", expected: "", expectedErr: fmt.Errorf(`unknown base [ -10 ]`)},
{number: "32", requestBase: "Decimal", originalBase: "Base10", expected: "32"},
{number: "33", requestBase: "Binary", originalBase: "Base10", expected: "100001"},
{number: "15", requestBase: "hex", originalBase: "Base 10", expected: "f"},
{number: "f", requestBase: "base2", originalBase: "hexadecimal", expected: "1111"},
{number: "c0c0c0", requestBase: "hex", originalBase: "base 16", expected: "c0c0c0"},
{number: "-c0c0c0", requestBase: "hex", originalBase: "base 16", expected: "-c0c0c0"},
{number: "111", requestBase: "unary", originalBase: "binary", expected: "1111111" },
{number: "1111111", requestBase: "Decimal", originalBase: "base 1", expected: "7" },
{number: "-3", requestBase: "Unary", originalBase: "base 10", expected: "", expectedErr: fmt.Errorf(`base 1 can only represent non-negative integers`) },
}

for i, tx := range tt {
var result string
var err error
if opt := tx.useOpt; opt != nil {
result, err = displayNumberIn(tx.requestBase, tx.originalBase, tx.number, *tx.useOpt)
} else {
result, err = displayNumberIn(tx.requestBase, tx.originalBase, tx.number)
}

assrtEqual(t, tx.expected, result)
assrtEqual(t, err, tx.expectedErr)
var errMsg string
if err != nil {
errMsg = err.Error()
}
t.Logf(`# %d: displayNumberIn("%s","%s","%s") ==>> "%s" %s`,
i, tx.requestBase, tx.originalBase, tx.number, result, errMsg)
}
}

0 comments on commit 8df9eca

Please sign in to comment.