/* -*- 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/ ** ******************************************************************************* ** This file holds test code for EVENT control artifacts. */ #include "fossil-scm/fossil-cli.h" /* Fossil App mini-framework */ #include "fossil-scm/fossil-internal.h" static void fcli_local_help(){ printf("Usage:\n\t%s [options]\n\n", fcli.appName); puts("Test app for EVENT manifests"); puts("\t--wet-run|-w is the opposite of dry-run.\n"); puts("\t--crosslink|-c enables crosslinking of the generated event.\n"); } static struct App_ { char crossLink; char wetRun; } App = { 0/*crossLink*/, 0/*wetRun*/ }; /* static */ int test_event_0(){ fsl_cx * f = fcli.f; fsl_db * db = fsl_cx_db_repo(f); fsl_deck DECK = fsl_deck_empty; fsl_deck * d = &DECK; fsl_buffer dout = fsl_buffer_empty; fsl_buffer hash = fsl_buffer_empty; int rc; fsl_double_t now = 1 ? 2456525.3001276273 /* 2013-08-20T19:12:11.027 */ : fsl_db_julian_now(db); if(!db){ return fsl_cx_err_set(f, FSL_RC_MISUSE, "This app requires a repo."); } VERBOSE(("now=%"FSL_JULIAN_T_PFMT"\n", now)); fsl_deck_init(f, d, FSL_CATYPE_EVENT); assert(f==d->f); assert(FSL_CATYPE_EVENT==d->type); assert(NULL==d->allocStamp); rc = fsl_deck_C_set(d, "Test event - automatically generated", -1); assert(!rc); rc = fsl_deck_D_set( d, now ); assert(!rc); #if 0 { char * eventId = fsl_db_random_hex(db, FSL_UUID_STRLEN); assert(fsl_is_uuid(eventId)); rc = fsl_deck_E_set( d, now, eventId ); fsl_free(eventId); } #else rc = fsl_deck_E_set( d, now, "b82b583b2cf60075c99e2ee5accec41906d3e6a2"); #endif assert(!rc); rc = fsl_deck_T_add( d, FSL_TAGTYPE_ADD, NULL, "automated", NULL); assert(!rc); { char * u = fsl_guess_user_name(); assert(u); rc = fsl_deck_U_set( d, u, -1); fsl_free(u); assert(!rc); } rc = fsl_deck_W_set( d, "Test event content.", -1 ); assert(!rc); rc = fsl_deck_output(f, d, fsl_output_f_buffer, &dout ); fcli_err_report(1); assert(!rc); f_out("%b", &dout); fsl_sha1sum_buffer( &dout, &hash ); d->uuid = fsl_buffer_str(&hash); hash = fsl_buffer_empty; VERBOSE(("SHA1=%s\n", d->uuid)); if(App.crossLink){ /* Write it! */ fsl_db_transaction_begin(db); assert(d->rid<=0); assert(d->uuid); rc = fsl_content_put_ex(f, &dout, d->uuid, 0, 0, 0, &d->rid); fcli_err_report(1); assert(!rc); /* assert( 1863 == d->rid ); */ VERBOSE(("Event content record id: %"FSL_ID_T_PFMT"\n", d->rid)); rc = fsl_deck_crosslink(f, d); fcli_err_report(0); assert(!rc); VERBOSE(("Crosslink of #%"FSL_ID_T_PFMT" [%.*s] finished.\n", d->rid, 12, d->uuid)); if(!App.wetRun){ VERBOSE(("dry-run mode: rolling back transaction.\n")); } fsl_db_transaction_end(db, rc || !App.wetRun); } fsl_buffer_clear(&dout); fsl_buffer_clear(&hash); fsl_deck_finalize(d); return rc; } int main(int argc, char * const * argv ){ int rc = 0; fcli.appHelp = fcli_local_help; rc = fcli_setup(argc, argv); if(FSL_RC_BREAK==rc) return 0; else if(rc) goto end; App.crossLink = fcli_flag2("c", "crosslink", 0); App.wetRun = fcli_flag2("w", "wet-run", 0); if(fcli_has_unused_flags(0)) goto end; #if 0 /* Testing a bug/fix: Build on a 32-bit environment (untested on 64-bit) Enable 'long long' typedef fsl_int32_t fsl_id_t #define FSL_ID_T_PFMT FSL_INT32_T_PFMT And then... */ { char buf[80]; int i = 0; f_out("#%d: %"FSL_ID_T_PFMT" %"FSL_ID_T_PFMT" %"FSL_ID_T_PFMT"\n", ++i, 1, 2, 3); f_out("#%d: %"FSL_SIZE_T_PFMT" %"FSL_ID_T_PFMT" %"FSL_SIZE_T_PFMT"\n", ++i, (fsl_size_t)1, (fsl_id_t)2, (fsl_size_t)3); puts("This next one (might) fail badly because the numeric arguments " "are passed on as integers and the va_arg() handling extracts " "a larger type, effectively skipping over arguments and potentially " "overrunning memory (i.e. corruption):"); f_out("#%d: %"FSL_SIZE_T_PFMT" %"FSL_ID_T_PFMT" %"FSL_SIZE_T_PFMT"\n", ++i, 1, 2, 3); puts("The trigger is the 'll' format specifier in conjunction with " "integer arguments which are not strongly typed and don't match " "their format specifier's expected sizeof() exactly."); /* Problem has something to do with the sizeof(int) resp. sizeof(fsl_id_t) and the va_arg() handling of the etRADIX bits in fsl_appendf(). The fix? Find the right combination of formatting string for integers in that combination. %d is apparently not correct. And it only appears to happen when we cross multiple levels of va_list handling? Namely, it happens in fsl_snprintf() but not fsl_output(): */ fsl_snprintf(buf, sizeof(buf), "?? #%d: ?? %"FSL_SIZE_T_PFMT" %"FSL_ID_T_PFMT" %"FSL_SIZE_T_PFMT" wth?\n", (int)++i, (fsl_size_t)1, (fsl_id_t)2, (fsl_size_t)3); f_out("i=%d, fsl_snprintf() says: %s\n", i, buf); puts("That one is failing differently in tcc/gcc."); } #else rc = test_event_0(); #endif end: return fcli_err_report(0) ? EXIT_FAILURE : rc; }