1- // ----------------------------------------------------------------------------------
1+ // ----------------------------------------------------------------------------------
22//
33// Copyright Microsoft Corporation
44// Licensed under the Apache License, Version 2.0 (the "License");
1313// ----------------------------------------------------------------------------------
1414
1515using Microsoft . Azure . PowerShell . Tools . AzPredictor . Test . Mocks ;
16+ using System ;
17+ using System . Collections . Generic ;
1618using System . Linq ;
19+ using System . Management . Automation . Language ;
1720using System . Management . Automation . Subsystem ;
1821using System . Threading ;
1922using Xunit ;
@@ -26,10 +29,36 @@ namespace Microsoft.Azure.PowerShell.Tools.AzPredictor.Test
2629 [ Collection ( "Model collection" ) ]
2730 public class AzPredictorServiceTests
2831 {
32+ private class PredictiveSuggestionComparer : EqualityComparer < PredictiveSuggestion >
33+ {
34+ public override bool Equals ( PredictiveSuggestion first , PredictiveSuggestion second )
35+ {
36+ if ( ( first == null ) && ( second == null ) )
37+ {
38+ return true ;
39+ }
40+ else if ( ( first == null ) || ( second == null ) )
41+ {
42+ return false ;
43+ }
44+
45+ return string . Equals ( first . SuggestionText , second . SuggestionText , StringComparison . Ordinal ) ;
46+ }
47+
48+ public override int GetHashCode ( PredictiveSuggestion suggestion )
49+ {
50+ return suggestion . SuggestionText . GetHashCode ( ) ;
51+ }
52+ }
53+
2954 private readonly ModelFixture _fixture ;
3055 private readonly AzPredictorService _service ;
31- private readonly Predictor _suggestionsPredictor ;
32- private readonly Predictor _commandsPredictor ;
56+ private readonly CommandLinePredictor _commandBasedPredictor ;
57+ private readonly CommandLinePredictor _fallbackPredictor ;
58+
59+ private readonly AzPredictorService _noFallbackPredictorService ;
60+ private readonly AzPredictorService _noCommandBasedPredictorService ;
61+ private readonly AzPredictorService _noPredictorService ;
3362
3463 /// <summary>
3564 /// Constructs a new instance of <see cref="AzPredictorServiceTests"/>
@@ -39,15 +68,36 @@ public AzPredictorServiceTests(ModelFixture fixture)
3968 {
4069 this . _fixture = fixture ;
4170 var startHistory = $ "{ AzPredictorConstants . CommandPlaceholder } { AzPredictorConstants . CommandConcatenator } { AzPredictorConstants . CommandPlaceholder } ";
42- this . _suggestionsPredictor = new Predictor ( this . _fixture . PredictionCollection [ startHistory ] , null ) ;
43- this . _commandsPredictor = new Predictor ( this . _fixture . CommandCollection , null ) ;
71+ this . _commandBasedPredictor = new CommandLinePredictor ( this . _fixture . PredictionCollection [ startHistory ] , null ) ;
72+ this . _fallbackPredictor = new CommandLinePredictor ( this . _fixture . CommandCollection , null ) ;
4473
4574 this . _service = new MockAzPredictorService ( startHistory , this . _fixture . PredictionCollection [ startHistory ] , this . _fixture . CommandCollection ) ;
75+
76+ this . _noFallbackPredictorService = new MockAzPredictorService ( startHistory , this . _fixture . PredictionCollection [ startHistory ] , null ) ;
77+ this . _noCommandBasedPredictorService = new MockAzPredictorService ( null , null , this . _fixture . CommandCollection ) ;
78+ this . _noPredictorService = new MockAzPredictorService ( null , null , null ) ;
4679 }
4780
81+ /// <summary>
82+ /// Verify the method checks parameter values.
83+ /// </summary>
84+ [ Fact ]
85+ public void VerifyParameterValues ( )
86+ {
87+ var predictionContext = PredictionContext . Create ( "Get-AzContext" ) ;
88+
89+ Action actual = ( ) => this . _service . GetSuggestion ( null , 1 , 1 , CancellationToken . None ) ;
90+ Assert . Throws < ArgumentNullException > ( actual ) ;
91+
92+ actual = ( ) => this . _service . GetSuggestion ( predictionContext . InputAst , 0 , 1 , CancellationToken . None ) ;
93+ Assert . Throws < ArgumentOutOfRangeException > ( actual ) ;
94+
95+ actual = ( ) => this . _service . GetSuggestion ( predictionContext . InputAst , 1 , 0 , CancellationToken . None ) ;
96+ Assert . Throws < ArgumentOutOfRangeException > ( actual ) ;
97+ }
4898
4999 /// <summary>
50- /// Verifies that the prediction comes from the suggestions list, not the command list.
100+ /// Verifies that the prediction comes from the command based list, not the fallback list.
51101 /// </summary>
52102 [ Theory ]
53103 [ InlineData ( "CONNECT-AZACCOUNT" ) ]
@@ -59,52 +109,126 @@ public AzPredictorServiceTests(ModelFixture fixture)
59109 [ InlineData ( "new-azresourcegroup -name hello" ) ]
60110 [ InlineData ( "Get-AzContext -Name" ) ]
61111 [ InlineData ( "Get-AzContext -ErrorAction" ) ]
62- public void VerifyUsingSuggestion ( string userInput )
112+ public void VerifyUsingCommandBasedPredictor ( string userInput )
63113 {
64114 var predictionContext = PredictionContext . Create ( userInput ) ;
65- var presentCommands = new System . Collections . Generic . Dictionary < string , int > ( ) ;
66- var expected = this . _suggestionsPredictor . Query ( predictionContext . InputAst , presentCommands , 1 , 1 , CancellationToken . None ) ;
115+ var commandAst = predictionContext . InputAst . FindAll ( p => p is CommandAst , true ) . LastOrDefault ( ) as CommandAst ;
116+ var commandName = ( commandAst ? . CommandElements ? . FirstOrDefault ( ) as StringConstantExpressionAst ) ? . Value ;
117+ var inputParameterSet = new ParameterSet ( commandAst ) ;
118+ var rawUserInput = predictionContext . InputAst . Extent . Text ;
119+ var presentCommands = new Dictionary < string , int > ( ) ;
120+ var expected = this . _commandBasedPredictor . GetSuggestion ( commandName ,
121+ inputParameterSet ,
122+ rawUserInput ,
123+ presentCommands ,
124+ 1 ,
125+ 1 ,
126+ CancellationToken . None ) ;
127+
67128 var actual = this . _service . GetSuggestion ( predictionContext . InputAst , 1 , 1 , CancellationToken . None ) ;
68- Assert . NotEmpty ( actual ) ;
69- Assert . NotNull ( actual . First ( ) . Item1 ) ;
70- Assert . Equal ( expected . Item1 . First ( ) . Key , actual . First ( ) . Item1 ) ;
71- Assert . Equal ( PredictionSource . CurrentCommand , actual . First ( ) . Item3 ) ;
129+ Assert . NotNull ( actual ) ;
130+ Assert . True ( actual . Count > 0 ) ;
131+ Assert . NotNull ( actual . PredictiveSuggestions . First ( ) ) ;
132+ Assert . NotNull ( actual . PredictiveSuggestions . First ( ) . SuggestionText ) ;
133+ Assert . Equal ( expected . Count , actual . Count ) ;
134+ Assert . Equal < PredictiveSuggestion > ( expected . PredictiveSuggestions , actual . PredictiveSuggestions , new PredictiveSuggestionComparer ( ) ) ;
135+ Assert . Equal < string > ( expected . SourceTexts , actual . SourceTexts ) ;
136+ Assert . All < SuggestionSource > ( actual . SuggestionSources , ( source ) => Assert . Equal ( SuggestionSource . CurrentCommand , source ) ) ;
137+
138+ actual = this . _noFallbackPredictorService . GetSuggestion ( predictionContext . InputAst , 1 , 1 , CancellationToken . None ) ;
139+ Assert . NotNull ( actual ) ;
140+ Assert . True ( actual . Count > 0 ) ;
141+ Assert . NotNull ( actual . PredictiveSuggestions . First ( ) ) ;
142+ Assert . NotNull ( actual . PredictiveSuggestions . First ( ) . SuggestionText ) ;
143+ Assert . Equal ( expected . Count , actual . Count ) ;
144+ Assert . Equal < PredictiveSuggestion > ( expected . PredictiveSuggestions , actual . PredictiveSuggestions , new PredictiveSuggestionComparer ( ) ) ;
145+ Assert . Equal < string > ( expected . SourceTexts , actual . SourceTexts ) ;
146+ Assert . All < SuggestionSource > ( actual . SuggestionSources , ( source ) => Assert . Equal ( SuggestionSource . CurrentCommand , source ) ) ;
72147 }
73148
74149 /// <summary>
75- /// Verifies that when no prediction is in the suggestion list, we'll use the command list.
150+ /// Verifies that when no prediction is in the command based list, we'll use the fallback list.
76151 /// </summary>
77152 [ Theory ]
78153 [ InlineData ( "Get-AzResource -Name hello -Pre" ) ]
79154 [ InlineData ( "Get-AzADServicePrincipal -ApplicationObject" ) ]
80- public void VerifyUsingCommand ( string userInput )
155+ public void VerifyUsingFallbackPredictor ( string userInput )
81156 {
82157 var predictionContext = PredictionContext . Create ( userInput ) ;
83- var presentCommands = new System . Collections . Generic . Dictionary < string , int > ( ) ;
84- var expected = this . _commandsPredictor . Query ( predictionContext . InputAst , presentCommands , 1 , 1 , CancellationToken . None ) ;
158+ var commandAst = predictionContext . InputAst . FindAll ( p => p is CommandAst , true ) . LastOrDefault ( ) as CommandAst ;
159+ var commandName = ( commandAst ? . CommandElements ? . FirstOrDefault ( ) as StringConstantExpressionAst ) ? . Value ;
160+ var inputParameterSet = new ParameterSet ( commandAst ) ;
161+ var rawUserInput = predictionContext . InputAst . Extent . Text ;
162+ var presentCommands = new Dictionary < string , int > ( ) ;
163+ var expected = this . _fallbackPredictor . GetSuggestion ( commandName ,
164+ inputParameterSet ,
165+ rawUserInput ,
166+ presentCommands ,
167+ 1 ,
168+ 1 ,
169+ CancellationToken . None ) ;
170+
85171 var actual = this . _service . GetSuggestion ( predictionContext . InputAst , 1 , 1 , CancellationToken . None ) ;
86- Assert . NotEmpty ( actual ) ;
87- Assert . NotNull ( actual . First ( ) . Item1 ) ;
88- Assert . Equal ( expected . Item1 . First ( ) . Key , actual . First ( ) . Item1 ) ;
89- Assert . Equal ( PredictionSource . StaticCommands , actual . First ( ) . Item3 ) ;
172+ Assert . NotNull ( actual ) ;
173+ Assert . True ( actual . Count > 0 ) ;
174+ Assert . NotNull ( actual . PredictiveSuggestions . First ( ) ) ;
175+ Assert . NotNull ( actual . PredictiveSuggestions . First ( ) . SuggestionText ) ;
176+ Assert . Equal ( expected . Count , actual . Count ) ;
177+ Assert . Equal < PredictiveSuggestion > ( expected . PredictiveSuggestions , actual . PredictiveSuggestions , new PredictiveSuggestionComparer ( ) ) ;
178+ Assert . Equal < string > ( expected . SourceTexts , actual . SourceTexts ) ;
179+ Assert . All < SuggestionSource > ( actual . SuggestionSources , ( source ) => Assert . Equal ( SuggestionSource . StaticCommands , source ) ) ;
180+
181+ actual = this . _noCommandBasedPredictorService . GetSuggestion ( predictionContext . InputAst , 1 , 1 , CancellationToken . None ) ;
182+ Assert . NotNull ( actual ) ;
183+ Assert . True ( actual . Count > 0 ) ;
184+ Assert . NotNull ( actual . PredictiveSuggestions . First ( ) ) ;
185+ Assert . NotNull ( actual . PredictiveSuggestions . First ( ) . SuggestionText ) ;
186+ Assert . Equal ( expected . Count , actual . Count ) ;
187+ Assert . Equal < PredictiveSuggestion > ( expected . PredictiveSuggestions , actual . PredictiveSuggestions , new PredictiveSuggestionComparer ( ) ) ;
188+ Assert . Equal < string > ( expected . SourceTexts , actual . SourceTexts ) ;
189+ Assert . All < SuggestionSource > ( actual . SuggestionSources , ( source ) => Assert . Equal ( SuggestionSource . StaticCommands , source ) ) ;
90190 }
91191
92192 /// <summary>
93- /// Verify that no prediction for the user input, meaning it's not in the prediction list or the command list.
193+ /// Verify that no prediction for the user input, meaning it's not in the command based list or the fallback list.
94194 /// </summary>
95195 [ Theory ]
96196 [ InlineData ( AzPredictorConstants . CommandPlaceholder ) ]
97- [ InlineData ( "git status" ) ]
98197 [ InlineData ( "Get-ChildItem" ) ]
99198 [ InlineData ( "new-azresourcegroup -NoExistingParam" ) ]
100199 [ InlineData ( "get-azaccount " ) ]
101- [ InlineData ( "Get-AzContext Name" ) ]
102200 [ InlineData ( "NEW-AZCONTEXT" ) ]
103201 public void VerifyNoPrediction ( string userInput )
104202 {
105203 var predictionContext = PredictionContext . Create ( userInput ) ;
106204 var actual = this . _service . GetSuggestion ( predictionContext . InputAst , 1 , 1 , CancellationToken . None ) ;
107- Assert . Empty ( actual ) ;
205+ Assert . Equal ( 0 , actual . Count ) ;
206+
207+ actual = this . _noFallbackPredictorService . GetSuggestion ( predictionContext . InputAst , 1 , 1 , CancellationToken . None ) ;
208+ Assert . Equal ( 0 , actual . Count ) ;
209+
210+ actual = this . _noCommandBasedPredictorService . GetSuggestion ( predictionContext . InputAst , 1 , 1 , CancellationToken . None ) ;
211+ Assert . Equal ( 0 , actual . Count ) ;
212+
213+ actual = this . _noPredictorService . GetSuggestion ( predictionContext . InputAst , 1 , 1 , CancellationToken . None ) ;
214+ Assert . Null ( actual ) ;
215+ }
216+
217+ /// <summary>
218+ /// Verify when we cannot parse the user input correctly.
219+ /// </summary>
220+ /// <remarks>
221+ /// When we can parse them correctly, please move the InlineData to the corresponding test methods, for example, "git status"
222+ /// doesn't have any prediction so it should move to <see cref="VerifyNoPrediction"/>.
223+ /// </remarks>
224+ [ Theory ]
225+ [ InlineData ( "git status" ) ]
226+ [ InlineData ( "Get-AzContext Name" ) ]
227+ public void VerifyMalFormattedCommandLine ( string userInput )
228+ {
229+ var predictionContext = PredictionContext . Create ( userInput ) ;
230+ Action actual = ( ) => this . _service . GetSuggestion ( predictionContext . InputAst , 1 , 1 , CancellationToken . None ) ;
231+ _ = Assert . Throws < InvalidOperationException > ( actual ) ;
108232 }
109233 }
110234}
0 commit comments