/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation \\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . Application Test-fileName Description Test some basic fileName functionality \*---------------------------------------------------------------------------*/ #include "argList.H" #include "fileName.H" #include "SubList.H" #include "DynamicList.H" #include "IOobject.H" #include "IOstreams.H" #include "OSspecific.H" #include "POSIX.H" #include "Switch.H" #include "etcFiles.H" #include "Pair.H" #include "Tuple2.H" #include using namespace Foam; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // unsigned testStrip ( const bool doClean, std::initializer_list < Tuple2 > tests ) { Info<< nl << "Checking with clean=" << Switch(doClean) << nl << endl; unsigned nFail = 0; for (const Tuple2& test : tests) { const bool expected = test.first(); const std::string& input = test.second(); fileName output(fileName::validate(input, doClean)); // Check for real failure (invalid chars) vs. // spurious failure (removed double slashes with 'doClean'). const bool same = ( doClean ? fileName::equals(input, output) : (input == output) ); if (same) { if (expected) { Info<< "(pass) validated " << input << " = " << output << nl; } else { ++nFail; Info<< "(fail) unexpected success for " << input << nl; } } else { if (expected) { ++nFail; Info<< "(fail) unexpected"; } else { Info<< "(pass) expected"; } Info<< " failure for " << input << nl; } } return nFail; } unsigned testEquals ( std::initializer_list < Tuple2> > tests ) { Info<< nl << "Checking fileName::equals()" << nl << endl; unsigned nFail = 0; for (const Tuple2>& test : tests) { const bool expected = test.first(); const std::string& s1 = test.second().first(); const std::string& s2 = test.second().second(); const bool same = fileName::equals(s1, s2); if (same) { if (expected) { Info<< "(pass) success"; } else { ++nFail; Info<< "(fail) unexpected success"; } } else { if (expected) { ++nFail; Info<< "(fail) unexpected failure"; } else { Info<< "(pass) expected failure"; } } Info<< " for " << s1 << " == " << s2 << nl; } return nFail; } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Main program: int main(int argc, char *argv[]) { argList::noParallel(); argList::addBoolOption("validate", "test fileName::validate"); argList::addBoolOption("ext", "test handing of file extensions"); argList::addBoolOption("construct", "test constructors"); argList::addBoolOption("default", "reinstate default tests"); argList::addNote("runs default tests or specified ones only"); #include "setRootCase.H" // Run default tests, unless only specific tests are requested const bool defaultTests = args.found("default") || args.options().empty(); if (args.found("construct")) { Info<< "From initializer_list = "; fileName file1 { "hello", "hello1", "hello2", "hello3", "hello4.hmm" }; Info<< file1 << nl; Info<< "From initializer_list = "; fileName file2 { file1, "some", "more/things.hmm" }; Info<< file2 << nl; Info<< "From initializer_list with nesting = "; fileName file3 { std::string("ffO"), "some", "more/things.hmm" }; Info<< file3 << nl; DynamicList base { "hello", "hello1" }; fileName file4 { "some", file3, "more/things.hmm", file1 }; Info<< "All ==> " << file4 << nl; } // Test various ext() methods if (args.found("ext")) { Info< -> " << input1.ext(e) << nl; } Info<< nl; Info<<"Test hasExt(word)" << nl <<"~~~~~~~~~~~~~~~~~" << nl; Info<<"Has extension(s):" << nl << "input: " << input1 << nl; for (const word& e : exts) { Info<<" '" << e << "' -> " << Switch(input1.hasExt(e)) << nl; } Info<< nl; Info<<"Has extension(s):" << nl << "input: " << endWithDot << nl; for (const word& e : exts) { Info<<" '" << e << "' -> " << Switch(endWithDot.hasExt(e)) << nl; } Info<< nl; Info<<"Test hasExt(wordRe)" << nl <<"~~~~~~~~~~~~~~~~~~~" << nl; // A regex with a zero length matcher doesn't work at all: // eg "(png|jpg|txt|)" regex matcher itself wordRe matcher0("()", wordRe::REGEX); wordRe matcher1("(png|jpg|txt)", wordRe::REGEX); wordRe matcher2("(png|txt)", wordRe::REGEX); Info<<"Has extension(s):" << nl << "input: " << endWithDot << nl; Info<<" " << matcher0 << " -> " << Switch(endWithDot.hasExt(matcher0)) << nl; Info<<" " << matcher1 << " -> " << Switch(endWithDot.hasExt(matcher1)) << nl; Info<<" " << matcher2 << " -> " << Switch(endWithDot.hasExt(matcher2)) << nl; Info<< "input: " << input1 << nl; Info<<" " << matcher0 << " -> " << Switch(input1.hasExt(matcher0)) << nl; Info<<" " << matcher1 << " -> " << Switch(input1.hasExt(matcher1)) << nl; Info<<" " << matcher2 << " -> " << Switch(input1.hasExt(matcher2)) << nl; Info<< nl; Info<<"Remove extension(s):" << nl << "input: " << input1 << nl; while (!input1.empty()) { if (input1.removeExt()) { Info<< " -> " << input1 << nl; } else { Info<< "stop> " << input1 << nl; break; } } Info<< nl; input0.clear(); Info<<"test with zero-sized: " << input0 << nl; Info<<"add extension: " << input0.ext("abc") << nl; Info<< nl; input0 = "this/"; Info<<"test add after slash: " << input0 << nl; Info<<"add extension: " << input0.ext("abc") << " <-- avoids accidentally creating hidden files" << nl; Info<< nl; input0 = "this.file."; Info<<"test after dot: " << input0 << nl; Info<<"add extension: " << input0.ext("abc") << " <-- No check for repeated dots (user error!)" << nl; Info<< nl; } if (args.found("validate")) { unsigned nFail = 0; Info<< nl << "Test fileName::validate" << nl; // Without clean nFail += testEquals ( { { true, { "abc", "abc/" } }, { true, { "///abc/", "//abc///" } }, { false, { " ab //c/", "ab/c" } }, } ); Info<< nl << "Test fileName::validate" << nl; // Without clean nFail += testStrip ( false, { { true, "abc/" }, { true, "/", }, { true, "//", }, { true, "/abc/def", }, { true, "/abc/def/", }, { false, "/abc def" }, { true, "/abc////def///", }, { false, "/abc//// def///" }, } ); // With clean nFail += testStrip ( true, { { true, "abc/" }, { true, "/" }, { true, "//" }, { true, "/abc/def" }, { true, "/abc/def/" }, { false, "/abc def" }, { true, "/abc////def///" }, { false, "/abc//// def///" }, } ); Info<< nl; if (nFail) { Info<< "failed " << nFail; } else { Info<< "passed all"; } Info<< " fileName::validate tests" << nl; } if (!defaultTests) { return 0; } DynamicList wrdList { "hello", "hello1", "hello2", "hello3", "hello4.hmm" }; fileName pathName(wrdList); Info<< "pathName = " << pathName << nl << "pathName.name() = >" << pathName.name() << "<\n" << "pathName.path() = " << pathName.path() << nl << "pathName.ext() = >" << pathName.ext() << "<\n" << "pathName.name(true) = >" << pathName.name(true) << "<\n"; Info<< "pathName.components() = " << pathName.components() << nl << "pathName.component(2) = " << pathName.component(2) << nl << endl; // try with different combination // The final one should emit warnings for (label start = 0; start <= wrdList.size(); ++start) { fileName instance, local; word name; fileName path(SubList(wrdList, wrdList.size()-start, start)); fileName path2 = "."/path; IOobject::fileNameComponents ( path, instance, local, name ); Info<< "IOobject::fileNameComponents for " << path << nl << " instance = " << instance << nl << " local = " << local << nl << " name = " << name << endl; IOobject::fileNameComponents ( path2, instance, local, name ); Info<< "IOobject::fileNameComponents for " << path2 << nl << " instance = " << instance << nl << " local = " << local << nl << " name = " << name << endl; } // Test some copying and deletion { const fileName dirA("dirA"); const fileName lnA("lnA"); const fileName lnB("lnB"); const fileName dirB("dirB"); Foam::rmDir(dirA); Foam::rm(lnA); Foam::rm(lnB); Foam::rmDir(dirB); Info<< nl << "=========================" << nl << "Test some copying and deletion" << endl; Info<< "Creating directory " << dirA << endl; Foam::mkDir(dirA); Info<< "Populating with various files" << endl; for ( const std::string name : { "file-1", "file-2", "bad name one", "bad name 2" } ) { // Full path, but without any stripping const fileName file ( (static_cast(dirA) + "/" + name), false ); Info<<" create: " << file << endl; std::ofstream os(file); os << "file=<" << file << ">" << nl; } const int oldPosix = POSIX::debug; POSIX::debug = 1; // Create link and test it Info<< "Creating softlink " << lnA << endl; Foam::ln(dirA, lnA); fileName::Type lnAType = lnA.type(false); if (lnAType != fileName::LINK) { FatalErrorIn("Test-fileName") << "Type of softlink " << lnA << " should be " << fileName::LINK << " but is " << lnAType << exit(FatalError); } fileName::Type dirAType = lnA.type(true); if (dirAType != fileName::DIRECTORY) { FatalErrorIn("Test-fileName") << "Type of what softlink " << lnA << " points to should be " << fileName::DIRECTORY << " but is " << dirAType << exit(FatalError); } // Copy link only { Info<< "Copying (non-follow) softlink " << lnA << " to " << lnB << endl; Foam::cp(lnA, lnB, false); if (lnB.type(false) != fileName::LINK) { FatalErrorIn("Test-fileName") << "Type of softlink " << lnB << " should be " << fileName::LINK << " but is " << lnB.type(false) << exit(FatalError); } if (lnB.type(true) != fileName::DIRECTORY) { FatalErrorIn("Test-fileName") << "Type of softlink " << lnB << " should be " << fileName::DIRECTORY << " but is " << lnB.type(true) << exit(FatalError); } // Delete (link) Foam::rm(lnB); } // Copy contents of link { Info<< "Copying (contents of) softlink " << lnA << " to " << lnB << endl; Foam::cp(lnA, lnB, true); if (lnB.type(false) != fileName::DIRECTORY) { FatalErrorIn("Test-fileName") << "Type of softlink " << lnB << " should be " << fileName::DIRECTORY << " but is " << lnB.type(false) << exit(FatalError); } // Delete (directory, not link) Foam::rmDir(lnB); } POSIX::debug = oldPosix; // Verify that rmDir works with bad names too Foam::rmDir(dirA); Foam::rm(lnA); } // test findEtcFile Info<< "\n\nfindEtcFile tests:" << nl << " controlDict => " << findEtcFile("controlDict") << nl << " badName => " << findEtcFile("badName") << endl; Info<< "This should emit a fatal error:" << endl; Info<< " badName(die) => " << findEtcFile("badName", true) << nl << endl; Info<< "\nEnd\n" << endl; return 0; } // ************************************************************************* //