Compare commits

..
34 Commits
Author SHA1 Message Date
Kelson 3b7c805183 Bump-up version to 8.2.0 2019-11-20 13:07:28 +01:00
Kelson 9c4867a95a Update Changelog 2019-11-20 13:06:24 +01:00
Kelson 223f7ee78a Add default Github configuration 2019-11-20 06:12:08 +01:00
Kelson 20690bd5f5 Merge pull request #294 from kiwix/remove-absolute-url-support
Remove absolute internal URL support
2019-11-08 15:29:40 +01:00
Emmanuel Engelhart de7b7c34b5 Remove absolute internal URL support 2019-11-07 18:05:58 +01:00
Kelson f0ac66aea1 Merge pull request #292 from kiwix/aria2-comment
More error handling for aria2 cmd
2019-11-01 15:40:51 +01:00
luddens 20a2c78733 add get aria2 launch cmd method 2019-11-01 15:27:21 +01:00
luddens 9850be7267 add Curl error message 2019-11-01 15:27:21 +01:00
luddens 0dd996c6a3 add try catch around aria2 first commands 2019-11-01 15:27:21 +01:00
Kelson 2500cc8e63 Merge pull request #288 from kiwix/get-bookmarks-api
Add a parameter to getBookmarks fct to get valid bookmarks only
2019-10-31 14:38:50 +01:00
luddens bd6797143c add getBookmarks test 2019-10-31 15:01:52 +02:00
luddens c9a15c9961 Add a parameter to getBookmarks fct to get valid bookmarks only
The default value of this parameter is false, in this case all the bookmarks
are returned, otherwise only those who are related to books of the library.
2019-10-31 14:05:21 +02:00
Kelson f1d55f8e86 Merge pull request #290 from kiwix/set-port-kiwixserve
add setPort() method
2019-10-28 16:41:19 +01:00
luddens a2c2955f41 add kiwixserve unit test 2019-10-28 16:00:26 +01:00
luddens 9975e0b369 add setPort() method 2019-10-28 15:56:49 +01:00
Kelson efe1c2dea3 Merge pull request #289 from Aditya-Sood/kiwix-android/issue/765
Fixes kiwix-android issue#765
2019-10-03 11:25:18 +01:00
Aditya-Sood 2af9ba4eab Readd original getNextSuggestion() 2019-10-01 13:30:35 +05:30
Aditya-Sood c007373b46 Re-add comment 2019-10-01 13:30:34 +05:30
Aditya-Sood e1acf9acff Code & local repository cleanup 2019-10-01 13:30:34 +05:30
Aditya-Sood daaadf3e1c Comment out previous definitions 2019-10-01 13:30:34 +05:30
Aditya-Sood 74bd482335 Preliminary work 2019-10-01 13:30:34 +05:30
Matthieu Gautier 2aebffb27c New version 8.1.0 2019-09-26 15:56:30 +02:00
Kelson da247b3242 Merge pull request #287 from kiwix/codecov-badge
Add Codecov badge to README
2019-09-26 13:40:57 +03:00
Kelson f85ec9ea6f Add Codecov badge to README 2019-09-26 12:37:57 +02:00
Matthieu Gautier b4fac9d0df Remove test directory from codecoverage (#286)
Remove test directory from codecoverage
2019-09-26 12:14:03 +02:00
Matthieu Gautier 4f2ede80e5 Remove test directory from codecoverage 2019-09-26 12:00:33 +02:00
Matthieu Gautier c2ecb9d126 Add code coverage in travis CI. (#285)
Add code coverage in travis CI.
2019-09-26 11:58:49 +02:00
Matthieu Gautier 5883dba0ef Add code coverage in travis CI.
Fix #284
2019-09-26 11:34:35 +02:00
Matthieu Gautier 7ad6aedd66 Convert path get from windows environment to utf8. (#283)
Convert path get from windows environment to utf8.
2019-09-25 18:13:59 +02:00
Matthieu Gautier 67170709bb Convert path get from windows environment to utf8.
Fix kiwix/kiwix-desktop#203
2019-09-25 18:07:42 +02:00
Matthieu Gautier dfd16155af Add missing implementation of android's getArticleCount and getM… (#282)
Add missing implementation of android's getArticleCount and getMediaCount.
2019-09-24 11:57:00 +02:00
Matthieu Gautier 0db06d98a8 Add missing implementation of android's getArticleCount and getMediaCount.
Fix #281
2019-09-24 11:47:05 +02:00
Matthieu Gautier 742156d366 [API Break] Fix pathTools (and a bit stringTools). (#280)
[API Break] Fix pathTools (and a bit stringTools).
2019-09-24 10:58:51 +02:00
Matthieu Gautier 598dd3c175 [API Break] Fix pathTools (and a bit stringTools).
Api changes :
 - removeLastPathElement do not takes extra arguments
   `removePreSeparator` and `removePostSeparator`.
   This is not needed as path do not need special tailing separator.
 - Only one function `split`. Arguments can be implicitly convert to
   string. No need for overloading functions to explicitly cast them.
 - `split` function takes another argument `trimEmpty`. If true, empty
   element are removed.

Path manipulation now almost pass trough a vector<string> to store each
path's part.

Most of the complex works is now made in the normalizeParts function.
2019-09-19 18:16:06 +02:00
31 changed files with 655 additions and 170 deletions

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
codecov:
notify:
require_ci_to_pass: yes
coverage:
status:
project:
default:
threshold: 1%
ignore:
- "test"
+12
View File
@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://kiwix.org/support-us/
+27
View File
@@ -0,0 +1,27 @@
# Configuration for Move Issues - https://github.com/dessant/move-issues
# Delete the command comment when it contains no other content
deleteCommand: true
# Close the source issue after moving
closeSourceIssue: true
# Lock the source issue after moving
lockSourceIssue: false
# Mention issue and comment authors
mentionAuthors: true
# Preserve mentions in the issue content
keepContentMentions: true
# Move labels that also exist on the target repository
moveLabels: true
# Set custom aliases for targets
# aliases:
# r: repo
# or: owner/repo
# Repository to extend settings from
# _extends: repo
+15
View File
@@ -0,0 +1,15 @@
daysUntilClose: false
staleLabel: stale
issues:
daysUntilStale: 60
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be now be reviewed manually. Thank you
for your contributions.
pulls:
daysUntilStale: 7
markComment: >
This pull request has been automatically marked as stale because it has not had
recent activity. It will be now be reviewed manually. Thank you
for your contributions.
+5
View File
@@ -31,6 +31,11 @@ addons:
- gcc-mingw-w64-i686 - gcc-mingw-w64-i686
- gcc-mingw-w64-base - gcc-mingw-w64-base
- mingw-w64-tools - mingw-w64-tools
- gcovr
homebrew:
update: true
packages:
- gcovr
matrix: matrix:
include: include:
- env: PLATFORM="native_dyn" - env: PLATFORM="native_dyn"
+15
View File
@@ -1,3 +1,18 @@
kiwix-lib 8.2.0
===============
* More debug information if aria2c command fails
* Allow to set kiwix-serve port
* Better (dead) bookmarks mgmt
kiwix-lib 8.1.0
===============
* Fix pathTools manipulation.
* Add missing implementation of getArticleCount and getMediaCount on android.
* Correctly convert windows path to utf8.
* Add code coverage in the CI
kiwix-lib 8.0.1 kiwix-lib 8.0.1
=============== ===============
+1
View File
@@ -9,6 +9,7 @@ GNU/Linux, macOS, Android, iOS, ...).
[![AUR version](https://img.shields.io/aur/version/kiwix-lib)](https://aur.archlinux.org/packages/kiwix-lib/) [![AUR version](https://img.shields.io/aur/version/kiwix-lib)](https://aur.archlinux.org/packages/kiwix-lib/)
[![Build Status](https://travis-ci.org/kiwix/kiwix-lib.svg?branch=master)](https://travis-ci.org/kiwix/kiwix-lib) [![Build Status](https://travis-ci.org/kiwix/kiwix-lib.svg?branch=master)](https://travis-ci.org/kiwix/kiwix-lib)
[![CodeFactor](https://www.codefactor.io/repository/github/kiwix/kiwix-lib/badge)](https://www.codefactor.io/repository/github/kiwix/kiwix-lib) [![CodeFactor](https://www.codefactor.io/repository/github/kiwix/kiwix-lib/badge)](https://www.codefactor.io/repository/github/kiwix/kiwix-lib)
[![Codecov](https://codecov.io/gh/kiwix/kiwix-lib/branch/master/graph/badge.svg)](https://codecov.io/gh/kiwix/kiwix-lib)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
Disclaimer Disclaimer
@@ -26,7 +26,7 @@ task writePom {
project { project {
groupId 'org.kiwix.kiwixlib' groupId 'org.kiwix.kiwixlib'
artifactId 'kiwixlib' artifactId 'kiwixlib'
version '8.0.1' + (System.env.KIWIXLIB_BUILDVERSION == null ? '' : '-'+System.env.KIWIXLIB_BUILDVERSION) version '8.1.0' + (System.env.KIWIXLIB_BUILDVERSION == null ? '' : '-'+System.env.KIWIXLIB_BUILDVERSION)
packaging 'aar' packaging 'aar'
name 'kiwixlib' name 'kiwixlib'
url 'https://github.com/kiwix/kiwix-lib' url 'https://github.com/kiwix/kiwix-lib'
+1
View File
@@ -97,6 +97,7 @@ class Downloader
size_t getNbDownload() { return m_knownDownloads.size(); } size_t getNbDownload() { return m_knownDownloads.size(); }
std::vector<std::string> getDownloadIds(); std::vector<std::string> getDownloadIds();
const std::string &getAria2LaunchCmd();
private: private:
std::map<std::string, std::unique_ptr<Download>> m_knownDownloads; std::map<std::string, std::unique_ptr<Download>> m_knownDownloads;
+1
View File
@@ -17,6 +17,7 @@ class KiwixServe
void shutDown(); void shutDown();
bool isRunning(); bool isRunning();
int getPort() { return m_port; } int getPort() { return m_port; }
int setPort(int port);
private: private:
std::unique_ptr<Subprocess> mp_kiwixServe; std::unique_ptr<Subprocess> mp_kiwixServe;
+1 -1
View File
@@ -208,7 +208,7 @@ class Library
* *
* @return A list of bookmarks * @return A list of bookmarks
*/ */
const std::vector<kiwix::Bookmark>& getBookmarks() { return m_bookmarks; } const std::vector<kiwix::Bookmark> getBookmarks(bool onlyValidBookmarks = true);
/** /**
* Get all book ids of the books in the library. * Get all book ids of the books in the library.
+1 -3
View File
@@ -25,9 +25,7 @@
bool isRelativePath(const std::string& path); bool isRelativePath(const std::string& path);
std::string computeAbsolutePath(const std::string& path, const std::string& relativePath); std::string computeAbsolutePath(const std::string& path, const std::string& relativePath);
std::string computeRelativePath(const std::string& path, const std::string& absolutePath); std::string computeRelativePath(const std::string& path, const std::string& absolutePath);
std::string removeLastPathElement(const std::string& path, std::string removeLastPathElement(const std::string& path);
const bool removePreSeparator = false,
const bool removePostSeparator = false);
std::string appendToDirectory(const std::string& directoryPath, const std::string& filename); std::string appendToDirectory(const std::string& directoryPath, const std::string& filename);
unsigned int getFileSize(const std::string& path); unsigned int getFileSize(const std::string& path);
+1 -4
View File
@@ -43,10 +43,7 @@ void loadICUExternalTables();
std::string urlEncode(const std::string& value, bool encodeReserved = false); std::string urlEncode(const std::string& value, bool encodeReserved = false);
std::string urlDecode(const std::string& value, bool component = false); std::string urlDecode(const std::string& value, bool component = false);
std::vector<std::string> split(const std::string&, const std::string&); std::vector<std::string> split(const std::string&, const std::string&, bool trimEmpty = true);
std::vector<std::string> split(const char*, const char*);
std::vector<std::string> split(const std::string&, const char*);
std::vector<std::string> split(const char*, const std::string&);
std::string join(const std::vector<std::string>& list, const std::string& sep); std::string join(const std::vector<std::string>& list, const std::string& sep);
std::string ucAll(const std::string& word); std::string ucAll(const std::string& word);
+1 -1
View File
@@ -1,5 +1,5 @@
project('kiwix-lib', 'cpp', project('kiwix-lib', 'cpp',
version : '8.0.1', # Also change this in android-kiwix-lib-publisher/kiwixLibAndroid/build.gradle version : '8.2.0', # Also change this in android-kiwix-lib-publisher/kiwixLibAndroid/build.gradle
license : 'GPL', license : 'GPL',
default_options : ['c_std=c11', 'cpp_std=c++11', 'werror=true']) default_options : ['c_std=c11', 'cpp_std=c++11', 'werror=true'])
+34 -2
View File
@@ -353,14 +353,17 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_searchSuggestions(JNIEnv* env,
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_org_kiwix_kiwixlib_JNIKiwixReader_getNextSuggestion(JNIEnv* env, Java_org_kiwix_kiwixlib_JNIKiwixReader_getNextSuggestion(JNIEnv* env,
jobject obj, jobject obj,
jobject titleObj) jobject titleObj,
jobject urlObj)
{ {
jboolean retVal = JNI_FALSE; jboolean retVal = JNI_FALSE;
std::string cTitle; std::string cTitle;
std::string cUrl;
try { try {
if (READER->getNextSuggestion(cTitle)) { if (READER->getNextSuggestion(cTitle, cUrl)) {
setStringObjValue(cTitle, titleObj, env); setStringObjValue(cTitle, titleObj, env);
setStringObjValue(cUrl, urlObj, env);
retVal = JNI_TRUE; retVal = JNI_TRUE;
} }
} catch (std::exception& e) { } catch (std::exception& e) {
@@ -424,6 +427,35 @@ Java_org_kiwix_kiwixlib_JNIKiwixReader_getDescription(JNIEnv* env, jobject obj)
return description; return description;
} }
JNIEXPORT jint JNICALL
Java_org_kiwix_kiwixlib_JNIKiwixReader_getArticleCount(JNIEnv* env, jobject obj)
{
jint articleCount = 0;
try {
auto cArticleCount = READER->getArticleCount();
articleCount = c2jni(cArticleCount);
} catch (std::exception& e) {
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get article count.");
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
}
return articleCount;
}
JNIEXPORT jint JNICALL
Java_org_kiwix_kiwixlib_JNIKiwixReader_getMediaCount(JNIEnv* env, jobject obj)
{
jint mediaCount = 0;
try {
auto cMediaCount = READER->getMediaCount();
mediaCount = c2jni(cMediaCount);
} catch (std::exception& e) {
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get media count.");
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
}
return mediaCount;
}
JNIEXPORT jboolean JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getRandomPage( JNIEXPORT jboolean JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getRandomPage(
JNIEnv* env, jobject obj, jobject urlObj) JNIEnv* env, jobject obj, jobject urlObj)
{ {
@@ -102,7 +102,7 @@ public class JNIKiwixReader
public native boolean searchSuggestions(String prefix, int count); public native boolean searchSuggestions(String prefix, int count);
public native boolean getNextSuggestion(JNIKiwixString title); public native boolean getNextSuggestion(JNIKiwixString title, JNIKiwixString url);
public native boolean getPageUrlFromTitle(String title, JNIKiwixString url); public native boolean getPageUrlFromTitle(String title, JNIKiwixString url);
+15 -1
View File
@@ -49,7 +49,7 @@ Aria2::Aria2():
m_secret = "token:"+m_secret; m_secret = "token:"+m_secret;
std::string aria2cmd = appendToDirectory( std::string aria2cmd = appendToDirectory(
removeLastPathElement(getExecutablePath(true), true, true), removeLastPathElement(getExecutablePath(true)),
ARIA2_CMD); ARIA2_CMD);
if (fileExists(aria2cmd)) { if (fileExists(aria2cmd)) {
// A local aria2c exe exists (packaged with kiwix-desktop), use it. // A local aria2c exe exists (packaged with kiwix-desktop), use it.
@@ -78,18 +78,32 @@ Aria2::Aria2():
callCmd.push_back("--max-concurrent-downloads=42"); callCmd.push_back("--max-concurrent-downloads=42");
callCmd.push_back("--rpc-max-request-size=6M"); callCmd.push_back("--rpc-max-request-size=6M");
callCmd.push_back("--file-allocation=none"); callCmd.push_back("--file-allocation=none");
for (auto &cmd : callCmd) {
m_launchCmd.append(cmd).append(" ");
}
mp_aria = Subprocess::run(callCmd); mp_aria = Subprocess::run(callCmd);
mp_curl = curl_easy_init(); mp_curl = curl_easy_init();
char errbuf[CURL_ERROR_SIZE];
curl_easy_setopt(mp_curl, CURLOPT_URL, "http://localhost/rpc"); curl_easy_setopt(mp_curl, CURLOPT_URL, "http://localhost/rpc");
curl_easy_setopt(mp_curl, CURLOPT_PORT, m_port); curl_easy_setopt(mp_curl, CURLOPT_PORT, m_port);
curl_easy_setopt(mp_curl, CURLOPT_POST, 1L); curl_easy_setopt(mp_curl, CURLOPT_POST, 1L);
curl_easy_setopt(mp_curl, CURLOPT_ERRORBUFFER, errbuf);
int watchdog = 50; int watchdog = 50;
while(--watchdog) { while(--watchdog) {
sleep(10); sleep(10);
errbuf[0] = 0;
auto res = curl_easy_perform(mp_curl); auto res = curl_easy_perform(mp_curl);
if (res == CURLE_OK) { if (res == CURLE_OK) {
break; break;
} else if (watchdog == 1) {
std::cerr <<" curl_easy_perform() failed." << std::endl;
fprintf(stderr, "\nlibcurl: (%d) ", res);
if (errbuf[0] != 0) {
std::cerr << errbuf << std::endl;
} else {
std::cerr << curl_easy_strerror(res) << std::endl;
}
} }
} }
if (!watchdog) { if (!watchdog) {
+2
View File
@@ -26,6 +26,7 @@ class Aria2
std::string m_downloadDir; std::string m_downloadDir;
CURL* mp_curl; CURL* mp_curl;
pthread_mutex_t m_lock; pthread_mutex_t m_lock;
std::string m_launchCmd;
std::string doRequest(const MethodCall& methodCall); std::string doRequest(const MethodCall& methodCall);
@@ -43,6 +44,7 @@ class Aria2
void pause(const std::string& gid); void pause(const std::string& gid);
void unpause(const std::string& gid); void unpause(const std::string& gid);
void remove(const std::string& gid); void remove(const std::string& gid);
const std::string &getLaunchCmd() { return m_launchCmd; };
}; };
}; //end namespace kiwix }; //end namespace kiwix
+19 -7
View File
@@ -127,17 +127,24 @@ void Download::cancelDownload()
Downloader::Downloader() : Downloader::Downloader() :
mp_aria(new Aria2()) mp_aria(new Aria2())
{ {
for (auto gid : mp_aria->tellActive()) { try {
m_knownDownloads[gid] = std::unique_ptr<Download>(new Download(mp_aria, gid)); for (auto gid : mp_aria->tellActive()) {
m_knownDownloads[gid]->updateStatus(); m_knownDownloads[gid] = std::unique_ptr<Download>(new Download(mp_aria, gid));
m_knownDownloads[gid]->updateStatus();
}
} catch (std::exception& e) {
std::cerr << "aria2 tellActive failed : " << e.what();
} }
for (auto gid : mp_aria->tellWaiting()) { try {
m_knownDownloads[gid] = std::unique_ptr<Download>(new Download(mp_aria, gid)); for (auto gid : mp_aria->tellWaiting()) {
m_knownDownloads[gid]->updateStatus(); m_knownDownloads[gid] = std::unique_ptr<Download>(new Download(mp_aria, gid));
m_knownDownloads[gid]->updateStatus();
}
} catch (std::exception& e) {
std::cerr << "aria2 tellWaiting failed : " << e.what();
} }
} }
/* Destructor */ /* Destructor */
Downloader::~Downloader() Downloader::~Downloader()
{ {
@@ -156,6 +163,11 @@ std::vector<std::string> Downloader::getDownloadIds() {
return ret; return ret;
} }
const std::string &Downloader::getAria2LaunchCmd()
{
return mp_aria->getLaunchCmd();
}
Download* Downloader::startDownload(const std::string& uri) Download* Downloader::startDownload(const std::string& uri)
{ {
for (auto& p: m_knownDownloads) { for (auto& p: m_knownDownloads) {
+11 -1
View File
@@ -36,7 +36,7 @@ void KiwixServe::run()
std::vector<const char*> callCmd; std::vector<const char*> callCmd;
std::string kiwixServeCmd = appendToDirectory( std::string kiwixServeCmd = appendToDirectory(
removeLastPathElement(getExecutablePath(true), true, true), removeLastPathElement(getExecutablePath(true)),
KIWIXSERVE_CMD); KIWIXSERVE_CMD);
if (fileExists(kiwixServeCmd)) { if (fileExists(kiwixServeCmd)) {
// A local kiwix-serve exe exists (packaged with kiwix-desktop), use it. // A local kiwix-serve exe exists (packaged with kiwix-desktop), use it.
@@ -68,4 +68,14 @@ bool KiwixServe::isRunning()
return false; return false;
} }
int KiwixServe::setPort(int port)
{
if (port >= 1 && port <= 65535) {
m_port = port;
} else {
return -1;
}
return m_port;
}
} }
+16 -1
View File
@@ -115,7 +115,7 @@ unsigned int Library::getBookCount(const bool localBooks,
bool Library::writeToFile(const std::string& path) bool Library::writeToFile(const std::string& path)
{ {
auto baseDir = removeLastPathElement(path, true, false); auto baseDir = removeLastPathElement(path);
LibXMLDumper dumper(this); LibXMLDumper dumper(this);
dumper.setBaseDir(baseDir); dumper.setBaseDir(baseDir);
return writeTextFile(path, dumper.dumpLibXMLContent(getBooksIds())); return writeTextFile(path, dumper.dumpLibXMLContent(getBooksIds()));
@@ -184,6 +184,21 @@ std::vector<std::string> Library::getBooksPublishers()
return booksPublishers; return booksPublishers;
} }
const std::vector<kiwix::Bookmark> Library::getBookmarks(bool onlyValidBookmarks)
{
if (!onlyValidBookmarks) {
return m_bookmarks;
}
std::vector<kiwix::Bookmark> validBookmarks;
auto booksId = getBooksIds();
for(auto& bookmark:m_bookmarks) {
if (std::find(booksId.begin(), booksId.end(), bookmark.getBookId()) != booksId.end()) {
validBookmarks.push_back(bookmark);
}
}
return validBookmarks;
}
std::vector<std::string> Library::getBooksIds() std::vector<std::string> Library::getBooksIds()
{ {
std::vector<std::string> bookIds; std::vector<std::string> bookIds;
+2 -2
View File
@@ -59,7 +59,7 @@ bool Manager::parseXmlDom(const pugi::xml_document& doc,
book.setReadOnly(readOnly); book.setReadOnly(readOnly);
book.updateFromXml(bookNode, book.updateFromXml(bookNode,
removeLastPathElement(libraryPath, true, false)); removeLastPathElement(libraryPath));
/* Update the book properties with the new importer */ /* Update the book properties with the new importer */
if (libraryVersion.empty() if (libraryVersion.empty()
@@ -177,7 +177,7 @@ std::string Manager::addBookFromPathAndGetId(const std::string& pathToOpen,
if (pathToSave != pathToOpen) { if (pathToSave != pathToOpen) {
book.setPath(isRelativePath(pathToSave) book.setPath(isRelativePath(pathToSave)
? computeAbsolutePath( ? computeAbsolutePath(
removeLastPathElement(writableLibraryPath, true, false), removeLastPathElement(writableLibraryPath),
pathToSave) pathToSave)
: pathToSave); : pathToSave);
} }
-16
View File
@@ -871,22 +871,6 @@ Response InternalServer::handle_content(const RequestContext& request)
content = string(raw_content.data(), raw_content.size()); content = string(raw_content.data(), raw_content.size());
auto response = get_default_response(); auto response = get_default_response();
response.set_mimeType(mimeType); response.set_mimeType(mimeType);
/* Special rewrite URL in case of ZIM file use intern *asbolute* url like
* /A/Kiwix */
if (mimeType.find("text/html") != string::npos) {
content = replaceRegex(content,
"$1$2" + m_root + "/" + bookName + "/$3/",
"(href|src)(=[\"|\']{0,1})/([A-Z|\\-])/");
content = replaceRegex(content,
"$1$2" + m_root + "/" + bookName + "/$3/",
"(@import[ ]+)([\"|\']{0,1})/([A-Z|\\-])/");
response.set_taskbar(bookName, reader->getTitle());
} else if (mimeType.find("text/css") != string::npos) {
content = replaceRegex(content,
"$1$2" + m_root + "/" + bookName + "/$3/",
"(url|URL)(\\([\"|\']{0,1})/([A-Z|\\-])/");
}
response.set_content(content); response.set_content(content);
response.set_compress(true); response.set_compress(true);
response.set_cache(true); response.set_cache(true);
+139 -103
View File
@@ -39,11 +39,12 @@
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <algorithm>
#ifdef _WIN32 #ifdef _WIN32
const std::string SEPARATOR("\\"); #define SEPARATOR "\\"
#else #else
const std::string SEPARATOR("/"); #define SEPARATOR "/"
#include <unistd.h> #include <unistd.h>
#endif #endif
@@ -53,6 +54,25 @@ const std::string SEPARATOR("/");
#define PATH_MAX 1024 #define PATH_MAX 1024
#endif #endif
#ifdef _WIN32
std::string WideToUtf8(const std::wstring& wstr)
{
auto needed_size = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr.size(), NULL, 0, NULL, NULL);
std::string ret(needed_size, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr.size(), &ret[0], needed_size, NULL, NULL);
return ret;
}
std::wstring Utf8ToWide(const std::string& str)
{
auto needed_size = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), NULL, 0);
std::wstring ret(needed_size, 0);
MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), &ret[0], needed_size);
return ret;
}
#endif
bool isRelativePath(const std::string& path) bool isRelativePath(const std::string& path)
{ {
#ifdef _WIN32 #ifdef _WIN32
@@ -62,11 +82,65 @@ bool isRelativePath(const std::string& path)
#endif #endif
} }
std::vector<std::string> normalizeParts(std::vector<std::string> parts, bool absolute)
{
std::vector<std::string> ret;
#ifdef _WIN32
//Special case if we have a drive directory not at first.
//Starts from there.
auto it = find_if(parts.rbegin(), parts.rend(),
[](const std::string& p) ->bool
{ return p.length() == 2 && p[1] == ':'; });
if (it != parts.rend()) {
parts.erase(parts.begin(), it.base()-1);
}
#endif
size_t index = 0;
for (auto& part: parts) {
index++;
if (part == "..") {
if (absolute) {
// We try to remove as far as possible.
if (ret.size() > 1) {
ret.pop_back();
}
} else {
// We remove only if we can remove it.
// Else we add it.
if (!ret.empty() && ret.back() != "..") {
ret.pop_back();
} else {
ret.push_back("..");
}
}
continue;
}
if (part == "") {
#ifndef _WIN32
if (ret.empty() && (absolute || index<parts.size())) {
ret.push_back("");
}
#endif
continue;
}
if (part == ".") {
continue;
}
ret.push_back(part);
}
#ifndef _WIN32
if (absolute && ret.size() == 1 && ret.back() == "") {
ret.push_back("");
}
#endif
return ret;
}
std::string computeRelativePath(const std::string& path, const std::string& absolutePath) std::string computeRelativePath(const std::string& path, const std::string& absolutePath)
{ {
std::vector<std::string> pathParts = kiwix::split(path, SEPARATOR); auto pathParts = normalizeParts(kiwix::split(path, SEPARATOR, false), false);
std::vector<std::string> absolutePathParts auto absolutePathParts = kiwix::split(absolutePath, SEPARATOR, false);
= kiwix::split(absolutePath, SEPARATOR);
unsigned int commonCount = 0; unsigned int commonCount = 0;
while (commonCount < pathParts.size() while (commonCount < pathParts.size()
@@ -75,108 +149,60 @@ std::string computeRelativePath(const std::string& path, const std::string& abso
commonCount++; commonCount++;
} }
std::string relativePath; std::vector<std::string> relativeParts;
#ifdef _WIN32
/* On Windows you have a token more because the root is represented
by a letter */
if (commonCount == 0) {
relativePath = ".." + SEPARATOR;
}
#endif
for (unsigned int i = commonCount; i < pathParts.size(); i++) { for (unsigned int i = commonCount; i < pathParts.size(); i++) {
relativePath += ".." + SEPARATOR; relativeParts.push_back("..");
} }
for (unsigned int i = commonCount; i < absolutePathParts.size(); i++) { for (unsigned int i = commonCount; i < absolutePathParts.size(); i++) {
relativePath += absolutePathParts[i]; relativeParts.push_back(absolutePathParts[i]);
relativePath += i + 1 < absolutePathParts.size() ? SEPARATOR : "";
} }
return relativePath; auto ret = kiwix::join(normalizeParts(relativeParts, false), SEPARATOR);
return ret;
} }
#ifdef _WIN32
# define STRTOK strtok_s
#else
# define STRTOK strtok_r
#endif
/* Warning: the relative path must be with slashes */
std::string computeAbsolutePath(const std::string& path, const std::string& relativePath) std::string computeAbsolutePath(const std::string& path, const std::string& relativePath)
{ {
std::string absolutePath; std::string absolutePath = path;
if (path.empty()) { if (path.empty()) {
char* path = NULL; absolutePath = getCurrentDirectory();
size_t size = 0;
#ifdef _WIN32
path = _getcwd(path, size);
#else
path = getcwd(path, size);
#endif
absolutePath = std::string(path) + SEPARATOR;
} else {
absolutePath = path.substr(path.length() - 1, 1) == SEPARATOR
? path
: path + SEPARATOR;
} }
#if _WIN32 auto absoluteParts = normalizeParts(kiwix::split(absolutePath, SEPARATOR, false), true);
char* cRelativePath = _strdup(relativePath.c_str()); auto relativeParts = kiwix::split(relativePath, SEPARATOR, false);
#else
char* cRelativePath = strdup(relativePath.c_str());
#endif
char* saveptr = nullptr;
char* token = STRTOK(cRelativePath, "/", &saveptr);
while (token != NULL) { absoluteParts.insert(absoluteParts.end(), relativeParts.begin(), relativeParts.end());
if (std::string(token) == "..") { auto ret = kiwix::join(normalizeParts(absoluteParts, true), SEPARATOR);
absolutePath = removeLastPathElement(absolutePath, true, false); return ret;
token = STRTOK(NULL, "/", &saveptr);
} else if (strcmp(token, ".") && strcmp(token, "")) {
absolutePath += std::string(token);
token = STRTOK(NULL, "/", &saveptr);
if (token != NULL) {
absolutePath += SEPARATOR;
}
} else {
token = STRTOK(NULL, "/", &saveptr);
}
}
free(cRelativePath);
return absolutePath;
} }
std::string removeLastPathElement(const std::string& path, std::string removeLastPathElement(const std::string& path)
const bool removePreSeparator,
const bool removePostSeparator)
{ {
std::string newPath = path; auto parts = normalizeParts(kiwix::split(path, SEPARATOR, false), false);
size_t offset = newPath.find_last_of(SEPARATOR); if (!parts.empty()) {
if (removePreSeparator && parts.pop_back();
#ifndef _WIN32
offset != newPath.find_first_of(SEPARATOR) &&
#endif
offset == newPath.length() - 1) {
newPath = newPath.substr(0, offset);
offset = newPath.find_last_of(SEPARATOR);
} }
newPath = removePostSeparator ? newPath.substr(0, offset) auto ret = kiwix::join(parts, SEPARATOR);
: newPath.substr(0, offset + 1); return ret;
return newPath;
} }
std::string appendToDirectory(const std::string& directoryPath, const std::string& filename) std::string appendToDirectory(const std::string& directoryPath, const std::string& filename)
{ {
std::string newPath = directoryPath + SEPARATOR + filename; std::string newPath = directoryPath;
if (!directoryPath.empty() && directoryPath.back() != SEPARATOR[0]) {
newPath += SEPARATOR;
}
newPath += filename;
return newPath; return newPath;
} }
std::string getLastPathElement(const std::string& path) std::string getLastPathElement(const std::string& path)
{ {
return path.substr(path.find_last_of(SEPARATOR) + 1); auto parts = normalizeParts(kiwix::split(path, SEPARATOR), false);
if (parts.empty()) {
return "";
}
auto ret = parts.back();
return ret;
} }
unsigned int getFileSize(const std::string& path) unsigned int getFileSize(const std::string& path)
@@ -216,7 +242,7 @@ std::string getFileContent(const std::string& path)
bool fileExists(const std::string& path) bool fileExists(const std::string& path)
{ {
#ifdef _WIN32 #ifdef _WIN32
return PathFileExists(path.c_str()); return PathFileExistsW(Utf8ToWide(path).c_str());
#else #else
bool flag = false; bool flag = false;
std::fstream fin; std::fstream fin;
@@ -232,7 +258,7 @@ bool fileExists(const std::string& path)
bool makeDirectory(const std::string& path) bool makeDirectory(const std::string& path)
{ {
#ifdef _WIN32 #ifdef _WIN32
int status = _mkdir(path.c_str()); int status = _wmkdir(Utf8ToWide(path).c_str());
#else #else
int status = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); int status = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif #endif
@@ -242,15 +268,15 @@ bool makeDirectory(const std::string& path)
std::string makeTmpDirectory() std::string makeTmpDirectory()
{ {
#ifdef _WIN32 #ifdef _WIN32
char cbase[MAX_PATH]; wchar_t cbase[MAX_PATH];
char ctmp[MAX_PATH]; wchar_t ctmp[MAX_PATH];
GetTempPath(MAX_PATH-14, cbase); GetTempPathW(MAX_PATH-14, cbase);
// This create a file for us, ensure it is unique. // This create a file for us, ensure it is unique.
// So we need to delete it and create the directory using the same name. // So we need to delete it and create the directory using the same name.
GetTempFileName(cbase, "kiwix", 0, ctmp); GetTempFileNameW(cbase, L"kiwix", 0, ctmp);
DeleteFile(ctmp); DeleteFileW(ctmp);
_mkdir(ctmp); _wmkdir(ctmp);
return std::string(ctmp); return WideToUtf8(ctmp);
#else #else
char _template_array[] = {"/tmp/kiwix-lib_XXXXXX"}; char _template_array[] = {"/tmp/kiwix-lib_XXXXXX"};
std::string dir = mkdtemp(_template_array); std::string dir = mkdtemp(_template_array);
@@ -281,34 +307,36 @@ bool copyFile(const std::string& sourcePath, const std::string& destPath)
std::string getExecutablePath(bool realPathOnly) std::string getExecutablePath(bool realPathOnly)
{ {
char binRootPath[PATH_MAX];
if (!realPathOnly) { if (!realPathOnly) {
char* cAppImage = ::getenv("APPIMAGE"); char* cAppImage = ::getenv("APPIMAGE");
if (cAppImage) { if (cAppImage) {
char* cArgv0 = ::getenv("ARGV0"); char* cArgv0 = ::getenv("ARGV0");
char* cOwd = ::getenv("OWD"); char* cOwd = ::getenv("OWD");
if (cArgv0 && cOwd) { if (cArgv0 && cOwd) {
return appendToDirectory(cOwd, cArgv0); auto ret = appendToDirectory(cOwd, cArgv0);
return ret;
} }
} }
} }
#ifdef _WIN32 #ifdef _WIN32
GetModuleFileName(NULL, binRootPath, PATH_MAX); std::wstring binRootPath(PATH_MAX, 0);
return std::string(binRootPath); GetModuleFileNameW(NULL, &binRootPath[0], PATH_MAX);
std::string ret = WideToUtf8(binRootPath);
return ret;
#elif __APPLE__ #elif __APPLE__
char binRootPath[PATH_MAX];
uint32_t max = (uint32_t)PATH_MAX; uint32_t max = (uint32_t)PATH_MAX;
_NSGetExecutablePath(binRootPath, &max); _NSGetExecutablePath(binRootPath, &max);
return std::string(binRootPath); return std::string(binRootPath);
#else #else
char binRootPath[PATH_MAX];
ssize_t size = readlink("/proc/self/exe", binRootPath, PATH_MAX); ssize_t size = readlink("/proc/self/exe", binRootPath, PATH_MAX);
if (size != -1) { if (size != -1) {
return std::string(binRootPath, size); return std::string(binRootPath, size);
} }
#endif
return ""; return "";
#endif
} }
bool writeTextFile(const std::string& path, const std::string& content) bool writeTextFile(const std::string& path, const std::string& content)
@@ -322,10 +350,16 @@ bool writeTextFile(const std::string& path, const std::string& content)
std::string getCurrentDirectory() std::string getCurrentDirectory()
{ {
char* a_cwd = getcwd(NULL, 0); #ifdef _WIN32
std::string s_cwd(a_cwd); wchar_t* a_cwd = _wgetcwd(NULL, 0);
std::string ret = WideToUtf8(a_cwd);
free(a_cwd); free(a_cwd);
return s_cwd; #else
char* a_cwd = getcwd(NULL, 0);
std::string ret(a_cwd);
free(a_cwd);
#endif
return ret;
} }
std::string getDataDirectory() std::string getDataDirectory()
@@ -336,8 +370,9 @@ std::string getDataDirectory()
char* cDataDir = ::getenv("KIWIX_DATA_DIR"); char* cDataDir = ::getenv("KIWIX_DATA_DIR");
#endif #endif
std::string dataDir = cDataDir==nullptr ? "" : cDataDir; std::string dataDir = cDataDir==nullptr ? "" : cDataDir;
if (!dataDir.empty()) if (!dataDir.empty()) {
return dataDir; return dataDir;
}
#ifdef _WIN32 #ifdef _WIN32
cDataDir = ::getenv("USERPROFILE"); cDataDir = ::getenv("USERPROFILE");
dataDir = cDataDir==nullptr ? getCurrentDirectory() : cDataDir; dataDir = cDataDir==nullptr ? getCurrentDirectory() : cDataDir;
@@ -351,7 +386,8 @@ std::string getDataDirectory()
dataDir = appendToDirectory(dataDir, "share"); dataDir = appendToDirectory(dataDir, "share");
} }
#endif #endif
return appendToDirectory(dataDir, "kiwix"); auto ret = appendToDirectory(dataDir, "kiwix");
return ret;
} }
static std::map<std::string, std::string> extMimeTypes = { static std::map<std::string, std::string> extMimeTypes = {
+15 -24
View File
@@ -267,37 +267,28 @@ std::string kiwix::urlDecode(const std::string& value, bool component)
/* Split string in a token array */ /* Split string in a token array */
std::vector<std::string> kiwix::split(const std::string& str, std::vector<std::string> kiwix::split(const std::string& str,
const std::string& delims = " *-") const std::string& delims,
bool trimEmpty)
{ {
std::string::size_type lastPos = str.find_first_not_of(delims, 0); std::string::size_type lastPos = 0;
std::string::size_type pos = str.find_first_of(delims, lastPos); std::string::size_type pos = 0;
std::vector<std::string> tokens; std::vector<std::string> tokens;
while( (pos = str.find_first_of(delims, lastPos)) < str.length() )
while (std::string::npos != pos || std::string::npos != lastPos) { {
tokens.push_back(str.substr(lastPos, pos - lastPos)); auto token = str.substr(lastPos, pos - lastPos);
lastPos = str.find_first_not_of(delims, pos); if (!trimEmpty || !token.empty()) {
pos = str.find_first_of(delims, lastPos); tokens.push_back(token);
}
lastPos = pos + 1;
} }
auto token = str.substr(lastPos);
if (!trimEmpty || !token.empty()) {
tokens.push_back(token);
}
return tokens; return tokens;
} }
std::vector<std::string> kiwix::split(const char* lhs, const char* rhs)
{
const std::string m1(lhs), m2(rhs);
return split(m1, m2);
}
std::vector<std::string> kiwix::split(const char* lhs, const std::string& rhs)
{
return split(lhs, rhs.c_str());
}
std::vector<std::string> kiwix::split(const std::string& lhs, const char* rhs)
{
return split(lhs.c_str(), rhs);
}
std::string kiwix::join(const std::vector<std::string>& list, const std::string& sep) std::string kiwix::join(const std::vector<std::string>& list, const std::string& sep)
{ {
std::stringstream ss; std::stringstream ss;
+18
View File
@@ -0,0 +1,18 @@
#include "gtest/gtest.h"
#include "../include/kiwixserve.h"
TEST(KiwixServeTest, PortTest)
{
kiwix::KiwixServe kiwixServe("libraryPath", 8181);
EXPECT_EQ(kiwixServe.getPort(), 8181);
kiwixServe.setPort(8484);
EXPECT_EQ(kiwixServe.getPort(), 8484);
EXPECT_EQ(kiwixServe.setPort(0), -1);
EXPECT_EQ(kiwixServe.setPort(3456789), -1);
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
+26
View File
@@ -180,6 +180,7 @@ const char * sampleOpdsStream = R"(
#include "../include/library.h" #include "../include/library.h"
#include "../include/manager.h" #include "../include/manager.h"
#include "../include/bookmark.h"
namespace namespace
{ {
@@ -191,9 +192,34 @@ class LibraryTest : public ::testing::Test {
manager.readOpds(sampleOpdsStream, "foo.urlHost"); manager.readOpds(sampleOpdsStream, "foo.urlHost");
} }
kiwix::Bookmark createBookmark(const std::string &id) {
kiwix::Bookmark bookmark;
bookmark.setBookId(id);
return bookmark;
};
kiwix::Library lib; kiwix::Library lib;
}; };
TEST_F(LibraryTest, getBookMarksTest)
{
auto bookId1 = lib.getBooksIds()[0];
auto bookId2 = lib.getBooksIds()[1];
lib.addBookmark(createBookmark(bookId1));
lib.addBookmark(createBookmark("invalid-bookmark-id"));
lib.addBookmark(createBookmark(bookId2));
auto onlyValidBookmarks = lib.getBookmarks();
auto allBookmarks = lib.getBookmarks(false);
EXPECT_EQ(onlyValidBookmarks[0].getBookId(), bookId1);
EXPECT_EQ(onlyValidBookmarks[1].getBookId(), bookId2);
EXPECT_EQ(allBookmarks[0].getBookId(), bookId1);
EXPECT_EQ(allBookmarks[1].getBookId(), "invalid-bookmark-id");
EXPECT_EQ(allBookmarks[2].getBookId(), bookId2);
}
TEST_F(LibraryTest, sanityCheck) TEST_F(LibraryTest, sanityCheck)
{ {
EXPECT_EQ(lib.getBookCount(true, true), 10U); EXPECT_EQ(lib.getBookCount(true, true), 10U);
+3 -1
View File
@@ -5,7 +5,9 @@ tests = [
'library', 'library',
'regex', 'regex',
'tagParsing', 'tagParsing',
'stringTools' 'stringTools',
'pathTools',
'kiwixserve'
] ]
+234
View File
@@ -0,0 +1,234 @@
/*
* Copyright (C) 2019 Matthieu Gautier
*
* This program 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 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
* NON-INFRINGEMENT. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "gtest/gtest.h"
#include <string>
#include <vector>
#include "../include/tools/pathTools.h"
#ifdef _WIN32
# define S "\\"
# define AS "c:"
#else
# define S "/"
# define AS ""
#endif
#define P2(a, b) a S b
#define P3(a, b, c) P2(P2(a, b), c)
#define P4(a, b, c, d) P2(P3(a, b, c), d)
#define P5(a, b, c, d, e) P2(P4(a, b, c, d), e)
#define P6(a, b, c, d, e, f) P2(P5(a, b, c ,d, e), f)
#define A1(a) P2(AS,a)
#define A2(a, b) A1(P2(a, b))
#define A3(a, b, c) A1(P3(a, b, c))
#define A4(a, b, c, d) A1(P4(a, b, c, d))
#define A5(a, b, c, d, e) A1(P5(a, b, c, d, e))
std::vector<std::string> normalizeParts(std::vector<std::string> parts, bool absolute);
#ifdef _WIN32
std::wstring Utf8ToWide(const std::string& str);
std::string WideToUtf8(const std::wstring& wstr);
#endif
namespace
{
#define V std::vector<std::string>
TEST(pathTools, normalizePartsAbsolute)
{
#define N(...) normalizeParts(__VA_ARGS__, true)
ASSERT_EQ(N({}), V({}));
#ifdef _WIN32
ASSERT_EQ(N({"c:"}), V({"c:"}));
#else
ASSERT_EQ(N({""}), V({"", ""}));
#endif
ASSERT_EQ(N({AS, "a"}), V({AS, "a"}));
ASSERT_EQ(N({AS, "a", "b"}), V({AS, "a", "b"}));
ASSERT_EQ(N({AS, "a", "b", ".."}), V({AS, "a"}));
#ifdef _WIN32
ASSERT_EQ(N({AS, "a", "b", "..", ".."}), V({AS}));
#else
ASSERT_EQ(N({AS, "a", "b", "..", ".."}), V({AS, ""}));
#endif
ASSERT_EQ(N({AS, "a", "b", "..", "..", "..", "foo"}), V({AS, "foo"}));
ASSERT_EQ(N({AS, "..", "..", "c", "d", ".", "..", "foo"}), V({AS, "c", "foo"}));
ASSERT_EQ(N({AS, "a", "b", ".", "c", "d", "..", "foo"}), V({AS, "a", "b", "c", "foo"}));
#ifdef _WIN32
ASSERT_EQ(N({"c:", "a", "b", ".", "c", "d:", "..", "foo"}), V({"d:", "foo"}));
#endif
#undef N
}
TEST(pathTools, normalizePartsRelative)
{
#define N(...) normalizeParts(__VA_ARGS__, false)
ASSERT_EQ(N({}), V({}));
ASSERT_EQ(N({""}), V({}));
ASSERT_EQ(N({"a"}), V({"a"}));
ASSERT_EQ(N({"a", "b"}), V({"a", "b"}));
ASSERT_EQ(N({"a", "b", ".."}), V({"a"}));
ASSERT_EQ(N({"a", "b", "..", ".."}), V({}));
ASSERT_EQ(N({"a", "b", "..", "..", "..", "foo"}), V({"..", "foo"}));
ASSERT_EQ(N({"..", "..", "c", "d", ".", "..", "foo"}), V({"..", "..", "c", "foo"}));
ASSERT_EQ(N({"a", "b", ".", "c", "d", "..", "foo"}), V({"a", "b", "c", "foo"}));
#undef N
}
TEST(pathTools, isRelativePath)
{
ASSERT_TRUE(isRelativePath("foo"));
ASSERT_TRUE(isRelativePath(P2("foo","bar")));
ASSERT_TRUE(isRelativePath(P3(".","foo","bar")));
ASSERT_TRUE(isRelativePath(P2("..","foo")));
ASSERT_TRUE(isRelativePath(P4("foo","","bar","")));
ASSERT_FALSE(isRelativePath(A1("foo")));
ASSERT_FALSE(isRelativePath(A2("foo", "bar")));
}
TEST(pathTools, computeAbsolutePath)
{
ASSERT_EQ(computeAbsolutePath(A2("a","b"), "foo"),
A3("a","b","foo"));
ASSERT_EQ(computeAbsolutePath(A3("a","b",""), "foo"),
A3("a","b","foo"));
ASSERT_EQ(computeAbsolutePath(A2("a","b"), P2(".","foo")),
A3("a","b","foo"));
ASSERT_EQ(computeAbsolutePath(A2("a","b"), P2("..","foo")),
A2("a","foo"));
ASSERT_EQ(computeAbsolutePath(A3("a","b",""), P2("..","foo")),
A2("a","foo"));
ASSERT_EQ(computeAbsolutePath(A5("a","b","c","d","e"), P2("..","foo")),
A5("a","b","c","d","foo"));
ASSERT_EQ(computeAbsolutePath(A5("a","b","c","d","e"), P5("..","..","..","g","foo")),
A4("a","b","g","foo"));
}
TEST(pathTools, computeRelativePath)
{
ASSERT_EQ(computeRelativePath(A2("a","b"), A3("a","b","foo")),
"foo");
ASSERT_EQ(computeRelativePath(A3("a","b",""), A3("a","b","foo")),
"foo");
ASSERT_EQ(computeRelativePath(A2("a","b"), A2("a","foo")),
P2("..","foo"));
ASSERT_EQ(computeRelativePath(A3("a","b",""), A2("a","foo")),
P2("..","foo"));
ASSERT_EQ(computeRelativePath(A5("a","b","c","d","e"), A5("a","b","c","d","foo")),
P2("..","foo"));
ASSERT_EQ(computeRelativePath(A5("a","b","c","d","e"), A4("a","b","g","foo")),
P5("..","..","..","g","foo"));
}
TEST(pathTools, removeLastPathElement)
{
ASSERT_EQ(removeLastPathElement(P3("a","b","c")),
P2("a","b"));
ASSERT_EQ(removeLastPathElement(A3("a","b","c")),
A2("a","b"));
ASSERT_EQ(removeLastPathElement(P4("a","b","c","")),
P2("a","b"));
ASSERT_EQ(removeLastPathElement(A4("a","b","c","")),
A2("a","b"));
}
TEST(pathTools, appendToDirectory)
{
ASSERT_EQ(appendToDirectory(P3("a","b","c"), "foo.xml"),
P4("a","b","c","foo.xml"));
ASSERT_EQ(appendToDirectory(P4("a","b","c",""), "foo.xml"),
P4("a","b","c","foo.xml"));
ASSERT_EQ(appendToDirectory(P3("a","b","c"), P2("d","foo.xml")),
P5("a","b","c","d","foo.xml"));
ASSERT_EQ(appendToDirectory(P4("a","b","c",""), P2("d","foo.xml")),
P5("a","b","c","d","foo.xml"));
ASSERT_EQ(appendToDirectory(P3("a","b","c"), P2(".","foo.xml")),
P5("a","b","c",".","foo.xml"));
ASSERT_EQ(appendToDirectory(P4("a","b","c",""), P2(".","foo.xml")),
P5("a","b","c",".","foo.xml"));
}
TEST(pathTools, goUp)
{
ASSERT_EQ(computeAbsolutePath(A3("a","b","c"), ".."),
A2("a", "b"));
ASSERT_EQ(computeAbsolutePath(A3("a","b","c"), P2("..","..")),
A1("a"));
#ifdef _WIN32
ASSERT_EQ(computeAbsolutePath(A3("a","b","c"), P3("..","..","..")),
"c:");
ASSERT_EQ(computeAbsolutePath(A3("a","b","c"), P4("..","..","..","..")),
"c:");
#else
ASSERT_EQ(computeAbsolutePath(A3("a","b","c"), P3("..","..","..")),
"/");
ASSERT_EQ(computeAbsolutePath(A3("a","b","c"), P4("..","..","..","..")),
"/");
#endif
ASSERT_EQ(computeAbsolutePath(A3("a","b","c"), P2("..", "foo")),
A3("a", "b","foo"));
ASSERT_EQ(computeAbsolutePath(A3("a","b","c"), P3("..","..","foo")),
A2("a","foo"));
ASSERT_EQ(computeAbsolutePath(A3("a","b","c"), P4("..","..","..","foo")),
A1("foo"));
ASSERT_EQ(computeAbsolutePath(A3("a","b","c"), P5("..","..","..","..","foo")),
A1("foo"));
}
#ifdef _WIN32
TEST(pathTools, dirChange)
{
std::string p1("c:\\a\\b\\c");
std::string p2("d:\\d\\e\\foo.xml");
std::string relative_path = computeRelativePath(p1, p2);
ASSERT_EQ(relative_path, "d:\\d\\e\\foo.xml");
std::string abs_path = computeAbsolutePath(p1, relative_path);
ASSERT_EQ(abs_path, p2);
ASSERT_EQ(computeAbsolutePath(p1, "..\\..\\..\\..\\..\\d:\\d\\e\\foo.xml"), p2);
}
TEST(pathTools, Utf8ToWide)
{
ASSERT_EQ(Utf8ToWide(u8""), L"");
ASSERT_EQ(Utf8ToWide(u8"test"), L"test");
ASSERT_EQ(Utf8ToWide(u8"testé`œà"), L"testé`œà");
}
TEST(pathTools, WideToUtf8)
{
ASSERT_EQ(WideToUtf8(L""), u8"");
ASSERT_EQ(WideToUtf8(L"test"), u8"test");
ASSERT_EQ(WideToUtf8(L"testé`œà"), u8"testé`œà");
}
#endif
};
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
+17
View File
@@ -23,6 +23,7 @@
namespace kiwix { namespace kiwix {
std::string join(const std::vector<std::string>& list, const std::string& sep); std::string join(const std::vector<std::string>& list, const std::string& sep);
std::vector<std::string> split(const std::string& base, const std::string& sep, bool trimEmpty);
}; };
using namespace kiwix; using namespace kiwix;
@@ -36,6 +37,22 @@ TEST(stringTools, join)
ASSERT_EQ(join(list, ";"), "a;b;c"); ASSERT_EQ(join(list, ";"), "a;b;c");
} }
TEST(stringTools, split)
{
std::vector<std::string> list1 = { "a", "b", "c" };
ASSERT_EQ(split("a;b;c", ";", false), list1);
ASSERT_EQ(split("a;b;c", ";", true), list1);
std::vector<std::string> list2 = { "", "a", "b", "c" };
ASSERT_EQ(split(";a;b;c", ";", false), list2);
ASSERT_EQ(split(";a;b;c", ";", true), list1);
std::vector<std::string> list3 = { "", "a", "b", "c", ""};
ASSERT_EQ(split(";a;b;c;", ";", false), list3);
ASSERT_EQ(split(";a;b;c;", ";", true), list1);
std::vector<std::string> list4 = { "", "a", "b", "", "c", ""};
ASSERT_EQ(split(";a;b;;c;", ";", false), list4);
ASSERT_EQ(split(";a;b;;c;", ";", true), list1);
}
}; };
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
+9 -1
View File
@@ -38,6 +38,10 @@ else
export PKG_CONFIG_PATH=${INSTALL_DIR}/lib/x86_64-linux-gnu/pkgconfig export PKG_CONFIG_PATH=${INSTALL_DIR}/lib/x86_64-linux-gnu/pkgconfig
fi fi
export CPPFLAGS="-I${INSTALL_DIR}/include" export CPPFLAGS="-I${INSTALL_DIR}/include"
if [[ "$TEST" == "1" ]]
then
MESON_OPTION="${MESON_OPTION} -Db_coverage=true"
fi
meson . build ${MESON_OPTION} meson . build ${MESON_OPTION}
cd build cd build
ninja ninja
@@ -45,5 +49,9 @@ if [[ "$TEST" == "1" ]]
then then
echo "Running test" echo "Running test"
export LD_LIBRARY_PATH=${INSTALL_DIR}/lib:${INSTALL_DIR}/lib64:${INSTALL_DIR}/lib/x86_64-linux-gnu export LD_LIBRARY_PATH=${INSTALL_DIR}/lib:${INSTALL_DIR}/lib64:${INSTALL_DIR}/lib/x86_64-linux-gnu
ninja test meson test --verbose
ninja coverage
cd ..
echo "*** Publish code coverage"
bash <(curl -s https://codecov.io/bash)
fi fi