コード例 #1
0
void VFSNodeUnit::_testWindowsDrivePaths(const VString& driveLetter, const VString& childNodeName, bool adornedWithSlash, bool childIsDirectory) {
    VString driveLetterNodeName(VSTRING_ARGS("%s:", driveLetter.chars()));
    VString adornedDriveLetterPath(VSTRING_ARGS("%s:%s", driveLetter.chars(), (adornedWithSlash ? VFSNode::PATH_SEPARATOR_CHARS : "")));

    VFSNode driveLetterNode(adornedDriveLetterPath);
    this->logStatus(VSTRING_FORMAT("Testing '%s'...", adornedDriveLetterPath.chars()));
    VUNIT_ASSERT_EQUAL_LABELED(driveLetterNode.getName(), driveLetterNodeName, "drive letter node name");
    VUNIT_ASSERT_EQUAL_LABELED(driveLetterNode.getParentPath(), "", "drive letter node parent path");
    VUNIT_ASSERT_EQUAL_LABELED(driveLetterNode.isDirectory(), true, "drive letter node is dir"); // this test assumes that drive C: exists; not true in some installations
    VUNIT_ASSERT_EQUAL_LABELED(driveLetterNode.isFile(), false, "drive letter node is not file");

    VString adornedChildNodePath(VSTRING_ARGS("%s:%s%s", driveLetter.chars(), (adornedWithSlash ? VFSNode::PATH_SEPARATOR_CHARS : ""), childNodeName.chars()));
    VFSNode childNode(driveLetterNode, childNodeName);
    this->logStatus(VSTRING_FORMAT("Testing '%s'...", adornedChildNodePath.chars()));
    VUNIT_ASSERT_EQUAL_LABELED(childNode.getName(), childNodeName, "drive letter child node name");
    VUNIT_ASSERT_EQUAL_LABELED(childNode.getParentPath(), driveLetterNodeName, "drive letter child node parent path");
    VUNIT_ASSERT_EQUAL_LABELED(childNode.isDirectory(), childIsDirectory, "drive letter child node is/not dir check"); // this test assumes that C:Windows dir exists; not true in some installations
    VUNIT_ASSERT_EQUAL_LABELED(childNode.isFile(), !childIsDirectory, "drive letter child node is/not file check");

    VString childFileName("child.txt");
    VString expectedChildPath(VSTRING_ARGS("%s:%c%s", driveLetter.chars(), VFSNode::PATH_SEPARATOR_CHAR, childFileName.chars()));
    VFSNode childFileNode(driveLetterNode, childFileName);
    this->logStatus(VSTRING_FORMAT("Testing '%s + %s'...", adornedDriveLetterPath.chars(), childFileName.chars()));
    VUNIT_ASSERT_EQUAL_LABELED(childFileNode.getName(), childFileName, "drive letter child file node name");
    VUNIT_ASSERT_EQUAL_LABELED(childFileNode.getParentPath(), driveLetterNodeName, "drive letter child file node parent path");
    VUNIT_ASSERT_EQUAL_LABELED(childFileNode.getPath(), expectedChildPath, "drive letter child file node path");
}
コード例 #2
0
void VFSNode::_platform_renameNode(const VString& newPath) const {
    int result = VFileSystem::rename(mPath, newPath);

    if (result != 0)
        throw VException(VSystemError(), VSTRING_FORMAT("VFSNode::_platform_renameNode failed with result %d renaming '%s' to '%s'.", result, mPath.chars(), newPath.chars()));
}
コード例 #3
0
// 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;
}
コード例 #4
0
void VFSNode::getChildPath(const VString& childName, VString& childPath) const {
    // TODO: Should we throw an exception if childName is empty? It would generate a nonsensical childPath.
    childPath.format("%s%s%s", mPath.chars(),
        (mPath.endsWith(PATH_SEPARATOR_CHAR) ? "" : PATH_SEPARATOR_CHARS), // don't add another slash if already trailing
        childName.chars());
}
コード例 #5
0
// static
VString VSocket::_platform_addrinfoToIPAddressString(const VString& hostName, const struct addrinfo* info) {
    void* addr;
    if (info->ai_family == AF_INET) {
        addr = (void*) &(((struct sockaddr_in*)info->ai_addr)->sin_addr);
    } else if (info->ai_family == AF_INET6) {
        addr = (void*) &(((struct sockaddr_in6*)info->ai_addr)->sin6_addr);
    } else {
        // We don't know how to access the addr for other family types. They could conceivably be added.
        throw VException(VSTRING_FORMAT("VSocket::_platform_addrinfoToIPAddressString(%s): An invalid family (%d) other than AF_INET or AF_INET6 was specified.", hostName.chars(), info->ai_family));
    }

    VString result;
    result.preflight(MAX_ADDRSTRLEN);
    const char* buf = ::inet_ntop(info->ai_family, addr, result.buffer(), MAX_ADDRSTRLEN);
    if (buf == NULL) {
        throw VException(VSystemError::getSocketError(), VSTRING_FORMAT("VSocket::_platform_addrinfoToIPAddressString(%s): inet_ntop() failed.", hostName.chars()));
    }
    result.postflight((int) ::strlen(buf));

    return result;
}
コード例 #6
0
void VFSNodeUnit::run() {
    // Note that we also do testing of streams and file i/o here.

    this->logStatus(VSTRING_FORMAT("getExecutable: '%s'", VFSNode::getExecutable().getPath().chars()));
    this->logStatus(VSTRING_FORMAT("getExecutableDirectory: '%s'", VFSNode::getExecutableDirectory().getPath().chars()));
    this->logStatus(VSTRING_FORMAT("USER_HOME_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::USER_HOME_DIRECTORY, "com", "app").getPath().chars()));
    this->logStatus(VSTRING_FORMAT("LOG_FILES_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::LOG_FILES_DIRECTORY, "com", "app").getPath().chars()));
    this->logStatus(VSTRING_FORMAT("USER_PREFERENCES_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::USER_PREFERENCES_DIRECTORY, "com", "app").getPath().chars()));
    this->logStatus(VSTRING_FORMAT("CACHED_DATA_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::CACHED_DATA_DIRECTORY, "com", "app").getPath().chars()));
    this->logStatus(VSTRING_FORMAT("APPLICATION_DATA_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::APPLICATION_DATA_DIRECTORY, "com", "app").getPath().chars()));
    this->logStatus(VSTRING_FORMAT("CURRENT_WORKING_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::CURRENT_WORKING_DIRECTORY, "com", "app").getPath().chars()));
    this->logStatus(VSTRING_FORMAT("EXECUTABLE_DIRECTORY: '%s'", VFSNode::getKnownDirectoryNode(VFSNode::EXECUTABLE_DIRECTORY, "com", "app").getPath().chars()));

    VFSNode tempDir = VFSNode::getKnownDirectoryNode(VFSNode::CACHED_DATA_DIRECTORY, "vault", "unittest");
    VString tempDirPath = tempDir.getPath();

    VFSNode testDirRoot(tempDir, "vfsnodetest_temp");
    (void) testDirRoot.rm();

    VFSNode testDirDeep(tempDir, "vfsnodetest_temp/one/two/three");
    VUNIT_ASSERT_FALSE_LABELED(testDirDeep.exists(), "initial state 1");
    testDirDeep.mkdirs();
    VUNIT_ASSERT_TRUE_LABELED(testDirDeep.exists(), "deep mkdirs");

    VFSNode testDirDeeper(testDirDeep, "four");
    VUNIT_ASSERT_FALSE_LABELED(testDirDeeper.exists(), "initial state 2");
    testDirDeeper.mkdirs();
    VUNIT_ASSERT_TRUE_LABELED(testDirDeeper.exists(), "one-deep mkdirs");

    // Now that we have created a deep directory structure, let's do some
    // file i/o streams stuff here.

    VFSNode testTextFileNode(testDirDeeper, "test_text_file.txt");

    VBufferedFileStream btfs(testTextFileNode);
    this->_testTextFileIO("starting Buffered Text IO tests", testTextFileNode, btfs);
    (void) testTextFileNode.rm();
    VUNIT_ASSERT_FALSE_LABELED(testTextFileNode.exists(), "buffered text file removed");

    VDirectIOFileStream dtfs(testTextFileNode);
    this->_testTextFileIO("starting Unbuffered Text IO tests", testTextFileNode, dtfs);
    this->_testTextFileReadAll(testTextFileNode);
    (void) testTextFileNode.rm();
    VUNIT_ASSERT_FALSE_LABELED(testTextFileNode.exists(), "unbuffered text file removed");

    VFSNode testBinaryFileNode(testDirDeeper, "test_binary_file");

    VBufferedFileStream bbfs(testBinaryFileNode);
    this->_testBinaryFileIO("starting Buffered Binary IO tests", testBinaryFileNode, bbfs);
    (void) testBinaryFileNode.rm();
    VUNIT_ASSERT_FALSE_LABELED(testBinaryFileNode.exists(), "buffered binary file removed");

    VDirectIOFileStream dbfs(testBinaryFileNode);
    this->_testBinaryFileIO("starting Unbuffered Binary IO tests", testBinaryFileNode, dbfs);
    (void) testBinaryFileNode.rm();
    VUNIT_ASSERT_FALSE_LABELED(testBinaryFileNode.exists(), "unbuffered binary file removed");

    this->_testDirectoryIteration(testDirDeeper);

    // Next, test all flavors of renaming operations.
    VFSNode copyTest1(tempDir, "vfsnodetest_temp/one/two/test1.txt");
    VBufferedFileStream sourceFileStream(copyTest1);
    sourceFileStream.openWrite();
    VTextIOStream sourceOut(sourceFileStream);
    sourceOut.writeLine("line 1");
    sourceOut.writeLine("line 2");
    sourceOut.flush();
    sourceFileStream.close();
    VUNIT_ASSERT_TRUE_LABELED(copyTest1.exists(), "test1 exists");

    VFSNode copyTest2(tempDir, "vfsnodetest_temp/one/two/test2.txt");
    copyTest1.renameToName("test2.txt");
    VUNIT_ASSERT_FALSE_LABELED(copyTest1.exists(), "test1 was renamed");
    VUNIT_ASSERT_TRUE_LABELED(copyTest2.exists(), "test2 exists");

    VFSNode copyTest3;
    copyTest2.renameToName("test3.txt", copyTest3);
    VUNIT_ASSERT_FALSE_LABELED(copyTest2.exists(), "test2 was renamed");
    VUNIT_ASSERT_TRUE_LABELED(copyTest3.getPath() == tempDirPath + "/vfsnodetest_temp/one/two/test3.txt" && copyTest3.exists(), "test3 exists");

    VFSNode copyTest4(tempDir, "vfsnodetest_temp/one/two/three/test4.txt");
    copyTest3.renameToNode(copyTest4);
    VUNIT_ASSERT_FALSE_LABELED(copyTest3.exists(), "test3 was moved and renamed");
    VUNIT_ASSERT_TRUE_LABELED(copyTest4.exists(), "test4 exists");

    copyTest4.renameToPath(tempDirPath + "/vfsnodetest_temp/one/two/test5.txt");
    VFSNode copyTest5(tempDir, "vfsnodetest_temp/one/two/test5.txt");
    VUNIT_ASSERT_FALSE_LABELED(copyTest4.exists(), "test4 was moved and renamed");
    VUNIT_ASSERT_TRUE_LABELED(copyTest5.exists(), "test5 exists");

    copyTest5.renameToName("test5.txt"); // should throw
    
    VFSNode dirCopyTarget(tempDir, "vfsnodetest_temp_copy");
    VFSNode::copyDirectory(testDirRoot, dirCopyTarget, true);
    // Verify that expected files now exist. Very dependent on file operations performed in tests above.
    VUNIT_ASSERT_TRUE_LABELED(VFSNode(tempDirPath + "/vfsnodetest_temp_copy/one/two/test5.txt").isFile(), "copied directory, spot check test5.txt");
    VUNIT_ASSERT_TRUE_LABELED(VFSNode(tempDirPath + "/vfsnodetest_temp_copy/one/two/three/four/iter_test_0.txt").isFile(), "copied directory, spot check iter_test_0.txt");
    VUNIT_ASSERT_TRUE_LABELED(VFSNode(tempDirPath + "/vfsnodetest_temp_copy/one/two/three/four/iter_test_1.txt").isFile(), "copied directory, spot check iter_test_1.txt");
    VUNIT_ASSERT_TRUE_LABELED(VFSNode(tempDirPath + "/vfsnodetest_temp_copy/one/two/three/four/iter_test_2.txt").isFile(), "copied directory, spot check iter_test_2.txt");
    VUNIT_ASSERT_TRUE_LABELED(VFSNode(tempDirPath + "/vfsnodetest_temp_copy/one/two/three/four/iter_test_3.txt").isFile(), "copied directory, spot check iter_test_3.txt");
    
    // Verify that a non-recursive copy of source into a subdirectory of itself is allowed.
    VFSNode nrcSource(tempDirPath + "/vfsnodetest_temp/one/two");
    VFSNode nrcDest(tempDirPath + "/vfsnodetest_temp/one/two/non-recursive-copy-of-two");
    VFSNode::copyDirectory(nrcSource, nrcDest, false);
    VUNIT_ASSERT_TRUE_LABELED(VFSNode(tempDirPath + "/vfsnodetest_temp/one/two/non-recursive-copy-of-two/test5.txt").isFile(), "non-recursive nested copy succeeds on child file");
    
    // Verify that a recursive copy of source into a subdirectory of itself yields an
    // exception (rather than an infinite loop copying until disk is full!).
    try {
        VFSNode rcSource(tempDirPath + "/vfsnodetest_temp/one/two");
        VFSNode rcDest(tempDirPath + "/vfsnodetest_temp/one/two/recursive-copy-of-two");
        VFSNode::copyDirectory(nrcSource, nrcDest, true);
        VUNIT_ASSERT_FAILURE("Recursive nested copy was improperly allowed");
    } catch (const VException& ex) {
        VUNIT_ASSERT_SUCCESS("Recursive nested copy threw an exception as expected");
    }

    // Clean up our litter.
    (void) copyTest5.rm();
    (void) dirCopyTarget.rm();
    (void) nrcDest.rm();

    // Done with exercising file i/o and streams and directory stuff. Clean up our litter.

    VString deepPath;
    testDirDeeper.getParentPath(deepPath);
    VUNIT_ASSERT_EQUAL_LABELED(deepPath, tempDirPath + "/vfsnodetest_temp/one/two/three", "get parent path");

    VString nodeName;
    testDirDeeper.getName(nodeName);
    VUNIT_ASSERT_EQUAL_LABELED(nodeName, "four", "get deep node name");

    VFSNode shallowNode("shallow");
    shallowNode.getName(nodeName);
    VUNIT_ASSERT_EQUAL_LABELED(nodeName, "shallow", "get shallow node name");

    (void) testDirRoot.rm();
    VUNIT_ASSERT_FALSE_LABELED(testDirRoot.exists(), "rm tree");

    // Test some of the path string manipulation.

    VString testPath3("one/two/three");
    VFSNode testPath3Node(testPath3);

    VString testPath2;
    testPath3Node.getParentPath(testPath2);
    VFSNode testPath2Node(testPath2);
    VUNIT_ASSERT_EQUAL_LABELED(testPath2, "one/two", "parent of level 3 path");

    VString testPath1;
    testPath2Node.getParentPath(testPath1);
    VFSNode testPath1Node(testPath1);
    VUNIT_ASSERT_EQUAL_LABELED(testPath1, "one", "parent of level 2 path");

    VString testPath0;
    testPath1Node.getParentPath(testPath0);
    VFSNode testPath0Node(testPath0);
    VUNIT_ASSERT_EQUAL_LABELED(testPath0, "", "parent of level 1 path");

    // Test oddities with DOS driver letters and mapped drives. Trailing slash on drive letter may or may be present.
#ifdef VPLATFORM_WIN
    // These tests assume that C: and C:Windows exist; some installations may use a different drive letter, in which case skip the test.
    const VString DRIVE_LETTER("C");
    const VString CHILD_NODE_NAME("Windows");
    if (VFSNode(VSTRING_FORMAT("%s:/%s", DRIVE_LETTER.chars(), CHILD_NODE_NAME.chars())).exists()) {
        this->_testWindowsDrivePaths(DRIVE_LETTER, CHILD_NODE_NAME, false, true);
        this->_testWindowsDrivePaths(DRIVE_LETTER, CHILD_NODE_NAME, true, true);
    }
#endif

    // Test assignment operator.
    VFSNode someNode("a/b/c/d");
    VFSNode copiedNode;
    copiedNode = someNode;
    VUNIT_ASSERT_EQUAL_LABELED(copiedNode.getPath(), "a/b/c/d", "assignment operator");

    /*
        Uncomment if you want to exercise this code. It's commented out for now because by its nature it
        will litter several directories with its output. (It tests the APIs that locate the various
        platform-dependent directories where log files, preference files, etc. should be written.
        So for now I've chosen not to exercise this code in this unit test.

        // Test known directory location lookup. Just write a file to each directory;
        // user will have to visually check that it was put in the right place.
        this->_writeKnownDirectoryTestFile(VFSNode::USER_HOME_DIRECTORY, "unittest-user");
        this->_writeKnownDirectoryTestFile(VFSNode::LOG_FILES_DIRECTORY, "unittest-logs");
        this->_writeKnownDirectoryTestFile(VFSNode::USER_PREFERENCES_DIRECTORY, "unittest-prefs");
        this->_writeKnownDirectoryTestFile(VFSNode::CACHED_DATA_DIRECTORY, "unittest-cache");
        this->_writeKnownDirectoryTestFile(VFSNode::APPLICATION_DATA_DIRECTORY, "unittest-appdata");
        this->_writeKnownDirectoryTestFile(VFSNode::CURRENT_WORKING_DIRECTORY, "unittest-cwd");
    */
}
コード例 #7
0
VCodePoint::VCodePoint(const VString& hexNotation)
    : mIntValue(0)
    , mUTF8Length(0)
    , mUTF16Length(0)
    {
    // If the string starts with "U+" we skip it.
    // From there we assume the rest is hexadecimal, at most 8 digits.
    int length = hexNotation.length();
    int start = 0;
    if (hexNotation.startsWith("U+")) {
        start += 2;
    }
    
    if (length - start > 8) {
        throw VRangeException(VSTRING_FORMAT("VCodePoint: attempt to construct with invalid notation '%s'.", hexNotation.chars()));
    }
    
    // Walk backwards until we process all characters or see the '+'.
    
    int valueByteIndex = 0;
    for (VString::const_reverse_iterator ri = hexNotation.rbegin(); ri != hexNotation.rend(); /*incremented below*/) {
    //for (int index = length-1; index >= start; ) {
        VCodePoint nextChar = *ri;
        ++ri;

        if (nextChar == '+') {
            break;
        }

        VCodePoint lowNibbleChar = nextChar;
        VCodePoint highNibbleChar('0');

        if (ri != hexNotation.rend()) {
            nextChar = *ri;
            ++ri;

            if (nextChar != '+') {
                highNibbleChar = nextChar;
            }
        }

        if (!highNibbleChar.isHexadecimal() || !lowNibbleChar.isHexadecimal()) {
            throw VRangeException(VSTRING_FORMAT("VCodePoint: attempt to construct with invalid notation '%s'.", hexNotation.chars()));
        }
        
        // At this point we have the two hex chars. Convert to a byte, and or it into the result at the appropriate location.
        Vs32 byteValue = (Vs32) VHex::hexCharsToByte((char) highNibbleChar.intValue(), (char) lowNibbleChar.intValue()); // char TODO: VHex API update to VCodePoint
        byteValue <<= (valueByteIndex * 8);
        Vs32 mask = 0x000000FF << (valueByteIndex * 8);
        
        mIntValue |= (int) (byteValue & mask);
        
        ++valueByteIndex;

        if (nextChar == '+') {
            break;
        }
    }

    mUTF8Length = VCodePoint::getUTF8LengthFromCodePointValue(mIntValue);
    mUTF16Length = VCodePoint::getUTF16LengthFromCodePointValue(mIntValue);
}
コード例 #8
0
void VBentoMessageInputThread::_callProcessMessage(VMessageHandler* handler) {
    try {
        VMessageInputThread::_callProcessMessage(handler);
    } catch (const std::exception& ex) {
        VBentoNode responseData("response");
        responseData.addInt("result", -1);
        responseData.addString("error-message", VSTRING_FORMAT("An error occurred processing the message: %s", ex.what()));

        VString bentoText;
        responseData.writeToBentoTextString(bentoText);
        VLOGGER_NAMED_ERROR(mLoggerName, VSTRING_FORMAT("[%s] Error Reply: %s", mName.chars(), bentoText.chars()));

        VMessagePtr response = mMessageFactory->instantiateNewMessage();
        responseData.writeToStream(*response);
        VBinaryIOStream io(mSocketStream);
        response->send(mName, io);
    }
}
コード例 #9
0
void VBentoMessageInputThread::_handleNoMessageHandler(VMessagePtr message) {
    VBentoNode responseData("response");
    responseData.addInt("result", -1);
    responseData.addString("error-message", VSTRING_FORMAT("Invalid message ID %d. No handler defined.", (int) message->getMessageID()));

    VString bentoText;
    responseData.writeToBentoTextString(bentoText);
    VLOGGER_NAMED_ERROR(mLoggerName, VSTRING_FORMAT("[%s] Error Reply: %s", mName.chars(), bentoText.chars()));

    VMessagePtr response = mMessageFactory->instantiateNewMessage();
    responseData.writeToStream(*response);
    VBinaryIOStream io(mSocketStream);
    response->send(mName, io);
}