@@ -19,7 +19,6 @@ import (
1919 "context"
2020 "fmt"
2121 "path/filepath"
22- "slices"
2322 "testing"
2423
2524 "github.com/slackapi/slack-cli/internal/experiment"
@@ -40,7 +39,7 @@ func Test_Config_WithExperimentOn(t *testing.T) {
4039 mockOutput , mockPrintDebug := setupMockPrintDebug ()
4140
4241 // Write our test script to the memory file system used by the mock
43- jsonContents := []byte (fmt .Sprintf ("{ \ " last_update_checked_at\" : \ " 2023-05-11T15:41:07.799619-07:00\" , \ " experiments\" :[ \ " %s\" ]}" , validExperiment ))
42+ jsonContents := []byte (fmt .Sprintf (`{ "last_update_checked_at": "2023-05-11T15:41:07.799619-07:00", "experiments":{ "%s":true}}` , validExperiment ))
4443 _ = afero .WriteFile (fs , pathToConfigJSON , jsonContents , 0600 )
4544
4645 config .LoadExperiments (ctx , mockPrintDebug )
@@ -50,13 +49,34 @@ func Test_Config_WithExperimentOn(t *testing.T) {
5049 fmt .Sprintf ("active system experiments: [%s]" , validExperiment ))
5150 })
5251
52+ t .Run ("Returns a parse error with remediation for old array format in config.json" , func (t * testing.T ) {
53+ // Setup
54+ ctx , fs , _ , config , pathToConfigJSON , teardown := setup (t )
55+ defer teardown (t )
56+ mockOutput , mockPrintDebug := setupMockPrintDebug ()
57+
58+ // Write old array format
59+ jsonContents := []byte (
60+ fmt .Sprintf (
61+ `{"last_update_checked_at":"2023-05-11T15:41:07.799619-07:00","experiments":["%s"]}` ,
62+ validExperiment ,
63+ ),
64+ )
65+ _ = afero .WriteFile (fs , pathToConfigJSON , jsonContents , 0600 )
66+
67+ config .LoadExperiments (ctx , mockPrintDebug )
68+ experimentOn := config .WithExperimentOn (validExperiment )
69+ assert .Equal (t , false , experimentOn )
70+ assert .Contains (t , mockOutput .String (), "failed to parse system-level config file" )
71+ })
72+
5373 t .Run ("Correctly returns false when experiments are not in config.json" , func (t * testing.T ) {
5474 // Setup
5575 ctx , fs , _ , config , pathToConfigJSON , teardown := setup (t )
5676 defer teardown (t )
5777 mockOutput , mockPrintDebug := setupMockPrintDebug ()
5878
59- jsonContents := []byte ("{ \ " last_update_checked_at\" : \ " 2023-05-11T15:41:07.799619-07:00\" , \ " experiments\" :[]}" )
79+ jsonContents := []byte (`{ "last_update_checked_at": "2023-05-11T15:41:07.799619-07:00", "experiments":{}}` )
6080 _ = afero .WriteFile (fs , pathToConfigJSON , jsonContents , 0600 )
6181
6282 config .LoadExperiments (ctx , mockPrintDebug )
@@ -72,7 +92,7 @@ func Test_Config_WithExperimentOn(t *testing.T) {
7292 mockOutput , mockPrintDebug := setupMockPrintDebug ()
7393
7494 // Write no contents via config.json
75- jsonContents := []byte ("{ \ " last_update_checked_at\" : \ " 2023-05-11T15:41:07.799619-07:00\" , \ " experiments\" :[]}" )
95+ jsonContents := []byte (`{ "last_update_checked_at": "2023-05-11T15:41:07.799619-07:00", "experiments":{}}` )
7696 _ = afero .WriteFile (fs , pathToConfigJSON , jsonContents , 0600 )
7797 config .ExperimentsFlag = []string {string (validExperiment )}
7898
@@ -89,7 +109,7 @@ func Test_Config_WithExperimentOn(t *testing.T) {
89109 defer teardown (t )
90110 mockOutput , mockPrintDebug := setupMockPrintDebug ()
91111
92- jsonContents := []byte (fmt .Sprintf ("{ \ " last_update_checked_at\" : \ " 2023-05-11T15:41:07.799619-07:00\" , \ " experiments\" :[ \ " %s\" ]}" , invalidExperiment ))
112+ jsonContents := []byte (fmt .Sprintf (`{ "last_update_checked_at": "2023-05-11T15:41:07.799619-07:00", "experiments":{ "%s":true}}` , invalidExperiment ))
93113 _ = afero .WriteFile (fs , pathToConfigJSON , jsonContents , 0600 )
94114 config .LoadExperiments (ctx , mockPrintDebug )
95115 assert .Contains (t , mockOutput .String (),
@@ -120,7 +140,7 @@ func Test_Config_WithExperimentOn(t *testing.T) {
120140 mockOutput , mockPrintDebug := setupMockPrintDebug ()
121141
122142 // Write contents via config.json
123- jsonContents := []byte (fmt .Sprintf ("{ \ " last_update_checked_at\" : \ " 2023-05-11T15:41:07.799619-07:00\" , \ " experiments\" :[ \ " %s\" ]}" , tc .experiment ))
143+ jsonContents := []byte (fmt .Sprintf (`{ "last_update_checked_at": "2023-05-11T15:41:07.799619-07:00", "experiments":{ "%s":true}}` , tc .experiment ))
124144 _ = afero .WriteFile (fs , pathToConfigJSON , jsonContents , 0600 )
125145
126146 config .LoadExperiments (ctx , mockPrintDebug )
@@ -172,7 +192,7 @@ func Test_Config_WithExperimentOn(t *testing.T) {
172192 require .NoError (t , err )
173193 err = afero .WriteFile (fs , GetProjectHooksJSONFilePath (slackdeps .MockWorkingDirectory ), []byte ("{}\n " ), 0600 )
174194 require .NoError (t , err )
175- jsonContents := []byte (fmt .Sprintf (`{"experiments":[ "%s"] }` , experiment .Placeholder ))
195+ jsonContents := []byte (fmt .Sprintf (`{"experiments":{ "%s":true} }` , experiment .Placeholder ))
176196 err = afero .WriteFile (fs , GetProjectConfigJSONFilePath (slackdeps .MockWorkingDirectory ), []byte (jsonContents ), 0600 )
177197 require .NoError (t , err )
178198
@@ -185,36 +205,37 @@ func Test_Config_WithExperimentOn(t *testing.T) {
185205 t .Run ("Loads valid experiments from project configs and removes duplicates" , func (t * testing.T ) {
186206 ctx , fs , _ , config , _ , teardown := setup (t )
187207 defer teardown (t )
188- mockOutput , mockPrintDebug := setupMockPrintDebug ()
208+ _ , mockPrintDebug := setupMockPrintDebug ()
189209 err := fs .Mkdir (slackdeps .MockWorkingDirectory , 0755 )
190210 require .NoError (t , err )
191211 err = fs .Mkdir (filepath .Join (slackdeps .MockWorkingDirectory , ProjectConfigDirName ), 0755 )
192212 require .NoError (t , err )
193213 err = afero .WriteFile (fs , GetProjectHooksJSONFilePath (slackdeps .MockWorkingDirectory ), []byte ("{}\n " ), 0600 )
194214 require .NoError (t , err )
195- jsonContents := []byte (fmt .Sprintf (
196- `{"experiments":["%s", "%s", "%s"]}` ,
197- experiment .Placeholder ,
198- experiment .Placeholder ,
199- experiment .Placeholder ,
200- ))
215+ jsonContents := []byte (
216+ fmt .Sprintf (`{"experiments":{"%s":true, "%s":true, "%s":true}}` ,
217+ experiment .Placeholder ,
218+ experiment .Placeholder ,
219+ experiment .Placeholder ,
220+ ),
221+ )
201222 err = afero .WriteFile (fs , GetProjectConfigJSONFilePath (slackdeps .MockWorkingDirectory ), []byte (jsonContents ), 0600 )
202223 require .NoError (t , err )
203224
225+ // Also set via flag to test dedup
226+ config .ExperimentsFlag = []string {string (experiment .Placeholder )}
227+
204228 config .LoadExperiments (ctx , mockPrintDebug )
205229 assert .True (t , config .WithExperimentOn (experiment .Placeholder ))
206- assert .Contains (t , mockOutput .String (), fmt .Sprintf (
207- "active project experiments: [%s %s %s]" ,
208- experiment .Placeholder ,
209- experiment .Placeholder ,
210- experiment .Placeholder ,
211- ))
212- // Assert that duplicates are removed and slice length is reduced
213- // Add in the permanently enabled experiments before comparing
214- activeExperiments := append (experiment .EnabledExperiments , experiment .Placeholder )
215- slices .Sort (activeExperiments )
216- activeExperiments = slices .Compact (activeExperiments )
217- assert .Equal (t , activeExperiments , config .experiments )
230+ // Assert that experiments are deduplicated via map
231+ exps := config .GetExperiments ()
232+ count := 0
233+ for _ , exp := range exps {
234+ if exp == experiment .Placeholder {
235+ count ++
236+ }
237+ }
238+ assert .Equal (t , 1 , count , "experiment should appear exactly once" )
218239 })
219240
220241 t .Run ("Loads valid experiments and enabled default experiments" , func (t * testing.T ) {
@@ -227,7 +248,7 @@ func Test_Config_WithExperimentOn(t *testing.T) {
227248 require .NoError (t , err )
228249 err = afero .WriteFile (fs , GetProjectHooksJSONFilePath (slackdeps .MockWorkingDirectory ), []byte ("{}\n " ), 0600 )
229250 require .NoError (t , err )
230- jsonContents := []byte (`{"experiments":[] }` ) // No experiments
251+ jsonContents := []byte (`{"experiments":{} }` ) // No experiments
231252 err = afero .WriteFile (fs , GetProjectConfigJSONFilePath (slackdeps .MockWorkingDirectory ), []byte (jsonContents ), 0600 )
232253 require .NoError (t , err )
233254
@@ -244,7 +265,7 @@ func Test_Config_WithExperimentOn(t *testing.T) {
244265 assert .True (t , config .WithExperimentOn (experiment .Placeholder ))
245266 assert .Contains (t , mockOutput .String (), "active project experiments: []" )
246267 assert .Contains (t , mockOutput .String (), fmt .Sprintf ("active permanently enabled experiments: [%s]" , experiment .Placeholder ))
247- assert .Equal (t , []experiment.Experiment {experiment .Placeholder }, config .experiments )
268+ assert .ElementsMatch (t , []experiment.Experiment {experiment .Placeholder }, config .GetExperiments () )
248269 })
249270
250271 t .Run ("Logs an invalid experiments in project configs" , func (t * testing.T ) {
@@ -257,7 +278,7 @@ func Test_Config_WithExperimentOn(t *testing.T) {
257278 require .NoError (t , err )
258279 err = afero .WriteFile (fs , GetProjectHooksJSONFilePath (slackdeps .MockWorkingDirectory ), []byte ("{}\n " ), 0600 )
259280 require .NoError (t , err )
260- jsonContents := []byte (fmt . Sprintf ( "{ \ " experiments\" :[ \" %s \" ]}" , " experiment-37") )
281+ jsonContents := []byte (`{ "experiments":{" experiment-37":true}}` )
261282 err = afero .WriteFile (fs , GetProjectConfigJSONFilePath (slackdeps .MockWorkingDirectory ), []byte (jsonContents ), 0600 )
262283 require .NoError (t , err )
263284
@@ -283,7 +304,7 @@ func Test_Config_GetExperiments(t *testing.T) {
283304 _ , mockPrintDebug := setupMockPrintDebug ()
284305
285306 // Write contents via config.json
286- var configJSON = []byte (fmt .Sprintf ("{ \ " last_update_checked_at\" : \ " 2023-05-11T15:41:07.799619-07:00\" , \ " experiments\" :[ \ " %s\" , \" %s \" ]}" , validExperiment , validExperiment ))
307+ var configJSON = []byte (fmt .Sprintf (`{ "last_update_checked_at": "2023-05-11T15:41:07.799619-07:00", "experiments":{ "%s":true}}` , validExperiment ))
287308 _ = afero .WriteFile (fs , pathToConfigJSON , configJSON , 0600 )
288309
289310 // Set contexts of experiment flag
0 commit comments