1
\$\begingroup\$

My idea is to make some testing system for functions, as per the model of CodeForces or TopCoder, but in VBA. There, the users write functions for a problem and the problems are tested vs. predefined tests.

In my case, it will be exactly the same, but the tests would be written on Notepad files.

Long story short, you have to write the function and then the function would be feeded with input parameters from one textfile and the result would be compared with the result from another test file.

The idea of the functions, is that they would be written by a "competitor", as in the aforementioned sites. The functions would be the answer of a predefined problem.

So, let's say that we have defined a problem, which is solvable through this:

If c Mod 2 = 0 Then
 MainTest = a + b + c
Else
 MainTest = a + b - c
End If

Thus, we need to write 2 notepad files in advance, which consist of the input parameters for a, b and c and the results. These are the notepad files:

2 2 2
2 2
2 2 3
4 54 1
2 2
54 23 6
45 45 10

File with results:

6
1
1
58
100
121
100

To make it more presentable, the file with the results, has some runtime errors and wrong calculation errors. Thus this is the result in the immediate window:

Test 1............................................ ok!
Runtime error on 2!
Test 3............................................ ok!
Error on test 4! Expected -> 57 Received -> 58
Runtime error on 5!
Error on test 6! Expected -> 83 Received -> 121
Test 7............................................ ok!

Another possible predefined problem may sound like - "Give me the next character of a string.". Thus "a b c d" would result to "b c d e" and "a z" would be "b a".

And this is the whole competitive testing system:

Option Explicit
Public Sub Main()
 Dim totalTests As Long
 Dim pathInputTests As String
 Dim pathOutputTests As String
 Dim inputTests As Variant
 Dim outputTests As Variant
 Dim cntTests As Long
 Dim cnt As Long
 pathInputTests = "C:\Desktop\Test001.txt"
 pathOutputTests = "C:\Desktop\Result001.txt"
 inputTests = Split(ReadFileLineByLineToString(pathInputTests), vbCrLf)
 outputTests = Split(ReadFileLineByLineToString(pathOutputTests), vbCrLf)
 For cnt = LBound(inputTests) To UBound(inputTests)
 Dim expectedValue As Variant
 Dim receivedValue As Variant
 On Error Resume Next
 expectedValue = MainTest(inputTests(cnt))
 receivedValue = outputTests(cnt)
 If Err.Number <> 0 Then
 Debug.Print runtimeError(cnt)
 Err.Clear
 Else
 If expectedValue = receivedValue Then
 Debug.Print positiveResult(cnt)
 Else
 Debug.Print negativeResult(cnt, expectedValue, receivedValue)
 End If
 End If
 Next cnt
End Sub
Public Function runtimeError(ByVal cnt As Long) As String
 cnt = cnt + 1
 runtimeError = "Runtime error on " & cnt & "!"
End Function
Public Function positiveResult(ByVal cnt As Long) As String
 cnt = cnt + 1
 positiveResult = "Test " & cnt & "..................................... ok!"
End Function
Public Function negativeResult(ByVal cnt As Long, expected As Variant, _
 received As Variant) As String
 cnt = cnt + 1
 negativeResult = "Error on test " & cnt & "!" & _
 " Expected -> " & vbTab & expected & vbTab & _
 " Received -> " & vbTab & received
End Function
'---------------------------------------------------------------------------------------
' Method : MainTest
' Purpose: This is where the competitors paste their solution.
'---------------------------------------------------------------------------------------
Public Function MainTest(ByVal consoleInput As String) As String
 Dim a As Double
 Dim b As Double
 Dim c As Double
 a = Split(consoleInput)(0)
 b = Split(consoleInput)(1)
 c = Split(consoleInput)(2)
 If c Mod 2 = 0 Then
 MainTest = a + b + c
 Else
 MainTest = a + b - c
 End If
End Function
Public Function ReadFileLineByLineToString(path As String) As String
 Dim fileNo As Long
 fileNo = FreeFile
 Open path For Input As #fileNo
 Do While Not EOF(fileNo)
 Dim textRowInput As String
 Line Input #fileNo, textRowInput
 ReadFileLineByLineToString = ReadFileLineByLineToString & textRowInput
 If Not EOF(fileNo) Then
 ReadFileLineByLineToString = ReadFileLineByLineToString & vbCrLf
 End If
 Loop
 Close #fileNo
