void VFSNodeUnit::_writeKnownDirectoryTestFile(VFSNode::KnownDirectoryIdentifier id, const VString& fileName) { VFSNode folder = VFSNode::getKnownDirectoryNode(id, "BombayDigital", "unittest-temp"); VFSNode fileNode; folder.getChildNode(fileName, fileNode); VBufferedFileStream fs(fileNode); fs.openWrite(); VTextIOStream out(fs); VInstant now; out.writeLine(now.getLocalString()); out.flush(); this->logStatus(VSTRING_FORMAT("Wrote to file '%s'.", fileNode.getPath().chars())); }
// static VFSNode VFSNode::_platform_getKnownDirectoryNode(KnownDirectoryIdentifier id, const VString& companyName, const VString& appName) { if (id == CURRENT_WORKING_DIRECTORY) { return VFSNode(VPlatformAPI::getcwd()); } if (id == EXECUTABLE_DIRECTORY) { /* This depends on the structure of the application or tool. If it's an iOS application, it's a bundle where we have: /...../wanted-dir/AppName.app/executable (2 levels up, wanted-dir is a randomized serial number at some path) If it's built as a Mac OS X application bundle we have: /...../wanted-dir/AppName.app/Contents/MacOS/executable (4 levels up, typically wanted-dir is /Applications if installed, but doesn't have to be) If it's built as a simple Unix-y tool we have: /...../wanted-dir/executable (1 level up, wanted-dir is wherever the tool has been placed) */ #ifdef VPLATFORM_MAC_IOS const int NUM_LEVELS_UP = 2; #else #ifdef VAULT_MACOSX_APP_IS_BUNDLE const int NUM_LEVELS_UP = 4; #else const int NUM_LEVELS_UP = 1; #endif #endif VFSNode node = VFSNode::getExecutable(); for (int i = 0; i < NUM_LEVELS_UP; ++i) { VFSNode parentNode; node.getParentNode(parentNode); node = parentNode; } return node; } VFSNode currentUserFolder(_V_NSHomeDirectory()); if (id == USER_HOME_DIRECTORY) { return currentUserFolder; } VFSNode libraryFolder; currentUserFolder.getChildNode("Library", libraryFolder); libraryFolder.mkdir(); VFSNode subFolder; switch (id) { case USER_HOME_DIRECTORY: // handled earlier; we returned above break; case LOG_FILES_DIRECTORY: libraryFolder.getChildNode("Logs", subFolder); break; case USER_PREFERENCES_DIRECTORY: libraryFolder.getChildNode("Preferences", subFolder); break; case CACHED_DATA_DIRECTORY: libraryFolder.getChildNode("Caches", subFolder); break; case APPLICATION_DATA_DIRECTORY: subFolder = libraryFolder; break; case CURRENT_WORKING_DIRECTORY: // handled earlier; we returned above break; case EXECUTABLE_DIRECTORY: // handled earlier; we returned above break; default: throw VStackTraceException(VSTRING_FORMAT("VFSNode::_platform_getKnownDirectoryNode: Requested invalid directory ID %d.", (int) id)); break; } subFolder.mkdir(); VFSNode companyFolder; if (companyName.isEmpty()) { companyFolder = subFolder; } else { subFolder.getChildNode(companyName, companyFolder); companyFolder.mkdir(); } VFSNode resultNode; if (appName.isEmpty()) { resultNode = companyFolder; } else { companyFolder.getChildNode(appName, resultNode); resultNode.mkdir(); } return resultNode; }
// static VFSNode VFSNode::_platform_getKnownDirectoryNode(KnownDirectoryIdentifier id, const VString& companyName, const VString& appName) { if (id == CURRENT_WORKING_DIRECTORY) { return VFSNode(VSystemAPI::getcwd()); } if (id == EXECUTABLE_DIRECTORY) { VFSNode executable = VFSNode::getExecutable(); VFSNode executableDirectory; executable.getParentNode(executableDirectory); return executableDirectory; } struct passwd* pwInfo = ::getpwuid(::getuid()); // Get info about the current user. if (pwInfo == NULL) { throw VStackTraceException( // Oddity: errno 0 can occur and means "no such user". (errno == 0 ? VSystemError(0, "No such user") : VSystemError()), "VFSNode::_platform_getKnownDirectoryNode failed to get current user info from getpwuid()." ); } const VString homePath(pwInfo->pw_dir); if (id == USER_HOME_DIRECTORY) { return VFSNode(homePath); } VString basePath; VString companyFolderName(companyName); switch (id) { case USER_HOME_DIRECTORY: // handled earlier; we returned above break; case LOG_FILES_DIRECTORY: basePath = homePath + "/log"; break; case USER_PREFERENCES_DIRECTORY: basePath = homePath; if (companyName.isNotEmpty()) { companyFolderName.format(".%s", companyName.chars()); } break; case CACHED_DATA_DIRECTORY: basePath = homePath + "/cache"; break; case APPLICATION_DATA_DIRECTORY: basePath = homePath + "/data"; break; case CURRENT_WORKING_DIRECTORY: // handled earlier; we returned above break; case EXECUTABLE_DIRECTORY: // handled earlier; we returned above break; default: throw VStackTraceException(VSTRING_FORMAT("VFSNode::_platform_getKnownDirectoryNode: Requested invalid directory ID %d.", (int) id)); break; } VFSNode baseDir(basePath); baseDir.mkdir(); VFSNode companyFolder; if (companyFolderName.isEmpty()) { companyFolder = baseDir; } else { baseDir.getChildNode(companyFolderName, companyFolder); companyFolder.mkdir(); } VFSNode resultNode; if (appName.isEmpty()) { resultNode = companyFolder; } else { companyFolder.getChildNode(appName, resultNode); resultNode.mkdir(); } return resultNode; }
VFSNode::VFSNode(const VFSNode& directory, const VString& childName) : mPath() { directory.getChildNode(childName, *this); }
void VFSNodeUnit::_testDirectoryIteration(const VFSNode& dir) { const int NUM_FILES_TO_CREATE = 5; const int NUM_FILES_TO_CHECK = NUM_FILES_TO_CREATE + 3; // we'll verify we don't have these extras // Test directory listing, iteration, find. // Create 5 files in the deep directory, then test that we can find them. for (int i = 0; i < NUM_FILES_TO_CREATE; ++i) { VString testIterFileName(VSTRING_ARGS("iter_test_%d.txt", i)); VFSNode testIterFileNode; dir.getChildNode(testIterFileName, testIterFileNode); VBufferedFileStream testIterStream(testIterFileNode); testIterStream.openWrite(); VTextIOStream out(testIterStream); out.writeLine(testIterFileName); } { // find() test VFSNode testIterNode; for (int i = 0; i < NUM_FILES_TO_CHECK; ++i) { VString testIterFileName(VSTRING_ARGS("iter_test_%d.txt", i)); if (i < NUM_FILES_TO_CREATE) VUNIT_ASSERT_TRUE_LABELED(dir.find(testIterFileName, testIterNode), VSTRING_FORMAT("find() found #%d", i)); // this file should exist else VUNIT_ASSERT_FALSE_LABELED(dir.find(testIterFileName, testIterNode), VSTRING_FORMAT("find() did not find #%d", i)); // this file should not exist } } // There is no guarantee that the list() and iterate() methods will return the directory // listing in any particular order. We either need to sort them ourself, or verify without // regard to order. Here, we'll sort the returned string list, since we know that our // file names are sortable because they are single-digit-number-based strings, e.g. "iter_test_3.txt". // Note that the result of sorting is ultimately dependent on strcmp(). { // list() names test int index = 0; VStringVector fileNames; dir.list(fileNames); std::sort(fileNames.begin(), fileNames.end()); VUNIT_ASSERT_EQUAL_LABELED(static_cast<int>(fileNames.size()), NUM_FILES_TO_CREATE, "list names size"); for (VStringVector::const_iterator i = fileNames.begin(); i != fileNames.end(); ++i, ++index) { VString testIterFileName(VSTRING_ARGS("iter_test_%d.txt", index)); VUNIT_ASSERT_EQUAL_LABELED(*i, testIterFileName, VSTRING_FORMAT("list names #%d", index)); } } { // list() nodes test int index = 0; VFSNodeVector fileNodes; dir.list(fileNodes); std::sort(fileNodes.begin(), fileNodes.end()); VUNIT_ASSERT_EQUAL_LABELED(static_cast<int>(fileNodes.size()), NUM_FILES_TO_CREATE, "list nodes size"); for (VFSNodeVector::const_iterator i = fileNodes.begin(); i != fileNodes.end(); ++i, ++index) { VString testIterFileName(VSTRING_ARGS("iter_test_%d.txt", index)); VString nodeFileName; i->getName(nodeFileName); VUNIT_ASSERT_EQUAL_LABELED(nodeFileName, testIterFileName, VSTRING_FORMAT("list nodes #%d", index)); } } { // iterate() test int index = 0; VFSNodeIterateTestCallback callback; dir.iterate(callback); std::sort(callback.mNodeNames.begin(), callback.mNodeNames.end()); VUNIT_ASSERT_EQUAL_LABELED(static_cast<int>(callback.mNodeNames.size()), NUM_FILES_TO_CREATE, "iterate size"); for (VStringVector::const_iterator i = callback.mNodeNames.begin(); i != callback.mNodeNames.end(); ++i, ++index) { VString testIterFileName(VSTRING_ARGS("iter_test_%d.txt", index)); VUNIT_ASSERT_EQUAL_LABELED(*i, testIterFileName, VSTRING_FORMAT("iterate nodes #%d", index)); } } }