brandonLi8/truenit

Implement truenit.js

Closed this issue · 11 comments

Implement truenit.js as the main script.

Goal API:

  • First call require( 'truenit' ); and reference it.
  • call truenit.start( () => { // start testing here } )
  • then inside of the truenit.start passed functions start testing via truenit.testModule
  • log the errors if there are any in different colors.

The first thing that I have ran into is the uglyness of Node errors.

For example:
Screen Shot 2019-11-02 at 6 19 54 PM

I think I want to use console.log to self catch all errors.

After further investigation, I have decided to use process.stdout.write for all errors.
I referenced this from this forum. This will allow me to log without new lines (optional) via \n.

This will allow me to do:
image

I still need to colorize these, however.

If found this article which demos colorized output via process.stdout.write.

I converted this to my script:

  /**
   * A logger for NodeJs that allows for same line logging. Should be wrapped inside a wrapper.
   * Use to indicate a new line and to colorize the output.
   *
   * @param {string} message
   * @param {number} [color] - the code for the color. See below:
   *    Reset = 0        Bright = 1     Di = 2          Underscore = 4
   *    Blink = 5        Reverse = 7    Hidden = 8      FgBlack = 30
   *    FgRed = 31       FgGreen = 32   FgYellow = 33   FgBlue = 34
   *    FgMagenta = 35   FgCyan = 36    FgWhite = 37    BgBlack = 40
   *    BgRed = 41       BgGreen = 42   BgYellow = 43   BgBlue = 44
   *    BgMagenta = 45   BgCyan = 46    BgWhite = 47
   */
  function log( message, color=0 ) {
    assert( typeof message === 'string', `invalid message: ${message}` );
    process.stdout.write( '\x1b[' + color + 'm' + message + '\x1b[0m' );
  }

I now need to wrap everything in a try-catch statement so that I can properly call log on all error catches.

I have decided to split this up to 3 layers:

First Layer:

  /**
   * Wraps a task such that any errors (which stops task) will be thrown via a log call.
   * Improves the Node.js error handling.
   *
   * @param {function} task
   */
  function wrap( task ) {
    try { task(); }
    catch( error ) {
      // Catch any errors while executing task and reformat the error message.
      log( `${error}`, 31 );
      process.exit( 1 );
    }
  };

This will do a task and log any errors and exit the script. This is the main wrapper for the script.

Second Layer:

    /**
     * Basic method that attempts to execute a tester. Used as a high-level wrapper to start a large
     * section of tests.
     * @public
     *
     * @param {function} tester
     * @param {string} [startMessage]
     * @param {number} [startColor]
     * @param {string} [endMessage]
     * @param {number} [endColor]
     * @param {string} [failedMessage]
     */
    static test( tester, startMessage, startColor, endMessage, endColor, failedMessage ) {
      wrap( () => {
        assert( typeof tester === 'function', `invalid tester: ${tester}` );
        assert( !startMessage || typeof startMessage === 'string', `invalid startMessage: ${startMessage}` );
        assert( !endMessage || typeof endMessage === 'string', `invalid endMessage: ${endMessage}` );
        assert( !failedMessage || typeof failedMessage === 'string', `invalid failedMessage: ${failedMessage}` );

        //----------------------------------------------------------------------------------------
        // Start testing
        log( startMessage ? startMessage : 'starting test...\n', startColor );

        try {
          tester();
        }
        catch( error ) {
          assert( false, failedMessage ? failedMessage : `FAILED \n\n${error.stack}\n\n` );
        }
        log( endMessage ? endMessage : 'Test passed!', endColor );
      } )
    }

The second layer calls wrap on a task that runs tester. This is public facing but generally won't be used. This is starting to put the module together.

Third layer

Call this.test in other methods (start and testModule). I haven't added these yet.

I have finished adding the other layers:

   /**
     * Test method wrapper for the start of a project.
     *
     * @param {function} tester
     */
    static start( tester ) {
      truenit.test( tester, 'Testing all...\n\n', 4, '\nAll tests passed!\n\n', 32 );
    }

    /**
     * Test method wrapper for a module. Should be wrapped inside of truenit.start().
     *
     * @param {string} name - the name of the module
     * @param {function} tester
     */
    static testModule( name, tester ) {
      wrap( () => {
        assert( typeof name === 'string', `invalid name: ${name}` );
      } );
      truenit.test( tester, `Testing ${name}...  `, 2, `passed.\n`, 0 );
    }

    /**
     * Tests that a predicate is truthy.
     * Should be wrapped inside of a tester.
     * @public
     *
     * @param {boolean} predicate
     * @param {string} [message]
     */
    static ok( predicate, message ) {
      assert( predicate, message || 'unit test failed.' );
    }

It is important to note that ok should be ran inside of start or testModule so that it is properly caught and logged.

I have adjusted the colors and tested a sample tester.

This is what it looks like when it errors:
image

The unalignment isn't great, so I'm going to work on aligning them.

I have decided on an API change to allow for this change:

    truenit.registerModule( 'Point', require( 'TESTS/util/PointTests' ) );
    truenit.registerModule( 'Node', require( 'TESTS/util/PointTests' ) );

    truenit.registerModule( 'ScreenView', require( 'TESTS/util/PointTests' ) );
    truenit.registerModule( 'Vector', require( 'TESTS/util/PointTests' ) );
    truenit.registerModule( 'VectorProperty', require( 'TESTS/util/PointTests' ) );
    truenit.registerModule( 'Merge', require( 'TESTS/util/PointTests' ) );
    truenit.registerModule( 'Enum', require( 'TESTS/util/PointTests' ) );
    truenit.registerModule( 'Property', require( 'TESTS/util/PointTests' ) );
    truenit.registerModule( 'PointProperty', require( 'TESTS/util/PointTests' ) );
    truenit.registerModule( 'Sim', require( 'TESTS/util/PointTests' ) );
    truenit.registerModule( 'ErrorModule', () => { throw new Error( 'Error Message')} );

    truenit.start();

As you can see from this example, I'm going to register each module's tester first then start it. This way I can align the "passed"

In the commit above, I have made the spacing the same:

image

However, this new API relies on static variables, which isn't ideal. I'm going to need more methods, like a resetRegisterModules.

It now looks like this:
image

which looks much better. Time to clean up the code.

With the commits, above, the formatting is now correct.

screenshots

  • Testing Non-registered test:
    image

-Testing non-registered test (fail):
image

  • Testing Registered
    image
    image

  • Testing Registered tests (fail)
    image

My work is done here. I changed up the appearance a bit 4f6ca9b and I'm going to lint and do some minor clean up in #3. Closing.