1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
+ using System . Linq ;
5
+ using System . Security . Cryptography ;
4
6
using Xunit ;
5
7
6
8
namespace System . IO . Tests
@@ -68,6 +70,10 @@ public partial class NoParallelTests { }
68
70
[ Collection ( "NoParallelTests" ) ]
69
71
public partial class FileStream_ctor_options_as : FileStream_ctor_options_as_base
70
72
{
73
+ protected override long PreallocationSize => 10 ;
74
+
75
+ protected override long InitialLength => 10 ;
76
+
71
77
[ Fact ]
72
78
public virtual void NegativePreallocationSizeThrows ( )
73
79
{
@@ -80,57 +86,68 @@ public virtual void NegativePreallocationSizeThrows()
80
86
[ InlineData ( FileMode . Create , 0L ) ]
81
87
[ InlineData ( FileMode . CreateNew , 0L ) ]
82
88
[ InlineData ( FileMode . OpenOrCreate , 0L ) ]
83
- public void WhenFileIsCreatedWithoutPreallocationSizeSpecifiedThePreallocationSizeIsNotSet ( FileMode mode , long preallocationSize )
89
+ public void WhenFileIsCreatedWithoutPreallocationSizeSpecifiedItsLengthIsZero ( FileMode mode , long preallocationSize )
84
90
{
85
91
using ( var fs = new FileStream ( GetPathToNonExistingFile ( ) , GetOptions ( mode , FileAccess . Write , FileShare . None , FileOptions . None , preallocationSize ) ) )
86
92
{
87
- Assert . Equal ( 0 , GetActualPreallocationSize ( fs ) ) ;
88
93
Assert . Equal ( 0 , fs . Length ) ;
89
94
Assert . Equal ( 0 , fs . Position ) ;
90
95
}
91
96
}
92
97
93
98
[ Theory ]
94
- [ InlineData ( FileMode . Open , 0L ) ]
95
- [ InlineData ( FileMode . Open , 1L ) ]
96
- [ InlineData ( FileMode . OpenOrCreate , 0L ) ]
97
- [ InlineData ( FileMode . OpenOrCreate , 1L ) ]
98
- [ InlineData ( FileMode . Append , 0L ) ]
99
- [ InlineData ( FileMode . Append , 1L ) ]
100
- public void WhenExistingFileIsBeingOpenedWithPreallocationSizeSpecifiedThePreallocationSizeIsNotChanged ( FileMode mode , long preallocationSize )
99
+ [ InlineData ( FileMode . Open , 20L ) ]
100
+ [ InlineData ( FileMode . Open , 5L ) ]
101
+ [ InlineData ( FileMode . Append , 20L ) ]
102
+ [ InlineData ( FileMode . Append , 5L ) ]
103
+ public void PreallocationSizeIsIgnoredForFileModeOpenAndAppend ( FileMode mode , long preallocationSize )
101
104
{
102
- const int initialSize = 1 ;
105
+ const int initialSize = 10 ;
103
106
string filePath = GetPathToNonExistingFile ( ) ;
104
107
File . WriteAllBytes ( filePath , new byte [ initialSize ] ) ;
105
- long initialPreallocationSize ;
106
108
107
- using ( var fs = new FileStream ( filePath , GetOptions ( mode , FileAccess . Write , FileShare . None , FileOptions . None , 0 ) ) ) // preallocationSize NOT provided
109
+ using ( var fs = new FileStream ( filePath , GetOptions ( mode , FileAccess . Write , FileShare . None , FileOptions . None , preallocationSize ) ) )
108
110
{
109
- initialPreallocationSize = GetActualPreallocationSize ( fs ) ; // just read it to ensure it's not being changed
111
+ Assert . Equal ( initialSize , fs . Length ) ; // it has NOT been changed
112
+ Assert . Equal ( mode == FileMode . Append ? initialSize : 0 , fs . Position ) ;
110
113
}
114
+ }
111
115
112
- using ( var fs = new FileStream ( filePath , GetOptions ( mode , FileAccess . Write , FileShare . None , FileOptions . None , preallocationSize ) ) )
116
+ [ Theory ]
117
+ [ InlineData ( FileMode . OpenOrCreate , 20L ) ] // preallocationSize > initialSize
118
+ [ InlineData ( FileMode . OpenOrCreate , 5L ) ] // preallocationSize < initialSize
119
+ public void WhenExistingFileIsBeingOpenedWithOpenOrCreateModeTheLengthRemainsUnchanged ( FileMode mode , long preallocationSize )
120
+ {
121
+ const int initialSize = 10 ;
122
+ string filePath = GetPathToNonExistingFile ( ) ;
123
+ byte [ ] initialData = RandomNumberGenerator . GetBytes ( initialSize ) ;
124
+ File . WriteAllBytes ( filePath , initialData ) ;
125
+
126
+ using ( var fs = new FileStream ( filePath , GetOptions ( mode , FileAccess . ReadWrite , FileShare . None , FileOptions . None , preallocationSize ) ) )
113
127
{
114
- Assert . Equal ( initialPreallocationSize , GetActualPreallocationSize ( fs ) ) ; // it has NOT been changed
115
- Assert . Equal ( initialSize , fs . Length ) ;
116
- Assert . Equal ( mode == FileMode . Append ? initialSize : 0 , fs . Position ) ;
128
+ Assert . Equal ( initialSize , fs . Length ) ; // it was not changed
129
+ Assert . Equal ( 0 , fs . Position ) ;
130
+
131
+ byte [ ] actualContent = new byte [ initialData . Length ] ;
132
+ Assert . Equal ( actualContent . Length , fs . Read ( actualContent ) ) ;
133
+ AssertExtensions . SequenceEqual ( initialData , actualContent ) ; // the initial content was not changed
117
134
}
118
135
}
119
136
120
137
[ Theory ]
121
138
[ InlineData ( FileMode . Create ) ]
122
139
[ InlineData ( FileMode . CreateNew ) ]
123
140
[ InlineData ( FileMode . OpenOrCreate ) ]
124
- public void WhenFileIsCreatedWithPreallocationSizeSpecifiedThePreallocationSizeIsSet ( FileMode mode )
141
+ public void WhenFileIsCreatedWithPreallocationSizeSpecifiedTheLengthIsSetAndTheContentIsZeroed ( FileMode mode )
125
142
{
126
143
const long preallocationSize = 123 ;
127
144
128
- using ( var fs = new FileStream ( GetPathToNonExistingFile ( ) , GetOptions ( mode , FileAccess . Write , FileShare . None , FileOptions . None , preallocationSize ) ) )
145
+ using ( var fs = new FileStream ( GetPathToNonExistingFile ( ) , GetOptions ( mode , FileAccess . ReadWrite , FileShare . None , FileOptions . None , preallocationSize ) ) )
129
146
{
130
- // OS might allocate MORE than we have requested
131
- Assert . True ( GetActualPreallocationSize ( fs ) >= preallocationSize , $ "Provided { preallocationSize } , actual: { GetActualPreallocationSize ( fs ) } ") ;
132
- Assert . Equal ( GetExpectedFileLength ( preallocationSize ) , fs . Length ) ;
147
+ Assert . Equal ( preallocationSize , fs . Length ) ;
133
148
Assert . Equal ( 0 , fs . Position ) ;
149
+
150
+ AssertFileContentHasBeenZeroed ( 0 , ( int ) fs . Length , fs ) ;
134
151
}
135
152
}
136
153
@@ -153,7 +170,7 @@ public void WhenDiskIsFullTheErrorMessageContainsAllDetails(FileMode mode)
153
170
Assert . Contains ( filePath , ex . Message ) ;
154
171
Assert . Contains ( tooMuch . ToString ( ) , ex . Message ) ;
155
172
156
- // ensure it was NOT created (provided OOTB by Windows, emulated on Unix)
173
+ // ensure it was NOT created
157
174
bool exists = File . Exists ( filePath ) ;
158
175
if ( exists )
159
176
{
@@ -163,37 +180,20 @@ public void WhenDiskIsFullTheErrorMessageContainsAllDetails(FileMode mode)
163
180
}
164
181
165
182
[ Fact ]
166
- public void WhenFileIsTruncatedWithoutPreallocationSizeSpecifiedThePreallocationSizeIsNotSet ( )
167
- {
168
- const int initialSize = 10_000 ;
169
-
170
- string filePath = GetPathToNonExistingFile ( ) ;
171
- File . WriteAllBytes ( filePath , new byte [ initialSize ] ) ;
172
-
173
- using ( var fs = new FileStream ( filePath , GetOptions ( FileMode . Truncate , FileAccess . Write , FileShare . None , FileOptions . None , 0 ) ) )
174
- {
175
- Assert . Equal ( 0 , GetActualPreallocationSize ( fs ) ) ;
176
- Assert . Equal ( 0 , fs . Length ) ;
177
- Assert . Equal ( 0 , fs . Position ) ;
178
- }
179
- }
180
-
181
- [ Fact ]
182
- public void WhenFileIsTruncatedWithPreallocationSizeSpecifiedThePreallocationSizeIsSet ( )
183
+ public void WhenFileIsTruncatedWithPreallocationSizeSpecifiedTheLengthIsSetAndTheContentIsZeroed ( )
183
184
{
184
185
const int initialSize = 10_000 ; // this must be more than 4kb which seems to be minimum allocation size on Windows
185
186
const long preallocationSize = 100 ;
186
187
187
188
string filePath = GetPathToNonExistingFile ( ) ;
188
- File . WriteAllBytes ( filePath , new byte [ initialSize ] ) ;
189
+ File . WriteAllBytes ( filePath , Enumerable . Repeat ( ( byte ) 1 , initialSize ) . ToArray ( ) ) ;
189
190
190
- using ( var fs = new FileStream ( filePath , GetOptions ( FileMode . Truncate , FileAccess . Write , FileShare . None , FileOptions . None , preallocationSize ) ) )
191
+ using ( var fs = new FileStream ( filePath , GetOptions ( FileMode . Truncate , FileAccess . ReadWrite , FileShare . None , FileOptions . None , preallocationSize ) ) )
191
192
{
192
- Assert . True ( GetActualPreallocationSize ( fs ) >= preallocationSize , $ "Provided { preallocationSize } , actual: { GetActualPreallocationSize ( fs ) } ") ;
193
- // less than initial file size (file got truncated)
194
- Assert . True ( GetActualPreallocationSize ( fs ) < initialSize , $ "initialSize { initialSize } , actual: { GetActualPreallocationSize ( fs ) } ") ;
195
- Assert . Equal ( GetExpectedFileLength ( preallocationSize ) , fs . Length ) ;
193
+ Assert . Equal ( preallocationSize , fs . Length ) ;
196
194
Assert . Equal ( 0 , fs . Position ) ;
195
+
196
+ AssertFileContentHasBeenZeroed ( 0 , ( int ) fs . Length , fs ) ;
197
197
}
198
198
}
199
199
@@ -208,5 +208,16 @@ private string GetPathToNonExistingFile()
208
208
209
209
return filePath ;
210
210
}
211
+
212
+ private static void AssertFileContentHasBeenZeroed ( int from , int to , FileStream fs )
213
+ {
214
+ int expectedByteCount = to - from ;
215
+ int extraByteCount = 1 ;
216
+ byte [ ] content = Enumerable . Repeat ( ( byte ) 1 , expectedByteCount + extraByteCount ) . ToArray ( ) ;
217
+ fs . Position = from ;
218
+ Assert . Equal ( expectedByteCount , fs . Read ( content ) ) ;
219
+ Assert . All ( content . SkipLast ( extraByteCount ) , @byte => Assert . Equal ( 0 , @byte ) ) ;
220
+ Assert . Equal ( to , fs . Position ) ;
221
+ }
211
222
}
212
223
}
0 commit comments