github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/internal/binres/binres_test.go (about)

     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 binres
     6  
     7  import (
     8  	"archive/zip"
     9  	"bytes"
    10  	"encoding"
    11  	"encoding/xml"
    12  	"fmt"
    13  	"io"
    14  	"io/ioutil"
    15  	"log"
    16  	"math"
    17  	"os"
    18  	"sort"
    19  	"strings"
    20  	"testing"
    21  )
    22  
    23  func printrecurse(t *testing.T, pl *Pool, el *Element, ws string) {
    24  	for _, attr := range el.attrs {
    25  		ns := ""
    26  		if attr.NS != math.MaxUint32 {
    27  			ns = pl.strings[int(attr.NS)]
    28  			nss := strings.Split(ns, "/")
    29  			ns = nss[len(nss)-1]
    30  		}
    31  
    32  		val := ""
    33  		if attr.RawValue != math.MaxUint32 {
    34  			val = pl.strings[int(attr.RawValue)]
    35  		} else {
    36  			switch attr.TypedValue.Type {
    37  			case DataIntDec:
    38  				val = fmt.Sprintf("%v", attr.TypedValue.Value)
    39  			case DataIntBool:
    40  				val = fmt.Sprintf("%v", attr.TypedValue.Value == 1)
    41  			default:
    42  				val = fmt.Sprintf("0x%08X", attr.TypedValue.Value)
    43  			}
    44  		}
    45  		dt := attr.TypedValue.Type
    46  
    47  		t.Logf("%s|attr:ns(%v) name(%s) val(%s) valtyp(%s)\n", ws, ns, pl.strings[int(attr.Name)], val, dt)
    48  	}
    49  	t.Log()
    50  	for _, e := range el.Children {
    51  		printrecurse(t, pl, e, ws+"        ")
    52  	}
    53  }
    54  
    55  func TestBootstrap(t *testing.T) {
    56  	bin, err := ioutil.ReadFile("testdata/bootstrap.bin")
    57  	if err != nil {
    58  		log.Fatal(err)
    59  	}
    60  
    61  	checkMarshal := func(res encoding.BinaryMarshaler, bsize int) {
    62  		b, err := res.MarshalBinary()
    63  		if err != nil {
    64  			t.Error(err)
    65  		}
    66  		idx := debugIndices[res]
    67  		a := bin[idx : idx+bsize]
    68  		if !bytes.Equal(a, b) {
    69  			x, y := len(a), len(b)
    70  			if x != y {
    71  				t.Errorf("%v: %T: byte length does not match, have %v, want %v", idx, res, y, x)
    72  			}
    73  			if x > y {
    74  				x, y = y, x
    75  			}
    76  			mismatch := false
    77  			for i := 0; i < x; i++ {
    78  				if mismatch = a[i] != b[i]; mismatch {
    79  					t.Errorf("%v: %T: first byte mismatch at %v of %v", idx, res, i, bsize)
    80  					break
    81  				}
    82  			}
    83  			if mismatch {
    84  				// print out a reasonable amount of data to help identify issues
    85  				truncate := x > 1300
    86  				if truncate {
    87  					x = 1300
    88  				}
    89  				t.Log("      HAVE               WANT")
    90  				for i := 0; i < x; i += 4 {
    91  					he, we := 4, 4
    92  					if i+he >= x {
    93  						he = x - i
    94  					}
    95  					if i+we >= y {
    96  						we = y - i
    97  					}
    98  					t.Logf("%3v | % X        % X\n", i, b[i:i+he], a[i:i+we])
    99  				}
   100  				if truncate {
   101  					t.Log("... output truncated.")
   102  				}
   103  			}
   104  		}
   105  	}
   106  
   107  	bxml := new(XML)
   108  	if err := bxml.UnmarshalBinary(bin); err != nil {
   109  		t.Fatal(err)
   110  	}
   111  
   112  	for i, x := range bxml.Pool.strings {
   113  		t.Logf("Pool(%v): %q\n", i, x)
   114  	}
   115  
   116  	for _, e := range bxml.Children {
   117  		printrecurse(t, bxml.Pool, e, "")
   118  	}
   119  
   120  	checkMarshal(&bxml.chunkHeader, int(bxml.headerByteSize))
   121  	checkMarshal(bxml.Pool, bxml.Pool.size())
   122  	checkMarshal(bxml.Map, bxml.Map.size())
   123  	checkMarshal(bxml.Namespace, bxml.Namespace.size())
   124  
   125  	for el := range bxml.iterElements() {
   126  		checkMarshal(el, el.size())
   127  		checkMarshal(el.end, el.end.size())
   128  	}
   129  
   130  	checkMarshal(bxml.Namespace.end, bxml.Namespace.end.size())
   131  	checkMarshal(bxml, bxml.size())
   132  }
   133  
   134  func retset(xs []string) []string {
   135  	m := make(map[string]struct{})
   136  	fo := xs[:0]
   137  	for _, x := range xs {
   138  		if x == "" {
   139  			continue
   140  		}
   141  		if _, ok := m[x]; !ok {
   142  			m[x] = struct{}{}
   143  			fo = append(fo, x)
   144  		}
   145  	}
   146  	return fo
   147  }
   148  
   149  type ByNamespace []xml.Attr
   150  
   151  func (a ByNamespace) Len() int      { return len(a) }
   152  func (a ByNamespace) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
   153  func (a ByNamespace) Less(i, j int) bool {
   154  	if a[j].Name.Space == "" {
   155  		return a[i].Name.Space != ""
   156  	}
   157  	return false
   158  }
   159  
   160  // WIP approximation of first steps to be taken to encode manifest
   161  func TestEncode(t *testing.T) {
   162  	f, err := os.Open("testdata/bootstrap.xml")
   163  	if err != nil {
   164  		t.Fatal(err)
   165  	}
   166  
   167  	var attrs []xml.Attr
   168  
   169  	dec := xml.NewDecoder(f)
   170  	for {
   171  		tkn, err := dec.Token()
   172  		if err != nil {
   173  			if err == io.EOF {
   174  				break
   175  			}
   176  			return
   177  			// t.Fatal(err)
   178  		}
   179  		tkn = xml.CopyToken(tkn)
   180  
   181  		switch tkn := tkn.(type) {
   182  		case xml.StartElement:
   183  			attrs = append(attrs, tkn.Attr...)
   184  		default:
   185  			// t.Error("unhandled token type", tkn)
   186  		}
   187  	}
   188  
   189  	bvc := xml.Attr{
   190  		Name: xml.Name{
   191  			Space: "",
   192  			Local: "platformBuildVersionCode",
   193  		},
   194  		Value: "10",
   195  	}
   196  	bvn := xml.Attr{
   197  		Name: xml.Name{
   198  			Space: "",
   199  			Local: "platformBuildVersionName",
   200  		},
   201  		Value: "2.3.3",
   202  	}
   203  	attrs = append(attrs, bvc, bvn)
   204  
   205  	sort.Sort(ByNamespace(attrs))
   206  	var names, vals []string
   207  	for _, attr := range attrs {
   208  		if strings.HasSuffix(attr.Name.Space, "tools") {
   209  			continue
   210  		}
   211  		names = append(names, attr.Name.Local)
   212  		vals = append(vals, attr.Value)
   213  	}
   214  
   215  	var all []string
   216  	all = append(all, names...)
   217  	all = append(all, vals...)
   218  
   219  	// do not eliminate duplicates until the entire slice has been composed.
   220  	// consider <activity android:label="label" .../>
   221  	// all attribute names come first followed by values; in such a case, the value "label"
   222  	// would be a reference to the same "android:label" in the string pool which will occur
   223  	// within the beginning of the pool where other attr names are located.
   224  	pl := new(Pool)
   225  	for _, x := range retset(all) {
   226  		pl.strings = append(pl.strings, x)
   227  		// t.Logf("Pool(%v) %q\n", i, x)
   228  	}
   229  }
   230  
   231  func TestAndroidJar(t *testing.T) {
   232  	zr, err := zip.OpenReader("/home/daniel/local/android-sdk/platforms/android-10/android.jar")
   233  	if err != nil {
   234  		t.Fatal(err)
   235  	}
   236  	defer zr.Close()
   237  
   238  	buf := new(bytes.Buffer)
   239  	for _, f := range zr.File {
   240  		if f.Name == "resources.arsc" {
   241  			rc, err := f.Open()
   242  			if err != nil {
   243  				t.Fatal(err)
   244  			}
   245  			_, err = io.Copy(buf, rc)
   246  			if err != nil {
   247  				t.Fatal(err)
   248  			}
   249  			rc.Close()
   250  			break
   251  		}
   252  	}
   253  	if buf.Len() == 0 {
   254  		t.Fatal("failed to read resources.arsc")
   255  	}
   256  
   257  	bin := buf.Bytes()
   258  
   259  	tbl := &Table{}
   260  	if err := tbl.UnmarshalBinary(bin); err != nil {
   261  		t.Fatal(err)
   262  	}
   263  
   264  	t.Logf("%+v\n", tbl.TableHeader)
   265  	t.Logf("%+v\n", tbl.pool.chunkHeader)
   266  	for i, x := range tbl.pool.strings[:10] {
   267  		t.Logf("pool(%v) %s\n", i, x)
   268  	}
   269  
   270  	t.Logf("%+v\n", tbl.pkg)
   271  }