Skip to content

Commit

Permalink
lookup tests
Browse files Browse the repository at this point in the history
  • Loading branch information
FreeSlave committed Jun 6, 2016
1 parent c10de63 commit 81b9362
Show file tree
Hide file tree
Showing 16 changed files with 1,031 additions and 16 deletions.
2 changes: 1 addition & 1 deletion dub.json
Expand Up @@ -5,7 +5,7 @@
"copyright": "Copyright © 2015-2016, Roman Chistokhodov",
"authors": ["Roman Chistokhodov"],
"dependencies": {
"inilike": "~>1.0.0-beta",
"inilike": "~>1.0.0-beta2",
"xdgpaths": "~>0.2.1"
},
"targetName" : "icontheme",
Expand Down
5 changes: 4 additions & 1 deletion source/icontheme/cache.d
Expand Up @@ -176,6 +176,9 @@ final class IconThemeCache
});
}

/**
* Path of cache file.
*/
@nogc @safe fileName() const nothrow {
return _fileName;
}
Expand Down Expand Up @@ -401,7 +404,7 @@ private:

unittest
{
string cachePath = "./test/icon-theme.cache";
string cachePath = "./test/Tango/icon-theme.cache";
assert(cachePath.exists);

const(IconThemeCache) cache = new IconThemeCache(cachePath);
Expand Down
6 changes: 3 additions & 3 deletions source/icontheme/file.d
Expand Up @@ -660,7 +660,7 @@ Type=Scalable
[X-NoName]
Key=Value`;

string path = buildPath(".", "test", "index.theme");
string path = buildPath(".", "test", "Tango", "index.theme");

auto iconTheme = new IconThemeFile(iniLikeStringReader(contents), path);
assert(equal(iconTheme.leadingComments(), ["# First comment"]));
Expand All @@ -671,14 +671,14 @@ Key=Value`;
assert(iconTheme.hidden());
assert(equal(iconTheme.directories(), ["16x16/actions", "32x32/animations", "scalable/emblems"]));
assert(equal(iconTheme.inherits(), ["gnome", "hicolor"]));
assert(iconTheme.internalName() == "test");
assert(iconTheme.internalName() == "Tango");
assert(iconTheme.example() == "folder");
assert(iconTheme.group("X-NoName") !is null);

iconTheme.removeGroup("Icon Theme");
assert(iconTheme.group("Icon Theme") !is null);

assert(iconTheme.cachePath() == buildPath(".", "test", "icon-theme.cache"));
assert(iconTheme.cachePath() == buildPath(".", "test", "Tango", "icon-theme.cache"));

assert(equal(iconTheme.bySubdir().map!(subdir => tuple(subdir.name(), subdir.size(), subdir.minSize(), subdir.maxSize(), subdir.context(), subdir.type() )),
[tuple("16x16/actions", 16, 16, 16, "Actions", IconSubDir.Type.Threshold),
Expand Down
155 changes: 144 additions & 11 deletions source/icontheme/lookup.d
Expand Up @@ -25,6 +25,19 @@ package {
import std.typecons;
}

/**
* Default icon extensions. This array include .png and .xpm.
* PNG is recommended format.
* XPM is kept for backward compatibility.
*
* Note: Icon Theme Specificiation also lists .svg as possible format,
* but it's less common to have SVG support for applications,
* hence this format is defined as optional by specificiation.
* If your application has proper support for SVG images,
* array should include it in the first place as the most preferred format.
*/
enum defaultIconExtensions = [".png", ".xpm"];

/**
* Find all icon themes in searchIconDirs.
* Note:
Expand Down Expand Up @@ -54,6 +67,16 @@ if(is(ElementType!Range : string))
}).joiner;
}

///
unittest
{
auto paths = iconThemePaths(["test"]).array;
assert(paths.length == 3);
assert(paths.canFind(buildPath("test", "NewTango", "index.theme")));
assert(paths.canFind(buildPath("test", "Tango", "index.theme")));
assert(paths.canFind(buildPath("test", "hicolor", "index.theme")));
}

/**
* Lookup index.theme files by theme name.
* Params:
Expand Down Expand Up @@ -118,6 +141,20 @@ IconThemeFile openIconTheme(Range)(string themeName,
return path.empty ? null : new IconThemeFile(to!string(path), options);
}

///
unittest
{
auto tango = openIconTheme("Tango", ["test"]);
assert(tango);
assert(tango.displayName() == "Tango");

auto hicolor = openIconTheme("hicolor", ["test"]);
assert(hicolor);
assert(hicolor.displayName() == "Hicolor");

assert(openIconTheme("Nonexistent", ["test"]) is null);
}


private auto withExtensions(Tripplet, Exts, IconTheme)(Exts extensions, string iconName, string subdirPath, IconSubDir subdir, IconTheme iconTheme)
if (isForwardRange!(Exts) && is(ElementType!Exts : string) && is(IconTheme : const(IconThemeFile)))
Expand Down Expand Up @@ -284,6 +321,27 @@ if (is(ElementType!BaseDirs : string) && is (ElementType!Exts : string))
).joiner;
}

/**
* Find fallback icon outside of icon themes. The first found is returned.
* See_Also: lookupFallbackIcon, icontheme.paths.baseIconDirs
*/
string findFallbackIcon(BaseDirs, Exts)(string iconName, BaseDirs searchIconDirs, Exts extensions)
{
auto r = lookupFallbackIcon(iconName, searchIconDirs, extensions);
if (r.empty) {
return null;
} else {
return r.front;
}
}

///
unittest
{
assert(findFallbackIcon("pidgin", ["test"], defaultIconExtensions) == buildPath("test", "pidgin.png"));
assert(findFallbackIcon("nonexistent", ["test"], defaultIconExtensions).empty);
}

/**
* Find icon closest of the size. It uses icon theme cache wherever possible. The first perfect match is used.
* Params:
Expand Down Expand Up @@ -329,6 +387,72 @@ string findClosestIcon(alias subdirFilter = (a => true), IconThemes, BaseDirs, E
}
}

///
unittest
{
auto baseDirs = ["test"];
auto iconThemes = [openIconTheme("Tango", baseDirs), openIconTheme("hicolor", baseDirs)];

string found;

//exact match
found = findClosestIcon("folder", 32, iconThemes, baseDirs);
assert(found == buildPath("test", "Tango", "32x32", "places", "folder.png"));

found = findClosestIcon("folder", 24, iconThemes, baseDirs);
assert(found == buildPath("test", "Tango", "24x24", "devices", "folder.png"));

found = findClosestIcon!(subdir => subdir.context == "Places")("folder", 32, iconThemes, baseDirs);
assert(found == buildPath("test", "Tango", "32x32", "places", "folder.png"));

found = findClosestIcon!(subdir => subdir.context == "Places")("folder", 24, iconThemes, baseDirs);
assert(found == buildPath("test", "Tango", "32x32", "places", "folder.png"));

found = findClosestIcon!(subdir => subdir.context == "MimeTypes")("folder", 32, iconThemes, baseDirs);
assert(found.empty);

//hicolor has exact match, but Tango is more preferred.
found = findClosestIcon("folder", 64, iconThemes, baseDirs);
assert(found == buildPath("test", "Tango", "32x32", "places", "folder.png"));

//find xpm
found = findClosestIcon("folder", 32, iconThemes, baseDirs, [".xpm"]);
assert(found == buildPath("test", "Tango", "32x32", "places", "folder.xpm"));

//find big png, not exact match
found = findClosestIcon("folder", 200, iconThemes, baseDirs);
assert(found == buildPath("test", "Tango", "128x128", "places", "folder.png"));

//svg is closer
found = findClosestIcon("folder", 200, iconThemes, baseDirs, [".png", ".svg"]);
assert(found == buildPath("test", "Tango", "scalable", "places", "folder.svg"));

//lookup with fallback
found = findClosestIcon("pidgin", 96, iconThemes, baseDirs);
assert(found == buildPath("test", "pidgin.png"));

//lookup without fallback
found = findClosestIcon("pidgin", 96, iconThemes, baseDirs, defaultIconExtensions, No.allowFallbackIcon);
assert(found.empty);

found = findClosestIcon("text-plain", 48, iconThemes, baseDirs);
assert(found == buildPath("test", "hicolor", "48x48", "mimetypes", "text-plain.png"));

found = findClosestIcon!(subdir => subdir.context == "MimeTypes")("text-plain", 48, iconThemes, baseDirs);
assert(found == buildPath("test", "hicolor", "48x48", "mimetypes", "text-plain.png"));

found = findClosestIcon!(subdir => subdir.context == "Actions")("text-plain", 48, iconThemes, baseDirs);
assert(found.empty);
}

/**
* ditto, but with predefined extensions and fallback allowed.
* See_Also: defaultIconExtensions
*/
string findClosestIcon(alias subdirFilter = (a => true), IconThemes, BaseDirs)(string iconName, uint size, IconThemes iconThemes, BaseDirs searchIconDirs)
{
return findClosestIcon!subdirFilter(iconName, size, iconThemes, searchIconDirs, defaultIconExtensions);
}

/**
* Find icon of the largest size. It uses icon theme cache wherever possible.
Expand Down Expand Up @@ -370,19 +494,13 @@ string findLargestIcon(alias subdirFilter = (a => true), IconThemes, BaseDirs, E
}
}


/**
* Find fallback icon outside of icon themes. The first found is returned.
* See_Also: lookupFallbackIcon, icontheme.paths.baseIconDirs
/**
* ditto, but with predefined extensions and fallback allowed.
* See_Also: defaultIconExtensions
*/
string findFallbackIcon(BaseDirs, Exts)(string iconName, BaseDirs searchIconDirs, Exts extensions)
string findLargestIcon(alias subdirFilter = (a => true), IconThemes, BaseDirs, Exts)(string iconName, IconThemes iconThemes, BaseDirs searchIconDirs)
{
auto r = lookupFallbackIcon(iconName, searchIconDirs, extensions);
if (r.empty) {
return null;
} else {
return r.front;
}
return findLargestIcon!subdirFilter(iconName, iconThemes, searchIconDirs, defaultIconExtensions);
}

/**
Expand Down Expand Up @@ -572,3 +690,18 @@ if(isForwardRange!Range && is(ElementType!Range : string))

return themes;
}

///
unittest
{
auto tango = openIconTheme("NewTango", ["test"]);
auto baseThemes = openBaseThemes(tango, ["test"]);

assert(baseThemes.length == 2);
assert(baseThemes[0].internalName() == "Tango");
assert(baseThemes[1].internalName() == "hicolor");

baseThemes = openBaseThemes(tango, ["test"], null);
assert(baseThemes.length == 1);
assert(baseThemes[0].internalName() == "Tango");
}
4 changes: 4 additions & 0 deletions test/NewTango/index.theme
@@ -0,0 +1,4 @@
[Icon Theme]
Name=NewTango
Comment=New Tango Icon Theme
Inherits=Tango
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
File renamed without changes.

0 comments on commit 81b9362

Please sign in to comment.