github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/hostarch/addr_range_seq_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package hostarch 16 17 import ( 18 "testing" 19 ) 20 21 var addrRangeSeqTests = []struct { 22 desc string 23 ranges []AddrRange 24 }{ 25 { 26 desc: "Empty sequence", 27 }, 28 { 29 desc: "Single empty AddrRange", 30 ranges: []AddrRange{ 31 {0x10, 0x10}, 32 }, 33 }, 34 { 35 desc: "Single non-empty AddrRange of length 1", 36 ranges: []AddrRange{ 37 {0x10, 0x11}, 38 }, 39 }, 40 { 41 desc: "Single non-empty AddrRange of length 2", 42 ranges: []AddrRange{ 43 {0x10, 0x12}, 44 }, 45 }, 46 { 47 desc: "Multiple non-empty AddrRanges", 48 ranges: []AddrRange{ 49 {0x10, 0x11}, 50 {0x20, 0x22}, 51 }, 52 }, 53 { 54 desc: "Multiple AddrRanges including empty AddrRanges", 55 ranges: []AddrRange{ 56 {0x10, 0x10}, 57 {0x20, 0x20}, 58 {0x30, 0x33}, 59 {0x40, 0x44}, 60 {0x50, 0x50}, 61 {0x60, 0x60}, 62 {0x70, 0x77}, 63 {0x80, 0x88}, 64 {0x90, 0x90}, 65 {0xa0, 0xa0}, 66 }, 67 }, 68 } 69 70 func testAddrRangeSeqEqualityWithTailIteration(t *testing.T, ars AddrRangeSeq, wantRanges []AddrRange) { 71 var wantLen int64 72 for _, ar := range wantRanges { 73 wantLen += int64(ar.Length()) 74 } 75 76 var i int 77 for !ars.IsEmpty() { 78 if gotLen := ars.NumBytes(); gotLen != wantLen { 79 t.Errorf("Iteration %d: %v.NumBytes(): got %d, wanted %d", i, ars, gotLen, wantLen) 80 } 81 if gotN, wantN := ars.NumRanges(), len(wantRanges)-i; gotN != wantN { 82 t.Errorf("Iteration %d: %v.NumRanges(): got %d, wanted %d", i, ars, gotN, wantN) 83 } 84 got := ars.Head() 85 if i >= len(wantRanges) { 86 t.Errorf("Iteration %d: %v.Head(): got %s, wanted <end of sequence>", i, ars, got) 87 } else if want := wantRanges[i]; got != want { 88 t.Errorf("Iteration %d: %v.Head(): got %s, wanted %s", i, ars, got, want) 89 } 90 ars = ars.Tail() 91 wantLen -= int64(got.Length()) 92 i++ 93 } 94 if gotLen := ars.NumBytes(); gotLen != 0 || wantLen != 0 { 95 t.Errorf("Iteration %d: %v.NumBytes(): got %d, wanted %d (which should be 0)", i, ars, gotLen, wantLen) 96 } 97 if gotN := ars.NumRanges(); gotN != 0 { 98 t.Errorf("Iteration %d: %v.NumRanges(): got %d, wanted 0", i, ars, gotN) 99 } 100 } 101 102 func TestAddrRangeSeqTailIteration(t *testing.T) { 103 for _, test := range addrRangeSeqTests { 104 t.Run(test.desc, func(t *testing.T) { 105 testAddrRangeSeqEqualityWithTailIteration(t, AddrRangeSeqFromSlice(test.ranges), test.ranges) 106 }) 107 } 108 } 109 110 func TestAddrRangeSeqDropFirstEmpty(t *testing.T) { 111 var ars AddrRangeSeq 112 if got, want := ars.DropFirst(1), ars; got != want { 113 t.Errorf("%v.DropFirst(1): got %v, wanted %v", ars, got, want) 114 } 115 } 116 117 func TestAddrRangeSeqDropSingleByteIteration(t *testing.T) { 118 // Tests AddrRangeSeq iteration using Head/DropFirst, simulating 119 // I/O-per-AddrRange. 120 for _, test := range addrRangeSeqTests { 121 t.Run(test.desc, func(t *testing.T) { 122 // Figure out what AddrRanges we expect to see. 123 var wantLen int64 124 var wantRanges []AddrRange 125 for _, ar := range test.ranges { 126 wantLen += int64(ar.Length()) 127 wantRanges = append(wantRanges, ar) 128 if ar.Length() == 0 { 129 // We "do" 0 bytes of I/O and then call DropFirst(0), 130 // advancing to the next AddrRange. 131 continue 132 } 133 // Otherwise we "do" 1 byte of I/O and then call DropFirst(1), 134 // advancing the AddrRange by 1 byte, or to the next AddrRange 135 // if this one is exhausted. 136 for ar.Start++; ar.Length() != 0; ar.Start++ { 137 wantRanges = append(wantRanges, ar) 138 } 139 } 140 t.Logf("Expected AddrRanges: %s (%d bytes)", wantRanges, wantLen) 141 142 ars := AddrRangeSeqFromSlice(test.ranges) 143 var i int 144 for !ars.IsEmpty() { 145 if gotLen := ars.NumBytes(); gotLen != wantLen { 146 t.Errorf("Iteration %d: %v.NumBytes(): got %d, wanted %d", i, ars, gotLen, wantLen) 147 } 148 got := ars.Head() 149 if i >= len(wantRanges) { 150 t.Errorf("Iteration %d: %v.Head(): got %s, wanted <end of sequence>", i, ars, got) 151 } else if want := wantRanges[i]; got != want { 152 t.Errorf("Iteration %d: %v.Head(): got %s, wanted %s", i, ars, got, want) 153 } 154 if got.Length() == 0 { 155 ars = ars.DropFirst(0) 156 } else { 157 ars = ars.DropFirst(1) 158 wantLen-- 159 } 160 i++ 161 } 162 if gotLen := ars.NumBytes(); gotLen != 0 || wantLen != 0 { 163 t.Errorf("Iteration %d: %v.NumBytes(): got %d, wanted %d (which should be 0)", i, ars, gotLen, wantLen) 164 } 165 }) 166 } 167 } 168 169 func TestAddrRangeSeqTakeFirstEmpty(t *testing.T) { 170 var ars AddrRangeSeq 171 if got, want := ars.TakeFirst(1), ars; got != want { 172 t.Errorf("%v.TakeFirst(1): got %v, wanted %v", ars, got, want) 173 } 174 } 175 176 func TestAddrRangeSeqTakeFirst(t *testing.T) { 177 ranges := []AddrRange{ 178 {0x10, 0x11}, 179 {0x20, 0x22}, 180 {0x30, 0x30}, 181 {0x40, 0x44}, 182 {0x50, 0x55}, 183 {0x60, 0x60}, 184 {0x70, 0x77}, 185 } 186 ars := AddrRangeSeqFromSlice(ranges).TakeFirst(5) 187 want := []AddrRange{ 188 {0x10, 0x11}, // +1 byte (total 1 byte), not truncated 189 {0x20, 0x22}, // +2 bytes (total 3 bytes), not truncated 190 {0x30, 0x30}, // +0 bytes (total 3 bytes), no change 191 {0x40, 0x42}, // +2 bytes (total 5 bytes), partially truncated 192 {0x50, 0x50}, // +0 bytes (total 5 bytes), fully truncated 193 {0x60, 0x60}, // +0 bytes (total 5 bytes), "fully truncated" (no change) 194 {0x70, 0x70}, // +0 bytes (total 5 bytes), fully truncated 195 } 196 testAddrRangeSeqEqualityWithTailIteration(t, ars, want) 197 }