@@ -32,3 +32,120 @@ func TestOpen(t *testing.T) {
3232		t .Fatalf ("\n got  %q\n want %q" , string (got ), string (want ))
3333	}
3434}
35+ 
36+ func  TestSeekRead (t  * testing.T ) {
37+ 	const  filename  =  "mmap_test.go" 
38+ 	r , err  :=  Open (filename )
39+ 	if  err  !=  nil  {
40+ 		t .Fatalf ("Open: %v" , err )
41+ 	}
42+ 	buf  :=  make ([]byte , 1 )
43+ 	if  _ , err  :=  r .Seek (0 , io .SeekStart ); err  !=  nil  {
44+ 		t .Fatalf ("Seek: %v" , err )
45+ 	}
46+ 	n , err  :=  r .Read (buf )
47+ 	if  err  !=  nil  {
48+ 		t .Fatalf ("Read: %v" , err )
49+ 	}
50+ 	if  n  !=  1  {
51+ 		t .Fatalf ("Read: got %d bytes, want 1" , n )
52+ 	}
53+ 	if  buf [0 ] !=  '/'  { // first comment slash 
54+ 		t .Fatalf ("Read: got %q, want '/'" , buf [0 ])
55+ 	}
56+ 	if  _ , err  :=  r .Seek (1 , io .SeekCurrent ); err  !=  nil  {
57+ 		t .Fatalf ("Seek: %v" , err )
58+ 	}
59+ 	n , err  =  r .Read (buf )
60+ 	if  err  !=  nil  {
61+ 		t .Fatalf ("Read: %v" , err )
62+ 	}
63+ 	if  n  !=  1  {
64+ 		t .Fatalf ("Read: got %d bytes, want 1" , n )
65+ 	}
66+ 	if  buf [0 ] !=  ' '  { // space after comment 
67+ 		t .Fatalf ("Read: got %q, want ' '" , buf [0 ])
68+ 	}
69+ 	if  _ , err  :=  r .Seek (- 1 , io .SeekEnd ); err  !=  nil  {
70+ 		t .Fatalf ("Seek: %v" , err )
71+ 	}
72+ 	n , err  =  r .Read (buf )
73+ 	if  err  !=  nil  {
74+ 		t .Fatalf ("Read: %v" , err )
75+ 	}
76+ 	if  n  !=  1  {
77+ 		t .Fatalf ("Read: got %d bytes, want 1" , n )
78+ 	}
79+ 	if  buf [0 ] !=  '\n'  { // last newline 
80+ 		t .Fatalf ("Read: got %q, want newline" , buf [0 ])
81+ 	}
82+ 	if  _ , err  :=  r .Seek (0 , io .SeekEnd ); err  !=  nil  {
83+ 		t .Fatalf ("Seek: %v" , err )
84+ 	}
85+ 	if  _ , err  :=  r .Read (buf ); err  !=  io .EOF  {
86+ 		t .Fatalf ("Read: expected EOF, got %v" , err )
87+ 	}
88+ }
89+ 
90+ func  TestWriterTo_idempotency (t  * testing.T ) {
91+ 	const  filename  =  "mmap_test.go" 
92+ 	r , err  :=  Open (filename )
93+ 	if  err  !=  nil  {
94+ 		t .Fatalf ("Open: %v" , err )
95+ 	}
96+ 	buf  :=  bytes .NewBuffer (make ([]byte , 0 , len (r .data )))
97+ 	// first run 
98+ 	n , err  :=  r .WriteTo (buf )
99+ 	if  err  !=  nil  {
100+ 		t .Fatalf ("WriteTo: %v" , err )
101+ 	}
102+ 	if  n  !=  int64 (len (r .data )) {
103+ 		t .Fatalf ("WriteTo: got %d bytes, want %d" , n , len (r .data ))
104+ 	}
105+ 	if  ! bytes .Equal (buf .Bytes (), r .data ) {
106+ 		t .Fatalf ("WriteTo: got %q, want %q" , buf .Bytes (), r .data )
107+ 	}
108+ 	// second run 
109+ 	n , err  =  r .WriteTo (buf )
110+ 	if  err  !=  nil  {
111+ 		t .Fatalf ("WriteTo: %v" , err )
112+ 	}
113+ 	if  n  !=  0  {
114+ 		t .Fatalf ("WriteTo: got %d bytes, want %d" , n , 0 )
115+ 	}
116+ 	if  ! bytes .Equal (buf .Bytes (), r .data ) {
117+ 		t .Fatalf ("WriteTo: got %q, want %q" , buf .Bytes (), r .data )
118+ 	}
119+ }
120+ 
121+ func  BenchmarkMmapCopy (b  * testing.B ) {
122+ 	var  f  io.ReadSeeker 
123+ 
124+ 	// mmap some big-ish file; will only work on unix-like OSs. 
125+ 	r , err  :=  Open ("/proc/self/exe" )
126+ 	if  err  !=  nil  {
127+ 		b .Fatalf ("Open: %v" , err )
128+ 	}
129+ 
130+ 	// Sanity check: ensure we will run into the io.Copy optimization when using the NEW code above. 
131+ 	var  _  io.WriterTo  =  r 
132+ 
133+ 	// f = io.NewSectionReader(r, 0, int64(len(r.data))) // old 
134+ 	f  =  r  // new 
135+ 
136+ 	buf  :=  bytes .NewBuffer (make ([]byte , 0 , len (r .data )))
137+ 	// "Hide" the ReaderFrom interface by wrapping the writer. 
138+ 	// Otherwise we skew the results by optimizing the wrong side. 
139+ 	writer  :=  struct { io.Writer  }{buf }
140+ 
141+ 	b .ReportAllocs ()
142+ 	b .ResetTimer ()
143+ 
144+ 	for  i  :=  0 ; i  <  b .N ; i ++  {
145+ 		_ , _  =  f .Seek (0 , io .SeekStart )
146+ 		buf .Reset ()
147+ 
148+ 		n , _  :=  io .Copy (writer , f )
149+ 		b .SetBytes (n )
150+ 	}
151+ }
0 commit comments