@@ -22,12 +22,28 @@ func notesHandler() http.Handler {
2222 path := strings .TrimPrefix (r .URL .Path , "/sheets/v4" )
2323 path = strings .TrimPrefix (path , "/v4" )
2424 if strings .HasPrefix (path , "/spreadsheets/s1" ) && r .Method == http .MethodGet {
25+ if r .URL .Query ().Get ("includeGridData" ) != "true" {
26+ http .Error (w , "expected includeGridData=true" , http .StatusBadRequest )
27+ return
28+ }
29+
30+ rangeParam := r .URL .Query ().Get ("ranges" )
31+ startRow , startCol := 0 , 0
32+ if strings .Contains (rangeParam , "B2" ) {
33+ startRow , startCol = 1 , 1
34+ }
35+
2536 w .Header ().Set ("Content-Type" , "application/json" )
2637 _ = json .NewEncoder (w ).Encode (map [string ]any {
2738 "sheets" : []map [string ]any {
2839 {
40+ "properties" : map [string ]any {
41+ "title" : "Sheet1" ,
42+ },
2943 "data" : []map [string ]any {
3044 {
45+ "startRow" : startRow ,
46+ "startColumn" : startCol ,
3147 "rowData" : []map [string ]any {
3248 {
3349 "values" : []map [string ]any {
@@ -105,6 +121,18 @@ func TestSheetsNotesCmd_JSON(t *testing.T) {
105121 }
106122
107123 first := notes [0 ].(map [string ]any )
124+ if first ["sheet" ] != "Sheet1" {
125+ t .Errorf ("expected sheet 'Sheet1', got %q" , first ["sheet" ])
126+ }
127+ if first ["a1" ] != "Sheet1!A1" {
128+ t .Errorf ("expected a1 'Sheet1!A1', got %q" , first ["a1" ])
129+ }
130+ if first ["row" ] != float64 (1 ) {
131+ t .Errorf ("expected row 1, got %v" , first ["row" ])
132+ }
133+ if first ["col" ] != float64 (1 ) {
134+ t .Errorf ("expected col 1, got %v" , first ["col" ])
135+ }
108136 if first ["note" ] != "Header note" {
109137 t .Errorf ("expected 'Header note', got %q" , first ["note" ])
110138 }
@@ -150,11 +178,60 @@ func TestSheetsNotesCmd_Text(t *testing.T) {
150178 if ! strings .Contains (out , "Estimated" ) {
151179 t .Errorf ("expected 'Estimated' in output: %q" , out )
152180 }
153- if ! strings .Contains (out , "ROW " ) {
181+ if ! strings .Contains (out , "A1 " ) {
154182 t .Errorf ("expected table header in output: %q" , out )
155183 }
156184}
157185
186+ func TestSheetsNotesCmd_OffsetRange_JSON (t * testing.T ) {
187+ origNew := newSheetsService
188+ t .Cleanup (func () { newSheetsService = origNew })
189+
190+ srv := httptest .NewServer (notesHandler ())
191+ defer srv .Close ()
192+
193+ svc , err := sheets .NewService (context .Background (),
194+ option .WithoutAuthentication (),
195+ option .WithHTTPClient (srv .Client ()),
196+ option .WithEndpoint (srv .URL + "/" ),
197+ )
198+ if err != nil {
199+ t .Fatalf ("NewService: %v" , err )
200+ }
201+ newSheetsService = func (context.Context , string ) (* sheets.Service , error ) { return svc , nil }
202+
203+ flags := & RootFlags {Account : "a@b.com" }
204+ u , uiErr := ui .New (ui.Options {Stdout : io .Discard , Stderr : io .Discard , Color : "never" })
205+ if uiErr != nil {
206+ t .Fatalf ("ui.New: %v" , uiErr )
207+ }
208+ ctx := ui .WithUI (context .Background (), u )
209+ ctx = outfmt .WithMode (ctx , outfmt.Mode {JSON : true })
210+
211+ out := captureStdout (t , func () {
212+ if err := runKong (t , & SheetsNotesCmd {}, []string {"s1" , "Sheet1!B2:C3" }, ctx , flags ); err != nil {
213+ t .Fatalf ("notes: %v" , err )
214+ }
215+ })
216+
217+ var result map [string ]any
218+ if err := json .Unmarshal ([]byte (out ), & result ); err != nil {
219+ t .Fatalf ("unmarshal: %v (output: %q)" , err , out )
220+ }
221+
222+ notes := result ["notes" ].([]any )
223+ first := notes [0 ].(map [string ]any )
224+ if first ["a1" ] != "Sheet1!B2" {
225+ t .Errorf ("expected a1 'Sheet1!B2', got %q" , first ["a1" ])
226+ }
227+ if first ["row" ] != float64 (2 ) {
228+ t .Errorf ("expected row 2, got %v" , first ["row" ])
229+ }
230+ if first ["col" ] != float64 (2 ) {
231+ t .Errorf ("expected col 2, got %v" , first ["col" ])
232+ }
233+ }
234+
158235func TestSheetsNotesCmd_NoNotes (t * testing.T ) {
159236 origNew := newSheetsService
160237 t .Cleanup (func () { newSheetsService = origNew })
@@ -192,19 +269,19 @@ func TestSheetsNotesCmd_NoNotes(t *testing.T) {
192269 newSheetsService = func (context.Context , string ) (* sheets.Service , error ) { return svc , nil }
193270
194271 flags := & RootFlags {Account : "a@b.com" }
195- u , uiErr := ui .New (ui.Options {Stdout : io .Discard , Stderr : io .Discard , Color : "never" })
196- if uiErr != nil {
197- t .Fatalf ("ui.New: %v" , uiErr )
198- }
199- ctx := ui .WithUI (context .Background (), u )
272+ errOut := captureStderr (t , func () {
273+ u , uiErr := ui .New (ui.Options {Stdout : io .Discard , Stderr : os .Stderr , Color : "never" })
274+ if uiErr != nil {
275+ t .Fatalf ("ui.New: %v" , uiErr )
276+ }
277+ ctx := ui .WithUI (context .Background (), u )
200278
201- out := captureStdout (t , func () {
202279 if err := runKong (t , & SheetsNotesCmd {}, []string {"s1" , "Sheet1!A1" }, ctx , flags ); err != nil {
203280 t .Fatalf ("notes: %v" , err )
204281 }
205282 })
206283
207- if strings .Contains (out , "ROW " ) {
208- t .Errorf ("expected no table output for empty notes : %q" , out )
284+ if ! strings .Contains (errOut , "No notes found " ) {
285+ t .Errorf ("expected 'No notes found' on stderr : %q" , errOut )
209286 }
210287}
0 commit comments