Repository: elliotchance/pie
Pull request #156 (2019-05-27 12:17:05)

add shift and unshift func
add shift and unshift func, see [detail](https://github.com/elliotchance/pie/issues/37)

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/elliotchance/pie/156)
<!-- Reviewable:end -->


codecov-io: # [Codecov](https://codecov.io/gh/elliotchance/pie/pull/156?src=pr&el=h1) Report
> Merging [#156](https://codecov.io/gh/elliotchance/pie/pull/156?src=pr&el=desc) into [master](https://codecov.io/gh/elliotchance/pie/commit/290807a9f9a2fd5c18ba5ec4505f7dae40da2769?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/elliotchance/pie/pull/156/graphs/tree.svg?width=650&token=OvugwUQGM3&height=150&src=pr)](https://codecov.io/gh/elliotchance/pie/pull/156?src=pr&el=tree)

```diff
@@          Coverage Diff          @@
##           master   #156   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           8      8           
  Lines        1643   1673   +30     
=====================================
+ Hits         1643   1673   +30
```


| [Impacted Files](https://codecov.io/gh/elliotchance/pie/pull/156?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pie/float64s\_pie.go](https://codecov.io/gh/elliotchance/pie/pull/156/diff?src=pr&el=tree#diff-cGllL2Zsb2F0NjRzX3BpZS5nbw==) | `100% <100%> (ø)` | :arrow_up: |
| [pie/carpointers\_pie.go](https://codecov.io/gh/elliotchance/pie/pull/156/diff?src=pr&el=tree#diff-cGllL2NhcnBvaW50ZXJzX3BpZS5nbw==) | `100% <100%> (ø)` | :arrow_up: |
| [pie/cars\_pie.go](https://codecov.io/gh/elliotchance/pie/pull/156/diff?src=pr&el=tree#diff-cGllL2NhcnNfcGllLmdv) | `100% <100%> (ø)` | :arrow_up: |
| [pie/ints\_pie.go](https://codecov.io/gh/elliotchance/pie/pull/156/diff?src=pr&el=tree#diff-cGllL2ludHNfcGllLmdv) | `100% <100%> (ø)` | :arrow_up: |
| [pie/strings\_pie.go](https://codecov.io/gh/elliotchance/pie/pull/156/diff?src=pr&el=tree#diff-cGllL3N0cmluZ3NfcGllLmdv) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/elliotchance/pie/pull/156?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/elliotchance/pie/pull/156?src=pr&el=footer). Last update [290807a...d90b1ff](https://codecov.io/gh/elliotchance/pie/pull/156?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/README.md b/README.md
index 73928fa..99b96cb 100644
--- a/README.md
+++ b/README.md
@@ -217,6 +217,7 @@ The letters in brackets indicate:
 | [`Send`](#send)                         | ✓      | ✓      | ✓      |      | n        | Send sends elements to channel in normal act it sends all elements but if func canceled it can be less  |
 | [`Sequence`](#sequence)                 |        | ✓      |        |      | n        | Sequence generates all numbers in range or returns nil if params invalid  |
 | [`SequenceUsing`](#sequenceusing)       | ✓      | ✓      | ✓      |      | n        | SequenceUsing generates slice in range using creator function  |
+| [`Shift`](#shift)                       | ✓      | ✓      | ✓      |      | n        | Shift will return two values: the shifted value and the rest slice.  |
 | [`Shuffle`](#shuffle)                   | ✓      | ✓      | ✓      |      | n        | Shuffle returns shuffled slice by your rand.Source  |
 | [`Sort`](#sort)                         | ✓      | ✓      |        |      | n⋅log(n) | Sort works similar to sort.SliceType(). However, unlike sort.SliceType the slice returned will be reallocated as to not modify the input slice.  |
 | [`SortStableUsing`](#sortstableusing)   | ✓      |        | ✓      |      | n⋅log(n) | SortStableUsing works similar to sort.SliceStable. However, unlike sort.SliceStable the slice returned will be reallocated as to not modify the input slice.  |
@@ -227,6 +228,7 @@ The letters in brackets indicate:
 | [`Top`](#top)                           | ✓      | ✓      | ✓      |      | n        | Top will return n elements from head of the slice if the slice has less elements then n that'll return all elements if n < 0 it'll return empty slice.  |
 | [`StringsUsing`](#stringsusing)         | ✓      | ✓      | ✓      |      | n        | StringsUsing transforms each element to a string.  |
 | [`Unique`](#unique)                     | ✓      | ✓      |        |      | n        | Unique returns a new slice with all of the unique values.  |
+| [`Unshift`](#unshift)                   | ✓      | ✓      | ✓      |      | n        | Unshift adds one or more elements to the beginning of the slice and returns the new slice.  |
 | [`Values`](#values)                     |        |        |        | ✓    | n        | Values returns the values in the map.  |
 
 ## Abs
@@ -615,6 +617,11 @@ where min is the first param, max is the second, step is the third one, [min, ma
 others params will be ignored
 
 
+## Shift
+
+Shift will return two values: the shifted value and the rest slice.
+
+
 ## Shuffle
 
 Shuffle returns shuffled slice by your rand.Source
@@ -703,6 +710,12 @@ A slice with zero elements is considered to be unique.
 See AreUnique().
 
 
+## Unshift
+
+Unshift adds one or more elements to the beginning of the slice
+and returns the new slice.
+
+
 ## Values
 
 Values returns the values in the map.
diff --git a/functions/main.go b/functions/main.go
index e650658..8c81e99 100644
--- a/functions/main.go
+++ b/functions/main.go
@@ -64,6 +64,7 @@ var Functions = []struct {
 	{"Send", "send.go", ForAll, "n"},
 	{"Sequence", "sequence.go", ForNumbers, "n"},
 	{"SequenceUsing", "sequence_using.go", ForAll, "n"},
+	{"Shift", "shift.go", ForAll, "n"},
 	{"Shuffle", "shuffle.go", ForAll, "n"},
 	{"Sort", "sort.go", ForNumbersAndStrings, "n⋅log(n)"},
 	{"SortStableUsing", "sort_stable_using.go", ForStrings | ForStructs, "n⋅log(n)"},
@@ -74,6 +75,7 @@ var Functions = []struct {
 	{"Top", "top.go", ForAll, "n"},
 	{"StringsUsing", "strings_using.go", ForAll, "n"},
 	{"Unique", "unique.go", ForNumbersAndStrings, "n"},
+	{"Unshift", "unshift.go", ForAll, "n"},
 	{"Values", "values.go", ForMaps, "n"},
 }
 
diff --git a/functions/shift.go b/functions/shift.go
new file mode 100644
index 0000000..613c7a7
--- /dev/null
+++ b/functions/shift.go
@@ -0,0 +1,6 @@
+package functions
+
+// Shift will return two values: the shifted value and the rest slice.
+func (ss SliceType) Shift() (ElementType, SliceType) {
+	return ss.First(), ss.DropTop(1)
+}
diff --git a/functions/unshift.go b/functions/unshift.go
new file mode 100644
index 0000000..ca62e2c
--- /dev/null
+++ b/functions/unshift.go
@@ -0,0 +1,10 @@
+package functions
+
+// Unshift adds one or more elements to the beginning of the slice
+// and returns the new slice.
+func (ss SliceType) Unshift(elements ...ElementType) (unshift SliceType) {
+	unshift = append(SliceType{}, elements...)
+	unshift = append(unshift, ss...)
+
+	return
+}
diff --git a/pie/carpointers_pie.go b/pie/carpointers_pie.go
index 93d92c7..8b67355 100755
--- a/pie/carpointers_pie.go
+++ b/pie/carpointers_pie.go
@@ -510,6 +510,11 @@ func (ss carPointers) SequenceUsing(creator func(int) *car, params ...int) carPo
 	}
 }
 
+// Shift will return two values: the shifted value and the rest slice.
+func (ss carPointers) Shift() (*car, carPointers) {
+	return ss.First(), ss.DropTop(1)
+}
+
 // Shuffle returns shuffled slice by your rand.Source
 func (ss carPointers) Shuffle(source rand.Source) carPointers {
 	n := len(ss)
@@ -653,3 +658,12 @@ func (ss carPointers) StringsUsing(transform func(*car) string) Strings {
 
 	return result
 }
+
+// Unshift adds one or more elements to the beginning of the slice
+// and returns the new slice.
+func (ss carPointers) Unshift(elements ...*car) (unshift carPointers) {
+	unshift = append(carPointers{}, elements...)
+	unshift = append(unshift, ss...)
+
+	return
+}
diff --git a/pie/cars_pie.go b/pie/cars_pie.go
index 5520471..a51f4ce 100755
--- a/pie/cars_pie.go
+++ b/pie/cars_pie.go
@@ -510,6 +510,11 @@ func (ss cars) SequenceUsing(creator func(int) car, params ...int) cars {
 	}
 }
 
+// Shift will return two values: the shifted value and the rest slice.
+func (ss cars) Shift() (car, cars) {
+	return ss.First(), ss.DropTop(1)
+}
+
 // Shuffle returns shuffled slice by your rand.Source
 func (ss cars) Shuffle(source rand.Source) cars {
 	n := len(ss)
@@ -653,3 +658,12 @@ func (ss cars) StringsUsing(transform func(car) string) Strings {
 
 	return result
 }
+
+// Unshift adds one or more elements to the beginning of the slice
+// and returns the new slice.
+func (ss cars) Unshift(elements ...car) (unshift cars) {
+	unshift = append(cars{}, elements...)
+	unshift = append(unshift, ss...)
+
+	return
+}
diff --git a/pie/float64s_pie.go b/pie/float64s_pie.go
index 975b4b9..fc67b8c 100755
--- a/pie/float64s_pie.go
+++ b/pie/float64s_pie.go
@@ -731,6 +731,11 @@ func (ss Float64s) SequenceUsing(creator func(int) float64, params ...int) Float
 	}
 }
 
+// Shift will return two values: the shifted value and the rest slice.
+func (ss Float64s) Shift() (float64, Float64s) {
+	return ss.First(), ss.DropTop(1)
+}
+
 // Shuffle returns shuffled slice by your rand.Source
 func (ss Float64s) Shuffle(source rand.Source) Float64s {
 	n := len(ss)
@@ -898,3 +903,12 @@ func (ss Float64s) Unique() Float64s {
 
 	return uniqueValues
 }
+
+// Unshift adds one or more elements to the beginning of the slice
+// and returns the new slice.
+func (ss Float64s) Unshift(elements ...float64) (unshift Float64s) {
+	unshift = append(Float64s{}, elements...)
+	unshift = append(unshift, ss...)
+
+	return
+}
diff --git a/pie/ints_pie.go b/pie/ints_pie.go
index b7c67d7..d75bcdf 100755
--- a/pie/ints_pie.go
+++ b/pie/ints_pie.go
@@ -731,6 +731,11 @@ func (ss Ints) SequenceUsing(creator func(int) int, params ...int) Ints {
 	}
 }
 
+// Shift will return two values: the shifted value and the rest slice.
+func (ss Ints) Shift() (int, Ints) {
+	return ss.First(), ss.DropTop(1)
+}
+
 // Shuffle returns shuffled slice by your rand.Source
 func (ss Ints) Shuffle(source rand.Source) Ints {
 	n := len(ss)
@@ -898,3 +903,12 @@ func (ss Ints) Unique() Ints {
 
 	return uniqueValues
 }
+
+// Unshift adds one or more elements to the beginning of the slice
+// and returns the new slice.
+func (ss Ints) Unshift(elements ...int) (unshift Ints) {
+	unshift = append(Ints{}, elements...)
+	unshift = append(unshift, ss...)
+
+	return
+}
diff --git a/pie/strings_pie.go b/pie/strings_pie.go
index e398516..8fb1191 100755
--- a/pie/strings_pie.go
+++ b/pie/strings_pie.go
@@ -620,6 +620,11 @@ func (ss Strings) SequenceUsing(creator func(int) string, params ...int) Strings
 	}
 }
 
+// Shift will return two values: the shifted value and the rest slice.
+func (ss Strings) Shift() (string, Strings) {
+	return ss.First(), ss.DropTop(1)
+}
+
 // Shuffle returns shuffled slice by your rand.Source
 func (ss Strings) Shuffle(source rand.Source) Strings {
 	n := len(ss)
@@ -814,3 +819,12 @@ func (ss Strings) Unique() Strings {
 
 	return uniqueValues
 }
+
+// Unshift adds one or more elements to the beginning of the slice
+// and returns the new slice.
+func (ss Strings) Unshift(elements ...string) (unshift Strings) {
+	unshift = append(Strings{}, elements...)
+	unshift = append(unshift, ss...)
+
+	return
+}
diff --git a/template.go b/template.go
index a724d6e..a93e7ca 100644
--- a/template.go
+++ b/template.go
@@ -881,6 +881,13 @@ func (ss SliceType) SequenceUsing(creator func(int) ElementType, params ...int)
 		return nil
 	}
 }
+`,
+	"Shift": `package functions
+
+// Shift will return two values: the shifted value and the rest slice.
+func (ss SliceType) Shift() (ElementType, SliceType) {
+	return ss.First(), ss.DropTop(1)
+}
 `,
 	"Shuffle": `package functions
 
@@ -1130,6 +1137,17 @@ func (ss SliceType) Unique() SliceType {
 
 	return uniqueValues
 }
+`,
+	"Unshift": `package functions
+
+// Unshift adds one or more elements to the beginning of the slice
+// and returns the new slice.
+func (ss SliceType) Unshift(elements ...ElementType) (unshift SliceType) {
+	unshift = append(SliceType{}, elements...)
+	unshift = append(unshift, ss...)
+
+	return
+}
 `,
 	"Values": `package functions
 


Test patch:
diff --git a/pie/carpointers_test.go b/pie/carpointers_test.go
index 8cf680d..f37fc41 100644
--- a/pie/carpointers_test.go
+++ b/pie/carpointers_test.go
@@ -1252,3 +1252,87 @@ func TestCarPointers_Equals(t *testing.T) {
 		})
 	}
 }
+
+var carPointersShiftAndUnshiftTests = []struct {
+	ss      carPointers
+	shifted *car
+	shift   carPointers
+	params  carPointers
+	unshift carPointers
+}{
+	{
+		nil,
+		nil,
+		nil,
+		nil,
+		carPointers{},
+	},
+	{
+		nil,
+		nil,
+		nil,
+		carPointers{},
+		carPointers{},
+	},
+	{
+		nil,
+		nil,
+		nil,
+		carPointers{carPointerA, carPointerB},
+		carPointers{carPointerA, carPointerB},
+	},
+	{
+		carPointers{},
+		nil,
+		nil,
+		nil,
+		carPointers{},
+	},
+	{
+		carPointers{},
+		nil,
+		nil,
+		carPointers{},
+		carPointers{},
+	},
+	{
+		carPointers{},
+		nil,
+		nil,
+		carPointers{carPointerA, carPointerB},
+		carPointers{carPointerA, carPointerB},
+	},
+	{
+		carPointers{carPointerA},
+		carPointerA,
+		nil,
+		carPointers{carPointerB},
+		carPointers{carPointerB, carPointerA},
+	},
+	{
+		carPointers{carPointerA, carPointerB},
+		carPointerA,
+		carPointers{carPointerB},
+		carPointers{carPointerC},
+		carPointers{carPointerC, carPointerA, carPointerB},
+	},
+	{
+		carPointers{carPointerA, carPointerB},
+		carPointerA,
+		carPointers{carPointerB},
+		carPointers{carPointerC, carPointerD},
+		carPointers{carPointerC, carPointerD, carPointerA, carPointerB},
+	},
+}
+
+func TestCarPointers_ShiftAndUnshift(t *testing.T) {
+	for _, test := range carPointersShiftAndUnshiftTests {
+		t.Run("", func(t *testing.T) {
+			defer assertImmutableCarPointers(t, &test.ss)()
+			shifted, shift := test.ss.Shift()
+			assert.Equal(t, test.shifted, shifted)
+			assert.Equal(t, test.shift, shift)
+			assert.Equal(t, test.unshift, test.ss.Unshift(test.params...))
+		})
+	}
+}
diff --git a/pie/cars_test.go b/pie/cars_test.go
index b9f0a4a..66ab8fc 100644
--- a/pie/cars_test.go
+++ b/pie/cars_test.go
@@ -1225,3 +1225,87 @@ func TestCars_Equals(t *testing.T) {
 		})
 	}
 }
+
+var carsShiftAndUnshiftTests = []struct {
+	ss      cars
+	shifted car
+	shift   cars
+	params  cars
+	unshift cars
+}{
+	{
+		nil,
+		car{},
+		nil,
+		nil,
+		cars{},
+	},
+	{
+		nil,
+		car{},
+		nil,
+		cars{},
+		cars{},
+	},
+	{
+		nil,
+		car{},
+		nil,
+		cars{car{"bar", "yellow"}, car{"Baz", "black"}},
+		cars{car{"bar", "yellow"}, car{"Baz", "black"}},
+	},
+	{
+		cars{},
+		car{},
+		nil,
+		nil,
+		cars{},
+	},
+	{
+		cars{},
+		car{},
+		nil,
+		cars{},
+		cars{},
+	},
+	{
+		cars{},
+		car{},
+		nil,
+		cars{car{"bar", "yellow"}, car{"Baz", "black"}},
+		cars{car{"bar", "yellow"}, car{"Baz", "black"}},
+	},
+	{
+		cars{car{"bar", "yellow"}},
+		car{"bar", "yellow"},
+		nil,
+		cars{car{"Baz", "black"}},
+		cars{car{"Baz", "black"}, car{"bar", "yellow"}},
+	},
+	{
+		cars{car{"bar", "yellow"}, car{"Baz", "black"}},
+		car{"bar", "yellow"},
+		cars{car{"Baz", "black"}},
+		cars{car{}},
+		cars{car{}, car{"bar", "yellow"}, car{"Baz", "black"}},
+	},
+	{
+		cars{car{"bar", "yellow"}, car{"Baz", "black"}},
+		car{"bar", "yellow"},
+		cars{car{"Baz", "black"}},
+		cars{car{}, car{"zzz", "blue"}},
+		cars{car{}, car{"zzz", "blue"}, car{"bar", "yellow"}, car{"Baz", "black"}},
+	},
+}
+
+func TestCars_ShiftAndUnshift(t *testing.T) {
+	for _, test := range carsShiftAndUnshiftTests {
+		t.Run("", func(t *testing.T) {
+			defer assertImmutableCars(t, &test.ss)()
+			shifted, shift := test.ss.Shift()
+			assert.Equal(t, test.shifted, shifted)
+			assert.Equal(t, test.shift, shift)
+			assert.Equal(t, test.unshift, test.ss.Unshift(test.params...))
+		})
+	}
+}
diff --git a/pie/float64s_test.go b/pie/float64s_test.go
index 2c0d2f3..4b73933 100644
--- a/pie/float64s_test.go
+++ b/pie/float64s_test.go
@@ -1398,3 +1398,87 @@ func TestFloat64s_Equals(t *testing.T) {
 		})
 	}
 }
+
+var float64sShiftAndUnshiftTests = []struct {
+	ss      Float64s
+	shifted float64
+	shift   Float64s
+	params  Float64s
+	unshift Float64s
+}{
+	{
+		nil,
+		0,
+		nil,
+		nil,
+		Float64s{},
+	},
+	{
+		nil,
+		0,
+		nil,
+		Float64s{},
+		Float64s{},
+	},
+	{
+		nil,
+		0,
+		nil,
+		Float64s{1.23, 2.34},
+		Float64s{1.23, 2.34},
+	},
+	{
+		Float64s{},
+		0,
+		nil,
+		nil,
+		Float64s{},
+	},
+	{
+		Float64s{},
+		0,
+		nil,
+		Float64s{},
+		Float64s{},
+	},
+	{
+		Float64s{},
+		0,
+		nil,
+		Float64s{1.23, 2.34},
+		Float64s{1.23, 2.34},
+	},
+	{
+		Float64s{1.23},
+		1.23,
+		nil,
+		Float64s{2.34},
+		Float64s{2.34, 1.23},
+	},
+	{
+		Float64s{1.23, 2.34},
+		1.23,
+		Float64s{2.34},
+		Float64s{3.45},
+		Float64s{3.45, 1.23, 2.34},
+	},
+	{
+		Float64s{1.23, 2.34},
+		1.23,
+		Float64s{2.34},
+		Float64s{3.45, 4.56},
+		Float64s{3.45, 4.56, 1.23, 2.34},
+	},
+}
+
+func TestFloat64s_ShiftAndUnshift(t *testing.T) {
+	for _, test := range float64sShiftAndUnshiftTests {
+		t.Run("", func(t *testing.T) {
+			defer assertImmutableFloat64s(t, &test.ss)()
+			shifted, shift := test.ss.Shift()
+			assert.Equal(t, test.shifted, shifted)
+			assert.Equal(t, test.shift, shift)
+			assert.Equal(t, test.unshift, test.ss.Unshift(test.params...))
+		})
+	}
+}
diff --git a/pie/ints_test.go b/pie/ints_test.go
index 809892d..b2e88d4 100644
--- a/pie/ints_test.go
+++ b/pie/ints_test.go
@@ -1387,3 +1387,87 @@ func TestInts_Equals(t *testing.T) {
 		})
 	}
 }
+
+var intsShiftAndUnshiftTests = []struct {
+	ss      Ints
+	shifted int
+	shift   Ints
+	params  Ints
+	unshift Ints
+}{
+	{
+		nil,
+		0,
+		nil,
+		nil,
+		Ints{},
+	},
+	{
+		nil,
+		0,
+		nil,
+		Ints{},
+		Ints{},
+	},
+	{
+		nil,
+		0,
+		nil,
+		Ints{1, 2},
+		Ints{1, 2},
+	},
+	{
+		Ints{},
+		0,
+		nil,
+		nil,
+		Ints{},
+	},
+	{
+		Ints{},
+		0,
+		nil,
+		Ints{},
+		Ints{},
+	},
+	{
+		Ints{},
+		0,
+		nil,
+		Ints{1, 2},
+		Ints{1, 2},
+	},
+	{
+		Ints{1},
+		1,
+		nil,
+		Ints{2},
+		Ints{2, 1},
+	},
+	{
+		Ints{1, 2},
+		1,
+		Ints{2},
+		Ints{3},
+		Ints{3, 1, 2},
+	},
+	{
+		Ints{1, 2},
+		1,
+		Ints{2},
+		Ints{3, 4},
+		Ints{3, 4, 1, 2},
+	},
+}
+
+func TestInts_ShiftAndUnshift(t *testing.T) {
+	for _, test := range intsShiftAndUnshiftTests {
+		t.Run("", func(t *testing.T) {
+			defer assertImmutableInts(t, &test.ss)()
+			shifted, shift := test.ss.Shift()
+			assert.Equal(t, test.shifted, shifted)
+			assert.Equal(t, test.shift, shift)
+			assert.Equal(t, test.unshift, test.ss.Unshift(test.params...))
+		})
+	}
+}
diff --git a/pie/strings_test.go b/pie/strings_test.go
index a2782cc..96bcebb 100644
--- a/pie/strings_test.go
+++ b/pie/strings_test.go
@@ -1417,3 +1417,87 @@ func TestStrings_Equals(t *testing.T) {
 		})
 	}
 }
