Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Mohammad Hamdy Ghanem
@VBAndCs
I have another unit tests to test critical parts:

    <TestMethod>
    Public Sub WriteNameValue()
        Dim code = <![CDATA[(Name ="", Value = 0.0)]]>.Value

        Dim expected = <![CDATA[   <Key>
   <DefaultValue("1= #1/1/0001#")>
   Public Shadows Property [Date] As Date

   <Key>
   <DefaultValue("1=__QUOTE____QUOTE__")>
   Public Property [Name] As String

   <Key>
   <DefaultValue("1= 0.0")>
   Public Property [Value] As Double


]]>.Value

        Dim properties As New List(Of PropertyInfo)
        Dim result = WriteProperties(code, properties, "Inherits Test").Replace(vbCrLf, vbLf)
        Assert.AreEqual(result, expected)


        expected = <![CDATA[    Public Sub New(
                Optional [date] As Date = #1/1/0001#,
                Optional [name] As String ="",
                Optional [value] As Double = 0.0
            )

        Me.Date = [date]
        Me.Name = [name]
        Me.Value = [value]
    End Sub

]]>.Value

        Dim sb As New StringBuilder
        RecordParser.WriteConstructor(properties, sb)
        result = sb.Replace(vbCrLf, vbLf).ToString()
        Assert.AreEqual(result, expected)


        expected = <![CDATA[    Public Function [With](
                Optional [date] As Date? = Nothing,
                Optional [name] As [Optional](Of String) = Nothing,
                Optional [value] As Double? = Nothing
            ) As NameValue

        Return  New NameValue(
            If ([date].HasValue, [date].Value, Me.Date),
            If ([name].HasValue, [name].Value, Me.Name),
            If ([value].HasValue, [value].Value, Me.Value)
        )
    End Function

]]>.Value
        sb.Clear()
        RecordParser.WriteWith("NameValue", "", properties, sb)
        result = sb.Replace(vbCrLf, vbLf).ToString()
        Assert.AreEqual(result, expected)

    End Sub
CyrusNajmabadi
@CyrusNajmabadi
none of that addresses teh point i made about your test :)
if it fails. it's not actionable.
Mohammad Hamdy Ghanem
@VBAndCs
@Clockwork-Muse Any change in the generator that changes the output, will need to change all the tests expected values, using hashing or plain strings.
CyrusNajmabadi
@CyrusNajmabadi
Any change in the generator that changes the output, will need to change all the tests expected values
taht's not necessarily true
it will be true if you're doing an exact check of contents (which is up to you)
you could, for example, do a whitespace-insensitive check, if you want your tests to effectively say: i don't care if whitespace changes
the hashing approach is somewhat the worst of all worlds
Stephen A. Imhoff
@Clockwork-Muse

you could, for example, do a whitespace-insensitive check, if you want your tests to effectively say: i don't care if whitespace changes

Right, this

CyrusNajmabadi
@CyrusNajmabadi
it always changes whenever the output cahnges (no matter how slight). but it gives the least amoutn of information about what changed.
it soundsl ike you want hte opposite. you want slight changes in your output to to not cause assertion failures.
Stephen A. Imhoff
@Clockwork-Muse
Which is why I brought up the point about syntax tree checking, because often for generators you don't care what it looks like.
Mohammad Hamdy Ghanem
@VBAndCs

if it fails. it's not actionable.

If NameValue integral test fails, I will run WriteNameValue and see what is going on.

