package multibase import ( "encoding/csv" "os" "path/filepath" "strconv" "strings" "testing" "unicode/utf8" ) func TestSpec(t *testing.T) { file, err := os.Open("spec/multibase.csv") if err != nil { t.Fatal(err) } defer file.Close() reader := csv.NewReader(file) reader.LazyQuotes = false reader.FieldsPerRecord = 4 reader.TrimLeadingSpace = true values, err := reader.ReadAll() if err != nil { t.Error(err) } expectedEncodings := make(map[Encoding]string, len(values)-1) for _, v := range values[1:] { encoding := v[0] codeStr := v[1] var code Encoding if strings.HasPrefix(codeStr, "0x") { i, err := strconv.ParseUint(codeStr[2:], 16, 64) if err != nil { t.Errorf("invalid multibase byte %q", codeStr) continue } code = Encoding(i) } else { codeRune, length := utf8.DecodeRuneInString(codeStr) if code == utf8.RuneError { t.Errorf("multibase %q wasn't valid utf8", codeStr) continue } if length != len(codeStr) { t.Errorf("multibase %q wasn't a single character", codeStr) continue } code = Encoding(codeRune) } expectedEncodings[code] = encoding } for name, enc := range Encodings { expectedName, ok := expectedEncodings[enc] if !ok { t.Errorf("encoding %q (%c) not defined in the spec", name, enc) continue } if expectedName != name { t.Errorf("encoding %q (%c) has unexpected name %q", expectedName, enc, name) } } } func TestSpecVectors(t *testing.T) { files, err := filepath.Glob("spec/tests/*.csv") if err != nil { t.Fatal(err) } for _, fname := range files { t.Run(fname, func(t *testing.T) { file, err := os.Open(fname) if err != nil { t.Error(err) return } defer file.Close() reader := csv.NewReader(file) reader.LazyQuotes = false reader.FieldsPerRecord = 2 reader.TrimLeadingSpace = true values, err := reader.ReadAll() if err != nil { t.Error(err) } if len(values) == 0 { t.Error("no test values") return } header := values[0] var decodeOnly bool switch header[0] { case "encoding": case "non-canonical encoding": decodeOnly = true default: t.Errorf("invalid test spec %q", fname) return } testValue, err := strconv.Unquote("\"" + header[1] + "\"") if err != nil { t.Error("failed to unquote testcase:", err) return } for _, testCase := range values[1:] { encodingName := testCase[0] expected := testCase[1] t.Run(encodingName, func(t *testing.T) { encoder, err := EncoderByName(encodingName) if err != nil { t.Skipf("skipping %s: not supported", encodingName) return } if !decodeOnly { t.Logf("encoding %q with %s", testValue, encodingName) actual := encoder.Encode([]byte(testValue)) if expected != actual { t.Errorf("expected %q, got %q", expected, actual) } } t.Logf("decoding %q", expected) encoding, decoded, err := Decode(expected) if err != nil { t.Error("failed to decode:", err) return } expectedEncoding := Encodings[encodingName] if encoding != expectedEncoding { t.Errorf("expected encoding to be %c, got %c", expectedEncoding, encoding) } if string(decoded) != testValue { t.Errorf("failed to decode %q to %q, got %q", expected, testValue, string(decoded)) } }) } }) } }