+
+var stringsShiftAndUnshiftTests = []struct {
+	ss      Strings
+	shifted string
+	shift   Strings
+	params  Strings
+	unshift Strings
+}{
+	{
+		nil,
+		"",
+		nil,
+		nil,
+		Strings{},
+	},
+	{
+		nil,
+		"",
+		nil,
+		Strings{},
+		Strings{},
+	},
+	{
+		nil,
+		"",
+		nil,
+		Strings{"foo", "bar"},
+		Strings{"foo", "bar"},
+	},
+	{
+		Strings{},
+		"",
+		nil,
+		nil,
+		Strings{},
+	},
+	{
+		Strings{},
+		"",
+		nil,
+		Strings{},
+		Strings{},
+	},
+	{
+		Strings{},
+		"",
+		nil,
+		Strings{"foo", "bar"},
+		Strings{"foo", "bar"},
+	},
+	{
+		Strings{"foo"},
+		"foo",
+		nil,
+		Strings{"bar"},
+		Strings{"bar", "foo"},
+	},
+	{
+		Strings{"foo", "bar"},
+		"foo",
+		Strings{"bar"},
+		Strings{"baz"},
+		Strings{"baz", "foo", "bar"},
+	},
+	{
+		Strings{"foo", "bar"},
+		"foo",
+		Strings{"bar"},
+		Strings{"baz", ""},
+		Strings{"baz", "", "foo", "bar"},
+	},
+}
+
+func TestStrings_ShiftAndUnshift(t *testing.T) {
+	for _, test := range stringsShiftAndUnshiftTests {
+		t.Run("", func(t *testing.T) {
+			defer assertImmutableStrings(t, &test.ss)()
+			shifted, shift := test.ss.Shift()
+			assert.Equal(t, test.shifted, shifted)
+			assert.Equal(t, test.shift, shift)
+			assert.Equal(t, test.unshift, test.ss.Unshift(test.params...))
+		})
+	}
+}