End Function

The code with the 4 test files is in GitHub here - https://github.com/Vitosh/VBA_personal/tree/master/AlgorithmsWithVBA - feel free to make push requests if you feel like it! :)

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Feb 2, 2018 at 16:00
\$\endgroup\$
3
  • \$\begingroup\$ Please see What to do when someone answers . I have rolled back Rev 4 → 3. \$\endgroup\$ Commented Feb 5, 2018 at 21:42
  • \$\begingroup\$ @200_success - why did you rolled back? The edit was improving the understanding of the question or I have missed something? \$\endgroup\$ Commented Feb 5, 2018 at 21:44
  • \$\begingroup\$ We don't allow the code to be modified once an answer has been posted. \$\endgroup\$ Commented Feb 5, 2018 at 22:10

1 Answer 1

1
\$\begingroup\$

You have split your input code across multiple functions - whereas you should encapsulate your input function to provide a single valid output. The easiest way to explain this is to look at the MainTest Function

  • The input is a single string
  • The MainTest function then has to parse that string
  • There is no error checking to see if the string or the parsing is valid

Inputs and Outputs of MainTest should be consistent with what it does. Your examples are Integer/Long but your code uses Double. Happy this is just brevity for code example sake.

  • Your input is string but it does number operations
  • Your output is string, but the answers inside are numbers
  • All conversions are implicit (see note earlier about no error checking)

A neat MainTest would be like (sticking with Double instead of Long)

Public Function MainTest(ByVal a As Double, b as Double, c as Double) As Double

Similarly, you can modify ReadFileLineByLineToString to return the array. You can then just add to the array as you read each line!

Public Function ReadFileLineByLineToString(path As String) As String()

Of course (arrays)

Dim inputTests() As Variant
Dim outputTests() As Variant

Just before you call expectedValue = MainTest(inputTests(cnt)), Split InputTests(cnt) (e.g. Inputs = split(InputTests(cnt), " ") where Inputs is String() and InputNums = validated Double() from Inputs) and check that you have the right number of elements and that they are numbers (basic error checking). You would then call MainTest as

expectedValue = MainTest(InputNums(0), InputNums(1), InputNums(2))

There are many other places in your code where this sort of thinking can be applied. Consider using Option Strict and well as Option Explicit.

answered Feb 2, 2018 at 20:12
\$\endgroup\$
7
  • \$\begingroup\$ Hi, thanks for the feedback. Probably you did not get the idea of the code. Its idea is to be a bit more robust, thus if another task is given it should be applicable. Imagine a task, which sounds as trivial as "Just give me the next letter in the alphabet". Then, when the input is "AB", you should return "BC". This is why I am using Strings here Function MainTest(ByVal consoleInput As String) As String. Furthermore, this is VBA, thus Option Strict does not exist there. \$\endgroup\$ Commented Feb 3, 2018 at 11:37
  • \$\begingroup\$ @Vityata: But you are not doing string manipulation as a MainTest, you are doing arithmetic in this example. Either way, you have to re-write your code base significantly for different operations. My point about using ReadFileLineByLineToString properly still stands. My other points about proper error checking to catch expected errors still stands - you do not have any basic error checking to ensure that your input is correct. For these reasons, your code is not as robust as you think. \$\endgroup\$ Commented Feb 4, 2018 at 4:35
  • \$\begingroup\$ @ThomasInzina: OK, point about Option Strict noted. However, including robust error checking to check inputs is not about "unit tests" - you are not testing anything if the test function itself fails (as opposed to the operation that is being tested). \$\endgroup\$ Commented Feb 4, 2018 at 4:37
  • \$\begingroup\$ @Vityata: Noting that in the OP you mentioned pre-defined tests, of which MainTest is an example. You haven't clarified who writes the function, or where it is implemented. \$\endgroup\$ Commented Feb 4, 2018 at 4:40
  • \$\begingroup\$ That makes sense. \$\endgroup\$ Commented Feb 4, 2018 at 6:33

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.