LxLeChat / FlowChartCore

PowerShell Module Written in C# to create DOT graphs from PS Scripts
MIT License
18 stars 3 forks source link

Write tests ... #13

Open LxLeChat opened 3 years ago

LxLeChat commented 3 years ago

C# tests PS Tests

LaurentDardenne commented 3 years ago

J'ai regardé comment créer des tests de dev rapido en ne spécifiant que des déclarations d'instructions , un aperçu avec Pester 5.0.4: image

La déclaration :

$Break4=New-CodeUseCase 'Break ElseIF without Break' @'
    $grade = 92
    if ($grade -ge 90) { "Grade A"}
    elseif ($grade -ge 80) { "Grade B"} 
'@

Le code Pester à proprement parler :

Describe "FlowChartCode " {

  Context "When there is no violation" {

        #On cherche à savoir si un type de construction est géré ou pas.
       It "<Name>." -TestCases $CodeUseCases {
        param($Name,$Code)         

        {
           $sb=[scriptblock]::Create($Code)
           Test-Statement @Parameters -FileName $Name -ScriptBlock $SB 
        } | Should -Not -Throw
      }
   }
}

Ceci serait dupliqué dans chaque répertoire (exemple : \Tests\Dev), un pour Break (\Tests\Dev\Break), un pour If etc Seule la déclaration du nom de variable serait différente :

$IF1=New-CodeUseCase 'IF ElseIF without Break' @'
    $grade = 92
    if ($grade -ge 90) { "Grade A"}
    elseif ($grade -ge 80) { "Grade B"} 
'@

Ensuite on recherche les déclarations 'normées' et on génère le tableau de hashtable en tant que jeu de test :

$CodeUseCases=@(
    Foreach ($Number in 1..$NumberOfUseCase) 
    { 
        #todo SI la variable existe
        $Value=(Get-Variable "IF$Number").Value #Ou IF ou Catch etc
        $value|ConvertTo-Hashtable
    }
)

Je continue de regarder ce point afin de m'assurer que ce n'est pas une bonne mauvaise idée. Ceci ne remplacera pas les tests fonctionels

LxLeChat commented 3 years ago

humm j'ai un peu de retard sur pester ... pas encore regarder comment fonctionnait le nouveau module depuis le breaking change de la 5.0 du coup new-codeusecase ca me parle pas, mais ça à l air assez parlant comme ça :)

LaurentDardenne commented 3 years ago

pas encore regarder comment fonctionnait le nouveau module depuis le breaking change de la 5.0

Le recherche du code perso dans un test a changé (rapido BeforeAll pour le partage de code), la syntaxe des assertions not be en -not -be et le formatage de sortie par défaut et d'autres trucs. Mais pour un usage basique tu passes un peu de temps à retrouver tes marques... Je crois qu'il une fonction d'aide à la conversion.

du coup new-codeusecase ca me parle pas, mais ça à l air assez parlant comme ça :)

A l'origine je voulais essayer qq chose comme ça, en ayant à l'esprit la progression du code :

$Break1=New-CodeUseCase 'Break absent' @'
    $grade = 92
'@

$Break2=New-CodeUseCase 'Break IF without Break' @'
    $Break1
    if ($grade -ge 90) { "Grade A"}
'@

$Break3=New-CodeUseCase 'Break IFElse without Break' @'
    $Break2
    Else {"Grade B"}
'@

Mais au bout de 10 cas on a peut de mal à savoir ce que l'on manipule.

Le New-CodeUseCase existe car je n'ai pas réussi à redéfinir la méthode ToString sur une hashtable

$h=@{
    Name='test'
    Code='  if ($grade -ge 90) { "Grade A"}'
   }|
  Add-Member -MemberType ScriptMethod -name ToString { $This.Code} -Force -PassThru
"$h"
#System.Collections.Hashtable
"$($h.tostring())"
#if ($grade -ge 90) { "Grade A"}'

Mais j'ai peut être loupé une marche...

Je vais simplifier en :

Function UseCase{
 #New-PSCustomObjectFunction -Noun CodeUseCase -Parameters Name,Code -file
    param(
         [Parameter(Mandatory=$True,position=0)]
        $Name,
          [Parameter(Mandatory=$True,position=1)]
        $Code
    )
  return $PSBoundParameters
}

$CodeUseCases=@(
 UseCase 'Break IFElse without Break' @'
   $grade = 92
   elseif ($grade -ge 80) { "Grade B"} 
'@
 # UseCase ...
)
LxLeChat commented 3 years ago
$h=@{
    Name='test'
    Code={if($a){"x"}}
   }

non ? du coup h.code et hop ! surement raté klk chose aussi xD

