@@ -355,6 +355,50 @@ void newsNoDataEnvelopeYieldsEmptyList() {
355355 assertThat (resp .updated ()).isNull ();
356356 }
357357
358+ @ Test
359+ void newsRejectsColumnsProjectionOnTypedPath () {
360+ // StockNewsArticle is non-null by contract, so a typed columns projection can't be honored
361+ // without lying. It must fail fast and clearly, before any request is dispatched (Option B).
362+ CapturingClient client = okWith (NEWS_BODY );
363+ StocksResource stocks = resourceWith (client );
364+
365+ assertThatThrownBy (() -> stocks .columns ("headline" ).news (StockNewsRequest .of ("AAPL" )))
366+ .isInstanceOf (IllegalArgumentException .class )
367+ .hasMessageContaining ("news" )
368+ .hasMessageContaining ("asCsv" );
369+ // Fail-fast: no request reached the wire.
370+ assertThat (client .captured ).isEmpty ();
371+ }
372+
373+ @ Test
374+ void newsColumnsRejectionIsAFailedFutureNotASyncThrow () {
375+ // ADR-006: the async surface signals errors through the future. The guard must NOT throw at the
376+ // call site (which would bypass .exceptionally/.handle) — newsAsync(...) returns normally and
377+ // the returned future completes exceptionally instead.
378+ CapturingClient client = okWith (NEWS_BODY );
379+ StocksResource stocks = resourceWith (client );
380+
381+ var future = stocks .columns ("headline" ).newsAsync (StockNewsRequest .of ("AAPL" ));
382+
383+ assertThat (future ).isCompletedExceptionally ();
384+ assertThatThrownBy (future ::join )
385+ .isInstanceOf (java .util .concurrent .CompletionException .class )
386+ .hasCauseInstanceOf (IllegalArgumentException .class );
387+ assertThat (client .captured ).isEmpty ();
388+ }
389+
390+ @ Test
391+ void newsColumnsProjectionStillWorksOnCsvFacet () {
392+ // The CSV facet returns raw text — no typed contract to break — so columns stays supported
393+ // there.
394+ CapturingClient client = okWith ("a,b\n 1,2" );
395+ StocksCsvResource csv = resourceWith (client ).asCsv ();
396+
397+ assertThat (csv .columns ("headline" ).news (StockNewsRequest .of ("AAPL" )).csv ()).contains ("a,b" );
398+ String url = URLDecoder .decode (client .captured .get (0 ).uri ().toString (), StandardCharsets .UTF_8 );
399+ assertThat (url ).contains ("columns=headline" );
400+ }
401+
358402 // ---------- earnings ----------
359403
360404 @ Test
0 commit comments