After my test script found errors with my previous median function, I’ve gone ahead and made some improvements. Again, the goal here isn’t to be thorough but is to demonstrate a boundary-testing technique that is easy to conceive, implement, and build-upon. Like I mentioned in my previous post, this single test script can be the foundation for a testing class. I would also go further by wrapping all of this into a table-driven engine, which would call the function, define its parameters, and identify its expected return value. With VFP9, structured error handling will also help.
I imagine that a revisit of this topic at some point will be in order. Until then, enjoy the much improved get_median function:
*--The following code is an improved get_median FUNCTION get_median_clean LPARAMETERS tnType, teName, teColDel *-- boundary testing IF !BETWEEN(tnType,1,3) RETURN 0 ENDIF DO CASE CASE tnType = 1 .and. VARTYPE(teName)<>"C" RETURN 0 CASE tnType = 1 .and. (!ISDIGIT(teName) .or.; VARTYPE(teColDel)<>"C") RETURN 0 CASE INLIST(tnType,2,3) .and. TYPE(teColDel)<>"N" RETURN 0 CASE tnType = 2 .and. (!USED(teName) .or. ; EMPTY(FIELD(teColDel,teName))) RETURN 0 CASE tnType = 2 .and. ; VARTYPE(EVALUATE(FIELD(teColDel,teName))) <> "N" RETURN 0 CASE tnType = 3 .and. ; VARTYPE(EVALUATE(teColDel[1,teColDel])) <> "N" RETURN 0 ENDCASE *-- local declerations LOCAL lcSelCol AS String LOCAL lnItems, lnHalf, lnInc AS Integer LOCAL lnMedian AS Number *-- create the aMedian Array DO CASE CASE tnType = 1 && use a delimted string lnItems = ALINES( aMedian , STRTRAN(teName ,teColDel,CHR(13)) ) FOR lnInc = 1 TO lnItems aMedian[lnInc] = VAL(aMedian[lnInc]) NEXT CASE tnType = 2 && calculate using an alias lcSelCol = FIELD(teColDel,teName) lcSQL = "SELECT " + lcSelCol + " FROM " + teName + ; " ORDER BY " + lcSelCol + " INTO ARRAY aMedian" &lcSQL lnItems= _TALLY CASE tnType = 3 && calculate using an array lnItems= ALEN(&teName,1) DIMENSION aMedian[lnItems] FOR lnInc = 1 TO lnItems aMedian[lnInc] = &teName.[lnInc,teColDel] NEXT ENDCASE *-- find the median ASORT(aMedian) lnHalf = CEILING( lnItems / 2) IF MOD(lnHalf,2) = 0 lnMedian = ( aMedian[lnHalf] + aMedian[lnHalf+1] ) / 2 ELSE lnMedian = aMedian[lnHalf] ENDIF RETURN lnMedian ENDFUNC