RIFF¤ WEBPVP8 ˜ ðÑ *ôô>‘HŸK¥¤"§£±¨àð ....................................../////.===Shadow-Here===./////................................................ > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < ------------------------------------------------------------------------------------------------------------------- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// RIFF¤ WEBPVP8 ˜ ðÑ *ôô>‘HŸK¥¤"§£±¨àð enü¹%½_F‘åè¿2ºQú³íªú`N¿­3ÿƒügµJžaÿ¯ÿ°~¼ÎùnúîÞÖô•òíôÁÉß®Sm¥Ü/ ‡ó˜f£Ùà<˜„xëJ¢Ù€SO3x<ªÔ©4¿+ç¶A`q@Ì“Úñè™ÍÿJÌ´ª-˜ÆtÊÛL]Ïq*‘Ý”ì#ŸÌÏãY]@ê`¿ /ªfkØB4·®£ó z—Üw¥Pxù–ÞLШKÇN¾AkÙTf½è'‰g gÆv›Øuh~ a˜Z— ïj*á¥t d£“uÒ ¨`K˜¹ßþ]b>˜]_ÏÔ6W—è2r4x•íÖ…"ƒÖNîä!¦å Ú}ýxGøÌ —@ ;ÆÚŠ=ɾ1ý8lªË¥ô ^yf®Œ¢u&2©nÙÇ›ñÂñŒ³ aPo['½»øFùà­+4ê“$!lövlüÞ=;N®3ð‚õ›DÉKòÞ>ÄÍ ¥ˆuߤ#ˆ$6ù™¥îЇy’ÍB¼ çxÛ;X"WL£R÷͝*ó-¶Zu}º.s¸sšXqù–DþÿvªhüïwyŸ ¯é³lÀ:KCûÄ£Ëá\…­ ~—ýóî ¼ûûÜTÓüÇy…ŽÆvc»¾×U ñ¸žþоP÷¦ó:Ò¨¨5;Ð#&#ÖúñläÿÁœ GxÉ­/ñ‡áQðìYÉtÒw޼GÔ´zàÒò ð*ëzƒ•4~H]Ø‹f ñÓÈñ`NåWçs'ÆÏW^ø¹!XžµmQ5ÃËoLœÎ: ÞËÍ¥J ù…î èo£ßPÎñ¶ž8.Œ]ʵ~5›ÙË-ù*8ÙÖß±~ ©¹rÓê‚j¶d¸{^Q'˜±Crß ÚH—#¥¥QlÀ×ëã‡DÜ«èî þ&Çæžî;ŽÏºò6ÒLÃXy&ZŒ'j‚¢Ù€IßÚù+–MGi‰*jE€‘JcÜ ÓÌ EÏÚj]o˜ Þr <¾U ûŪæÍ/šÝH¥˜b”¼ ÁñßX GP›ï2›4WŠÏà×£…íÓk†¦H·ÅíMh–*nó÷à]ÁjCº€b7<ب‹¨5車bp2:Á[UªM„QŒçiNMa#<5›áËó¸HýÊ"…×Éw¹¦ì2º–x<›»a±¸3Weü®FÝ⑱ö–î–³|LPÈ~çð~Çå‡|º kD¢µÏàÆAI %1À% ¹Ò – ”ϝS¦‰4&¶£°à Öý”û_Ò Áw°A«Å€?mÇÛgHÉ/8)á¾ÛìáöŽP í¨PŸNÙµº¦‡§Ùš"ÿ«>+ªÕ`Ê÷‡‚ß Õû˜þãÇ-PÍ.¾XV‘€ dÜ"þ4¹ ±Oú‘©t¥¦FªÄÃÄ•b‚znýu½—#cDs˜ÃiÑOˆñ×QO=*IAÊ,¶ŽZƒ;‡wøXè%EÐk:F±Ú” .Ѽ+Áu&Ç`."pÈÉw o&¿dE6‘’EqTuK@Ì¥ã™À(Êk(h‰,H}RÀIXÛš3µ1©_OqÚÒJAñ$ÊÙÜ;D3çŒ[þùœh¬Ã³™ö6ç†NY".Ú‰ï[ªŸŒ '²Ð öø_¨ÂÉ9ué¶³ÒŠõTàîMØ#û¯gN‡bÙ놚X„ö …ÉeüÌ^J ‹€.œ$Æ)βÄeæW#óüßĺŸ€ ÀzwV 9oä»f4V*uB «Ë†¹ì¯žR霓æHXa=&“I4K;¯ç‹h×·"UŠ~<•╪Vêª&ÍSÃÆÅ?ÔqÎ*mTM ˜›µwêd#[C¡©§‘D<©àb†–ÁœøvH/,í:¯( ²£|4-„Æövv„Yͼ™^Á$ˆ„¢Û[6yB.åH*V¨æ?$=˜Ñ€•ñ·­(VlŸ‘ nÀt8W÷´Bûba?q9ú¶Xƒl«ÿ\ù¶’þòUÐj/õ¢Ìµ³g$ƒÎR!¸»|Oߍë’BhîÚÑ¢ñåŒJ„®„£2Ð3•ô02Nt…!£Í]Ïc½Qÿ?ˆ<&ÃA¾Ú,JˆijÌ#5yz„‰Î|ÊŽ5QÏ:‹ÐaóVÔxW—CpeÏzÐïíçôÿÅ_[hãsÐ_/ŽTÝ?BîˆííV$<¿i>²F¬_Eß¿ †bÊŒº­ÿ®Z H“C}”¬,Mp ý/Bá£w>˜YV°aƒúh+cŠ- r/[%|üUMHäQ°X»|û/@|°¥Ð !BÔ Ç¢Ä©š+Õì D«7ìN¶ŽðÔ " ƶ’ÖçtA‰Û×}{tþz­¾GÍ›k¹OEJR$ Â׃ «ëÁ"oÉôž$oUK(Ä)Ãz³Ê-‹êN[Ò3Œñbï8P 4ƒ×q¢bo|?<ÛX¬òÄͰL–±›(™ûG?ýË©ÚÄ–ÂDØÐ_Ç¡ô ¾–ÄÏø ×e8Ë©$ÄF¹Å‹ì[©óìl:F¾f´‹‹Xì²ï®\¬ôùƒ ÿat¥óèÒùHß0äe‚;ü×h:ÆWðHž=Ã8骣"kœ'Y?³}Tûè€>?0l›e1Lòñ„aæKÆw…hÖŠùW…ÈÆÄ0ši·›[pcwËþñiêíY/~-Á5˜!¿†A›™Mÿþ(±“t@â“ö2­´TG5yé]çå僳 .·ÍïçÝ7UÚ±Ð/Nè»,_Ï ùdj7\ï Wì4›„»c¸àešg#ÒÊ⥭áØo5‘?ÌdÝô¯ ¹kzsƒ=´#ëÉK›Ø´±-¥eW?‡çßtòTã…$Ý+qÿ±ƒ÷_3Ô¥í÷:æ–ž<·Ö‡‰Å¢ š‡%Ô—utÌÈìðžgÖÀz²À—ï÷Óîäõ{K'´È÷³yaÏÁjƒô}ž§®æÊydÕÈë5¯èˆõvÕ©ã*çD„ “z„Ó‡^^xÂ3M§A´JG‚öï 3W'ˆ.OvXè¡ÊÕª?5º7†˜(˜Ç¶#çê’¶!ÌdZK§æ 0fãaN]òY³RV ™î$®K2R¨`W!1Ôó\;Ý ýB%qæK•&ÓÈe9È0êI±žeŸß -ú@žQr¦ ö4»M¼Áè¹µmw 9 EÆE_°2ó„ŸXKWÁ×Hóì^´²GѝF©óäR†¦‰ç"V»eØ<3ùd3ÿÚ¤Žú“Gi" —‘_ÙËÎ~Üö¯¥½Î»üŸEÚŽåmÞþí ;ÞólËΦMzA"Âf(´òá;Éï(/7½ûñÌ­cïÕçлþÝz¾-ÍvÑ“pH­–ðÓj$¸Äû¤‚‘ãUBË-n“2åPkS5&‹Â|+g^œ®Ì͆d!OïäîU«c;{Û!ÅŽ«ëZ9Ókóˆ]¯ƒ›né `ÇÒ+tÆš (ØKá¾—=3œ®•vuMñg²\ï Ec€ 05±d™‡×iÇ×›UúvÌ¢£Èþ¡ÕØô¶ßÎA"ß±#Ö²ˆÊŸ¦*Ä~ij|àø.-¼'»Ú¥£h ofº¦‡VsR=N½„Î v˜Z*SÌ{=jÑB‹tê…;’HžH¯8–îDù8ñ¢|Q•bÛçš–‹m³“ê¨ åÏ^m¬Žãþ©ïêO‡½6] µÆ„Ooòü ²x}N¦Ë3ïé¿»€›HA˜m%çÞ/¿í7Fø“‹léUk)É°Œµ8Q8›:ÀŠeT*šõ~ôڝG6 ¢}`ùH­–”¡k ‰P1>š†®9z11!X wKfmÁ¦xÑ,N1Q”–æB¶M…ÒÃv6SMˆhU¬ÊPŽï‘öj=·CŒ¯u¹ƒVIЃsx4’ömÛýcå¡¶7ßŠß 57^\wÒÐÆ k§h,Œý î«q^R½3]J¸ÇðN ‚çU¬ôº^Áì} ³f©Õœ§ˆã:FÄÈ‚é(€™?àýÓüè1Gô£¼éj‚OÅñ  #>×—ßtà 0G¥Åa뀐kßhc™À_ÉñÞ#±)GD" YîäË-ÿÙ̪ ¹™a¯´¢E\ÝÒö‚;™„ë]_ p8‰o¡ñ+^÷ 3‘'dT4œŽ ðVë½° :¬víÑ«£tßÚS-3¶“þ2 †üüʨòrš¹M{É_¤`Û¨0ìjœøJ‡:÷ÃáZ˜†@GP&œÑDGÏs¡þ¦þDGú‘1Yá9Ôþ¼ ûø…§÷8&–ÜÑnÄ_m®^üÆ`;ÉVÁJ£?â€-ßê}suÍ2sõA NÌúA磸‘îÿÚ»ƒìö·á¿±tÑÐ"Tÿü˜[@/äj¬€uüªìù¥Ý˜á8Ý´sõj 8@rˆð äþZÇD®ÿUÏ2ùôõrBzÆÏÞž>Ì™xœ“ wiÎ×7_… ¸ \#€MɁV¶¥üÕÿPÔ9Z‡ø§É8#H:ƒ5ÀÝå9ÍIŒ5åKÙŠ÷qÄ>1AÈøžj"µÂд/ªnÀ qªã}"iŸBå˜ÓÛŽ¦…&ݧ;G@—³b¯“•"´4í¨ôM¨åñC‹ïùÉó¯ÓsSH2Ý@ßáM‡ˆKÀªÛUeø/4\gnm¥‹ŸŒ qÄ b9ÞwÒNÏ_4Ég³ú=܆‚´ •â¥õeíþkjz>éÚyU«Íӝ݃6"8/ø{=Ô¢»G¥ äUw°W«,ô—¿ãㆅү¢³xŠUû™yŒ (øSópÐ 9\åTâ»—*oG$/×ÍT†Y¿1¤Þ¢_‡ ¼ „±ÍçèSaÓ 3ÛMÁBkxs‰’R/¡¤ˆÙçª(*õ„üXÌ´ƒ E§´¬EF"Ù”R/ÐNyÆÂ^°?™6¡œïJ·±$§?º>ÖüœcNÌù¯G ‹ñ2ЁBB„^·úìaz¨k:#¨Æ¨8LÎõލ£^§S&cŒÐU€ü(‡F±Š¼&P>8ÙÁ ‰ p5?0ÊÆƒZl¸aô š¼¡}gÿ¶zÆC²¹¬ÎÖG*HB¡O<º2#ñŒAƒ–¡B˜´É$¥›É:FÀÔx¾u?XÜÏÓvN©RS{2ʈãk9rmP¼Qq̳ è¼ÐFׄ^¡Öì fE“F4A…!ì/…¦Lƒ… … $%´¾yã@CI¬ á—3PþBÏNÿ<ý°4Ü ËÃ#ØÍ~âW«rEñw‹eùMMHß²`¬Öó½íf³:‹k˜¯÷}Z!ã¿<¥,\#öµÀ¯aÒNÆIé,Ћ–lŽ#Àæ9ÀÒS·I’½-Ïp Äz¤Š Â* ­íÄ9­< h>׍3ZkËU¹§˜ŒŠ±f­’¤º³Q ÏB?‹#µíÃ¥®@(Gs«†vI¥Mµ‹Á©e~2ú³ÁP4ìÕi‚²Ê^ö@-DþÓàlÜOÍ]n"µã:žpsŽ¢:! Aõ.ç~ÓBûH÷JCÌ]õVƒd «ú´QÙEA–¯¯Œ!.ˆˆëQ±ù œ·Ì!Õâ )ùL„ÅÀlÚè5@B…o´Æ¸XÓ&Û…O«˜”_#‡ƒ„ûÈt!¤ÁÏ›ÎÝŠ?c9 â\>lÓÁVÄÑ™£eØY]:fÝ–—ù+p{™ðè û³”g±OƒÚSù£áÁÊ„ä,ï7š²G ÕÌBk)~ÑiCµ|h#u¤¶îK¨² #²vݯGãeÖ϶ú…¾múÀ¶þÔñ‚Š9'^($¤§ò “š½{éúp÷J›ušS¹áªCÂubÃH9™D™/ZöØÁ‡¦ÝÙŸ·kð*_”.C‹{áXó€‡c¡c€§/šò/&éš÷,àéJþ‰X›fµ“C¨œ®r¬"kL‰Â_q…Z–.ÉL~O µ›zn‚¹À¦Öª7\àHµšÖ %»ÇníV[¥*Õ;ƒ#½¾HK-ÖIÊdÏEÚ#=o÷Óò³´Š: Ç?{¾+9›–‘OEáU·S€˜j"ÄaÜ ŒÛWt› á–c#a»pÔZÞdŽtWê=9éöÊ¢µ~ ë ;Öe‡Œ®:bî3±ýê¢wà¼îpêñ¹¾4 zc¾ðÖÿzdêŒÑÒŝÀ‰s6¤í³ÎÙB¿OZ”+F¤á‡3@Ñëäg©·Ž ˆèª<ù@É{&S„œÕúÀA)‰h:YÀ5^ÂÓŒ°õäU\ ùËÍû#²?Xe¬tu‰^zÒÔãë¼ÛWtEtû …‚g¶Úüâî*moGè¨7%u!]PhÏd™Ý%Îx: VÒ¦ôÊD3ÀŽKÛËãvÆî…N¯ä>Eró–ð`5 Œ%u5XkñÌ*NU%¶áœÊ:Qÿú»“úzyÏ6å-၇¾ ´ ÒÊ]y žO‘w2Äøæ…H’²f±ÎÇ.ª|¥'gîV•Ü .̘¯€šòü¤U~Ù†*¢!?ò wý,}´°ÔÞnïoKq5µb!áÓ3"vAßH¡³¡·G(ÐÎ0Îò¼MG!/ài®@—¬04*`…«é8ªøøló“ˆÊ”èù¤…ßÊoÿé'ËuÌÖ5×È¡§ˆˆfŽë9}hìâ_!!¯  B&Ëö¶‰ÀAÙNVŸ Wh›¸®XÑJì¨ú“¿÷3uj²˜¨ÍÎìë±aúŠÝå¯ð*Ó¨ôJ“yºØ)m°WýOè68†ŸÏ2—‰Ïüꪫٚ¥‹l1 ø ÏÄFjêµvÌbü¦èÝx:X±¢H=MÐß—,ˆÉÇ´(9ú¾^ÅÚ4¿m‡$âX‘å%(AlZo@½¨UOÌÕ”1ø¸jÎÀÃÃ_ µ‘Ü.œº¦Ut: Æï’!=¯uwû#,“pþÇúŒø(é@?³ü¥‘Mo §—s@Œ#)§ŒùkL}NOÆêA›¸~r½¼ÙA—HJ«eˆÖ´*¡ÓpÌŸö.m<-"³ûÈ$¬_6­åf£ïÚâj1y§ÕJ½@dÞÁr&Í\Z%D£Íñ·AZ Û³øüd/ªAi†/Й~  ‡âĮҮÏh§°b—›Û«mJžòG'[ÈYýŒ¦9psl ýÁ ®±f¦x,‰½tN ‚Xª9 ÙÖH.«Lo0×?͹m¡å†Ѽ+›2ƒF ±Ê8 7Hցϓ²Æ–m9…òŸï]Â1äN†VLâCˆU .ÿ‰Ts +ÅÎx(%¦u]6AF Š ØF鈄‘ |¢¶c±soŒ/t[a¾–û:s·`i햍ê›ËchÈ…8ßÀUÜewŒðNOƒõD%q#éû\9¤x¹&UE×G¥ Í—™$ð E6-‡¼!ýpãÔM˜ Âsìe¯ñµK¢Ç¡ùôléœ4Ö£”À Š®Ðc ^¨À}ÙËŸ§›ºê{ÊuÉC ×Sr€¤’fÉ*j!úÓ’Gsùìoîßîn%ò· àc Wp÷$¨˜)û»H ×8ŽÒ€Zj¤3ÀÙºY'Ql¦py{-6íÔCeiØp‘‡XÊîÆUߢ܂ž£Xé¼Y8þ©ëgñß}é.ÎógÒ„ÃØËø¯»™§Xýy M%@NŠ À(~áÐvu7&•,Ù˜ó€uP‡^^®=_E„jt’ 403WebShell
403Webshell
Server IP : 104.225.223.251  /  Your IP : 216.73.216.41
Web Server : Apache/2.4.41 (Ubuntu)
System : Linux agtdemo03 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64
User : root ( 0)
PHP Version : 7.4.3-4ubuntu2.29
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /srv/wp/ciieduconnect.in/www/core/tests/Drupal/Tests/Core/Render/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /srv/wp/ciieduconnect.in/www/core/tests/Drupal/Tests/Core/Render//RendererPlaceholdersTest.php
<?php

