VOL-381 add unum container to support ONOS cluster formation under swarm

Change-Id: Ic260edda19bb199ed040f05164ab605f28c919d0
diff --git a/unum/vendor/golang.org/x/text/secure/bidirule/bench_test.go b/unum/vendor/golang.org/x/text/secure/bidirule/bench_test.go
new file mode 100644
index 0000000..2db922b
--- /dev/null
+++ b/unum/vendor/golang.org/x/text/secure/bidirule/bench_test.go
@@ -0,0 +1,54 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bidirule
+
+import (
+	"testing"
+
+	"golang.org/x/text/internal/testtext"
+)
+
+var benchData = []struct{ name, data string }{
+	{"ascii", "Scheveningen"},
+	{"arabic", "دبي"},
+	{"hangul", "다음과"},
+}
+
+func doBench(b *testing.B, fn func(b *testing.B, data string)) {
+	for _, d := range benchData {
+		testtext.Bench(b, d.name, func(b *testing.B) { fn(b, d.data) })
+	}
+}
+
+func BenchmarkSpan(b *testing.B) {
+	r := New()
+	doBench(b, func(b *testing.B, str string) {
+		b.SetBytes(int64(len(str)))
+		data := []byte(str)
+		for i := 0; i < b.N; i++ {
+			r.Reset()
+			r.Span(data, true)
+		}
+	})
+}
+
+func BenchmarkDirectionASCII(b *testing.B) {
+	doBench(b, func(b *testing.B, str string) {
+		b.SetBytes(int64(len(str)))
+		data := []byte(str)
+		for i := 0; i < b.N; i++ {
+			Direction(data)
+		}
+	})
+}
+
+func BenchmarkDirectionStringASCII(b *testing.B) {
+	doBench(b, func(b *testing.B, str string) {
+		b.SetBytes(int64(len(str)))
+		for i := 0; i < b.N; i++ {
+			DirectionString(str)
+		}
+	})
+}
diff --git a/unum/vendor/golang.org/x/text/secure/bidirule/bidirule.go b/unum/vendor/golang.org/x/text/secure/bidirule/bidirule.go
new file mode 100644
index 0000000..0e6b858
--- /dev/null
+++ b/unum/vendor/golang.org/x/text/secure/bidirule/bidirule.go
@@ -0,0 +1,340 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bidirule implements the Bidi Rule defined by RFC 5893.
+//
+// This package is under development. The API may change without notice and
+// without preserving backward compatibility.
+package bidirule
+
+import (
+	"errors"
+	"unicode/utf8"
+
+	"golang.org/x/text/transform"
+	"golang.org/x/text/unicode/bidi"
+)
+
+// This file contains an implementation of RFC 5893: Right-to-Left Scripts for
+// Internationalized Domain Names for Applications (IDNA)
+//
+// A label is an individual component of a domain name.  Labels are usually
+// shown separated by dots; for example, the domain name "www.example.com" is
+// composed of three labels: "www", "example", and "com".
+//
+// An RTL label is a label that contains at least one character of class R, AL,
+// or AN. An LTR label is any label that is not an RTL label.
+//
+// A "Bidi domain name" is a domain name that contains at least one RTL label.
+//
+//  The following guarantees can be made based on the above:
+//
+//  o  In a domain name consisting of only labels that satisfy the rule,
+//     the requirements of Section 3 are satisfied.  Note that even LTR
+//     labels and pure ASCII labels have to be tested.
+//
+//  o  In a domain name consisting of only LDH labels (as defined in the
+//     Definitions document [RFC5890]) and labels that satisfy the rule,
+//     the requirements of Section 3 are satisfied as long as a label
+//     that starts with an ASCII digit does not come after a
+//     right-to-left label.
+//
+//  No guarantee is given for other combinations.
+
+// ErrInvalid indicates a label is invalid according to the Bidi Rule.
+var ErrInvalid = errors.New("bidirule: failed Bidi Rule")
+
+type ruleState uint8
+
+const (
+	ruleInitial ruleState = iota
+	ruleLTR
+	ruleLTRFinal
+	ruleRTL
+	ruleRTLFinal
+	ruleInvalid
+)
+
+type ruleTransition struct {
+	next ruleState
+	mask uint16
+}
+
+var transitions = [...][2]ruleTransition{
+	// [2.1] The first character must be a character with Bidi property L, R, or
+	// AL. If it has the R or AL property, it is an RTL label; if it has the L
+	// property, it is an LTR label.
+	ruleInitial: {
+		{ruleLTRFinal, 1 << bidi.L},
+		{ruleRTLFinal, 1<<bidi.R | 1<<bidi.AL},
+	},
+	ruleRTL: {
+		// [2.3] In an RTL label, the end of the label must be a character with
+		// Bidi property R, AL, EN, or AN, followed by zero or more characters
+		// with Bidi property NSM.
+		{ruleRTLFinal, 1<<bidi.R | 1<<bidi.AL | 1<<bidi.EN | 1<<bidi.AN},
+
+		// [2.2] In an RTL label, only characters with the Bidi properties R,
+		// AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
+		// We exclude the entries from [2.3]
+		{ruleRTL, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN | 1<<bidi.NSM},
+	},
+	ruleRTLFinal: {
+		// [2.3] In an RTL label, the end of the label must be a character with
+		// Bidi property R, AL, EN, or AN, followed by zero or more characters
+		// with Bidi property NSM.
+		{ruleRTLFinal, 1<<bidi.R | 1<<bidi.AL | 1<<bidi.EN | 1<<bidi.AN | 1<<bidi.NSM},
+
+		// [2.2] In an RTL label, only characters with the Bidi properties R,
+		// AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
+		// We exclude the entries from [2.3] and NSM.
+		{ruleRTL, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN},
+	},
+	ruleLTR: {
+		// [2.6] In an LTR label, the end of the label must be a character with
+		// Bidi property L or EN, followed by zero or more characters with Bidi
+		// property NSM.
+		{ruleLTRFinal, 1<<bidi.L | 1<<bidi.EN},
+
+		// [2.5] In an LTR label, only characters with the Bidi properties L,
+		// EN, ES, CS, ET, ON, BN, or NSM are allowed.
+		// We exclude the entries from [2.6].
+		{ruleLTR, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN | 1<<bidi.NSM},
+	},
+	ruleLTRFinal: {
+		// [2.6] In an LTR label, the end of the label must be a character with
+		// Bidi property L or EN, followed by zero or more characters with Bidi
+		// property NSM.
+		{ruleLTRFinal, 1<<bidi.L | 1<<bidi.EN | 1<<bidi.NSM},
+
+		// [2.5] In an LTR label, only characters with the Bidi properties L,
+		// EN, ES, CS, ET, ON, BN, or NSM are allowed.
+		// We exclude the entries from [2.6].
+		{ruleLTR, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN},
+	},
+	ruleInvalid: {
+		{ruleInvalid, 0},
+		{ruleInvalid, 0},
+	},
+}
+
+// [2.4] In an RTL label, if an EN is present, no AN may be present, and
+// vice versa.
+const exclusiveRTL = uint16(1<<bidi.EN | 1<<bidi.AN)
+
+// From RFC 5893
+// An RTL label is a label that contains at least one character of type
+// R, AL, or AN.
+//
+// An LTR label is any label that is not an RTL label.
+
+// Direction reports the direction of the given label as defined by RFC 5893.
+// The Bidi Rule does not have to be applied to labels of the category
+// LeftToRight.
+func Direction(b []byte) bidi.Direction {
+	for i := 0; i < len(b); {
+		e, sz := bidi.Lookup(b[i:])
+		if sz == 0 {
+			i++
+		}
+		c := e.Class()
+		if c == bidi.R || c == bidi.AL || c == bidi.AN {
+			return bidi.RightToLeft
+		}
+		i += sz
+	}
+	return bidi.LeftToRight
+}
+
+// DirectionString reports the direction of the given label as defined by RFC
+// 5893. The Bidi Rule does not have to be applied to labels of the category
+// LeftToRight.
+func DirectionString(s string) bidi.Direction {
+	for i := 0; i < len(s); {
+		e, sz := bidi.LookupString(s[i:])
+		if sz == 0 {
+			i++
+			continue
+		}
+		c := e.Class()
+		if c == bidi.R || c == bidi.AL || c == bidi.AN {
+			return bidi.RightToLeft
+		}
+		i += sz
+	}
+	return bidi.LeftToRight
+}
+
+// Valid reports whether b conforms to the BiDi rule.
+func Valid(b []byte) bool {
+	var t Transformer
+	if n, ok := t.advance(b); !ok || n < len(b) {
+		return false
+	}
+	return t.isFinal()
+}
+
+// ValidString reports whether s conforms to the BiDi rule.
+func ValidString(s string) bool {
+	var t Transformer
+	if n, ok := t.advanceString(s); !ok || n < len(s) {
+		return false
+	}
+	return t.isFinal()
+}
+
+// New returns a Transformer that verifies that input adheres to the Bidi Rule.
+func New() *Transformer {
+	return &Transformer{}
+}
+
+// Transformer implements transform.Transform.
+type Transformer struct {
+	state  ruleState
+	hasRTL bool
+	seen   uint16
+}
+
+// A rule can only be violated for "Bidi Domain names", meaning if one of the
+// following categories has been observed.
+func (t *Transformer) isRTL() bool {
+	const isRTL = 1<<bidi.R | 1<<bidi.AL | 1<<bidi.AN
+	return t.seen&isRTL != 0
+}
+
+func (t *Transformer) isFinal() bool {
+	return t.state == ruleLTRFinal || t.state == ruleRTLFinal || t.state == ruleInitial
+}
+
+// Reset implements transform.Transformer.
+func (t *Transformer) Reset() { *t = Transformer{} }
+
+// Transform implements transform.Transformer. This Transformer has state and
+// needs to be reset between uses.
+func (t *Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	if len(dst) < len(src) {
+		src = src[:len(dst)]
+		atEOF = false
+		err = transform.ErrShortDst
+	}
+	n, err1 := t.Span(src, atEOF)
+	copy(dst, src[:n])
+	if err == nil || err1 != nil && err1 != transform.ErrShortSrc {
+		err = err1
+	}
+	return n, n, err
+}
+
+// Span returns the first n bytes of src that conform to the Bidi rule.
+func (t *Transformer) Span(src []byte, atEOF bool) (n int, err error) {
+	if t.state == ruleInvalid && t.isRTL() {
+		return 0, ErrInvalid
+	}
+	n, ok := t.advance(src)
+	switch {
+	case !ok:
+		err = ErrInvalid
+	case n < len(src):
+		if !atEOF {
+			err = transform.ErrShortSrc
+			break
+		}
+		err = ErrInvalid
+	case !t.isFinal():
+		err = ErrInvalid
+	}
+	return n, err
+}
+
+// Precomputing the ASCII values decreases running time for the ASCII fast path
+// by about 30%.
+var asciiTable [128]bidi.Properties
+
+func init() {
+	for i := range asciiTable {
+		p, _ := bidi.LookupRune(rune(i))
+		asciiTable[i] = p
+	}
+}
+
+func (t *Transformer) advance(s []byte) (n int, ok bool) {
+	var e bidi.Properties
+	var sz int
+	for n < len(s) {
+		if s[n] < utf8.RuneSelf {
+			e, sz = asciiTable[s[n]], 1
+		} else {
+			e, sz = bidi.Lookup(s[n:])
+			if sz <= 1 {
+				if sz == 1 {
+					// We always consider invalid UTF-8 to be invalid, even if
+					// the string has not yet been determined to be RTL.
+					// TODO: is this correct?
+					return n, false
+				}
+				return n, true // incomplete UTF-8 encoding
+			}
+		}
+		// TODO: using CompactClass would result in noticeable speedup.
+		// See unicode/bidi/prop.go:Properties.CompactClass.
+		c := uint16(1 << e.Class())
+		t.seen |= c
+		if t.seen&exclusiveRTL == exclusiveRTL {
+			t.state = ruleInvalid
+			return n, false
+		}
+		switch tr := transitions[t.state]; {
+		case tr[0].mask&c != 0:
+			t.state = tr[0].next
+		case tr[1].mask&c != 0:
+			t.state = tr[1].next
+		default:
+			t.state = ruleInvalid
+			if t.isRTL() {
+				return n, false
+			}
+		}
+		n += sz
+	}
+	return n, true
+}
+
+func (t *Transformer) advanceString(s string) (n int, ok bool) {
+	var e bidi.Properties
+	var sz int
+	for n < len(s) {
+		if s[n] < utf8.RuneSelf {
+			e, sz = asciiTable[s[n]], 1
+		} else {
+			e, sz = bidi.LookupString(s[n:])
+			if sz <= 1 {
+				if sz == 1 {
+					return n, false // invalid UTF-8
+				}
+				return n, true // incomplete UTF-8 encoding
+			}
+		}
+		// TODO: using CompactClass results in noticeable speedup.
+		// See unicode/bidi/prop.go:Properties.CompactClass.
+		c := uint16(1 << e.Class())
+		t.seen |= c
+		if t.seen&exclusiveRTL == exclusiveRTL {
+			t.state = ruleInvalid
+			return n, false
+		}
+		switch tr := transitions[t.state]; {
+		case tr[0].mask&c != 0:
+			t.state = tr[0].next
+		case tr[1].mask&c != 0:
+			t.state = tr[1].next
+		default:
+			t.state = ruleInvalid
+			if t.isRTL() {
+				return n, false
+			}
+		}
+		n += sz
+	}
+	return n, true
+}
diff --git a/unum/vendor/golang.org/x/text/secure/bidirule/bidirule_test.go b/unum/vendor/golang.org/x/text/secure/bidirule/bidirule_test.go
new file mode 100644
index 0000000..4b6c612
--- /dev/null
+++ b/unum/vendor/golang.org/x/text/secure/bidirule/bidirule_test.go
@@ -0,0 +1,851 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bidirule
+
+import (
+	"fmt"
+	"testing"
+
+	"golang.org/x/text/internal/testtext"
+	"golang.org/x/text/transform"
+	"golang.org/x/text/unicode/bidi"
+)
+
+const (
+	strL   = "ABC"    // Left to right - most letters in LTR scripts
+	strR   = "עברית"  // Right to left - most letters in non-Arabic RTL scripts
+	strAL  = "دبي"    // Arabic letters - most letters in the Arabic script
+	strEN  = "123"    // European Number (0-9, and Extended Arabic-Indic numbers)
+	strES  = "+-"     // European Number Separator (+ and -)
+	strET  = "$"      // European Number Terminator (currency symbols, the hash sign, the percent sign and so on)
+	strAN  = "\u0660" // Arabic Number; this encompasses the Arabic-Indic numbers, but not the Extended Arabic-Indic numbers
+	strCS  = ","      // Common Number Separator (. , / : et al)
+	strNSM = "\u0300" // Nonspacing Mark - most combining accents
+	strBN  = "\u200d" // Boundary Neutral - control characters (ZWNJ, ZWJ, and others)
+	strB   = "\u2029" // Paragraph Separator
+	strS   = "\u0009" // Segment Separator
+	strWS  = " "      // Whitespace, including the SPACE character
+	strON  = "@"      // Other Neutrals, including @, &, parentheses, MIDDLE DOT
+)
+
+type ruleTest struct {
+	in  string
+	dir bidi.Direction
+	n   int // position at which the rule fails
+	err error
+
+	// For tests that split the string in two.
+	pSrc  int   // number of source bytes to consume first
+	szDst int   // size of destination buffer
+	nSrc  int   // source bytes consumed and bytes written
+	err0  error // error after first run
+}
+
+var testCases = [][]ruleTest{
+	// Go-specific rules.
+	// Invalid UTF-8 is invalid.
+	0: []ruleTest{{
+		in:  "",
+		dir: bidi.LeftToRight,
+	}, {
+		in:  "\x80",
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   0,
+	}, {
+		in:  "\xcc",
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   0,
+	}, {
+		in:  "abc\x80",
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   3,
+	}, {
+		in:  "abc\xcc",
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   3,
+	}, {
+		in:  "abc\xccdef",
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   3,
+	}, {
+		in:  "\xccdef",
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   0,
+	}, {
+		in:  strR + "\x80",
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   len(strR),
+	}, {
+		in:  strR + "\xcc",
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   len(strR),
+	}, {
+		in:  strAL + "\xcc" + strR,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   len(strAL),
+	}, {
+		in:  "\xcc" + strR,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   0,
+	}},
+
+	// Rule 2.1: The first character must be a character with Bidi property L,
+	// R, or AL.  If it has the R or AL property, it is an RTL label; if it has
+	// the L property, it is an LTR label.
+	1: []ruleTest{{
+		in:  strL,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAN,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+	}, {
+		in:  strEN,
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   len(strEN),
+	}, {
+		in:  strES,
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   len(strES),
+	}, {
+		in:  strET,
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   len(strET),
+	}, {
+		in:  strCS,
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   len(strCS),
+	}, {
+		in:  strNSM,
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   len(strNSM),
+	}, {
+		in:  strBN,
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   len(strBN),
+	}, {
+		in:  strB,
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   len(strB),
+	}, {
+		in:  strS,
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   len(strS),
+	}, {
+		in:  strWS,
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   len(strWS),
+	}, {
+		in:  strON,
+		dir: bidi.LeftToRight,
+		err: ErrInvalid,
+		n:   len(strON),
+	}, {
+		in:  strEN + strR,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   3,
+	}, {
+		in:  strES + strR,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   2,
+	}, {
+		in:  strET + strR,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   1,
+	}, {
+		in:  strCS + strR,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   1,
+	}, {
+		in:  strNSM + strR,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   2,
+	}, {
+		in:  strBN + strR,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   3,
+	}, {
+		in:  strB + strR,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   3,
+	}, {
+		in:  strS + strR,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   1,
+	}, {
+		in:  strWS + strR,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   1,
+	}, {
+		in:  strON + strR,
+		dir: bidi.RightToLeft,
+		err: ErrInvalid,
+		n:   1,
+	}},
+
+	// Rule 2.2: In an RTL label, only characters with the Bidi properties R,
+	// AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
+	2: []ruleTest{{
+		in:  strR + strR + strAL,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strAL + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strAN + strAL,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strEN + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strES + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strCS + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strET + strAL,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strON + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strBN + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strNSM + strAL,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strL + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strR),
+		err: ErrInvalid,
+	}, {
+		in:  strR + strB + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strR),
+		err: ErrInvalid,
+	}, {
+		in:  strR + strS + strAL,
+		dir: bidi.RightToLeft,
+		n:   len(strR),
+		err: ErrInvalid,
+	}, {
+		in:  strR + strWS + strAL,
+		dir: bidi.RightToLeft,
+		n:   len(strR),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strR + strAL,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strAL + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strAN + strAL,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strEN + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strES + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strCS + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strET + strAL,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strON + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strBN + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strNSM + strAL,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strL + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strAL),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strB + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strAL),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strS + strAL,
+		dir: bidi.RightToLeft,
+		n:   len(strAL),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strWS + strAL,
+		dir: bidi.RightToLeft,
+		n:   len(strAL),
+		err: ErrInvalid,
+	}},
+
+	// Rule 2.3: In an RTL label, the end of the label must be a character with
+	// Bidi property R, AL, EN, or AN, followed by zero or more characters with
+	// Bidi property NSM.
+	3: []ruleTest{{
+		in:  strR + strNSM,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strAL + strNSM,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strEN + strNSM + strNSM,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strAN,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strR + strES + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strR + strES + strNSM),
+		err: ErrInvalid,
+	}, {
+		in:  strR + strCS + strNSM + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strR + strCS + strNSM + strNSM),
+		err: ErrInvalid,
+	}, {
+		in:  strR + strET,
+		dir: bidi.RightToLeft,
+		n:   len(strR + strET),
+		err: ErrInvalid,
+	}, {
+		in:  strR + strON + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strR + strON + strNSM),
+		err: ErrInvalid,
+	}, {
+		in:  strR + strBN + strNSM + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strR + strBN + strNSM + strNSM),
+		err: ErrInvalid,
+	}, {
+		in:  strR + strL + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strR),
+		err: ErrInvalid,
+	}, {
+		in:  strR + strB + strNSM + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strR),
+		err: ErrInvalid,
+	}, {
+		in:  strR + strS,
+		dir: bidi.RightToLeft,
+		n:   len(strR),
+		err: ErrInvalid,
+	}, {
+		in:  strR + strWS,
+		dir: bidi.RightToLeft,
+		n:   len(strR),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strNSM,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strR,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strAL + strNSM,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strEN + strNSM + strNSM,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strAN,
+		dir: bidi.RightToLeft,
+	}, {
+		in:  strAL + strES + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strAL + strES + strNSM),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strCS + strNSM + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strAL + strCS + strNSM + strNSM),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strET,
+		dir: bidi.RightToLeft,
+		n:   len(strAL + strET),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strON + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strAL + strON + strNSM),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strBN + strNSM + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strAL + strBN + strNSM + strNSM),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strL + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strAL),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strB + strNSM + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strAL),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strS,
+		dir: bidi.RightToLeft,
+		n:   len(strAL),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strWS,
+		dir: bidi.RightToLeft,
+		n:   len(strAL),
+		err: ErrInvalid,
+	}},
+
+	// Rule 2.4: In an RTL label, if an EN is present, no AN may be present,
+	// and vice versa.
+	4: []ruleTest{{
+		in:  strR + strEN + strAN,
+		dir: bidi.RightToLeft,
+		n:   len(strR + strEN),
+		err: ErrInvalid,
+	}, {
+		in:  strR + strAN + strEN + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strR + strAN),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strEN + strAN,
+		dir: bidi.RightToLeft,
+		n:   len(strAL + strEN),
+		err: ErrInvalid,
+	}, {
+		in:  strAL + strAN + strEN + strNSM,
+		dir: bidi.RightToLeft,
+		n:   len(strAL + strAN),
+		err: ErrInvalid,
+	}},
+
+	// Rule 2.5: In an LTR label, only characters with the Bidi properties L,
+	// EN, ES, CS, ET, ON, BN, or NSM are allowed.
+	5: []ruleTest{{
+		in:  strL + strL + strL,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strEN + strL,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strES + strL,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strCS + strL,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strET + strL,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strON + strL,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strBN + strL,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strNSM + strL,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strR + strL,
+		dir: bidi.RightToLeft,
+		n:   len(strL),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strAL + strL,
+		dir: bidi.RightToLeft,
+		n:   len(strL),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strAN + strL,
+		dir: bidi.RightToLeft,
+		n:   len(strL),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strB + strL,
+		dir: bidi.LeftToRight,
+		n:   len(strL + strB + strL),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strB + strL + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strL + strB + strL),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strS + strL,
+		dir: bidi.LeftToRight,
+		n:   len(strL + strS + strL),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strS + strL + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strL + strS + strL),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strWS + strL,
+		dir: bidi.LeftToRight,
+		n:   len(strL + strWS + strL),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strWS + strL + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strL + strWS + strL),
+		err: ErrInvalid,
+	}},
+
+	// Rule 2.6: In an LTR label, the end of the label must be a character with
+	// Bidi property L or EN, followed by zero or more characters with Bidi
+	// property NSM.
+	6: []ruleTest{{
+		in:  strL,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strNSM,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strNSM + strNSM,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strEN,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strEN + strNSM,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strEN + strNSM + strNSM,
+		dir: bidi.LeftToRight,
+	}, {
+		in:  strL + strES,
+		dir: bidi.LeftToRight,
+		n:   len(strL + strES),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strES + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strL + strES),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strCS,
+		dir: bidi.LeftToRight,
+		n:   len(strL + strCS),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strCS + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strL + strCS),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strET,
+		dir: bidi.LeftToRight,
+		n:   len(strL + strET),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strET + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strL + strET),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strON,
+		dir: bidi.LeftToRight,
+		n:   len(strL + strON),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strON + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strL + strON),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strBN,
+		dir: bidi.LeftToRight,
+		n:   len(strL + strBN),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strBN + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strL + strBN),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strL),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strAL,
+		dir: bidi.RightToLeft,
+		n:   len(strL),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strAN,
+		dir: bidi.RightToLeft,
+		n:   len(strL),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strB,
+		dir: bidi.LeftToRight,
+		n:   len(strL + strB),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strB + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strL + strB),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strS,
+		dir: bidi.LeftToRight,
+		n:   len(strL + strS),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strS + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strL + strS),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strWS,
+		dir: bidi.LeftToRight,
+		n:   len(strL + strWS),
+		err: ErrInvalid,
+	}, {
+		in:  strL + strWS + strR,
+		dir: bidi.RightToLeft,
+		n:   len(strL + strWS),
+		err: ErrInvalid,
+	}},
+
+	// Incremental processing.
+	9: []ruleTest{{
+		in:  "e\u0301", // é
+		dir: bidi.LeftToRight,
+
+		pSrc: 2,
+		nSrc: 1,
+		err0: transform.ErrShortSrc,
+	}, {
+		in:  "e\u1000f", // é
+		dir: bidi.LeftToRight,
+
+		pSrc: 3,
+		nSrc: 1,
+		err0: transform.ErrShortSrc,
+	}, {
+		// Remain invalid once invalid.
+		in:  strR + "ab",
+		dir: bidi.RightToLeft,
+		n:   len(strR),
+		err: ErrInvalid,
+
+		pSrc: len(strR) + 1,
+		nSrc: len(strR),
+		err0: ErrInvalid,
+	}, {
+		// Short destination
+		in:  "abcdefghij",
+		dir: bidi.LeftToRight,
+
+		pSrc:  10,
+		szDst: 5,
+		nSrc:  5,
+		err0:  transform.ErrShortDst,
+	}, {
+		in:  "\U000102f7",
+		dir: bidi.LeftToRight,
+		n:   len("\U000102f7"),
+		err: ErrInvalid,
+	}, {
+		// Short destination splitting input rune
+		in:  "e\u0301",
+		dir: bidi.LeftToRight,
+
+		pSrc:  3,
+		szDst: 2,
+		nSrc:  1,
+		err0:  transform.ErrShortDst,
+	}, {
+		// Unicode 10.0.0 IDNA test string.
+		in:  "FAX\u2a77\U0001d186",
+		dir: bidi.LeftToRight,
+		n:   len("FAX\u2a77\U0001d186"),
+		err: ErrInvalid,
+	}, {
+		in:  "\x80\u0660",
+		dir: bidi.RightToLeft,
+		n:   0,
+		err: ErrInvalid,
+	}},
+}
+
+func init() {
+	for rule, cases := range testCases {
+		for i, tc := range cases {
+			if tc.err == nil {
+				testCases[rule][i].n = len(tc.in)
+			}
+		}
+	}
+}
+
+func doTests(t *testing.T, fn func(t *testing.T, tc ruleTest)) {
+	for rule, cases := range testCases {
+		for i, tc := range cases {
+			name := fmt.Sprintf("%d/%d:%+q:%s", rule, i, tc.in, tc.in)
+			testtext.Run(t, name, func(t *testing.T) {
+				fn(t, tc)
+			})
+		}
+	}
+}
+
+func TestDirection(t *testing.T) {
+	doTests(t, func(t *testing.T, tc ruleTest) {
+		dir := Direction([]byte(tc.in))
+		if dir != tc.dir {
+			t.Errorf("dir was %v; want %v", dir, tc.dir)
+		}
+	})
+}
+
+func TestDirectionString(t *testing.T) {
+	doTests(t, func(t *testing.T, tc ruleTest) {
+		dir := DirectionString(tc.in)
+		if dir != tc.dir {
+			t.Errorf("dir was %v; want %v", dir, tc.dir)
+		}
+	})
+}
+
+func TestValid(t *testing.T) {
+	doTests(t, func(t *testing.T, tc ruleTest) {
+		got := Valid([]byte(tc.in))
+		want := tc.err == nil
+		if got != want {
+			t.Fatalf("Valid: got %v; want %v", got, want)
+		}
+
+		got = ValidString(tc.in)
+		want = tc.err == nil
+		if got != want {
+			t.Fatalf("Valid: got %v; want %v", got, want)
+		}
+	})
+}
+
+func TestSpan(t *testing.T) {
+	doTests(t, func(t *testing.T, tc ruleTest) {
+		// Skip tests that test for limited destination buffer size.
+		if tc.szDst > 0 {
+			return
+		}
+
+		r := New()
+		src := []byte(tc.in)
+
+		n, err := r.Span(src[:tc.pSrc], tc.pSrc == len(tc.in))
+		if err != tc.err0 {
+			t.Errorf("err0 was %v; want %v", err, tc.err0)
+		}
+		if n != tc.nSrc {
+			t.Fatalf("nSrc was %d; want %d", n, tc.nSrc)
+		}
+
+		n, err = r.Span(src[n:], true)
+		if err != tc.err {
+			t.Errorf("error was %v; want %v", err, tc.err)
+		}
+		if got := n + tc.nSrc; got != tc.n {
+			t.Errorf("n was %d; want %d", got, tc.n)
+		}
+	})
+}
+
+func TestTransform(t *testing.T) {
+	doTests(t, func(t *testing.T, tc ruleTest) {
+		r := New()
+
+		src := []byte(tc.in)
+		dst := make([]byte, len(tc.in))
+		if tc.szDst > 0 {
+			dst = make([]byte, tc.szDst)
+		}
+
+		// First transform operates on a zero-length string for most tests.
+		nDst, nSrc, err := r.Transform(dst, src[:tc.pSrc], tc.pSrc == len(tc.in))
+		if err != tc.err0 {
+			t.Errorf("err0 was %v; want %v", err, tc.err0)
+		}
+		if nDst != nSrc {
+			t.Fatalf("nDst (%d) and nSrc (%d) should match", nDst, nSrc)
+		}
+		if nSrc != tc.nSrc {
+			t.Fatalf("nSrc was %d; want %d", nSrc, tc.nSrc)
+		}
+
+		dst1 := make([]byte, len(tc.in))
+		copy(dst1, dst[:nDst])
+
+		nDst, nSrc, err = r.Transform(dst1[nDst:], src[nSrc:], true)
+		if err != tc.err {
+			t.Errorf("error was %v; want %v", err, tc.err)
+		}
+		if nDst != nSrc {
+			t.Fatalf("nDst (%d) and nSrc (%d) should match", nDst, nSrc)
+		}
+		n := nSrc + tc.nSrc
+		if n != tc.n {
+			t.Fatalf("n was %d; want %d", n, tc.n)
+		}
+		if got, want := string(dst1[:n]), tc.in[:tc.n]; got != want {
+			t.Errorf("got %+q; want %+q", got, want)
+		}
+	})
+}