1 /++
2 $(H2 Scriptlike $(SCRIPTLIKE_VERSION))
3 
4 Extra Scriptlike-only functionality to complement and wrap $(MODULE_STD_FILE),
5 providing extra functionality, such as no-fail "try*" alternatives, and support
6 for Scriptlike's $(API_PATH_EXTR Path), command echoing and dry-run features.
7 
8 Modules:
9 $(UL
10 	$(LI $(MODULE_FILE_EXTR) )
11 	$(LI $(MODULE_FILE_WRAP) )
12 )
13 
14 Copyright: Copyright (C) 2014-2015 Nick Sabalausky
15 License:   zlib/libpng
16 Authors:   Nick Sabalausky
17 +/
18 module scriptlike.file;
19 
20 public import scriptlike.file.extras;
21 public import scriptlike.file.wrappers;
22 
23 version(unittest_scriptlike_d)
24 unittest
25 {
26 	import std.algorithm : equal;
27 	import std.conv;
28 	import std.datetime;
29 	import std.string;
30 	import std.traits;
31 	import std.typecons;
32 
33 	import scriptlike.path;
34 	
35 	// std.file.slurp seems to randomly trigger an internal std.algorithm
36 	// assert failure on DMD 2.064.2, so don't test it there. Seems
37 	// to be fixed in DMD 2.065.
38 	static import std.compiler;
39 	static if(
40 		std.compiler.vendor == std.compiler.Vendor.digitalMars ||
41 		(std.compiler.version_major == 2 && std.compiler.version_minor == 64)
42 	)
43 		enum testSlurp = false;
44 	else
45 		enum testSlurp = true;
46 
47 	import std.stdio : writeln;
48 	import std.process : thisProcessID;
49 	import core.thread;
50 	alias copy = scriptlike.path.wrappers.copy;
51 
52 	writeln("Running Scriptlike unittests: std.file wrappers");
53 	
54 	immutable tempname  = std.path.buildPath(std.file.tempDir(), "deleteme.script like.unit test.pid"  ~ to!string(thisProcessID));
55 	immutable tempname2 = std.path.buildPath(std.file.tempDir(), "deleteme.script like.unit test2.pid" ~ to!string(thisProcessID));
56 	immutable tempname3 = std.path.buildPath(std.file.tempDir(), "deleteme.script like.unit test3.pid" ~ to!string(thisProcessID), "somefile");
57 	auto tempPath  = Path(tempname);
58 	auto tempPath2 = Path(tempname2);
59 	auto tempPath3 = Path(tempname3);
60 	assert(!std.file.exists(tempname));
61 	assert(!std.file.exists(tempname2));
62 	assert(!std.file.exists( std.path.dirName(tempname3) ));
63 	assert(!std.file.exists(tempname3));
64 	
65 	{
66 		scope(exit)
67 		{
68 			if(std.file.exists(tempname)) std.file.remove(tempname);
69 		}
70 
71 		tempPath.write("stuff");
72 
73 		tempPath.append(" more");
74 		assert(tempPath.read(3) == "stu");
75 		assert(tempPath.read() == "stuff more");
76 		assert(tempPath.readText() == "stuff more");
77 		assert(tempPath.getSize() == 10);
78 
79 		if(testSlurp)
80 		{
81 			auto parsed = tempPath.slurp!(string, string)("%s %s");
82 			assert(equal(parsed, [tuple("stuff", "more")]));
83 		}
84 		
85 		SysTime timeA, timeB, timeC;
86 		tempPath.getTimes(timeA, timeB);
87 		version(Windows)
88 			tempPath.getTimesWin(timeA, timeB, timeC);
89 		tempPath.setTimes(timeA, timeB);
90 		timeA = tempPath.timeLastModified();
91 		timeA = tempPath.timeLastModified(timeB);
92 		
93 		uint attr;
94 		attr = tempPath.getAttributes();
95 		attr = tempPath.getLinkAttributes();
96 		
97 		assert(tempPath.exists());
98 		assert(tempPath.isFile());
99 		assert(tempPath.existsAsFile());
100 		assert(!tempPath.isDir());
101 		assert(!tempPath.existsAsDir());
102 		assert(!tempPath.isSymlink());
103 		assert(!tempPath.existsAsSymlink());
104 		tempPath.remove();
105 		assert(!tempPath.exists());
106 		assert(!tempPath.existsAsFile());
107 		assert(!tempPath.existsAsDir());
108 		assert(!tempPath.existsAsSymlink());
109 	}
110 	
111 	{
112 		assert(!tempPath.exists());
113 		assert(!tempPath2.exists());
114 
115 		scope(exit)
116 		{
117 			if(std.file.exists(tempname))  std.file.remove(tempname);
118 			if(std.file.exists(tempname2)) std.file.remove(tempname2);
119 		}
120 		tempPath.write("ABC");
121 		
122 		assert(tempPath.existsAsFile());
123 		assert(!tempPath2.exists());
124 
125 		tempPath.rename(tempPath2);
126 		
127 		assert(!tempPath.exists());
128 		assert(tempPath2.existsAsFile());
129 		
130 		tempPath2.copy(tempPath);
131 		
132 		assert(tempPath.existsAsFile());
133 		assert(tempPath2.existsAsFile());
134 	}
135 	
136 	{
137 		scope(exit)
138 		{
139 			if(std.file.exists(tempname))  std.file.rmdir(tempname);
140 			if(std.file.exists(tempname3)) std.file.rmdir(tempname3);
141 			if(std.file.exists( std.path.dirName(tempname3) )) std.file.rmdir( std.path.dirName(tempname3) );
142 		}
143 		
144 		assert(!tempPath.exists());
145 		assert(!tempPath3.exists());
146 		
147 		tempPath.mkdir();
148 		assert(tempPath.exists());
149 		assert(!tempPath.isFile());
150 		assert(!tempPath.existsAsFile());
151 		assert(tempPath.isDir());
152 		assert(tempPath.existsAsDir());
153 		assert(!tempPath.isSymlink());
154 		assert(!tempPath.existsAsSymlink());
155 
156 		tempPath3.mkdirRecurse();
157 		assert(tempPath3.exists());
158 		assert(!tempPath3.isFile());
159 		assert(!tempPath3.existsAsFile());
160 		assert(tempPath3.isDir());
161 		assert(tempPath3.existsAsDir());
162 		assert(!tempPath3.isSymlink());
163 		assert(!tempPath3.existsAsSymlink());
164 		
165 		auto saveDirName = std.file.getcwd();
166 		auto saveDir = Path(saveDirName);
167 		scope(exit) chdir(saveDirName);
168 
169 		tempPath.chdir();
170 		assert(getcwd() == tempname);
171 		saveDir.chdir();
172 		assert(getcwd() == saveDirName);
173 		
174 		auto entries1 = (tempPath3~"..").dirEntries(SpanMode.shallow);
175 		assert(!entries1.empty);
176 		auto entries2 = (tempPath3~"..").dirEntries("*", SpanMode.shallow);
177 		assert(!entries2.empty);
178 		auto entries3 = (tempPath3~"..").dirEntries("TUNA TUNA THIS DOES NOT EXIST TUNA WHEE", SpanMode.shallow);
179 		assert(entries3.empty);
180 		
181 		tempPath.rmdir();
182 		assert(!tempPath.exists());
183 		assert(!tempPath.existsAsFile());
184 		assert(!tempPath.existsAsDir());
185 		assert(!tempPath.existsAsSymlink());
186 
187 		tempPath3.rmdirRecurse();
188 		assert(!tempPath.exists());
189 		assert(!tempPath.existsAsFile());
190 		assert(!tempPath.existsAsDir());
191 		assert(!tempPath.existsAsSymlink());
192 	}
193 	
194 	{
195 		version(Posix)
196 		{
197 			assert(!tempPath.exists());
198 			assert(!tempPath2.exists());
199 
200 			scope(exit)
201 			{
202 				if(std.file.exists(tempname2)) std.file.remove(tempname2);
203 				if(std.file.exists(tempname))  std.file.remove(tempname);
204 			}
205 			tempPath.write("DEF");
206 			
207 			tempPath.symlink(tempPath2);
208 			assert(tempPath2.exists());
209 			assert(tempPath2.isFile());
210 			assert(tempPath2.existsAsFile());
211 			assert(!tempPath2.isDir());
212 			assert(!tempPath2.existsAsDir());
213 			assert(tempPath2.isSymlink());
214 			assert(tempPath2.existsAsSymlink());
215 			
216 			auto linkTarget = tempPath2.readLink();
217 			assert(linkTarget.toRawString() == tempname);
218 		}
219 	}
220 	
221 	{
222 		assert(!tempPath.exists());
223 
224 		scope(exit)
225 		{
226 			if(std.file.exists(tempname)) std.file.remove(tempname);
227 		}
228 
229 		import scriptlike.process;
230 		run(`echo TestScriptStuff > `~tempPath.to!string());
231 		assert(tempPath.exists());
232 		assert(tempPath.isFile());
233 		assert((cast(string)tempPath.read()).strip() == "TestScriptStuff");
234 		tempPath.remove();
235 		assert(!tempPath.exists());
236 
237 		auto errlevel = tryRun(`echo TestScriptStuff > `~tempPath.to!string());
238 		assert(tempPath.exists());
239 		assert(tempPath.isFile());
240 		assert((cast(string)tempPath.read()).strip() == "TestScriptStuff");
241 		assert(errlevel == 0);
242 		tempPath.remove();
243 		assert(!tempPath.exists());
244 
245 		import scriptlike.process;
246 		getcwd().run(`echo TestScriptStuff > `~tempPath.to!string());
247 		getcwd().tryRun(`echo TestScriptStuff > `~tempPath.to!string());
248 	}
249 	
250 	{
251 		assert(!tempPath3.exists());
252 		assert(!tempPath3.up.exists());
253 
254 		scope(exit)
255 		{
256 			if(std.file.exists(tempname3)) std.file.remove(tempname3);
257 			if(std.file.exists( std.path.dirName(tempname3) )) std.file.rmdir( std.path.dirName(tempname3) );
258 		}
259 		
260 		tempPath3.up.mkdir();
261 		assert(tempPath3.up.exists());
262 		assert(tempPath3.up.isDir());
263 				
264 		import scriptlike.process;
265 		tempPath3.up.run(`echo MoreTestStuff > `~tempPath3.baseName().to!string());
266 		assert(tempPath3.exists());
267 		assert(tempPath3.isFile());
268 		assert((cast(string)tempPath3.read()).strip() == "MoreTestStuff");
269 	}
270 
271 	{
272 		scope(exit)
273 		{
274 			if(std.file.exists(tempname))  std.file.rmdir(tempname);
275 			if(std.file.exists(tempname3)) std.file.rmdir(tempname3);
276 			if(std.file.exists( std.path.dirName(tempname3) )) std.file.rmdir( std.path.dirName(tempname3) );
277 		}
278 		
279 		assert(!tempPath.exists());
280 		assert(!tempPath3.exists());
281 		
282 		assert(!tempPath.tryRmdir());
283 		assert(!tempPath.tryRmdirRecurse());
284 		assert(!tempPath.tryRemove());
285 		assert(!tempPath.tryRename(tempPath3));
286 		version(Posix) assert(!tempPath.trySymlink(tempPath3));
287 		assert(!tempPath.tryCopy(tempPath3));
288 
289 		assert(tempPath.tryMkdir());
290 		assert(tempPath.exists());
291 		assert(!tempPath.tryMkdir());
292 		assert(!tempPath.tryMkdirRecurse());
293 
294 		assert(tempPath.tryRmdir());
295 		assert(!tempPath.exists());
296 
297 		assert(tempPath.tryMkdirRecurse());
298 		assert(tempPath.exists());
299 		assert(!tempPath.tryMkdirRecurse());
300 	}
301 }