// Copyright 2017 The Mellium Contributors.
// Use of this source code is governed by the BSD 2-clause
// license that can be found in the LICENSE file.
package ibr2
import (
"bytes"
"context"
"encoding/xml"
"fmt"
"io"
"reflect"
"testing"
)
// TestList checks that the server listing is generated properly and does not
// repeat challenge types.
func TestList(t *testing.T) {
b := new(bytes.Buffer)
d := xml.NewDecoder(b)
e := xml.NewEncoder(b)
f := Recovery(
Challenge{Type: "jabber:x:data"},
Challenge{Type: "pow"},
Challenge{Type: "jabber:x:data"})
_, err := f.List(context.Background(), e, xml.StartElement{Name: xml.Name{Local: "recover"}})
if err != nil {
t.Fatalf("List returned error: %v\n", err)
}
if err = e.Flush(); err != nil {
t.Fatalf("Error flushing: %q", err)
}
o := struct {
XMLName xml.Name `xml:"recover"`
Challenge []string `xml:"challenge"`
}{}
err = d.Decode(&o)
if err != nil && err != io.EOF {
t.Fatalf("Decoding error: %v\n", err)
}
if len(o.Challenge) != 2 {
t.Fatalf("Expected 2 challenges, got %d", len(o.Challenge))
}
if o.Challenge[0] != "jabber:x:data" {
t.Errorf("Expected first challenge to be jabber:x:data but got %s", o.Challenge[0])
}
if o.Challenge[1] != "pow" {
t.Errorf("Expected second challenge to be pow but got %s", o.Challenge[1])
}
}
var parseTests = [...]struct {
Listing []string
Challenges []string
Supported bool
}{
0: {
[]string{"test", "test", "test", "test", "test", "test"},
[]string{"type", "more", "test"},
true,
},
1: {
[]string{"test", "test", "test", "test", "test", "test"},
[]string{"type", "more"},
false,
},
2: {
[]string{"test", "test"},
[]string{"type", "more", "test"},
true,
},
3: {
[]string{"test", "test"},
[]string{"type", "more", "new", "castle"},
false,
},
4: {
[]string{"a", "new", "test"},
[]string{"new", "test", "a"},
true,
},
5: {
[]string{},
[]string{"new", "test", "a"},
true,
},
6: {
[]string{"nope", "never"},
[]string{},
false,
},
7: {
[]string{},
[]string{},
true,
},
}
// TestParse checks that clients parse challenge feature listings correctly and
// that they correctly determine if they support all the listed challenge types.
func TestParse(t *testing.T) {
for i, tc := range parseTests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
// Create the feature with the named challenges.
challenges := make([]Challenge, len(tc.Challenges))
for i, c := range tc.Challenges {
challenges[i] = Challenge{Type: c}
}
r := Register(challenges...)
// Marshal an XML listing for us to decode.
b, err := xml.Marshal(struct {
XMLName xml.Name `xml:"urn:xmpp:register:0 recovery"`
Challenges []string `xml:"challenge"`
}{
Challenges: tc.Listing,
})
if err != nil {
t.Fatal(err)
}
d := xml.NewDecoder(bytes.NewReader(b))
tok, err := d.Token()
if err != nil {
t.Fatal(err)
}
start, ok := tok.(xml.StartElement)
if !ok {
t.Fatalf("Marshaled bad XML; didn't get start element, got %#v", tok)
}
req, data, err := r.Parse(context.Background(), d, &start)
supported, ok := data.(bool)
switch {
case req:
t.Error("Feature parsed as required")
case err != nil:
t.Errorf("Unexpected error while parsing feature: %v", err)
case !ok:
t.Errorf("Parse returned wrong type data; want=bool, got=%v", reflect.TypeOf(supported))
case supported != tc.Supported:
t.Errorf("Parse got mismatched feature support: want=%v, got=%v", tc.Supported, supported)
}
})
}
}