LaurentDardenne commented 3 years ago

Oui tout à fait. Je voulais éviter de saisir à chaque fois le nom des clés...

LaurentDardenne commented 3 years ago

En attendant une PR :

#FlowChartCore init
$ModulePath='C:\Users\Laurent\Downloads\FlowChartCore\Code\bin\Debug\netstandard2.0'

if (-Not (Test-Path Env:GRAPHVIZ_DOT))
{ $Env:GRAPHVIZ_DOT='C:\Tools\Graphviz\bin' }

unblock-File "$ModulePath\DotNetGraph.dll"
unblock-File "$ModulePath\FlowchartCore.dll"
 #first time, close and open PS console
Import-Module "$ModulePath\FlowchartCore.dll"

Function New-CodeUseCase{
#New-PSCustomObjectFunction -Noun CodeUseCase -Parameters Name,Code -file
param(
     [Parameter(Mandatory=$True,position=0)]
    [String] $Name,

     [Parameter(Mandatory=$True,position=1)]
    [ScriptBlock] $Code
)

  @{
    Name=$Name;
    Code=$Code;
   }
}

$CodeUseCases=@(
    #Todo cas sans résultat
#  New-CodeUseCase 'Break absent' {
#     $grade = 92
# }

 New-CodeUseCase 'Break IF without Break' {
   $grade = 92
   if ($grade -ge 90) { "Grade A"}
}

 New-CodeUseCase 'Break IFElse without Break' {
    $grade = 92
    if ($grade -ge 90) { "Grade A"}
    Else {"Grade B"}
}

 New-CodeUseCase 'Break ElseIF without Break' {
    $grade = 92
    if ($grade -ge 90) { "Grade A"}
    elseif ($grade -ge 80) { "Grade B"} 
}

 New-CodeUseCase 'Break at the end of code' {
    $grade = 92
    if ($grade -ge 90) { "Grade A"}
    Break
}

 New-CodeUseCase 'Break inside IF block' {
  $grade = 92
  if ($grade -ge 90) { "Grade A";Break}
}

#todo Token IF
 New-CodeUseCase 'Break IF ElseIF Else' {
    $grade = 92
    if ($grade -ge 90) { "Grade A" }
    elseif ($grade -ge 70)  { "Grade C"}
    else { "Grade D"}
}

#NOK
 New-CodeUseCase 'Break IF ElseIF' {
    $grade = 92
    if ($grade -ge 90) { "Grade A" }
    elseif ($grade -ge 70)  { "Grade C"}
 }

#NOK
 New-CodeUseCase 'Break IF inside For loop' {
    for ($i = 1; ; ++$i)
    {
        if ($i * $i -gt 50)
        {
            Get-ChildItem
        }
    }
}
)

# BeforeAll { 
#     $script:Parameters=@{
#         AsText=$false
#         NoDisplay=$true
#         Strict=$true
#     }
#     #F°
# }

