mirror of
https://github.com/weiju/amiga-stuff
synced 2025-11-19 16:01:31 +00:00
added sorting for the file list
added chibi test framework in requesters for unit testing the more complicated sorting functionality, added sorting for file lists
This commit is contained in:
@ -7,5 +7,12 @@ all: main
|
||||
clean:
|
||||
rm -f *.o main
|
||||
|
||||
main: main.o filereq.o dos13.o
|
||||
main: main.o filereq.o dos13.o file_list.o
|
||||
$(CC) $(CFLAGS) $^ -lamiga -lauto -o $@
|
||||
|
||||
|
||||
check: file_list_test
|
||||
|
||||
file_list_test: file_list.c file_list_test.c chibi.c
|
||||
gcc $^ -o $@
|
||||
./file_list_test
|
||||
|
||||
336
requesters/chibi.c
Normal file
336
requesters/chibi.c
Normal file
@ -0,0 +1,336 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "chibi.h"
|
||||
|
||||
#define MAX_DIGITS_INT 10
|
||||
|
||||
chibi_suite *chibi_suite_new_fixture(chibi_fixfunc setup,
|
||||
chibi_fixfunc teardown,
|
||||
void *userdata)
|
||||
{
|
||||
chibi_suite *result = calloc(1, sizeof(chibi_suite));
|
||||
result->head = NULL;
|
||||
result->setup = setup;
|
||||
result->teardown = teardown;
|
||||
result->userdata = userdata;
|
||||
result->first_child = NULL;
|
||||
result->next = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
chibi_suite *chibi_suite_new()
|
||||
{
|
||||
return chibi_suite_new_fixture(NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void chibi_suite_delete(chibi_suite *suite)
|
||||
{
|
||||
if (suite) {
|
||||
struct _chibi_testcase *tc = suite->head, *tmp;
|
||||
while (tc) {
|
||||
tmp = tc->next;
|
||||
if (tc->error_msg) free(tc->error_msg);
|
||||
free(tc);
|
||||
tc = tmp;
|
||||
}
|
||||
/* recursively free the children and siblings */
|
||||
if (suite->first_child) chibi_suite_delete(suite->first_child);
|
||||
if (suite->next) chibi_suite_delete(suite->next);
|
||||
free(suite);
|
||||
}
|
||||
}
|
||||
|
||||
void chibi_suite_add_suite(chibi_suite *suite, chibi_suite *toadd)
|
||||
{
|
||||
if (!suite->first_child) suite->first_child = toadd;
|
||||
else {
|
||||
chibi_suite *cur = suite->first_child;
|
||||
while (cur->next) cur = cur->next;
|
||||
cur->next = toadd;
|
||||
}
|
||||
}
|
||||
|
||||
void _chibi_suite_add_test(chibi_suite *suite, chibi_testfunc fun, const char *fname)
|
||||
{
|
||||
struct _chibi_testcase *tc, *newtc;
|
||||
newtc = calloc(1, sizeof(struct _chibi_testcase));
|
||||
newtc->fun = fun;
|
||||
newtc->fname = fname;
|
||||
newtc->next = NULL;
|
||||
newtc->success = 1;
|
||||
newtc->error_msg = NULL;
|
||||
newtc->userdata = suite->userdata;
|
||||
|
||||
if (!suite->head) suite->head = newtc;
|
||||
else {
|
||||
tc = suite->head;
|
||||
while (tc->next) tc = tc->next;
|
||||
tc->next = newtc;
|
||||
}
|
||||
}
|
||||
|
||||
static void _chibi_suite_summary_data(chibi_suite *suite, chibi_summary_data *summary, int level)
|
||||
{
|
||||
if (suite && summary) {
|
||||
chibi_testcase *tc = suite->head;
|
||||
if (!level) {
|
||||
summary->num_runs = 0;
|
||||
summary->num_failures = 0;
|
||||
summary->num_pass = 0;
|
||||
}
|
||||
|
||||
while (tc) {
|
||||
summary->num_runs++;
|
||||
if (!tc->success) {
|
||||
summary->num_failures++;
|
||||
}
|
||||
tc = tc->next;
|
||||
}
|
||||
if (suite->first_child) _chibi_suite_summary_data(suite->first_child, summary, level + 1);
|
||||
if (suite->next) _chibi_suite_summary_data(suite->next, summary, level + 1);
|
||||
|
||||
if (!level) summary->num_pass = summary->num_runs - summary->num_failures;
|
||||
}
|
||||
}
|
||||
|
||||
static int _print_messages(chibi_suite *suite, int testnum)
|
||||
{
|
||||
chibi_testcase *tc = suite->head;
|
||||
while (tc) {
|
||||
if (!tc->success) {
|
||||
fprintf(stderr, "%d. %s\n", testnum, tc->error_msg);
|
||||
testnum++;
|
||||
}
|
||||
tc = tc->next;
|
||||
}
|
||||
if (suite->first_child) testnum = _print_messages(suite->first_child, testnum);
|
||||
if (suite->next) testnum = _print_messages(suite->next, testnum);
|
||||
|
||||
return testnum;
|
||||
}
|
||||
|
||||
static void chibi_suite_print_summary(chibi_suite *suite)
|
||||
{
|
||||
chibi_summary_data summary;
|
||||
_chibi_suite_summary_data(suite, &summary, 0);
|
||||
|
||||
fprintf(stderr, "\n\nSummary (chibitest %s)\n\n", CHIBI_TEST_GIT_SHA);
|
||||
if (summary.num_failures > 0) {
|
||||
fprintf(stderr, "# of failures: %d\n\n", summary.num_failures);
|
||||
_print_messages(suite, 0);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
fprintf(stderr, "Runs: %d Pass: %d Fail: %d\n\n", summary.num_runs,
|
||||
summary.num_runs - summary.num_failures, summary.num_failures);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reused by assertions to generate a standard format error message.
|
||||
*/
|
||||
static char *assemble_message(const char *msg, const char *srcfile,
|
||||
const char *funname, int line)
|
||||
{
|
||||
char *msgbuffer = calloc(strlen(msg) + strlen(srcfile) + strlen(funname) + MAX_DIGITS_INT + 8,
|
||||
sizeof(char));
|
||||
sprintf(msgbuffer, "%s:%d - %s() - %s", srcfile, line, funname, msg);
|
||||
return msgbuffer;
|
||||
}
|
||||
|
||||
static char *assemble_message2(const char *msg1, const char *msg2,
|
||||
const char *srcfile, const char *funname,
|
||||
int line)
|
||||
{
|
||||
char *msgbuffer = calloc(strlen(msg1) + strlen(msg2) + strlen(srcfile) + strlen(funname)
|
||||
+ MAX_DIGITS_INT + 10, sizeof(char));
|
||||
sprintf(msgbuffer, "%s:%d - %s() - %s %s", srcfile, line, funname, msg1, msg2);
|
||||
return msgbuffer;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* ASSERTIONS
|
||||
*
|
||||
* TODO: test exit after first fail: make a test case with 2 assertions and ensure
|
||||
* that the second is not executed when the first fails
|
||||
* Note: setjmp()/longjmp() seem to be broken on Amiga/VBCC
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
void _exit_on_fail(chibi_testcase *tc)
|
||||
{
|
||||
#ifndef AMIGA
|
||||
longjmp(tc->env, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void _chibi_assert_not_null(chibi_testcase *tc, void *ptr, const char *msg, const char *srcfile,
|
||||
int line)
|
||||
{
|
||||
if (ptr == NULL) {
|
||||
tc->error_msg = assemble_message(msg, srcfile, tc->fname, line);
|
||||
tc->success = 0;
|
||||
_exit_on_fail(tc);
|
||||
}
|
||||
}
|
||||
|
||||
void _chibi_fail(chibi_testcase *tc, const char *msg, const char *srcfile, int line)
|
||||
{
|
||||
tc->error_msg = assemble_message(msg, srcfile, tc->fname, line);
|
||||
tc->success = 0;
|
||||
_exit_on_fail(tc);
|
||||
}
|
||||
|
||||
void _chibi_assert(chibi_testcase *tc, int cond, const char *cond_str, const char *msg,
|
||||
const char *srcfile, int line)
|
||||
{
|
||||
if (!cond) {
|
||||
tc->error_msg = assemble_message2(msg, cond_str, srcfile, tc->fname, line);
|
||||
tc->success = 0;
|
||||
_exit_on_fail(tc);
|
||||
}
|
||||
}
|
||||
|
||||
void _chibi_assert_eq_int(chibi_testcase *tc, int expected, int value,
|
||||
const char *srcfile, int line)
|
||||
{
|
||||
if (value != expected) {
|
||||
char *fmt = "%s:%d - %s() - expected:<%d> but was:<%d>";
|
||||
char *msgbuffer = calloc(strlen(fmt) + strlen(srcfile) + strlen(tc->fname)
|
||||
+ MAX_DIGITS_INT * 3 + 10, sizeof(char));
|
||||
sprintf(msgbuffer, fmt, srcfile, line, tc->fname, expected, value);
|
||||
tc->error_msg = msgbuffer;
|
||||
tc->success = 0;
|
||||
_exit_on_fail(tc);
|
||||
}
|
||||
}
|
||||
|
||||
void _chibi_assert_eq_cstr(chibi_testcase *tc, const char *expected, const char *value,
|
||||
const char *srcfile, int line)
|
||||
{
|
||||
if (value == expected) return;
|
||||
if (!value || !expected || strcmp(value, expected)) {
|
||||
char *fmt, *msgbuffer;
|
||||
|
||||
if (!expected) expected = "(null)";
|
||||
if (!value) value = "(null)";
|
||||
fmt = "%s:%d - %s() - expected:<%s> but was:<%s>";
|
||||
msgbuffer = calloc(strlen(fmt) + strlen(srcfile) + strlen(tc->fname)
|
||||
+ strlen(expected) + strlen(value)
|
||||
+ MAX_DIGITS_INT + 10, sizeof(char));
|
||||
sprintf(msgbuffer, fmt, srcfile, line, tc->fname, expected, value);
|
||||
tc->error_msg = msgbuffer;
|
||||
tc->success = 0;
|
||||
_exit_on_fail(tc);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* TEST RUNNERS
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
/*
|
||||
* Generic runner. Supports fixtures and report function customization.
|
||||
* If the suite was defined with setup and/or teardown functions, those
|
||||
* are run on the optional userdata object.
|
||||
* The report_num_tests(int), report_success(int, chibi_testcase *) and
|
||||
* report_fail(int, chibi_testcase *) functions are used to support
|
||||
* different output protocols (e.g. for reporting the success/failure of
|
||||
* tests while they are run).
|
||||
*/
|
||||
static int _count_tests(chibi_suite *suite) {
|
||||
chibi_testcase *testcase = suite->head;
|
||||
int result = 0;
|
||||
if (suite->first_child) result += _count_tests(suite->first_child);
|
||||
if (suite->next) result += _count_tests(suite->next);
|
||||
while (testcase) {
|
||||
result++;
|
||||
testcase = testcase->next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int _chibi_suite_run(chibi_suite *suite, void (*report_num_tests)(int),
|
||||
void (*report_success)(int, chibi_testcase *),
|
||||
void (*report_fail)(int, chibi_testcase *),
|
||||
int tcnum, int level)
|
||||
{
|
||||
if (suite) {
|
||||
chibi_testcase *testcase;
|
||||
|
||||
if (suite->first_child) {
|
||||
tcnum = _chibi_suite_run(suite->first_child, report_num_tests,
|
||||
report_success, report_fail, tcnum, level + 1);
|
||||
}
|
||||
if (suite->next) {
|
||||
tcnum = _chibi_suite_run(suite->next, report_num_tests,
|
||||
report_success, report_fail, tcnum, level + 1);
|
||||
}
|
||||
|
||||
/* only report the number of tests at the top level */
|
||||
if (level == 0) report_num_tests(_count_tests(suite));
|
||||
|
||||
/* run this level's tests */
|
||||
testcase = suite->head;
|
||||
while (testcase) {
|
||||
#ifndef AMIGA
|
||||
if (!setjmp(testcase->env)) {
|
||||
#endif
|
||||
if (suite->setup) suite->setup(suite->userdata);
|
||||
testcase->fun(testcase);
|
||||
if (suite->teardown) suite->teardown(suite->userdata);
|
||||
#ifndef AMIGA
|
||||
}
|
||||
#endif
|
||||
if (testcase->success) report_success(tcnum, testcase);
|
||||
else report_fail(tcnum, testcase);
|
||||
testcase = testcase->next;
|
||||
tcnum++;
|
||||
}
|
||||
}
|
||||
return tcnum;
|
||||
}
|
||||
|
||||
/*
|
||||
* Standard Runner
|
||||
*/
|
||||
static void report_num_tests_silent(int num_tests) { }
|
||||
static void report_success_silent(int testnum, chibi_testcase *testcase) { }
|
||||
static void report_fail_silent(int testnum, chibi_testcase *testcase) { }
|
||||
static void report_success_std(int testnum, chibi_testcase *testcase) { fprintf(stderr, "."); }
|
||||
static void report_fail_std(int testnum, chibi_testcase *testcase) { fprintf(stderr, "F"); }
|
||||
|
||||
void chibi_suite_run(chibi_suite *suite, chibi_summary_data *summary)
|
||||
{
|
||||
_chibi_suite_run(suite, report_num_tests_silent, report_success_std, report_fail_std, 0, 0);
|
||||
if (summary) _chibi_suite_summary_data(suite, summary, 0);
|
||||
chibi_suite_print_summary(suite);
|
||||
}
|
||||
|
||||
void chibi_suite_run_silently(chibi_suite *suite, chibi_summary_data *summary)
|
||||
{
|
||||
_chibi_suite_run(suite, report_num_tests_silent, report_success_silent, report_fail_silent, 0, 0);
|
||||
if (summary) _chibi_suite_summary_data(suite, summary, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* TAP Runner
|
||||
*/
|
||||
static void report_num_tests_tap(int num_tests) { fprintf(stdout, "1..%d\n", num_tests); }
|
||||
static void report_success_tap(int testnum, chibi_testcase *testcase)
|
||||
{
|
||||
fprintf(stdout, "ok %d - %s\n", testnum + 1, testcase->fname);
|
||||
}
|
||||
static void report_fail_tap(int testnum, chibi_testcase *testcase)
|
||||
{
|
||||
fprintf(stdout, "not ok %d - %s\n", testnum + 1, testcase->fname);
|
||||
}
|
||||
|
||||
void chibi_suite_run_tap(chibi_suite *suite, chibi_summary_data *summary)
|
||||
{
|
||||
_chibi_suite_run(suite, report_num_tests_tap, report_success_tap, report_fail_tap, 0, 0);
|
||||
if (summary) _chibi_suite_summary_data(suite, summary, 0);
|
||||
}
|
||||
85
requesters/chibi.h
Normal file
85
requesters/chibi.h
Normal file
@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
#ifndef __CHIBI_H__
|
||||
#define __CHIBI_H__
|
||||
#include <setjmp.h>
|
||||
|
||||
#define CHIBI_TEST_GIT_SHA "$Id: 72c6f3db3710d13bf1995a89992041e29ab2f43d $"
|
||||
|
||||
/* DATA STRUCTURES */
|
||||
typedef struct _chibi_testcase {
|
||||
void (*fun)(struct _chibi_testcase *);
|
||||
const char *fname;
|
||||
struct _chibi_testcase *next;
|
||||
int success;
|
||||
char *error_msg;
|
||||
void *userdata;
|
||||
jmp_buf env;
|
||||
} chibi_testcase;
|
||||
|
||||
typedef void (*chibi_testfunc)(chibi_testcase *);
|
||||
typedef void (*chibi_fixfunc)(void *);
|
||||
|
||||
typedef struct _chibi_suite {
|
||||
chibi_testcase *head;
|
||||
chibi_fixfunc setup, teardown;
|
||||
void *userdata;
|
||||
|
||||
/* defines the head of the child list */
|
||||
struct _chibi_suite *first_child;
|
||||
|
||||
/* next member in the child list */
|
||||
struct _chibi_suite *next;
|
||||
} chibi_suite;
|
||||
|
||||
typedef struct _chibi_summary_data {
|
||||
int num_runs;
|
||||
int num_pass;
|
||||
int num_failures;
|
||||
} chibi_summary_data;
|
||||
|
||||
/* SUITE MANAGEMENT */
|
||||
extern chibi_suite *chibi_suite_new();
|
||||
extern chibi_suite *chibi_suite_new_fixture(chibi_fixfunc setup, chibi_fixfunc teardown, void *userdata);
|
||||
extern void chibi_suite_delete(chibi_suite *suite);
|
||||
extern void chibi_suite_run(chibi_suite *suite, chibi_summary_data *summary);
|
||||
extern void chibi_suite_run_silently(chibi_suite *suite, chibi_summary_data *summary);
|
||||
extern void chibi_suite_run_tap(chibi_suite *suite, chibi_summary_data *summary);
|
||||
|
||||
/*
|
||||
* We can nest suites. Since every suite can define a fixture, we might define
|
||||
* a number of fixtures and run them as part of a larger suite.
|
||||
*/
|
||||
extern void chibi_suite_add_suite(chibi_suite *suite, chibi_suite *toadd);
|
||||
|
||||
/* don't use this directly */
|
||||
extern void _chibi_suite_add_test(chibi_suite *suite, chibi_testfunc fun, const char *fname);
|
||||
|
||||
/*
|
||||
* ASSERTIONS
|
||||
* don't use these directly, use the macros instead, they are more convenient
|
||||
* to use.
|
||||
*/
|
||||
extern void _chibi_assert_not_null(chibi_testcase *tc, void *ptr, const char *msg,
|
||||
const char *srcfile, int line);
|
||||
extern void _chibi_fail(chibi_testcase *tc, const char *msg, const char *srcfile, int line);
|
||||
extern void _chibi_assert(chibi_testcase *tc, int cond, const char *cond_str, const char *msg,
|
||||
const char *srcfile, int line);
|
||||
extern void _chibi_assert_eq_int(chibi_testcase *tc, int expected, int value,
|
||||
const char *srcfile, int line);
|
||||
extern void _chibi_assert_eq_cstr(chibi_testcase *tc, const char *expected, const char *value,
|
||||
const char *srcfile, int line);
|
||||
|
||||
/* MACROS */
|
||||
#define chibi_suite_add_test(suite, testfun) (_chibi_suite_add_test(suite, testfun, #testfun))
|
||||
#define CHIBI_TEST(funname) void funname(chibi_testcase *_tc)
|
||||
|
||||
#define chibi_assert_not_null(arg) (_chibi_assert_not_null(_tc, arg, "argument was NULL", __FILE__, __LINE__))
|
||||
#define chibi_fail(msg) (_chibi_fail(_tc, msg, __FILE__, __LINE__))
|
||||
#define chibi_assert(cond) (_chibi_assert(_tc, cond, #cond, "condition was wrong:", __FILE__, __LINE__))
|
||||
#define chibi_assert_msg(cond, msg) (_chibi_assert(_tc, cond, "", msg, __FILE__, __LINE__))
|
||||
#define chibi_assert_eq_int(expected, value) (_chibi_assert_eq_int(_tc, expected, value, __FILE__, __LINE__))
|
||||
#define chibi_assert_eq_cstr(expected, value) (_chibi_assert_eq_cstr(_tc, expected, value, __FILE__, __LINE__))
|
||||
|
||||
#define TC_USERDATA (_tc->userdata)
|
||||
|
||||
#endif /* __CHIBI_H__ */
|
||||
@ -111,13 +111,3 @@ struct FileListEntry *scan_dir(const char *dirpath, int *num_entries)
|
||||
if (!dirpath) return all_volumes(num_entries);
|
||||
return dir_contents(dirpath, num_entries);
|
||||
}
|
||||
|
||||
void free_file_list(struct FileListEntry *entries)
|
||||
{
|
||||
struct FileListEntry *cur = entries, *next;
|
||||
while (cur) {
|
||||
next = cur->next;
|
||||
free(cur);
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,27 +3,7 @@
|
||||
#ifndef __DOS13_H__
|
||||
#define __DOS13_H__
|
||||
|
||||
#include <exec/types.h>
|
||||
|
||||
#define FILETYPE_FILE 0
|
||||
#define FILETYPE_DIR 1
|
||||
#define FILETYPE_VOLUME 2
|
||||
|
||||
// This file requester is only for 1.x, so 31 characters is the
|
||||
// maximum
|
||||
#define MAX_FILENAME_LEN 31
|
||||
|
||||
/*
|
||||
* Store file list entries in these entries. Storing a previous pointer allows us to
|
||||
* navigate backwards, e.g. for scrolling up a file list.
|
||||
*/
|
||||
struct FileListEntry {
|
||||
struct FileListEntry *next, *prev;
|
||||
UWORD file_type;
|
||||
UWORD index; // index in the list
|
||||
UWORD selected;
|
||||
char name[MAX_FILENAME_LEN + 1];
|
||||
};
|
||||
#include "file_list.h"
|
||||
|
||||
/*
|
||||
* Scans the specified directory and returns the entries, if dirpath is NULL,
|
||||
|
||||
59
requesters/file_list.c
Normal file
59
requesters/file_list.c
Normal file
@ -0,0 +1,59 @@
|
||||
#include "file_list.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void free_file_list(struct FileListEntry *entries)
|
||||
{
|
||||
struct FileListEntry *cur = entries, *next;
|
||||
while (cur) {
|
||||
next = cur->next;
|
||||
free(cur);
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
||||
static struct FileListEntry *splice(struct FileListEntry *list)
|
||||
{
|
||||
struct FileListEntry *fast = list, *slow = list;
|
||||
while (fast->next && fast->next->next) {
|
||||
fast = fast->next->next;
|
||||
slow = slow->next;
|
||||
}
|
||||
struct FileListEntry *temp = slow->next;
|
||||
slow->next = NULL;
|
||||
return temp;
|
||||
}
|
||||
|
||||
static struct FileListEntry *merge(struct FileListEntry *list1, struct FileListEntry *list2,
|
||||
BOOL asc)
|
||||
{
|
||||
if (!list1) return list2;
|
||||
if (!list2) return list1;
|
||||
int val = strncmp(list1->name, list2->name, MAX_FILENAME_LEN);
|
||||
val = asc ? val : -val; // reverse the comparison value if direction reversed
|
||||
|
||||
if (val < 0) {
|
||||
list1->next = merge(list1->next, list2, asc);
|
||||
list1->next->prev = list1;
|
||||
list1->prev = NULL;
|
||||
return list1;
|
||||
} else {
|
||||
list2->next = merge(list1, list2->next, asc);
|
||||
list2->next->prev = list2;
|
||||
list2->prev = NULL;
|
||||
return list2;
|
||||
}
|
||||
}
|
||||
|
||||
struct FileListEntry *sort_file_list(struct FileListEntry *list, BOOL asc)
|
||||
{
|
||||
if (!list || !list->next) return list;
|
||||
struct FileListEntry *list2 = splice(list);
|
||||
list = sort_file_list(list, asc);
|
||||
list2 = sort_file_list(list2, asc);
|
||||
return merge(list, list2, asc);
|
||||
}
|
||||
|
||||
struct FileListEntry *new_file_list_entry()
|
||||
{
|
||||
return calloc(1, sizeof(struct FileListEntry));
|
||||
}
|
||||
54
requesters/file_list.h
Normal file
54
requesters/file_list.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#ifndef __FILE_LIST_H__
|
||||
#define __FILE_LIST_H__
|
||||
|
||||
/*
|
||||
* File list implementation, this is a system independent module that can be unit tested
|
||||
* easily.
|
||||
*/
|
||||
#ifdef __VBCC__
|
||||
#include <exec/types.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <stdint.h>
|
||||
typedef uint16_t UWORD;
|
||||
typedef uint8_t BOOL;
|
||||
#ifndef NULL
|
||||
#define NULL (0L)
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE (1)
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE (0)
|
||||
#endif
|
||||
|
||||
#endif /* __VBCC__ */
|
||||
|
||||
#define FILETYPE_FILE 0
|
||||
#define FILETYPE_DIR 1
|
||||
#define FILETYPE_VOLUME 2
|
||||
|
||||
// This file requester is only for 1.x, so 31 characters is the
|
||||
// maximum
|
||||
#define MAX_FILENAME_LEN 31
|
||||
|
||||
/*
|
||||
* Store file list entries in these entries. Storing a previous pointer allows us to
|
||||
* navigate backwards, e.g. for scrolling up a file list.
|
||||
*/
|
||||
struct FileListEntry {
|
||||
struct FileListEntry *next, *prev;
|
||||
UWORD file_type;
|
||||
UWORD index; // index in the list
|
||||
UWORD selected;
|
||||
char name[MAX_FILENAME_LEN + 1];
|
||||
};
|
||||
|
||||
extern void free_file_list(struct FileListEntry *entries);
|
||||
|
||||
extern struct FileListEntry *new_file_list_entry();
|
||||
extern struct FileListEntry *sort_file_list(struct FileListEntry *list, BOOL asc);
|
||||
|
||||
#endif /* __FILE_LIST_H__ */
|
||||
69
requesters/file_list_test.c
Normal file
69
requesters/file_list_test.c
Normal file
@ -0,0 +1,69 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "chibi.h"
|
||||
#include "file_list.h"
|
||||
|
||||
CHIBI_TEST(TestMakeEntry)
|
||||
{
|
||||
struct FileListEntry *entry = new_file_list_entry();
|
||||
chibi_assert_not_null(entry);
|
||||
chibi_assert(entry->next == NULL);
|
||||
chibi_assert(entry->prev == NULL);
|
||||
free_file_list(entry);
|
||||
}
|
||||
|
||||
CHIBI_TEST(TestSortListNull)
|
||||
{
|
||||
chibi_assert(sort_file_list(NULL, TRUE) == NULL);
|
||||
chibi_assert(sort_file_list(NULL, FALSE) == NULL);
|
||||
}
|
||||
|
||||
CHIBI_TEST(TestSortListSingle)
|
||||
{
|
||||
struct FileListEntry *entry = new_file_list_entry();
|
||||
chibi_assert(sort_file_list(entry, TRUE) == entry);
|
||||
chibi_assert(sort_file_list(entry, FALSE) == entry);
|
||||
free_file_list(entry);
|
||||
}
|
||||
|
||||
CHIBI_TEST(TestSortListTwoElemsAsc)
|
||||
{
|
||||
struct FileListEntry *entry1 = new_file_list_entry();
|
||||
struct FileListEntry *entry2 = new_file_list_entry();
|
||||
strcpy(entry2->name, "abc");
|
||||
strcpy(entry1->name, "bcd");
|
||||
entry1->next = entry2;
|
||||
entry2->prev = entry1;
|
||||
|
||||
chibi_assert(sort_file_list(entry1, TRUE) == entry2);
|
||||
free_file_list(entry2);
|
||||
}
|
||||
|
||||
CHIBI_TEST(TestSortListTwoElemsDesc)
|
||||
{
|
||||
struct FileListEntry *entry1 = new_file_list_entry();
|
||||
struct FileListEntry *entry2 = new_file_list_entry();
|
||||
strcpy(entry2->name, "abc");
|
||||
strcpy(entry1->name, "bcd");
|
||||
entry1->next = entry2;
|
||||
entry2->prev = entry1;
|
||||
|
||||
chibi_assert(sort_file_list(entry1, FALSE) == entry1);
|
||||
free_file_list(entry1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
chibi_summary_data summary;
|
||||
chibi_suite *suite = chibi_suite_new();
|
||||
chibi_suite_add_test(suite, TestMakeEntry);
|
||||
chibi_suite_add_test(suite, TestSortListNull);
|
||||
chibi_suite_add_test(suite, TestSortListSingle);
|
||||
chibi_suite_add_test(suite, TestSortListTwoElemsAsc);
|
||||
chibi_suite_add_test(suite, TestSortListTwoElemsDesc);
|
||||
|
||||
chibi_suite_run(suite, &summary);
|
||||
|
||||
chibi_suite_delete(suite);
|
||||
return summary.num_failures;
|
||||
}
|
||||
Reference in New Issue
Block a user