USING Progress.Lang.*.
USING OpenEdge.Core.Assert.
USING support.test.AssertExt.

USING Progress.Lang.*.

BLOCK-LEVEL ON ERROR UNDO, THROW.

CLASS tests.preproc.TestPreprocBasic:

	@Test.
	METHOD PUBLIC VOID TestKeepTildes(  ):  
        DEF VAR txt AS CHAR.
        txt = "hel~nlo".
        Assert:Equals("hel\nlo", txt).
	END METHOD.

	@Test.
	METHOD PUBLIC VOID TestMissingEqualsInNamedArgs(  ):  
	    Assert:Equals("something", {tests/preproc/support/simple.i &name1 = something &name2 &name3 = "something else" }).
	END METHOD.

	@Test.
	METHOD PUBLIC VOID TestMissingIncludeFile(  ):
	    DEF VAR errNum AS INTEGER  EXTENT 2.
        ASSIGN
            errNum[1] = 293
            errNum[2] = 193.
            
        COMPILE "tests/preproc/support/missing_include_file.p" NO-ERROR.
        AssertExt:Errors(errNum).
        AssertExt:Error(293, '** "missing.i" was not found. (293)').
	END METHOD.

	@Test.
	METHOD PUBLIC VOID TestNestedPreprocessor(  ):  
        &SCOPED-DEFINE nothing better than nothing
        &GLOBAL-DEFINE something something else
        
        &if false &then
           /* this can never be included since the expression is false */
        &elseif defined(something) &then
           /* welcome to a preprocessed program */
        &else
           /* this can never be included since the elseif will always be true */
        &endif
        
        Assert:Equals("Hello World! This is {&something}, isn't it?", {tests/preproc/support/top.i "isn't it?" "second (unused positional argument)"}).
	END METHOD.
	
	@Test.
	METHOD PUBLIC VOID TestEatTilde(  ):  
        DEF VAR txt AS CHAR.
        DEF VAR something AS CHAR INIT "WHAT?".
        
        /* defines eat tildes before double quotes leaving just the double quotes */
        &SCOPED-DEF EAT_TILDE ~"
        
        /* this same quirky behavior does not occur for the single quote char */
        /* the following define will fail compilation in the following example: */
        /* &SCOPED-DEF EAT_TILDE2 ~?*/
        /* txt = "{&EAT_TILDE2} something {&EAT_TILDE2}".*/
        
        /* Even "inside a string" the tilde is gone before the substitution occurs. */
        /* Notice that this closes the quotes at the beginning and end making this */
        /* a reference to the something variable. */
        txt = " {&EAT_TILDE} + something + {&EAT_TILDE} ".
        
        Assert:Equals(" WHAT? ", txt).
        
        /* Outside of a string is the same, the output is just a single double quote char. */
        /* This means that something is just text in a string, not a variable ref. */
        txt = {&EAT_TILDE} something {&EAT_TILDE}.
        
        Assert:Equals(" something ", txt).
	END METHOD.

    @Test.
    METHOD PUBLIC VOID TestRedefineUsingGlobalDefine(  ):
        DEF VAR errNum AS INTEGER   EXTENT 2.
        DEF VAR errMsg AS CHAR      EXTENT 2.
        ASSIGN
            errNum[1] = 2967
            errNum[2] = 2967
            
            errMsg[1] = "Invalid global redefinition of preprocessor name 'bogus'. (2967)"
            errMsg[2] = "Invalid global redefinition of preprocessor name 'argname'. (2967)".
            
        COMPILE "tests/preproc/support/redefine_using_global_define.p" SAVE NO-ERROR.
        AssertExt:Errors(errNum, errMsg).
    END METHOD.
    
	@Test.
	METHOD PUBLIC VOID TestTextLexerCommentAsCode(  ):  
        COMPILE "tests/preproc/support/text_lexer_comment_as_code.p" SAVE NO-ERROR.
        AssertExt:NotErrorNotWarning().
	END METHOD.
	
    @Test.
    METHOD PUBLIC VOID TestTildesInPreprocDefines(  ):  
        def var txt as char.
        def var txt2 as char.
        def var txt3 as char.
        
        def var results as char extent 3.
        
        results[1] = " ~n something ~n else".
        results[2] = " ~n another ~n thing".
        results[3] = " ~n again ~n again".

        /* these are equivalent, the ~" is the same as just " (the tilde is dropped) when */
        /* this construct occurs inside a define; outside of a define (or a string) it will */
        /* cause compilation failures */
        &SCOP NLIS1 " ~~n "
        &SCOP NLIS2 ~" ~~n ~"    /* new line in a string */
        
        /* this is broken code if uncommented, the ~n ends the definition and you are left */
        /* with a " on the next line which means the string literals are unbalanced */
        /* &SCOP NLIS3 " ~n " */
        
        txt = {&NLIS1} + "something" + {&NLIS1}.
        txt = txt + "else".

        txt2 = {&NLIS2} + "another" + {&NLIS2}.
        txt2 = txt2 + "thing".

        txt3 = " ~n again ~n again".

        Assert:Equals(results[1], txt).
        Assert:Equals(results[2], txt2).
        Assert:Equals(results[3], txt3).
    END METHOD.
END CLASS

.