Describe "FlowChartCode " {
    Context "When there is no violation" {
        #On cherche à savoir si un type de construction est géré ou pas.
        #Chacune des ces constructions doit renvoyer un résultat
       It "<Name>." -TestCases $CodeUseCases {
        param($Name,$Code)         
         $script:Result=$script:OutView=$script:OutViewAsText=$null

          #Pas d'exception
         {   [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
           $script:Result=Find-FLowChartNodes -ScriptBlock $Code } | Should -Not -Throw

          #Le résultat doit être renseigné
         $script:Result |Should -Not -BeNullOrEmpty

         {   [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
            $script:OutView=New-FLowChartGraph -Nodes $script:Result} | Should -Not -Throw

        $script:OutView |Should -Not -BeNullOrEmpty
         # Même chose mais avec -CodeAsText
         {   [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
           $script:OutViewAsText=New-FLowChartGraph -Nodes $script:Result -CodeAsText} | Should -Not -Throw

           $script:OutViewAsText|Should -Not -BeNullOrEmpty
      }
   }
}

Il reste des chemins codés en dur à modifier ( avec un module on pourrait s'en affranchir). La gestion de la variable Env:GRAPHVIZDOT est a envisager dans le module (+ un loader ici), ainsi on a une indirection que l'on peut utiliser dans des scripts de démos. Et je dois vérifier si la portée script est la solution pour le partage de code ou si l'ecriture du It_ à changé. Encore une fois ce test est pour le debug (là tout est dans tout).

LxLeChat commented 3 years ago

top!

LxLeChat commented 3 years ago

Par contre pourquoi l'histoire du path de graphviz @LaurentDardenne, je ne vois pas en quoi ça peut nous servir.

il faut la dernière version de pester ? ok j'ai la 3.4 -_- completement en retard !

LxLeChat commented 3 years ago

ok top! je galere avec pester -- impossible d installer la derniere version ... j'ai réussi à virer celle qui vient par defaut la 3.4 mais l'install-module foncitonne, mais le module n'apparait pas -- grummmmmble

LaurentDardenne commented 3 years ago

je galere avec pester

Peut être as-tu + chemins où il est installé, le mode verbose donne qq infos.

Pour l'usage de graphviz :

Write-FUGraph -InputObject $r -ShowGraph
export-PSGraph : Could not find GraphViz installed on this system. Please run 'Install-GraphViz' to install the needed
binaries and libraries. This module just a wrapper around GraphViz and is looking for it in the following paths:
C:\Program Files\NuGet\Packages\Graphviz*\dot.exe or C:\program files*\GraphViz*\bin\dot.exe or /usr/local/bin/dot or
/usr/bin/dot. Optionally pass a path to your dot.exe file with the GraphVizPath parameter
Au caractère C:\Users\Laurent\Downloads\PSFunctionExplorer\PSFunctionExplorer\PSFunctionExplorer.psm1:348 : 26
+                 $graph | export-PSGraph @ExportAttrib

Il existe une dépendance mais pas de contrôle sur son existence/accès

LaurentDardenne commented 3 years ago

Et surtout le module PSGraph fige le chemin d'installation...

LaurentDardenne commented 3 years ago

J'ai supprimé ma réponse sur l'histoire du path, j'ai oublié que les liens pointaient sur le référentiel cité...

LxLeChat commented 3 years ago

oh petard .. j'utilise tellement plus windows powershell sur ma machine ... il fallait en passer par la pour installer le module ... du coup j'ai un fail sur [-] Switch -File 👍 MERCIIIIIIIIII @LaurentDardenne !!! ça défonce tout ça !

du coup faut que je check comment t as fait mais ça à l air top ! jamais écris des tests comme ça !!! very interessant !

LxLeChat commented 3 years ago

par contre je comprends pas le test foire, mais quand je le fais manuellement ça fonctionne .. ! étrange

LaurentDardenne commented 3 years ago

Je regarde ça.

LaurentDardenne commented 3 years ago

Peut être un pb d'encodage de fichier... En ajoutant ceci dans le test cela fonctionne:

   param($Name,$Code)         
        $code=[scriptblock]::Create("$code")

repro:

cd ..\FlowChartCore\Test\dev
$r=. .\Switch.UseCases.ps1
$Result=Find-FLowChartNodes -ScriptBlock ($r[-2].code)
$OutView=New-FLowChartGraph -Nodes $Result -CodeAsText
#New-FLowChartGraph : L'index et la longueur doivent faire référence à un emplacement situé dans la chaîne.
#Nom du paramètre : length

Le référentiel est à jour de ton côté ? Que l'on utilise la même version.

LaurentDardenne commented 3 years ago

Pour retrouver le nœud posant pb:

$Result=Find-FLowChartNodes -ScriptBlock ($r[-2].code)
$result[1].Children|%{write-host "$_";$_}|% {New-FLowChartGraph -Nodes $_ -CodeAsText}
#FlowChartCore.SwitchCaseNode

#New-FLowChartGraph : L'index et la longueur doivent faire référence à un emplacement situé dans la chaîne.
#Nom du paramètre : length

#FlowChartCore.SwitchCaseNode
#digraph "a" {
...

Directement :

New-FLowChartGraph -Nodes $result[1].Children[0] -CodeAsText
LaurentDardenne commented 3 years ago

Vérifie si la classe ContinueNode doit redéclarer la méthode OffSetScriptBlockEnd.

LxLeChat commented 3 years ago

effectivement, il manquait un appel de méthode. j'ai corrigé et poussé

LaurentDardenne commented 3 years ago

et poussé

Dans la branche Dev est-ce à dessein ?

LxLeChat commented 3 years ago

j'ai mergé avec la master

LaurentDardenne commented 3 years ago

Ok, les tests réussissent dorénavant.

LaurentDardenne commented 3 years ago

Il faudrait modifier le nom du fichier sur cette ligne . Il n'était pas dans la branche Dev.

Et pour rappel ce fichier ne contient pas de tests fonctionnel. Il devrait plutôt être configuré ainsi :

Invoke-Pester -Path .\Test -Output Detailed -ExcludeTagFilter 'DevUseCases'

Et si tu veux le laisser, dans ce cas renommer le tag en 'UseCases' et simplifier :

Invoke-Pester -Path .\Test -Output Detailed 
LaurentDardenne commented 3 years ago

C# tests

Au cas où j'ai trouvé ceci :