{"id":430,"date":"2012-04-13T08:48:39","date_gmt":"2012-04-13T07:48:39","guid":{"rendered":"http:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/"},"modified":"2012-04-13T08:48:39","modified_gmt":"2012-04-13T07:48:39","slug":"verifying-mysql-behaviour-with-automated-test-suites-and-mytap","status":"publish","type":"post","link":"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/","title":{"rendered":"Verifying MySQL behaviour with automated test suites and mytap"},"content":{"rendered":"<p>You know everything about how MySQL treats UTF8 and LATIN1 charsets and how the collation table impacts on selection and insertion of data, right?<\/p>\n<p>Great, then stop reading :)<\/p>\n<p>I don&#39;t and since I&#39;m in the process of setting up a new version of the Opera accounts database, I really don&#39;t want to screw up things. I tried to fully understand how MySQL works in this respect (charsets, collations, etc&#8230;) but reading documentation and memorizing it wasn&#39;t very easy. Plus, there&#39;s <a href=\"http:\/\/duckduckgo.com\/?q=mysql+utf8+latin1\" rel=\"nofollow\">a thousands<\/a> <a href=\"http:\/\/duckduckgo.com\/?q=mysql+utf8_general_ci+utf8_unicode_ci+latin1_swedish_ci\" rel=\"nofollow\">blog posts<\/a> on the matter, not always 100% accurate.<\/p>\n<p>So I thought I&#39;d better get hands on and I wrote a kind of <b>database test suite<\/b>.<\/p>\n<p>Now this test suite is hooked up to the main project builds on Jenkins. Here&#39;s a sample output:<\/p>\n<pre><code>\r\n[...]\r\n[workspace] $ \/bin\/sh -xe \/tmp\/hudson3255767718598715423.sh\r\n+ .\/bin\/run-dbtest-suite\r\nbasedir=\/var\/lib\/jenkins\/jobs\/auth-db\/workspace\r\n\/var\/lib\/jenkins\/jobs\/auth-db\/workspace\/t\/database-tests\/__initdb__.my ........................................... \r\n1..2\r\nok 1 - Using utf8tests database\r\nok 2 - Server charset is latin1\r\nok\r\n\/var\/lib\/jenkins\/jobs\/auth-db\/workspace\/t\/database-tests\/collation-utf8_bin.my ................................... \r\n1..6\r\nok 1 - All our records are there. No duplicate key error.\r\nok 2 - utf8_bin collation does not collate a\/\u00c3\u00a2\/\u00c3\u00a0\/A\/...\r\nok 3 - utf8_bin collation does not collate a\/\u00c3\u00a2\/\u00c3\u00a0\/A\/...\r\nok 4 - utf8_bin collation does not collate a\/\u00c3\u00a2\/\u00c3\u00a0\/A\/...\r\nok 5 - Query for mixed-case username does not return lowercase username\r\nok 6 - Query for upper-case username does not return lowercase username\r\nok\r\n\/var\/lib\/jenkins\/jobs\/auth-db\/workspace\/t\/database-tests\/collation-utf8_general_ci.my ............................ \r\n1..7\r\nok 1 - Collation for t007 is utf8_general_ci\r\nok 2 - utf8_general_ci collation normalizes accents, diacritics and the like\r\nok 3 - A and \u00c3\u2026 are collated to the same character in the utf8_general_ci table\r\nok 4 - \u00c3\u00a5 and \u00c3\u2026 are collated to the same character in the utf8_general_ci table\r\nok 5 - lower\/upper case chars are collated in the utf8_general_ci table\r\nok 6 - lower\/upper case chars are collated in the utf8_general_ci table\r\nok 7 - We are allowed to insert all records just because there is no unique constraint\r\nok\r\n\/var\/lib\/jenkins\/jobs\/auth-db\/workspace\/t\/database-tests\/collation-utf8_unicode_ci.my ............................ \r\n1..7\r\nok 1 - Collation for t005 is utf8_unicode_ci\r\nok 2 - utf8_unicode_ci collation normalizes accents, diacritics and the like\r\nok 3 - A and \u00c3\u2026 are collated to the same character in the utf8_unicode_ci table\r\nok 4 - \u00c3\u00a5 and \u00c3\u2026 are collated to the same character in the utf8_unicode_ci table\r\nok 5 - lower\/upper case chars are collated in the utf8_unicode_ci table\r\nok 6 - lower\/upper case chars are collated in the utf8_unicode_ci table\r\nok 7 - We are allowed to insert all records just because there is no unique constraint\r\nok\r\n\/var\/lib\/jenkins\/jobs\/auth-db\/workspace\/t\/database-tests\/default-table-charset.my ................................ \r\n1..3\r\nok 1 - Default character set is utf8 when no charset is specified (from server)\r\nok 2 - Default character set is utf8 when &quot;CHARSET utf8&quot; specified in the CREATE TABLE\r\nok 3 - Default character set is utf8 when &quot;CHARSET utf8&quot; and &quot;COLLATE&quot; specified in the CREATE TABLE\r\nok\r\n...\r\n\/var\/lib\/jenkins\/jobs\/auth-db\/workspace\/t\/database-tests\/username-with-utf8-chars.my ............................. \r\n1..5\r\nok 1 - We have some UTF-8 encoded string in our hands (hex)\r\nok 2 - We have some UTF-8 encoded string in our hands (charset)\r\nok 3 - Can select back UTF-8 content from a CHARSET utf8 table\r\nok 4 - Given string is exactly 24 bytes long (length)\r\nok 5 - Given string is exactly 8 (wide) characters long (char_length)\r\nok\r\nAll tests successful.\r\nFiles=11, Tests=80, 0.739731 wallclock secs ( 0.05 usr  0.02 sys +  0.07 cusr  0.01 csys =  0.15 CPU)\r\nResult: PASS\r\nRecording test results\r\nFinished: SUCCESS\r\n<\/code><\/pre>\n<p>And here&#39;s an example of &quot;sanity check&quot; test case, which doesn&#39;t do much:<\/p>\n<pre><code>\r\n   1 -- Check that we can insert and retrieve UTF-8 content correctly\r\n   2 \r\n   3 BEGIN;\r\n   4 \r\n   5 SET NAMES utf8;\r\n   6 \r\n   7 SELECT tap.plan(5);\r\n   8 \r\n   9 USE auth_utf8tests;\r\n  10 \r\n  11 SET @username = &#39;\u00e4\u00bb\u0160\u00e6\u2014\u00a5\u00e8\u00af\u009d\u00e9\u00a2\u02dc\u00e4\u00bb\u0160\u00e6\u2014\u00a5\u00e8\u00af\u009d\u00e9\u00a2\u02dc&#39;;\r\n  12 SET @encoded  = &#39;C1BB8AE697A5E8AF9DE9A298E4BB8AE697A5E8AF9DE9A298&#39;;\r\n  13 \r\n  14 SELECT tap.eq(\r\n  15     HEX(@username),\r\n  16     @encoded,\r\n  17     &#39;We have some UTF-8 encoded string in our hands (hex)&#39;\r\n  18 );\r\n  19 \r\n  20 SELECT tap.eq(\r\n  21     CHARSET(@username),\r\n  22     &#39;utf8&#39;,\r\n  23     &#39;We have some UTF-8 encoded string in our hands (charset)&#39;\r\n  24 );\r\n  25 \r\n  26 INSERT INTO t001 (f1) VALUES (@username);\r\n  27 \r\n  28 SELECT tap.eq(\r\n  29     (SELECT HEX(f1) FROM t001 WHERE f1 = @username),\r\n  30     @encoded,\r\n  31     &#39;Can select back UTF-8 content from a CHARSET utf8 table&#39;\r\n  32 );\r\n  33 \r\n  34 SELECT tap.eq(\r\n  35     (SELECT LENGTH(f1) FROM t001 WHERE f1 = @username),\r\n  36     24,\r\n  37     &#39;Given string is exactly 24 bytes long (length)&#39;\r\n  38 );\r\n  39 \r\n  40 SELECT tap.eq(\r\n  41     (SELECT CHAR_LENGTH(f1) FROM t001 WHERE f1 = @username),\r\n  42     8,\r\n  43     &#39;Given string is exactly 8 (wide) characters long (char_length)&#39;\r\n  44 );\r\n  45 \r\n  46 -- Finish the tests and clean up.\r\n  47 CALL tap.finish();\r\n  48 ROLLBACK;\r\n<\/code><\/pre>\n<p>This SQL test code uses <a href=\"http:\/\/theory.github.com\/mytap\/\" rel=\"nofollow\">mytap<\/a>. You can see how the <code>SELECT tap.*<\/code> calls are just the equivalents of the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Test_Anything_Protocol\" rel=\"nofollow\">TAP testing framework<\/a> of Perl. <code>SELECT tap.eq()<\/code> is the equivalent of <a href=\"https:\/\/metacpan.org\/module\/Test::More#Im-ok-youre-not-ok.\" rel=\"nofollow\"><code>Test::More::is()<\/code><\/a>, and so on.<\/p>\n<p>Another, more interesting test case, is the following:<\/p>\n<pre><code>\r\n   1 --\r\n   2 -- Verify how the utf8_unicode_ci collation works\r\n   3 --\r\n   4 \r\n   5 BEGIN;\r\n   6 \r\n   7 SET NAMES utf8;\r\n   8 \r\n   9 SELECT tap.plan(12);\r\n  10 \r\n  11 USE auth_utf8tests;\r\n  12 \r\n\r\n  [...]\r\n\r\n  40 SELECT tap.eq(\r\n  41     (SELECT TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME=&#39;t015&#39;),\r\n  42     &#39;utf8_unicode_ci&#39;,\r\n  43     &#39;Collation for t015 is utf8_unicode_ci&#39;\r\n  44 );\r\n\r\n  [...]\r\n\r\n  48 \r\n  49 SELECT tap.eq(\r\n  50     (SELECT GROUP_CONCAT(id) FROM t015 WHERE username = &#39;testuser1a&#39; ORDER BY id),\r\n  51     &#39;10&#39;,\r\n  52     &#39;utf8_unicode_ci collation normalizes accents, diacritics and the like&#39;\r\n  53 );\r\n  54 \r\n  55 SELECT tap.eq(\r\n  56     (SELECT GROUP_CONCAT(id) FROM t015 WHERE username = &#39;testuser1\u00c3\u2026&#39; ORDER BY id),\r\n  57     &#39;10&#39;,\r\n  58     &#39;A and \u00c3\u2026 are collated to the same character in the utf8_unicode_ci table&#39;\r\n  59 );\r\n  60 \r\n  61 SELECT tap.eq(\r\n  62     (SELECT GROUP_CONCAT(id) FROM t015 WHERE username = &#39;testuser1\u00c3\u00a5&#39; ORDER BY id),\r\n  63     &#39;10&#39;,\r\n  64     &#39;\u00c3\u00a5 and \u00c3\u2026 are collated to the same character in the utf8_unicode_ci table&#39;\r\n  65 );\r\n  66 \r\n  67 SELECT tap.eq(\r\n  68     (SELECT GROUP_CONCAT(id) FROM t015 WHERE username = &#39;TestUser1A&#39; ORDER BY id),\r\n  69     &#39;10&#39;,\r\n  70     &#39;lower\/upper case chars are collated in the utf8_unicode_ci table&#39;\r\n  71 );\r\n  72 \r\n  73 SELECT tap.eq(\r\n  74     (SELECT GROUP_CONCAT(id) FROM t015 WHERE username = &#39;TESTUSER1A&#39; ORDER BY id),\r\n  75     &#39;10&#39;,\r\n  76     &#39;lower\/upper case chars are collated in the utf8_unicode_ci table&#39;\r\n  77 );\r\n  78 \r\n  79 SELECT tap.eq(\r\n  80     (SELECT COUNT(*) FROM t015),\r\n  81     1,\r\n  82     &#39;We are allowed to insert only 1 record, because the others collate to the same string&#39;\r\n  83 );\r\n  84 \r\n  85 -- Finish the tests and clean up.\r\n  86 CALL tap.finish();\r\n  87 ROLLBACK;\r\n<\/code><\/pre>\n<p>An interesting thing that I didn&#39;t know how to do in the beginning is <b>how to trap errors<\/b>. I left out that part from the test code to simplify, but here it is:<\/p>\n<pre><code>\r\n  13 DELIMITER \/\/\r\n  14 \r\n  15 DROP PROCEDURE IF EXISTS populate_table \/\/\r\n  16 \r\n  17 CREATE PROCEDURE populate_table ()\r\n  18 BEGIN\r\n  19 \r\n  20     DECLARE CONTINUE HANDLER FOR SQLSTATE &#39;23000&#39; BEGIN\r\n  21         SELECT tap.ok(\r\n  22             1,\r\n  23             &#39;We should get dupkey errors when inserting data with collation utf8_unicode_ci&#39;\r\n  24         );\r\n  25     END;\r\n  26 \r\n  27     INSERT INTO t015 (id,username,note) VALUES (10, &#39;testuser1a&#39;, &#39;plain&#39;);\r\n  28     INSERT INTO t015 (id,username,note) VALUES (20, &#39;testuser1\u00c3\u00a2&#39;, &#39;circumflex a&#39;);\r\n  29     INSERT INTO t015 (id,username,note) VALUES (30, &#39;testuser1\u00c3\u00a0&#39;, &#39;a grave&#39;);\r\n  30     INSERT INTO t015 (id,username,note) VALUES (40, &#39;testuser1\u00c3\u2026&#39;, &#39;A circ&#39;);\r\n  31     INSERT INTO t015 (id,username,note) VALUES (50, &#39;TestUser1A&#39;, &#39;mixed case&#39;);\r\n  32     INSERT INTO t015 (id,username,note) VALUES (60, &#39;TESTUSER1A&#39;, &#39;upper case&#39;);\r\n  33 \r\n  34 END;\r\n  35 \r\n  36 \/\/\r\n  37 \r\n  38 DELIMITER ;\r\n  39 \r\n  46 \/* Should generate 5 dupkey errors (taken as successful tests) *\/\r\n  47 CALL populate_table;\r\n<\/code><\/pre>\n<p>It&#39;s a bit convoluted. To trap errors you have use the <code>DECLARE HANDLER<\/code> statement. <code>DECLARE CONTINUE HANDLER FOR SQLSTATE &#39;23000&#39;<\/code> means that whenever SQLSTATE is &#39;23000&#39;, and that corresponds to a <b>duplicate key error<\/b>, then execute this block of code. All of that <b>must necessarily be wrapped into a stored procedure<\/b>. Handlers outside of stored procedures are not allowed.<\/p>\n<p>In this particular tests, the table uses the <code>utf8_unicode_ci<\/code> collation table, so we <b>are expecting a duplicate key error on username<\/b> whenever we insert the string <code>&#39;testuser1\u00c3\u00a0&#39;<\/code> or <code>&#39;TESTUSER1A&#39;<\/code>, because <code>&#39;testuser1a&#39;<\/code> was already inserted at the beginning. Of all the <code>INSERT<\/code> statements, only the first one is bound to succeed, so I put a <code>SELECT tap.ok(1)<\/code> for the duplicate key HANDLER and I expect 5 tests when I make the <code>CALL populate_table;<\/code>.<\/p>\n<p>This of course may seem trivial. And I guess it is, but for me it&#39;s a <b>much better way of learning<\/b> than scouring through the manuals or the many blog posts out there that may or may not reflect the environment I&#39;m working with.<\/p>\n<p>Routinely running this kind of test suite makes it possible and easy to verify the database behaviour:<\/p>\n<ul>\n<li>instantly<\/li>\n<li>after upgrades (5.1 -&gt; 5.5? -&gt; 6?) or storage engine changes<\/li>\n<li>after mysql configuration changes. For example, I discovered in this way that adding <code>default-charset=utf8<\/code> in my MySQL config breaks everything.<\/li>\n<\/ul>\n<p><b>I consider this my live documentation on how MySQL works.<\/b> I would really appreciate if you have any feedback on this. Have fun!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You know everything about how MySQL treats UTF8 and LATIN1 charsets and how the collation table impacts on selection and insertion of data, right? Great, then stop reading :) I don&#39;t and since I&#39;m in the process of setting up a new version of the Opera accounts database, I really don&#39;t want to screw up [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[58,55,54,56,50,59,53,57],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.9 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Verifying MySQL behaviour with automated test suites and mytap - Random hacking<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Verifying MySQL behaviour with automated test suites and mytap - Random hacking\" \/>\n<meta property=\"og:description\" content=\"You know everything about how MySQL treats UTF8 and LATIN1 charsets and how the collation table impacts on selection and insertion of data, right? Great, then stop reading :) I don&#039;t and since I&#039;m in the process of setting up a new version of the Opera accounts database, I really don&#039;t want to screw up [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/\" \/>\n<meta property=\"og:site_name\" content=\"Random hacking\" \/>\n<meta property=\"article:published_time\" content=\"2012-04-13T07:48:39+00:00\" \/>\n<meta name=\"author\" content=\"cosimo\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"cosimo\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/\"},\"author\":{\"name\":\"cosimo\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1\"},\"headline\":\"Verifying MySQL behaviour with automated test suites and mytap\",\"datePublished\":\"2012-04-13T07:48:39+00:00\",\"dateModified\":\"2012-04-13T07:48:39+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/\"},\"wordCount\":459,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1\"},\"keywords\":[\"database\",\"latin1\",\"mysql\",\"mytap\",\"perl\",\"tap\",\"test suite\",\"utf8\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/\",\"url\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/\",\"name\":\"Verifying MySQL behaviour with automated test suites and mytap - Random hacking\",\"isPartOf\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#website\"},\"datePublished\":\"2012-04-13T07:48:39+00:00\",\"dateModified\":\"2012-04-13T07:48:39+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.streppone.it\/cosimo\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Verifying MySQL behaviour with automated test suites and mytap\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#website\",\"url\":\"https:\/\/www.streppone.it\/cosimo\/blog\/\",\"name\":\"Random hacking\",\"description\":\"Assume nothing. Code defensively. Keep it simple, stupid!\",\"publisher\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.streppone.it\/cosimo\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1\",\"name\":\"cosimo\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/cb1d938720df45a2720724aae99e3bfc?s=96&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/cb1d938720df45a2720724aae99e3bfc?s=96&r=g\",\"caption\":\"cosimo\"},\"logo\":{\"@id\":\"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/image\/\"},\"url\":\"https:\/\/www.streppone.it\/cosimo\/blog\/author\/cosimo\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Verifying MySQL behaviour with automated test suites and mytap - Random hacking","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/","og_locale":"en_US","og_type":"article","og_title":"Verifying MySQL behaviour with automated test suites and mytap - Random hacking","og_description":"You know everything about how MySQL treats UTF8 and LATIN1 charsets and how the collation table impacts on selection and insertion of data, right? Great, then stop reading :) I don&#39;t and since I&#39;m in the process of setting up a new version of the Opera accounts database, I really don&#39;t want to screw up [&hellip;]","og_url":"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/","og_site_name":"Random hacking","article_published_time":"2012-04-13T07:48:39+00:00","author":"cosimo","twitter_card":"summary_large_image","twitter_misc":{"Written by":"cosimo","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/#article","isPartOf":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/"},"author":{"name":"cosimo","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1"},"headline":"Verifying MySQL behaviour with automated test suites and mytap","datePublished":"2012-04-13T07:48:39+00:00","dateModified":"2012-04-13T07:48:39+00:00","mainEntityOfPage":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/"},"wordCount":459,"commentCount":0,"publisher":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1"},"keywords":["database","latin1","mysql","mytap","perl","tap","test suite","utf8"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/","url":"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/","name":"Verifying MySQL behaviour with automated test suites and mytap - Random hacking","isPartOf":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#website"},"datePublished":"2012-04-13T07:48:39+00:00","dateModified":"2012-04-13T07:48:39+00:00","breadcrumb":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/2012\/04\/verifying-mysql-behaviour-with-automated-test-suites-and-mytap\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.streppone.it\/cosimo\/blog\/"},{"@type":"ListItem","position":2,"name":"Verifying MySQL behaviour with automated test suites and mytap"}]},{"@type":"WebSite","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#website","url":"https:\/\/www.streppone.it\/cosimo\/blog\/","name":"Random hacking","description":"Assume nothing. Code defensively. Keep it simple, stupid!","publisher":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.streppone.it\/cosimo\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/c443bedbf6ecf99550d6395620801df1","name":"cosimo","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/cb1d938720df45a2720724aae99e3bfc?s=96&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/cb1d938720df45a2720724aae99e3bfc?s=96&r=g","caption":"cosimo"},"logo":{"@id":"https:\/\/www.streppone.it\/cosimo\/blog\/#\/schema\/person\/image\/"},"url":"https:\/\/www.streppone.it\/cosimo\/blog\/author\/cosimo\/"}]}},"_links":{"self":[{"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/posts\/430"}],"collection":[{"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/comments?post=430"}],"version-history":[{"count":0,"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/posts\/430\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/media?parent=430"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/categories?post=430"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.streppone.it\/cosimo\/blog\/wp-json\/wp\/v2\/tags?post=430"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}