https://www.twisterrob.net/TWiStErRob2023-10-21T00:00:00+00:00Home for all things about and by Róbert Papp (TWiStErRob).Róbert Papp (TWiStErRob)info@twisterrob.nethttps://twisterrob.net/Jekyllhttps://www.twisterrob.net/blog/2023/10/sqlite-unicode61-remove-diacritics-2.htmlAndroid SQLite FTS4 tokenize=unicode61 remove_diacritics=22023-10-21T00:00:00+00:00It was too good to be true to begin with!<p><em>Android developer</em> wants to create a quick full text search for an international audience with case-insensitivity.<!--more--></p>
<h2 id="tldr">TL;DR</h2>
<p>See the <a href="#summary-">Summary</a> section below.</p>
<div id="toc" class="panel radius">
<h2 class="no_toc" id="table-of-contents">Table of Contents</h2>
<ul id="markdown-toc">
<li><a href="#tldr" id="markdown-toc-tldr">TL;DR</a></li>
<li><a href="#the-high-of-feasibility" id="markdown-toc-the-high-of-feasibility">The High of Feasibility</a></li>
<li><a href="#testing-a-proof-of-concept" id="markdown-toc-testing-a-proof-of-concept">Testing a Proof of Concept</a></li>
<li><a href="#compassion" id="markdown-toc-compassion">Compassion</a></li>
<li><a href="#reproducer" id="markdown-toc-reproducer">Reproducer</a></li>
<li><a href="#in-depth-research" id="markdown-toc-in-depth-research">In Depth Research</a></li>
<li><a href="#summary-" id="markdown-toc-summary-">Summary </a></li>
<li><a href="#conclusion" id="markdown-toc-conclusion">Conclusion</a></li>
</ul>
</div>
<h2 id="the-high-of-feasibility">The High of Feasibility</h2>
<p><em>Android developer</em> searches a bit and finds SQLite, FTS4 and <code class="language-text highlighter-rouge">unicode61</code> as potential solution.</p>
<p>The <a href="https://www.sqlite.org/fts3.html">FTS4 documentation</a> reads as follows:</p>
<blockquote>
<p>FTS4 is an enhancement to FTS3.<br />
FTS3 has been available since SQLite version 3.5.0 (2007-09-04)<br />
The enhancements for FTS4 were added with SQLite version 3.7.4 (2010-12-07).<br />
[…]<br />
The “unicode61” tokenizer is available beginning with SQLite version 3.7.13 (2012-06-11).</p>
</blockquote>
<p>Quick check of <a href="https://developer.android.com/reference/android/database/sqlite/package-summary">Android SQLite versions</a> reveals the following table:</p>
<table>
<thead>
<tr>
<th>Android API</th>
<th>SQLite Version</th>
<th>Comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>API 1</td>
<td>3.4</td>
<td> </td>
</tr>
<tr>
<td>API 3</td>
<td>3.5</td>
<td>FTS3 from this point onwards.</td>
</tr>
<tr>
<td>API 8</td>
<td>3.6</td>
<td> </td>
</tr>
<tr>
<td>API 11</td>
<td>3.7</td>
<td>FTS4 was added somewhere here.</td>
</tr>
<tr>
<td>API 21</td>
<td>3.8</td>
<td>FTS4 and <code class="language-text highlighter-rouge">unicode61</code> definitely from this point onwards.</td>
</tr>
<tr>
<td>API 24</td>
<td>3.9</td>
<td> </td>
</tr>
<tr>
<td>API 26</td>
<td>3.18</td>
<td> </td>
</tr>
<tr>
<td>API 27</td>
<td>3.19</td>
<td> </td>
</tr>
<tr>
<td>API 28</td>
<td>3.22</td>
<td> </td>
</tr>
<tr>
<td>API 30</td>
<td>3.28</td>
<td> </td>
</tr>
<tr>
<td>API 31</td>
<td>3.32</td>
<td> </td>
</tr>
</tbody>
</table>
<p>Let’s say that the app under development has an “old” <code class="language-text highlighter-rouge">minSdk = 21</code> which covers 99.34% of the market in 2023<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. This is great, this means we can use FTS4 for the app, no restrictions. Quick further check of <a href="https://stackoverflow.com/a/4377116/253468">StackOverflow: Version of SQLite used in Android?</a> reveals the exact version we could expect from API 21 is 3.8.6. Further check of the <a href="https://www.sqlite.org/releaselog/3_8_6.html">release notes</a> shows:</p>
<blockquote>
<p>The unicode61 tokenizer is now included in FTS4 by default.</p>
</blockquote>
<p>Such, great, news! Feasibility confirmed, let continue <a href="https://www.sqlite.org/fts3.html">reading the docs</a> and find the option to remove diacritics (e.g. accents, which makes the search a little bit more dynamic in ways I won’t go into detail here.):</p>
<blockquote>
<p>The remove_diacritics option may be set to “0”, “1” or “2”. The default value is “1”. […]<br />
This is technically a bug […]<br />
If this option is set to “2”, then diacritics are correctly removed from all Latin characters.</p>
</blockquote>
<p>OK, so the default behavior is bugged in some cases<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>, let’s just set the option to <code class="language-text highlighter-rouge">2</code> to ensure the best behavior for an international audience.</p>
<h2 id="testing-a-proof-of-concept">Testing a Proof of Concept</h2>
<p>So, now equipped with a very simple SQL statement based on all the above documentation:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">CREATE</span> <span class="n">VIRTUAL</span> <span class="k">TABLE</span> <span class="k">Search</span> <span class="k">USING</span> <span class="n">FTS4</span> <span class="p">(</span>
<span class="n">tokenize</span><span class="o">=</span><span class="n">unicode61</span> <span class="s1">'remove_diacritics=2'</span><span class="p">,</span>
<span class="n">content</span>
<span class="p">);</span>
</code></pre></div></div>
<p>let’s try this out. I was using the latest emulator API 34, and it was working fine. Then I tried API 21 and got greeted with</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>android.database.sqlite.SQLiteException: unknown tokenizer (code 1)
at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:734)
at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:754)
at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:64)
at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1676)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1605)
</code></pre></div></div>
<p>Uhm, OK, this shouldn’t happen according to the version checks I did earlier, right? <code class="language-text highlighter-rouge">unicode61</code> was available much earlier, and is now included by default too. What’s going on?</p>
<h2 id="compassion">Compassion</h2>
<p>Failing to make it work, I turned to our big G friend to find some answers.</p>
<p>My first try to search for the error message <code class="language-text highlighter-rouge">SQLiteException: unknown tokenizer (code 1)</code> pretty much failed, as I only found false positives which were a similar error showing me how “icu” and “unicode61” tokenizers were not found. These seemed like proper errors where the tokenizer was simply not available.</p>
<p>On to more direct search based on what I knew <code class="language-text highlighter-rouge">fts4 unicode61 remove_diacritics</code> also gave me no usable results, so I went back to try an exact search <code class="language-text highlighter-rouge">"SQLiteException: unknown tokenizer (code 1)"</code> which yielded a Bingo! result at <a href="https://stackoverflow.com/q/72807615/253468">Unknown tokenizer - TOKENIZER_UNICODE61</a> which was exactly the same problem. I was glad to find some info, but there were no answers, just guessing.</p>
<p>I also tried <code class="language-text highlighter-rouge">android "unicode61" "remove_diacritics"</code> which lead me to find <a href="https://github.com/UweTrottmann/SeriesGuide/issues/673">Uwe’s issue</a> where he apparently also had a similar issue at first, but in the end he just went with <code class="language-text highlighter-rouge">remove_diacritics=0</code>.</p>
<p>I wasn’t satisfied with finding only questions, without knowing why it’s not possible. Luckily the above references gave me some ideas, so I started researching deeper.</p>
<h2 id="reproducer">Reproducer</h2>
<p>At this point I knew I needed more info: what is failing exactly and where? So I went on to create a small standalone project and see what’s possible.</p>
<p>I tested variations of <code class="language-text highlighter-rouge">FTS3</code>/<code class="language-text highlighter-rouge">FTS4</code>/<code class="language-text highlighter-rouge">FTS5</code> with <code class="language-text highlighter-rouge">tokenize=simple|porter|icu|unicode61</code> and all possible <code class="language-text highlighter-rouge">remove_diacritics=*</code> values and executed this on all relevant API levels (21-34).</p>
<p>The results (see <a href="https://github.com/TWiStErRob/repros/tree/main/android/sqlite-tokenizer-availability">project for test and CI code</a>):</p>
<ul>
<li>FTS5 is not supported on Android at all.</li>
<li>Almost everything in FTS3 and FTS4 works on all versions,
except the <code class="language-text highlighter-rouge">tokenize=unicode61 'remove_diacritics=2'</code> combination I wanted,
which throws up on API 21-29:
<div class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>android.database.sqlite.SQLiteException: unknown tokenizer (code 1 SQLITE_ERROR)
</code></pre></div> </div>
<p>and works from 30 onwards.</p>
</li>
</ul>
<p>I would like to call out a few things here:</p>
<ol>
<li><code class="language-text highlighter-rouge">tokenize=unicode61 'remove_diacritics=0'</code> and <code class="language-text highlighter-rouge">tokenize=unicode61 'remove_diacritics=1'</code> works, but <code class="language-text highlighter-rouge">tokenize=unicode61 'remove_diacritics=2'</code> doesn’t.</li>
<li>The same problem occurs with <code class="language-text highlighter-rouge">FTS3</code> and <code class="language-text highlighter-rouge">FTS4</code>.</li>
<li>API level 30 and onwards works, so there must be something with that version. <sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup></li>
</ol>
<h2 id="in-depth-research">In Depth Research</h2>
<p>I wanted to answer the question: why does <code class="language-text highlighter-rouge">tokenize=unicode61 'remove_diacritics=2'</code> only work on API 30 and above, if <code class="language-text highlighter-rouge">FTS4</code> and <code class="language-text highlighter-rouge">unicode61</code> already works from API 21. <sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup></p>
<p>Let’s start with what we already know from <a href="https://developer.android.com/reference/android/database/sqlite/package-summary">Android’s SQLite package</a>:</p>
<table>
<thead>
<tr>
<th>Android API</th>
<th>SQLite Version</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>API 21</td>
<td>3.8</td>
<td>fails</td>
</tr>
<tr>
<td>…</td>
<td>…</td>
<td>fails</td>
</tr>
<tr>
<td>API 28</td>
<td>3.22</td>
<td>fails</td>
</tr>
<tr>
<td>API 29</td>
<td>3.22</td>
<td>fails</td>
</tr>
<tr>
<td>API 30</td>
<td>3.28</td>
<td>works</td>
</tr>
</tbody>
</table>
<p>From here I’ve reviewed all the SQLite release notes between 3.22 and 3.28 looking for <code class="language-text highlighter-rouge">FTS</code>/tokenizer/<code class="language-text highlighter-rouge">unicode61</code> keywords.
There were 3 release notes that contained these, but the big reveal was in <a href="https://sqlite.org/releaselog/3_27_0.html">3.27.0</a>:</p>
<blockquote>
<p>Added the <code class="language-text highlighter-rouge">remove_diacritics=2</code> option to FTS3 and FTS5.</p>
</blockquote>
<p>So this confirms why it started to work in API 30.</p>
<p>To double-check this finding, I looked at the FTS3 documentation
<a href="https://web.archive.org/web/20190206145549/https://www.sqlite.org/fts3.html#tokenizer:~:text=By%20default%2C%20%22unicode61,unicode61%20%22remove_diacritics%3D0%22">before</a>
and
<a href="https://web.archive.org/web/20190324224724/https://www.sqlite.org/fts3.html#tokenizer:~:text=By%20default%2C%20%22unicode61,all%20Latin%20characters.">after</a>
that release, and found that the sentence about <code class="language-text highlighter-rouge">remove_diacritics=2</code> was added after 7th February 2019 which is exactly the release date of SQLite <code class="language-text highlighter-rouge">3.27.0</code>.</p>
<h2 id="summary-">Summary <sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup></h2>
<p>Android API 30 (including SQLite <code class="language-text highlighter-rouge">3.28</code>) is the first one that supports <code class="language-text highlighter-rouge">remove_diacritics=2</code>, which was added in SQLite <code class="language-text highlighter-rouge">3.27.0</code>.</p>
<table>
<thead>
<tr>
<th>Date</th>
<th>What happened?</th>
</tr>
</thead>
<tbody>
<tr>
<td>2007-09-04</td>
<td><a href="https://sqlite.org/releaselog/3_5_0.html">SQLite 3.5.0</a> was released with FTS3 (no mention in release notes, but in documentation).</td>
</tr>
<tr>
<td>2010-12-07</td>
<td><a href="https://sqlite.org/releaselog/3_7_4.html">SQLite 3.7.4</a> was released with FTS4.</td>
</tr>
<tr>
<td>2012-06-11</td>
<td><a href="https://sqlite.org/releaselog/3_7_13.html">SQLite 3.7.13</a> was released with the <code class="language-text highlighter-rouge">unicode61</code> tokenizer.</td>
</tr>
<tr>
<td>2014-08-15</td>
<td><a href="https://sqlite.org/releaselog/3_8_6.html">SQLite 3.8.6</a> was released where the <code class="language-text highlighter-rouge">unicode61</code> tokenizer is included in FTS4 by default.</td>
</tr>
<tr>
<td>2014-11</td>
<td><a href="https://developer.android.com/reference/kotlin/android/os/Build.VERSION_CODES#lollipop">Android 5 / L / API 21</a> was released <a href="https://developer.android.com/reference/android/database/sqlite/package-summary">including SQLite 3.8</a><a href="https://stackoverflow.com/a/4377116/253468">.6</a>.</td>
</tr>
<tr>
<td>2018-01-22</td>
<td><a href="https://sqlite.org/releaselog/3_22_0.html">SQLite 3.22.0</a> was released.</td>
</tr>
<tr>
<td>2018-08</td>
<td><a href="https://developer.android.com/reference/kotlin/android/os/Build.VERSION_CODES#p">Android 9 / P / API 28</a> was released <a href="https://developer.android.com/reference/android/database/sqlite/package-summary">including SQLite 3.22</a>.</td>
</tr>
<tr>
<td>2019-02-06</td>
<td><a href="https://archive.org/">archive.org</a> took a snapshot <a href="https://web.archive.org/web/20190206145549/https://www.sqlite.org/fts3.html#tokenizer:~:text=By%20default%2C%20%22unicode61,unicode61%20%22remove_diacritics%3D0%22">before</a> the release.</td>
</tr>
<tr>
<td>2019-02-07</td>
<td><a href="https://sqlite.org/releaselog/3_27_0.html">SQLite 3.27.0</a> was released including support for <code class="language-text highlighter-rouge">remove_diacritics=2</code></td>
</tr>
<tr>
<td>2019-03-24</td>
<td><a href="https://archive.org/">archive.org</a> took a snapshot of the <a href="https://web.archive.org/web/20190324224724/https://www.sqlite.org/fts3.html#tokenizer:~:text=By%20default%2C%20%22unicode61,all%20Latin%20characters.">FTS3 documentation including <code class="language-text highlighter-rouge">remove_diacritics=2</code> mention</a>.</td>
</tr>
<tr>
<td>2019-04-16</td>
<td><a href="https://sqlite.org/releaselog/3_28_0.html">SQLite 3.28.0</a> was released.</td>
</tr>
<tr>
<td>2020-09</td>
<td><a href="https://developer.android.com/reference/kotlin/android/os/Build.VERSION_CODES#r">Android 11 / R / API 30</a> was released <a href="https://developer.android.com/reference/android/database/sqlite/package-summary">including SQLite 3.28</a>.</td>
</tr>
<tr>
<td>2023-…</td>
<td>Android developers are reading the <a href="https://www.sqlite.org/fts3.html">latest version of the FTS documentation</a>.</td>
</tr>
</tbody>
</table>
<h2 id="conclusion">Conclusion</h2>
<ol>
<li>When it comes to Android, we need to be more aware of versioning and history.<br />
After 10 years I’m still not used to this, as showcased by this above story.
SQLite team is wonderful at keeping a version history, <a href="https://archive.org/">archive.org</a> is a godsend when it comes to time travel.</li>
<li>Read the error message, and write good error messages!<br />
Think about how much difference it had made if the error was:
<div class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>SQLiteException: unknown tokenizer option value 2 for remove_diacritics
</code></pre></div> </div>
</li>
<li>Test assumptions if possible.<br />
Luckily I tested on my <code class="language-text highlighter-rouge">minSdk</code> version before releasing this time and found the problem early.</li>
</ol>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>You can substitute many versions here for a few coming years. According to <a href="https://apilevels.com/">apilevels.com</a> which sources data from <a href="https://gs.statcounter.com/android-version-market-share/mobile-tablet/worldwide">GlobalStats</a>. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Foreshadowing: At this point something was fishy to me: using the first SQLite version where FTS4 was available had “historical reasons” already. But I dismissed feeling on account of the high of the great feasibility news. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>I set out to find and document the exact problem here, the end result is what you’re reading right now. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p>In hindsight the answer is very simple, but finding it wasn’t that trivial. <a href="#fnref:4" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:5" role="doc-endnote">
<p>Research based on <a href="https://developer.android.com/reference/kotlin/android/os/Build.VERSION_CODES">Android Release dates</a>, <a href="https://developer.android.com/reference/android/database/sqlite/package-summary">Android embedded SQLite versions</a>, <a href="https://www.sqlite.org/fts3.html">SQLite FTS3 and FTS4 documentation</a> and its <a href="https://web.archive.org/web/20190207000000*/https://www.sqlite.org/fts3.html">historical snapshots on archive.org</a>, <a href="https://sqlite.org/chronology.html">SQLite release dates</a> and <a href="https://sqlite.org/changes.html">release notes</a>. <a href="#fnref:5" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
2023-10-21T00:00:00+00:00https://www.twisterrob.net/blog/2022/03/recommended-reading.htmlRecommended reading2022-03-17T00:00:00+00:00Inspiring content, see inside!<p>Collection of things I’ve read during the years, and I keep referring back to them.<!--more--> I either agree with their content, or they have material I can refer back to. These articles have made me a better software engineer, colleague or just straight up person.</p>
<p>Let’s start with a quick baseline that should be(come) common sense:</p>
<ul>
<li><a href="https://nohello.net/">nohello: please don’t say just hello in chat</a><br />
(probably the original version: https://www.nohello.com/)</li>
<li><a href="https://dontasktoask.com/">Don’t ask to ask</a></li>
<li><a href="https://xyproblem.info">The XY Problem</a></li>
<li><a href="https://www.zacsweers.dev/you-are-not-blocked/">Zac Sweers: You are not blocked</a></li>
</ul>
<p>The pages are in no particular order, just randomly thrown here.
If I get inspiration I might write some actual recommendations, until then, just read on!</p>
<ul>
<li><a href="https://ben.balter.com/2016/07/21/removing-a-feature-is-a-feature/">Ben Balter: Removing a feature is a feature</a></li>
<li><a href="https://nedbatchelder.com/blog/201401/comments_should_be_sentences.html">Ned Batchelder: Comments should be sentences</a></li>
<li><a href="https://coderwall.com/p/7aymfa/please-oh-please-use-git-pull-rebase">Krzysztof Hasiński: Please, oh please, use git pull –rebase</a></li>
<li><a href="https://blog.jetbrains.com/idea/2017/08/code-smells-null/">Trisha Gee: Code Smells series from IntelliJ Blog</a><br />
(⚠ The series is a long read, but well worth the time!)</li>
<li><a href="https://leconjugueur.lefigaro.fr/ukponctuationtypographie.php">French vs. English punctuation rules (the French perspective)</a></li>
<li><a href="https://adamtuttle.codes/blog/2021/tabs-vs-spaces-its-an-accessibility-issue/">Tabs vs. Spaces: It’s an Accessibility Issue</a></li>
<li><a href="https://developer.android.com/studio/write/lint"><del>Android Lint User Guide</del></a> → <a href="https://googlesamples.github.io/android-custom-lint-rules/book.md.html">Android Lint Documentation</a></li>
<li><a href="https://www.youtube.com/watch?v=lIFE7h3m40U">Tom Scott: The Art of the Bodge</a></li>
<li><a href="https://www.youtube.com/watch?v=2ffR1h4BejQ">Marcin Moskala: Kotlin not-to-do list (after the book Effective Kotlin)</a></li>
<li><a href="https://css-tricks.com/front-end-test-element-locators/">Description of test-only, contextual and absolute selectors</a></li>
<li><a href="https://blog.jetbrains.com/kotlin/2020/09/the-dark-secrets-of-fast-compilation-for-kotlin/">The Dark Secrets of Fast Compilation for Kotlin</a></li>
<li><a href="https://jakewharton.com/build-on-latest-java-test-through-lowest-java/">Jake Wharton: Build on latest Java, test through lowest Java</a></li>
<li><a href="https://ionathan.ch/2022/04/09/angzarr.html">Jonathan Chan: U+237C ⍼ RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW</a></li>
</ul>
2022-03-17T00:00:00+00:00https://www.twisterrob.net/blog/2019/03/practical-jfixture.htmlPractical JFixture2019-03-10T00:00:00+00:00Magic one-liner with powerful behaviour<p>Tests need data, let’s see how can we create them using <a href="https://github.com/FlexTradeUKLtd/jfixture">JFixture</a>.<!--more-->
In this article we’ll go through some practical usage patterns of JFixture, and compare those to some other alternatives.</p>
<h2 id="introduction">Introduction</h2>
<blockquote>
<p>JFixture is a Java library to assist in the writing of Unit Tests, particularly when following Test Driven Development. It generates types based on the concept of ‘constrained non-determinism’, which is an implementation of the <a href="https://xunitpatterns.com/Generated%20Value.html">Generated Value</a> xUnit test pattern.
<cite><a href="https://github.com/FlexTradeUKLtd/jfixture">JFixture README.md</a></cite></p>
</blockquote>
<p>In practice this means, is that JFixture can create any data object with very little developer effort, here’s an example:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">private</span> <span class="n">val</span> <span class="n">fixture</span> <span class="o">=</span> <span class="nc">JFixture</span><span class="o">()</span>
<span class="nd">@Test</span> <span class="n">fun</span> <span class="nf">test</span><span class="o">()</span> <span class="o">{</span>
<span class="n">val</span> <span class="nl">fixtJourney:</span> <span class="nc">Journey</span> <span class="o">=</span> <span class="n">fixture</span><span class="o">();</span>
<span class="n">val</span> <span class="n">result</span> <span class="o">=</span> <span class="n">sut</span><span class="o">.</span><span class="na">process</span><span class="o">(</span><span class="n">fixtJourney</span><span class="o">);</span>
<span class="n">assertNotNull</span><span class="o">(</span><span class="n">result</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Compare this to the classic approach where we would need to create each object individually, filling in the properties with dummy values, and potentially creating constants for these values. No matter how deep or complicated it gets, JFixture usually finds a way to create an instance with all the data filled in.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">val</span> <span class="py">journey</span> <span class="p">=</span> <span class="nc">Journey</span><span class="p">(</span>
<span class="s">""</span><span class="p">,</span>
<span class="nf">listOf</span><span class="p">(</span>
<span class="nc">Leg</span><span class="p">(</span>
<span class="nc">Stop</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">),</span>
<span class="nc">LocalDateTime</span><span class="p">.</span><span class="nf">now</span><span class="p">(),</span>
<span class="nc">TransportMode</span><span class="p">.</span><span class="nc">TRAIN</span><span class="p">,</span>
<span class="nc">Stop</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">),</span>
<span class="nc">LocalDataTime</span><span class="p">.</span><span class="nf">now</span><span class="p">()</span>
<span class="p">),</span>
<span class="nc">Leg</span><span class="p">(</span>
<span class="nc">Stop</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">),</span>
<span class="nc">LocalDateTime</span><span class="p">.</span><span class="nf">now</span><span class="p">(),</span>
<span class="nc">TransportMode</span><span class="p">.</span><span class="nc">TRAIN</span><span class="p">,</span>
<span class="nc">Stop</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">),</span>
<span class="nc">LocalDataTime</span><span class="p">.</span><span class="nf">now</span><span class="p">()</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>
<div id="toc" class="panel radius">
<h2 class="no_toc" id="table-of-contents">Table of Contents</h2>
<ul id="markdown-toc">
<li><a href="#introduction" id="markdown-toc-introduction">Introduction</a></li>
<li><a href="#the-need-for-jfixture" id="markdown-toc-the-need-for-jfixture">The need for JFixture</a> <ul>
<li><a href="#from-the-ground-up" id="markdown-toc-from-the-ground-up">From the ground up</a></li>
<li><a href="#classic-approach" id="markdown-toc-classic-approach">Classic approach</a></li>
<li><a href="#more-complex-model" id="markdown-toc-more-complex-model">More complex model</a></li>
<li><a href="#enter-factories" id="markdown-toc-enter-factories">Enter factories</a></li>
<li><a href="#enter-builders" id="markdown-toc-enter-builders">Enter builders</a></li>
<li><a href="#jfixture-to-the-rescue" id="markdown-toc-jfixture-to-the-rescue">JFixture to the rescue</a> <ul>
<li><a href="#how-does-jfixture-create-an-object" id="markdown-toc-how-does-jfixture-create-an-object">How does JFixture create an object?</a></li>
<li><a href="#benefits-no-builder-required" id="markdown-toc-benefits-no-builder-required">Benefits: No builder required</a></li>
<li><a href="#benefits-data-is-randomised" id="markdown-toc-benefits-data-is-randomised">Benefits: Data is randomised</a></li>
<li><a href="#a-note-on-kotlin" id="markdown-toc-a-note-on-kotlin">A note on Kotlin</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#data-oriented-testing" id="markdown-toc-data-oriented-testing">Data-oriented testing</a> <ul>
<li><a href="#controlling-collections" id="markdown-toc-controlling-collections">Controlling collections</a></li>
<li><a href="#property-customisation" id="markdown-toc-property-customisation">Property customisation</a></li>
<li><a href="#mutating-the-immutable" id="markdown-toc-mutating-the-immutable">Mutating the immutable</a></li>
<li><a href="#fine-grained-property-customisation" id="markdown-toc-fine-grained-property-customisation">Fine-grained property customisation</a></li>
<li><a href="#fine-grained-repetition" id="markdown-toc-fine-grained-repetition">Fine-grained repetition</a></li>
</ul>
</li>
<li><a href="#best-practices" id="markdown-toc-best-practices">Best practices</a> <ul>
<li><a href="#shared-jfixture" id="markdown-toc-shared-jfixture">Shared JFixture</a></li>
<li><a href="#sharing-data-setup" id="markdown-toc-sharing-data-setup">Sharing data setup</a></li>
<li><a href="#centralized-fixture" id="markdown-toc-centralized-fixture">Centralized Fixture</a></li>
<li><a href="#stubbing-fixture-behaviour" id="markdown-toc-stubbing-fixture-behaviour">Stubbing fixture behaviour</a></li>
</ul>
</li>
<li><a href="#pitfalls" id="markdown-toc-pitfalls">Pitfalls</a> <ul>
<li><a href="#kotlin-generics-interoperability" id="markdown-toc-kotlin-generics-interoperability">Kotlin generics interoperability</a></li>
<li><a href="#customise-the-right-jfixture" id="markdown-toc-customise-the-right-jfixture">Customise the right JFixture</a></li>
<li><a href="#beware-of-overloads" id="markdown-toc-beware-of-overloads">Beware of overloads</a></li>
<li><a href="#flaky-tests" id="markdown-toc-flaky-tests">Flaky tests</a></li>
</ul>
</li>
<li><a href="#conclusion" id="markdown-toc-conclusion">Conclusion</a></li>
<li><a href="#references" id="markdown-toc-references">References</a></li>
</ul>
</div>
<div class="alert-box info radius ">
<p>Note: In this article I use JUnit Jupiter and Mockito + Mockito Kotlin as the testing frameworks; and Kotlin as the language, because of its conciseness.
While JFixture was written for the JVM with Java in mind it works for Kotlin too due to Kotlin’s awesome interoperability.
Everything you see here applies to Java as well (unless it’s about using some Kotlin language feature).</p>
</div>
<h2 id="the-need-for-jfixture">The need for JFixture</h2>
<p>In this section, we’ll go through developing and testing a fictitious component.
Starting simply, and getting more complicated, we’ll find solutions to problems that come up on the way.</p>
<h3 id="from-the-ground-up">From the ground up</h3>
<p>Let’s imagine we’re writing a user interface for displaying some info based on a journey. Journey data is coming from a data source, and we transform it to display it on the UI.</p>
<p>Let’s start with a simple data structure:</p>
<div title="data models" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">data class</span> <span class="nc">Journey</span><span class="p">(</span>
<span class="kd">val</span> <span class="py">id</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span>
<span class="kd">val</span> <span class="py">origin</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span>
<span class="kd">val</span> <span class="py">destination</span><span class="p">:</span> <span class="nc">String</span>
<span class="p">)</span>
<span class="kd">data class</span> <span class="nc">Model</span><span class="p">(</span><span class="cm">/*...*/</span><span class="p">)</span>
</code></pre></div></div>
<p>Additionally, let’s say this is the class that orchestrates the loading and displaying:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">class</span> <span class="nc">JourneyPresenter</span><span class="p">(</span>
<span class="k">private</span> <span class="kd">val</span> <span class="py">view</span><span class="p">:</span> <span class="nc">JourneyView</span><span class="p">,</span>
<span class="k">private</span> <span class="kd">val</span> <span class="py">dataSource</span><span class="p">:</span> <span class="nc">DataSource</span><span class="p"><</span><span class="nc">Journey</span><span class="p">>,</span>
<span class="k">private</span> <span class="kd">val</span> <span class="py">mapper</span><span class="p">:</span> <span class="p">(</span><span class="nc">Journey</span><span class="p">)</span> <span class="p">-></span> <span class="nc">Model</span>
<span class="p">)</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">load</span><span class="p">(</span><span class="n">journeyId</span><span class="p">:</span> <span class="nc">String</span><span class="p">)</span> <span class="p">{</span>
<span class="n">dataSource</span>
<span class="p">.</span><span class="nf">getById</span><span class="p">(</span><span class="n">journeyId</span><span class="p">)</span>
<span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="n">mapper</span><span class="p">)</span>
<span class="p">.</span><span class="nf">subscribe</span> <span class="p">{</span> <span class="n">model</span> <span class="p">-></span> <span class="n">view</span><span class="p">.</span><span class="nf">show</span><span class="p">(</span><span class="n">model</span><span class="p">)</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Here are the collaborator interfaces for completeness (using RxJava’s <code class="language-text highlighter-rouge">Single</code>):</p>
<div title="collabolators" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">interface</span> <span class="nc">JourneyView</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">show</span><span class="p">(</span><span class="n">model</span><span class="p">:</span> <span class="nc">Model</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">interface</span> <span class="nc">DataSource</span><span class="p"><</span><span class="nc">T</span><span class="p">></span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">getById</span><span class="p">(</span><span class="n">id</span><span class="p">:</span> <span class="nc">String</span><span class="p">):</span> <span class="nc">Single</span><span class="p"><</span><span class="nc">T</span><span class="p">></span>
<span class="p">}</span>
</code></pre></div></div>
<p>To test this, we will need to mock the collaborators and stub their inputs and return values.
Mind you, we’re testing the data flow here: <code class="language-text highlighter-rouge">dataSource</code> → <code class="language-text highlighter-rouge">mapper</code> → <code class="language-text highlighter-rouge">view</code>.
At this point, we don’t really care what the data is, as long as it’s of the right type:</p>
<div title="JourneyPresenterTest" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">private</span> <span class="kd">val</span> <span class="py">mockView</span><span class="p">:</span> <span class="nc">JourneyView</span> <span class="p">=</span> <span class="nf">mock</span><span class="p">()</span>
<span class="k">private</span> <span class="kd">val</span> <span class="py">mockDataSource</span><span class="p">:</span> <span class="nc">DataSource</span><span class="p"><</span><span class="nc">Journey</span><span class="p">></span> <span class="p">=</span> <span class="nf">mock</span><span class="p">()</span>
<span class="k">private</span> <span class="kd">val</span> <span class="py">mockMapper</span><span class="p">:</span> <span class="p">(</span><span class="nc">Journey</span><span class="p">)</span> <span class="p">-></span> <span class="nc">Model</span> <span class="p">=</span> <span class="nf">mock</span><span class="p">()</span>
<span class="k">private</span> <span class="kd">val</span> <span class="py">sut</span> <span class="p">=</span> <span class="nc">JourneyPresenter</span><span class="p">(</span><span class="n">mockView</span><span class="p">,</span> <span class="n">mockDataSource</span><span class="p">,</span> <span class="n">mockMapper</span><span class="p">)</span>
<span class="nd">@Test</span> <span class="k">fun</span> <span class="nf">`loads</span> <span class="n">journey</span> <span class="n">and</span> <span class="n">presents</span> <span class="n">it</span> <span class="n">to</span> <span class="nf">view`</span><span class="p">()</span> <span class="p">{</span>
<span class="nf">whenever</span><span class="p">(</span><span class="n">mockDataSource</span><span class="p">.</span><span class="nf">getById</span><span class="p">(</span><span class="n">fixtJourneyId</span><span class="p">)).</span><span class="nf">thenReturn</span><span class="p">(</span><span class="n">fixtJourney</span><span class="p">)</span>
<span class="nf">whenever</span><span class="p">(</span><span class="n">mockMapper</span><span class="p">.</span><span class="nf">invoke</span><span class="p">(</span><span class="n">fixtJourney</span><span class="p">)).</span><span class="nf">thenReturn</span><span class="p">(</span><span class="n">fixtModel</span><span class="p">)</span>
<span class="n">sut</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="n">fixtJourneyId</span><span class="p">)</span>
<span class="nf">verify</span><span class="p">(</span><span class="n">mockView</span><span class="p">).</span><span class="nf">show</span><span class="p">(</span><span class="n">fixtModel</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You might notice, some of the declarations are missing, namely <code class="language-text highlighter-rouge">fixtJourneyId</code>, <code class="language-text highlighter-rouge">fixtJourney</code> and <code class="language-text highlighter-rouge">fixtModel</code>. These are left out, as they will be the focus of the next sections.</p>
<h3 id="classic-approach">Classic approach</h3>
<p>Usually when we’re faced with a problem of creating an instance of a class, we use instantiation (the good old <code class="language-text highlighter-rouge">new</code> in Java).
The simplest way to fill in the missing pieces above is this:</p>
<div title="Classic data setup for test" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">private</span> <span class="kd">val</span> <span class="py">fixtJourneyId</span> <span class="p">=</span> <span class="s">""</span>
<span class="k">private</span> <span class="kd">val</span> <span class="py">fixtJourney</span> <span class="p">=</span> <span class="nc">Journey</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">)</span>
<span class="k">private</span> <span class="kd">val</span> <span class="py">fixtModel</span> <span class="p">=</span> <span class="nc">Model</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</code></pre></div></div>
<p>Here, we filled in the values, so that it compiles. At the same time, we don’t really care about what the values are, so we mostly use default values such as use empty strings, <code class="language-text highlighter-rouge">false</code>, or <code class="language-text highlighter-rouge">0</code>s.</p>
<h3 id="more-complex-model">More complex model</h3>
<p>Let’s expand our very simple model to a more realistic example:</p>
<div title="Realistic data structure" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">data class</span> <span class="nc">Journey</span><span class="p">(</span>
<span class="kd">val</span> <span class="py">id</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span>
<span class="kd">val</span> <span class="py">legs</span><span class="p">:</span> <span class="nc">List</span><span class="p"><</span><span class="nc">Leg</span><span class="p">></span>
<span class="p">)</span>
<span class="kd">data class</span> <span class="nc">Leg</span><span class="p">(</span>
<span class="kd">val</span> <span class="py">origin</span><span class="p">:</span> <span class="nc">Stop</span><span class="p">,</span>
<span class="kd">val</span> <span class="py">departure</span><span class="p">:</span> <span class="nc">LocalDateTime</span><span class="p">,</span>
<span class="kd">val</span> <span class="py">mode</span><span class="p">:</span> <span class="nc">TransportMode</span><span class="p">,</span>
<span class="kd">val</span> <span class="py">destination</span><span class="p">:</span> <span class="nc">Stop</span><span class="p">,</span>
<span class="kd">val</span> <span class="py">arrival</span><span class="p">:</span> <span class="nc">LocalDateTime</span>
<span class="p">)</span>
<span class="k">enum</span> <span class="kd">class</span> <span class="nc">TransportMode</span> <span class="p">{</span> <span class="nc">WALK</span><span class="p">,</span> <span class="nc">TRAIN</span><span class="p">,</span> <span class="nc">TAXI</span> <span class="p">}</span>
<span class="kd">data class</span> <span class="nc">Stop</span><span class="p">(</span>
<span class="kd">val</span> <span class="py">id</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span>
<span class="kd">val</span> <span class="py">name</span><span class="p">:</span> <span class="nc">String</span>
<span class="p">)</span>
</code></pre></div></div>
<p>Now let’s update our classic approach:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">private</span> <span class="kd">val</span> <span class="py">fixtJourney</span> <span class="p">=</span> <span class="nc">Journey</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="nf">emptyList</span><span class="p">())</span>
</code></pre></div></div>
<p>OK… I took a shortcut here, but what will happen if we can’t assume to have an empty list there?
Say, the production code needs to loop through the list and we need to check the outcome based on that.
Let’s go with the assumption that we need at least 2 legs:</p>
<div title="Complex instantiation of realistic data structure" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">private</span> <span class="kd">val</span> <span class="py">fixtJourney</span> <span class="p">=</span> <span class="nc">Journey</span><span class="p">(</span>
<span class="s">""</span><span class="p">,</span>
<span class="nf">listOf</span><span class="p">(</span>
<span class="nc">Leg</span><span class="p">(</span>
<span class="nc">Stop</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">),</span>
<span class="nc">LocalDateTime</span><span class="p">.</span><span class="nf">now</span><span class="p">(),</span>
<span class="nc">TransportMode</span><span class="p">.</span><span class="nc">WALK</span><span class="p">,</span>
<span class="nc">Stop</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">),</span>
<span class="nc">LocalDataTime</span><span class="p">.</span><span class="nf">now</span><span class="p">()</span>
<span class="p">),</span>
<span class="nc">Leg</span><span class="p">(</span>
<span class="nc">Stop</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">),</span>
<span class="nc">LocalDateTime</span><span class="p">.</span><span class="nf">now</span><span class="p">(),</span>
<span class="nc">TransportMode</span><span class="p">.</span><span class="nc">WALK</span><span class="p">,</span>
<span class="nc">Stop</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">),</span>
<span class="nc">LocalDataTime</span><span class="p">.</span><span class="nf">now</span><span class="p">()</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>
<p>What can we observe so far? Instantiate one <code class="language-text highlighter-rouge">Leg</code>, instantiate multiple <code class="language-text highlighter-rouge">Stop</code>s, pick an <code class="language-text highlighter-rouge">TransportMode</code> to use; and then instantiate another leg, and so forth. It’s simply too much to write, read, and maintain; and when we scale it, there’s repetition.</p>
<h3 id="enter-factories">Enter factories</h3>
<p>What do we do when we see repeated code? We extract methods/classes. So we go on and refactor our code to introduce a <em>factory method</em> for leg creation:</p>
<div title="Re-using code with factory method" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">private</span> <span class="kd">val</span> <span class="py">fixtJourney</span> <span class="p">=</span> <span class="nc">Journey</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="nf">listOf</span><span class="p">(</span><span class="nf">createLeg</span><span class="p">(),</span> <span class="nf">createLeg</span><span class="p">()))</span>
<span class="k">private</span> <span class="k">fun</span> <span class="nf">createLeg</span><span class="p">()</span> <span class="p">=</span> <span class="nc">Leg</span><span class="p">(</span>
<span class="nc">Stop</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">),</span>
<span class="nc">LocalDateTime</span><span class="p">.</span><span class="nf">now</span><span class="p">(),</span>
<span class="nc">TransportMode</span><span class="p">.</span><span class="nc">WALK</span><span class="p">,</span>
<span class="nc">Stop</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">),</span>
<span class="nc">LocalDataTime</span><span class="p">.</span><span class="nf">now</span><span class="p">()</span>
<span class="p">)</span>
</code></pre></div></div>
<p>Cool, it works! Using code looks clean, but is that scalable? How many factory methods should we create to cover all the model types. Is it easily maintainable? How many variations of the same factory method should we have to satisfy all the test scenarios? Okay, we could parameterise each factory method by passing in the parameters that we are interested in; we could even leverage Kotlin’s default parameters for functions. But…, what happens if it’s a complex model? How many parameters and/or overloads should we have?</p>
<h3 id="enter-builders">Enter builders</h3>
<p>So then, let’s move on to the next solution… <em>builders</em>! The perfect tool to solve all our issues in terms of maintainability, is it not?
It alleviates the repetition and allows dynamism for creating objects; for example something like this would help with <code class="language-text highlighter-rouge">Journey</code>s:</p>
<div title="Re-using code by implementing complex builder classes" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">class</span> <span class="nc">JourneyBuilder</span><span class="p">(</span>
<span class="k">private</span> <span class="kd">var</span> <span class="py">id</span><span class="p">:</span> <span class="nc">String</span> <span class="p">=</span> <span class="s">""</span><span class="p">,</span>
<span class="k">private</span> <span class="kd">val</span> <span class="py">legs</span><span class="p">:</span> <span class="nc">MutableList</span><span class="p"><</span><span class="nc">Leg</span><span class="p">></span> <span class="p">=</span> <span class="nf">mutableListOf</span><span class="p">()</span>
<span class="p">)</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">build</span><span class="p">()</span> <span class="p">=</span> <span class="nc">Journey</span><span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">legs</span><span class="p">)</span>
<span class="k">fun</span> <span class="nf">setId</span><span class="p">(</span><span class="n">id</span><span class="p">:</span> <span class="nc">String</span><span class="p">):</span> <span class="nc">JourneyBuilder</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">apply</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="n">id</span> <span class="p">=</span> <span class="n">id</span> <span class="p">}</span>
<span class="k">fun</span> <span class="nf">addLeg</span><span class="p">(</span><span class="n">leg</span><span class="p">:</span> <span class="nc">Leg</span><span class="p">):</span> <span class="nc">JourneyBuilder</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">apply</span> <span class="p">{</span> <span class="n">legs</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="n">leg</span><span class="p">)</span> <span class="p">}</span>
<span class="p">}</span>
<span class="kd">class</span> <span class="nc">LegBuilder</span><span class="p">(</span>
<span class="k">private</span> <span class="kd">var</span> <span class="py">origin</span><span class="p">:</span> <span class="nc">Stop</span> <span class="p">=</span> <span class="nc">Stop</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">),</span>
<span class="k">private</span> <span class="kd">var</span> <span class="py">departure</span><span class="p">:</span> <span class="nc">LocalDateTime</span> <span class="p">=</span> <span class="nc">LocalDateTime</span><span class="p">.</span><span class="nf">now</span><span class="p">(),</span>
<span class="k">private</span> <span class="kd">var</span> <span class="py">mode</span><span class="p">:</span> <span class="nc">TransportMode</span> <span class="p">=</span> <span class="nc">TransportMode</span><span class="p">.</span><span class="nc">WALK</span><span class="p">,</span>
<span class="k">private</span> <span class="kd">var</span> <span class="py">destination</span><span class="p">:</span> <span class="nc">Stop</span> <span class="p">=</span> <span class="nc">Stop</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">""</span><span class="p">),</span>
<span class="k">private</span> <span class="kd">var</span> <span class="py">arrival</span><span class="p">:</span> <span class="nc">LocalDateTime</span> <span class="p">=</span> <span class="nc">LocalDateTime</span><span class="p">.</span><span class="nf">now</span><span class="p">()</span>
<span class="p">)</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">build</span><span class="p">()</span> <span class="p">=</span> <span class="nc">Leg</span><span class="p">(</span><span class="n">origin</span><span class="p">,</span> <span class="n">departure</span><span class="p">,</span> <span class="n">mode</span><span class="p">,</span> <span class="n">destination</span><span class="p">,</span> <span class="n">arrival</span><span class="p">)</span>
<span class="k">fun</span> <span class="nf">setOrigin</span><span class="p">(</span><span class="n">origin</span><span class="p">:</span> <span class="nc">Stop</span><span class="p">):</span> <span class="nc">LegBuilder</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">apply</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="n">origin</span> <span class="p">=</span> <span class="n">origin</span> <span class="p">}</span>
<span class="k">fun</span> <span class="nf">setMode</span><span class="p">(</span><span class="n">mode</span><span class="p">:</span> <span class="nc">TransportMode</span><span class="p">):</span> <span class="nc">LegBuilder</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">apply</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="n">mode</span> <span class="p">=</span> <span class="n">mode</span> <span class="p">}</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Phew, that was a lot of code to type — and I didn’t even write out all the properties (e.g. <code class="language-text highlighter-rouge">destination</code>), and sub-builders (e.g. <code class="language-text highlighter-rouge">Stop</code>), nor did I use Kotlin DSL and lambdas.</p>
<p>Anyway, let’s use this builder to replace the factory:</p>
<div title="Simple, yet dynamic builder usage" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">private</span> <span class="kd">val</span> <span class="py">fixtJourney</span> <span class="p">=</span> <span class="nc">JourneyBuilder</span><span class="p">()</span>
<span class="p">.</span><span class="nf">addLeg</span><span class="p">(</span><span class="nc">LegBuilder</span><span class="p">().</span><span class="nf">build</span><span class="p">())</span>
<span class="p">.</span><span class="nf">addLeg</span><span class="p">(</span><span class="nc">LegBuilder</span><span class="p">().</span><span class="nf">build</span><span class="p">())</span>
<span class="p">.</span><span class="nf">build</span><span class="p">()</span>
</code></pre></div></div>
<p>Nice! Easy to read, we can create our own domain specific language. But I think it’s easy to see how the builder approach might get complicated really fast as the system grows and more data types, properties are added and combined together in various ways.</p>
<h3 id="jfixture-to-the-rescue">JFixture to the rescue</h3>
<p>Remember <code class="language-text highlighter-rouge">JourneyBuilder</code> we created just now? Turns out a very similar effect can be achieved by using the <code class="language-text highlighter-rouge">JFixture</code> library:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">private</span> <span class="kd">val</span> <span class="py">fixtJourney</span><span class="p">:</span> <span class="nc">Journey</span> <span class="p">=</span> <span class="n">fixture</span><span class="p">.</span><span class="nf">create</span><span class="p">(</span><span class="nc">Journey</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>
</code></pre></div></div>
<p>… but what does this do? and what are the benefits? That’s what we’ll explore next.</p>
<h4 id="how-does-jfixture-create-an-object">How does JFixture create an object?</h4>
<p>When we call <code class="language-text highlighter-rouge">fixture.create(Class)</code>, JFixture tries numerous ways to create our objects:</p>
<ul>
<li>built-in types (
see <a href="https://github.com/FlexTradeUKLtd/jfixture/wiki/Default-Behaviour#default-supported-types">Default Supported Types</a>
and <a href="https://github.com/FlexTradeUKLtd/jfixture/blob/master/jfixture/src/main/java/com/flextrade/jfixture/builders/DefaultEngineParts.java"><code class="language-text highlighter-rouge">DefaultEngineParts</code></a>
)</li>
<li><code class="language-text highlighter-rouge">customise()</code> (if any)
<ul>
<li><code class="language-text highlighter-rouge">lazyInstance</code></li>
<li><code class="language-text highlighter-rouge">sameInstance</code></li>
<li><code class="language-text highlighter-rouge">useSubType</code></li>
</ul>
</li>
<li>public constructor with the least number of arguments</li>
<li>public factory method with the least number of arguments</li>
<li>package visible constructor with the least number of arguments</li>
</ul>
<div class="alert-box tip radius "><p>Pro tip:
<q>public constructor with the least number of arguments</q> can be changed to <q>most</q> when a class has overloaded constructors:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="n">fixture</span><span class="p">.</span><span class="nf">customise</span><span class="p">(</span><span class="nc">GreedyConstructorCustomisation</span><span class="p">(</span><span class="nc">SomeType</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">))</span>
</code></pre></div></div>
</div>
<p>When it succeeds, after creation it’ll also use:</p>
<ul>
<li><code class="language-text highlighter-rouge">customise()</code>
<ul>
<li><code class="language-text highlighter-rouge">propertyOf</code></li>
<li><code class="language-text highlighter-rouge">intercept</code></li>
</ul>
</li>
<li>setters for mutable properties</li>
<li>write visible mutable fields</li>
</ul>
<p>Notice that while this may seems like a lot to digest at first, we’re usually only using 1 or 2 of these.</p>
<h4 id="benefits-no-builder-required">Benefits: No builder required</h4>
<p>JFixture is a builder by itself, except it adapts to the shape of your code automatically.</p>
<dl>
<dt>less code to write</dt>
<dd>
<p>We can save a lot of code that would just create our objects by using the library.</p>
</dd>
<dt>less code to maintain</dt>
<dd>
<p>Every time a new property is added all the usages of the class have to be revised and the constructor calls/builders adjusted.
Most of the time these are unrelated places and the new field doesn’t affect behaviour of the tests, yet we still have to modify them.
With builders the situation is much better than the classic or factory approach, but maintenance is still needed.</p>
</dd>
<dt>customisation of objects is still possible</dt>
<dd>
<p>The flexibility of the builder is that we can pick which parts to be set and how.
For example a <code class="language-text highlighter-rouge">TRAIN</code>-only journey with multiple legs; this is still easily possible.</p>
</dd>
</dl>
<h4 id="benefits-data-is-randomised">Benefits: Data is randomised</h4>
<p>Don’t worry, it’s the <a href="https://github.com/FlexTradeUKLtd/jfixture#overview">good type of random</a>.</p>
<dl>
<dt>no conflicts from random data</dt>
<dd>
<p>Consider this simple thing:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code> <span class="kd">val</span> <span class="py">journeys</span> <span class="p">=</span> <span class="nf">setOf</span><span class="p">(</span>
<span class="nc">JourneyBuilder</span><span class="p">().</span><span class="nf">addLeg</span><span class="p">(</span><span class="nc">LegBuilder</span><span class="p">().</span><span class="nf">build</span><span class="p">()).</span><span class="nf">build</span><span class="p">(),</span>
<span class="nc">JourneyBuilder</span><span class="p">().</span><span class="nf">addLeg</span><span class="p">(</span><span class="nc">LegBuilder</span><span class="p">().</span><span class="nf">build</span><span class="p">()).</span><span class="nf">build</span><span class="p">()</span>
<span class="p">)</span>
<span class="nf">assertThat</span><span class="p">(</span><span class="n">journeys</span><span class="p">,</span> <span class="nf">hasSize</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span>
</code></pre></div> </div>
<p>With the hand-built builders we would have to write randomising code ourselves to get this to pass.
What’s even worse: sometimes it would pass, sometimes it wouldn’t; depending on what time it is now and how fast our computer is.</p>
</dd>
<dt>more confidence in verification</dt>
<dd>
<p>Let’s imagine we have a bug, and the production code is using the wrong leg to calculate the origin station’s name. With the current builder implementation each leg’s station names are all the same. This means that we could easily end up with a false positive verification. JFixture puts different data everywhere, so it would catch the problem:
With the current builder implementation</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code> <span class="c1">// same as fixtJourney.legs[i].origin.name</span>
<span class="nf">assertEquals</span><span class="p">(</span><span class="n">fixtJourney</span><span class="p">.</span><span class="n">legs</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">origin</span><span class="p">.</span><span class="n">name</span><span class="p">,</span> <span class="n">model</span><span class="p">.</span><span class="n">origin</span><span class="p">)</span>
</code></pre></div> </div>
</dd>
</dl>
<h4 id="a-note-on-kotlin">A note on Kotlin</h4>
<p>Writing <code class="language-text highlighter-rouge">fixture.create(Journey::class.java)</code> over and over again gets old really fast. In Kotlin we can do better:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">inline</span> <span class="k">fun</span> <span class="p"><</span><span class="k">reified</span> <span class="nc">T</span><span class="p">></span> <span class="nc">JFixture</span><span class="p">.</span><span class="nf">build</span><span class="p">():</span> <span class="nc">T</span> <span class="p">=</span> <span class="nf">create</span><span class="p">(</span><span class="nc">T</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>
<span class="k">inline</span> <span class="k">operator</span> <span class="k">fun</span> <span class="p"><</span><span class="k">reified</span> <span class="nc">T</span><span class="p">></span> <span class="nc">JFixture</span><span class="p">.</span><span class="nf">invoke</span><span class="p">():</span> <span class="nc">T</span> <span class="p">=</span> <span class="nf">create</span><span class="p">(</span><span class="nc">T</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>
</code></pre></div></div>
<p>The first one gives us <code class="language-text highlighter-rouge">val fixtString: String = fixture.build()</code> with inferred type arguments.
The second one enables <code class="language-text highlighter-rouge">val fixtString: String = fixture()</code> similar to <code class="language-text highlighter-rouge">mock()</code> (given <code class="language-text highlighter-rouge">val fixture: JFixture</code> in scope of course).
It’s up to you which way you go, based on how much Kotlin magic is acceptable.
I recommend writing extension methods for most of the <code class="language-text highlighter-rouge">customise()</code> methods using <code class="language-text highlighter-rouge">KClass</code>, or <code class="language-text highlighter-rouge">inline</code> + <code class="language-text highlighter-rouge">reified</code> so they feel more idiomatic.</p>
<p><em>I’ll use <code class="language-text highlighter-rouge">operator invoke</code> in the rest of the article.</em></p>
<h2 id="data-oriented-testing">Data-oriented testing</h2>
<div class="alert-box info radius ">
<p>Most of the examples in this section demonstrate features that are also listed on the <a href="https://github.com/FlexTradeUKLtd/jfixture/wiki/Usage-Cheat-Sheet">JFixture cheat sheet</a>.</p>
</div>
<p>Until now the focus was on the presenter, and data flow; let’s move on to the <code class="language-text highlighter-rouge">JourneyMapper</code>’s tests to demonstrate how JFixture can help.</p>
<h3 id="controlling-collections">Controlling collections</h3>
<p>Let’s say the model has a field which represents how many changes passengers have to make on a journey:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">data class</span> <span class="nc">Model</span><span class="p">(</span>
<span class="c1">// ...,</span>
<span class="kd">val</span> <span class="py">changeCount</span><span class="p">:</span> <span class="nc">Int</span>
<span class="p">)</span>
</code></pre></div></div>
<p>this is of course calculated as follows:</p>
<div title="JourneyMapper" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">override</span> <span class="k">fun</span> <span class="nf">invoke</span><span class="p">(</span><span class="n">journey</span><span class="p">:</span> <span class="nc">Journey</span><span class="p">)</span> <span class="p">=</span> <span class="nc">Model</span><span class="p">(</span>
<span class="c1">// ...,</span>
<span class="n">changeCount</span> <span class="p">=</span> <span class="n">journey</span><span class="p">.</span><span class="n">legs</span><span class="p">.</span><span class="n">size</span> <span class="p">-</span> <span class="mi">1</span>
<span class="p">)</span>
</code></pre></div></div>
<p>If we were to use the classic approach, tests for this would get unwieldy. Builders are a bit better, but testing for multiple counts in a parameterised test still requires some form of looping, or a custom factory just to create a certain amount of legs. With JFixture this is supported out of the box for any type:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nd">@CsvSource</span><span class="p">(</span><span class="s">"1, 0"</span><span class="p">,</span> <span class="s">"2, 1"</span><span class="p">,</span> <span class="s">"3, 2"</span><span class="p">,</span> <span class="s">"4, 3"</span><span class="p">)</span>
<span class="nd">@ParameterizedTest</span>
<span class="k">fun</span> <span class="nf">`changeCount</span> <span class="k">is</span> <span class="n">mapped</span> <span class="nf">correctly`</span><span class="p">(</span><span class="n">legCount</span><span class="p">:</span> <span class="nc">Int</span><span class="p">,</span> <span class="n">expectedChanges</span><span class="p">:</span> <span class="nc">Int</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fixture</span><span class="p">.</span><span class="nf">customise</span><span class="p">().</span><span class="nf">repeatCount</span><span class="p">(</span><span class="n">legCount</span><span class="p">)</span>
<span class="kd">val</span> <span class="py">fixtJourney</span><span class="p">:</span> <span class="nc">Journey</span> <span class="p">=</span> <span class="nf">fixture</span><span class="p">()</span>
<span class="kd">val</span> <span class="py">result</span> <span class="p">=</span> <span class="n">sut</span><span class="p">.</span><span class="nf">invoke</span><span class="p">(</span><span class="n">fixtJourney</span><span class="p">)</span>
<span class="nf">assertThat</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">changeCount</span><span class="p">,</span> <span class="nf">equalTo</span><span class="p">(</span><span class="n">expectedChanges</span><span class="p">))</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="alert-box info radius ">
<p><code class="language-text highlighter-rouge">repeatCount</code> is a built-in method that changes how many elements each fixtured collection will contain;
the default is <a href="https://github.com/FlexTradeUKLtd/jfixture/blob/master/jfixture/src/main/java/com/flextrade/jfixture/MultipleCount.java"><var>3</var></a>.</p>
</div>
<div class="alert-box warning radius ">
<p>Warning: This actually does not scale well, but good enough for simple tests.<br />
More on this in <a href="#fine-grained-repetition">“Fine-grained repetition”</a>.</p>
</div>
<h3 id="property-customisation">Property customisation</h3>
<p>Let’s look at how we can calculate if the journey is train-only:</p>
<div title="JourneyMapper" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">override</span> <span class="k">fun</span> <span class="nf">invoke</span><span class="p">(</span><span class="n">journey</span><span class="p">:</span> <span class="nc">Journey</span><span class="p">)</span> <span class="p">=</span> <span class="nc">Model</span><span class="p">(</span>
<span class="c1">// ...,</span>
<span class="n">trainOnly</span> <span class="p">=</span> <span class="n">journey</span><span class="p">.</span><span class="n">legs</span><span class="p">.</span><span class="nf">all</span> <span class="p">{</span> <span class="n">it</span><span class="p">.</span><span class="n">mode</span> <span class="p">==</span> <span class="nc">TRAIN</span> <span class="p">}</span>
<span class="p">)</span>
</code></pre></div></div>
<p>The tests for this involve setting all the leg modes to <code class="language-text highlighter-rouge">TRAIN</code>. With the builders approach we could use <code class="language-text highlighter-rouge">LegBuilder.setMode</code>, with JFixture we just say: <q>all transport modes are <code class="language-text highlighter-rouge">TRAIN</code></q>:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nd">@Test</span> <span class="k">fun</span> <span class="nf">`trainOnly</span> <span class="k">is</span> <span class="k">true</span> <span class="k">for</span> <span class="nc">TRAIN-only</span> <span class="nf">journey`</span><span class="p">()</span> <span class="p">{</span>
<span class="n">fixture</span><span class="p">.</span><span class="nf">customise</span><span class="p">().</span><span class="nf">sameInstance</span><span class="p">(</span><span class="nc">TransportMode</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">,</span> <span class="nc">TRAIN</span><span class="p">)</span>
<span class="kd">val</span> <span class="py">fixtJourney</span><span class="p">:</span> <span class="nc">Journey</span> <span class="p">=</span> <span class="nf">fixture</span><span class="p">()</span>
<span class="kd">val</span> <span class="py">result</span> <span class="p">=</span> <span class="n">sut</span><span class="p">.</span><span class="nf">invoke</span><span class="p">(</span><span class="n">fixtJourney</span><span class="p">)</span>
<span class="nf">assertThat</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">trainOnly</span><span class="p">,</span> <span class="nf">equalTo</span><span class="p">(</span><span class="k">true</span><span class="p">))</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="alert-box info radius ">
<p><code class="language-text highlighter-rouge">sameInstance</code> is a built-in method that can be used to make sure a type is <strong>always</strong> resolved to <strong>the same</strong> instance.</p>
</div>
<p>We need to test another scenario though: when there are no <code class="language-text highlighter-rouge">TRAIN</code> legs. In this case each leg should have a mode of anything but <code class="language-text highlighter-rouge">TRAIN</code>. Here’s a way to do this:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nd">@Test</span> <span class="k">fun</span> <span class="nf">`trainOnly</span> <span class="k">is</span> <span class="k">false</span> <span class="k">for</span> <span class="n">a</span> <span class="nc">TRAIN-less</span> <span class="nf">journey`</span><span class="p">()</span> <span class="p">{</span>
<span class="n">fixture</span><span class="p">.</span><span class="nf">customise</span><span class="p">().</span><span class="nf">lazyInstance</span><span class="p">(</span><span class="nc">TransportMode</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fixture</span><span class="p">.</span><span class="nf">create</span><span class="p">().</span><span class="nf">fromList</span><span class="p">(*</span><span class="nc">Enum</span><span class="p">.</span><span class="nf">valuesExcluding</span><span class="p">(</span><span class="nc">TRAIN</span><span class="p">))</span>
<span class="p">}</span>
<span class="kd">val</span> <span class="py">fixtJourney</span><span class="p">:</span> <span class="nc">Journey</span> <span class="p">=</span> <span class="nf">fixture</span><span class="p">()</span>
<span class="kd">val</span> <span class="py">result</span> <span class="p">=</span> <span class="n">sut</span><span class="p">.</span><span class="nf">invoke</span><span class="p">(</span><span class="n">fixtJourney</span><span class="p">)</span>
<span class="nf">assertThat</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">trainOnly</span><span class="p">,</span> <span class="nf">equalTo</span><span class="p">(</span><span class="k">false</span><span class="p">))</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="alert-box info radius ">
<p><code class="language-text highlighter-rouge">lazyInstance</code> will be called each time a <code class="language-text highlighter-rouge">Leg</code> is being created to fill its <code class="language-text highlighter-rouge">mode</code>.<br />
<code class="language-text highlighter-rouge">fromList</code> will pick an item from the array.</p>
</div>
<p><code class="language-text highlighter-rouge">Enum.valuesExcluding</code> is not in a library, it’s one of the few utilities we use to make parameterised tests and fixturing nicer:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">inline</span> <span class="k">fun</span> <span class="p"><</span><span class="k">reified</span> <span class="nc">E</span> <span class="p">:</span> <span class="nc">Enum</span><span class="p"><</span><span class="nc">E</span><span class="p">>></span>
<span class="nc">Enum</span><span class="p">.</span><span class="nc">Companion</span><span class="p">.</span><span class="nf">valuesExcluding</span><span class="p">(</span><span class="k">vararg</span> <span class="n">excluded</span><span class="p">:</span> <span class="nc">E</span><span class="p">):</span> <span class="nc">Array</span><span class="p"><</span><span class="nc">E</span><span class="p">></span> <span class="p">=</span>
<span class="p">(</span><span class="n">enumValues</span><span class="p"><</span><span class="nc">E</span><span class="p">>().</span><span class="nf">toList</span><span class="p">()</span> <span class="p">-</span> <span class="n">excluded</span><span class="p">).</span><span class="nf">toTypedArray</span><span class="p">()</span>
</code></pre></div></div>
<p>You may notice that this <code class="language-text highlighter-rouge">lazyInstance</code> + <code class="language-text highlighter-rouge">fromList</code> + <code class="language-text highlighter-rouge">valuesExcluding</code> combination has potential for re-use, and you’re right:
it is possible to extract customisation logic via <code class="language-text highlighter-rouge">SpecimenSupplier</code> and/or <code class="language-text highlighter-rouge">Customisation</code> interfaces.</p>
<h3 id="mutating-the-immutable">Mutating the immutable</h3>
<p>I warn you, things are going to get controversial.
You may have noticed that the only <code class="language-text highlighter-rouge">var</code> I used is in the builder: we use a lot of immutable data types.
These data types still need to be created, and we’re using JFixture as our builders. This is where this very useful small utility comes into play:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">fun</span> <span class="nc">Any</span><span class="p">.</span><span class="nf">setField</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nc">Any</span><span class="p">?)</span> <span class="p">{</span>
<span class="k">this</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">.</span><span class="nf">getDeclaredField</span><span class="p">(</span><span class="n">name</span><span class="p">).</span><span class="nf">apply</span> <span class="p">{</span>
<span class="n">isAccessible</span> <span class="p">=</span> <span class="k">true</span>
<span class="k">set</span><span class="p">(</span><span class="k">this</span><span class="nd">@setField</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>An example usage would look like this:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nd">@Test</span> <span class="k">fun</span> <span class="nf">`duration</span> <span class="n">returns</span> <span class="n">time</span> <span class="k">for</span> <span class="n">whole</span> <span class="nf">journey`</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">val</span> <span class="py">expectedMinutes</span><span class="p">:</span> <span class="nc">Int</span> <span class="p">=</span> <span class="nf">fixture</span><span class="p">()</span>
<span class="kd">val</span> <span class="py">fixtJourney</span><span class="p">:</span> <span class="nc">Journey</span> <span class="p">=</span> <span class="nf">fixture</span><span class="p">()</span>
<span class="n">fixtJourney</span><span class="p">.</span><span class="n">legs</span><span class="p">.</span><span class="nf">last</span><span class="p">().</span><span class="nf">setField</span><span class="p">(</span><span class="s">"arrival"</span><span class="p">,</span> <span class="n">fixtJourney</span><span class="p">.</span><span class="n">legs</span><span class="p">.</span><span class="nf">first</span><span class="p">().</span><span class="n">departure</span><span class="p">.</span><span class="nf">plusMinutes</span><span class="p">(</span><span class="n">expectedMinutes</span><span class="p">))</span>
<span class="kd">val</span> <span class="py">result</span> <span class="p">=</span> <span class="n">sut</span><span class="p">.</span><span class="nf">invoke</span><span class="p">(</span><span class="n">fixtJourney</span><span class="p">)</span>
<span class="nf">assertThat</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">length</span><span class="p">,</span> <span class="nf">equalTo</span><span class="p">(</span><span class="nc">Duration</span><span class="p">.</span><span class="nf">of</span><span class="p">(</span><span class="n">expectedMinutes</span><span class="p">,</span> <span class="nc">ChronoUnit</span><span class="p">.</span><span class="nc">MINUTES</span><span class="p">)))</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You can see that it gives us the benefit of <q>naturally</q> mutating objects that are otherwise immutable.
Additionally it really focuses on the bits that we care about and leaves everything else up to JFixture.
The reflection may look counter-productive, but in the rare instance we rename properties or change types of properties the tests will fail at run-time;
which is slower to detect than a compile error, but we’re still protected from false positives.</p>
<p>Sometimes each object has to contain self-consistent data, for example: each leg has to be a non-zero length travel. In this case <code class="language-text highlighter-rouge">intercept</code> comes in handy combined with <code class="language-text highlighter-rouge">setField</code>:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="n">fixture</span><span class="p">.</span><span class="nf">customise</span><span class="p">().</span><span class="nf">intercept</span><span class="p">(</span><span class="nc">Leg</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span> <span class="p">{</span>
<span class="n">it</span><span class="p">.</span><span class="nf">setField</span><span class="p">(</span><span class="s">"arrival"</span><span class="p">,</span> <span class="n">it</span><span class="p">.</span><span class="n">departure</span><span class="p">.</span><span class="nf">plusMinutes</span><span class="p">(</span><span class="n">fixture</span><span class="p"><</span><span class="nc">Long</span><span class="p">>()))</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="alert-box info radius ">
<p><code class="language-text highlighter-rouge">intercept</code> is a built-in method that lets you mutate the created object further after creation. It will be called once for each instance.</p>
</div>
<div class="alert-box warning radius ">
<p>JFixture has a <code class="language-text highlighter-rouge">propertyOf</code> customisation which we could use instead of <code class="language-text highlighter-rouge">setField</code>, but it’s a no-go when using immutable classes. It will only work on <code class="language-text highlighter-rouge">var</code>s, not <code class="language-text highlighter-rouge">val</code>s.</p>
</div>
<h3 id="fine-grained-property-customisation">Fine-grained property customisation</h3>
<p>Here’s the thing about <code class="language-text highlighter-rouge">lazyInstance</code>: it affects every single object created from the given <code class="language-text highlighter-rouge">fixture</code> factory. This may be unwanted, and needs to be resolved.
Let’s consider what happens if there are <code class="language-text highlighter-rouge">Passengers</code> in the system:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">data class</span> <span class="nc">Passenger</span><span class="p">(</span>
<span class="kd">val</span> <span class="py">preferredMode</span><span class="p">:</span> <span class="nc">TransportMode</span>
<span class="p">)</span>
</code></pre></div></div>
<p>In this case, creating a <code class="language-text highlighter-rouge">Journey</code> and a <code class="language-text highlighter-rouge">Passenger</code> in the same test would mean we would be always creating them with the same <code class="language-text highlighter-rouge">TransportMode</code> when using <code class="language-text highlighter-rouge">sameInstance</code>.
To make this more explicit we can use:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="n">fixture</span><span class="p">.</span><span class="nf">customise</span><span class="p">().</span><span class="nf">intercept</span><span class="p">(</span><span class="nc">Leg</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span> <span class="p">{</span>
<span class="n">it</span><span class="p">.</span><span class="nf">setField</span><span class="p">(</span><span class="s">"mode"</span><span class="p">,</span> <span class="nc">TransportMode</span><span class="p">.</span><span class="nc">TRAIN</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">fixture</span><span class="p">.</span><span class="nf">customise</span><span class="p">().</span><span class="nf">intercept</span><span class="p">(</span><span class="nc">Passenger</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span> <span class="p">{</span>
<span class="n">it</span><span class="p">.</span><span class="nf">setField</span><span class="p">(</span><span class="s">"preferredMode"</span><span class="p">,</span> <span class="nc">TransportMode</span><span class="p">.</span><span class="nc">WALK</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="fine-grained-repetition">Fine-grained repetition</h3>
<p>Similarly <code class="language-text highlighter-rouge">repeatCount</code> is a tricky one. It changes each collection’s size at once, which is probably not what we want. For example we may need to test 2 passengers over 3 legs:</p>
<div title="Adding passengers to data type" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">data class</span> <span class="nc">Journey</span><span class="p">(</span>
<span class="c1">// ...,</span>
<span class="kd">val</span> <span class="py">legs</span><span class="p">:</span> <span class="nc">List</span><span class="p"><</span><span class="nc">Leg</span><span class="p">>,</span>
<span class="kd">val</span> <span class="py">passengers</span><span class="p">:</span> <span class="nc">List</span><span class="p"><</span><span class="nc">Passenger</span><span class="p">></span>
<span class="p">)</span>
</code></pre></div></div>
<div title="Creating a specific number of passengers" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">val</span> <span class="py">fixtJourney</span><span class="p">:</span> <span class="nc">Journey</span> <span class="p">=</span> <span class="nf">fixture</span><span class="p">()</span>
<span class="n">fixtJourney</span><span class="p">.</span><span class="nf">setField</span><span class="p">(</span><span class="s">"passengers"</span><span class="p">,</span> <span class="n">fixture</span><span class="p">.</span><span class="n">createList</span><span class="p"><</span><span class="nc">Passenger</span><span class="p">>(</span><span class="n">size</span> <span class="p">=</span> <span class="mi">2</span><span class="p">))</span>
</code></pre></div></div>
<p><code class="language-text highlighter-rouge">createList</code> is not a library function, it is one of the extensions we added to help us create lists in a very simple way. JFixture — being designed for Java — has some quirks in Kotlin, so hiding them in utility functions helps to write nicer code:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nd">@Suppress</span><span class="p">(</span><span class="s">"UNCHECKED_CAST"</span><span class="p">)</span> <span class="c1">// can't have List<T>::class literal, so need to cast</span>
<span class="k">inline</span> <span class="k">fun</span> <span class="p"><</span><span class="k">reified</span> <span class="nc">T</span> <span class="p">:</span> <span class="nc">Any</span><span class="p">></span> <span class="nc">JFixture</span><span class="p">.</span><span class="nf">createList</span><span class="p">(</span><span class="n">size</span><span class="p">:</span> <span class="nc">Int</span> <span class="p">=</span> <span class="mi">3</span><span class="p">):</span> <span class="nc">List</span><span class="p"><</span><span class="nc">T</span><span class="p">></span> <span class="p">=</span>
<span class="k">this</span><span class="p">.</span><span class="nf">collections</span><span class="p">().</span><span class="nf">createCollection</span><span class="p">(</span><span class="nc">List</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span> <span class="k">as</span> <span class="nc">Class</span><span class="p"><</span><span class="nc">List</span><span class="p"><</span><span class="nc">T</span><span class="p">>>,</span> <span class="nc">T</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span>
</code></pre></div></div>
<h2 id="best-practices">Best practices</h2>
<p>Now that we have the tools, here are some tips to prevent hurting ourselves.</p>
<h3 id="shared-jfixture">Shared JFixture</h3>
<p>It might be tempting to create globals, but try not to.
It’s not worth the hours of debugging when you accidentally end up with the wrong fixtured data because another test customised it in a counter-productive way.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">val</span> <span class="py">fixture</span> <span class="p">=</span> <span class="nc">JFixture</span><span class="p">()</span>
<span class="c1">// or</span>
<span class="kd">object</span> <span class="err">fixture : </span><span class="nc">JFixture</span><span class="p">()</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
<span class="nd">@TestMethodOrder</span><span class="p">(</span><span class="nc">Random</span><span class="o">::</span><span class="k">class</span><span class="p">)</span>
<span class="kd">class</span> <span class="nc">SharedStateTest</span> <span class="p">{</span>
<span class="nd">@Test</span> <span class="k">fun</span> <span class="nf">customiser</span><span class="p">()</span> <span class="p">{</span>
<span class="n">fixture</span><span class="p">.</span><span class="nf">customise</span><span class="p">().</span><span class="nf">sameInstance</span><span class="p">(</span><span class="nc">String</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">,</span> <span class="s">""</span><span class="p">)</span>
<span class="nf">assertThat</span><span class="p">(</span><span class="n">fixture</span><span class="p"><</span><span class="nc">String</span><span class="p">>(),</span> <span class="nf">emptyString</span><span class="p">())</span>
<span class="p">}</span>
<span class="nd">@Test</span> <span class="k">fun</span> <span class="nf">annoyedObserver</span><span class="p">()</span> <span class="p">{</span>
<span class="nf">assertThat</span><span class="p">(</span><span class="n">fixture</span><span class="p"><</span><span class="nc">String</span><span class="p">>(),</span> <span class="nf">not</span><span class="p">(</span><span class="nf">emptyString</span><span class="p">()))</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In the above example the <code class="language-text highlighter-rouge">fixture</code> global property outlives the test’s lifecycle and leaks the <code class="language-text highlighter-rouge">""</code> customisation to the other test, which expects <code class="language-text highlighter-rouge">JFixture</code>’s default behaviour.
This expectation is usually implicit when writing fixtured tests.</p>
<p>As seen above, sharing state between a single test class’ methods is risky. We always use non-static <code class="language-text highlighter-rouge">JFixture</code> instance set up in <code class="language-text highlighter-rouge">@BeforeEach</code> to prevent cross-test customisations:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">private</span> <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">fixture</span><span class="p">:</span> <span class="nc">JFixture</span>
<span class="nd">@BeforeEach</span> <span class="k">fun</span> <span class="nf">setUp</span><span class="p">()</span> <span class="p">{</span>
<span class="n">fixture</span> <span class="p">=</span> <span class="nc">JFixture</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>
<p>If we share <code class="language-text highlighter-rouge">fixture</code> like this and put customisations into the <code class="language-text highlighter-rouge">setUp</code> method, we could end up with not fully self-contained tests. Your mileage may vary on how much shared setup is acceptable in your project. This is a similar decision to how/where <code class="language-text highlighter-rouge">mock()</code> variables are set up and stubbed.</p>
<p>Note that having <code class="language-text highlighter-rouge">private val fixture = JFixture()</code> inside the class may not be enough,
because the test runner may create an instance per test class, not per test method: Google <code class="language-text highlighter-rouge">@TestInstance(PER_CLASS)</code> for more information on when this could break down.</p>
<h3 id="sharing-data-setup">Sharing data setup</h3>
<p>That being said, sharing setup is a good idea.
For example, if all the tests create objects which have <code class="language-text highlighter-rouge">CharSequence</code> fields, the following setup makes sure that is possible in each test:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nd">@BeforeEach</span> <span class="k">fun</span> <span class="nf">setUp</span><span class="p">()</span> <span class="p">{</span>
<span class="n">fixture</span> <span class="p">=</span> <span class="nc">JFixture</span><span class="p">()</span>
<span class="n">fixture</span><span class="p">.</span><span class="nf">apply</span> <span class="p">{</span>
<span class="nf">customise</span><span class="p">().</span><span class="nf">useSubType</span><span class="p">(</span><span class="nc">CharSequence</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">,</span> <span class="nc">String</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Notice that it’s only the code being shared, not the run-time objects.</p>
<h3 id="centralized-fixture">Centralized Fixture</h3>
<p>Taking it a step further, it’s very likely we’ll end up having very common customisations.
<code class="language-text highlighter-rouge">CharSequence</code> → <code class="language-text highlighter-rouge">String</code> is a good example; it could occur often in Android.
It is recommended to create a custom type that builds on JFixture:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">class</span> <span class="nc">MyFixture</span> <span class="p">:</span> <span class="nc">JFixture</span><span class="p">()</span> <span class="p">{</span>
<span class="nf">init</span> <span class="p">{</span>
<span class="nf">customise</span><span class="p">().</span><span class="nf">useSubType</span><span class="p">(</span><span class="nc">CharSequence</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">,</span> <span class="nc">String</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>It helps:</p>
<ul>
<li>sharing customisations</li>
<li>sharing fixture related utility methods<br />
(not so beneficial when we can use Kotlin extension methods, but it is in Java)</li>
<li>creating a better API fitting your style<br />
(if you go with encapsulation over inheritance)</li>
</ul>
<p>That said, we are not using this pattern, because we prefer easily discoverable and focused test setups.</p>
<h3 id="stubbing-fixture-behaviour">Stubbing fixture behaviour</h3>
<p>Let’s see what happens if our data classes have calculated properties, for example:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">data class</span> <span class="nc">Journey</span><span class="p">(</span>
<span class="c1">// ...</span>
<span class="kd">val</span> <span class="py">legs</span><span class="p">:</span> <span class="nc">List</span><span class="p"><</span><span class="nc">Leg</span><span class="p">>,</span>
<span class="p">)</span> <span class="p">{</span>
<span class="kd">val</span> <span class="py">changeCount</span> <span class="k">get</span><span class="p">()</span> <span class="p">=</span> <span class="n">legs</span><span class="p">.</span><span class="n">size</span> <span class="p">-</span> <span class="mi">1</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This is very simple, but it can easily get complicated, in which case setting up the fixture to be exactly correct for the calculated property could be tricky.
At this point you might be thinking: let’s mock the logic to isolate it, but it’s on a JFixture generated class.
Mockito spies come to the rescue:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">val</span> <span class="py">spyJourney</span> <span class="p">=</span> <span class="nf">spy</span><span class="p">(</span><span class="n">fixture</span><span class="p"><</span><span class="nc">Journey</span><span class="p">>())</span>
<span class="nf">doReturn</span><span class="p">(</span><span class="mi">6</span><span class="p">).</span><span class="nf">whenever</span><span class="p">(</span><span class="n">spyJourney</span><span class="p">).</span><span class="n">changeCount</span>
</code></pre></div></div>
<div class="alert-box warning radius ">
<p>Beware: when using <code class="language-text highlighter-rouge">spy</code>s, we must always use the <code class="language-text highlighter-rouge">doReturn(result).when(spy).method(args)</code> pattern,
otherwise the real method gets called, which can cause problems.</p>
</div>
<p>Tip: even when using annotated setup, it’s possible to combine the two frameworks:</p>
<div title="JourneyPresenterTest" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nd">@Mock</span> <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">mockView</span><span class="p">:</span> <span class="nc">JourneyView</span>
<span class="nd">@Mock</span> <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">mockDataSource</span><span class="p">:</span> <span class="nc">DataSource</span><span class="p"><</span><span class="nc">Journey</span><span class="p">></span>
<span class="nd">@Mock</span> <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">mockMapper</span><span class="p">:</span> <span class="p">(</span><span class="nc">Journey</span><span class="p">)</span> <span class="p">-></span> <span class="nc">Model</span>
<span class="nd">@Fixture</span> <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">fixtJourneyId</span><span class="p">:</span> <span class="nc">String</span>
<span class="nd">@Spy</span> <span class="nd">@Fixture</span> <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">spyJourney</span><span class="p">:</span> <span class="nc">Journey</span>
<span class="nd">@Fixture</span> <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">fixtModel</span><span class="p">:</span> <span class="nc">Model</span>
<span class="k">private</span> <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">fixture</span><span class="p">:</span> <span class="nc">JFixture</span>
<span class="k">private</span> <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">sut</span><span class="p">:</span> <span class="nc">JourneyPresenter</span>
<span class="nd">@BeforeEach</span> <span class="k">fun</span> <span class="nf">setUp</span><span class="p">()</span> <span class="p">{</span>
<span class="n">fixture</span> <span class="p">=</span> <span class="nc">JFixture</span><span class="p">()</span>
<span class="nc">FixtureAnnotations</span><span class="p">.</span><span class="nf">initFixtures</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="n">fixture</span><span class="p">)</span>
<span class="nc">MockitoAnnotations</span><span class="p">.</span><span class="nf">initMocks</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
<span class="n">sut</span> <span class="p">=</span> <span class="nc">JourneyPresenter</span><span class="p">(</span><span class="n">mockView</span><span class="p">,</span> <span class="n">mockDataSource</span><span class="p">,</span> <span class="n">mockMapper</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The important thing here is to have <code class="language-text highlighter-rouge">initMocks</code> <strong>after</strong> <code class="language-text highlighter-rouge">initFixtures</code>.</p>
<h2 id="pitfalls">Pitfalls</h2>
<p>No tool is without its drawbacks — here are some interesting problems we have encountered while using JFixture.</p>
<h3 id="kotlin-generics-interoperability">Kotlin generics interoperability</h3>
<p>Kotlin makes every usage of a generic <code class="language-text highlighter-rouge">out T</code> (e.g. <code class="language-text highlighter-rouge">kotlin.collections.List<T></code>) automatically appear in the class files as <code class="language-text highlighter-rouge">? extends T</code>.
JFixture doesn’t like this, because there’s no right choice for it to pick when creating test data.
The workaround we use is adding <code class="language-text highlighter-rouge">@JvmSuppressWildcards</code> on the field declarations like so:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nd">@Fixture</span> <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">fixtJourneys</span><span class="p">:</span> <span class="nc">List</span><span class="p"><</span><span class="err">@</span><span class="nc">JvmSuppressWildcards</span> <span class="nc">Journey</span><span class="p">></span>
</code></pre></div></div>
<h3 id="customise-the-right-jfixture">Customise the right JFixture</h3>
<p>When using the annotated setup, it’s quite easy to end up using the wrong <code class="language-text highlighter-rouge">JFixture</code> instance and wonder why none of our customisations work:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nd">@Fixture</span> <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">fixtModel</span><span class="p">:</span> <span class="nc">Model</span>
<span class="k">private</span> <span class="k">lateinit</span> <span class="kd">var</span> <span class="py">fixture</span><span class="p">:</span> <span class="nc">JFixture</span>
<span class="nd">@BeforeEach</span> <span class="k">fun</span> <span class="nf">setUp</span><span class="p">()</span> <span class="p">{</span>
<span class="n">fixture</span> <span class="p">=</span> <span class="nc">JFixture</span><span class="p">()</span>
<span class="n">fixture</span><span class="p">.</span><span class="nf">customise</span><span class="p">()</span><span class="o">....</span>
<span class="nc">FixtureAnnotations</span><span class="p">.</span><span class="nf">initFixtures</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The problem here is using the wrong <code class="language-text highlighter-rouge">initFixtures</code> overload.
When we create and customise a <code class="language-text highlighter-rouge">JFixture</code> instance, we need to call <code class="language-text highlighter-rouge">initFixtures(this, fixture)</code>; otherwise <code class="language-text highlighter-rouge">initFixtures</code> will create a new non-customised <code class="language-text highlighter-rouge">JFixture</code> instance.</p>
<h3 id="beware-of-overloads">Beware of overloads</h3>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="n">fixture</span><span class="p">.</span><span class="nf">customise</span><span class="p">().</span><span class="nf">useSubType</span><span class="p">(</span><span class="nc">CharSequence</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">,</span> <span class="nc">String</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>
<span class="n">fixture</span><span class="p">.</span><span class="nf">customise</span><span class="p">().</span><span class="nf">sameInstance</span><span class="p">(</span><span class="nc">CharSequence</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">,</span> <span class="nc">String</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>
</code></pre></div></div>
<p>Let’s say we wanted to use <code class="language-text highlighter-rouge">useSubType</code>, but accidentally used <code class="language-text highlighter-rouge">sameInstance</code>. This makes a subtle difference when it’s one of the hundreds of lines of test code. Sadly, this compiles, and when JFixture tries to create an instance of <code class="language-text highlighter-rouge">CharSequence</code>, it throws a <code class="language-text highlighter-rouge">ClassCastException</code>: cannot cast <code class="language-text highlighter-rouge">Class<String></code> to <code class="language-text highlighter-rouge">CharSequence</code>. This is because <code class="language-text highlighter-rouge">sameInstance</code> has an overload that matches the arguments:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">public</span> <span class="kd">interface</span> <span class="nc">FluentCustomisation</span> <span class="o">{</span>
<span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="nc">FluentCustomisation</span> <span class="nf">sameInstance</span><span class="o">(</span><span class="nc">Class</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="n">clazz</span><span class="o">,</span> <span class="no">T</span> <span class="n">instance</span><span class="o">);</span>
<span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="nc">FluentCustomisation</span> <span class="nf">sameInstance</span><span class="o">(</span><span class="nc">Type</span> <span class="n">type</span><span class="o">,</span> <span class="no">T</span> <span class="n">instance</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p><code class="language-text highlighter-rouge">Class<*></code> implements <code class="language-text highlighter-rouge">Type</code> so when the <code class="language-text highlighter-rouge">instance</code> argument is not a subclass of <code class="language-text highlighter-rouge">T</code> in <code class="language-text highlighter-rouge">clazz</code>, the overload resolution finds the <code class="language-text highlighter-rouge">Type</code> overload and <code class="language-text highlighter-rouge">T</code> becomes <code class="language-text highlighter-rouge">Class<String></code>.</p>
<h3 id="flaky-tests">Flaky tests</h3>
<p>One of the main benefits of JFixture is reproducibility through constrained non-determinism.
In practice this means that if tests fail on one computer (e.g. CI) they’ll fail the same way on another (e.g. dev machine).
Mind you, this failure may not be immediate, but it’s eventually reproducible.
Don’t fret though, it’s not as bad as the <a href="https://en.wikipedia.org/wiki/Infinite_monkey_theorem">infinite monkey theorem</a> states.
In practice, we observed that if we see a flaky test on the CI, we can simply run the test a 100 times and we’ll see some failures:</p>
<p><img src="data:image/png;base64,
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
QmCC" alt="Run/Debug Configurations > JUnit > Configuration > Repeat > N Times" /></p>
<p>Here’s an example flaky test that will pass 90% of the time:</p>
<div title="Production code" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">enum</span> <span class="kd">class</span> <span class="nc">Type</span> <span class="p">{</span> <span class="nc">Other</span><span class="p">,</span> <span class="nc">Type1</span><span class="p">,</span> <span class="nc">Type2</span><span class="p">,</span> <span class="nc">Type3</span><span class="p">,</span> <span class="nc">Type4</span><span class="p">,</span> <span class="nc">Type5</span><span class="p">,</span> <span class="nc">Type6</span><span class="p">,</span> <span class="nc">Type7</span><span class="p">,</span> <span class="nc">Type8</span><span class="p">,</span> <span class="nc">Type9</span> <span class="p">}</span>
<span class="k">fun</span> <span class="nc">Type</span><span class="p">.</span><span class="nf">isValidType</span><span class="p">()</span> <span class="p">=</span> <span class="k">this</span> <span class="p">!=</span> <span class="nc">Other</span>
</code></pre></div></div>
<div title="Test code" class="language-kotlin highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nd">@Test</span> <span class="k">fun</span> <span class="nf">flaky90</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">val</span> <span class="py">fixture</span> <span class="p">=</span> <span class="nc">JFixture</span><span class="p">()</span>
<span class="kd">val</span> <span class="py">fixtType</span><span class="p">:</span> <span class="nc">Type</span> <span class="p">=</span> <span class="nf">fixture</span><span class="p">()</span>
<span class="kd">val</span> <span class="py">result</span> <span class="p">=</span> <span class="n">fixtType</span><span class="p">.</span><span class="nf">isValidType</span><span class="p">()</span>
<span class="nf">assertTrue</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This could mean that if you run the test a few times, and the code reviewer runs it,
and the CI runs it; it’s still going to pass all those times, but then when you merge to the default branch, it fails.
The above example is over-simplified, but even the most complex flaky tests we had of this type weren’t that hard to debug and fix.
Notice that the reason for failure is assuming what the fixture will generate.
If this <code class="language-text highlighter-rouge">isValidType</code> is used in an <code class="language-text highlighter-rouge">if</code>, that behaviour will trigger 90% of the time.
To fix this test, we need to use <code class="language-text highlighter-rouge">valuesExcluding</code> technique described in the <a href="#property-customisation">Property Customisation</a> section,
and write a separate test for <code class="language-text highlighter-rouge">Other</code> specifically.
Bear in mind that in some cases we need to consider that the <code class="language-text highlighter-rouge">isValidType</code>’s input should be parameterised to test all possibilities (not just a random one), but that’s a topic for another time.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Introducing JFixture to an existing project is a big leap, but we think it’s worth the effort and the learning curve is not that bad.
There will be times when you scratch your heads, but you’ll learn something new each time, until you develop a solid stable usage pattern.
I personally found it very useful to debug into JFixture when something is wrong.
Give it a whirl and let me know how you find the framework.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/FlexTradeUKLtd/jfixture">JFixture library’s GitHub repository</a></li>
<li><a href="https://github.com/FlexTradeUKLtd/jfixture/wiki">JFixture library’s documentation</a></li>
<li><a href="https://github.com/TWiStErRob/TWiStErRob/tree/main/JFixturePlayground">Example code used</a></li>
</ul>
2019-03-10T00:00:00+00:00https://www.twisterrob.net/blog/2017/12/import-git-repo-to-svn-folder.htmlImport a GIT repository to an SVN repository's subfolder preserving history2017-12-01T00:00:00+00:00with full reproducible example<p>I had an interview for which I created a GIT repo, but I wanted to import it into my personal monolyth SVN repo.<!--more--> After some Googling I found some examples, and this was the simplest solution. I decided to re-write from the original it in hopes that it’ll be more discoverable.</p>
<h2 id="intro">Intro</h2>
<p>I’ll be doing everything on Windows and using spaces in paths, because that’s trickier, and to show that these things are not evil ;). Obviously, all these work on Unix systems as well, just convert the paths to use forward slashes and ignore the drive letters.</p>
<h2 id="initial-state">Initial state</h2>
<ul>
<li>
<p>GIT repository with a project on a branch<br />
(simple Gradle project shown, with 3 commits that created it)</p>
<div title="structure" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code> + src
+ main
+ java
- Test.java
- build.gradle
- README.md
</code></pre></div> </div>
<div title="branches & commits" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code> main: A --- B --- C
</code></pre></div> </div>
</li>
<li>
<p>SVN repository with projects in subfolders<br />
(I have 4 projects in 2 groups, with 6 commits that created these)</p>
<div title="structure" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code> + project group 1
+ project 1
+ project 2
+ project group 2
+ project 3
+ project 4
</code></pre></div> </div>
<div title="branches & commits" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code> svn: pg1 --- p1 --- p2 --- pg2 --- p3 --- p4
</code></pre></div> </div>
</li>
</ul>
<h2 id="goal">Goal</h2>
<p>To grab the GIT repository contents into <samp>project group 2/project 5</samp> subfolder of the SVN repository.</p>
<div title="structure" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>+ project group 1
+ project 1
+ project 2
+ project group 2
+ project 3
+ project 4
+ project 5
+ src
+ main
+ java
- Test.java
- build.gradle
- README.md
</code></pre></div></div>
<div title="branches & commits" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>svn: pg1 --- p1 --- p2 --- pg2 --- p3 --- p4 --- A --- B --- C
</code></pre></div></div>
<h2 id="set-up">Set-up</h2>
<p>I’ll be using local repositories to do everything; meaning there’s no network requests going on. It should be easy to generalize this to remote repositories.</p>
<p>The GIT repository is located in: <samp>P:\temp\git repo</samp></p>
<div title="setup steps executed starting in P:\temp if you want to follow along" class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>git init <span class="s2">"git repo"</span>
<span class="nb">cd</span> <span class="s2">"git repo"</span>
<span class="nb">echo</span> <span class="s2">"Test repo"</span> <span class="o">></span> README.md
git add <span class="nt">--all</span> <span class="o">&&</span> git commit <span class="nt">--message</span> <span class="s2">"Init repo"</span>
<span class="nb">echo</span> <span class="s2">"apply plugin: java"</span> <span class="o">></span> build.gradle
git add <span class="nt">--all</span> <span class="o">&&</span> git commit <span class="nt">--message</span> <span class="s2">"Init project"</span>
<span class="nb">mkdir </span>src<span class="se">\m</span>ain<span class="se">\j</span>ava
<span class="nb">echo</span> <span class="s2">"public class Test { public static void main(String... args) { System.out.println(""Hello""); } }"</span> <span class="o">></span> src<span class="se">\m</span>ain<span class="se">\j</span>ava<span class="se">\T</span>est.java
git add <span class="nt">--all</span> <span class="o">&&</span> git commit <span class="nt">--message</span> <span class="s2">"Add code"</span>
</code></pre></div></div>
<p>The SVN repository is located in: <samp>P:\temp\svn repo</samp> (Note: original repository, not the checked-out files)</p>
<div title="setup steps executed starting in P:\temp if you want to follow along" class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>svnadmin create <span class="s2">"svn repo"</span>
svn <span class="nb">mkdir</span> <span class="s2">"file://P:/temp/svn repo/project group 1"</span> <span class="nt">-m</span> <span class="s2">"add project group 1"</span>
svn <span class="nb">mkdir</span> <span class="s2">"file://P:/temp/svn repo/project group 1/project 1"</span> <span class="nt">-m</span> <span class="s2">"add project 1"</span>
svn <span class="nb">mkdir</span> <span class="s2">"file://P:/temp/svn repo/project group 1/project 2"</span> <span class="nt">-m</span> <span class="s2">"add project 2"</span>
svn <span class="nb">mkdir</span> <span class="s2">"file://P:/temp/svn repo/project group 2"</span> <span class="nt">-m</span> <span class="s2">"add project group 2"</span>
svn <span class="nb">mkdir</span> <span class="s2">"file://P:/temp/svn repo/project group 2/project 3"</span> <span class="nt">-m</span> <span class="s2">"add project 3"</span>
svn <span class="nb">mkdir</span> <span class="s2">"file://P:/temp/svn repo/project group 2/project 4"</span> <span class="nt">-m</span> <span class="s2">"add project 4"</span>
svn checkout <span class="s2">"file://P:/temp/svn repo"</span> svn
</code></pre></div></div>
<div class="alert-box info radius "><p>Sadly I couldn’t find a way yet to clone the SVN repo via <code class="language-text highlighter-rouge">git svn</code> with <code class="language-text highlighter-rouge">file:///</code> url, so in the SVN repo you’ll need to <code class="language-text highlighter-rouge">svnserve -d --listen-port 1234 -r P:\temp\svn-repo</code> for it to be accessible on <code class="language-text highlighter-rouge">svn://localhost:1234</code> (edit <code class="language-text highlighter-rouge">P:\temp\svn-repo\conf\svn-serve.conf</code> to include <code class="language-text highlighter-rouge">anon-access=write</code> in <code class="language-text highlighter-rouge">[general]</code> block; or otherwise configure your access rights).</p>
</div>
<h2 id="steps">Steps</h2>
<ul>
<li>Prepare folder (<code class="language-text highlighter-rouge">svn mkdir</code>)</li>
<li>Check out SVN via git (<code class="language-text highlighter-rouge">git svn clone</code>)</li>
<li>Link GIT (<code class="language-text highlighter-rouge">git remote add</code>)</li>
<li>Link commits (<code class="language-text highlighter-rouge">git rebase</code>)</li>
<li>Send to SVN (<code class="language-text highlighter-rouge">git merge --ff-only</code> & <code class="language-text highlighter-rouge">git svn dcommit</code>)</li>
</ul>
<h3 id="create-hosting-folder-in-svn-repository">Create hosting folder in SVN repository</h3>
<p>A folder needs to be created to host the project in SVN. This is required to be able to put the branch from GIT repo into a subfolder.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>svn <span class="nb">mkdir</span> <span class="s2">"svn://localhost:1234/project group 2/project 5"</span> <span class="nt">-m</span> <span class="s2">"prepare project 5"</span>
</code></pre></div></div>
<p>at this point we’ve added an extra commit to SVN. It would be nice to skip this from the steps, but didn’t find a way yet.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>root
+ ...
+ project group 2
+ project 5
</code></pre></div></div>
<div title="branches & commits" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>svn: pg1 --- p1 --- p2 --- pg2 --- p3 --- p4 --- prep
</code></pre></div></div>
<h3 id="prepare-bridge-repo-from-svn">Prepare bridge repo from SVN</h3>
<p>We’ll clone the actual project subfolder from the SVN repo, this is why it was required to exist beforehand.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>git svn clone <span class="s2">"svn://localhost:1234/project group 2/project 5"</span> <span class="s2">"svn via git"</span>
</code></pre></div></div>
<h3 id="link-up-the-bridge-repo-with-git">Link up the bridge repo with GIT</h3>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nb">cd</span> <span class="s2">"svn via git"</span>
git remote add bridge <span class="s2">"P:</span><span class="se">\t</span><span class="s2">emp</span><span class="se">\g</span><span class="s2">it repo"</span>
git fetch bridge
</code></pre></div></div>
<div title="branches & commits" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>main: pg1 --- p1 --- p2 --- pg2 --- p3 --- p4 --- prep
bridge/main: A --- B --- C
</code></pre></div></div>
<div class="alert-box warning radius "><p>It is really important to step into the bridge repo folder, otherwise you may get an error like this:</p>
<blockquote>
<p>fatal: Not a git repository (or any of the parent directories): .git</p>
</blockquote>
</div>
<h3 id="prepare-commits-to-be-put-on-top-of-the-svn-repo">Prepare commits to be put on top of the SVN repo</h3>
<p>Create working copy of the GIT repo (<code class="language-text highlighter-rouge">bridge/main</code>) and put its history (<code class="language-text highlighter-rouge">import</code>) on top of the SVN folder’s history (<code class="language-text highlighter-rouge">main</code>).</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>git checkout <span class="nt">-b</span> import bridge/main
git rebase <span class="nt">-i</span> main
</code></pre></div></div>
<div title="branches & commits after checkout" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>main: pg1 --- p1 --- p2 --- pg2 --- p3 --- p4 --- prep
import: A --- B --- C
bridge/main: A --- B --- C
</code></pre></div></div>
<div title="branches & commits after rebase" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>main: pg1 --- p1 --- p2 --- pg2 --- p3 --- p4 --- prep
\
import: A' --- B' --- C'
bridge/main: A --- B --- C
</code></pre></div></div>
<div class="alert-box info radius "><p>This is the point where you can edit the history, filter the branch, reword commits, etc.. Just <code class="language-text highlighter-rouge">rebase -i main</code> as much as you want.</p>
</div>
<h3 id="finalize-the-process">Finalize the process</h3>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>git checkout main
git merge <span class="nt">--ff-only</span> import
</code></pre></div></div>
<div title="branches & commits" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>main: pg1 --- p1 --- p2 --- pg2 --- p3 --- p4 --- prep --- A' --- B' --- C'
\
import: A' --- B' --- C'
bridge/main: A --- B --- C
</code></pre></div></div>
<p>After checking that everything is correct <code class="language-text highlighter-rouge">git log</code>, <code class="language-text highlighter-rouge">gitk</code> and the like push the changes to the SVN repo via <code class="language-text highlighter-rouge">git svn dcommit</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://stackoverflow.com/questions/661018/pushing-an-existing-git-repository-to-svn">StackOverflow question with tricky answers</a></li>
<li><a href="https://chani.wordpress.com/2012/01/25/the-easy-way-to-import-from-git-into-svn/">Original idea and credit</a></li>
<li><a href="https://svnbook.red-bean.com/en/1.7/svn.ref.svn.c.mkdir.html"><code class="language-text highlighter-rouge">svn mkdir</code></a></li>
<li><a href="https://git-scm.com/docs/git-svn"><code class="language-text highlighter-rouge">git svn</code></a></li>
</ul>
2017-12-01T00:00:00+00:00https://www.twisterrob.net/blog/2016/09/android-xml-colors.htmlColor support for XML string resources in Android2016-09-20T00:00:00+00:00I challenge you to find anything more inconsistent than this!<p>So you read somewhere that Android supports <code class="language-text highlighter-rouge"><font></code> tags to color <code class="language-text highlighter-rouge">string</code> resources, when used with <code class="language-text highlighter-rouge">Resources#getText()</code>? Well, yeah, except…<!--more--></p>
<p>… there’s no uniform way across SDK platform versions to represent “this text should be red” with just a String resource.</p>
<p>Following is a summary and excerpt of the code handling XML font colors in Android. I tried to make it easier to digest than just raw code. The codes did not change between the listed versions unless otherwise noted.
The sources come from</p>
<ul>
<li><code class="language-text highlighter-rouge">android.content.res.StringBlock</code>: parses tags and attributes</li>
<li><code class="language-text highlighter-rouge">com.android.internal.util.XmlUtils</code>: parses numbers as colors</li>
<li><code class="language-text highlighter-rouge">android.graphics.Color</code>: color handling</li>
</ul>
<p>(They’re all available in <samp>android-sdk/sources</samp> folder, but to see them in IDEA you have use the <mark>Navigate > File</mark> action instead of <mark>Navigate > Class</mark> because they’re <code class="language-text highlighter-rouge">@hide</code>.)</p>
<h2 id="api-level-10-1417">API Level 10, 14—17</h2>
<dl>
<dt>Attribute names</dt>
<dd><code class="language-text highlighter-rouge">fgcolor</code><br />
(via <code class="language-text highlighter-rouge">XmlUtils.convertValueToUnsignedInt -> parseLong</code>)</dd>
<dt>Base prefixes</dt>
<dd><code class="language-text highlighter-rouge">0</code> (octal), <code class="language-text highlighter-rouge">0x</code> (hexadecimal), <code class="language-text highlighter-rouge">#</code> (hexadecimal)</dd>
<dt>Number formats</dt>
<dd><code class="language-text highlighter-rouge">Bd*</code>, <code class="language-text highlighter-rouge">B-d*</code><br />
(<code class="language-text highlighter-rouge">B</code> is the base prefix above, <code class="language-text highlighter-rouge">d*</code> is any resonable number of digits in that base)</dd>
<dt>Color range</dt>
<dd>full ARGB</dd>
<dt>Exceptions</dt>
<dd>
<ul>
<li><code class="language-text highlighter-rouge">null</code>: no effect (guarded in <code class="language-text highlighter-rouge">StringBlock</code>)</li>
<li>empty string: crash</li>
<li><code class="language-text highlighter-rouge">@system_color_res</code>: crash <code class="language-text highlighter-rouge">NumberFormatException</code></li>
<li>named color: crash <code class="language-text highlighter-rouge">NumberFormatException</code></li>
</ul>
</dd>
</dl>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span>
<span class="nf">convertValueToUnsignedInt</span><span class="o">(</span><span class="nc">String</span> <span class="n">value</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">)</span>
<span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="kc">null</span> <span class="o">==</span> <span class="n">value</span><span class="o">)</span>
<span class="k">return</span> <span class="n">defaultValue</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">parseUnsignedIntAttribute</span><span class="o">(</span><span class="n">value</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span>
<span class="nf">parseUnsignedIntAttribute</span><span class="o">(</span><span class="nc">CharSequence</span> <span class="n">charSeq</span><span class="o">)</span>
<span class="o">{</span>
<span class="nc">String</span> <span class="n">value</span> <span class="o">=</span> <span class="n">charSeq</span><span class="o">.</span><span class="na">toString</span><span class="o">();</span>
<span class="kt">long</span> <span class="n">bits</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">len</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="na">length</span><span class="o">();</span>
<span class="kt">int</span> <span class="n">base</span> <span class="o">=</span> <span class="mi">10</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="sc">'0'</span> <span class="o">==</span> <span class="n">value</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">index</span><span class="o">))</span> <span class="o">{</span>
<span class="c1">// Quick check for zero by itself</span>
<span class="k">if</span> <span class="o">(</span><span class="n">index</span> <span class="o">==</span> <span class="o">(</span><span class="n">len</span> <span class="o">-</span> <span class="mi">1</span><span class="o">))</span>
<span class="k">return</span> <span class="mi">0</span><span class="o">;</span>
<span class="kt">char</span> <span class="n">c</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">index</span> <span class="o">+</span> <span class="mi">1</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="sc">'x'</span> <span class="o">==</span> <span class="n">c</span> <span class="o">||</span> <span class="sc">'X'</span> <span class="o">==</span> <span class="n">c</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// check for hex</span>
<span class="n">index</span> <span class="o">+=</span> <span class="mi">2</span><span class="o">;</span>
<span class="n">base</span> <span class="o">=</span> <span class="mi">16</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span> <span class="c1">// check for octal</span>
<span class="n">index</span><span class="o">++;</span>
<span class="n">base</span> <span class="o">=</span> <span class="mi">8</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="sc">'#'</span> <span class="o">==</span> <span class="n">value</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">index</span><span class="o">))</span> <span class="o">{</span>
<span class="n">index</span><span class="o">++;</span>
<span class="n">base</span> <span class="o">=</span> <span class="mi">16</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="nc">Long</span><span class="o">.</span><span class="na">parseLong</span><span class="o">(</span><span class="n">value</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="n">index</span><span class="o">),</span> <span class="n">base</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="api-level-1822">API Level 18—22</h2>
<dl>
<dt>Attribute names</dt>
<dd><code class="language-text highlighter-rouge">fgcolor</code>, <code class="language-text highlighter-rouge">color</code><br />
(via <code class="language-text highlighter-rouge">getColor -> Color.getHtmlColor -> XmlUtils.convertValueToInt -> parseInt</code>)</dd>
<dt>Base prefixes</dt>
<dd><code class="language-text highlighter-rouge">0</code> (octal), <code class="language-text highlighter-rouge">0x</code> (hexadecimal), <code class="language-text highlighter-rouge">#</code> (hexadecimal)</dd>
<dt>Number formats</dt>
<dd><code class="language-text highlighter-rouge">Bd*</code>, <code class="language-text highlighter-rouge">-Bd*</code>, <code class="language-text highlighter-rouge">B-d*</code>, <code class="language-text highlighter-rouge">-B+d*</code>, <code class="language-text highlighter-rouge">-B-d*</code><br />
(<code class="language-text highlighter-rouge">B</code> is the base prefix above, <code class="language-text highlighter-rouge">d*</code> is any resonable number of digits in that base)</dd>
<dt>Color range</dt>
<dd>partial ARGB (<code class="language-text highlighter-rouge">alpha <= 0x7f</code>)</dd>
<dt>Exceptions</dt>
<dd>
<ul>
<li><code class="language-text highlighter-rouge">null</code>: no effect (guarded in <code class="language-text highlighter-rouge">StringBlock</code>)</li>
<li>empty string: 0xff000000 (= BLACK)</li>
<li><code class="language-text highlighter-rouge">@system_color_res</code>: works</li>
<li>named color: works<br />
<em>(except it may be problematic on API Level 18: the explicit <code class="language-text highlighter-rouge">Locale.ROOT</code> is missing from <code class="language-text highlighter-rouge">toLowerCase</code>.
For example, this causes <code class="language-text highlighter-rouge">color="LIME"</code> to be interpreted as <code class="language-text highlighter-rouge">lıme</code> in <code class="language-text highlighter-rouge">tr-TR</code> (Turkish) locale;
notice there is no dot on the <code class="language-text highlighter-rouge">i</code>!)</em></li>
<li>invalid named color: -1 (= 0xFFFFFFFF = WHITE)</li>
<li>invalid format: -1 (= 0xFFFFFFFF = WHITE)</li>
<li>numeric color above 0x7fffffff: -1 (= 0xFFFFFFFF = WHITE)</li>
</ul>
</dd>
</dl>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">private</span> <span class="kd">static</span> <span class="nc">CharacterStyle</span> <span class="nf">getColor</span><span class="o">(</span><span class="nc">String</span> <span class="n">color</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">foreground</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="mh">0xff000000</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(!</span><span class="nc">TextUtils</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">(</span><span class="n">color</span><span class="o">))</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">color</span><span class="o">.</span><span class="na">startsWith</span><span class="o">(</span><span class="s">"@"</span><span class="o">))</span> <span class="o">{</span>
<span class="nc">Resources</span> <span class="n">res</span> <span class="o">=</span> <span class="nc">Resources</span><span class="o">.</span><span class="na">getSystem</span><span class="o">();</span>
<span class="nc">String</span> <span class="n">name</span> <span class="o">=</span> <span class="n">color</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">1</span><span class="o">);</span>
<span class="kt">int</span> <span class="n">colorRes</span> <span class="o">=</span> <span class="n">res</span><span class="o">.</span><span class="na">getIdentifier</span><span class="o">(</span><span class="n">name</span><span class="o">,</span> <span class="s">"color"</span><span class="o">,</span> <span class="s">"android"</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">colorRes</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">ColorStateList</span> <span class="n">colors</span> <span class="o">=</span> <span class="n">res</span><span class="o">.</span><span class="na">getColorStateList</span><span class="o">(</span><span class="n">colorRes</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">foreground</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">TextAppearanceSpan</span><span class="o">(</span><span class="kc">null</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">colors</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">colors</span><span class="o">.</span><span class="na">getDefaultColor</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">c</span> <span class="o">=</span> <span class="nc">Color</span><span class="o">.</span><span class="na">getHtmlColor</span><span class="o">(</span><span class="n">color</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">foreground</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">ForegroundColorSpan</span><span class="o">(</span><span class="n">c</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">BackgroundColorSpan</span><span class="o">(</span><span class="n">c</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">int</span> <span class="nf">getHtmlColor</span><span class="o">(</span><span class="nc">String</span> <span class="n">color</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Integer</span> <span class="n">i</span> <span class="o">=</span> <span class="n">sColorNameMap</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">color</span><span class="o">.</span><span class="na">toLowerCase</span><span class="o">(</span><span class="nc">Locale</span><span class="o">.</span><span class="na">ROOT</span><span class="o">));</span>
<span class="k">if</span> <span class="o">(</span><span class="n">i</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">i</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="k">return</span> <span class="nc">XmlUtils</span><span class="o">.</span><span class="na">convertValueToInt</span><span class="o">(</span><span class="n">color</span><span class="o">,</span> <span class="o">-</span><span class="mi">1</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NumberFormatException</span> <span class="n">nfe</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span>
<span class="nf">convertValueToInt</span><span class="o">(</span><span class="nc">CharSequence</span> <span class="n">charSeq</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">)</span>
<span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="kc">null</span> <span class="o">==</span> <span class="n">charSeq</span><span class="o">)</span>
<span class="k">return</span> <span class="n">defaultValue</span><span class="o">;</span>
<span class="nc">String</span> <span class="n">nm</span> <span class="o">=</span> <span class="n">charSeq</span><span class="o">.</span><span class="na">toString</span><span class="o">();</span>
<span class="c1">// XXX This code is copied from Integer.decode() so we don't</span>
<span class="c1">// have to instantiate an Integer!</span>
<span class="kt">int</span> <span class="n">value</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">sign</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">len</span> <span class="o">=</span> <span class="n">nm</span><span class="o">.</span><span class="na">length</span><span class="o">();</span>
<span class="kt">int</span> <span class="n">base</span> <span class="o">=</span> <span class="mi">10</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="sc">'-'</span> <span class="o">==</span> <span class="n">nm</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="mi">0</span><span class="o">))</span> <span class="o">{</span>
<span class="n">sign</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="o">;</span>
<span class="n">index</span><span class="o">++;</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="sc">'0'</span> <span class="o">==</span> <span class="n">nm</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">index</span><span class="o">))</span> <span class="o">{</span>
<span class="c1">// Quick check for a zero by itself</span>
<span class="k">if</span> <span class="o">(</span><span class="n">index</span> <span class="o">==</span> <span class="o">(</span><span class="n">len</span> <span class="o">-</span> <span class="mi">1</span><span class="o">))</span>
<span class="k">return</span> <span class="mi">0</span><span class="o">;</span>
<span class="kt">char</span> <span class="n">c</span> <span class="o">=</span> <span class="n">nm</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">index</span> <span class="o">+</span> <span class="mi">1</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="sc">'x'</span> <span class="o">==</span> <span class="n">c</span> <span class="o">||</span> <span class="sc">'X'</span> <span class="o">==</span> <span class="n">c</span><span class="o">)</span> <span class="o">{</span>
<span class="n">index</span> <span class="o">+=</span> <span class="mi">2</span><span class="o">;</span>
<span class="n">base</span> <span class="o">=</span> <span class="mi">16</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">index</span><span class="o">++;</span>
<span class="n">base</span> <span class="o">=</span> <span class="mi">8</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="sc">'#'</span> <span class="o">==</span> <span class="n">nm</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">index</span><span class="o">))</span>
<span class="o">{</span>
<span class="n">index</span><span class="o">++;</span>
<span class="n">base</span> <span class="o">=</span> <span class="mi">16</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">nm</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="n">index</span><span class="o">),</span> <span class="n">base</span><span class="o">)</span> <span class="o">*</span> <span class="n">sign</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="api-level-2328">API Level 23—28</h2>
<dl>
<dt>Attribute names</dt>
<dd><code class="language-text highlighter-rouge">fgcolor</code>, <code class="language-text highlighter-rouge">color</code><br />
(via <code class="language-text highlighter-rouge">getColor -> Color.parseColor -> parseLong</code>)</dd>
<dt>Base prefixes</dt>
<dd><code class="language-text highlighter-rouge">#</code> (hexadecimal)</dd>
<dt>Number formats</dt>
<dd><code class="language-text highlighter-rouge">#xxxxxx</code>, <code class="language-text highlighter-rouge">#xxxxxxxx</code><br />
(<code class="language-text highlighter-rouge">#</code> is literally the hashmark, <code class="language-text highlighter-rouge">x</code> is hexadecimal digit, strictly 6 or 8 digits)</dd>
<dt>Color range</dt>
<dd>full ARGB</dd>
<dt>Exceptions</dt>
<dd>
<ul>
<li><code class="language-text highlighter-rouge">null</code>: no effect (guarded in <code class="language-text highlighter-rouge">StringBlock</code>)</li>
<li>empty string: 0xff000000 (= BLACK)</li>
<li><code class="language-text highlighter-rouge">@system_color_res</code>: works</li>
<li>named color: works</li>
<li>invalid named color: BLACK (= 0xFF000000)</li>
<li>invalid format: BLACK (= 0xFF000000)</li>
</ul>
</dd>
</dl>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">private</span> <span class="kd">static</span> <span class="nc">CharacterStyle</span> <span class="nf">getColor</span><span class="o">(</span><span class="nc">String</span> <span class="n">color</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">foreground</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="mh">0xff000000</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(!</span><span class="nc">TextUtils</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">(</span><span class="n">color</span><span class="o">))</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">color</span><span class="o">.</span><span class="na">startsWith</span><span class="o">(</span><span class="s">"@"</span><span class="o">))</span> <span class="o">{</span>
<span class="nc">Resources</span> <span class="n">res</span> <span class="o">=</span> <span class="nc">Resources</span><span class="o">.</span><span class="na">getSystem</span><span class="o">();</span>
<span class="nc">String</span> <span class="n">name</span> <span class="o">=</span> <span class="n">color</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">1</span><span class="o">);</span>
<span class="kt">int</span> <span class="n">colorRes</span> <span class="o">=</span> <span class="n">res</span><span class="o">.</span><span class="na">getIdentifier</span><span class="o">(</span><span class="n">name</span><span class="o">,</span> <span class="s">"color"</span><span class="o">,</span> <span class="s">"android"</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">colorRes</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">ColorStateList</span> <span class="n">colors</span> <span class="o">=</span> <span class="n">res</span><span class="o">.</span><span class="na">getColorStateList</span><span class="o">(</span><span class="n">colorRes</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">foreground</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">TextAppearanceSpan</span><span class="o">(</span><span class="kc">null</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">colors</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">colors</span><span class="o">.</span><span class="na">getDefaultColor</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">c</span> <span class="o">=</span> <span class="nc">Color</span><span class="o">.</span><span class="na">parseColor</span><span class="o">(</span><span class="n">color</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IllegalArgumentException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">c</span> <span class="o">=</span> <span class="nc">Color</span><span class="o">.</span><span class="na">BLACK</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">foreground</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">ForegroundColorSpan</span><span class="o">(</span><span class="n">c</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">BackgroundColorSpan</span><span class="o">(</span><span class="n">c</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">int</span> <span class="nf">parseColor</span><span class="o">(</span><span class="nc">String</span> <span class="n">colorString</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">colorString</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="mi">0</span><span class="o">)</span> <span class="o">==</span> <span class="sc">'#'</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Use a long to avoid rollovers on #ffXXXXXX</span>
<span class="kt">long</span> <span class="n">color</span> <span class="o">=</span> <span class="nc">Long</span><span class="o">.</span><span class="na">parseLong</span><span class="o">(</span><span class="n">colorString</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">1</span><span class="o">),</span> <span class="mi">16</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">colorString</span><span class="o">.</span><span class="na">length</span><span class="o">()</span> <span class="o">==</span> <span class="mi">7</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Set the alpha value</span>
<span class="n">color</span> <span class="o">|=</span> <span class="mh">0x00000000ff000000</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">colorString</span><span class="o">.</span><span class="na">length</span><span class="o">()</span> <span class="o">!=</span> <span class="mi">9</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"Unknown color"</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">return</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span><span class="n">color</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="nc">Integer</span> <span class="n">color</span> <span class="o">=</span> <span class="n">sColorNameMap</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">colorString</span><span class="o">.</span><span class="na">toLowerCase</span><span class="o">(</span><span class="nc">Locale</span><span class="o">.</span><span class="na">ROOT</span><span class="o">));</span>
<span class="k">if</span> <span class="o">(</span><span class="n">color</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">color</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"Unknown color"</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="special-cases">Special cases</h2>
<ul>
<li>HTC One M8 4.4.2 where named colors crash with <code class="language-text highlighter-rouge">NumberFormatException: Invalid long: "cyan"</code> (sample size is 1, and I’m not sure if it’s a custom ROM or not)</li>
</ul>
<h2 id="solution">Solution?</h2>
<p><strong>Forget colors!</strong>
But seriously, after days of investigation I found no built-in way of doing it.
For full support we have to write code that builds/fixes the <code class="language-text highlighter-rouge">ForegroundColorSpan</code>s’ alpha values or our own parser. At first I thought it’ll work with <code class="language-text highlighter-rouge">color="@res_name"</code>, but that format only supports color resources from the framework’s resources, no custom ones.</p>
<p>Here are some partial solutions that does’t require (much) code. Most of the hacks I tried were based on the fact that <code class="language-text highlighter-rouge">color</code> is parsed after <code class="language-text highlighter-rouge">fgcolor</code> in the code of <code class="language-text highlighter-rouge">StringBlock</code> and <code class="language-text highlighter-rouge">CharSequence</code>’s spans are created in the order that allows <code class="language-text highlighter-rouge">color</code> to win on newer platforms. If you don’t like multiple attributes, you could also nest <code class="language-text highlighter-rouge"><font></code> tags, then the outermost wins.</p>
<p><img src="data:image/png;base64,
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
AABJRU5ErkJggg==" alt="Screenshots of the above techniques" /></p>
<dl>
<dt><code class="language-text highlighter-rouge"><font fgcolor="#FFFF0000" color="red"></code></dt>
<dd>If you want to use a named color you’re in luck! Your designers won’t be happy, but you CAN actually do this.
The above solutions work on all 3 variants of code: the old platforms understand <code class="language-text highlighter-rouge">fgcolor=ARGB</code> correctly, the new platforms support named colors.
Note: this will probably crash on special cases.</dd>
<dt><code class="language-text highlighter-rouge"><font fgcolor="#FFFF0000" color="-#00010000"></code></dt>
<dd>If you don’t care about new platforms… (Who does that?!), then you can use this to support anything below API 23. Old platforms understand <code class="language-text highlighter-rouge">fgcolor=ARGB</code> correctly, and the not-so-old ones support the negative hack.
Note: on new platforms the color will be black, so be careful if you have a dark theme.</dd>
<dt><code class="language-text highlighter-rouge"><font fgcolor="#7FFF0000"></code></dt>
<dd>If you want only <samp>alpha < 128</samp> you’re in luck, because all platforms uniformly support <code class="language-text highlighter-rouge">fgcolor=ARGB</code> in that range.</dd>
<dt><code class="language-text highlighter-rouge">Html.fromHtml("<font color=\"#FF0000\">text</font>")</code></dt>
<dd>If you only want opaque colors and willing to write some minor code, you can use HTML (string can be stored as <code class="language-text highlighter-rouge"><![CDATA[</code> in an XML string resource). But this only supports <code class="language-text highlighter-rouge">RGB</code> colors, no alpha channel. Works on all platforms.</dd>
<dt>…</dt>
<dd>Please share if you find more minimal-code workarounds, I’ll add it here!</dd>
</dl>
<h2 id="references">References</h2>
<ul>
<li><a href="https://stackoverflow.com/questions/9635435/change-word-color-in-resource-string/11577658#comment40124504_11577658">Original conversation and investigation</a></li>
</ul>
2016-09-20T00:00:00+00:00https://www.twisterrob.net/blog/2016/08/android-xslt-function-available.htmlXalan Java Extensions on Android2016-08-13T00:00:00+00:00A saga of finding out, that I can't use them without external dependencies.<p>I wanted to do a simple check to see whether Xalan’s extension functions are available. This would’ve helped speeding up an XML-to-CSV transformation a bit.</p>
<!--more-->
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nt"><xsl:stylesheet</span> <span class="na">xmlns:str=</span><span class="s">"xalan://java.lang.String"</span><span class="nt">></span>
...
<span class="nt"><xsl:variable</span> <span class="na">name=</span><span class="s">"quote"</span><span class="nt">></span><span class="ni">&quot;</span><span class="nt"></xsl:variable></span>
<span class="nt"><xsl:variable</span> <span class="na">name=</span><span class="s">"double-quote"</span><span class="nt">></span><span class="ni">&quot;&quot;</span><span class="nt"></xsl:variable></span>
<span class="nt"><xsl:choose></span>
<span class="nt"><xsl:when</span> <span class="na">test=</span><span class="s">"function-available('str:replaceAll')"</span><span class="nt">></span>
<span class="c"><!-- Happy days, fast replacement! --></span>
<span class="nt"><xsl:value-of</span> <span class="na">select=</span><span class="s">"str:replaceAll(string($text), $quote, $double-quote)"</span> <span class="nt">/></span>
<span class="nt"></xsl:when></span>
<span class="nt"><xsl:otherwise></span>
<span class="c"><!-- Oh well, we have this nice XSLT 1.0-compatbile implementation --></span>
<span class="nt"><xsl:variable</span> <span class="na">name=</span><span class="s">"escaped"</span><span class="nt">></span>
<span class="c"><!-- @see https://stackoverflow.com/a/10528912/253468 --></span>
<span class="nt"><xsl:call-template</span> <span class="na">name=</span><span class="s">"string-replace-all"</span><span class="nt">></span>
<span class="nt"><xsl:with-param</span> <span class="na">name=</span><span class="s">"text"</span> <span class="na">select=</span><span class="s">"$text"</span> <span class="nt">/></span>
<span class="nt"><xsl:with-param</span> <span class="na">name=</span><span class="s">"replace"</span> <span class="na">select=</span><span class="s">"$quote"</span> <span class="nt">/></span>
<span class="nt"><xsl:with-param</span> <span class="na">name=</span><span class="s">"with"</span> <span class="na">select=</span><span class="s">"$double-quote"</span> <span class="nt">/></span>
<span class="nt"></xsl:call-template></span>
<span class="nt"></xsl:variable></span>
<span class="nt"><xsl:value-of</span> <span class="na">select=</span><span class="s">"$escaped"</span> <span class="nt">/></span>
<span class="nt"></xsl:otherwise></span>
<span class="nt"></xsl:choose></span>
</code></pre></div></div>
<p>After running it on my Android phone it just kept spewing <code class="language-text highlighter-rouge">NullPointerException</code>s at me:</p>
<blockquote>
<p>W/System.err: SystemId Unknown; Line #98; Column #3; Attempt to invoke virtual method ‘boolean org.apache.xalan.extensions.ExtensionsTable.functionAvailable(java.lang.String, java.lang.String)’ on a null object reference</p>
</blockquote>
<p>Everything was still working, but I don’t like warnings, so I started looking for the root cause.</p>
<h2 id="xalan-version">Xalan Version</h2>
<p>The source code is not available in the Android SDK. This means that it’s nearly impossible to comperehend what’s going on and use the stepping facilities of the IDE. I didn’t even know where the exception is coming from, because there’s no stack trace.</p>
<p>So I set out to figure out which version of Xalan is running on the device, so I can get the sources. I found that calling <code class="language-text highlighter-rouge">org.apache.xml.serializer.Version.main(new String[0])</code> would give me the answer. It’s not possible to call this from code, not even from an Evaluate while debugging, but the problem was only that it wasn’t known to IDEA, so this worked:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nc">Class</span>
<span class="o">.</span><span class="na">forName</span><span class="o">(</span><span class="s">"org.apache.xml.serializer.Version"</span><span class="o">)</span>
<span class="o">.</span><span class="na">getDeclaredMethod</span><span class="o">(</span><span class="s">"main"</span><span class="o">,</span> <span class="nc">String</span><span class="o">[].</span><span class="na">class</span><span class="o">)</span>
<span class="o">.</span><span class="na">invoke</span><span class="o">(</span><span class="kc">null</span><span class="o">,</span> <span class="k">new</span> <span class="nc">Object</span><span class="o">[]</span> <span class="o">{</span> <span class="k">new</span> <span class="nc">String</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">});</span>
</code></pre></div></div>
<p>The answer was: <q>Serializer Java 2.7.1</q> on both a 2.3.7 and a 5.0.0 device. So I tried to reproduce the issue on my desktop, but the <code class="language-text highlighter-rouge">function-available</code> call worked real good when using <code class="language-text highlighter-rouge">xalan:xalan:2.7.1</code>. <strong>The problem was only reproducible on the phone.</strong> So now, I knew the version of Xalan, and added it to my source path so the IDE can handle debugging. As usual with Android source code, there are some problems with line alignment. I still couldn’t set meaningful breakpoints, but it was possible to set method breakpoints, however slow.</p>
<h2 id="finding-the-sources">Finding the Sources</h2>
<p>So the official Xalan release is not the one I needed. A quick Google search for <code class="language-text highlighter-rouge">TransformerImpl.java</code> revealed that it was once available as <code class="language-text highlighter-rouge">/luni/src/main/java/...</code> in the AOSP <a href="https://android.googlesource.com/platform/libcore">platform/libcore</a> repository. I tried to get the latest by simply jumping to the <code class="language-text highlighter-rouge">master</code> branch, but it wasn’t there. Quick cloning and <code class="language-text highlighter-rouge">git log -- luni/...</code> showed me that the whole <code class="language-text highlighter-rouge">org.apache.xalan</code> package was moved to <code class="language-text highlighter-rouge">/apache-xml</code> in <a href="https://android.googlesource.com/platform/libcore/+/f029395dff382fc4dcba0689fd948ec06644e1f0">f029395</a>. That one still wasn’t on the <code class="language-text highlighter-rouge">master</code> branch, so another <code class="language-text highlighter-rouge">git log</code> revealed that it was deleted and moved to an <q>external</q> repository in <a href="https://android.googlesource.com/platform/libcore/+/e590b9c7ecbe9b35c33fd2d101b1abc6bd7d1489">e590b9c</a>. At first, I was puzzled by what that means, but after a quick look at the <a href="https://android.googlesource.com/?format=HTML">repository listing</a> I found <a href="https://android.googlesource.com/platform/external/apache-xml/">platform/external/apache-xml</a>. Finally this one contained up-to-date code for <a href="https://android.googlesource.com/platform/external/apache-xml/+/refs/heads/lollipop-release">Lollipop</a>.</p>
<h2 id="finally-debugging">Finally Debugging</h2>
<p>Adding the above sources to the IDE source path I was able to browse and debug. I found out the full stack trace:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>java.lang.NullPointerException: Attempt to invoke virtual method 'boolean org.apache.xalan.extensions.ExtensionsTable.functionAvailable(java.lang.String, java.lang.String)' on a null object reference
at org.apache.xalan.transformer.TransformerImpl.functionAvailable(TransformerImpl.java:396)
at org.apache.xpath.functions.FuncExtFunctionAvailable.execute(FuncExtFunctionAvailable.java:89)
at org.apache.xpath.Expression.bool(Expression.java:186)
at org.apache.xpath.XPath.bool(XPath.java:412)
at org.apache.xalan.templates.ElemChoose.execute(ElemChoose.java:103)
at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2223)
at org.apache.xalan.templates.ElemTemplate.execute(ElemTemplate.java:389)
at org.apache.xalan.templates.ElemCallTemplate.execute(ElemCallTemplate.java:241)
at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2223)
at org.apache.xalan.transformer.TransformerImpl.transformToRTF(TransformerImpl.java:1830)
at org.apache.xalan.transformer.TransformerImpl.transformToRTF(TransformerImpl.java:1752)
at org.apache.xalan.templates.ElemVariable.getValue(ElemVariable.java:302)
at org.apache.xalan.templates.ElemVariable.execute(ElemVariable.java:245)
at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2223)
at org.apache.xalan.templates.ElemTemplate.execute(ElemTemplate.java:389)
at org.apache.xalan.templates.ElemCallTemplate.execute(ElemCallTemplate.java:241)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:370)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:175)
at org.apache.xalan.templates.ElemApplyTemplates.transformSelectedNodes(ElemApplyTemplates.java:370)
at org.apache.xalan.templates.ElemApplyTemplates.execute(ElemApplyTemplates.java:175)
at org.apache.xalan.transformer.TransformerImpl.executeChildTemplates(TransformerImpl.java:2223)
at org.apache.xalan.transformer.TransformerImpl.applyTemplateToNode(TransformerImpl.java:2096)
at org.apache.xalan.transformer.TransformerImpl.transformNode(TransformerImpl.java:1228)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:614)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1145)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1123)
</code></pre></div></div>
<p>The reason it worked even with the error is because <code class="language-text highlighter-rouge">XPath#bool</code> catches the exception and just returns <code class="language-text highlighter-rouge">false</code> after logging.</p>
<p>So the question now is: <q>Why is the <code class="language-text highlighter-rouge">ExtensionsTable</code> <code class="language-text highlighter-rouge">null</code>?</q>. It is only set in one place:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kt">void</span> <span class="nf">setExtensionsTable</span><span class="o">(</span><span class="nc">StylesheetRoot</span> <span class="n">sroot</span><span class="o">)</span>
<span class="kd">throws</span> <span class="n">javax</span><span class="o">.</span><span class="na">xml</span><span class="o">.</span><span class="na">transform</span><span class="o">.</span><span class="na">TransformerException</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">sroot</span><span class="o">.</span><span class="na">getExtensions</span><span class="o">()</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span>
<span class="n">m_extensionsTable</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ExtensionsTable</span><span class="o">(</span><span class="n">sroot</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">javax</span><span class="o">.</span><span class="na">xml</span><span class="o">.</span><span class="na">transform</span><span class="o">.</span><span class="na">TransformerException</span> <span class="n">te</span><span class="o">)</span> <span class="o">{</span>
<span class="n">te</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The extensions are correctly recognized, I saw earlier during debug that <code class="language-text highlighter-rouge">sroot.getExtensions()</code> is a non-null <code class="language-text highlighter-rouge">Vector</code> containing one element. After a debug session, it turns out that an exception was thrown, however that <code class="language-text highlighter-rouge">printStackTrace</code> had no effect and it wasn’t visible. Don’t fret, just use <code class="language-text highlighter-rouge">printStackTrace(PrintWriter(StringWriter))</code> to get the trace:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>javax.xml.transform.TransformerException: java.lang.ClassNotFoundException: org.apache.xalan.extensions.ExtensionHandlerJavaClass
at org.apache.xalan.extensions.ExtensionNamespaceSupport.launch(ExtensionNamespaceSupport.java:101)
at org.apache.xalan.extensions.ExtensionsTable.<init>(ExtensionsTable.java:66)
at org.apache.xalan.transformer.TransformerImpl.setExtensionsTable(TransformerImpl.java:385)
at org.apache.xalan.transformer.TransformerImpl.transformNode(TransformerImpl.java:1184)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:614)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1145)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1123)
Caused by: java.lang.ClassNotFoundException: org.apache.xalan.extensions.ExtensionHandlerJavaClass
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at org.apache.xalan.extensions.ObjectFactory.findProviderClass(ObjectFactory.java:100)
at org.apache.xalan.extensions.ExtensionHandler.getClassForName(ExtensionHandler.java:65)
at org.apache.xalan.extensions.ExtensionNamespaceSupport.launch(ExtensionNamespaceSupport.java:76)
... 22 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available
</code></pre></div></div>
<p>Surprise, surprise, there’s a class missing. I diffed the Android Xalan and Xalan 2.7.1 sources and indeed, the whole XSLTC and most of the extension classes are not included in Android. This exception causes <code class="language-text highlighter-rouge">m_extensionsTable</code> to be <code class="language-text highlighter-rouge">null</code> and that’s a problem in <code class="language-text highlighter-rouge">functionAvailable</code>. So I went ahead tried to ensure that it’s non-null:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="c1">// transformer created by factory.newTransformer(...)</span>
<span class="nc">TransformerImpl</span> <span class="n">xalanTransformer</span> <span class="o">=</span> <span class="o">(</span><span class="nc">TransformerImpl</span><span class="o">)</span><span class="n">transformer</span><span class="o">;</span>
<span class="nc">StylesheetRoot</span> <span class="n">sroot</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StylesheetRoot</span><span class="o">((</span><span class="nc">ErrorListener</span><span class="o">)</span><span class="kc">null</span><span class="o">);</span>
<span class="c1">// creates an empty Vector to be returned from getExtensions()</span>
<span class="n">sroot</span><span class="o">.</span><span class="na">getExtensionNamespacesManager</span><span class="o">();</span>
<span class="c1">// make sure the workaround works in Marsmallow too</span>
<span class="n">sroot</span><span class="o">.</span><span class="na">setSecureProcessing</span><span class="o">(</span><span class="kc">false</span><span class="o">);</span>
<span class="c1">// sets up an empty ExtensionTable, so functionAvailable works without NPE</span>
<span class="n">xalanTransformer</span><span class="o">.</span><span class="na">setExtensionsTable</span><span class="o">(</span><span class="n">sroot</span><span class="o">);</span> <span class="c1">// default visibility</span>
</code></pre></div></div>
<p>It’s worth noting that this code cannot be executed as is, because the compile classpath doesn’t have these classes. However, it’s a trivial conversion to reflective calls.</p>
<h2 id="summary">Summary</h2>
<p>This indeed fixed the problem, however it is not a good solution, even if you accept reflective hacks. The problem being that even though the XSLT ran, and there was no error, the <code class="language-text highlighter-rouge">test="function-available"</code> check still evaluated to <code class="language-text highlighter-rouge">false</code> and the <code class="language-text highlighter-rouge"><xsl:template></code> version was used. I now think it’s pointless to do the hack to ensure an extension table, because the only place where <code class="language-text highlighter-rouge">replaceAll</code> could have benefit, it doesn’t work. In the end I just removed the Xalan Java Extension and swallowed the XSLT 1.0-compatible workaround.</p>
2016-08-13T00:00:00+00:00https://www.twisterrob.net/blog/2016/02/blog-formatting.htmlFormatting used in this blog2016-02-16T00:00:00+00:00All-in-one visual medley of most formatting options I use in markdown on this website.<p>I created this blog more than half a year ago and a lot of convetion I tried to introduce was lost in memory. This document will help to remember what’s possible and how it will look like.</p>
<!--more-->
<p>It should also help to quickly test if formatting would break with any future updates of the site.</p>
<h2 class="no_toc" id="tldr"><abbr title="Too Long; Didn't Read">TL;DR</abbr></h2>
<p>This heading is not part of the <a href="#toc">TOC</a>. All headings can be linked via their short name: <a href="#tldr">this heading</a>.</p>
<div id="toc" class="panel radius">
<h2 class="no_toc" id="table-of-contents">Table of Contents</h2>
<ul id="markdown-toc">
<li><a href="#formatting" id="markdown-toc-formatting">Formatting</a></li>
<li><a href="#code" id="markdown-toc-code">Code</a> <ul>
<li><a href="#normal-code-block" id="markdown-toc-normal-code-block">Normal code block</a></li>
<li><a href="#code-block-with-title" id="markdown-toc-code-block-with-title">Code block with title</a></li>
<li><a href="#code-block-with-liquid-code" id="markdown-toc-code-block-with-liquid-code">Code block with Liquid code</a></li>
<li><a href="#code-block-for-shell" id="markdown-toc-code-block-for-shell">Code block for shell</a></li>
</ul>
</li>
<li><a href="#quotes" id="markdown-toc-quotes">Quotes</a></li>
<li><a href="#alerts" id="markdown-toc-alerts">Alerts</a></li>
</ul>
</div>
<h2 id="formatting">Formatting</h2>
<ul>
<li>Belonging words should have <code class="language-text highlighter-rouge">&nbsp;</code> between to prevent wrapping: Papp Róbert.</li>
<li>Long list of alternatives should have <code class="language-text highlighter-rouge"><wbr></code> between them to allow wrapping: this one<wbr />/that one<wbr />/other thing</li>
<li>Use <code class="language-text highlighter-rouge"><samp></code> for sample output: <samp>Exit code: 1</samp>.</li>
<li>Use <code class="language-text highlighter-rouge"><samp></code> for math: <samp>4 people × 5 days = 20 man hours</samp>.</li>
<li>Use <code class="language-text highlighter-rouge"><var></code> for something representing a number: <var>your age</var> times.</li>
<li>Use <code class="language-text highlighter-rouge"><mark></code> for callout <mark>Grammar Nazis</mark></li>
<li>Use <code class="language-text highlighter-rouge"><mark></code> for UI elements: Press <mark>Next</mark> to proceed.</li>
<li>Use <code class="language-text highlighter-rouge"><abbr></code> to show an abbreviation: <abbr title="shortended text">shot</abbr>, but it’s not necessary if the <abbr title="abbreviation">abbr</abbr> is defined in markdown</li>
<li>Custom colors when referencing something highlighted on an image: <span style="color:cyan">Save button</span>.</li>
</ul>
<h2 id="code">Code</h2>
<ul>
<li>File extensions with <code class="language-text highlighter-rouge"><code></code>: <code class="language-text highlighter-rouge">.css</code>, <code class="language-text highlighter-rouge">.js</code>, <code class="language-text highlighter-rouge">.html</code></li>
<li>Paths and file names with <code class="language-text highlighter-rouge"><samp></code>: <samp>lib/code/path/file.name</samp></li>
<li>Liquid-like code may need some escaping: <code class="language-text highlighter-rouge">{{tag}}</code></li>
<li>Fencing code blocks’ ticks can be output like this: <code class="language-text highlighter-rouge"><code>```</code></code> → <code>```</code>.</li>
<li>Don’t be lazy with <code class="language-text highlighter-rouge">alternative</code>/<code class="language-text highlighter-rouge">code</code>/<code class="language-text highlighter-rouge">formatting</code>.</li>
</ul>
<h3 id="normal-code-block">Normal code block</h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="cm">/** Comment */</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">method</span><span class="o">();</span>
</code></pre></div></div>
<p><em>Some extra explanation to help understand the code.</em></p>
<h3 id="code-block-with-title">Code block with title</h3>
<div title="Short description of the code block" class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="cm">/** Comment */</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">method</span><span class="o">();</span>
</code></pre></div></div>
<h3 id="code-block-with-liquid-code">Code block with Liquid code</h3>
<div title="Liquid code, that's not executed" class="language-liquid highlighter-rouge"><div class="highlight"><pre class=""><code><span class="p">{%</span><span class="w"> </span><span class="nt">for</span><span class="w"> </span><span class="nv">tag</span><span class="w"> </span><span class="nt">in</span><span class="w"> </span><span class="nv">site.data.tags</span><span class="w"> </span><span class="p">%}</span><li><span class="p">{{</span><span class="w"> </span><span class="nv">tag</span><span class="p">.</span><span class="nv">name</span><span class="w"> </span><span class="p">}}{%</span><span class="w"> </span><span class="kr">unless</span><span class="w"> </span><span class="nb">forloop.last</span><span class="w"> </span><span class="p">%}</span>, <span class="p">{%</span><span class="w"> </span><span class="kr">endunless</span><span class="w"> </span><span class="p">%}</span></li><span class="p">{%</span><span class="w"> </span><span class="nt">endfor</span><span class="w"> </span><span class="p">%}</span>
</code></pre></div></div>
<h3 id="code-block-for-shell">Code block for shell</h3>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>me@laptop<span class="nv">$ </span><span class="nb">command </span>args <span class="s2">"more args"</span>
output text from <span class="nb">command
</span>though output may be highlighted weirdly
</code></pre></div></div>
<h2 id="quotes">Quotes</h2>
<p>Here’s a <q>short quotation</q> which is in the middle of a sentence.</p>
<blockquote>
<p>This is a long quotation by someone, normal markdown formatting rules apply:<br />
<strong>strong</strong>, <em>em</em>, <em>em</em>, <strong><em>strong em</em></strong>, <b>html bold</b>, <code class="language-text highlighter-rouge">code</code>, <kbd>kbd</kbd>, <samp>samp</samp>, <ins>ins</ins>, <del>del</del>
<cite>TWiStErRob</cite></p>
</blockquote>
<blockquote>
<p><samp>Program output text</samp> <cite>output from <a href="https://sources.com/path/to/file.name#line=123">file.name</a> in <a href="https://library.com/">library</a></cite></p>
</blockquote>
<h2 id="alerts">Alerts</h2>
<p>All <code class="language-text highlighter-rouge">alert</code>s support markdown and their names are all lowercase, because they’re used as CSS classes, for example TODO is <code class="language-text highlighter-rouge">alert todo=</code>. The <q>TODO:</q> prefix is not automatically inserted, it’s for name calling only here.</p>
<div class="alert-box alert radius "><p>Alert:<br />
This is like any normal markdown, even when used from non-markdown context:<br />
<strong>strong</strong>, <em>em</em>, <em>em</em>, <strong><em>strong em</em></strong>, <b>html bold</b>, <code class="language-text highlighter-rouge">code</code>, <kbd>kbd</kbd>, <samp>samp</samp>, <ins>ins</ins>, <del>del</del>.</p>
</div>
<div class="alert-box warning radius "><p>Warning: call out a caveat that’s easy to trigger<br />
This is like any normal markdown, even when used from non-markdown context:<br />
<strong>strong</strong>, <em>em</em>, <em>em</em>, <strong><em>strong em</em></strong>, <b>html bold</b>, <code class="language-text highlighter-rouge">code</code>, <kbd>kbd</kbd>, <samp>samp</samp>, <ins>ins</ins>, <del>del</del>.</p>
</div>
<div class="alert-box info radius "><p>Info: supplementary information, for example links to further reading or documentation.<br />
This is like any normal markdown, even when used from non-markdown context:<br />
<strong>strong</strong>, <em>em</em>, <em>em</em>, <strong><em>strong em</em></strong>, <b>html bold</b>, <code class="language-text highlighter-rouge">code</code>, <kbd>kbd</kbd>, <samp>samp</samp>, <ins>ins</ins>, <del>del</del>.</p>
</div>
<div class="alert-box tip radius "><p>Tip: call out something non-trivial that could help.<br />
This is like any normal markdown, even when used from non-markdown context:<br />
<strong>strong</strong>, <em>em</em>, <em>em</em>, <strong><em>strong em</em></strong>, <b>html bold</b>, <code class="language-text highlighter-rouge">code</code>, <kbd>kbd</kbd>, <samp>samp</samp>, <ins>ins</ins>, <del>del</del>.</p>
</div>
<div class="alert-box success radius "><p>Success:<br />
This is like any normal markdown, even when used from non-markdown context:<br />
<strong>strong</strong>, <em>em</em>, <em>em</em>, <strong><em>strong em</em></strong>, <b>html bold</b>, <code class="language-text highlighter-rouge">code</code>, <kbd>kbd</kbd>, <samp>samp</samp>, <ins>ins</ins>, <del>del</del>.</p>
</div>
<div class="alert-box text radius "><p>Text:<br />
This is like any normal markdown, even when used from non-markdown context:<br />
<strong>strong</strong>, <em>em</em>, <em>em</em>, <strong><em>strong em</em></strong>, <b>html bold</b>, <code class="language-text highlighter-rouge">code</code>, <kbd>kbd</kbd>, <samp>samp</samp>, <ins>ins</ins>, <del>del</del>.</p>
</div>
<div class="alert-box todo radius "><p>TODO: reminder to myself that something needs to be done here<br />
This is like any normal markdown, even when used from non-markdown context:<br />
<strong>strong</strong>, <em>em</em>, <em>em</em>, <strong><em>strong em</em></strong>, <b>html bold</b>, <code class="language-text highlighter-rouge">code</code>, <kbd>kbd</kbd>, <samp>samp</samp>, <ins>ins</ins>, <del>del</del>.</p>
</div>
<div class="alert-box terminal radius "><p>Terminal:<br />
This is like any normal markdown, even when used from non-markdown context:<br />
<strong>strong</strong>, <em>em</em>, <em>em</em>, <strong><em>strong em</em></strong>, <b>html bold</b>, <code class="language-text highlighter-rouge">code</code>, <kbd>kbd</kbd>, <samp>samp</samp>, <ins>ins</ins>, <del>del</del>.</p>
</div>
2016-02-16T00:00:00+00:00https://www.twisterrob.net/blog/2015/06/git-pull-request.htmlHow to do a PR?2015-06-13T00:00:00+00:00Full process of how I go through a pull request for a GitHub fork.<p>Many times when you ask for a feature in a GitHub issue, you’re welcomed with:</p>
<blockquote>
<p>Can you create a <abbr title="Pull Request">PR</abbr> please?</p>
</blockquote>
<p>… even if it’s a one-character typo. Here’s how I create a <abbr title="Pull Request">PR</abbr>.</p>
<!--more-->
<h2 id="what-is-a-pr">What is a <abbr title="Pull Request">PR</abbr>?</h2>
<p>A <dfn>Pull Request</dfn> is request created on GitHub to merge code from one fork of the repository to another. Usually there’s a feature/bug branch in the fork and the <abbr title="Pull Request">PR</abbr> is made against the default branch (usually called <code class="language-text highlighter-rouge">main</code> or <code class="language-text highlighter-rouge">master</code>) in the base repository.</p>
<h2 id="github-setup">GitHub setup</h2>
<p>As easy as pressing <img src="data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAAF0AAAAaCAMAAADi8qAlAAAABGdBTUEAALGPC/xhBQAAAAFzUkdC
AK7OHOkAAABCUExURfPz8/Hx8fX19d3d3fr6+v////j4+Pz8/NXV1e/v719fX3R0dOTk5Orq6ktL
SzMzM8fHx7q6us/Pzz4+PqWlpY2NjfCuymIAAAGWSURBVEjHtZaJsoMgDEVZbGUJART//1dfQqti
++zuzQyZkMkBIy6iB/Ol9J5CLwBE139j5rSjDoIwqvtOu/TTWQvTHUY/HU4/L0qIqfWv6UV68MPg
w+q7OdE1dj/xIf0cXGRtryM4bz/Z+11n7kAs+JQOzsHWv0PvyoiZx3E6N3Q1GziskUGi15hAnIGJ
SoBi53GgyTIWtVTN9ITGOD2Mg8G00tUiOUUHiiBxkhwz/eoBvANeXVKQx0v+opmenbUuGyT68B9d
BR+ZE31QFyrfVG9zzErRQODAFzhe81s67V3j1JcYS7/ShVqN8Qy/RLx39iUmJVIsNeYl0TQ1Td+d
mwZeo+mMaMW1DpaA1iHRtutQY2p+xsmuJc2ZkT7X/kw7dGEQjbihk9e69r3SfShjuqdTuwfUtT95
j86n8ZYudD0zYqHrOdHSuTOpnsjSnEi5ET9J8i09fpqkFFcjAb8FQC4TS2KWuA5isWf0RuBTYvrv
9m5by4h5O/PMHtPtRtK+q3fo9sf0cBidvtqgw0F0/uM49G/pDxDMOtB3YFf6AAAAAElFTkSuQmCC" alt="Fork button on GitHub" />.</p>
<h2 id="checkout">Checkout</h2>
<p>Click the <a href="javascript:;">HTTPS</a> link below the clone URL box and then copy the <em><strong>HTTPS</strong> clone URL</em> which can be then used to clone a repo:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>me@laptop<span class="nv">$ </span>git clone https://github.com/me/repo-name.git <span class="nb">.</span>
Cloning into <span class="s1">'.'</span>...
</code></pre></div></div>
<p>Immediately after this I go back to the original repository (where I forked from) and repeat the <a href="#">HTTPS</a> link copying and add the remote:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>me@laptop<span class="nv">$ </span>git remote add <span class="nt">-f</span> mint https://github.com/stranger/repo-name.git <span class="c"># -f == immediate fetch</span>
Updating mint
me@laptop<span class="nv">$ </span>git remote set-url <span class="nt">--push</span> mint DISALLOWED
</code></pre></div></div>
<p>This is useful if the original repo is active and you want to keep up to date. I call it <code class="language-text highlighter-rouge">mint</code> (after the adjective in “mint condition”), because the normal clone operation creates an <code class="language-text highlighter-rouge">origin</code> remote, also mint suggests to keep it clean.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>me@laptop<span class="nv">$ </span>git remote <span class="nt">-v</span> <span class="c"># == git remote --verbose show</span>
mint https://github.com/stranger/repo-name.git <span class="o">(</span>fetch<span class="o">)</span>
mint DISALLOWED <span class="o">(</span>push<span class="o">)</span>
origin https://github.com/me/repo-name.git <span class="o">(</span>fetch<span class="o">)</span>
origin https://github.com/me/repo-name.git <span class="o">(</span>push<span class="o">)</span>
</code></pre></div></div>
<h2 id="update-remote">Update remote</h2>
<p><code class="language-text highlighter-rouge">stranger-head-branch</code> is usually the <code class="language-text highlighter-rouge">main</code> branch and <code class="language-text highlighter-rouge">my-pr-branch</code>’s name is highly correlated with what your <abbr title="Pull Request">PR</abbr> is representing.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>me@laptop<span class="nv">$ </span>git checkout stranger-head-branch
Switched to branch <span class="s1">'stranger-head-branch'</span>
me@laptop<span class="nv">$ </span>git merge mint/stranger-head-branch
Updating abc1230..abc123f
Fast-forward
...
me@laptop<span class="nv">$ </span>git checkout my-pr-branch
Switched to branch <span class="s1">'my-pr-branch'</span>
me@laptop<span class="nv">$ </span>git rebase stranger-head-branch
First, rewinding <span class="nb">head </span>to replay your work on top of it...
Applying: Commit message 1
Applying: Commit message 2
...
</code></pre></div></div>
<h2 id="create-pr">Create <abbr title="Pull Request">PR</abbr></h2>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>me@laptop<span class="nv">$ </span>git push <span class="nt">--all</span>
</code></pre></div></div>
<p>Upon success just go to the original repo or your fork on GitHub and you should see a <mark>Your recently pushed branches:</mark> tip with a <mark>Compare & pull request</mark> button.</p>
<p>Review changes, fill in description and you’re good to go.</p>
<h2 id="future-of-a-pr">Future of a <abbr title="Pull Request">PR</abbr></h2>
<p>If the repository owners like what you did and it adheres to rules usually defined in <code class="language-text highlighter-rouge">CONTRIBUTING.md</code> they’ll merge your <abbr title="Pull Request">PR</abbr> and you’ll see a <mark>Pull request successfully merged and closed</mark> message with a <mark>Delete branch</mark> button next to it. That helps to keep your fork’s working branches to a minimum. Once it’s merged the commits are copied to their repository so it’s safe to delete your branch.</p>
<p>There’s of course the possibility that something goes wrong, like the CI build fails or there’s some modification needed in the <abbr title="Pull Request">PR</abbr>. In that case make some more commits to your fork, or even rebase or squash commits; then push it to the working branch and the <abbr title="Pull Request">PR</abbr> will be updated automatically.</p>
2015-06-13T00:00:00+00:00https://www.twisterrob.net/blog/2015/06/Jekyll-hacks-for-development.htmlJekyll enhancements for development2015-06-09T00:00:00+00:00Have you ever found that Jekyll or one of its components is lacking a feature?<p>Jekyll is nice if you like the defaults, but as soon as you start customizing you run into walls.
Here are some tips to make it less painful.
<!--more--></p>
<div id="toc" class="panel radius">
<h2 class="no_toc" id="table-of-contents">Table of Contents</h2>
<ul id="markdown-toc">
<li><a href="#continous-development" id="markdown-toc-continous-development">Continous Development</a></li>
<li><a href="#debugging-liquid" id="markdown-toc-debugging-liquid">Debugging Liquid</a> <ul>
<li><a href="#debugging-example-walkthrough" id="markdown-toc-debugging-example-walkthrough">Debugging Example Walkthrough</a></li>
<li><a href="#more-debugging-options" id="markdown-toc-more-debugging-options">More Debugging options</a></li>
</ul>
</li>
<li><a href="#hidden-gems" id="markdown-toc-hidden-gems">Hidden Gems</a> <ul>
<li><a href="#filter-documentation" id="markdown-toc-filter-documentation">Filter Documentation</a></li>
<li><a href="#working-with-arrays" id="markdown-toc-working-with-arrays">Working With Arrays</a></li>
<li><a href="#liquid-code-highlight" id="markdown-toc-liquid-code-highlight">Liquid code highlight</a></li>
</ul>
</li>
<li><a href="#liquid-error-messages" id="markdown-toc-liquid-error-messages">Liquid Error Messages</a></li>
</ul>
</div>
<h2 id="continous-development">Continous Development</h2>
<p>I’m sure you’ve met this line if you started <kbd>jekyll serve</kbd> at least once:</p>
<blockquote>
<p><samp>Regenerating: 1 file(s) changed at 2015-06-09 12:34:56 ... done in 3.14 seconds.</samp> <cite>output from <a href="https://github.com/jekyll/jekyll-watch/blob/v1.2.1/lib/jekyll/watcher.rb#L40">watcher.rb</a> in <a href="https://github.com/jekyll/jekyll-watch">jekyll-watch</a> gem</cite></p>
</blockquote>
<p>Now, if you’re like me, you immediate ask the question: <q>What are those files?</q>, especially when it says multiple files changed and you only changed one.</p>
<div title="RUBY_HOME\lib\ruby\gems\2.2.0\gems\jekyll-watch-1.2.1\lib\jekyll\watcher.rb@40" class="language-ruby highlighter-rouge"><div class="highlight"><pre class=""><code><span class="n">removed</span><span class="p">.</span><span class="nf">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">file</span><span class="o">|</span> <span class="no">Jekyll</span><span class="p">.</span><span class="nf">logger</span><span class="p">.</span><span class="nf">info</span><span class="p">(</span><span class="s2">"Changes:"</span><span class="p">,</span> <span class="s2">"Removed </span><span class="si">#{</span><span class="n">file</span><span class="p">.</span><span class="nf">slice</span><span class="p">(</span><span class="n">site</span><span class="p">.</span><span class="nf">source</span><span class="p">.</span><span class="nf">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">file</span><span class="p">.</span><span class="nf">length</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span> <span class="p">}</span>
<span class="n">added</span><span class="p">.</span><span class="nf">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">file</span><span class="o">|</span> <span class="no">Jekyll</span><span class="p">.</span><span class="nf">logger</span><span class="p">.</span><span class="nf">info</span><span class="p">(</span><span class="s2">"Changes:"</span><span class="p">,</span> <span class="s2">"Added </span><span class="si">#{</span><span class="n">file</span><span class="p">.</span><span class="nf">slice</span><span class="p">(</span><span class="n">site</span><span class="p">.</span><span class="nf">source</span><span class="p">.</span><span class="nf">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">file</span><span class="p">.</span><span class="nf">length</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span> <span class="p">}</span>
<span class="n">modified</span><span class="p">.</span><span class="nf">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">file</span><span class="o">|</span> <span class="no">Jekyll</span><span class="p">.</span><span class="nf">logger</span><span class="p">.</span><span class="nf">info</span><span class="p">(</span><span class="s2">"Changes:"</span><span class="p">,</span> <span class="s2">"Modified </span><span class="si">#{</span><span class="n">file</span><span class="p">.</span><span class="nf">slice</span><span class="p">(</span><span class="n">site</span><span class="p">.</span><span class="nf">source</span><span class="p">.</span><span class="nf">length</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">file</span><span class="p">.</span><span class="nf">length</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span> <span class="p">}</span>
<span class="nb">print</span> <span class="no">Jekyll</span><span class="p">.</span><span class="nf">logger</span><span class="p">.</span><span class="nf">message</span><span class="p">(</span><span class="s2">"Regenerating:"</span><span class="p">,</span> <span class="s2">"</span><span class="si">#{</span><span class="n">n</span><span class="si">}</span><span class="s2"> file</span><span class="si">#{</span><span class="n">n</span><span class="o">></span><span class="mi">1</span><span class="p">?</span><span class="s2">"s"</span><span class="p">:</span><span class="s2">""</span><span class="si">}</span><span class="s2"> changed at </span><span class="si">#{</span><span class="n">t</span><span class="p">.</span><span class="nf">strftime</span><span class="p">(</span><span class="s2">"%Y-%m-%d %H:%M:%S"</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">)</span>
</code></pre></div></div>
<div title="Resulting log after the change, more informative, isn't it?" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>...
Changes: Added _posts/2015-06-09-Jekyll-hacks-for-development
Regenerating: 1 file changed at 2015-06-09 15:18:56 ...done in 3.220606 seconds.
Changes: Removed _posts/2015-06-09-Jekyll-hacks-for-development
Changes: Added _posts/2015-06-09-Jekyll-hacks-for-development.md
Regenerating: 2 files changed at 2015-06-09 15:19:00 ...done in 3.286006 seconds.
Changes: Modified _sass/_09_elements.scss
Regenerating: 1 file changed at 2015-06-09 15:20:27 ...done in 3.239607 seconds.
Changes: Modified _posts/2015-06-09-Jekyll-hacks-for-development.md
Regenerating: 1 file changed at 2015-06-09 15:20:53 ...done in 3.246334 seconds.
</code></pre></div></div>
<p><em>The paths are relative to <samp>Auto-regeneration: enabled for '...'</samp>.</em></p>
<h2 id="debugging-liquid">Debugging Liquid</h2>
<p>When copy-pasting-building a site from articles found on the internet you’ll most likely find yourself wondering: <q>Why is it not working?</q>.
There’s a built-in <code class="language-text highlighter-rouge">| inspect</code>, but it just dumps the text without any escaping or formatting, messing up HTML pages.
Luckily Jade Dominguez included a <a href="https://github.com/plusjade/jekyll-bootstrap/blob/master/_plugins/debug.rb">little plugin</a> in his bootstrap which would come to the rescue in this case. The following is a more advanced version of his plugin.</p>
<div class="alert-box warning radius "><p>This <strong>is</strong> compatible with GitHub Pages! The default mode of Jekyll is unsafe, but GitHub starts it with <code>--safe</code>. So plugins can be used during local development; just don’t forget to remove <code> | debug</code>s before commit.</p>
</div>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class=""><code><span class="c1"># A simple way to inspect liquid template variables.</span>
<span class="c1"># Based on: https://github.com/plusjade/jekyll-bootstrap/blob/master/_plugins/debug.rb</span>
<span class="c1"># The filters below can be used anywhere liquid syntax is parsed (templates, includes, posts/pages/collections)</span>
<span class="nb">require</span> <span class="s1">'pp'</span> <span class="c1"># obj.pretty_inspect</span>
<span class="nb">require</span> <span class="s1">'cgi'</span> <span class="c1"># CGI.escape_html</span>
<span class="k">module</span> <span class="nn">Jekyll</span>
<span class="c1"># Need to overwrite the inspect methods, because the original uses a strange format</span>
<span class="c1"># and we're trying to output JSON. <> also conflicts with HTML code if output literally.</span>
<span class="k">class</span> <span class="nc">Post</span>
<span class="c1"># Replace original #<Jekyll:Post @id="self.id"></span>
<span class="k">def</span> <span class="nf">inspect</span>
<span class="s2">"{ </span><span class="se">\"</span><span class="s2">type</span><span class="se">\"</span><span class="s2">: </span><span class="se">\"</span><span class="s2">Jekyll:Post</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">id</span><span class="se">\"</span><span class="s2">: </span><span class="si">#{</span><span class="nb">self</span><span class="p">.</span><span class="nf">id</span><span class="p">.</span><span class="nf">inspect</span><span class="si">}</span><span class="s2"> }"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Page</span>
<span class="c1"># Replace original #<Jekyll:Page @name="self.name"></span>
<span class="k">def</span> <span class="nf">inspect</span>
<span class="s2">"{ </span><span class="se">\"</span><span class="s2">type</span><span class="se">\"</span><span class="s2">: </span><span class="se">\"</span><span class="s2">Jekyll:Page</span><span class="se">\"</span><span class="s2">, </span><span class="se">\"</span><span class="s2">name</span><span class="se">\"</span><span class="s2">: </span><span class="si">#{</span><span class="nb">self</span><span class="p">.</span><span class="nf">name</span><span class="p">.</span><span class="nf">inspect</span><span class="si">}</span><span class="s2"> }"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nn">DebugFilter</span>
<span class="c1"># Returns a highlighted HTML code block displaying the received object.</span>
<span class="c1"># Example usages:</span>
<span class="c1"># * <tt>{{ site.pages | debug }}</tt></span>
<span class="c1"># * <tt>{{ site.pages | debug: 'pages' }}</tt></span>
<span class="k">def</span> <span class="nf">debug</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">label</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
<span class="n">pretty</span> <span class="o">=</span> <span class="n">obj</span><span class="p">.</span><span class="nf">pretty_inspect</span>
<span class="n">pretty</span> <span class="o">=</span> <span class="n">pretty</span><span class="p">.</span><span class="nf">gsub</span><span class="p">(</span><span class="sr">/\=\>/</span><span class="p">,</span> <span class="s1">': '</span><span class="p">)</span> <span class="c1"># approximate JSON syntax</span>
<span class="n">pretty</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="n">prefix</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">label</span><span class="p">)</span><span class="si">}</span><span class="se">\n</span><span class="si">#{</span><span class="n">pretty</span><span class="si">}</span><span class="s2">"</span> <span class="c1"># prefix with type</span>
<span class="n">highlight</span> <span class="o">=</span> <span class="no">Jekyll</span><span class="o">::</span><span class="no">Tags</span><span class="o">::</span><span class="no">HighlightBlock</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s1">'highlight'</span><span class="p">,</span> <span class="s1">'json'</span><span class="p">,</span> <span class="p">[</span> <span class="n">pretty</span><span class="p">,</span> <span class="s2">"{% endhighlight %}"</span> <span class="p">])</span>
<span class="n">pretty</span> <span class="o">=</span> <span class="n">highlight</span><span class="p">.</span><span class="nf">render_pygments</span><span class="p">(</span><span class="n">pretty</span><span class="p">,</span> <span class="kp">true</span><span class="p">)</span>
<span class="n">pretty</span> <span class="o">=</span> <span class="n">highlight</span><span class="p">.</span><span class="nf">add_code_tag</span><span class="p">(</span><span class="n">pretty</span><span class="p">)</span>
<span class="n">pretty</span> <span class="o">=</span> <span class="n">pretty</span><span class="p">.</span><span class="nf">sub</span><span class="p">(</span><span class="sr">/<div class="highlight">/</span><span class="p">,</span> <span class="s2">"<div class=</span><span class="se">\"</span><span class="s2">highlight debug</span><span class="se">\"</span><span class="s2"> title=</span><span class="se">\"</span><span class="si">#{</span><span class="n">prefix</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">label</span><span class="p">)</span><span class="si">}</span><span class="se">\"</span><span class="s2">>"</span><span class="p">)</span>
<span class="k">return</span> <span class="n">pretty</span>
<span class="k">end</span>
<span class="c1"># Returns a non-highlighted HTML code block displaying the received object.</span>
<span class="c1"># Example usages:</span>
<span class="c1"># * <tt>{{ site.pages | dump_html }}</tt></span>
<span class="c1"># * <tt>{{ site.pages | dump_html: 'pages' }}</tt></span>
<span class="k">def</span> <span class="nf">dump_html</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">label</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
<span class="n">pretty</span> <span class="o">=</span> <span class="n">obj</span><span class="p">.</span><span class="nf">pretty_inspect</span>
<span class="n">pretty</span> <span class="o">=</span> <span class="no">CGI</span><span class="p">.</span><span class="nf">escape_html</span><span class="p">(</span><span class="n">pretty</span><span class="p">)</span>
<span class="n">pretty</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="n">prefix</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">label</span><span class="p">)</span><span class="si">}</span><span class="se">\n</span><span class="si">#{</span><span class="n">pretty</span><span class="si">}</span><span class="s2">"</span> <span class="c1"># prefix with type</span>
<span class="n">pretty</span> <span class="o">=</span> <span class="s2">"<pre class=</span><span class="se">\"</span><span class="s2">debug</span><span class="se">\"</span><span class="s2"> title=</span><span class="se">\"</span><span class="si">#{</span><span class="n">prefix</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">label</span><span class="p">)</span><span class="si">}</span><span class="se">\"</span><span class="s2">></span><span class="si">#{</span><span class="n">pretty</span><span class="si">}</span><span class="s2"></pre>"</span>
<span class="k">return</span> <span class="n">pretty</span>
<span class="k">end</span>
<span class="c1"># Returns pretty-printed plain text displaying the received object.</span>
<span class="c1"># Example usages:</span>
<span class="c1"># * <tt>{{ site.pages | dump_text }}</tt></span>
<span class="c1"># * <tt>{{ site.pages | dump_text: 'pages' }}</tt></span>
<span class="k">def</span> <span class="nf">dump_text</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">label</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
<span class="n">pretty</span> <span class="o">=</span> <span class="n">obj</span><span class="p">.</span><span class="nf">pretty_inspect</span>
<span class="k">return</span> <span class="s2">"</span><span class="si">#{</span><span class="n">prefix</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">label</span><span class="p">)</span><span class="si">}#{</span><span class="n">pretty</span><span class="p">.</span><span class="nf">strip</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="c1"># Prints pretty-printed plain text displaying the received object to the console.</span>
<span class="c1"># Returns the original object, making it chainable.</span>
<span class="c1"># Example usages:</span>
<span class="c1"># * <tt>{% assign upperTitle = page.title | dump_console | upcase | dump_console %}</tt></span>
<span class="c1"># * <tt>{% assign upperTitle = page.title | dump_console: 'original' | upcase | dump_console: 'upcased' %}</tt></span>
<span class="k">def</span> <span class="nf">dump_console</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">label</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
<span class="n">pretty</span> <span class="o">=</span> <span class="n">obj</span><span class="p">.</span><span class="nf">pretty_inspect</span>
<span class="nb">puts</span> <span class="s2">"</span><span class="si">#{</span><span class="n">prefix</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">label</span><span class="p">)</span><span class="si">}#{</span><span class="n">pretty</span><span class="p">.</span><span class="nf">strip</span><span class="si">}</span><span class="s2">"</span>
<span class="k">return</span> <span class="n">obj</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">prefix</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">label</span><span class="p">)</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="s2">"(</span><span class="si">#{</span><span class="n">obj</span><span class="p">.</span><span class="nf">class</span><span class="si">}</span><span class="s2">)"</span> <span class="k">if</span> <span class="n">obj</span>
<span class="n">label</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="n">label</span><span class="si">}</span><span class="s2">: "</span> <span class="k">if</span> <span class="n">label</span>
<span class="k">return</span> <span class="s2">"</span><span class="si">#{</span><span class="n">label</span><span class="si">}#{</span><span class="n">clazz</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span> <span class="c1"># DebugFilter</span>
<span class="k">end</span> <span class="c1"># Jekyll</span>
<span class="no">Liquid</span><span class="o">::</span><span class="no">Template</span><span class="p">.</span><span class="nf">register_filter</span><span class="p">(</span><span class="no">Jekyll</span><span class="o">::</span><span class="no">DebugFilter</span><span class="p">)</span>
</code></pre></div></div>
<h3 id="debugging-example-walkthrough">Debugging Example Walkthrough</h3>
<p>Suppose there’s a <a href="https://www.minddust.com/post/tags-and-categories-on-github-pages/">tags data file</a> in the <a href="https://github.com/minddust/minddust.github.io/issues/5">format I suggested</a>:</p>
<div title="_data/tags.yaml" class="language-yaml highlighter-rouge"><div class="highlight"><pre class=""><code><span class="na">tag1</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Tag</span><span class="nv"> </span><span class="s">1</span><span class="nv"> </span><span class="s">Long</span><span class="nv"> </span><span class="s">Name"</span>
<span class="na">tag2</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Tag</span><span class="nv"> </span><span class="s">2</span><span class="nv"> </span><span class="s">Long</span><span class="nv"> </span><span class="s">Name"</span>
</code></pre></div></div>
<p>… and you’re trying to list all the tags on the site, like <a href="https://github.com/minddust/minddust.github.io/issues/5#issuecomment-125376549"><cite>LovesTha</cite> did</a>:</p>
<div title="Problematic code" class="language-liquid highlighter-rouge"><div class="highlight"><pre class=""><code><ul>
<span class="p">{%</span><span class="w"> </span><span class="nt">for</span><span class="w"> </span><span class="nv">tag</span><span class="w"> </span><span class="nt">in</span><span class="w"> </span><span class="nv">site.data.tags</span><span class="w"> </span><span class="p">%}</span>
<li><a href='/blog/tag/<span class="p">{{</span><span class="w"> </span><span class="nv">tag</span><span class="w"> </span><span class="p">}}</span>/'><span class="p">{{</span><span class="w"> </span><span class="nv">tag</span><span class="p">.</span><span class="nv">name</span><span class="w"> </span><span class="p">}}</span></a></li>
<span class="p">{%</span><span class="w"> </span><span class="nt">endfor</span><span class="w"> </span><span class="p">%}</span>
</ul>
</code></pre></div></div>
<div title="Resulting HTML" class="language-html highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nt"><ul></span>
<span class="nt"><li><a</span> <span class="na">href=</span><span class="s">'/blog/tag/tag1{"name"=>"Tag 1 Long Name"}/'</span><span class="nt">></a></li></span>
<span class="nt"><li><a</span> <span class="na">href=</span><span class="s">'/blog/tag/tag2{"name"=>"Tag 2 Long Name"}/'</span><span class="nt">></a></li></span>
<span class="nt"></ul></span>
</code></pre></div></div>
<p>For some reason <code class="language-text highlighter-rouge">{{tag}}</code> comes up as <samp>tag1{"name"=>"Tag 1 Long Name"}</samp> instead of the expected <samp>tag1</samp> and <code class="language-text highlighter-rouge">{{tag.name}}</code> is empty. Let’s augment the code to see what’s going wrong (the argument to <code class="language-text highlighter-rouge">debug</code> and <code class="language-text highlighter-rouge">dump_*</code> is optional):</p>
<div title="Augmented code" class="language-liquid highlighter-rouge"><div class="highlight"><pre class=""><code><span class="p">{{</span><span class="w"> </span><span class="nv">site</span><span class="p">.</span><span class="nv">data</span><span class="p">.</span><span class="nv">tags</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">debug</span><span class="p">:</span><span class="w"> </span><span class="s2">"data.tags"</span><span class="w"> </span><span class="p">}}</span>
<ul>
<span class="p">{%</span><span class="w"> </span><span class="nt">for</span><span class="w"> </span><span class="nv">tag</span><span class="w"> </span><span class="nt">in</span><span class="w"> </span><span class="nv">site.data.tags</span><span class="w"> </span><span class="p">%}</span>
<li><a href='/blog/tag/<span class="p">{{</span><span class="w"> </span><span class="nv">tag</span><span class="w"> </span><span class="p">}}</span>/'><span class="p">{{</span><span class="w"> </span><span class="nv">tag</span><span class="p">.</span><span class="nv">name</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_text</span><span class="w"> </span><span class="p">}}</span></a><span class="p">{{</span><span class="w"> </span><span class="nv">tag</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_html</span><span class="p">:</span><span class="w"> </span><span class="nb">forloop.index</span><span class="w"> </span><span class="p">}}</span></li>
<span class="p">{%</span><span class="w"> </span><span class="nt">endfor</span><span class="w"> </span><span class="p">%}</span>
</ul>
</code></pre></div></div>
<p>… and here’s how it looks like on the page:</p>
<div class="panel">
<div class="highlight debug"><pre><code class="language-json" data-lang="json"><span class="err">data.tags:</span><span class="err">(Hash)</span>
<span class="p">{</span><span class="nt">"tag1"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"name"</span><span class="p">:</span> <span class="s2">"Tag 1 Long Name"</span><span class="p">},</span> <span class="nt">"tag2"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"name"</span><span class="p">:</span> <span class="s2">"Tag 2 Long Name"</span><span class="p">}}</span></code></pre></div>
<ul>
<li><a href="/blog/tag/.../">nil</a><pre class="debug">1: (Array)
["tag1", {"name"=>"Tag 1 Long Name"}]</pre></li>
<li><a href="/blog/tag/.../">nil</a><pre class="debug">2: (Array)
["tag2", {"name"=>"Tag 2 Long Name"}]</pre></li>
</ul>
</div>
<p>From the above the following is revealed:</p>
<ul>
<li>the iteration was correctly going through the Hash (map) as expected</li>
<li><code class="language-text highlighter-rouge">{{tag.name}}</code> is <samp>nil</samp> displayed as an empty string</li>
<li>at each iteration <var>tag</var> is an array and not the key of the hash</li>
</ul>
<div class="alert-box tip radius "><p>In Liquid a hash entry is stored as <samp>[key, value]</samp>; compare to <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in#Examples" target="_blank">for..in loop in JavaScript</a>.</p>
</div>
<p>Based on the above it’s clear that the code must be changed to correctly read the value from the entry:</p>
<div title="Fixed code" class="language-liquid highlighter-rouge"><div class="highlight"><pre class=""><code><span class="p">{%</span><span class="w"> </span><span class="nt">for</span><span class="w"> </span><span class="nv">tag_entry</span><span class="w"> </span><span class="nt">in</span><span class="w"> </span><span class="nv">site.data.tags</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">tag_key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">tag_entry</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">tag_data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">tag_entry</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="p">%}</span>
<li><a href="/blog/tag/<span class="p">{{</span><span class="w"> </span><span class="nv">tag_key</span><span class="w"> </span><span class="p">}}</span>/"><span class="p">{{</span><span class="w"> </span><span class="nv">tag_data</span><span class="p">.</span><span class="nv">name</span><span class="w"> </span><span class="p">}}</span></a></li>
<span class="p">{%</span><span class="w"> </span><span class="nt">endfor</span><span class="w"> </span><span class="p">%}</span>
</code></pre></div></div>
<h3 id="more-debugging-options">More Debugging options</h3>
<p>In case you’re generating something other than HTML, <code class="language-text highlighter-rouge">dump_text</code> and <code class="language-text highlighter-rouge">dump_console</code> come in handy.</p>
<div class="alert-box warning radius "><p>Different languages have different rules, make sure you escape everything accordingly.<br />For example XML comments cannot contain <samp>--</samp> so it’s required to strip (<code>| remove: '--'</code>) or collapse them (<code>| replace: '--', '-'</code>) to make parsers happy.</p>
</div>
<div title="Example debugging of sitemap.xml" class="language-liquid highlighter-rouge"><div class="highlight"><pre class=""><code><url>
<!-- <span class="p">{{</span><span class="w"> </span><span class="nv">link</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_text</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">remove</span><span class="p">:</span><span class="w"> </span><span class="s1">'--'</span><span class="w"> </span><span class="p">}}</span> -->
<loc><span class="p">{{</span><span class="w"> </span><span class="nv">site</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="p">}}{{</span><span class="w"> </span><span class="nv">site</span><span class="p">.</span><span class="nv">baseurl</span><span class="w"> </span><span class="p">}}{{</span><span class="w"> </span><span class="nv">link</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_console</span><span class="p">:</span><span class="w"> </span><span class="s2">"original"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">remove</span><span class="p">:</span><span class="w"> </span><span class="s1">'index.html'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_console</span><span class="p">:</span><span class="w"> </span><span class="s2">"stripped"</span><span class="w"> </span><span class="p">}}</span></loc>
...
</url>
</code></pre></div></div>
<div title="Sample from sitemap.xml" class="language-xml highlighter-rouge"><div class="highlight"><pre class=""><code><span class="nt"><url></span>
<span class="c"><!-- (Hash){...
"dir"=>"/blog",
"name"=>"index.html",
"path"=>"blog/index.html",
"url"=>"/blog/index.html"} --></span>
<span class="nt"><loc></span>http://localhost:4000/dev/blog/<span class="nt"></loc></span>
</code></pre></div></div>
<div title="Sample console dump from sitemap.xml" class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code> Regenerating: 1 file changed at 2015-07-29 14:16:06
original: (String)"/blog/index.html"
stripped: (String)"/blog/"
original: (String)"/blog/tags/"
stripped: (String)"/blog/tags/"
...
</code></pre></div></div>
<div class="alert-box tip radius "><p>It’s also worth looking at <a href="https://github.com/octopress/debugger">Octopress Debugger</a> which offers different features.</p>
</div>
<h2 id="hidden-gems">Hidden Gems</h2>
<h3 id="filter-documentation">Filter Documentation</h3>
<p>Not all the filters documented are available when using an older version of either <a href="https://jekyllrb.com/docs/templates/#filters">Jekyll</a> or <a href="https://docs.shopify.com/themes/liquid-documentation/filters">Liquid</a>. The most relevant documentation and list of filters can be found in your local Ruby installation:</p>
<ul>
<li>Jekyll: <samp>lib/ruby/gems/2.2.0/gems/jekyll-2.4.0/lib/jekyll/filters.rb</samp></li>
<li>Liquid <samp>lib/ruby/gems/2.2.0/gems/liquid-2.6.2/lib/liquid/standardfilters.rb</samp></li>
</ul>
<h3 id="working-with-arrays">Working With Arrays</h3>
<p>By default Liquid <a href="https://github.com/Shopify/liquid/issues/523">doesn’t have array manipulation</a>, but our friends at Jekyll were kind enough to implement it, and we can even create new arrays with the <code class="language-text highlighter-rouge">split</code> trick.</p>
<div title="Array Manipulation" class="language-liquid highlighter-rouge"><div class="highlight"><pre class=""><code><span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">","</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">split</span><span class="p">:</span><span class="w"> </span><span class="s2">","</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_console</span><span class="p">:</span><span class="w"> </span><span class="s2">"new array"</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">push</span><span class="p">:</span><span class="w"> </span><span class="s2">"c"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_console</span><span class="p">:</span><span class="w"> </span><span class="s2">"insert last"</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">push</span><span class="p">:</span><span class="w"> </span><span class="s2">"d"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_console</span><span class="p">:</span><span class="w"> </span><span class="s2">"insert last"</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">unshift</span><span class="p">:</span><span class="w"> </span><span class="s2">"b"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_console</span><span class="p">:</span><span class="w"> </span><span class="s2">"insert first"</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">unshift</span><span class="p">:</span><span class="w"> </span><span class="s2">"a"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_console</span><span class="p">:</span><span class="w"> </span><span class="s2">"insert first"</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">shift</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_console</span><span class="p">:</span><span class="w"> </span><span class="s2">"remove first 2"</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">pop</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_console</span><span class="p">:</span><span class="w"> </span><span class="s2">"remove last 1"</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">unshift</span><span class="p">:</span><span class="w"> </span><span class="s2">"z"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_console</span><span class="p">:</span><span class="w"> </span><span class="s2">"insert first"</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">push</span><span class="p">:</span><span class="w"> </span><span class="s2">"a"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_console</span><span class="p">:</span><span class="w"> </span><span class="s2">"insert last"</span><span class="w"> </span><span class="p">%}</span>
<span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">r</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">sort</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">dump_console</span><span class="p">:</span><span class="w"> </span><span class="s2">"order by contents"</span><span class="w"> </span><span class="p">%}</span>
</code></pre></div></div>
<div title="output" class="language-bash highlighter-rouge"><div class="highlight"><pre class=""><code>insert last: <span class="o">(</span>Array<span class="o">)[</span><span class="s2">"c"</span><span class="o">]</span>
insert last: <span class="o">(</span>Array<span class="o">)[</span><span class="s2">"c"</span>, <span class="s2">"d"</span><span class="o">]</span>
insert first: <span class="o">(</span>Array<span class="o">)[</span><span class="s2">"b"</span>, <span class="s2">"c"</span>, <span class="s2">"d"</span><span class="o">]</span>
insert first: <span class="o">(</span>Array<span class="o">)[</span><span class="s2">"a"</span>, <span class="s2">"b"</span>, <span class="s2">"c"</span>, <span class="s2">"d"</span><span class="o">]</span>
remove first 2: <span class="o">(</span>Array<span class="o">)[</span><span class="s2">"c"</span>, <span class="s2">"d"</span><span class="o">]</span>
remove last 1: <span class="o">(</span>Array<span class="o">)[</span><span class="s2">"c"</span><span class="o">]</span>
insert first: <span class="o">(</span>Array<span class="o">)[</span><span class="s2">"z"</span>, <span class="s2">"c"</span><span class="o">]</span>
insert last: <span class="o">(</span>Array<span class="o">)[</span><span class="s2">"z"</span>, <span class="s2">"c"</span>, <span class="s2">"a"</span><span class="o">]</span>
order by contents: <span class="o">(</span>Array<span class="o">)[</span><span class="s2">"a"</span>, <span class="s2">"c"</span>, <span class="s2">"z"</span><span class="o">]</span>
</code></pre></div></div>
<h3 id="liquid-code-highlight">Liquid code highlight</h3>
<p>Luckily the page’s code is first run through Liquid and then kramdown, so it’s possible to use liquid tags to generate the markdown code. Based on this it’s also possible to nest them weirdly, notice that the <code>```</code> pair is interleaving with the <code class="language-text highlighter-rouge">raw</code>/<code class="language-text highlighter-rouge">endraw</code> tags; I prefer this because the markdown indentation is natural, only the end of the line is a little different.</p>
<div title="output is similar to this block" class="language-liquid highlighter-rouge"><div class="highlight"><pre class=""><code>```liquid<span class="p">{%</span><span class="w"> </span><span class="nt">raw</span><span class="w"> </span><span class="p">%}</span>
{% assign var = other_var | sort | split: ' ' %}
```<span class="p">{%</span><span class="w"> </span><span class="nt">endraw</span><span class="w"> </span><span class="p">%}</span>
{: title="caption of code"}
</code></pre></div></div>
<h2 id="liquid-error-messages">Liquid Error Messages</h2>
<div class="alert-box todo radius "><p>Maybe https://saimonmoore.com/tumblog/200612/debugging-liquid-templates.html can help with this.</p>
</div>
<p>Among other modifications made to my tags display, I wanted to sort tags case insensitively and I got the following error message:</p>
<blockquote>
<p>Liquid Exception: no implicit conversion from nil to integer <cite>in tags.html</cite></p>
</blockquote>
<p>Not knowing which line gave the error, I tried to fix and remove parts of the file which were dealing with numbers like <samp>0 < post.size</samp>. After many minutes of trying I found out that the above line gives the message and the problem is that I missed the quotes on <code class="language-text highlighter-rouge">downcase</code>: quotes are required for map as method are called via reflection.</p>
<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class=""><code><span class="p">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">tag_words</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">site_tags</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">split</span><span class="p">:</span><span class="w"> </span><span class="s1">','</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">map</span><span class="p">:</span><span class="w"> </span><span class="nv">downcase</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">sort</span><span class="w"> </span><span class="p">%}</span>
</code></pre></div></div>
2015-06-09T00:00:00+00:00https://www.twisterrob.net/blog/2015/04/android-full-thread-dump.htmlGetting a full Thread Dump on Android2015-04-13T00:00:00+00:00<p>The Android operating system does a thread dump whenever it receives <code class="language-text highlighter-rouge">SIGQUIT</code> signal.
However you need an unlocked device to send that signal.
Fear not, there’s a workaround to get the exact same thread dump with a little more effort on a production device with a debuggable application.
<!--more--></p>
<h2 id="background">Background</h2>
<p>There are a few sources on the Internet on how to make a thread dump in Android, but most of them don’t work or are lacking the intrinsic locking information, here’s an example:</p>
<blockquote>
<p>If you have a developer / rooted device, you can ask the Dalvik VM to dump thread stacks by sending a <code class="language-text highlighter-rouge">SIGQUIT</code> to the app process you’re interested in.
<cite><a href="https://stackoverflow.com/a/13592951/253468">How to make Java Thread Dump in Android?</a></cite></p>
</blockquote>
<p>If you try to send a signal on a non-rooted/non-dev device you’ll get:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>me@laptop<span class="nv">$ </span>adb shell <span class="s2">"ps | grep twister"</span>
USER PID PPID VSIZE RSS WCHAN PC NAME
u0_a504 10904 278 914108 23164 ffffffff 00000000 S net.twisterrob.app
me@laptop<span class="nv">$ </span>adb shell <span class="nb">kill</span> <span class="nt">-s</span> SIGQUIT 10904
/system/bin/sh: <span class="nb">kill</span>: 10904: Operation not permitted
</code></pre></div></div>
<p><a href="https://stackoverflow.com/a/17737101/253468">An answer</a> to <a href="https://stackoverflow.com/q/17736188/253468">How to stop an android application from adb without force-stop or root?</a> suggests to use <code class="language-text highlighter-rouge">run-as</code>:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>me@laptop<span class="nv">$ </span>adb shell run-as net.twisterrob.app <span class="nb">kill</span> <span class="nt">-3</span> 10904
run-as: Package <span class="s1">'net.twisterrob.app'</span> is unknown
</code></pre></div></div>
<p>while the OP states that <code class="language-text highlighter-rouge">force-stop</code> and <code class="language-text highlighter-rouge">am kill</code> is ruled out, we could use them here:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>me@laptop<span class="nv">$ </span>adb shell am force-stop net.twisterrob.app
me@laptop<span class="nv">$ </span>adb shell am <span class="nb">kill</span> <span class="nt">--user</span> all net.twisterrob.app
</code></pre></div></div>
<p>…the first really kills the app, and the second does nothing, in any case there’s no thread dump.</p>
<h2 id="solution">Solution</h2>
<p>A solution for the above issues follows, based on the fact that you have control over your own Android process from the app’s code.</p>
<h3 id="step-0-fake-a-ui-lock-down">Step 0: Fake a UI lock-down</h3>
<p>To have something to validate that we have the right information I suggest to lock on a known object. So later we’ll see who/where and when locked. I put the following into my main Activity’s <code class="language-text highlighter-rouge">onCreate</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="c1">// we want to see what "this" is in a thread dump</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="k">this</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">wait</span><span class="o">();</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">InterruptedException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h3 id="step-1-always-available-debugger-break-entry-point">Step 1: Always available debugger break entry point</h3>
<p>If you want a thread dump you probably have a deadlock in your code in which case it might not be trivial to know when and where to stop the code execution. You’ll need to start a background thread in your app so that you can stop the execution any time and be able to mess around in immediate mode too.</p>
<p>There’s a <mark>Pause Program</mark> action available in IntelliJ IDEA’s Debug view:<br />
<img src="data:image/png;base64,
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" alt=""Pause Program" action in IDEA's Debug View" /><br />
but you can’t execute any code in that mode:</p>
<blockquote>
<p>Target VM is not paused by breakpoint request. Evaluation of methods is not possible in this mode</p>
</blockquote>
<p>So to have a live breakable point, put the following snippet somewhere in your app:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="k">new</span> <span class="nc">Thread</span><span class="o">(</span><span class="s">"Debug-Breaker"</span><span class="o">)</span> <span class="o">{</span>
<span class="nd">@Override</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">run</span><span class="o">()</span> <span class="o">{</span>
<span class="k">while</span> <span class="o">(</span><span class="kc">true</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="nc">Thread</span><span class="o">.</span><span class="na">sleep</span><span class="o">(</span><span class="mi">1</span><span class="o">);</span> <span class="c1">// breakpoint here</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">InterruptedException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}.</span><span class="na">start</span><span class="o">();</span>
</code></pre></div></div>
<p>Anywhere is ok that you know will surely execute before you need the thread dump.
Even an button’s event handler will work.
I choose to put mine in:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">App</span> <span class="kd">extends</span> <span class="nc">Application</span> <span class="o">{</span>
<span class="nd">@Override</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">()</span> <span class="o">{</span>
</code></pre></div></div>
<p><em>Don’t forget to register it in your manifest: <code class="language-text highlighter-rouge"><application android:name=".App"</code>.</em></p>
<p>Compile and run your app. If you did step 0 as I did, your app will be plain black/white and do nothing at this point, because <code class="language-text highlighter-rouge">wait()</code> blocked the UI thread.</p>
<h3 id="step-2-create-thread-dump">Step 2: Create thread dump</h3>
<p>Go to your IDE and do <mark>Run > Attach debugger</mark> to Android process<br />
<img src="data:image/png;base64,
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
TkSuQmCC" alt="Choose Process dialog" /><br />
and select your app’s process and then go to the place where you have <code class="language-text highlighter-rouge">Thread.sleep(1);</code> and put a breakpoint on it:<br />
<img src="data:image/png;base64,
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
IH75H0nGqlhgzt4HAAAAAElFTkSuQmCC" alt="Breakpoint on line `Thread.sleep`" /><br />
The breakpoint should be hit immediately:<br />
<img src="data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAAbwAAACGCAMAAACR+M+SAAAABGdBTUEAALGPC/xhBQAAAAFzUkdC
AK7OHOkAAABdUExURfHx8dbW1snS4u3s7DOZ/8vU5AAAAP///8/Y6MbP39zc3NLS0ouUpZycnHBw
cMrKyqCns9fg8M7OzpaWloqMi02UvNVqWt5/a12myjusVXV6faLK41xYUr7Cv92rnFvBPYAAAA6g
SURBVHja7J0Jm6I4EIbRGoNDL+oMXi3i//+ZmztVSQWxtbfx2ZTdgOQA8/IVSThSVe0/xd7Uqqr9
U+xNTcJbF3tTK/AKvGLzh3cJVoquwCv2angiC49ZupNSTM99ajRRsFF4QtoUeDtlv68enhDZchVh
Oi33JCebSoRlOy3cKDxcJnzhHLwtJ8FDaybkzqQTYWaX8ZpiCt5KmbATeWjriTCr/BdpAd7v6+qy
cslCFD0TIZeQ9l7ufroy6X2w+4qW3X+xlYa39sUrMlMV5eDSGHhrm0zQkhXou0DcxnKP0/v9iVkH
eOt1+VtFyhNWPQk8xWzV9/3y+s/qvIqVx8Rn4WVyF1FoojxRlJdVHtXGagzedbNb9bvNYOCJPOyc
8lajylsVeF+EJ8bKS8NbXrVJgKvVqDtk4InVNLdZ4D0Cb6lMKcjO/ReBvyyXh6VR3rJfOjNJ9MzF
RLmQXEdz91Obpc3aR4yny2LKHLxRQ/CW104uLJcr/Zlmqym5Cxx/NQ5IuO3/zz8G3mqkyJ3wNDO6
QCKvSNmn+axGcvfbwCH4K54W4T2kPMssNNKLvRu8YgVesVfC+13sTa3Ae2945Ra6N771rxqz9utW
Fft2uwOv/qoVeG8PD3KT+AsTA143eTw+vMNEwwP1x32ehDe2VbIGvhcdPBS/RcswX5LwH7nNdNNt
pLoZSa9CPmN8B39WdeO7+jQ8yOc82zMi5PYN5rej3m0G5+V96PNuU9otOmaB6n1PDPtPOK+jHfOB
FR8g/3rX/Yq9XreTue06JlHfh2gh8xZ7TFpczCZ/bInRwOf2tW7zeAPuoHWHTAwvFNP5rOglh35z
O51Of0nZ4uz7szEcuJP05H+6ExJ1r2aRb/Ulwu5btMmfXYrc5ucnwcfBEw/BO56AOX6zztqt0gg0
vZ7UAbeno7RTQ6OH47EP8DyQXdcp9eFzKVjSkl5/YEtEweuD7aOqFTr+f2iJVlhg+LS2DYVseUn7
KjxNrzPGn/OsnyNluHb0VNmS6ruS3vHYeJdMj4A1UZ79mXLLwB28it7ZbxsiryDh+bv7z/v5yA0t
+WJsPr39jZUnMLPH4CmlQGXLIHGbXmXxga0pHA7r3pYtQvRh6d2OsWDBsTuTH6qU124HcvyA9bLo
BOn2ACnvcjmYz3mfHPYzOOWFCouENkBF0BF4aqIFaGQo/Bo8VetEAu+UcZt2N8hJimjogEXpHV+j
6d2OR9Ia03o9HDS7A67VyPPd1p/zOvrrtfLaa1Vdr6lX2J+D7WdX8cRuc/f5qVyRRed+IIUnpkxF
7DaV3+TdJphagy5uXXfwdV1L72C8GkSQjPYUvMhnHlRmXq2htjlI9W0XwzBUHTmIent0IHQYHgTb
s6e8H5Qe4F2VuuPaPBSeVlgemwtNz3mM24Rw8Ct4Z1I9B8PizJ0OtfaO6kPbDZrdwZ0nCdiuWmwb
Cs9WNwk87xXAwrtc1J9y/HOrbdLjzAgvlkiqvHpUeXUKb6S2aVboWsMZ2Kp83GZzJn3mKbhNfxgY
draGikIlvL/D1sGDpBQ0PLinvBnVNuEOPEgrLGKi86TtPHIFCheQ3Yk/yjv+ibo65aQPDe4q0tjt
eDRuk0BSGa3jo9R4zkqCG/Y7rDzc/sy5TaM8WQ+gypuF8CB1mxnl2aYCqp3EVZVQYYl7WMJtZwe+
qbA8HJbp7vUkEVGLZXeMQ/4Y3UGiVQNP0jPwEpUbeKj3B+6c8+ZxyosrLDy8URNsA6LNd+5C1FTQ
3VQ0nG+6w+NdjiY7RnmkKKZVWObXzekdmHQOuybAm9i36VWYv6qQdZvZ7rF8ADABwPe04aOgq+gS
sMqLO6ZzW5pfbdM00r+ivHuXhMbcZoIC7vRYP4jbVViCVWnL43olVZZ2XP40cB61TdM99lp4wF6z
g7iHhY0x9bIMZJPAuI+DXGB7zwnPo7YJI9fzXnRJaPzmC3jgFAaPnfYgSzZuUMal0lbJFbIok7kI
b0wD1Utug2BV0iY9FcDU5PAdGhVzlwkwudCMshfj4kKBiutAyFzQm11tkz/UnlYecMV291YDpkiB
nqdgWt0Psm44URREHQhThDeX2ua33MMC967fsxfKUzbA0c3oDvWPAosKMnfP3PdFc61tZnz88/ew
VJzw8v6cEx48JDxITpIwdk5knfXoSW+Wtc0q3zFdbrqdp7Whnw+q5I7FJ+AV+25DykvwPQev2Lfb
SMW4wHsLeLmHgQq8t4CXtcvfYrO1u88qlOdP52hb92RsvlUDBd4bwIOivHdWXrZvsxTU7OHBuPLQ
tcxScHNUHncdzMPzqXal4GZZYWHxWXjo/oJScnNU3uVy2X3ugXWb+1h6+u7oUoizcpv2MRPUMW3h
obFMDLxSgD9jm82Gaypo5an7//AFMQ/Pp8bwhJprCaqJlqJA02L/BTysvE973zt1m5ff/e6qnhB1
8ITH5SHauZ0We7nt8/Cc8tRzeuFKuodn2PWR8izHAI9ALfZa1e23d8552ny9Jas8PxWJ8gzRUtav
dpfS9qO1TU8vhafe7b6bAk+UGs3PKw91j1l4kt4dtxmqL8W+5Zx3X3lD3DGdKK/YLNt5uLYJvmM6
bioUm2EPC2rnAb4kFDfSi822hwW96KMU1NzhAdO3Wa6kv43yIPMIVIH3Pm4zfSCkFNQbuM3MExUF
3hsqD8gloWLzP+cxz64VeO9R2wTu+e8C7x3cJnBPMcrQXbEZ2lZP43NeLL+27i6bYs/Ypatf/lDl
Fj1owj0Rbiss+w7K4zhPGXT7b4WXf8K+3UBdnh5+ymrYMG+SeWYaw6vY15SAhFfYPU1vE7275Lkp
xPDyt7sXeC+D9zrhGXgDrrCYd475d/4VeK9X3rPQ3BcNr8O5dm3buam/qqDhXa/7/VUb99YU4F4P
Bvl3pIwN1DS2xw8ZPBxwN7evjlMV4E1HNPaiNaDwTCQKDytve7123XXfDo12ukDHbLOrosHbmEhJ
EE7OjgJHciY5VFUaL96R6C8fnQ+PA/K/a3yClWeLehh4ctjthReoIzsjt9kRt4ngIbep3vN6vW5O
N/Vy4NPNvvlVyM8jJp4KplEf2/KPm4fnhTR03cAKzL0tE3ujMzEOHkTnPH9JyMA7SWryXw1ncOOL
UGQgCGOT4am4eEX4ZjNyW7bf7FIyA7IoQnIcEKfwm0izegU8V6x6bJWBe8kWGXvCEeyD8PoqqzwK
DyvvpHSn2Mn5LYYnfJG7GQNmIjxBEYIrRLwts0EfLNDuCLyxsCjSQwFEGo0cgWLSfj8ID4zuWvlR
9JJzWvQq3ioMbqVGLzj3VQYepLVNQG7zdrypEZhu9ceJwhPp7w6FRcrCykZwWkmEK8hWcOELW+5O
0IJsnoMnOL8gom8pPIgyppIW9rc87DbNmEat1R59dR1VjudnhiY7hPHMCDxIlWe7xzZVI+10HI4f
9U2ykx60QSaEWyCzsN6t0yuEm+EE5JsylMgFRFtxASJJj7+hLKK9s1H9xnwKs0akPwjvuQvHvzE1
e76QSxVxm4NFhzxnXGFJXoJohpjoQ9Txdl5wmwbe6e/xBLVih+Gh3U+KJ4QJ/IObHDz9S2lwVFwo
dwyvcQzigkebFAw7tB0RUW2a9KjhM75Hr6HwoIoY0VqMsyFp1tDBxtLusUwjXcNTbvMk6cHp9FXl
4SJwR3gErInh+d8/Bu+e8pJcgh/gDrpGhHLHB+DD8PwxUW3idx/TSqHr8xoidvjdouHV+MBcVYBc
bdO6TV1h0exuTbOwH4RJUPejZzrKIqO8sVWJowzTxeNuEy8uGja8iY815GwXY/AW5J9+TLwFcZsQ
10sw0yGwi6sy0bA848pDbnMhTdZUtrqpIFt66rvcN/VnTPgJXXYxBJrEy8LPkqhoDZm6RaOoOGeX
WJB86CLdWDYF2hzZc7zj9ov9b6J/Y/ScF9VLyEsyB6o7VJlx8ACd8+qxgaUhwNONdD1k3W2hDyvz
Zz4LW5B+trBxbHgCb2GjCVMCdqaThBCBC8pR8psUGGRIg2ZhsSGli7HnUqCdsBsN8Bq/4yZDBC8U
C/r1TYAHuba4Xxh43Wl4fU55UEFmgAgNb9DdY5eu3S5mY4EvH/y6gGejV0n3WKhXRC06229WkfaD
+jfDkwF3zsu8FFtfz6s+Pj5Cx7T8snj6E9tzObDhIperyKSjKdLcP+IwMXnXK9oxDVxHeTpgBF17
pu9Kj2+DyF3Pq2hZLWbzGd2ZjwfXLx76aUr00/cT1zYh+0r7kSsw92+DAP7V/Fp5xZ6xqMISn6Yg
utUZ+OFAAAdsJ73ptsB7JTx+7IbcWFaQH02McZuQ3r/Zbhoo7wN+yqDZVOz7+SA/SktuJB5eecCO
qqBu/ds35UaGp6zRg/m1FTuyC2TrKTFhqEYb6WlKddPtvtw2+6Ttv/emW/aAMMrbFpujJcrj7ptu
xa/ymd8n7Zjm7rBqfxWbn4l7TQVb2xSlqGZoCbwjsqK8N1Ke8pPmBiNtCF5R3lso74QsuM37GdX1
F/egLhBeds6L4E1VXk0o1BplXUdE6zF49USmBTavvLzbnCSfmpZvnRR1zSpWI445F0ZfUV4EL61t
1spDWjC1K3QyqTMMTDKbJsxYWlxc754tb7u1uq6L8lh4qfLqOnByy3Uo/9qLKQevxknvwCNxSTxH
938sU7a2+W87Z7TCMAxC0YeM+Qfd///pCpurmqtB6IMjNg8lYAjkcKumiQc36POkyIzWyFhoTUjQ
YiiEh23NJB74rfM8ZnfAaDMBTy+rA4QJJ+Cxn+Tx1MpjeC+QpD/vgHe5KgUPhjbY1s4Kx+4cba52
WIRkEDyKyVIML7alyRs+rk4rb4KHok3O5DQB7evkywD55QbipaTm2Qo/KcIV7myuvOHe3E7meWHG
Zr+nlLDtBDBQ3vCKpSZ3WKLFjuCtbBteHG3O5VJv3tvMpGYo6mlmUHnDrXjRfxX+QnlQeKfy+sxB
wbYqX/W91txV+yo+yOeBc5u9UPXhjQnf53B8wysPD5/ZbOUVh/cGO055EoUJ9b4AAAAASUVORK5C
YII=" alt="app pause at breakpoint" /></p>
<p>Now there’s a context you can execute code in, go to <mark>Run > Evaluate Expression...</mark> and enter:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class=""><code><span class="n">android</span><span class="o">.</span><span class="na">os</span><span class="o">.</span><span class="na">Process</span><span class="o">.</span><span class="na">sendSignal</span><span class="o">(</span><span class="n">android</span><span class="o">.</span><span class="na">os</span><span class="o">.</span><span class="na">Process</span><span class="o">.</span><span class="na">myPid</span><span class="o">(),</span> <span class="n">android</span><span class="o">.</span><span class="na">os</span><span class="o">.</span><span class="na">Process</span><span class="o">.</span><span class="na">SIGNAL_QUIT</span><span class="o">)</span>
</code></pre></div></div>
<p>In the Android LogCat view you’ll see the following information printed:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>04-13 16:36:21.971 10904-10954/net.twisterrob.app I/Process﹕ Sending signal. PID: 10904 SIG: 3
04-13 16:36:21.971 10904-10909/net.twisterrob.app I/dalvikvm﹕ threadid=3: reacting to signal 3
04-13 16:36:22.061 10904-10909/net.twisterrob.app I/dalvikvm﹕ Wrote stack traces to '/data/anr/traces.txt'
</code></pre></div></div>
<p>The app may be still running at this point, but it doesn’t matter any more. Feel free to detach debugger and/or stop it on the phone.</p>
<h3 id="step-3-acquire-thread-dump">Step 3: Acquire thread dump</h3>
<p>Now it should be a simple <code class="language-text highlighter-rouge">pull</code> from your device like this, but hey it’s not that simple…</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>me@laptop<span class="nv">$ </span>adb pull /data/anr/traces.txt
failed to copy <span class="s1">'/data/anr/traces.txt'</span> to <span class="s1">'./traces.txt'</span>: Permission denied
</code></pre></div></div>
<p>for some reason I wasn’t able to copy the file, but I can read it… so it’s simple after all:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class=""><code>me@laptop<span class="nv">$ </span>adb shell <span class="s2">"cat /data/anr/traces.txt"</span> <span class="o">></span> traces.txt
</code></pre></div></div>
<h3 id="step-4-read-thread-dump">Step 4: Read thread dump</h3>
<p>Now if you open <samp>traces.txt</samp> on you machine and scroll from the bottom you should find your app:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>----- pid 10904 at 2015-04-13 17:16:40 -----
Cmd line: net.twisterrob.app
... lots of stack traces of threads ...
----- end 10904 -----
</code></pre></div></div>
<p>Here’s the UI thread’s state, remember in <a href="#step-0-fake-a-ui-lock-down">Step 0</a> I synchronized on <code class="language-text highlighter-rouge">this</code>, see line #6 (starting with “waiting on”):</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class=""><code>"main" prio=5 tid=1 WAIT
| group="main" sCount=1 dsCount=0 obj=0x418ccea0 self=0x417c7388
| sysTid=13183 nice=-11 sched=0/0 cgrp=apps handle=1074684244
| state=S schedstat=( 0 0 0 ) utm=7 stm=5 core=3
at java.lang.Object.wait(Native Method)
- waiting on <0x42aeb7a8> (a net.twisterrob.app.MainActivity)
at java.lang.Object.wait(Object.java:364)
at net.twisterrob.app.MainActivity.onCreate(MainActivity.java:45)
at android.app.Activity.performCreate(Activity.java:5426)
...
</code></pre></div></div>
<h2 id="summary">Summary</h2>
<p>The above steps should give you access to thread dumps for any application you develop from your real device. The full thread dumps contain locking information like the <samp>waiting on</samp> line above which helps to diagnose deadlocks and synchronization issues. If you just want to see where your app is at the current time I suggest you use the Threads view of the SDK’s DDMS <code class="language-text highlighter-rouge">monitor</code>, or <code class="language-text highlighter-rouge">Thread.getAllStackTraces()</code> programmatically or while debugging.</p>
2015-04-13T00:00:00+00:00