-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature(two-fer): add two-fer practice exercise (#27)
- Loading branch information
Showing
9 changed files
with
371 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Instructions | ||
|
||
`Two-fer` or `2-fer` is short for two for one. | ||
One for you and one for me. | ||
|
||
Given a name, return a string with the message: | ||
|
||
```text | ||
One for name, one for me. | ||
``` | ||
|
||
Where "name" is the given name. | ||
|
||
However, if the name is missing, return the string: | ||
|
||
```text | ||
One for you, one for me. | ||
``` | ||
|
||
Here are some examples: | ||
|
||
|Name |String to return | ||
|:-------|:------------------ | ||
|Alice |One for Alice, one for me. | ||
|Bob |One for Bob, one for me. | ||
| |One for you, one for me. | ||
|Zaphod |One for Zaphod, one for me. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"authors": ["ajborla"], | ||
"files": { | ||
"solution": ["two_fer.prg"], | ||
"test": ["two_fer_test.prg"], | ||
"example": [".meta/example.prg"] | ||
}, | ||
"blurb": "Create a sentence of the form \"One for X, one for me.\".", | ||
"source_url": "https://github.com/exercism/problem-specifications/issues/757" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
* ---------------------------------------------------------------------------- | ||
* exercism.org | ||
* Harbour Track Exercise: two-fer | ||
* Contributed: Anthony J. Borla ([email protected]) | ||
* ---------------------------------------------------------------------------- | ||
|
||
function TwoFer(name) | ||
return ; | ||
IIF(name == NIL .OR. EMPTY(name), ; | ||
"One for you, one for me.", ; | ||
"One for " + ALLTRIM(name) + ", one for me.") | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# This is an auto-generated file. | ||
# | ||
# Regenerating this file via `configlet sync` will: | ||
# - Recreate every `description` key/value pair | ||
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications | ||
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) | ||
# - Preserve any other key/value pair | ||
# | ||
# As user-added comments (using the # character) will be removed when this file | ||
# is regenerated, comments can be added via a `comment` key. | ||
|
||
[1cf3e15a-a3d7-4a87-aeb3-ba1b43bc8dce] | ||
description = "no name given" | ||
|
||
[b4c6dbb8-b4fb-42c2-bafd-10785abe7709] | ||
description = "a name given" | ||
|
||
[3549048d-1a6e-4653-9a79-b0bda163e8d5] | ||
description = "another name given" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
* ---------------------------------------------------------------------------- | ||
* Harbour Unit Test Worker | ||
* Anthony J. Borla ([email protected]) | ||
* ---------------------------------------------------------------------------- | ||
|
||
#ifndef UTILS_PRG | ||
#include "utils.prg" | ||
#endif | ||
|
||
procedure MakeTestDatabaseStructure(dbfName) | ||
* Creation overwites any existing database | ||
create &dbfName | ||
|
||
* Each record describes the structure of a FIELD | ||
append blank | ||
replace Field_name with "NAME", Field_type with "C",; | ||
Field_Len with 80, Field_dec with 0 | ||
append blank | ||
replace Field_name with "CMPOP", Field_type with "C",; | ||
Field_Len with 2, Field_dec with 0 | ||
append blank | ||
replace Field_name with "EXPVALUE", Field_type with "C",; | ||
Field_Len with 80, Field_dec with 0 | ||
append blank | ||
replace Field_name with "CMDSTR", Field_type with "C",; | ||
Field_Len with 80, Field_dec with 0 | ||
|
||
* Ensure data written to disk | ||
close &dbfName | ||
return | ||
|
||
procedure MakeTestDatabase(dbfName) | ||
local dbfStructure := dbfName + "_STRUCTURE" | ||
|
||
* Build test database from database structure file | ||
do MakeTestDatabaseStructure with dbfStructure | ||
create &dbfName from &dbfStructure | ||
|
||
* Ensure database structure file is removed | ||
dbfStructure := dbfStructure + ".dbf" | ||
erase &dbfStructure | ||
return | ||
|
||
procedure AddTestDatabase(dbfName, testName, cmpOp, expValue, cmdStr) | ||
* Load a test data record into tests database (note use of 'Wrap' to | ||
* preserve spaces in expected value string) | ||
use &dbfName | ||
append blank | ||
replace &dbfName->NAME with testName | ||
replace &dbfName->CMPOP with cmpOp | ||
replace &dbfName->EXPVALUE with Wrap(expValue) | ||
replace &dbfName->CMDSTR with cmdStr | ||
close &dbfName | ||
return | ||
|
||
function RunTests(dbfName, keepTestDBF, outputJSON) | ||
local testName, cmpOp, expValue, cmdStr, retValue, testExpr | ||
local success := .T. | ||
|
||
use &dbfName | ||
|
||
* Determine, and print, number of tests (required for TAP) | ||
if outputJSON == NIL .OR. !outputJSON | ||
? "1.." + LTRIM(STR(LASTREC())) | ||
endif | ||
|
||
* Execute unit tests | ||
do while !EOF() | ||
* Extract test data (note use of 'Unwrap' to extract space-preserved | ||
* expected value string) | ||
testName := ALLTRIM(&dbfName->NAME) | ||
cmpOp := &dbfName->CMPOP | ||
expValue := Unwrap(ALLTRIM(&dbfName->EXPVALUE)) | ||
cmdStr := ALLTRIM(&dbfName->CMDSTR) | ||
|
||
* Execute test, and build test expression | ||
retValue := TypeToS(&cmdStr) | ||
testExpr := '"' + retValue + '" ' + cmpOp + ' "' + expValue + '"' | ||
|
||
* If the parameter flag, outputJSON, is omitted, or set to .F., then | ||
* emit test report in TAP format | ||
if outputJSON == NIL .OR. !outputJSON | ||
* Report test outcome - TAP | ||
if &testExpr | ||
? "OK " + LTRIM(STR(RECNO())) + " - " + testName | ||
else | ||
* Single test failure signals failure of whole suite | ||
success := .F. | ||
? "FAIL " + LTRIM(STR(RECNO())) + " - " + testName | ||
endif | ||
else | ||
* Report test outcome - JSON | ||
? "JSON" | ||
endif | ||
|
||
* ... next test | ||
skip | ||
enddo | ||
|
||
close &dbfName | ||
|
||
* If the parameter flag, keepTestDBF, is omitted, or set to .F., then | ||
* remove the tests database | ||
if keepTestDBF == NIL .OR. !keepTestDBF | ||
dbfName := dbfName + ".dbf" | ||
erase &dbfName | ||
endif | ||
|
||
return success | ||
|
||
function TypeToS(value) | ||
* Use VALTYPE() instead of TYPE() to check type | ||
local typeValue := VALTYPE(value) | ||
|
||
switch typeValue | ||
* Array type (assume 1D array of non-aggregate elements), | ||
* returns the concatenation of elements as a string | ||
case "A" ; return ArrToS(value) | ||
|
||
* Character type returned untouched | ||
case "C" ; return value | ||
|
||
* Date as "yyyymmdd" | ||
case "D" ; return DTOS(value) | ||
|
||
* Logical as literal string representation of self | ||
case "L" ; return IIF(value, ".T.", ".F.") | ||
|
||
* String-converted numerics are right-justified, so ensure are | ||
* returned trimmed | ||
case "N" ; return ALLTRIM(STR(value)) | ||
|
||
* Support use of NIL return type (usually to indicate error) | ||
case "U" ; return "NIL" | ||
endswitch | ||
|
||
* Ignore the remaining types, just return NIL (likely runtime error) | ||
return NIL | ||
|
||
* Utilities to preserve leading and trailing spaces in strings as they | ||
* are stored into, and extracted from, database fields | ||
function Wrap(string) ; return WrapString(string, .F., "[", "]") | ||
function Unwrap(string) ; return WrapString(string, .T.) | ||
|
||
function WrapString(string, doUnwrap, wrapStart, wrapEnd) | ||
local uws | ||
if doUnwrap | ||
uws := SUBSTR(SUBSTR(string, 2), 1, LEN(string) - 2) | ||
else | ||
uws := wrapStart + string + wrapEnd | ||
endif | ||
return uws | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
* ---------------------------------------------------------------------------- | ||
* exercism.org | ||
* Harbour Track Exercise: two-fer | ||
* ---------------------------------------------------------------------------- | ||
|
||
function TwoFer(name) | ||
return "" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
* ---------------------------------------------------------------------------- | ||
* Harbour Unit Test Runner [two_fer.prg] | ||
* ---------------------------------------------------------------------------- | ||
|
||
* Variable declarations | ||
memvar TESTS, SUCCESS | ||
|
||
* Test database name | ||
TESTS := IIF(PCOUNT() > 0, hb_PValue(1), "TESTS") | ||
|
||
* Create tests database | ||
do MakeTestDatabase with TESTS | ||
|
||
* Add test data into tests database. Each test case stub should be altered | ||
* to follow this format: | ||
* | ||
* do AddTestDatabase with TESTS, "say Hi!", "==", "Hello, World!", "HelloWorld()" | ||
* do AddTestDatabase with TESTS, "add 5 and 3", "==", "8", "Add_5_And_3(5, 3)" | ||
* | ||
* Note: | ||
* 1st field is the test description (already supplied) | ||
* 2nd field is comparator operator, usually "==" | ||
* 3rd field is the function return result, always written as a string | ||
* 4th field is the function (optionally with arguments), always written as a string | ||
* | ||
|
||
* Add test data into tests database | ||
do AddTestDatabase with TESTS, "No name given", "==", "One for you, one for me.", "TwoFer()" | ||
do AddTestDatabase with TESTS, "A name given", "==", "One for Alice, one for me.", "TwoFer('Alice')" | ||
do AddTestDatabase with TESTS, "Another name given", "==", "One for Bob, one for me.", "TwoFer('Bob')" | ||
do AddTestDatabase with TESTS, "Handle arg with spaces", "==", "One for John Smith, one for me.", "TwoFer('John Smith')" | ||
do AddTestDatabase with TESTS, "Name as empty string", "==", "One for you, one for me.", "TwoFer('')" | ||
|
||
|
||
* Execute unit tests. Arguments: | ||
* - Tests database name | ||
* - Database retention flag (.T. to not delete test database on test end) | ||
* - JSON output flag (.T. to emit test results in JSON format [default is TAP]) | ||
SUCCESS := RunTests(TESTS, SToBool(hb_PValue(2)), SToBool(hb_PValue(3))) | ||
|
||
* Return success status to OS | ||
ERRORLEVEL(IIF(SUCCESS, 0, 1)) | ||
|
||
* Code under test (CUT) | ||
#include "two_fer.prg" | ||
|
||
* Unit Test Framework | ||
#include "PRGUNIT.prg" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
* ---------------------------------------------------------------------------- | ||
* Harbour Miscellaneous Utilities | ||
* Anthony J. Borla ([email protected]) | ||
* ---------------------------------------------------------------------------- | ||
|
||
#define UTILS_PRG | ||
|
||
* | ||
* Given a string, charSet, interpreted as a set of individual characters, | ||
* and a string, string, returns a copy of string with all occurrences of | ||
* the characters in charSet, removed. | ||
* | ||
function RemoveCharSet(charSet, string) | ||
local i, clen := LEN(charSet) | ||
for i := 1 to clen | ||
string := STRTRAN(string, SUBSTR(charSet, i, 1)) | ||
next | ||
return string | ||
|
||
* | ||
* Given a string, and a separator string (usually a single character) | ||
* returns an array of separator-split tokens, or the original string | ||
* if separation not possible. | ||
* | ||
function SToArr(string, separator) | ||
local array := {}, i, element | ||
|
||
* Return untouched string if no separator, or it is not in string | ||
if PCOUNT() < 2 .OR. separator == NIL ; return string ; endif | ||
i := AT(separator, string) ; if i == 0 ; return string ; endif | ||
|
||
* Parse the string, extracting each element, and adding to array | ||
do while i <> 0 | ||
element := LEFT(string, i - 1) | ||
if !EMPTY(element) ; AADD(array, element) ; endif | ||
string := SUBSTR(string, i + 1) | ||
i := AT(separator, string) | ||
enddo | ||
|
||
* Handle last element, and return array | ||
if !EMPTY(string) ; AADD(array, string) ; endif | ||
return array | ||
|
||
* | ||
* Given an array whose elements are non-aggregate types, returns a | ||
* string of those elements separated by separator. If a string | ||
* cannot be built, an empty string is returned. | ||
* | ||
function ArrToS(array, separator) | ||
local i, element, string := "", arrlen := LEN(array) | ||
if PCOUNT() < 2 .OR. separator == NIL ; separator := "" ; endif | ||
if arrlen < 1 ; return "" ; endif | ||
for i := 1 to arrlen | ||
element := IIF(VALTYPE(array[i]) <> "C", ALLTRIM(STR(array[i])), array[i]) | ||
string += element + separator | ||
next | ||
return ; | ||
IIF(EMPTY(separator), string, SUBSTR(string, 1, RAT(separator, string) - 1)) | ||
|
||
* | ||
* Given a string, returns the Boolean status indicating whether | ||
* it is convertible to an integer. Non-numeric and floating | ||
* point values will both return .F. | ||
* | ||
function IsINTString(s) | ||
local slen, i | ||
if PCOUNT() <> 1 .OR. VALTYPE(s) <> "C" ; return .F. ; endif | ||
slen := LEN(s) | ||
if AT(".", s) <> 0 .OR. slen < 1 ; return .F. ; endif | ||
if VAL(s) <> 0 ; return .T. ; endif | ||
for i := 1 to slen | ||
if !(SUBSTR(s, i, 1) $ "0123456789") ; return .F. ; endif | ||
next | ||
return .T. | ||
|
||
* | ||
* Given a string, returns the Boolean value represented. | ||
* | ||
function SToBool(s) | ||
return ; | ||
IIF(VALTYPE(s) <> "C", NIL, ; | ||
IIF(UPPER(s) == ".T.", .T., ; | ||
IIF(UPPER(s) == ".F.", .F., ; | ||
IIF(SUBSTR(s, 1, 1) $ 'Tt', .T., ; | ||
IIF(SUBSTR(s, 1, 1) $ 'Ff', .F., NIL))))) | ||
|