/**
 * @file
 * Contains \Drupal\Tests\Core\Render\RendererPlaceholdersTest.
 */

namespace Drupal\Tests\Core\Render;

use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Html;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Render\Markup;
use Drupal\Core\Security\TrustedCallbackInterface;
use Drupal\Core\Render\RenderContext;

/**
 * @coversDefaultClass \Drupal\Core\Render\Renderer
 * @covers \Drupal\Core\Render\RenderCache
 * @covers \Drupal\Core\Render\PlaceholderingRenderCache
 * @group Render
 */
class RendererPlaceholdersTest extends RendererTestBase {

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    // Disable the required cache contexts, so that this test can test just the
    // placeholder replacement behavior.
    $this->rendererConfig['required_cache_contexts'] = [];

    parent::setUp();
  }

  /**
   * Provides the two classes of placeholders: cacheable and uncacheable.
   *
   * I.e. with or without #cache[keys].
   *
   * Also, different types:
   * - A) automatically generated placeholder
   *   - 1) manually triggered (#create_placeholder = TRUE)
   *   - 2) automatically triggered (based on max-age = 0 at the top level)
   *   - 3) automatically triggered (based on high cardinality cache contexts at
   *        the top level)
   *   - 4) automatically triggered (based on high-invalidation frequency cache
   *        tags at the top level)
   *   - 5) automatically triggered (based on max-age = 0 in its subtree, i.e.
   *        via bubbling)
   *   - 6) automatically triggered (based on high cardinality cache contexts in
   *        its subtree, i.e. via bubbling)
   *   - 7) automatically triggered (based on high-invalidation frequency cache
   *        tags in its subtree, i.e. via bubbling)
   * - B) manually generated placeholder
   *
   * So, in total 2*8 = 16 permutations. (On one axis: uncacheable vs.
   * uncacheable = 2; on the other axis: A1–7 and B = 8.)
   *
   * @todo Case A5 is not yet supported by core. So that makes for only 14
   *   permutations currently, instead of 16. That will be done in
   *   https://www.drupal.org/node/2559847
   *
   * @return array
   */
  public function providerPlaceholders() {
    $args = [$this->randomContextValue()];

    $generate_placeholder_markup = function ($cache_keys = NULL) use ($args) {
      $token_render_array = [
        '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
      ];
      if (is_array($cache_keys)) {
        $token_render_array['#cache']['keys'] = $cache_keys;
      }
      $token = Crypt::hashBase64(serialize($token_render_array));
      // \Drupal\Core\Render\Markup::create() is necessary as the render
      // system would mangle this markup. As this is exactly what happens at
      // runtime this is a valid use-case.
      return Markup::create('<drupal-render-placeholder callback="Drupal\Tests\Core\Render\PlaceholdersTest::callback" arguments="' . '0=' . $args[0] . '" token="' . $token . '"></drupal-render-placeholder>');
    };

    $extract_placeholder_render_array = function ($placeholder_render_array) {
      return array_intersect_key($placeholder_render_array, ['#lazy_builder' => TRUE, '#cache' => TRUE]);
    };

    // Note the presence of '#create_placeholder'.
    $base_element_a1 = [
      '#attached' => [
        'drupalSettings' => [
          'foo' => 'bar',
        ],
      ],
      'placeholder' => [
        '#cache' => [
          'contexts' => [],
        ],
        '#create_placeholder' => TRUE,
        '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
      ],
    ];
    // Note the absence of '#create_placeholder', presence of max-age=0 at the
    // top level.
    $base_element_a2 = [
      '#attached' => [
        'drupalSettings' => [
          'foo' => 'bar',
        ],
      ],
      'placeholder' => [
        '#cache' => [
          'contexts' => [],
          'max-age' => 0,
        ],
        '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
      ],
    ];
    // Note the absence of '#create_placeholder', presence of high cardinality
    // cache context at the top level.
    $base_element_a3 = [
      '#attached' => [
        'drupalSettings' => [
          'foo' => 'bar',
        ],
      ],
      'placeholder' => [
        '#cache' => [
          'contexts' => ['user'],
        ],
        '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
      ],
    ];
    // Note the absence of '#create_placeholder', presence of high-invalidation
    // frequency cache tag at the top level.
    $base_element_a4 = [
      '#attached' => [
        'drupalSettings' => [
          'foo' => 'bar',
        ],
      ],
      'placeholder' => [
        '#cache' => [
          'contexts' => [],
          'tags' => ['current-temperature'],
        ],
        '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
      ],
    ];
    // Note the absence of '#create_placeholder', presence of max-age=0 created
    // by the #lazy_builder callback.
    // @todo in https://www.drupal.org/node/2559847
    $base_element_a5 = [];
    // Note the absence of '#create_placeholder', presence of high cardinality
    // cache context created by the #lazy_builder callback.
    // @see \Drupal\Tests\Core\Render\PlaceholdersTest::callbackPerUser()
    $base_element_a6 = [
      '#attached' => [
        'drupalSettings' => [
          'foo' => 'bar',
        ],
      ],
      'placeholder' => [
        '#cache' => [
          'contexts' => [],
        ],
        '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callbackPerUser', $args],
      ],
    ];
    // Note the absence of '#create_placeholder', presence of high-invalidation
    // frequency cache tag created by the #lazy_builder callback.
    // @see \Drupal\Tests\Core\Render\PlaceholdersTest::callbackTagCurrentTemperature()
    $base_element_a7 = [
      '#attached' => [
        'drupalSettings' => [
          'foo' => 'bar',
        ],
      ],
      'placeholder' => [
        '#cache' => [
          'contexts' => [],
        ],
        '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callbackTagCurrentTemperature', $args],
      ],
    ];
    // Note the absence of '#create_placeholder', but the presence of
    // '#attached[placeholders]'.
    $base_element_b = [
      '#markup' => $generate_placeholder_markup(),
      '#attached' => [
        'drupalSettings' => [
          'foo' => 'bar',
        ],
        'placeholders' => [
          (string) $generate_placeholder_markup() => [
            '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
          ],
        ],
      ],
    ];

    $keys = ['placeholder', 'output', 'can', 'be', 'render', 'cached', 'too'];

    $cases = [];

    // Case one: render array that has a placeholder that is:
    // - automatically created, but manually triggered (#create_placeholder = TRUE)
    // - uncacheable
    $element_without_cache_keys = $base_element_a1;
    $expected_placeholder_render_array = $extract_placeholder_render_array($base_element_a1['placeholder']);
    $cases[] = [
      $element_without_cache_keys,
      $args,
      $expected_placeholder_render_array,
      FALSE,
      [],
      [],
      [],
    ];

    // Case two: render array that has a placeholder that is:
    // - automatically created, but manually triggered (#create_placeholder = TRUE)
    // - cacheable
    $element_with_cache_keys = $base_element_a1;
    $element_with_cache_keys['placeholder']['#cache']['keys'] = $keys;
    $expected_placeholder_render_array['#cache']['keys'] = $keys;
    $cases[] = [
      $element_with_cache_keys,
      $args,
      $expected_placeholder_render_array,
      $keys,
      [],
      [],
      [
        '#markup' => '<p>This is a rendered placeholder!</p>',
        '#attached' => [
          'drupalSettings' => [
            'dynamic_animal' => $args[0],
          ],
        ],
        '#cache' => [
          'contexts' => [],
          'tags' => [],
          'max-age' => Cache::PERMANENT,
        ],
      ],
    ];

    // Case three: render array that has a placeholder that is:
    // - automatically created, and automatically triggered due to max-age=0
    // - uncacheable
    $element_without_cache_keys = $base_element_a2;
    $expected_placeholder_render_array = $extract_placeholder_render_array($base_element_a2['placeholder']);
    $cases[] = [
      $element_without_cache_keys,
      $args,
      $expected_placeholder_render_array,
      FALSE,
      [],
      [],
      [],
    ];

    // Case four: render array that has a placeholder that is:
    // - automatically created, but automatically triggered due to max-age=0
    // - cacheable
    $element_with_cache_keys = $base_element_a2;
    $element_with_cache_keys['placeholder']['#cache']['keys'] = $keys;
    $expected_placeholder_render_array['#cache']['keys'] = $keys;
    $cases[] = [
      $element_with_cache_keys,
      $args,
      $expected_placeholder_render_array,
      FALSE,
      [],
      [],
      [],
    ];

    // Case five: render array that has a placeholder that is:
    // - automatically created, and automatically triggered due to high
    //   cardinality cache contexts
    // - uncacheable
    $element_without_cache_keys = $base_element_a3;
    $expected_placeholder_render_array = $extract_placeholder_render_array($base_element_a3['placeholder']);
    $cases[] = [
      $element_without_cache_keys,
      $args,
      $expected_placeholder_render_array,
      FALSE,
      [],
      [],
      [],
    ];

    // Case six: render array that has a placeholder that is:
    // - automatically created, and automatically triggered due to high
    //   cardinality cache contexts
    // - cacheable
    $element_with_cache_keys = $base_element_a3;
    $element_with_cache_keys['placeholder']['#cache']['keys'] = $keys;
    $expected_placeholder_render_array['#cache']['keys'] = $keys;
    // The CID parts here consist of the cache keys plus the 'user' cache
    // context, which in this unit test is simply the given cache context token,
    // see \Drupal\Tests\Core\Render\RendererTestBase::setUp().
    $cid_parts = array_merge($keys, ['user']);
    $cases[] = [
      $element_with_cache_keys,
      $args,
      $expected_placeholder_render_array,
      $cid_parts,
      [],
      [],
      [
        '#markup' => '<p>This is a rendered placeholder!</p>',
        '#attached' => [
          'drupalSettings' => [
            'dynamic_animal' => $args[0],
          ],
        ],
        '#cache' => [
          'contexts' => ['user'],
          'tags' => [],
          'max-age' => Cache::PERMANENT,
        ],
      ],
    ];

    // Case seven: render array that has a placeholder that is:
    // - automatically created, and automatically triggered due to high
    //   invalidation frequency cache tags
    // - uncacheable
    $element_without_cache_keys = $base_element_a4;
    $expected_placeholder_render_array = $extract_placeholder_render_array($base_element_a4['placeholder']);
    $cases[] = [
      $element_without_cache_keys,
      $args,
      $expected_placeholder_render_array,
      FALSE,
      [],
      [],
      [],
    ];

    // Case eight: render array that has a placeholder that is:
    // - automatically created, and automatically triggered due to high
    //   invalidation frequency cache tags
    // - cacheable
    $element_with_cache_keys = $base_element_a4;
    $element_with_cache_keys['placeholder']['#cache']['keys'] = $keys;
    $expected_placeholder_render_array['#cache']['keys'] = $keys;
    $cases[] = [
      $element_with_cache_keys,
      $args,
      $expected_placeholder_render_array,
      $keys,
      [],
      [],
      [
        '#markup' => '<p>This is a rendered placeholder!</p>',
        '#attached' => [
          'drupalSettings' => [
            'dynamic_animal' => $args[0],
          ],
        ],
        '#cache' => [
          'contexts' => [],
          'tags' => ['current-temperature'],
          'max-age' => Cache::PERMANENT,
        ],
      ],
    ];

    // Case nine: render array that DOES NOT have a placeholder that is:
    // - NOT created, despite max-age=0 that is bubbled
    // - uncacheable
    // (because the render element with #lazy_builder does not have #cache[keys]
    // and hence the max-age=0 bubbles up further)
    // @todo in https://www.drupal.org/node/2559847

    // Case ten: render array that has a placeholder that is:
    // - automatically created, and automatically triggered due to max-age=0
    //   that is bubbled
    // - cacheable
    // @todo in https://www.drupal.org/node/2559847

    // Case eleven: render array that DOES NOT have a placeholder that is:
    // - NOT created, despite high cardinality cache contexts that are bubbled
    // - uncacheable
    $element_without_cache_keys = $base_element_a6;
    $expected_placeholder_render_array = $extract_placeholder_render_array($base_element_a6['placeholder']);
    $cases[] = [
      $element_without_cache_keys,
      $args,
      $expected_placeholder_render_array,
      FALSE,
      ['user'],
      [],
      [],
    ];

    // Case twelve: render array that has a placeholder that is:
    // - automatically created, and automatically triggered due to high
    //   cardinality cache contexts that are bubbled
    // - cacheable
    $element_with_cache_keys = $base_element_a6;
    $element_with_cache_keys['placeholder']['#cache']['keys'] = $keys;
    $expected_placeholder_render_array['#cache']['keys'] = $keys;
    $cases[] = [
      $element_with_cache_keys,
      $args,
      $expected_placeholder_render_array,
      $keys,
      ['user'],
      [],
      [
        '#markup' => '<p>This is a rendered placeholder!</p>',
        '#attached' => [
          'drupalSettings' => [
            'dynamic_animal' => $args[0],
          ],
        ],
        '#cache' => [
          'contexts' => ['user'],
          'tags' => [],
          'max-age' => Cache::PERMANENT,
        ],
      ],
    ];

    // Case thirteen: render array that has a placeholder that is:
    // - automatically created, and automatically triggered due to high
    //   invalidation frequency cache tags that are bubbled
    // - uncacheable
    $element_without_cache_keys = $base_element_a7;
    $expected_placeholder_render_array = $extract_placeholder_render_array($base_element_a7['placeholder']);
    $cases[] = [
      $element_without_cache_keys,
      $args,
      $expected_placeholder_render_array,
      FALSE,
      [],
      ['current-temperature'],
      [],
    ];

    // Case fourteen: render array that has a placeholder that is:
    // - automatically created, and automatically triggered due to high
    //   invalidation frequency cache tags that are bubbled
    // - cacheable
    $element_with_cache_keys = $base_element_a7;
    $element_with_cache_keys['placeholder']['#cache']['keys'] = $keys;
    $expected_placeholder_render_array['#cache']['keys'] = $keys;
    $cases[] = [
      $element_with_cache_keys,
      $args,
      $expected_placeholder_render_array,
      $keys,
      [],
      [],
      [
        '#markup' => '<p>This is a rendered placeholder!</p>',
        '#attached' => [
          'drupalSettings' => [
            'dynamic_animal' => $args[0],
          ],
        ],
        '#cache' => [
          'contexts' => [],
          'tags' => ['current-temperature'],
          'max-age' => Cache::PERMANENT,
        ],
      ],
    ];

    // Case fifteen: render array that has a placeholder that is:
    // - manually created
    // - uncacheable
    $x = $base_element_b;
    $expected_placeholder_render_array = $x['#attached']['placeholders'][(string) $generate_placeholder_markup()];
    $this->assertArrayNotHasKey('#cache', $expected_placeholder_render_array);
    $cases[] = [
      $x,
      $args,
      $expected_placeholder_render_array,
      FALSE,
      [],
      [],
      [],
    ];

    // Case sixteen: render array that has a placeholder that is:
    // - manually created
    // - cacheable
    $x = $base_element_b;
    $x['#markup'] = $placeholder_markup = $generate_placeholder_markup($keys);
    $placeholder_markup = (string) $placeholder_markup;
    $x['#attached']['placeholders'] = [
      $placeholder_markup => [
        '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
        '#cache' => ['keys' => $keys],
      ],
    ];
    $expected_placeholder_render_array = $x['#attached']['placeholders'][$placeholder_markup];
    $cases[] = [
      $x,
      $args,
      $expected_placeholder_render_array,
      $keys,
      [],
      [],
      [
        '#markup' => '<p>This is a rendered placeholder!</p>',
        '#attached' => [
          'drupalSettings' => [
            'dynamic_animal' => $args[0],
          ],
        ],
        '#cache' => [
          'contexts' => [],
          'tags' => [],
          'max-age' => Cache::PERMANENT,
        ],
      ],
    ];

    return $cases;
  }

  /**
   * Generates an element with a placeholder.
   *
   * @return array
   *   An array containing:
   *   - A render array containing a placeholder.
   *   - The context used for that #lazy_builder callback.
   */
  protected function generatePlaceholderElement() {
    $args = [$this->randomContextValue()];
    $test_element = [];
    $test_element['#attached']['drupalSettings']['foo'] = 'bar';
    $test_element['placeholder']['#cache']['keys'] = ['placeholder', 'output', 'can', 'be', 'render', 'cached', 'too'];
    $test_element['placeholder']['#cache']['contexts'] = [];
    $test_element['placeholder']['#create_placeholder'] = TRUE;
    $test_element['placeholder']['#lazy_builder'] = ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args];

    return [$test_element, $args];
  }

  /**
   * @param false|array $cid_parts
   *   The cid parts.
   * @param string[] $bubbled_cache_contexts
   *   Additional cache contexts that were bubbled when the placeholder was
   *   rendered.
   * @param array $expected_data
   *   A render array with the expected values.
   *
   * @internal
   */
  protected function assertPlaceholderRenderCache($cid_parts, array $bubbled_cache_contexts, array $expected_data): void {
    if ($cid_parts !== FALSE) {
      if ($bubbled_cache_contexts) {
        // Verify render cached placeholder.
        $cached_element = $this->memoryCache->get(implode(':', $cid_parts))->data;
        $expected_redirect_element = [
          '#cache_redirect' => TRUE,
          '#cache' => $expected_data['#cache'] + [
            'keys' => $cid_parts,
            'bin' => 'render',
          ],
        ];
        $this->assertEquals($expected_redirect_element, $cached_element, 'The correct cache redirect exists.');
      }

      // Verify render cached placeholder.
      $cached = $this->memoryCache->get(implode(':', array_merge($cid_parts, $bubbled_cache_contexts)));
      $cached_element = $cached->data;
      $this->assertEquals($expected_data, $cached_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by the placeholder being replaced.');
    }
  }

  /**
   * @covers ::render
   * @covers ::doRender
   *
   * @dataProvider providerPlaceholders
   */
  public function testUncacheableParent($element, $args, array $expected_placeholder_render_array, $placeholder_cid_parts, array $bubbled_cache_contexts, array $bubbled_cache_tags, array $placeholder_expected_render_cache_array) {
    if ($placeholder_cid_parts) {
      $this->setupMemoryCache();
    }
    else {
      $this->setUpUnusedCache();
    }

    $this->setUpRequest('GET');

    // No #cache on parent element.
    $element['#prefix'] = '<p>#cache disabled</p>';
    $output = $this->renderer->renderRoot($element);
    $this->assertSame('<p>#cache disabled</p><p>This is a rendered placeholder!</p>', (string) $output, 'Output is overridden.');
    $this->assertSame('<p>#cache disabled</p><p>This is a rendered placeholder!</p>', (string) $element['#markup'], '#markup is overridden.');
    $expected_js_settings = [
      'foo' => 'bar',
      'dynamic_animal' => $args[0],
    ];
    $this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the one added by the placeholder #lazy_builder callback exist.');
    $this->assertPlaceholderRenderCache($placeholder_cid_parts, $bubbled_cache_contexts, $placeholder_expected_render_cache_array);
  }

  /**
   * @covers ::render
   * @covers ::doRender
   * @covers \Drupal\Core\Render\RenderCache::get
   * @covers \Drupal\Core\Render\RenderCache::set
   * @covers \Drupal\Core\Render\RenderCache::createCacheID
   *
   * @dataProvider providerPlaceholders
   */
  public function testCacheableParent($test_element, $args, array $expected_placeholder_render_array, $placeholder_cid_parts, array $bubbled_cache_contexts, array $bubbled_cache_tags, array $placeholder_expected_render_cache_array) {
    $element = $test_element;
    $this->setupMemoryCache();

    $this->setUpRequest('GET');

    $token = Crypt::hashBase64(serialize($expected_placeholder_render_array));
    $placeholder_callback = $expected_placeholder_render_array['#lazy_builder'][0];
    $expected_placeholder_markup = '<drupal-render-placeholder callback="' . $placeholder_callback . '" arguments="0=' . $args[0] . '" token="' . $token . '"></drupal-render-placeholder>';
    $this->assertSame($expected_placeholder_markup, Html::normalize($expected_placeholder_markup), 'Placeholder unaltered by Html::normalize() which is used by FilterHtmlCorrector.');

    // GET request: #cache enabled, cache miss.
    $element['#cache'] = ['keys' => ['placeholder_test_GET']];
    $element['#prefix'] = '<p>#cache enabled, GET</p>';
    $output = $this->renderer->renderRoot($element);
    $this->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', (string) $output, 'Output is overridden.');
    $this->assertTrue(isset($element['#printed']), 'No cache hit');
    $this->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', (string) $element['#markup'], '#markup is overridden.');
    $expected_js_settings = [
      'foo' => 'bar',
      'dynamic_animal' => $args[0],
    ];
    $this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the one added by the placeholder #lazy_builder callback exist.');
    $this->assertPlaceholderRenderCache($placeholder_cid_parts, $bubbled_cache_contexts, $placeholder_expected_render_cache_array);

    // GET request: validate cached data.
    $cached = $this->memoryCache->get('placeholder_test_GET');
    // There are three edge cases, where the shape of the render cache item for
    // the parent (with CID 'placeholder_test_GET') is vastly different. These
    // are the cases where:
    // - the placeholder is uncacheable (because it has no #cache[keys]), and;
    // - cacheability metadata that meets auto_placeholder_conditions is bubbled
    $has_uncacheable_lazy_builder = !isset($test_element['placeholder']['#cache']['keys']) && isset($test_element['placeholder']['#lazy_builder']);
    // Edge cases: always where both bubbling of an auto-placeholdering
    // condition happens from within a #lazy_builder that is uncacheable.
    // - uncacheable + A5 (cache max-age)
    // @todo in https://www.drupal.org/node/2559847
    // - uncacheable + A6 (cache context)
    $edge_case_a6_uncacheable = $has_uncacheable_lazy_builder && $test_element['placeholder']['#lazy_builder'][0] === 'Drupal\Tests\Core\Render\PlaceholdersTest::callbackPerUser';
    // - uncacheable + A7 (cache tag)
    $edge_case_a7_uncacheable = $has_uncacheable_lazy_builder && $test_element['placeholder']['#lazy_builder'][0] === 'Drupal\Tests\Core\Render\PlaceholdersTest::callbackTagCurrentTemperature';
    // The redirect-cacheable edge case: a high-cardinality cache context is
    // bubbled from a #lazy_builder callback for an uncacheable placeholder. The
    // element containing the uncacheable placeholder has cache keys set, and
    // due to the bubbled cache contexts it creates a cache redirect.
    if ($edge_case_a6_uncacheable) {
      $cached_element = $cached->data;
      $expected_redirect = [
        '#cache_redirect' => TRUE,
        '#cache' => [
          'keys' => ['placeholder_test_GET'],
          'contexts' => ['user'],
          'tags' => [],
          'max-age' => Cache::PERMANENT,
          'bin' => 'render',
        ],
      ];
      $this->assertEquals($expected_redirect, $cached_element);
      // Follow the redirect.
      $cached_element = $this->memoryCache->get('placeholder_test_GET:' . implode(':', $bubbled_cache_contexts))->data;
      $expected_element = [
        '#markup' => '<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>',
        '#attached' => [
          'drupalSettings' => [
            'foo' => 'bar',
            'dynamic_animal' => $args[0],
          ],
        ],
        '#cache' => [
          'contexts' => $bubbled_cache_contexts,
          'tags' => [],
          'max-age' => Cache::PERMANENT,
        ],
      ];
      $this->assertEquals($expected_element, $cached_element, 'The parent is render cached with a redirect in ase a cache context is bubbled from an uncacheable child (no #cache[keys]) with a #lazy_builder.');
    }
    // The normally cacheable edge case: a high-invalidation frequency cache tag
    // is bubbled from a #lazy_builder callback for an uncacheable placeholder.
    // The element containing the uncacheable placeholder has cache keys set,
    // and also has the bubbled cache tags.
    elseif ($edge_case_a7_uncacheable) {
      $cached_element = $cached->data;
      $expected_element = [
        '#markup' => '<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>',
        '#attached' => [
          'drupalSettings' => [
            'foo' => 'bar',
            'dynamic_animal' => $args[0],
          ],
        ],
        '#cache' => [
          'contexts' => [],
          'tags' => $bubbled_cache_tags,
          'max-age' => Cache::PERMANENT,
        ],
      ];
      $this->assertEquals($expected_element, $cached_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by placeholder #lazy_builder callbacks.');
    }
    // The regular case.
    else {
      $cached_element = $cached->data;
      $expected_element = [
        '#markup' => '<p>#cache enabled, GET</p>' . $expected_placeholder_markup,
        '#attached' => [
          'drupalSettings' => [
            'foo' => 'bar',
          ],
          'placeholders' => [
            $expected_placeholder_markup => [
              '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
            ],
          ],
        ],
        '#cache' => [
          'contexts' => [],
          'tags' => $bubbled_cache_tags,
          'max-age' => Cache::PERMANENT,
        ],
      ];
      $expected_element['#attached']['placeholders'][$expected_placeholder_markup] = $expected_placeholder_render_array;
      $this->assertEquals($expected_element, $cached_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by placeholder #lazy_builder callbacks.');
    }

    // GET request: #cache enabled, cache hit.
    $element = $test_element;
    $element['#cache'] = ['keys' => ['placeholder_test_GET']];
    $element['#prefix'] = '<p>#cache enabled, GET</p>';
    $output = $this->renderer->renderRoot($element);
    $this->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', (string) $output, 'Output is overridden.');
    $this->assertFalse(isset($element['#printed']), 'Cache hit');
    $this->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', (string) $element['#markup'], '#markup is overridden.');
    $expected_js_settings = [
      'foo' => 'bar',
      'dynamic_animal' => $args[0],
    ];
    $this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the one added by the placeholder #lazy_builder callback exist.');
  }

  /**
   * @covers ::render
   * @covers ::doRender
   * @covers \Drupal\Core\Render\RenderCache::get
   * @covers ::replacePlaceholders
   *
   * @dataProvider providerPlaceholders
   */
  public function testCacheableParentWithPostRequest($test_element, $args) {
    $this->setUpUnusedCache();

    // Verify behavior when handling a non-GET request, e.g. a POST request:
    // also in that case, placeholders must be replaced.
    $this->setUpRequest('POST');

    // POST request: #cache enabled, cache miss.
    $element = $test_element;
    $element['#cache'] = ['keys' => ['placeholder_test_POST']];
    $element['#prefix'] = '<p>#cache enabled, POST</p>';
    $output = $this->renderer->renderRoot($element);
    $this->assertSame('<p>#cache enabled, POST</p><p>This is a rendered placeholder!</p>', (string) $output, 'Output is overridden.');
    $this->assertTrue(isset($element['#printed']), 'No cache hit');
    $this->assertSame('<p>#cache enabled, POST</p><p>This is a rendered placeholder!</p>', (string) $element['#markup'], '#markup is overridden.');
    $expected_js_settings = [
      'foo' => 'bar',
      'dynamic_animal' => $args[0],
    ];
    $this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the one added by the placeholder #lazy_builder callback exist.');

    // Even when the child element's placeholder is cacheable, it should not
    // generate a render cache item.
    $this->assertPlaceholderRenderCache(FALSE, [], []);
  }

  /**
   * @covers ::render
   * @covers ::doRender
   * @covers \Drupal\Core\Render\RenderCache::get
   * @covers \Drupal\Core\Render\PlaceholderingRenderCache::get
   * @covers \Drupal\Core\Render\PlaceholderingRenderCache::set
   * @covers ::replacePlaceholders
   *
   * @dataProvider providerPlaceholders
   */
  public function testPlaceholderingDisabledForPostRequests($test_element, $args) {
    $this->setUpUnusedCache();
    $this->setUpRequest('POST');

    $element = $test_element;

    // Render without replacing placeholders, to allow this test to see which
    // #attached[placeholders] there are, if any.
    $this->renderer->executeInRenderContext(new RenderContext(), function () use (&$element) {
      return $this->renderer->render($element);
    });
    // Only test cases where the placeholders have been specified manually are
    // allowed to have placeholders. This means that of the different situations
    // listed in providerPlaceholders(), only type B can have attached
    // placeholders. Everything else, whether:
    // 1. manual placeholdering
    // 2. automatic placeholdering via already-present cacheability metadata
    // 3. automatic placeholdering via bubbled cacheability metadata
    // All three of those should NOT result in placeholders.
    if (!isset($test_element['#attached']['placeholders'])) {
      $this->assertFalse(isset($element['#attached']['placeholders']), 'No placeholders created.');
    }
  }

  /**
   * Tests a placeholder that adds another placeholder.
   *
   * E.g. when rendering a node in a placeholder the rendering of that node
   * needs a placeholder of its own to be executed (to render the node links).
   *
   * @covers ::render
   * @covers ::doRender
   * @covers ::replacePlaceholders
   */
  public function testRecursivePlaceholder() {
    $args = [$this->randomContextValue()];
    $element = [];
    $element['#create_placeholder'] = TRUE;
    $element['#lazy_builder'] = ['Drupal\Tests\Core\Render\RecursivePlaceholdersTest::callback', $args];

    $output = $this->renderer->renderRoot($element);
    $this->assertEquals('<p>This is a rendered placeholder!</p>', $output, 'The output has been modified by the indirect, recursive placeholder #lazy_builder callback.');
    $this->assertSame((string) $element['#markup'], '<p>This is a rendered placeholder!</p>', '#markup is overridden by the indirect, recursive placeholder #lazy_builder callback.');
    $expected_js_settings = [
      'dynamic_animal' => $args[0],
    ];
    $this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified by the indirect, recursive placeholder #lazy_builder callback.');
  }

  /**
   * @covers ::render
   * @covers ::doRender
   */
  public function testInvalidLazyBuilder() {
    $element = [];
    $element['#lazy_builder'] = '\Drupal\Tests\Core\Render\PlaceholdersTest::callback';

    $this->expectException(\AssertionError::class);
    $this->expectExceptionMessage('The #lazy_builder property must have an array as a value.');
    $this->renderer->renderRoot($element);
  }

  /**
   * @covers ::render
   * @covers ::doRender
   */
  public function testInvalidLazyBuilderArguments() {
    $element = [];
    $element['#lazy_builder'] = ['\Drupal\Tests\Core\Render\PlaceholdersTest::callback', 'arg1', 'arg2'];

    $this->expectException(\AssertionError::class);
    $this->expectExceptionMessage('The #lazy_builder property must have an array as a value, containing two values: the callback, and the arguments for the callback.');
    $this->renderer->renderRoot($element);
  }

  /**
   * @covers ::render
   * @covers ::doRender
   *
   * @see testNonScalarLazybuilderCallbackContext
   */
  public function testScalarLazybuilderCallbackContext() {
    $element = [];
    $element['#lazy_builder'] = [
      '\Drupal\Tests\Core\Render\PlaceholdersTest::callback',
      [
        'string' => 'foo',
        'bool' => TRUE,
        'int' => 1337,
        'float' => 3.14,
        'null' => NULL,
      ],
    ];

    $result = $this->renderer->renderRoot($element);
    $this->assertInstanceOf('\Drupal\Core\Render\Markup', $result);
    $this->assertEquals('<p>This is a rendered placeholder!</p>', (string) $result);
  }

  /**
   * @covers ::render
   * @covers ::doRender
   */
  public function testNonScalarLazybuilderCallbackContext() {
    $element = [];
    $element['#lazy_builder'] = [
      '\Drupal\Tests\Core\Render\PlaceholdersTest::callback',
      [
        'string' => 'foo',
        'bool' => TRUE,
        'int' => 1337,
        'float' => 3.14,
        'null' => NULL,
        // array is not one of the scalar types.
        'array' => ['hi!'],
      ],
    ];

    $this->expectException(\AssertionError::class);
    $this->expectExceptionMessage("A #lazy_builder callback's context may only contain scalar values or NULL.");
    $this->renderer->renderRoot($element);
  }

  /**
   * @covers ::render
   * @covers ::doRender
   */
  public function testChildrenPlusBuilder() {
    $element = [];
    $element['#lazy_builder'] = ['Drupal\Tests\Core\Render\RecursivePlaceholdersTest::callback', []];
    $element['child_a']['#markup'] = 'Oh hai!';
    $element['child_b']['#markup'] = 'kthxbai';

    $this->expectException(\AssertionError::class);
    $this->expectExceptionMessage('When a #lazy_builder callback is specified, no children can exist; all children must be generated by the #lazy_builder callback. You specified the following children: child_a, child_b.');
    $this->renderer->renderRoot($element);
  }

  /**
   * @covers ::render
   * @covers ::doRender
   */
  public function testPropertiesPlusBuilder() {
    $element = [];
    $element['#lazy_builder'] = ['Drupal\Tests\Core\Render\RecursivePlaceholdersTest::callback', []];
    $element['#llama'] = '#awesome';
    $element['#piglet'] = '#cute';

    $this->expectException(\AssertionError::class);
    $this->expectExceptionMessage('When a #lazy_builder callback is specified, no properties can exist; all properties must be generated by the #lazy_builder callback. You specified the following properties: #llama, #piglet.');
    $this->renderer->renderRoot($element);
  }

  /**
   * @covers ::render
   * @covers ::doRender
   */
  public function testCreatePlaceholderPropertyWithoutLazyBuilder() {
    $element = [];
    $element['#create_placeholder'] = TRUE;

    $this->expectException(\LogicException::class);
    $this->expectExceptionMessage('When #create_placeholder is set, a #lazy_builder callback must be present as well.');
    $this->renderer->renderRoot($element);
  }

  /**
   * Tests that an error is thrown if a lazy builder doesn't return an array.
   */
  public function testNonArrayReturnFromLazyBuilder(): void {
    $element = [
      '#lazy_builder' => ['\Drupal\Tests\Core\Render\PlaceholdersTest::callbackNonArrayReturn', []],
    ];
    $this->expectException('AssertionError');
    $this->expectExceptionMessage("#lazy_builder callbacks must return a valid renderable array, got boolean from \Drupal\Tests\Core\Render\PlaceholdersTest::callbackNonArrayReturn");
    $this->renderer->renderRoot($element);
  }

  /**
   * Create an element with a child and subchild. Each element has the same
   * #lazy_builder callback, but with different contexts. They don't modify
   * markup, only attach additional drupalSettings.
   *
   * @covers ::render
   * @covers ::doRender
   * @covers \Drupal\Core\Render\RenderCache::get
   * @covers ::replacePlaceholders
   */
  public function testRenderChildrenPlaceholdersDifferentArguments() {
    $this->setUpRequest();
    $this->setupMemoryCache();
    $this->cacheContextsManager->expects($this->any())
      ->method('convertTokensToKeys')
      ->willReturnArgument(0);
    $this->controllerResolver->expects($this->any())
      ->method('getControllerFromDefinition')
      ->willReturnArgument(0);
    $this->setupThemeManagerForDetails();

    $args_1 = ['foo', TRUE];
    $args_2 = ['bar', TRUE];
    $args_3 = ['baz', TRUE];
    $test_element = $this->generatePlaceholdersWithChildrenTestElement($args_1, $args_2, $args_3);

    $element = $test_element;
    $output = $this->renderer->renderRoot($element);
    $expected_output = <<<HTML
<details>
  <summary>Parent</summary>
  <div class="details-wrapper"><details>
  <summary>Child</summary>
  <div class="details-wrapper">Subchild</div>
</details></div>
</details>
HTML;
    $this->assertSame($expected_output, (string) $output, 'Output is not overridden.');
    $this->assertTrue(isset($element['#printed']), 'No cache hit');
    $this->assertSame($expected_output, (string) $element['#markup'], '#markup is not overridden.');
    $expected_js_settings = [
      'foo' => 'bar',
      'dynamic_animal' => [$args_1[0] => TRUE, $args_2[0] => TRUE, $args_3[0] => TRUE],
    ];
    $this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the ones added by each placeholder #lazy_builder callback exist.');

    // GET request: validate cached data.
    $cached_element = $this->memoryCache->get('simpletest:renderer:children_placeholders')->data;
    $expected_element = [
      '#attached' => [
        'drupalSettings' => [
          'foo' => 'bar',
        ],
        'placeholders' => [
          'parent-x-parent' => [
            '#lazy_builder' => [__NAMESPACE__ . '\\PlaceholdersTest::callback', $args_1],
          ],
          'child-x-child' => [
            '#lazy_builder' => [__NAMESPACE__ . '\\PlaceholdersTest::callback', $args_2],
          ],
          'subchild-x-subchild' => [
            '#lazy_builder' => [__NAMESPACE__ . '\\PlaceholdersTest::callback', $args_3],
          ],
        ],
      ],
      '#cache' => [
        'contexts' => [],
        'tags' => [],
        'max-age' => Cache::PERMANENT,
      ],
    ];

    // Verify that the correct data is cached: the stored #markup is not
    // affected by placeholder #lazy_builder callbacks.
    $dom = Html::load($cached_element['#markup']);
    $xpath = new \DOMXPath($dom);
    $this->assertNotEmpty($xpath->query('//details/summary[text()="Parent"]')->length);
    $this->assertNotEmpty($xpath->query('//details/div[@class="details-wrapper"]/details/summary[text()="Child"]')->length);
    $this->assertNotEmpty($xpath->query('//details/div[@class="details-wrapper"]/details/div[@class="details-wrapper" and text()="Subchild"]')->length);

    // Remove markup because it's compared above in the xpath.
    unset($cached_element['#markup']);
    $this->assertEquals($cached_element, $expected_element, 'The correct data is cached: the stored #attached properties are not affected by placeholder #lazy_builder callbacks.');

    // GET request: #cache enabled, cache hit.
    $element = $test_element;
    $output = $this->renderer->renderRoot($element);
    $this->assertSame($expected_output, (string) $output, 'Output is not overridden.');
    $this->assertFalse(isset($element['#printed']), 'Cache hit');
    $this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the ones added by each placeholder #lazy_builder callback exist.');

    // Use the exact same element, but now unset #cache; ensure we get the same
    // result.
    unset($test_element['#cache']);
    $element = $test_element;
    $output = $this->renderer->renderRoot($element);
    $this->assertSame($expected_output, (string) $output, 'Output is not overridden.');
    $this->assertSame($expected_output, (string) $element['#markup'], '#markup is not overridden.');
    $this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the ones added by each #lazy_builder callback exist.');
  }

  /**
   * Generates an element with placeholders at 3 levels.
   *
   * @param array $args_1
   *   The arguments for the placeholder at level 1.
   * @param array $args_2
   *   The arguments for the placeholder at level 2.
   * @param array $args_3
   *   The arguments for the placeholder at level 3.
   *
   * @return array
   *   The generated render array for testing.
   */
  protected function generatePlaceholdersWithChildrenTestElement(array $args_1, array $args_2, array $args_3) {
    $test_element = [
      '#type' => 'details',
      '#cache' => [
        'keys' => ['simpletest', 'renderer', 'children_placeholders'],
      ],
      '#title' => 'Parent',
      '#attached' => [
        'drupalSettings' => [
          'foo' => 'bar',
        ],
        'placeholders' => [
          'parent-x-parent' => [
            '#lazy_builder' => [__NAMESPACE__ . '\\PlaceholdersTest::callback', $args_1],
          ],
        ],
      ],
    ];
    $test_element['child'] = [
      '#type' => 'details',
      '#attached' => [
        'placeholders' => [
          'child-x-child' => [
            '#lazy_builder' => [__NAMESPACE__ . '\\PlaceholdersTest::callback', $args_2],
          ],
        ],
      ],
      '#title' => 'Child',
    ];
    $test_element['child']['subchild'] = [
      '#attached' => [
        'placeholders' => [
          'subchild-x-subchild' => [
            '#lazy_builder' => [__NAMESPACE__ . '\\PlaceholdersTest::callback', $args_3],
          ],
        ],
      ],
      '#markup' => 'Subchild',
    ];
    return $test_element;
  }

  /**
   * @return \Drupal\Core\Theme\ThemeManagerInterface|\PHPUnit\Framework\MockObject\Builder\InvocationMocker
   */
  protected function setupThemeManagerForDetails() {
    return $this->themeManager->expects($this->any())
      ->method('render')
      ->willReturnCallback(function ($theme, array $vars) {
        $output = <<<'EOS'
<details>
  <summary>{{ title }}</summary>
  <div class="details-wrapper">{{ children }}</div>
</details>
EOS;
        $output = str_replace([
          '{{ title }}',
          '{{ children }}',
        ], [$vars['#title'], $vars['#children']], $output);
        return $output;
      });
  }

}

/**
 * @see \Drupal\Tests\Core\Render\RendererPlaceholdersTest::testRecursivePlaceholder()
 */
class RecursivePlaceholdersTest implements TrustedCallbackInterface {

  /**
   * #lazy_builder callback; bubbles another placeholder.
   *
   * @param string $animal
   *   An animal.
   *
   * @return array
   *   A renderable array.
   */
  public static function callback($animal) {
    return [
      'another' => [
        '#create_placeholder' => TRUE,
        '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', [$animal]],
      ],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public static function trustedCallbacks() {
    return ['callback'];
  }

}

Youez - 2016 - github.com/yon3zu
LinuXploit