CyrusNajmabadi
@CyrusNajmabadi
I will run WriteNameValue and see what is going on.
why don't you just always run this then :)
they're tests :)
Mohammad Hamdy Ghanem
@VBAndCs
In fact I need these tests as a debugging entry points rather than tests.
CyrusNajmabadi
@CyrusNajmabadi
just have each test call your 'invariant checking test helper'
if you already have a test helper which can tell you precisely what is different... then that's what your tests should use. you shouldn't need a manual step fo going "oh, the hash changed, let me manually run this helper to find out why"
the tests can all run without manual intervention
Mohammad Hamdy Ghanem
@VBAndCs
I ran them all after every change. I will debug into some of them to see why things fail.
CyrusNajmabadi
@CyrusNajmabadi
...
i mean, you're proving the point :)
Mohammad Hamdy Ghanem
@VBAndCs
This helps me while updating the generator.
CyrusNajmabadi
@CyrusNajmabadi
you're picking a lossy testing strategy that requires you to have to debug in to figure out what went wrong when it fails.
let's step back.
i get yoru goal here. you want to be able to updat ethe generator, but not have to deal with lots of fallout when somethign changes
however the hashing approach does not provide that. indeed, it's worse. because any slight changes in input produces a new hash.
Mohammad Hamdy Ghanem
@VBAndCs
yes
CyrusNajmabadi
@CyrusNajmabadi
so... it doesn't meet that goal. and it actually costs you more because you can't do anything with the assertion failure. you have to then go in and debug it all and try to figure out if you have a bug, or if you need to update the test.
so. to meet your goal, what would be better would be to send your code not through a hashing step, but through a normalization step.
where your 'normalization' ensures that two strings with cosmetic differences (as defined by you) are treated the same
Mohammad Hamdy Ghanem
@VBAndCs
I can watch the output while debugging. See no issue here. This is much faster that parsing the syntax tree of the output and write long code to check nodes.
CyrusNajmabadi
@CyrusNajmabadi
then, if you update your generator, and you only make a cosmetic difference, your test doesn't fail.
My point is... if you do this, you don't need to watch anything in teh first place :)
your tests either pass, and everything is good. or they fail, and you know why.
This is much faster
in one case you hae to do work. in the other, the test harness does the work (likely in <1ms or 1mu-s per test) :)
Stephen A. Imhoff
@Clockwork-Muse

I can watch the output while debugging.

This is antithetical to good testing output. Your test report should clearly say "this specific thing is unexpected". For one thing, this enables compile/test runs on targets you can't interactively debug (for example, you can legally only develop code for a Mac on a Mac - I don't want to buy one if I can help it, so github actions for me)

Mohammad Hamdy Ghanem
@VBAndCs
I use tests as a helper tool not a goal. It did helped like this in this project. If I ran into troubles I will modify them as needed. Thanks.
CyrusNajmabadi
@CyrusNajmabadi
I use tests as a helper tool not a goal
Sure. the general point here is that there are more effective ways to use them (in terms of spending less time to get more value out of htem).
You're welcome to test however you want. You're just likely going to get feedback from a lot of people that you're spinning your wheels a lot :)
Mohammad Hamdy Ghanem
@VBAndCs
Think of the checksum as a bonus. I need to run the whole generator and make sure it doesn't throw. The test can end here, but I added a checksum to make sure that the output file is ok. There are other tests focusing on the important parts of the generated code (the property definition, the constructor, and the With method). It is a good idea to ignore white-spaces in comparison, but this will need time and will give me nothing write now. May be I can do it in new tests to come. Thanks.
CyrusNajmabadi
@CyrusNajmabadi
up to you :)
Paul M Cohen
@paul1956
@VBAndCs I never depend on line ending, I use several functions that deal with the various line ending in a language/encoding independent way. Look here https://github.com/paul1956/CSharpToVB/blob/master/CodeConverter/Utilities/UnicodeNewline.vb
Mohammad Hamdy Ghanem
@VBAndCs
Nice, but I am not parsing here. I am just normalizing. I can include white spaces in normalization like this:
Public Function Normalize(str As String) As String
    Dim sb As New StringBuilder(str)

    ' Normalize tab and line terminator
    sb.Replace(vbTab, " ")
    sb.Replace(vbCr, vbLf)

    ' Remove duplicate spaces
    DeleteDuplicates(" ", sb)

    ' Trim each line
    sb.Replace(vbLf & " ", vbLf)
    sb.Replace(" " & vbLf, vbLf)

    ' Remove duplicate lines
    DeleteDuplicates(vbLf, sb)

    ' Trim the string
    If sb(0) = " " OrElse sb(0) = vbLf Then sb.Remove(0, 1)
    Dim en = sb.Length - 1
    If sb(en) = " " OrElse sb(en) = vbLf Then sb.Remove(en, 1)

    Return sb.ToString()
End Function
Sub DeleteDuplicates(str As String, fromStr As StringBuilder)
    Dim L As Integer
    Dim dupStr = str & str
    Do
        L = fromStr.Length
        fromStr.Replace(dupStr, str)
        If L = fromStr.Length Then Return
    Loop
End Sub