github.com/kortschak/utter@v1.5.0/internal_test.go (about)

     1  /*
     2   * Copyright (c) 2013 Dave Collins <dave@davec.name>
     3   * Copyright (c) 2015 Dan Kortschak <dan.kortschak@adelaide.edu.au>
     4   *
     5   * Permission to use, copy, modify, and distribute this software for any
     6   * purpose with or without fee is hereby granted, provided that the above
     7   * copyright notice and this permission notice appear in all copies.
     8   *
     9   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    10   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    11   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    12   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    13   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    14   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    15   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    16   */
    17  
    18  /*
    19  This test file is part of the utter package rather than than the utter_test
    20  package because it needs access to internals to properly test certain cases
    21  which are not possible via the public interface since they should never happen.
    22  */
    23  
    24  package utter
    25  
    26  import (
    27  	"bytes"
    28  	"reflect"
    29  	"testing"
    30  	"unsafe"
    31  )
    32  
    33  // dummyFmtState implements a fake fmt.State to use for testing invalid
    34  // reflect.Value handling.  This is necessary because the fmt package catches
    35  // invalid values before invoking the formatter on them.
    36  type dummyFmtState struct {
    37  	bytes.Buffer
    38  }
    39  
    40  func (dfs *dummyFmtState) Flag(f int) bool {
    41  	return f == int('+')
    42  }
    43  
    44  func (dfs *dummyFmtState) Precision() (int, bool) {
    45  	return 0, false
    46  }
    47  
    48  func (dfs *dummyFmtState) Width() (int, bool) {
    49  	return 0, false
    50  }
    51  
    52  // TestInvalidReflectValue ensures the dump and formatter code handles an
    53  // invalid reflect value properly.  This needs access to internal state since it
    54  // should never happen in real code and therefore can't be tested via the public
    55  // API.
    56  func TestInvalidReflectValue(t *testing.T) {
    57  	i := 1
    58  
    59  	// Dump invalid reflect value.
    60  	v := new(reflect.Value)
    61  	buf := new(bytes.Buffer)
    62  	d := dumpState{w: buf, cs: &Config}
    63  	d.dump(*v, false, true, false, 0)
    64  	s := buf.String()
    65  	want := "<invalid>"
    66  	if s != want {
    67  		t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want)
    68  	}
    69  }
    70  
    71  // changeKind uses unsafe to intentionally change the kind of a reflect.Value to
    72  // the maximum kind value which does not exist.  This is needed to test the
    73  // fallback code which punts to the standard fmt library for new types that
    74  // might get added to the language.
    75  func changeKind(v *reflect.Value, readOnly bool) {
    76  	rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag))
    77  	*rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
    78  	if readOnly {
    79  		*rvf |= flagRO
    80  	} else {
    81  		*rvf &= ^uintptr(flagRO)
    82  	}
    83  }
    84  
    85  // TestAddedReflectValue tests functionaly of the dump and formatter code which
    86  // falls back to the standard fmt library for new types that might get added to
    87  // the language.
    88  func TestAddedReflectValue(t *testing.T) {
    89  	i := 1
    90  
    91  	// Dump using a reflect.Value that is exported.
    92  	v := reflect.ValueOf(int8(5))
    93  	changeKind(&v, false)
    94  	buf := new(bytes.Buffer)
    95  	d := dumpState{w: buf, cs: &Config}
    96  	d.dump(v, false, true, false, 0)
    97  	s := buf.String()
    98  	want := "int8(5)"
    99  	if s != want {
   100  		t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
   101  	}
   102  	i++
   103  
   104  	// Dump using a reflect.Value that is not exported.
   105  	changeKind(&v, true)
   106  	buf.Reset()
   107  	d.dump(v, false, true, false, 0)
   108  	s = buf.String()
   109  	want = "int8(<int8 Value>)"
   110  	if s != want {
   111  		t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
   112  	}
   113  }
   114  
   115  // SortMapByKeyVals makes the internal sortMapByKeyVals function available
   116  // to the test package.
   117  func SortMapByKeyVals(keys, vals []reflect.Value) {
   118  	sortMapByKeyVals(keys, vals)
   119  }