tagdb: Remove tagdb
This shifts the taglib code into library.cpp. I also remove the tagdb section of the DESIGN document. Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
parent
c7fe5b18d5
commit
e7e36caa3a
56
DESIGN
56
DESIGN
|
@ -33,7 +33,7 @@ Core Layers:
|
|||
* Library (include/core/library.h)
|
||||
* Queue (include/core/queue.h)
|
||||
* RNG (include/core/random.h)
|
||||
* Tag database (include/core/tags.h)
|
||||
* Tags (include/core/tags/*.h)
|
||||
* Idle queue (include/core/idle.h)
|
||||
* Filter (include/core/filter.h)
|
||||
* Index (include/core/index.h)
|
||||
|
@ -66,60 +66,6 @@ Callbacks:
|
|||
|
||||
|
||||
|
||||
Tag Database:
|
||||
The tag database is actually several databases that describe every
|
||||
track added by the user. I do not expect the artist_db, album_db,
|
||||
genre_db and library_db to change often, so they can be created as
|
||||
autosaving databases that will write to disk whenever they are changed.
|
||||
The track_db can have several additions and removals in a row, so the
|
||||
commit() function is used to control when this db is written to disk,
|
||||
avoiding the huge performance hit that would come with saving on EVERY
|
||||
change.
|
||||
|
||||
Tags are defined in the sections below.
|
||||
|
||||
- Databases:
|
||||
Database<Artist> artist_db;
|
||||
Database<Album> album_db;
|
||||
Database<Genre> genre_db;
|
||||
Database<Library> library_db;
|
||||
Database<Track> track_db;
|
||||
|
||||
- API:
|
||||
void tagdb :: init();
|
||||
Load all databases from disk.
|
||||
|
||||
void tagdb :: commit();
|
||||
Write track_db to disk.
|
||||
|
||||
Track *tagdb :: add_track(const std::string &filepath, Library *library);
|
||||
Add a new track to the track_db and return a pointer to it.
|
||||
Return NULL if this track is already in the database or if
|
||||
there is an error when tagging.
|
||||
|
||||
Library *tagdb :: add_library(const std::string &filepath);
|
||||
Add a new path to library_db. Return a pointer to the new path
|
||||
or return NULL if the path is already in the database.
|
||||
|
||||
void tagdb :: remove_track(unsigned int track_id);
|
||||
Remove the track with id equal to track_id from the track_db.
|
||||
|
||||
void tagdb :: remove_library(unsigned int library_id);
|
||||
Remove all tracks associated with this library from the
|
||||
track_db, then remove this library from the library_db.
|
||||
|
||||
Track *tagdb :: lookup(unsigned int track_id);
|
||||
Look up the track_id in the track database. Return NULL if
|
||||
there is no matching track.
|
||||
|
||||
Database<Track> &tagdb :: get_track_db();
|
||||
Return a reference to the track_db.
|
||||
|
||||
Database<Library> &tagdb :: get_library_db();
|
||||
Return a reference to the library_db.
|
||||
|
||||
|
||||
|
||||
Track Tag:
|
||||
The track tag is used to store information about a single track in the
|
||||
user's music collection.
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
*/
|
||||
#include <core/idle.h>
|
||||
#include <core/library.h>
|
||||
#include <core/print.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <taglib/tag.h>
|
||||
#include <taglib/fileref.h>
|
||||
|
||||
|
||||
class LibraryQueue : public Queue {
|
||||
|
@ -76,6 +79,33 @@ static void scan_path(struct scan_info &);
|
|||
/*
|
||||
* Scanning functions are here
|
||||
*/
|
||||
static void tag_track(Library *library, const std::string &filepath)
|
||||
{
|
||||
Track *track;
|
||||
TagLib :: Tag *tag;
|
||||
TagLib :: AudioProperties *audio;
|
||||
TagLib :: FileRef ref(filepath.c_str(), true, TagLib::AudioProperties::Fast);
|
||||
|
||||
if (ref.isNull()) {
|
||||
print("WARNING: Could not read tags for file %s\n", filepath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
tag = ref.tag();
|
||||
audio = ref.audioProperties();
|
||||
|
||||
track = tags :: add_track(
|
||||
tags :: get_album(tag->album().stripWhiteSpace().to8Bit(true), tag->year()),
|
||||
tags :: get_artist(tag->artist().stripWhiteSpace().to8Bit(true)),
|
||||
tags :: get_genre(tag->genre().stripWhiteSpace().to8Bit(true)),
|
||||
library, filepath,
|
||||
tag->title().stripWhiteSpace().to8Bit(true),
|
||||
audio->length(), tag->track()
|
||||
);
|
||||
|
||||
if (track)
|
||||
library_q.add(track);
|
||||
}
|
||||
|
||||
static void process_path(Library *library, const std :: string &dir,
|
||||
const std :: string &name)
|
||||
|
@ -87,11 +117,8 @@ static void process_path(Library *library, const std :: string &dir,
|
|||
|
||||
if (g_file_test(scan.path.c_str(), G_FILE_TEST_IS_DIR) == true)
|
||||
idle :: schedule (scan_path, scan);
|
||||
else {
|
||||
Track *track = tagdb :: add_track(scan.path, library);
|
||||
if (track)
|
||||
library_q.add(track);
|
||||
}
|
||||
else
|
||||
tag_track(library, scan.path);
|
||||
}
|
||||
|
||||
static void scan_path(struct scan_info &scan)
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* Copyright 2014 (c) Anna Schumaker.
|
||||
*/
|
||||
|
||||
#include <core/tags.h>
|
||||
#include <core/print.h>
|
||||
|
||||
#include <taglib/tag.h>
|
||||
#include <taglib/fileref.h>
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Tagdb functions
|
||||
*
|
||||
*/
|
||||
|
||||
Track *tagdb :: add_track(const std::string &filepath, Library *library)
|
||||
{
|
||||
Track *track;
|
||||
TagLib :: Tag *tag;
|
||||
TagLib :: AudioProperties *audio;
|
||||
TagLib :: FileRef ref(filepath.c_str(), true, TagLib::AudioProperties::Fast);
|
||||
|
||||
if (ref.isNull()) {
|
||||
print("WARNING: Could not read tags for file %s\n", filepath.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tag = ref.tag();
|
||||
audio = ref.audioProperties();
|
||||
|
||||
track = tags :: add_track(
|
||||
tags :: get_album(tag->album().stripWhiteSpace().to8Bit(true), tag->year()),
|
||||
tags :: get_artist(tag->artist().stripWhiteSpace().to8Bit(true)),
|
||||
tags :: get_genre(tag->genre().stripWhiteSpace().to8Bit(true)),
|
||||
library, filepath,
|
||||
tag->title().stripWhiteSpace().to8Bit(true),
|
||||
audio->length(), tag->track()
|
||||
);
|
||||
|
||||
return track;
|
||||
}
|
|
@ -6,7 +6,6 @@
|
|||
#define OCARINA_CORE_LIBRARY_H
|
||||
|
||||
#include <core/queue.h>
|
||||
#include <core/tags.h>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#define OCARINA_CORE_QUEUE_H
|
||||
|
||||
#include <core/file.h>
|
||||
#include <core/tags.h>
|
||||
#include <core/tags/track.h>
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* Copyright 2014 (c) Anna Schumaker.
|
||||
*/
|
||||
#ifndef OCARINA_CORE_TAGS_H
|
||||
#define OCARINA_CORE_TAGS_H
|
||||
|
||||
#include <core/tags/library.h>
|
||||
#include <core/tags/track.h>
|
||||
|
||||
|
||||
/** Functions for accessing the tag database */
|
||||
namespace tagdb
|
||||
{
|
||||
|
||||
/**
|
||||
* Add a track to the database
|
||||
* @param filepath Filepath to be added
|
||||
* @param library Library containing the new track
|
||||
* @return A pointer to the newly created track
|
||||
*/
|
||||
Track *add_track(const std::string &, Library *);
|
||||
|
||||
}
|
||||
|
||||
#endif /* OCARINA_CORE_TAGS_H */
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
#include <core/library.h>
|
||||
#include <core/playlist.h>
|
||||
#include <core/tags.h>
|
||||
#include <core/tags/track.h>
|
||||
#include <lib/colmgr.h>
|
||||
#include <lib/lib.h>
|
||||
#include <gtkmm.h>
|
||||
|
|
|
@ -19,17 +19,14 @@ test( "tags/artist" )
|
|||
test( "tags/album" )
|
||||
test( "tags/genre" )
|
||||
test( "tags/library" )
|
||||
|
||||
test_env.UsePackage("taglib")
|
||||
objs += [ get_test_obj("tags", "core") ]
|
||||
objs += [ get_test_obj("tags/tags", "core") ]
|
||||
test( "tags/track" )
|
||||
|
||||
#test( "tags" )
|
||||
test( "random" )
|
||||
|
||||
objs += [ get_test_obj("callback", "core") ]
|
||||
objs += [ get_test_obj("tags/tags", "core") ]
|
||||
test( "queue" )
|
||||
test_env.UsePackage("taglib")
|
||||
test( "library" )
|
||||
test( "playlist" )
|
||||
test( "deck" )
|
||||
|
|
|
@ -1,321 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 (c) Anna Schumaker.
|
||||
* Test a DatabaseEntry
|
||||
*/
|
||||
|
||||
#include <core/tags.h>
|
||||
#include <tests/test.h>
|
||||
|
||||
static Library *LIB_NULL = NULL;
|
||||
static Track *TRACK_NULL = NULL;
|
||||
|
||||
struct TagArgs {
|
||||
struct Library *library;
|
||||
std::string full_path;
|
||||
|
||||
std::string artist;
|
||||
std::string artist_lower;
|
||||
|
||||
std::string album;
|
||||
std::string album_lower;
|
||||
unsigned int year;
|
||||
|
||||
std::string genre;
|
||||
std::string genre_lower;
|
||||
|
||||
unsigned int track;
|
||||
unsigned int length;
|
||||
unsigned int play_count;
|
||||
unsigned int last_year;
|
||||
unsigned int last_month;
|
||||
unsigned int last_day;
|
||||
std::string title;
|
||||
std::string title_lower;
|
||||
std::string filepath;
|
||||
std::string length_str;
|
||||
};
|
||||
|
||||
static void test_library()
|
||||
{
|
||||
Library *lib = tagdb :: add_library("tests/Music/");
|
||||
|
||||
test_not_equal(lib, LIB_NULL);
|
||||
test_equal(lib->root_path, (std::string)"tests/Music/");
|
||||
test_equal(lib->count, (unsigned)0);
|
||||
test_equal(lib->enabled, true);
|
||||
|
||||
test_equal(tagdb :: add_library("tests/Music/"), LIB_NULL);
|
||||
test_equal(lib, tagdb :: lookup_library(0));
|
||||
|
||||
tagdb :: remove_library(0);
|
||||
test_equal(tagdb :: get_library_db().size(), (unsigned)0);
|
||||
}
|
||||
|
||||
static void test_track(struct TagArgs *args)
|
||||
{
|
||||
Track *track = tagdb :: add_track(args->full_path, args->library);
|
||||
|
||||
test_not_equal(track, TRACK_NULL);
|
||||
test_equal(track->path(), args->full_path);
|
||||
|
||||
/*
|
||||
* Check tags
|
||||
*/
|
||||
test_equal(track->artist->name, args->artist);
|
||||
test_equal(track->artist->lower, args->artist_lower);
|
||||
test_equal(track->album->name, args->album);
|
||||
test_equal(track->album->lower, args->album_lower);
|
||||
test_equal(track->album->year, args->year);
|
||||
test_equal(track->genre->name, args->genre);
|
||||
test_equal(track->genre->lower, args->genre_lower);
|
||||
test_equal(track->track, args->track);
|
||||
test_equal(track->length, args->length);
|
||||
test_equal(track->play_count, args->play_count);
|
||||
test_equal(track->last_year, args->last_year);
|
||||
test_equal(track->last_month, args->last_month);
|
||||
test_equal(track->last_day, args->last_day);
|
||||
test_equal(track->title, args->title);
|
||||
test_equal(track->title_lower, args->title_lower);
|
||||
test_equal(track->filepath, args->filepath);
|
||||
test_equal(track->length_str, args->length_str);
|
||||
|
||||
test_equal(tagdb :: lookup(args->track - 1), track);
|
||||
test_equal(args->library->count, (unsigned)1);
|
||||
tagdb :: remove_track(args->track - 1);
|
||||
test_equal(tagdb :: lookup(args->track - 1), TRACK_NULL);
|
||||
test_equal(tagdb :: get_track_db().size(), (unsigned)0);
|
||||
test_equal(args->library->count, (unsigned)0);
|
||||
|
||||
/*
|
||||
* Mark track played, double check new values
|
||||
*/
|
||||
track->played();
|
||||
test_equal(track->play_count, args->play_count + 1);
|
||||
test_not_equal(track->last_year, args->last_year);
|
||||
test_not_equal(track->last_month, args->last_month);
|
||||
test_not_equal(track->last_day, args->last_day);
|
||||
}
|
||||
|
||||
static void test_invalid_track(Library *lib)
|
||||
{
|
||||
unsigned int library_size = lib->count;
|
||||
Track *track = tagdb :: add_track("tests/Music/invalid_track", lib);
|
||||
test_equal(track, TRACK_NULL);
|
||||
test_equal(lib->count, library_size);
|
||||
}
|
||||
|
||||
static void test_all_tracks()
|
||||
{
|
||||
struct TagArgs expected;
|
||||
Library *library = tagdb :: add_library("tests/Music");
|
||||
|
||||
expected.library = library;
|
||||
expected.full_path = "tests/Music/1.ogg";
|
||||
expected.artist = "Artist";
|
||||
expected.artist_lower = "artist";
|
||||
expected.album = "Album";
|
||||
expected.album_lower = "album";
|
||||
expected.year = 2014;
|
||||
expected.genre = "Silence";
|
||||
expected.genre_lower = "silence";
|
||||
expected.track = 1;
|
||||
expected.length = 1;
|
||||
expected.play_count = 0;
|
||||
expected.last_year = 0;
|
||||
expected.last_month = 0;
|
||||
expected.last_day = 0;
|
||||
expected.title = "One";
|
||||
expected.title_lower = "one";
|
||||
expected.filepath = "1.ogg";
|
||||
expected.length_str = "0:01";
|
||||
run_test("Tags Track Test (1.ogg)", test_track, &expected);
|
||||
|
||||
expected.full_path = "tests/Music/10.ogg";
|
||||
expected.track = 2;
|
||||
expected.length = 10;
|
||||
expected.title = "Ten";
|
||||
expected.title_lower = "ten";
|
||||
expected.filepath = "10.ogg";
|
||||
expected.length_str = "0:10";
|
||||
run_test("Tags Track Test (10.ogg)", test_track, &expected);
|
||||
|
||||
expected.full_path = "tests/Music/15.ogg";
|
||||
expected.track = 3;
|
||||
expected.length = 15;
|
||||
expected.title = "Fifteen";
|
||||
expected.title_lower = "fifteen";
|
||||
expected.filepath = "15.ogg";
|
||||
expected.length_str = "0:15";
|
||||
run_test("Tags Track Test (15.ogg)", test_track, &expected);
|
||||
|
||||
expected.full_path = "tests/Music/60.ogg";
|
||||
expected.track = 4;
|
||||
expected.length = 60;
|
||||
expected.title = "Sixty";
|
||||
expected.title_lower = "sixty";
|
||||
expected.filepath = "60.ogg";
|
||||
expected.length_str = "1:00";
|
||||
run_test("Tags Track Test (60.ogg)", test_track, &expected);
|
||||
|
||||
expected.full_path = "tests/Music/90.ogg";
|
||||
expected.album = "Album Two";
|
||||
expected.album_lower = "album two";
|
||||
expected.track = 5;
|
||||
expected.length = 90;
|
||||
expected.title = "Ninety";
|
||||
expected.title_lower = "ninety";
|
||||
expected.filepath = "90.ogg";
|
||||
expected.length_str = "1:30";
|
||||
run_test("Tags Track Test (90.ogg)", test_track, &expected);
|
||||
|
||||
expected.full_path = "tests/Music/600.ogg";
|
||||
expected.track = 6;
|
||||
expected.length = 600;
|
||||
expected.title = "Six Hundred";
|
||||
expected.title_lower = "six hundred";
|
||||
expected.filepath = "600.ogg";
|
||||
expected.length_str = "10:00";
|
||||
run_test("Tags Track Test (600.ogg)", test_track, &expected);
|
||||
|
||||
expected.full_path = "tests/Music/666.ogg";
|
||||
expected.track = 7;
|
||||
expected.length = 666;
|
||||
expected.title = "Six-Six-Six";
|
||||
expected.title_lower = "six six six";
|
||||
expected.filepath = "666.ogg";
|
||||
expected.length_str = "11:06";
|
||||
run_test("Tags Track Test (666.ogg)", test_track, &expected);
|
||||
|
||||
run_test("Tags Track Test (Invalid)", test_invalid_track, library);
|
||||
}
|
||||
|
||||
static void test_comparison()
|
||||
{
|
||||
Library *lib = tagdb :: lookup_library(1);
|
||||
Track *track1 = tagdb :: add_track("tests/Music/1.ogg", lib);
|
||||
Track *track10 = tagdb :: add_track("tests/Music/10.ogg", lib);
|
||||
Track *track15 = tagdb :: add_track("tests/Music/15.ogg", lib);
|
||||
Track *track60 = tagdb :: add_track("tests/Music/60.ogg", lib);
|
||||
Track *track90 = tagdb :: add_track("tests/Music/90.ogg", lib);
|
||||
Track *track600 = tagdb :: add_track("tests/Music/600.ogg", lib);
|
||||
Track *track666 = tagdb :: add_track("tests/Music/666.ogg", lib);
|
||||
|
||||
Artist art2("");
|
||||
track10->artist = &art2;
|
||||
test_equal(track1->less_than(track10, SORT_ARTIST), -1);
|
||||
test_equal(track10->less_than(track1, SORT_ARTIST), 1);
|
||||
|
||||
Artist art3("Artist Three");
|
||||
track10->artist = &art3;
|
||||
test_equal(track1->less_than(track1, SORT_ARTIST), 0);
|
||||
test_equal(track1->less_than(track10, SORT_ARTIST) < 0, true);
|
||||
test_equal(track10->less_than(track1, SORT_ARTIST) > 0, true);
|
||||
|
||||
test_equal(track1->less_than(track1, SORT_ALBUM), 0);
|
||||
test_equal(track1->less_than(track90, SORT_ALBUM) < 0, true);
|
||||
test_equal(track90->less_than(track1, SORT_ALBUM) > 0, true);
|
||||
|
||||
track15->play_count++;
|
||||
test_equal(track1->less_than(track1, SORT_COUNT), 0);
|
||||
test_equal(track1->less_than(track15, SORT_COUNT) < 0, true);
|
||||
test_equal(track15->less_than(track1, SORT_COUNT) > 0, true);
|
||||
|
||||
Genre gen2("X-Treme Silence!!!");
|
||||
track60->genre = &gen2;
|
||||
test_equal(track1->less_than(track1, SORT_GENRE), 0);
|
||||
test_equal(track1->less_than(track60, SORT_GENRE) < 0, true);
|
||||
test_equal(track60->less_than(track1, SORT_GENRE) > 0, true);
|
||||
|
||||
test_equal(track1->less_than(track1, SORT_LENGTH), 0);
|
||||
test_equal(track1->less_than(track600, SORT_LENGTH) < 0, true);
|
||||
test_equal(track600->less_than(track1, SORT_LENGTH) > 0, true);
|
||||
|
||||
track15->last_year = 2014;
|
||||
test_equal(track1->less_than(track1, SORT_PLAYED), 0);
|
||||
test_equal(track1->less_than(track15, SORT_PLAYED) < 0, true);
|
||||
test_equal(track15->less_than(track1, SORT_PLAYED) > 0, true);
|
||||
|
||||
track1->last_year = 2014;
|
||||
track15->last_month = 5;
|
||||
test_equal(track1->less_than(track15, SORT_PLAYED) < 0, true);
|
||||
test_equal(track15->less_than(track1, SORT_PLAYED) > 0, true);
|
||||
|
||||
track1->last_month = 5;
|
||||
track15->last_day = 6;
|
||||
test_equal(track1->less_than(track15, SORT_PLAYED) < 0, true);
|
||||
test_equal(track15->less_than(track1, SORT_PLAYED) > 0, true);
|
||||
|
||||
test_equal(track1->less_than(track1, SORT_TITLE), 0);
|
||||
test_equal(track1->less_than(track666, SORT_TITLE) < 0, true);
|
||||
test_equal(track666->less_than(track1, SORT_TITLE) > 0, true);
|
||||
|
||||
test_equal(track1->less_than(track1, SORT_TRACK), 0);
|
||||
test_equal(track1->less_than(track60, SORT_TRACK) < 0, true);
|
||||
test_equal(track60->less_than(track1, SORT_TRACK) > 0, true);
|
||||
|
||||
track666->album->year = 2048;
|
||||
test_equal(track1->less_than(track1, SORT_YEAR), 0);
|
||||
test_equal(track1->less_than(track666, SORT_YEAR) < 0, true);
|
||||
test_equal(track666->less_than(track1, SORT_YEAR) > 0, true);
|
||||
}
|
||||
|
||||
static void test_lib_removal()
|
||||
{
|
||||
test_equal(tagdb :: get_track_db().size(), (unsigned)7);
|
||||
test_equal(tagdb :: lookup_library(1)->count, (unsigned)7);
|
||||
tagdb :: remove_library(1);
|
||||
test_equal(tagdb :: get_track_db().size(), (unsigned)0);
|
||||
}
|
||||
|
||||
static void test_save_load()
|
||||
{
|
||||
Database<Artist> artist("artist.db", false);
|
||||
Database<Album> album("album.db", false);
|
||||
Database<Genre> genre("genre.db", false);
|
||||
|
||||
artist.load();
|
||||
album.load();
|
||||
genre.load();
|
||||
|
||||
test_equal(artist.size(), (unsigned)1);
|
||||
test_equal(album.size(), (unsigned)2);
|
||||
test_equal(genre.size(), (unsigned)1);
|
||||
|
||||
|
||||
Database<Library> library("library.db", false);
|
||||
library.load();
|
||||
test_equal(library.size(), (unsigned)0);
|
||||
|
||||
Library *lib = tagdb :: add_library("tests/Music");
|
||||
library.load();
|
||||
test_equal(library.size(), (unsigned)1);
|
||||
|
||||
Database<Library> library2("library.db", false);
|
||||
lib->enabled = false;
|
||||
tagdb :: commit_library();
|
||||
library2.load();
|
||||
test_equal(library2.at(2)->enabled, false);
|
||||
|
||||
|
||||
tagdb :: add_track("tests/Music/1.ogg", lib);
|
||||
tagdb :: add_track("tests/Music/15.ogg", lib);
|
||||
tagdb :: add_track("tests/Music/60.ogg", lib);
|
||||
|
||||
Database<Track> track("track.db", false);
|
||||
track.load();
|
||||
test_equal(track.size(), (unsigned)0);
|
||||
|
||||
tagdb :: commit();
|
||||
track.load();
|
||||
test_equal(track.size(), (unsigned)3);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
run_test("Tags Library Test", test_library);
|
||||
test_all_tracks();
|
||||
run_test("Tags Comparison Test", test_comparison);
|
||||
run_test("Tags Library Removal Test", test_lib_removal);
|
||||
run_test("Tags Save and Load Test", test_save_load);
|
||||
return 0;
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
*/
|
||||
#include <core/idle.h>
|
||||
#include <core/library.h>
|
||||
#include <core/tags.h>
|
||||
#include <lib/colmgr.h>
|
||||
#include <lib/lib.h>
|
||||
#include <tests/test.h>
|
||||
|
|
Loading…
Reference in New Issue