Login
f-event.c at [9a344d2655]
Login

File f-event.c artifact 741a919bd1 part of check-in 9a344d2655


/* -*- 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;
}