/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* ** Copyright (c) 2013 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** ** This program is distributed in the hope that it will be useful, ** but without any warranty; without even the implied warranty of ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** Test/demo code for the fossil library API. */ /* Force assert() to always work... */ #if defined(NDEBUG) #undef NDEBUG #define DEBUG 1 #endif #include "fossil-scm/fossil-internal.h" #include "fossil-scm/fossil-cli.h" #include <assert.h> static int test_buffer_0(){ fsl_buffer buf = fsl_buffer_empty; int rc = 0; fsl_cx * f = fcli.f; fsl_size_t sz, szOrig; char const * infile = __FILE__; assert(f); rc = fsl_buffer_fill_from_filename(&buf, infile); assert(!rc); assert(0 > fsl_buffer_uncompressed_size(&buf)); sz = szOrig = buf.used; rc = fsl_buffer_compress( &buf, &buf ); assert(!rc); assert(buf.used < sz); assert(szOrig == fsl_buffer_uncompressed_size(&buf)); f_out("Compressed [%s]. Size: %"FSL_SIZE_T_PFMT " => %"FSL_SIZE_T_PFMT"\n", infile, szOrig, buf.used); sz = buf.used; rc = fsl_buffer_uncompress(&buf, &buf); assert(!rc); f_out("Uncompressed [%s]. Size: %"FSL_SIZE_T_PFMT " => %"FSL_SIZE_T_PFMT"\n", infile, sz, buf.used); assert(szOrig == buf.used); if(0){ fsl_buffer sql = fsl_buffer_empty; fsl_buffer_reset(&buf); rc = fsl_buffer_appendf(&buf, "this isn't a quoted value."); fsl_buffer_appendf(&sql,"/*%%b*/ SELECT x FROM a WHERE a=%b\n", &buf); fsl_output(f, sql.mem, sql.used ); fsl_buffer_reset(&sql); fsl_buffer_appendf(&sql,"/*%%B*/ SELECT x FROM a WHERE a=%B\n", &buf); fsl_output(f, sql.mem, sql.used ); rc = fsl_buffer_reserve(&sql, 0); assert(!rc); } rc = fsl_buffer_reserve(&buf, 0); assert(!rc); return rc; } static int test_stmt_cached(){ fsl_db * db = fsl_cx_db(fcli.f); fsl_stmt * s1 = NULL, * s2 = NULL, * check = NULL; int rc; char const * sql = "SELECT 1 WHERE 3=?"; assert(db); rc = fsl_db_prepare_cached(db, &s1, sql); assert(0==rc); assert(s1); check = s1; /* Concurrent use must fail to avoid that recursion bones us with a hard-to-track error... */ rc = fsl_db_prepare_cached(db, &s2, sql); assert(FSL_RC_ACCESS==rc); assert(!s2); rc = fsl_stmt_cached_yield(s1); assert(0==rc); /* Make sure we get the same pointer back... */ s1 = NULL; rc = fsl_db_prepare_cached(db, &s1, sql); assert(0==rc); assert(s1); assert(check == s1); rc = fsl_stmt_cached_yield(s1); assert(0==rc); rc = fsl_stmt_cached_yield(s1); assert(FSL_RC_MISUSE==rc); rc = 0; f_out("Statement caching seems to work.\n"); return rc; } /* static */ int test_db_beforeCommit(){ int rc; fsl_cx * f = fcli.f; fsl_db * db = fsl_cx_db_checkout(f); char * str; assert(db); rc = fsl_db_transaction_begin(db); assert(!rc); rc = fsl_db_before_commit(db, "REPLACE INTO vvar (name,value) VALUES" "('test-beforeCommit', '%p')", (void const *)db); assert(!rc); rc = fsl_db_exec(db, "REPLACE INTO vvar (name,value) VALUES" "('change-placeholder','%p')", (void const *)f); assert(!rc); rc = fsl_db_transaction_end(db, 0); assert(!rc); str = fsl_db_g_text( db, NULL, "SELECT value FROM vvar " "WHERE name='test-beforeCommit'"); assert(str); f_out("Read back beforeCommit-added value: %s\n", str); fsl_free(str); return rc; } static int test0(){ fsl_cx * f = fcli.f; int rc = 0; if(fsl_cx_db_repo(f)){ f_out("ID of tag 'sym-trunk'=%"FSL_ID_T_PFMT"\n", fsl_tag_id(f, "sym-trunk", 0)); f_out("ID of tag 'tag-creation-test2'=%"FSL_ID_T_PFMT"\n", fsl_tag_id(f, "tag-creation-test2", 1)); assert(0 == fsl_tag_id(f, "no-such-tag", 0)); } if(fsl_cx_db_checkout(f)){ fsl_id_t id = 0, id2 = 0; char * uuid = 0; f_out("Running sym-to-rid tests...\n"); id = 0; rc = fsl_sym_to_rid(f, "tip", FSL_ATYPE_ANY, &id); assert(0==rc); assert(id>0); id = 0; rc = fsl_sym_to_rid(f, "current", FSL_ATYPE_ANY, &id); f_out("rc=%d/%s\n", rc, fsl_rc_cstr(rc)); assert(0==rc); assert(id>0); assert(!fsl_content_is_private(f,id)); id = 0; rc = fsl_sym_to_rid(f, "9d8c610ad6", FSL_ATYPE_CHECKIN, &id); assert(0==rc); assert(id>0); id = 0; rc = fsl_sym_to_rid(f, "9d8c610ad6", FSL_ATYPE_WIKI, &id); assert(FSL_RC_NOT_FOUND==rc); assert(id==0); fsl_cx_err_reset(f) /* stop propagation of that error. */; id = 0; rc = fsl_sym_to_rid(f, "trunk", FSL_ATYPE_ANY, &id); assert(0==rc); assert(id>0); assert(fsl_rid_is_leaf(f, id)); assert(0 == fsl_count_nonbranch_children(f, id)); if(0){ fsl_buffer buf = fsl_buffer_empty; rc = fsl_content_blob(f, id, &buf); assert(!rc); f_out("Control artifact for rid #%"FSL_ID_T_PFMT":\n%s", id, fsl_buffer_cstr(&buf)); fsl_buffer_clear(&buf); } id = 0; rc = fsl_sym_to_rid(f, "prev", FSL_ATYPE_CHECKIN, &id); assert(0==rc); assert(id>0); assert(!fsl_rid_is_leaf(f, id)); assert(0 < fsl_count_nonbranch_children(f, id)); id = 0; rc = fsl_sym_to_rid(f, "current", FSL_ATYPE_CHECKIN, &id); assert(0==rc); assert(id>0); rc = fsl_sym_to_uuid(f, "current", FSL_ATYPE_CHECKIN, &uuid, &id2); assert(0==rc); assert(uuid); assert(id2 == id); assert(FSL_UUID_STRLEN==fsl_strlen(uuid)); f_out("Current checkout: %.*s\n", FSL_UUID_STRLEN, uuid); fsl_free(uuid); } return rc; } /* static */ int test_leaves_rebuild(){ int rc; f_out("Rebuilding leaves...\n"); rc = fsl_repo_leaves_rebuild(fcli.f); assert(!rc); f_out("Done rebuilding leaves.\n"); return rc; } static int test_content_get(){ char const * sym = /* some version of th1ish/test-003.th1ish */ "33b40942db0c00eba3a2a0bf1e61ea5c573e902f" /* first version */ ; int rc; fsl_id_t rid = 0; fsl_buffer c = fsl_buffer_empty; fsl_cx * f = fcli.f; rc = fsl_sym_to_rid(f, sym, FSL_ATYPE_ANY, &rid); assert(!rc); assert(rid>0); rc = fsl_content_get(f, rid, &c); fsl_cx_err_report(f, 1); assert(!rc); assert(1032==c.used); rc = fsl_sha1sum_buffer( &c, &c ); assert(!rc); assert(FSL_UUID_STRLEN==c.used); assert(0==fsl_strcmp( sym, fsl_buffer_cstr(&c) )); /* Now fetch a few other versions of that same file and ensure that they meet our expectations... */ sym = "e9b776a8a72753823e4553a309edae21897cb2c4"; rid = 0; rc = fsl_sym_to_rid(f, sym, FSL_ATYPE_ANY, &rid); assert(!rc); assert(rid>0); rc = fsl_content_get(f, rid, &c); assert(!rc); assert(2076==c.used); rc = fsl_sha1sum_buffer( &c, &c ); assert(!rc); assert(FSL_UUID_STRLEN==c.used); assert(0==fsl_strcmp( sym, fsl_buffer_cstr(&c) )); sym = "f7d3a2e155d59a96ecc37001b05de26dee23c0cf"; rid = 0; rc = fsl_sym_to_rid(f, sym, FSL_ATYPE_ANY, &rid); assert(!rc); assert(rid>0); rc = fsl_content_get(f, rid, &c); assert(!rc); assert(2481==c.used); rc = fsl_sha1sum_buffer( &c, &c ); assert(!rc); assert(FSL_UUID_STRLEN==c.used); assert(0==fsl_strcmp( sym, fsl_buffer_cstr(&c) )); sym = "31e01e2a3c"; rid = 0; rc = fsl_sym_to_rid(f, sym, FSL_ATYPE_WIKI, &rid); assert(!rc); assert(rid>0); rc = fsl_content_get(f, rid, &c); #if 1 if(0){ f_out("got content [%s]:\n%.*s", sym, (int)c.used, (char const *)c.mem); }else{ f_out("got content [%.*s]: %d byte(s)\n", 8, sym, (int)c.used); } #endif fsl_buffer_clear(&c); return rc; } static int test_hash_this_file(){ fsl_buffer hash = fsl_buffer_empty; int rc; rc = fsl_md5sum_filename(__FILE__, &hash); assert(!rc); f_out("MD5 of this file: %s\n", fsl_buffer_cstr(&hash)); rc = fsl_sha1sum_filename(__FILE__, &hash); assert(!rc); f_out("SHA1 of this file: %s\n", fsl_buffer_cstr(&hash)); fsl_buffer_clear(&hash); return rc; } static int test_text_diff(){ fsl_buffer lhs = fsl_buffer_empty; fsl_buffer rhs = fsl_buffer_empty; fsl_buffer diff = fsl_buffer_empty; int rc; int context = 1; rc = fsl_buffer_fill_from_filename(&lhs, __FILE__); assert(!rc); rc = fsl_buffer_append( &rhs, lhs.mem, lhs.used ); assert(!rc); for( rc = 0; rc < 20; ++rc ){ rhs.mem[rc + 100] = '*'; } rc = fsl_diff_text_to_buffer( &lhs, &rhs, &diff, context, 0, FSL_DIFF_INLINE); f_out("diff rc=%s, output len=%"FSL_SIZE_T_PFMT"\n", fsl_rc_cstr(rc), diff.used); f_out("Diff from this file and a mangled copy:\n%b", &diff); fsl_buffer_clear(&diff); f_out("\nInverted...\n"); rc = fsl_diff_text( &lhs, &rhs, fsl_output_f_FILE, stdout, context, 0, FSL_DIFF_INVERT); f_out("\nWith line numbers...\n"); rc = fsl_diff_text( &lhs, &rhs, fsl_output_f_FILE, stdout, context, 0, FSL_DIFF_INLINE | FSL_DIFF_LINENO); f_out("\nSide-by-side...\n"); rc = fsl_diff_text( &lhs, &rhs, fsl_output_f_FILE, stdout, context, 30, 0 /*FSL_DIFF_SIDEBYSIDE is implicit when sbsWidth>0*/); f_out("\nInverted...\n"); rc = fsl_diff_text( &lhs, &rhs, fsl_output_f_FILE, stdout, context, 30, FSL_DIFF_INVERT); if(0){ f_out("\nAnd using HTML...\n"); rc = fsl_diff_text( &lhs, &rhs, fsl_output_f_FILE, stdout, 3, 80, FSL_DIFF_SIDEBYSIDE | FSL_DIFF_HTML); } fsl_buffer_clear(&lhs); fsl_buffer_clear(&rhs); #if 0 printf("[%*s]\n", 7, "-----"); f_out("[%*s]\n", 7, "-----"); printf("[%7s]\n", "-----"); f_out("[%7s]\n", "-----"); printf("[%*s]\n", 3, "-----"); f_out("[%*s]\n", 3, "-----"); printf("[%3s]\n", "-----"); f_out("[%3s]\n", "-----"); printf("[%.*s]\n", 7, "-----"); f_out("[%.*s]\n", 7, "-----"); printf("[%.*s]\n", 3, "-----"); f_out("[%.*s]\n", 3, "-----"); printf("[%*s]\n", 10, "-----"); f_out("[%*s]\n", 10, "-----"); printf("[%-*s]\n", 10, "-----"); f_out("[%-*s]\n", 10, "-----"); #endif return rc; } static void fcli_local_help(){ puts("This is a scratchpad app and has no help."); } int main(int argc, char * const * argv ){ int rc = 0; fsl_cx * f = NULL;; assert(sizeof(fsl_int32_t) >= 4); assert(sizeof(fsl_int64_t) >= 8); fcli.appHelp = fcli_local_help; rc = fcli_setup(argc, argv); if(rc) goto end; f = fcli.f; rc = test0(); if(!rc) rc = test_buffer_0(); #if 0 && defined(SQLITE_FCNTL_TEMPFILENAME) if(!rc) rc = test_tmpfile_0(); #endif if(!rc && fsl_cx_db_repo(fcli.f)){ /* rc = test_leaves_rebuild(); */ if(!rc) rc = test_content_get(); } if(!rc){ rc = test_hash_this_file(); } if(!rc && fsl_cx_db_checkout(f)){ test_db_beforeCommit(); } if(!rc && fsl_cx_db(f)){ rc = test_stmt_cached(); } if(!rc){ rc = test_text_diff(); } end: f_out("Done! rc=%d (%s)\n", rc, fsl_rc_cstr(rc)); return (fcli_err_report(0) || rc) ? EXIT_FAILURE : EXIT_SUCCESS; }