...

Source file src/github.com/gofrs/uuid/codec_test.go

Documentation: github.com/gofrs/uuid

     1  // Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining
     4  // a copy of this software and associated documentation files (the
     5  // "Software"), to deal in the Software without restriction, including
     6  // without limitation the rights to use, copy, modify, merge, publish,
     7  // distribute, sublicense, and/or sell copies of the Software, and to
     8  // permit persons to whom the Software is furnished to do so, subject to
     9  // the following conditions:
    10  //
    11  // The above copyright notice and this permission notice shall be
    12  // included in all copies or substantial portions of the Software.
    13  //
    14  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    15  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    16  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    17  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    18  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    19  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    20  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    21  
    22  package uuid
    23  
    24  import (
    25  	"bytes"
    26  	"flag"
    27  	"fmt"
    28  	"io/ioutil"
    29  	"os"
    30  	"path/filepath"
    31  	"testing"
    32  )
    33  
    34  // codecTestData holds []byte data for a UUID we commonly use for testing.
    35  var codecTestData = []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
    36  
    37  // codecTestUUID is the UUID value corresponding to codecTestData.
    38  var codecTestUUID = UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
    39  
    40  func TestFromBytes(t *testing.T) {
    41  	t.Run("Valid", func(t *testing.T) {
    42  		got, err := FromBytes(codecTestData)
    43  		if err != nil {
    44  			t.Fatal(err)
    45  		}
    46  		if got != codecTestUUID {
    47  			t.Fatalf("FromBytes(%x) = %v, want %v", codecTestData, got, codecTestUUID)
    48  		}
    49  	})
    50  	t.Run("Invalid", func(t *testing.T) {
    51  		var short [][]byte
    52  		for i := 0; i < len(codecTestData); i++ {
    53  			short = append(short, codecTestData[:i])
    54  		}
    55  		var long [][]byte
    56  		for i := 1; i < 17; i++ {
    57  			tmp := append(codecTestData, make([]byte, i)...)
    58  			long = append(long, tmp)
    59  		}
    60  		invalid := append(short, long...)
    61  		for _, b := range invalid {
    62  			got, err := FromBytes(b)
    63  			if err == nil {
    64  				t.Fatalf("FromBytes(%x): want err != nil, got %v", b, got)
    65  			}
    66  		}
    67  	})
    68  }
    69  
    70  func TestFromBytesOrNil(t *testing.T) {
    71  	t.Run("Invalid", func(t *testing.T) {
    72  		b := []byte{4, 8, 15, 16, 23, 42}
    73  		got := FromBytesOrNil(b)
    74  		if got != Nil {
    75  			t.Errorf("FromBytesOrNil(%x): got %v, want %v", b, got, Nil)
    76  		}
    77  	})
    78  	t.Run("Valid", func(t *testing.T) {
    79  		got := FromBytesOrNil(codecTestData)
    80  		if got != codecTestUUID {
    81  			t.Errorf("FromBytesOrNil(%x): got %v, want %v", codecTestData, got, codecTestUUID)
    82  		}
    83  	})
    84  
    85  }
    86  
    87  type fromStringTest struct {
    88  	input   string
    89  	variant string
    90  }
    91  
    92  // Run runs the FromString test in a subtest of t, named by fst.variant.
    93  func (fst fromStringTest) Run(t *testing.T) {
    94  	t.Run(fst.variant, func(t *testing.T) {
    95  		got, err := FromString(fst.input)
    96  		if err != nil {
    97  			t.Fatalf("FromString(%q): %v", fst.input, err)
    98  		}
    99  		if want := codecTestUUID; got != want {
   100  			t.Fatalf("FromString(%q) = %v, want %v", fst.input, got, want)
   101  		}
   102  	})
   103  }
   104  
   105  // fromStringTests contains UUID variants that are expected to be parsed
   106  // successfully by UnmarshalText / FromString.
   107  //
   108  // variants must be unique across elements of this slice. Please see the
   109  // comment in fuzz.go if you change this slice or add new tests to it.
   110  var fromStringTests = []fromStringTest{
   111  	{
   112  		input:   "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
   113  		variant: "Canonical",
   114  	},
   115  	{
   116  		input:   "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
   117  		variant: "BracedCanonical",
   118  	},
   119  	{
   120  		input:   "{6ba7b8109dad11d180b400c04fd430c8}",
   121  		variant: "BracedHashlike",
   122  	},
   123  	{
   124  		input:   "6ba7b8109dad11d180b400c04fd430c8",
   125  		variant: "Hashlike",
   126  	},
   127  	{
   128  		input:   "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8",
   129  		variant: "URNCanonical",
   130  	},
   131  	{
   132  		input:   "urn:uuid:6ba7b8109dad11d180b400c04fd430c8",
   133  		variant: "URNHashlike",
   134  	},
   135  }
   136  
   137  var invalidFromStringInputs = []string{
   138  	// short
   139  	"6ba7b810-9dad-11d1-80b4-00c04fd430c",
   140  	"6ba7b8109dad11d180b400c04fd430c",
   141  
   142  	// invalid hex
   143  	"6ba7b8109dad11d180b400c04fd430q8",
   144  
   145  	// long
   146  	"6ba7b810-9dad-11d1-80b4-00c04fd430c8=",
   147  	"6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
   148  	"{6ba7b810-9dad-11d1-80b4-00c04fd430c8}f",
   149  	"6ba7b810-9dad-11d1-80b4-00c04fd430c800c04fd430c8",
   150  
   151  	// malformed in other ways
   152  	"ba7b8109dad11d180b400c04fd430c8}",
   153  	"6ba7b8109dad11d180b400c04fd430c86ba7b8109dad11d180b400c04fd430c8",
   154  	"urn:uuid:{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
   155  	"uuid:urn:6ba7b810-9dad-11d1-80b4-00c04fd430c8",
   156  	"uuid:urn:6ba7b8109dad11d180b400c04fd430c8",
   157  	"6ba7b8109-dad-11d1-80b4-00c04fd430c8",
   158  	"6ba7b810-9dad1-1d1-80b4-00c04fd430c8",
   159  	"6ba7b810-9dad-11d18-0b4-00c04fd430c8",
   160  	"6ba7b810-9dad-11d1-80b40-0c04fd430c8",
   161  	"6ba7b810+9dad+11d1+80b4+00c04fd430c8",
   162  	"(6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
   163  	"{6ba7b810-9dad-11d1-80b4-00c04fd430c8>",
   164  	"zba7b810-9dad-11d1-80b4-00c04fd430c8",
   165  	"6ba7b810-9dad11d180b400c04fd430c8",
   166  	"6ba7b8109dad-11d180b400c04fd430c8",
   167  	"6ba7b8109dad11d1-80b400c04fd430c8",
   168  	"6ba7b8109dad11d180b4-00c04fd430c8",
   169  }
   170  
   171  func TestFromString(t *testing.T) {
   172  	t.Run("Valid", func(t *testing.T) {
   173  		for _, fst := range fromStringTests {
   174  			fst.Run(t)
   175  		}
   176  	})
   177  	t.Run("Invalid", func(t *testing.T) {
   178  		for _, s := range invalidFromStringInputs {
   179  			got, err := FromString(s)
   180  			if err == nil {
   181  				t.Errorf("FromString(%q): want err != nil, got %v", s, got)
   182  			}
   183  		}
   184  	})
   185  }
   186  
   187  func TestFromStringOrNil(t *testing.T) {
   188  	t.Run("Invalid", func(t *testing.T) {
   189  		s := "bad"
   190  		got := FromStringOrNil(s)
   191  		if got != Nil {
   192  			t.Errorf("FromStringOrNil(%q): got %v, want Nil", s, got)
   193  		}
   194  	})
   195  	t.Run("Valid", func(t *testing.T) {
   196  		s := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
   197  		got := FromStringOrNil(s)
   198  		if got != codecTestUUID {
   199  			t.Errorf("FromStringOrNil(%q): got %v, want %v", s, got, codecTestUUID)
   200  		}
   201  	})
   202  }
   203  
   204  func TestMarshalBinary(t *testing.T) {
   205  	got, err := codecTestUUID.MarshalBinary()
   206  	if err != nil {
   207  		t.Fatal(err)
   208  	}
   209  	if !bytes.Equal(got, codecTestData) {
   210  		t.Fatalf("%v.MarshalBinary() = %x, want %x", codecTestUUID, got, codecTestData)
   211  	}
   212  }
   213  
   214  func TestMarshalText(t *testing.T) {
   215  	want := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
   216  	got, err := codecTestUUID.MarshalText()
   217  	if err != nil {
   218  		t.Fatal(err)
   219  	}
   220  	if !bytes.Equal(got, want) {
   221  		t.Errorf("%v.MarshalText(): got %s, want %s", codecTestUUID, got, want)
   222  	}
   223  }
   224  
   225  func TestDecodePlainWithWrongLength(t *testing.T) {
   226  	arg := []byte{'4', '2'}
   227  
   228  	u := UUID{}
   229  
   230  	if u.decodePlain(arg) == nil {
   231  		t.Errorf("%v.decodePlain(%q): should return error, but it did not", u, arg)
   232  	}
   233  }
   234  
   235  var stringBenchmarkSink string
   236  
   237  func BenchmarkString(b *testing.B) {
   238  	for i := 0; i < b.N; i++ {
   239  		stringBenchmarkSink = codecTestUUID.String()
   240  	}
   241  }
   242  
   243  func BenchmarkFromBytes(b *testing.B) {
   244  	for i := 0; i < b.N; i++ {
   245  		FromBytes(codecTestData)
   246  	}
   247  }
   248  
   249  func BenchmarkFromString(b *testing.B) {
   250  	b.Run("canonical", func(b *testing.B) {
   251  		for i := 0; i < b.N; i++ {
   252  			FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
   253  		}
   254  	})
   255  	b.Run("urn", func(b *testing.B) {
   256  		for i := 0; i < b.N; i++ {
   257  			FromString("urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8")
   258  		}
   259  	})
   260  	b.Run("braced", func(b *testing.B) {
   261  		for i := 0; i < b.N; i++ {
   262  			FromString("{6ba7b810-9dad-11d1-80b4-00c04fd430c8}")
   263  		}
   264  	})
   265  }
   266  
   267  func BenchmarkMarshalBinary(b *testing.B) {
   268  	for i := 0; i < b.N; i++ {
   269  		codecTestUUID.MarshalBinary()
   270  	}
   271  }
   272  
   273  func BenchmarkMarshalText(b *testing.B) {
   274  	for i := 0; i < b.N; i++ {
   275  		codecTestUUID.MarshalText()
   276  	}
   277  }
   278  
   279  var seedFuzzCorpus = flag.Bool("seed_fuzz_corpus", false, "seed fuzz test corpus")
   280  
   281  func TestSeedFuzzCorpus(t *testing.T) {
   282  	// flag.Parse() is called for us by the test binary.
   283  	if !*seedFuzzCorpus {
   284  		t.Skip("seeding fuzz test corpus only on demand")
   285  	}
   286  	corpusDir := filepath.Join(".", "testdata", "corpus")
   287  	writeSeedFile := func(name, data string) error {
   288  		path := filepath.Join(corpusDir, name)
   289  		return ioutil.WriteFile(path, []byte(data), os.ModePerm)
   290  	}
   291  	for _, fst := range fromStringTests {
   292  		name := "seed_valid_" + fst.variant
   293  		if err := writeSeedFile(name, fst.input); err != nil {
   294  			t.Fatal(err)
   295  		}
   296  	}
   297  	for i, s := range invalidFromStringInputs {
   298  		name := fmt.Sprintf("seed_invalid_%d", i)
   299  		if err := writeSeedFile(name, s); err != nil {
   300  			t.Fatal(err)
   301  		}
   302  	}
   303  }
   304  

View as plain text