...

Source file src/golang.org/x/text/unicode/bidi/core_test.go

Documentation: golang.org/x/text/unicode/bidi

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package bidi
     6  
     7  import (
     8  	"flag"
     9  	"fmt"
    10  	"log"
    11  	"strconv"
    12  	"strings"
    13  	"testing"
    14  
    15  	"golang.org/x/text/internal/gen"
    16  	"golang.org/x/text/internal/testtext"
    17  	"golang.org/x/text/internal/ucd"
    18  	"golang.org/x/text/unicode/norm"
    19  )
    20  
    21  var testLevels = flag.Bool("levels", false, "enable testing of levels")
    22  
    23  // TestBidiCore performs the tests in BidiTest.txt.
    24  // See https://www.unicode.org/Public/UCD/latest/ucd/BidiTest.txt.
    25  func TestBidiCore(t *testing.T) {
    26  	testtext.SkipIfNotLong(t)
    27  
    28  	r := gen.OpenUCDFile("BidiTest.txt")
    29  	defer r.Close()
    30  
    31  	var wantLevels, wantOrder []string
    32  	p := ucd.New(r, ucd.Part(func(p *ucd.Parser) {
    33  		s := strings.Split(p.String(0), ":")
    34  		switch s[0] {
    35  		case "Levels":
    36  			wantLevels = strings.Fields(s[1])
    37  		case "Reorder":
    38  			wantOrder = strings.Fields(s[1])
    39  		default:
    40  			log.Fatalf("Unknown part %q.", s[0])
    41  		}
    42  	}))
    43  
    44  	for p.Next() {
    45  		types := []Class{}
    46  		for _, s := range p.Strings(0) {
    47  			types = append(types, bidiClass[s])
    48  		}
    49  		// We ignore the bracketing part of the algorithm.
    50  		pairTypes := make([]bracketType, len(types))
    51  		pairValues := make([]rune, len(types))
    52  
    53  		for i := uint(0); i < 3; i++ {
    54  			if p.Uint(1)&(1<<i) == 0 {
    55  				continue
    56  			}
    57  			lev := level(int(i) - 1)
    58  			par, err := newParagraph(types, pairTypes, pairValues, lev)
    59  			if err != nil {
    60  				t.Error(err)
    61  			}
    62  
    63  			if *testLevels {
    64  				levels := par.getLevels([]int{len(types)})
    65  				for i, s := range wantLevels {
    66  					if s == "x" {
    67  						continue
    68  					}
    69  					l, _ := strconv.ParseUint(s, 10, 8)
    70  					if level(l)&1 != levels[i]&1 {
    71  						t.Errorf("%s:%d:levels: got %v; want %v", p.String(0), lev, levels, wantLevels)
    72  						break
    73  					}
    74  				}
    75  			}
    76  
    77  			order := par.getReordering([]int{len(types)})
    78  			gotOrder := filterOrder(types, order)
    79  			if got, want := fmt.Sprint(gotOrder), fmt.Sprint(wantOrder); got != want {
    80  				t.Errorf("%s:%d:order: got %v; want %v\noriginal %v", p.String(0), lev, got, want, order)
    81  			}
    82  		}
    83  	}
    84  	if err := p.Err(); err != nil {
    85  		log.Fatal(err)
    86  	}
    87  }
    88  
    89  var removeClasses = map[Class]bool{
    90  	LRO: true,
    91  	RLO: true,
    92  	RLE: true,
    93  	LRE: true,
    94  	PDF: true,
    95  	BN:  true,
    96  }
    97  
    98  // TestBidiCharacters performs the tests in BidiCharacterTest.txt.
    99  // See https://www.unicode.org/Public/UCD/latest/ucd/BidiCharacterTest.txt
   100  func TestBidiCharacters(t *testing.T) {
   101  	testtext.SkipIfNotLong(t)
   102  
   103  	ucd.Parse(gen.OpenUCDFile("BidiCharacterTest.txt"), func(p *ucd.Parser) {
   104  		var (
   105  			types      []Class
   106  			pairTypes  []bracketType
   107  			pairValues []rune
   108  			parLevel   level
   109  
   110  			wantLevel       = level(p.Int(2))
   111  			wantLevels      = p.Strings(3)
   112  			wantVisualOrder = p.Strings(4)
   113  		)
   114  
   115  		switch l := p.Int(1); l {
   116  		case 0, 1:
   117  			parLevel = level(l)
   118  		case 2:
   119  			parLevel = implicitLevel
   120  		default:
   121  			// Spec says to ignore unknown parts.
   122  		}
   123  
   124  		runes := p.Runes(0)
   125  
   126  		for _, r := range runes {
   127  			// Assign the bracket type.
   128  			if d := norm.NFKD.PropertiesString(string(r)).Decomposition(); d != nil {
   129  				r = []rune(string(d))[0]
   130  			}
   131  			p, _ := LookupRune(r)
   132  
   133  			// Assign the class for this rune.
   134  			types = append(types, p.Class())
   135  
   136  			switch {
   137  			case !p.IsBracket():
   138  				pairTypes = append(pairTypes, bpNone)
   139  				pairValues = append(pairValues, 0)
   140  			case p.IsOpeningBracket():
   141  				pairTypes = append(pairTypes, bpOpen)
   142  				pairValues = append(pairValues, r)
   143  			default:
   144  				pairTypes = append(pairTypes, bpClose)
   145  				pairValues = append(pairValues, p.reverseBracket(r))
   146  			}
   147  		}
   148  		par, err := newParagraph(types, pairTypes, pairValues, parLevel)
   149  		if err != nil {
   150  			t.Error(err)
   151  		}
   152  
   153  		// Test results:
   154  		if got := par.embeddingLevel; got != wantLevel {
   155  			t.Errorf("%v:level: got %d; want %d", string(runes), got, wantLevel)
   156  		}
   157  
   158  		if *testLevels {
   159  			gotLevels := getLevelStrings(types, par.getLevels([]int{len(types)}))
   160  			if got, want := fmt.Sprint(gotLevels), fmt.Sprint(wantLevels); got != want {
   161  				t.Errorf("%04X %q:%d: got %v; want %v\nval: %x\npair: %v", runes, string(runes), parLevel, got, want, pairValues, pairTypes)
   162  			}
   163  		}
   164  
   165  		order := par.getReordering([]int{len(types)})
   166  		order = filterOrder(types, order)
   167  		if got, want := fmt.Sprint(order), fmt.Sprint(wantVisualOrder); got != want {
   168  			t.Errorf("%04X %q:%d: got %v; want %v\ngot order: %s", runes, string(runes), parLevel, got, want, reorder(runes, order))
   169  		}
   170  	})
   171  }
   172  
   173  func getLevelStrings(cl []Class, levels []level) []string {
   174  	var results []string
   175  	for i, l := range levels {
   176  		if !removeClasses[cl[i]] {
   177  			results = append(results, fmt.Sprint(l))
   178  		} else {
   179  			results = append(results, "x")
   180  		}
   181  	}
   182  	return results
   183  }
   184  
   185  func filterOrder(cl []Class, order []int) []int {
   186  	no := []int{}
   187  	for _, o := range order {
   188  		if !removeClasses[cl[o]] {
   189  			no = append(no, o)
   190  		}
   191  	}
   192  	return no
   193  }
   194  
   195  func reorder(r []rune, order []int) string {
   196  	nr := make([]rune, len(order))
   197  	for i, o := range order {
   198  		nr[i] = r[o]
   199  	}
   200  	return string(nr)
   201  }
   202  
   203  // bidiClass names and codes taken from class "bc" in
   204  // https://www.unicode.org/Public/8.0.0/ucd/PropertyValueAliases.txt
   205  var bidiClass = map[string]Class{
   206  	"AL":  AL,  // classArabicLetter,
   207  	"AN":  AN,  // classArabicNumber,
   208  	"B":   B,   // classParagraphSeparator,
   209  	"BN":  BN,  // classBoundaryNeutral,
   210  	"CS":  CS,  // classCommonSeparator,
   211  	"EN":  EN,  // classEuropeanNumber,
   212  	"ES":  ES,  // classEuropeanSeparator,
   213  	"ET":  ET,  // classEuropeanTerminator,
   214  	"L":   L,   // classLeftToRight,
   215  	"NSM": NSM, // classNonspacingMark,
   216  	"ON":  ON,  // classOtherNeutral,
   217  	"R":   R,   // classRightToLeft,
   218  	"S":   S,   // classSegmentSeparator,
   219  	"WS":  WS,  // classWhiteSpace,
   220  
   221  	"LRO": LRO, // classLeftToRightOverride,
   222  	"RLO": RLO, // classRightToLeftOverride,
   223  	"LRE": LRE, // classLeftToRightEmbedding,
   224  	"RLE": RLE, // classRightToLeftEmbedding,
   225  	"PDF": PDF, // classPopDirectionalFormat,
   226  	"LRI": LRI, // classLeftToRightIsolate,
   227  	"RLI": RLI, // classRightToLeftIsolate,
   228  	"FSI": FSI, // classFirstStrongIsolate,
   229  	"PDI": PDI, // classPopDirectionalIsolate,
   230  }
   231  

View as plain text