├── Makefile ├── README.mkdn ├── index.html ├── node_modules └── qunit-tap │ ├── .idea │ ├── .name │ ├── encodings.xml │ ├── misc.xml │ ├── modules.xml │ ├── qunit-tap.iml │ ├── vcs.xml │ └── workspace.xml │ ├── .npmignore │ ├── GPL-LICENSE.txt │ ├── MIT-LICENSE.txt │ ├── README.md │ ├── lib │ └── qunit-tap.js │ ├── package.json │ ├── sample │ ├── commonjs │ │ ├── lib │ │ │ ├── incr.js │ │ │ └── math.js │ │ ├── test │ │ │ ├── incr_test.js │ │ │ ├── math_test.js │ │ │ └── tap_compliance_test.js │ │ └── test_helper.js │ ├── interop │ │ ├── index.html │ │ ├── lib │ │ │ ├── incr.js │ │ │ ├── math.js │ │ │ └── namespaces.js │ │ ├── phantomjs_test.sh │ │ ├── run_qunit.js │ │ ├── run_tests.js │ │ ├── test │ │ │ ├── incr_test.js │ │ │ ├── math_test.js │ │ │ └── tap_compliance_test.js │ │ └── test_helper.js │ └── js │ │ ├── index.html │ │ ├── lib │ │ ├── incr.js │ │ └── math.js │ │ ├── phantomjs_test.sh │ │ ├── run_qunit.js │ │ ├── run_tests.js │ │ └── test │ │ ├── incr_test.js │ │ ├── math_test.js │ │ └── tap_compliance_test.js │ └── vendor │ └── qunit │ ├── .gitignore │ ├── History.md │ ├── README.md │ ├── addons │ ├── canvas │ │ ├── README.md │ │ ├── canvas-test.js │ │ ├── canvas.html │ │ └── qunit-canvas.js │ ├── close-enough │ │ ├── README.md │ │ ├── close-enough-test.js │ │ ├── close-enough.html │ │ └── qunit-close-enough.js │ ├── composite │ │ ├── README.md │ │ ├── composite-demo-test.html │ │ ├── composite-test.html │ │ ├── composite-test.js │ │ ├── dummy-qunit-test.html │ │ ├── dummy-same-test.html │ │ ├── index.html │ │ ├── qunit-composite.css │ │ └── qunit-composite.js │ └── step │ │ ├── README.md │ │ ├── qunit-step.js │ │ ├── step-test.js │ │ └── step.html │ ├── package.json │ ├── qunit │ ├── qunit.css │ └── qunit.js │ └── test │ ├── headless.html │ ├── index.html │ ├── logs.html │ ├── logs.js │ ├── same.js │ ├── swarminject.js │ └── test.js ├── strftime.js ├── t ├── 01_strftime.js └── lib │ └── test-more.js └── test ├── index.html ├── node-test.js ├── qunit-git.css ├── qunit.js └── test.js /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | node test/node-test.js 3 | test-browser: 4 | @echo "Access to http://localhost:9041/test/index.html" 5 | plackup -p 9041 -e 'use Plack::App::Directory; Plack::App::Directory->new()->to_app()' 6 | test-setup: 7 | npm install qunit-tap 8 | 9 | .PHONY: test test-browser test-setup 10 | -------------------------------------------------------------------------------- /README.mkdn: -------------------------------------------------------------------------------- 1 | strftime.js 2 | =========== 3 | 4 | This is a strftime.js. Yet another Date.prototype.strftime library. 5 | 6 | USAGE 7 | ----- 8 | 9 | 10 | 13 | 14 | FUNCTION MANUAL 15 | --------------- 16 | 17 | Date.prototype.strftime('%Y-%m-%d') 18 | Date.prototype.strftime('%Y-%m-%d(%a)', 'ja') 19 | Date.prototype.strftime('%Y-%m-%d(%a)', 'en') 20 | 21 | You can specify the locale by second parameter. 22 | 23 | FORMATS 24 | ------- 25 | 26 | %a 27 | abbreviated weekday name according to the current locale 28 | 29 | %A 30 | full weekday name according to the current locale 31 | 32 | %b 33 | abbreviated month name according to the current locale 34 | 35 | %B 36 | full month name according to the current locale 37 | 38 | %c 39 | preferred date and time representation for the current locale 40 | 41 | %C 42 | century number (the year divided by 100 and truncated to an integer, range 00 to 99) 43 | 44 | %d 45 | day of the month as a decimal number (range 01 to 31) 46 | 47 | %D 48 | same as %m/%d/%y 49 | 50 | %e 51 | day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31') 52 | 53 | %F 54 | same as %Y-%m-%d (ISO 8601 date format) 55 | 56 | %h 57 | same as %b 58 | 59 | %H 60 | hour as a decimal number using a 24-hour clock (range 00 to 23) 61 | 62 | %I 63 | hour as a decimal number using a 12-hour clock (range 01 to 12) 64 | 65 | %k 66 | hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.) 67 | 68 | %l 69 | hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.) 70 | 71 | %m 72 | month as a decimal number (range 01 to 12) 73 | 74 | %M 75 | minute as a decimal number 76 | 77 | %n 78 | newline character 79 | 80 | %p 81 | either `AM' or `PM' according to the given time value, or the corresponding strings for the current locale 82 | 83 | %P 84 | like %p, but lower case 85 | 86 | %r 87 | time in a.m. and p.m. notation equal to %I:%M:%S %p 88 | 89 | %R 90 | time in 24 hour notation equal to %H:%M 91 | 92 | %s 93 | number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC 94 | 95 | %S 96 | second as a decimal number 97 | 98 | %t 99 | tab character 100 | 101 | %T 102 | current time, equal to %H:%M:%S 103 | 104 | %u 105 | weekday as a decimal number [1,7], with 1 representing Monday 106 | 107 | %w 108 | day of the week as a decimal, Sunday being 0 109 | 110 | %x 111 | preferred date representation for the current locale without the time 112 | 113 | %X 114 | preferred time representation for the current locale without the date 115 | 116 | %y 117 | year as a decimal number without a century (range 00 to 99) 118 | 119 | %Y 120 | year as a decimal number including the century 121 | 122 | %z 123 | numerical time zone representation 124 | 125 | %% 126 | a literal `%' character 127 | 128 | HOW CAN I ADD MY OWN LOCALE? 129 | ---------------------------- 130 | 131 | You can add your locale by following: 132 | 133 | Date.prototype.strftime.locales['de'] = { 134 | B: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], 135 | b: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], 136 | A: ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"], 137 | a: ["Mo\.", "Di\.", "Mi\.", "Do\.", "Fr\.", "Sa\.", "So\."] 138 | }; 139 | 140 | HOW CAN I SET MY OWN LOCALE AS DEFAULT? 141 | --------------------------------------- 142 | 143 | You can call following method: 144 | 145 | Date.prototype.strftime.setDefaultLocale('ja'); 146 | 147 | LICENSE 148 | ------ 149 | 150 | It's based on Daniel Rench's Date.prototype.strftime library in http://dren.ch/strftime/. 151 | He releases original version in Public Domain. I also release this modificated code in Public Domain. 152 | 153 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/.idea/.name: -------------------------------------------------------------------------------- 1 | qunit-tap -------------------------------------------------------------------------------- /node_modules/qunit-tap/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | http://www.w3.org/1999/xhtml 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/.idea/qunit-tap.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 39 | 40 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 82 | 83 | 86 | 87 | 88 | 89 | 92 | 93 | 96 | 97 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 130 | 131 | 132 | 133 | 1322212312296 134 | 1322212312296 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 172 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/.npmignore: -------------------------------------------------------------------------------- 1 | .git* 2 | test/ 3 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/GPL-LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, 2011 Takuto Wada, http://github.com/twada/qunit-tap/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/README.md: -------------------------------------------------------------------------------- 1 | QUnit-TAP - a TAP Output Producer Plugin for QUnit 2 | ================================ 3 | 4 | 5 | *NEWS (2011/03/25)* Usage has changed. Please see USAGE section. 6 | 7 | 8 | DESCRIPTION 9 | --------------------------------------- 10 | QUnit-TAP is a simple plugin for [QUnit](http://docs.jquery.com/QUnit) to produce [TAP](http://testanything.org/) output, to run tests on CLI. 11 | 12 | With QUnit-TAP you can test your QUnit test scripts on your terminal, and you can use TAP Consumers like [prove](http://perldoc.perl.org/prove.html) for test automation. 13 | 14 | QUnit-TAP runs under headless browsers like [phantomjs](http://code.google.com/p/phantomjs/), command-line js environments (like [SpiderMonkey](https://developer.mozilla.org/en/SpiderMonkey) or [Rhino](https://developer.mozilla.org/en/Rhino)), and [CommonJS](http://commonjs.org/) environments (like [node.js](http://nodejs.org/) or [narwhal](http://narwhaljs.org/)), and of cource, runs under real browser too. 15 | 16 | 17 | DOWNLOAD 18 | --------------------------------------- 19 | * Just download [qunit-tap.js](http://github.com/twada/qunit-tap/raw/master/lib/qunit-tap.js) 20 | * or download archive from [qunit-tap archives](http://github.com/twada/qunit-tap/downloads) 21 | * or `git clone git://github.com/twada/qunit-tap.git` 22 | * or `npm install qunit-tap` if you use npm. 23 | 24 | You can use QUnit-TAP, 25 | 26 | * as a single file, copy lib/qunit-tap.js to anywhere you like. 27 | * as git submodule. 28 | * as a node.js package (via npm). 29 | 30 | 31 | USAGE 32 | --------------------------------------- 33 | Three steps to use QUnit-TAP. 34 | 35 | 1. load/require qunit.js 36 | 2. load/require qunit-tap.js 37 | 3. Call `qunitTap` function with two or three arguments. The first argument is QUnit reference, the second is print-like function for TAP output. And the third argument is object to customize default behavior. (Note that the first and second argument is mandatory, and the third argument is optional.) 38 | 39 | ### usage example 1 : embed QUnit-TAP in your HTML (e.g. to run with PhantomJS) 40 | 41 | 42 | 45 | 46 | 47 | 48 | ### usage example 2 : use QUnit-TAP with Rhino/SpiderMonkey 49 | load("path/to/qunit.js"); 50 | load("path/to/qunit-tap.js"); 51 | 52 | // enable TAP output 53 | qunitTap(QUnit, print); //NOTE: 'print' is Rhino/SpiderMonkey's built-in function 54 | 55 | // or customize default behavior 56 | // qunitTap(QUnit, print, {noPlan: true, showDetailsOnFailure: false}); 57 | 58 | // configure QUnit to run under non-browser env. 59 | QUnit.init(); 60 | QUnit.config.updateRate = 0; 61 | 62 | load("path/to/your_test.js"); 63 | load("path/to/your_test2.js"); 64 | 65 | QUnit.start(); 66 | 67 | 68 | CONFIGURATION OPTIONS 69 | --------------------------------------- 70 | `qunitTap` function takes third optional argument as options object to customize default behavior. Customization props are, 71 | 72 | * noPlan : If true, print test plan line at the bottom after all the test points have run. Inspired by Perl's "no_plan" feature. Default is false. 73 | * showDetailsOnFailure : If true, show 'expected' and 'actual' on failure output. Default is true. 74 | 75 | 76 | TAP OUTPUT EXAMPLE 77 | --------------------------------------- 78 | 1..16 79 | # module: math module 80 | # test: add 81 | ok 1 82 | ok 2 83 | ok 3 - passing 3 args 84 | ok 4 - just one arg 85 | ok 5 - no args 86 | not ok 6 - expected: 7 result: 1 87 | not ok 7 - with message, expected: 7 result: 1 88 | ok 8 89 | ok 9 - with message 90 | not ok 10 91 | not ok 11 - with message 92 | # module: incr module 93 | # test: increment 94 | ok 12 95 | ok 13 96 | # module: TAP spec compliance 97 | # test: Diagnostic lines 98 | ok 14 - with\r 99 | # multiline 100 | # message 101 | not ok 15 - with\r 102 | # multiline 103 | # message, expected: foo\r 104 | # bar result: foo 105 | # bar 106 | not ok 16 - with\r 107 | # multiline 108 | # message, expected: foo 109 | # bar result: foo\r 110 | # bar 111 | 112 | 113 | RUNNING EXAMPLES 114 | --------------------------------------- 115 | ### prepare 116 | $ git clone git://github.com/twada/qunit-tap.git 117 | $ cd qunit-tap 118 | $ git submodule update --init 119 | 120 | 121 | ### to run with PhantomJS 122 | 123 | # assume you have built and installed phantomjs 124 | $ cd sample/js/ 125 | $ ./phantomjs_test.sh 126 | 127 | # with prove 128 | $ prove phantomjs_test.sh 129 | 130 | for details, see [phantomjs_test.sh](http://github.com/twada/qunit-tap/tree/master/sample/js/phantomjs_test.sh) 131 | 132 | 133 | ### to run with Rhino/SpiderMonkey 134 | 135 | # assume you are using rhino 136 | $ cd sample/js/ 137 | $ rhino run_tests.js 138 | 139 | for details, see [sample/js/](http://github.com/twada/qunit-tap/tree/master/sample/js/) 140 | 141 | 142 | ### to run under CommonJS environment 143 | 144 | # assume you are using node.js 145 | $ cd sample/commonjs/ 146 | $ node test/math_test.js 147 | $ node test/incr_test.js 148 | 149 | # with prove 150 | $ prove --exec=/usr/local/bin/node test/*.js 151 | 152 | for details, see [sample/commonjs/](http://github.com/twada/qunit-tap/tree/master/sample/commonjs/) 153 | 154 | 155 | ### to use both under standard js and CommonJS environments 156 | 157 | # assume you are using node.js and rhino 158 | $ cd sample/interop/ 159 | $ rhino run_tests.js 160 | $ node test/math_test.js 161 | $ node test/incr_test.js 162 | 163 | # with prove 164 | $ prove --exec=/usr/bin/rhino run_tests.js 165 | $ prove --exec=/usr/local/bin/node test/*.js 166 | 167 | for details, see [sample/interop/](http://github.com/twada/qunit-tap/tree/master/sample/interop/) 168 | 169 | 170 | 171 | TESTED ENVIRONMENTS 172 | --------------------------------------- 173 | * [phantomjs](http://code.google.com/p/phantomjs/) 174 | * [SpiderMonkey](https://developer.mozilla.org/en/SpiderMonkey) 175 | * [Rhino](https://developer.mozilla.org/en/Rhino) 176 | * [node.js](http://nodejs.org/) 177 | * [narwhal](http://narwhaljs.org/) 178 | 179 | 180 | AUTHOR 181 | --------------------------------------- 182 | Takuto Wada (takuto.wada at gmail dot com) 183 | 184 | 185 | CONTRIBUTORS 186 | --------------------------------------- 187 | * Nikita Vasilyev (http://github.com/NV) 188 | * Hiroki Kondo (http://github.com/kompiro) 189 | * Keiji Yoshimi (http://github.com/walf443) 190 | 191 | 192 | LICENSE 193 | --------------------------------------- 194 | Dual licensed under the MIT and GPLv2 licenses. 195 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/lib/qunit-tap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * QUnit-TAP - A TAP Output Producer Plugin for QUnit 3 | * 4 | * http://github.com/twada/qunit-tap 5 | * version: 1.0.5 6 | * 7 | * Copyright (c) 2010, 2011 Takuto Wada 8 | * Dual licensed under the MIT (MIT-LICENSE.txt) 9 | * and GPLv2 (GPL-LICENSE.txt) licenses. 10 | * 11 | * @param qunitObject QUnit object reference. 12 | * @param printLikeFunction print-like function for TAP output (assumes line-separator is added by this function for each call). 13 | * @param options configuration options to customize default behavior. 14 | */ 15 | var qunitTap = function qunitTap(qunitObject, printLikeFunction, options) { 16 | var qunitTapVersion = "1.0.5", 17 | initialCount, 18 | multipleLoggingCallbacksSupported, 19 | qu = qunitObject; 20 | 21 | if (typeof qu === 'undefined') { 22 | throw new Error('should pass QUnit object reference'); 23 | } 24 | if (typeof printLikeFunction !== 'function') { 25 | throw new Error('should pass print-like function'); 26 | } 27 | if (typeof qu.tap !== 'undefined') { 28 | return; 29 | } 30 | 31 | // borrowed from qunit.js 32 | var extend = function(a, b) { 33 | var prop; 34 | for (prop in b) { 35 | if (b[prop] === undefined) { 36 | delete a[prop]; 37 | } else { 38 | a[prop] = b[prop]; 39 | } 40 | } 41 | return a; 42 | }; 43 | 44 | // using QUnit.tap as namespace. 45 | qu.tap = extend({ 46 | count: 0, 47 | noPlan: false, 48 | showDetailsOnFailure: true 49 | }, options); 50 | qu.tap.puts = printLikeFunction; 51 | qu.tap.VERSION = qunitTapVersion; 52 | initialCount = qu.tap.count || 0; 53 | 54 | // detect QUnit's multipleCallbacks feature. see jquery/qunit@34f6bc1 55 | multipleLoggingCallbacksSupported = 56 | (typeof qu.config !== 'undefined' 57 | && typeof qu.config.log !== 'undefined' 58 | && typeof qu.config.done !== 'undefined' 59 | && typeof qu.config.moduleStart !== 'undefined' 60 | && typeof qu.config.testStart !== 'undefined'); 61 | 62 | // borrowed from prototype.js 63 | // not required since QUnit.log receives raw data (details). see jquery/qunit@c2cde34 64 | var stripTags = function(str) { 65 | if (!str) return str; 66 | return str.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); 67 | }; 68 | 69 | var commentAfterLineEnd = function(str) { 70 | return str.replace(/(\r?\n)/g, '$&# '); 71 | }; 72 | 73 | var formDescription = function(str) { 74 | if (!str) return str; 75 | return commentAfterLineEnd(' - ' + str); 76 | }; 77 | 78 | var appendDetailsTo = function(desc, details) { 79 | if (!qu.tap.showDetailsOnFailure || details.result) { 80 | return desc; 81 | } 82 | if (typeof details.expected !== 'undefined') { 83 | if (desc) desc += ', '; 84 | desc += 'expected: '; 85 | desc += details.expected; 86 | desc += ' result: '; 87 | desc += details.actual; 88 | } 89 | return desc; 90 | }; 91 | 92 | qu.tap.moduleStart = function(arg) { 93 | var name = (typeof arg === 'string') ? arg : arg.name; 94 | qu.tap.puts('# module: ' + name); 95 | }; 96 | 97 | qu.tap.testStart = function(arg) { 98 | var name = (typeof arg === 'string') ? arg : arg.name; 99 | qu.tap.puts('# test: ' + name); 100 | }; 101 | 102 | qu.tap.diag = function(str) { 103 | qu.tap.puts(commentAfterLineEnd('# ' + str)); 104 | }; 105 | 106 | qu.tap.log = function() { 107 | var details, testLine, desc; 108 | switch (arguments.length) { 109 | case 1: // details 110 | details = arguments[0]; 111 | break; 112 | case 2: // result, message(with tags) 113 | details = {result: arguments[0], message: stripTags(arguments[1])}; 114 | break; 115 | case 3: // result, message, details 116 | details = arguments[2]; 117 | break; 118 | } 119 | testLine = (details.result ? 'ok' : 'not ok') + 120 | ' ' + (qu.tap.count += 1); 121 | if (details.result && !details.message) { 122 | qu.tap.puts(testLine); 123 | return; 124 | } 125 | desc = appendDetailsTo((details.message || ''), details); 126 | qu.tap.puts(testLine + formDescription(desc)); 127 | }; 128 | 129 | // prop in arg: failed,passed,total,runtime 130 | qu.tap.done = function(arg) { 131 | if (! qu.tap.noPlan) { 132 | return; 133 | } 134 | qu.tap.puts((initialCount + 1) + '..' + qu.tap.count); 135 | }; 136 | 137 | var addListener = function(target, name, listener) { 138 | var originalLoggingCallback = target[name]; 139 | if (multipleLoggingCallbacksSupported) { 140 | originalLoggingCallback(listener); 141 | } else if (typeof originalLoggingCallback === 'function') { 142 | // add listener, not replacing former ones. 143 | target[name] = function() { 144 | var args = Array.prototype.slice.apply(arguments); 145 | originalLoggingCallback.apply(target, args); 146 | listener.apply(target, args); 147 | }; 148 | } 149 | }; 150 | addListener(qu, 'moduleStart', qu.tap.moduleStart); 151 | addListener(qu, 'testStart', qu.tap.testStart); 152 | addListener(qu, 'log', qu.tap.log); 153 | addListener(qu, 'done', qu.tap.done); 154 | }; 155 | 156 | if (typeof exports !== 'undefined' || typeof require !== 'undefined') { 157 | // exports qunitTap function to CommonJS world 158 | exports.qunitTap = qunitTap; 159 | } 160 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qunit-tap", 3 | "description": "A TAP Output Producer Plugin for QUnit", 4 | "version": "1.0.5", 5 | "keywords": ["TDD", "QUnit", "test", "tests", "testing", "TAP"], 6 | "homepage": "http://github.com/twada/qunit-tap", 7 | "author": { 8 | "name": "Takuto Wada", 9 | "email": "takuto.wada@gmail.com", 10 | "url": "http://github.com/twada" 11 | }, 12 | "contributors": [ 13 | { 14 | "name": "Nikita Vasilyev", 15 | "url": "http://elv1s.ru/" 16 | }, 17 | { 18 | "name": "Hiroki Kondo", 19 | "url": "http://github.com/kompiro/" 20 | }, 21 | { 22 | "name": "Keiji Yoshimi", 23 | "url": "http://github.com/walf443/" 24 | } 25 | ], 26 | "main": "./lib/qunit-tap", 27 | "directories": { 28 | "lib": "./lib", 29 | "example": "./sample" 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "http://github.com/twada/qunit-tap.git" 34 | }, 35 | "engines": [ 36 | "node >=0.1.96", 37 | "narwhal >=0.2.2", 38 | "spidermonkey", 39 | "rhino", 40 | "phantomjs" 41 | ], 42 | "licenses": [ 43 | { 44 | "type": "MIT", 45 | "url": "http://www.opensource.org/licenses/mit-license.php" 46 | }, 47 | { 48 | "type": "GPL", 49 | "url": "http://www.opensource.org/licenses/gpl-2.0.php" 50 | } 51 | ], 52 | "bugs": { 53 | "url" : "http://github.com/twada/qunit-tap/issues" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/commonjs/lib/incr.js: -------------------------------------------------------------------------------- 1 | var add = require('./math').add; 2 | exports.increment = function(val) { 3 | return add(val, 1); 4 | }; 5 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/commonjs/lib/math.js: -------------------------------------------------------------------------------- 1 | exports.add = function() { 2 | var sum = 0, i = 0, args = arguments, l = args.length; 3 | while (i < l) { 4 | sum += args[i++]; 5 | } 6 | return sum; 7 | }; 8 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/commonjs/test/incr_test.js: -------------------------------------------------------------------------------- 1 | require("../test_helper"); 2 | inc = require("../lib/incr").increment; 3 | 4 | QUnit.module("incr module"); 5 | 6 | QUnit.test('increment' , function() { 7 | assert.equal(inc(1), 2); 8 | assert.equal(inc(-3), -2); 9 | }); 10 | 11 | QUnit.start(); 12 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/commonjs/test/math_test.js: -------------------------------------------------------------------------------- 1 | require("../test_helper"); 2 | math = require("../lib/math"); 3 | 4 | QUnit.module("math module"); 5 | 6 | QUnit.test('add' , function() { 7 | var add = math.add; 8 | assert.equal(add(1, 4), 5); 9 | assert.equal(add(-3, 2), -1); 10 | assert.equal(add(1, 3, 4), 8, 'passing 3 args'); 11 | assert.equal(add(2), 2, 'just one arg'); 12 | assert.equal(add(), 0, 'no args'); 13 | 14 | assert.equal(add(-3, 4), 7); 15 | assert.equal(add(-3, 4), 7, 'with message'); 16 | 17 | assert.ok(true); 18 | assert.ok(true, 'with message'); 19 | assert.ok(false); 20 | assert.ok(false, 'with message'); 21 | }); 22 | 23 | QUnit.start(); 24 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/commonjs/test/tap_compliance_test.js: -------------------------------------------------------------------------------- 1 | require("../test_helper"); 2 | 3 | QUnit.module("TAP spec compliance"); 4 | 5 | QUnit.test('Diagnostic lines' , function() { 6 | assert.ok(true, "with\r\nmultiline\nmessage"); 7 | assert.equal("foo\nbar", "foo\r\nbar", "with\r\nmultiline\nmessage"); 8 | assert.equal("foo\r\nbar", "foo\nbar", "with\r\nmultiline\nmessage"); 9 | }); 10 | 11 | QUnit.start(); 12 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/commonjs/test_helper.js: -------------------------------------------------------------------------------- 1 | exports = module.exports = global; 2 | 3 | var tryRequireThese = function() { 4 | var args = Array.prototype.slice.apply(arguments); 5 | for(var i=0; i < args.length; i+=1) { 6 | try { 7 | return require(args[i]); 8 | } catch(e) { 9 | // ignore 10 | } 11 | } 12 | throw new Error("cannot find moduele: " + args); 13 | }; 14 | 15 | QUnit = require("../../vendor/qunit/qunit/qunit").QUnit; 16 | var qunitTap = require("../../lib/qunit-tap").qunitTap; 17 | 18 | var sys = tryRequireThese("sys", "system"); 19 | for (var i in sys) exports[i] = sys[i]; 20 | puts = (typeof sys.puts === 'function') ? sys.puts : sys.print; 21 | 22 | qunitTap(QUnit, puts, {noPlan: true}); 23 | 24 | QUnit.init(); 25 | QUnit.config.updateRate = 0; 26 | 27 | exports.assert = QUnit; 28 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/interop/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Test Suite 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |

QUnit Test Suite

24 |

25 |
26 |

27 |
    28 | 29 | 30 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/interop/lib/incr.js: -------------------------------------------------------------------------------- 1 | (function(ns) { 2 | var math; 3 | if ( typeof exports !== "undefined" || typeof require !== "undefined" ) { 4 | math = require('./math'); 5 | } else { 6 | math = ns; 7 | } 8 | 9 | ns.increment = function(val) { 10 | return math.add(val, 1); 11 | }; 12 | })((typeof(exports) !== "undefined") ? exports : (this.xx || this)); 13 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/interop/lib/math.js: -------------------------------------------------------------------------------- 1 | (function(ns) { 2 | ns.add = function() { 3 | var sum = 0, i = 0, args = arguments, l = args.length; 4 | while (i < l) { 5 | sum += args[i++]; 6 | } 7 | return sum; 8 | }; 9 | })((typeof(exports) !== "undefined") ? exports : (this.xx || this)); 10 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/interop/lib/namespaces.js: -------------------------------------------------------------------------------- 1 | if (typeof xx === 'undefined') { xx = {}; } 2 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/interop/phantomjs_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | URL=file://$PWD/index.html 3 | phantomjs run_qunit.js $URL 4 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/interop/run_qunit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Wait until the test condition is true or a timeout occurs. Useful for waiting 3 | * on a server response or for a ui change (fadeIn, etc.) to occur. 4 | * 5 | * @param testFx javascript condition that evaluates to a boolean, 6 | * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or 7 | * as a callback function. 8 | * @param onReady what to do when testFx condition is fulfilled, 9 | * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or 10 | * as a callback function. 11 | * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used. 12 | */ 13 | function waitFor(testFx, onReady, timeOutMillis) { 14 | var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3001, //< Default Max Timout is 3s 15 | start = new Date().getTime(), 16 | condition = false, 17 | interval = setInterval(function() { 18 | if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) { 19 | // If not time-out yet and condition not yet fulfilled 20 | condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code 21 | } else { 22 | if(!condition) { 23 | // If condition still not fulfilled (timeout but condition is 'false') 24 | console.log("# 'waitFor()' timeout"); 25 | phantom.exit(1); 26 | } else { 27 | // Condition fulfilled (timeout and/or condition is 'true') 28 | // console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms."); 29 | typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled 30 | clearInterval(interval); //< Stop this interval 31 | } 32 | } 33 | }, 100); //< repeat check every 250ms 34 | }; 35 | 36 | 37 | if (phantom.args.length === 0 || phantom.args.length > 2) { 38 | console.log('Usage: run-qunit.js URL'); 39 | phantom.exit(1); 40 | } 41 | 42 | var page = new WebPage(); 43 | 44 | // Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this") 45 | page.onConsoleMessage = function(msg) { 46 | console.log(msg); 47 | }; 48 | 49 | page.open(phantom.args[0], function(status){ 50 | if (status !== "success") { 51 | console.log("Unable to access network"); 52 | phantom.exit(1); 53 | } else { 54 | waitFor(function(){ 55 | return page.evaluate(function(){ 56 | var el = document.getElementById('qunit-testresult'); 57 | if (el && el.innerText.match('completed')) { 58 | return true; 59 | } 60 | return false; 61 | }); 62 | }, function(){ 63 | var failedNum = page.evaluate(function(){ 64 | var el = document.getElementById('qunit-testresult'); 65 | // console.log(el.innerText); 66 | try { 67 | return el.getElementsByClassName('failed')[0].innerHTML; 68 | } catch (e) { } 69 | return 10000; 70 | }); 71 | phantom.exit((parseInt(failedNum, 10) > 0) ? 1 : 0); 72 | }); 73 | } 74 | }); 75 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/interop/run_tests.js: -------------------------------------------------------------------------------- 1 | load("./lib/namespaces.js"); 2 | load("./lib/math.js"); 3 | load("./lib/incr.js"); 4 | 5 | load("../../vendor/qunit/qunit/qunit.js"); 6 | load("../../lib/qunit-tap.js"); 7 | 8 | qunitTap(QUnit, print, {noPlan: true}); 9 | 10 | QUnit.init(); 11 | QUnit.config.updateRate = 0; 12 | 13 | load("./test/math_test.js"); 14 | load("./test/incr_test.js"); 15 | load("./test/tap_compliance_test.js"); 16 | 17 | QUnit.start(); 18 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/interop/test/incr_test.js: -------------------------------------------------------------------------------- 1 | if ( typeof exports !== "undefined" || typeof require !== "undefined" ) { 2 | require("../test_helper"); 3 | xx = require("../lib/incr"); 4 | equal = assert.equal; 5 | } 6 | 7 | QUnit.module("incr module"); 8 | 9 | QUnit.test('increment' , function() { 10 | var inc = xx.increment; 11 | equal(inc(1), 2); 12 | equal(inc(-3), -2); 13 | }); 14 | 15 | if ( typeof exports !== "undefined" || typeof require !== "undefined" ) { 16 | QUnit.start(); 17 | } 18 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/interop/test/math_test.js: -------------------------------------------------------------------------------- 1 | if ( typeof exports !== "undefined" || typeof require !== "undefined" ) { 2 | require("../test_helper"); 3 | xx = require("../lib/math"); 4 | equal = assert.equal; 5 | ok = assert.ok; 6 | } 7 | 8 | QUnit.module("math module"); 9 | 10 | QUnit.test('add' , function() { 11 | var add = xx.add; 12 | equal(add(1, 4), 5); 13 | equal(add(-3, 2), -1); 14 | equal(add(1, 3, 4), 8, 'passing 3 args'); 15 | equal(add(2), 2, 'just one arg'); 16 | equal(add(), 0, 'no args'); 17 | 18 | equal(add(-3, 4), 7); 19 | equal(add(-3, 4), 7, 'with message'); 20 | 21 | ok(true); 22 | ok(true, 'with message'); 23 | ok(false); 24 | ok(false, 'with message'); 25 | }); 26 | 27 | if ( typeof exports !== "undefined" || typeof require !== "undefined" ) { 28 | QUnit.start(); 29 | } 30 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/interop/test/tap_compliance_test.js: -------------------------------------------------------------------------------- 1 | if ( typeof exports !== "undefined" || typeof require !== "undefined" ) { 2 | require("../test_helper"); 3 | equal = assert.equal; 4 | ok = assert.ok; 5 | } 6 | 7 | QUnit.module("TAP spec compliance"); 8 | 9 | QUnit.test('Diagnostic lines' , function() { 10 | ok(true, "with\r\nmultiline\nmessage"); 11 | equal("foo\nbar", "foo\r\nbar", "with\r\nmultiline\nmessage"); 12 | equal("foo\r\nbar", "foo\nbar", "with\r\nmultiline\nmessage"); 13 | }); 14 | 15 | if ( typeof exports !== "undefined" || typeof require !== "undefined" ) { 16 | QUnit.start(); 17 | } 18 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/interop/test_helper.js: -------------------------------------------------------------------------------- 1 | exports = module.exports = global; 2 | 3 | var tryRequireThese = function() { 4 | var args = Array.prototype.slice.apply(arguments); 5 | for(var i=0; i < args.length; i+=1) { 6 | try { 7 | return require(args[i]); 8 | } catch(e) { 9 | // ignore 10 | } 11 | } 12 | throw new Error("cannot find moduele: " + args); 13 | }; 14 | 15 | QUnit = require("../../vendor/qunit/qunit/qunit").QUnit; 16 | var qunitTap = require("../../lib/qunit-tap").qunitTap; 17 | 18 | var sys = tryRequireThese("sys", "system"); 19 | for (var i in sys) exports[i] = sys[i]; 20 | puts = (typeof sys.puts === 'function') ? sys.puts : sys.print; 21 | 22 | qunitTap(QUnit, puts, {noPlan: true}); 23 | 24 | QUnit.init(); 25 | QUnit.config.updateRate = 0; 26 | 27 | exports.assert = QUnit; 28 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/js/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Test Suite 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |

    QUnit Test Suite

    23 |

    24 |
    25 |

    26 |
      27 | 28 | 29 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/js/lib/incr.js: -------------------------------------------------------------------------------- 1 | if (typeof incr === 'undefined') { incr = {}; } 2 | 3 | incr.increment = function(val) { 4 | var add = math.add; 5 | return add(val, 1); 6 | }; 7 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/js/lib/math.js: -------------------------------------------------------------------------------- 1 | if (typeof math === 'undefined') { math = {}; } 2 | 3 | math.add = function() { 4 | var sum = 0, i = 0, args = arguments, l = args.length; 5 | while (i < l) { 6 | sum += args[i++]; 7 | } 8 | return sum; 9 | }; 10 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/js/phantomjs_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | URL=file://$PWD/index.html 3 | phantomjs run_qunit.js $URL 4 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/js/run_qunit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Wait until the test condition is true or a timeout occurs. Useful for waiting 3 | * on a server response or for a ui change (fadeIn, etc.) to occur. 4 | * 5 | * @param testFx javascript condition that evaluates to a boolean, 6 | * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or 7 | * as a callback function. 8 | * @param onReady what to do when testFx condition is fulfilled, 9 | * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or 10 | * as a callback function. 11 | * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used. 12 | */ 13 | function waitFor(testFx, onReady, timeOutMillis) { 14 | var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3001, //< Default Max Timout is 3s 15 | start = new Date().getTime(), 16 | condition = false, 17 | interval = setInterval(function() { 18 | if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) { 19 | // If not time-out yet and condition not yet fulfilled 20 | condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code 21 | } else { 22 | if(!condition) { 23 | // If condition still not fulfilled (timeout but condition is 'false') 24 | console.log("# 'waitFor()' timeout"); 25 | phantom.exit(1); 26 | } else { 27 | // Condition fulfilled (timeout and/or condition is 'true') 28 | // console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms."); 29 | typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled 30 | clearInterval(interval); //< Stop this interval 31 | } 32 | } 33 | }, 100); //< repeat check every 250ms 34 | }; 35 | 36 | 37 | if (phantom.args.length === 0 || phantom.args.length > 2) { 38 | console.log('Usage: run-qunit.js URL'); 39 | phantom.exit(1); 40 | } 41 | 42 | var page = new WebPage(); 43 | 44 | // Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this") 45 | page.onConsoleMessage = function(msg) { 46 | console.log(msg); 47 | }; 48 | 49 | page.open(phantom.args[0], function(status){ 50 | if (status !== "success") { 51 | console.log("Unable to access network"); 52 | phantom.exit(1); 53 | } else { 54 | waitFor(function(){ 55 | return page.evaluate(function(){ 56 | var el = document.getElementById('qunit-testresult'); 57 | if (el && el.innerText.match('completed')) { 58 | return true; 59 | } 60 | return false; 61 | }); 62 | }, function(){ 63 | var failedNum = page.evaluate(function(){ 64 | var el = document.getElementById('qunit-testresult'); 65 | // console.log(el.innerText); 66 | try { 67 | return el.getElementsByClassName('failed')[0].innerHTML; 68 | } catch (e) { } 69 | return 10000; 70 | }); 71 | phantom.exit((parseInt(failedNum, 10) > 0) ? 1 : 0); 72 | }); 73 | } 74 | }); 75 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/js/run_tests.js: -------------------------------------------------------------------------------- 1 | load("./lib/math.js"); 2 | load("./lib/incr.js"); 3 | 4 | load("../../vendor/qunit/qunit/qunit.js"); 5 | load("../../lib/qunit-tap.js"); 6 | 7 | qunitTap(QUnit, print, {noPlan: true}); 8 | 9 | QUnit.init(); 10 | QUnit.config.updateRate = 0; 11 | 12 | load("./test/math_test.js"); 13 | load("./test/incr_test.js"); 14 | load("./test/tap_compliance_test.js"); 15 | 16 | QUnit.start(); 17 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/js/test/incr_test.js: -------------------------------------------------------------------------------- 1 | module("incr module"); 2 | 3 | test('increment' , function() { 4 | var inc = incr.increment; 5 | equal(inc(1), 2); 6 | equal(inc(-3), -2); 7 | }); 8 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/js/test/math_test.js: -------------------------------------------------------------------------------- 1 | module("math module"); 2 | 3 | test('add' , function() { 4 | var add = math.add; 5 | equal(add(1, 4), 5); 6 | equal(add(-3, 2), -1); 7 | equal(add(1, 3, 4), 8, 'passing 3 args'); 8 | equal(add(2), 2, 'just one arg'); 9 | equal(add(), 0, 'no args'); 10 | 11 | equal(add(-3, 4), 7); 12 | equal(add(-3, 4), 7, 'with message'); 13 | 14 | ok(true); 15 | ok(true, 'with message'); 16 | ok(false); 17 | ok(false, 'with message'); 18 | }); 19 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/sample/js/test/tap_compliance_test.js: -------------------------------------------------------------------------------- 1 | module("TAP spec compliance"); 2 | 3 | test('Diagnostic lines' , function() { 4 | ok(true, "with\r\nmultiline\nmessage"); 5 | equal("foo\nbar", "foo\r\nbar", "with\r\nmultiline\nmessage"); 6 | equal("foo\r\nbar", "foo\nbar", "with\r\nmultiline\nmessage"); 7 | }); 8 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | *~ 3 | *.diff 4 | *.patch 5 | .DS_Store 6 | .settings 7 | 8 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/History.md: -------------------------------------------------------------------------------- 1 | 2 | 1.2.0 / 2011-11-24 3 | ================== 4 | 5 | * remove uses of equals(), as it's deprecated in favor of equal() 6 | * Code review of "Allow objects with no prototype to be tested against object literals." 7 | * Allow objects with no prototype to tested against object literals. 8 | * Fix IE8 "Member not found" error 9 | * Using node-qunit port, the start/stop function are not exposed so we need to prefix any call to them with 'QUnit'. Aka: start() -> QUnit.start() 10 | * Remove the 'let teardown clean up globals test' - IE<9 doesn't support (==buggy) deleting window properties, and that's not worth the trouble, as everything else passes just fine. Fixes #155 11 | * Fix globals in test.js, part 2 12 | * Fix globals in test.js. ?tell wwalser to use ?noglobals everyonce in a while 13 | * Extend readme regarding release process 14 | 15 | 1.1.0 / 2011-10-11 16 | ================== 17 | 18 | * Fixes #134 - Add a window.onerror handler. Makes uncaught errors actually fail the testsuite, instead of going by unnoticed. 19 | * Whitespace cleanup 20 | * Merge remote branch 'trevorparscal/master' 21 | * Fixed IE compatibility issues with using toString on NodeList objects, which in some browsers results in [object Object] rather than [object NodeList]. Now using duck typing for NodeList objects based on the presence of length, length being a number, presence of item method (which will be typeof string in IE and function in others, so we just check that it's not undefined) and that item(0) returns the same value as [0], unless it's empty, in which case item(0) will return 0, while [0] would return undefined. Tested in IE6, IE8, Firefox 6, Safari 5 and Chrome 16. 22 | * Update readme with basic notes on releases 23 | * More whitespace/parens cleanup 24 | * Check if setTimeout is available before trying to delay running the next task. Fixes #160 25 | * Whitespace/formatting fix, remove unnecessary parens 26 | * Use alias for Object.prototype.toString 27 | * Merge remote branch 'trevorparscal/master' 28 | * Merge remote branch 'wwalser/recursionBug' 29 | * Default 'expected' to null in asyncTest(), same as in test() itself. 30 | * Whitespace cleanup 31 | * Merge remote branch 'mmchaney/master' 32 | * Merge remote branch 'Krinkle/master' 33 | * Using === instead of == 34 | * Added more strict array type detection for dump output, and allowed NodeList objects to be output as arrays 35 | * Bump post-release version 36 | * Fixes a bug where after an async test, assertions could move between test cases because of internal state (config.current) being incorrectly set 37 | * Simplified check for assertion count and adjusted whitespace 38 | * Redo of fixing issue #156 (Support Object.prototype extending environment). * QUnit.diff: Throws exception without this if Object.prototype is set (Property 'length' of undefined. Since Object.prototype.foo doesn't have a property 'rows') * QUnit.url: Without this fix, if Object.prototype.foo is set, the url will be set to ?foo=...&the=rest. * saveGlobals: Without this fix, whenever a member is added to Object.prototype, saveGlobals will think it was a global variable in this loop. --- This time using the call method instead of obj.hasOwnProperty(key), which may fail if the object has that as it's own property (touché!). 39 | * Handle expect(0) as expected, i.e. expect(0); ok(true, foo); will cause a test to fail 40 | 41 | 1.0.0 / 2011-10-06 42 | ================== 43 | 44 | * Make QUnit work with TestSwarm 45 | * Run other addons tests as composite addon demo. Need to move that to /test folder once this setup actually works 46 | * Add-on: New assertion-type: step() 47 | * added parameter to start and stop allowing a user to increment/decrement the semaphore more than once per call 48 | * Update readmes with .md extension for GitHub to render them as markdown 49 | * Update close-enough addon to include readme and match (new) naming convetions 50 | * Merge remote branch 'righi/close-enough-addon' 51 | * Canvas addon: Update file referneces 52 | * Update canvas addon: Rename files and add README 53 | * Merge remote branch 'wwalser/composite' 54 | * Fix #142 - Backslash characters in messages should not be escaped 55 | * Add module name to testStart and testDone callbacks 56 | * Removed extra columns in object literals. Closes #153 57 | * Remove dead links in comments. 58 | * Merge remote branch 'wwalser/multipleCallbacks' 59 | * Fixed syntax error and CommonJS incompatibilities in package.json 60 | * Allow multiple callbacks to be registered. 61 | * Add placeholder for when Safari may end up providing useful error handling 62 | * changed file names to match addon naming convention 63 | * Whitespace 64 | * Created the composite addon. 65 | * Using array and object literals. 66 | * Issue #140: Make toggle system configurable. 67 | * Merge remote branch 'tweetdeck/master' 68 | * Adds the 'close enough' addon to determine if numbers are acceptably close enough in value. 69 | * Fix recursion support in jsDump, along with tests. Fixes #63 and #100 70 | * Adding a QUnit.config.altertitle flag which will allow users to opt-out of the functionality introduced in 60147ca0164e3d810b8a9bf46981c3d9cc569efc 71 | * Refactor window.load handler into QUnit.load, makes it possible to call it manually. 72 | * More whitespace cleanup 73 | * Merge remote branch 'erikvold/one-chk-in-title' 74 | * Whitespace 75 | * Merge remote branch 'wwalser/syncStopCalls' 76 | * Introducing the first QUnit addon, based on https://github.com/jquery/qunit/pull/84 - adds QUnit.pixelEqual assertion method, along with example tests. 77 | * Remove config.hidepassed setting in test.js, wasn't intended to land in master. 78 | * Expose QUnit.config.hidepassed setting. Overrides sessionStorage and enables enabling the feature programmatically. Fixes #133 79 | * Fix formatting (css whitespace) for tracebacks. 80 | * Expose extend, id, and addEvent methods. 81 | * minor comment typo correction 82 | * Ignore Eclipse WTP .settings 83 | * Set 'The jQuery Project' as author in package.json 84 | * Fixes a bug where synchronous calls to stop would cause tests to end before start was called again 85 | * Point to planning testing wiki in readme 86 | * only add one checkmark to the document.title 87 | * Escape the stacktrace output before setting it as innerHTML, since it tends to contain `<` and `>` characters. 88 | * Cleanup whitespace 89 | * Run module.teardown before checking for pollution. Fixes #109 - noglobals should run after module teardown 90 | * Fix accidental global variable "not" 91 | * Update document.title status to use more robust unicode escape sequences, works even when served with non-utf-8-charset. 92 | * Modify document.title when suite is done to show success/failure in tab, allows you to see the overall result without seeing the tab content. 93 | * Merge pull request #107 from sexyprout/master 94 | * Set a generic font 95 | * Add/update headers 96 | * Drop support for deprecated #main in favor of #qunit-fixture. If this breaks your testsuite, replace id="main" with id="qunit-fixture". Fixes #103 97 | * Remove the same key as the one being set. Partial fix for #101 98 | * Don't modify expected-count when checking pollution. The failing assertion isn't expected, so shouldn't be counted. And if expect wasn't used, the count is misleading. 99 | * Fix order of noglobals check to produce correct introduced/delete error messages 100 | * Prepend module name to sessionStorage keys to avoid conflicts 101 | * Store filter-tests only when checked 102 | * Write to sessionStorage only bad tests 103 | * Moved QUnit.url() defintion after QUnit properties are merged into the global scope. Fixes #93 - QUnit url/extend function breaking urls in jQuery ajax test component 104 | * Add a "Rerun" link to each test to replce the dblclick (still supported, for now). 105 | * Fixed the regex for parsing the name of a test when double clicking to filter. 106 | * Merge remote branch 'scottgonzalez/url' 107 | * Added checkboxes to show which flags are currently on and allow toggling them. 108 | * Retain all querystring parameters when filtering a test via double click. 109 | * Added better querystring parsing. Now storing all querystring params in QUnit.urlParams so that we can carry the params forward when filtering to a specific test. This removes the ability to specify multiple filters. 110 | * Make reordering optional (QUnit.config.reorder = false) and optimize "Hide passed tests" mode by also hiding "Running [testname]" entries. 111 | * Added missing semicolons and wrapped undefined key in quotes. 112 | * Optimize test hiding, add class on page load if stored in sessionStorage 113 | * Optimize the hiding of passed tests. 114 | * Position test results above test list, making it visible without ever having to scroll. Create a placeholder to avoid pushing down results later. 115 | * Don't check for existing qunit-testresult element, it gets killed on init anyway. 116 | * Added URL flag ?notrycatch (ala ?noglobals) for debugging exceptions. Won't try/catch test code, giving better debugging changes on the original exceptions. Fixes #72 117 | * Always show quni-toolbar (if at all specified), persist checkbox via sessionStorage. Fixes #47 118 | * Use non-html testname for calls to fail(). Fixes #77 119 | * Overhaul of QUnit.callbacks. Consistent single argument with related properties, with additonal runtime property for QUnit.done 120 | * Extended test/logs.html to capture more of the callbacks. 121 | * Fixed moduleStart/Done callbacks. Added test/logs.html to test these callbacks. To be extended. 122 | * Update copyright and license header. Fixes #61 123 | * Formatting fix. 124 | * Use a semaphore to synchronize stop() and start() calls. Fixes #76 125 | * Merge branch 'master' of https://github.com/paulirish/qunit into paulirish-master 126 | * Added two tests for previous QUnit.raises behaviour. For #69 127 | * add optional 2. arg to QUnit.raises #69. 128 | * fix references inside Complex Instances Nesting to what was originally intended. 129 | * Qualify calls to ok() in raises() for compability with CLI enviroments. 130 | * Fix done() handling, check for blocking, not block property 131 | * Fix moduleStart/Done and done callbacks. 132 | * Replacing sessionStorage test with the one from Modernizr/master (instead of current release). Here's hoping it'll work for some time. 133 | * Updated test for availibility of sessionStorage, based on test from Modernizr. Fixes #64 134 | * Defer test execution when previous run passed, persisted via sessionStorage. Fixes #49 135 | * Refactored module handling and queuing to enable selective defer of test runs. 136 | * Move assertions property from config to Test 137 | * Move expected-tests property from config to Test 138 | * Refactored test() method to delegate to a Test object to encapsulate all properties and methods of a single test, allowing further modifications. 139 | * Adding output of sourcefile and linenumber of failed assertions (except ok()). Only limited cross-browser support for now. Fixes #60 140 | * Drop 'hide missing tests' feature. Fixes #48 141 | * Adding readme. Fixes #58 142 | * Merge branch 'prettydiff' 143 | * Improve jsDump output with formatted diffs. 144 | * Cleanup whitespace 145 | * Cleanup whitespace 146 | * Added additional guards around browser specific code and cleaned up jsDump code 147 | * Added guards around tests which are only for browsers 148 | * cleaned up setTimeout undefined checking and double done on test finish 149 | * fixing .gitignore 150 | * making window setTimeout query more consistent 151 | * Moved expect-code back to beginning of function, where it belongs. Fixes #52 152 | * Bread crumb in header: Link to suite without filters, add link to current page based on the filter, if present. Fixes #50 153 | * Make the toolbar element optional when checking for show/hide of test results. Fixes #46 154 | * Adding headless.html to manually test logging and verify that QUnit works without output elements. Keeping #qunit-fixture as a few tests actually use that. 155 | * Fix for QUnit.moduleDone, get rid of initial bogus log. Fixes #33 156 | * Pass raw data (result, message, actual, expected) as third argument to QUnit.log. Fixes #32 157 | * Dump full exception. Not pretty, but functional (see issue Pretty diff for pretty output). Fixes #31 158 | * Don't let QUnit.reset() cause assertions to run. Manually applied from Scott Gonzalez branch. Fixes #34 159 | * Added missing semicolons. Fixes #37 160 | * Show okay/failed instead of undefined. Fixes #38 161 | * Expose push as QUnit.push to build custom assertions. Fixes #39 162 | * Respect filter pass selection when writing new results. Fixes #43 163 | * Cleanup tests, removing asyncTest-undefined check and formatting 164 | * Reset: Fall back to innerHTML when jQuery isn't available. Fixes #44 165 | * Merge branch 'master' of github.com:jquery/qunit 166 | * reset doesn't exist here - fixes #28. 167 | * - less css cruft, better readability - replaced inline style for test counts with "counts" class - test counts now use a "failed"/"passed" vs "pass"/"fail", shorter/more distinct selectors - pulled all test counts styling together and up (they're always the same regardless of section pass/fail state) 168 | * Adding .gitignore file 169 | * Removing diff test - diffing works fine, as the browser collapses whitespace in its output, but the test can't do that and isn't worth fixing. 170 | * Always synchronize the done-step (it'll set the timeout when necessary), fixes timing race conditions. 171 | * Insert location.href as an anchor around the header. Fixes issue #29 172 | * - kill double ;; in escapeHtml. oops 173 | * Removed html escaping from QUnit.diff, as input is already escaped, only leads to double escaping. Replaced newlines with single whitespace. 174 | * Optimized and cleaned up CSS file 175 | * Making the reset-method non-global (only module, test and assertions should be global), and fixing the fixture reset by using jQuery's html() method again, doesn't work with innerHTML, yet 176 | * Introducing #qunit-fixture element, deprecating the (never documented) #main element. Doesn't require inline styles and is now independent of jQuery. 177 | * Ammending previous commit: Remove jQuery-core specific resets (will be replaced within jQuery testsuite). Fixes issue #19 - QUnit.reset() removes global jQuery ajax event handlers 178 | * Remove jQuery-core specific resets (will be replaced within jQuery testsuite). Fixes issue #19 - QUnit.reset() removes global jQuery ajax event handlers 179 | * Cleaning up rubble from the previous commit. 180 | * Added raises assertion, reusing some of kennsnyder's code. 181 | * Merged kensnyder's object detection code. Original message: Streamlined object detection and exposed QUnit.objectType as a function. 182 | * Fixed some bad formatting. 183 | * Move various QUnit properties below the globals-export to avoid init becoming a global method. Fixes issue #11 - Remove 'init' function from a global namespace 184 | * Improved output when expected != actual: Output both only then, and add a diff. Fixes issue #10 - Show diff if equal() or deepEqual() failed 185 | * Expand failed tests on load. Fixes issue #8 - Failed tests expanded on load 186 | * Set location.search for url-filtering instead of location.href. Fixes issue #7 - Modify location.search instead of location.href on test double-click 187 | * Add QUnit.begin() callback. Fixes issue #6 - Add 'start' callback. 188 | * add css style for result (".test-actual") in passed tests 189 | * Fixed output escaping by using leeoniya's custom escaping along with innerHTML. Also paves the way for outputting diffs. 190 | * Cleanup 191 | * Revert "Revert part of bad merge, back to using createTextNode" 192 | * Revert part of bad merge, back to using createTextNode 193 | * Fixed doubleclick-handler and filtering to rerun only a single test. 194 | * Add ability to css style a test's messages, expected and actual results. Merged from Leon Sorokin (leeoniya). 195 | * Remove space between module name and colon 196 | * - removed "module" wording from reports (unneeded and cluttery) - added and modified css to make module & test names styleable 197 | * Logging support for Each test can extend the module testEnvironment 198 | * Fixing whitespace 199 | * Update tests to use equal() and deepEqual() rather than the deprecated equals() and same() 200 | * Consistent argument names for deepEqual 201 | * Skip DOM part of jsDump test if using a SSJS environment without a DOM 202 | * Improve async testing by creating the result element before running the test, updating it later. If the test fails, its clear which test is the culprit. 203 | * Add autostart option to config. Set via QUnit.config.autostart = false; start later via QUnit.start() 204 | * Expose QUnit.config, but don't make config a global 205 | * Expose QUnit.config as global to make external workarounds easier 206 | * Merge branch 'asyncsetup' 207 | * Allowing async setup and teardown. Fixes http://github.com/jquery/qunit/issues#issue/20 208 | * Always output expected and actual result (no reason not to). Fixes http://github.com/jquery/qunit/issues#issue/21 209 | * More changes to the detection of types in jsDump's typeOf. 210 | * Change the typeOf checks in QUnit to be more accurate. 211 | * Added test for jsDump and modified its options to properly output results when document.createTextNode is used; currently tests for DOM elements cause a stackoverflow error in IEs, works fine, with the correct output, elsewhere 212 | * Always use jsDump to output result objects into messages, making the output for passing assertions more useful 213 | * Make it so that the display is updated, at least, once a second - also prevents scripts from executing for too long and causing problems. 214 | * added tests and patch for qunit.equiv to avoid circular references in objects and arrays 215 | * No reason to continue looping, we can stop at this point. Thanks to Chris Thatcher for the suggestion. 216 | * Use createTextNode instead of innerHTML for showing test result since expected and actual might be something that looks like a tag. 217 | * 'Test card' design added 218 | * switched green to blue for top-level pass + reduced padding 219 | * Bringing the QUnit API in line with the CommonJS API. 220 | * Explicitly set list-style-position: inside on result LIs. 221 | * Madness with border-radius. 222 | * Corrected banner styles for new class names 223 | * Added rounded corners and removed body rules for embedded tests 224 | * Resolving merge conflicts. 225 | * added colouring for value summary 226 | * adding some extra text colours 227 | * added styles for toolbar 228 | * added new styles 229 | * IE 6 and 7 weren't respecting the CSS rules for the banner, used a different technique instead. 230 | * Went a bit further and made extra-sure that the target was specified correctly. 231 | * Fixed problem where double-clicking an entry in IE caused an error to occur. 232 | * Path for http://dev.jquery.com/ticket/5426 - fix the microformat test result 233 | * Fixed test() to use 'expected' 2nd param 234 | * Remove the named function expressions, to stop Safari 2 from freaking out. Fixes #5. 235 | * Each test can extend the module testEnvironment 236 | * Extra test for current test environment 237 | * Make the current testEnvironment available to utility functions 238 | * typeOf in QUnit.jsDump now uses QUnit.is 239 | * hoozit in QUnit.equiv now uses QUnit.is 240 | * Properly set label attributes. 241 | * Some minor tweaks to RyanS' GETParams change. 242 | * left a console.log in :( 243 | * Took into account a fringe case when using qunit with testswarm. Trying to run all the tests with the extra url params from testswarm would make qunit look for a testsuite that did not exist 244 | * need to set config.currentModule to have correct names and working filters 245 | * Support logging of testEnvironment 246 | * async tests aren't possible on rhino 247 | * Fixed a missing QUnit.reset(). 248 | * The QUnit. prefix was missing from the uses of the start() method. 249 | * Merged lifecycle object into testEnvironment 250 | * "replacing totally wrong diff algorithm with a working one" Patch from kassens (manually applied). 251 | * fixing jslint errors in test.js 252 | * Fixed: testDone() was always called with 0 failures in CommonJS mode 253 | * Fixed: moduleDone() was invoked on first call to module() 254 | * Added a new asyncTest method - removes the need for having to call start() at the beginning of an asynchronous test. 255 | * Added support for expected numbers in the test method. 256 | * Fixed broken dynamic loading of tests (can now dynamically load tests and done still works properly). 257 | * Simplified the logic for calling 'done' and pushing off new tests - was causing too many inconsistencies otherwise. 258 | * Simplified the markup for the QUnit test test suite. 259 | * Realized that it's really easy to handle the case where stop() has been called and then an exception is thrown. 260 | * Added in better logging support. Now handle moduleStart/moduleDone and testStart/testDone. Also make sure that done only fires once at the end. 261 | * Made it so that you can reset the suite to an initial state (at which point tests can be dynamically loaded and run, for example). 262 | * Re-worked QUnit to handle dynamic loading of additional code (the 'done' code will be re-run after additional code is loaded). 263 | * Removed the old SVN version stuff. 264 | * Moved the QUnit source into a separate directory and updated the test suite/packages files. 265 | * Added in CommonJS support for exporting the QUnit functionality. 266 | * Missing quote from package.json. 267 | * Fixed trailing comma in package.json. 268 | * Added a CommonJS/Narwhal package.json file. 269 | * Accidentally reverted the jsDump/equiv changes that had been made. 270 | * Hide the filter toolbar if it's not needed. Also exposed the jsDump and equiv objects on QUnit. 271 | * Retooled the QUnit CSS to be more generic. 272 | * Renamed the QUnit files from testrunner/testsuite to QUnit. 273 | * Expose QUnit.equiv and QUnit.jsDump in QUnit. 274 | * Moved the QUnit test directory into the QUnit directory. 275 | * Reworked the QUnit CSS (moved jQuery-specific stuff out, made all the other selectors more specific). 276 | * Removed the #main reset for non-jQuery code (QUnit.reset can be overwritten with your own reset code). 277 | * Moved the QUnit toolbar inline. 278 | * Switched to using a qunit- prefix for special elements (banner, userAgent, and tests). 279 | * Missed a case in QUnit where an element was assumed to exist. 280 | * QUnit's isSet and isObj are no longer needed - you should use same instead. 281 | * Make sure that QUnit's equiv entity escaping is enabled by default (otherwise the output gets kind of crazy). 282 | * Refactored QUnit, completely reorganized the structure of the file. Additionally made it so that QUnit can run outside of a browser (inside Rhino, for example). 283 | * Removed some legacy and jQuery-specific test methods. 284 | * Added callbacks for tests and modules. It's now possible to reproduce the full display of the testrunner without using the regular rendering. 285 | * QUnit no longer depends upon rendering the results (it can work simply by using the logging callbacks). 286 | * Made QUnit no longer require jQuery (it is now a standalone, framework independent, test runner). 287 | * Reverted the noglobals changed from QUnit - causing chaos in the jQuery test suite. 288 | * qunit: removed noglobals flag, instead always check for globals after teardown; if a test has to introduce a global "myVar", use delete window.myVar in teardown or at the end of a test 289 | * qunit: don't child selectors when IE should behave nicely, too 290 | * qunit: improvment for the test-scope: create a new object and call setup, the test, and teardown in the scope of that object - allows you to provide test fixtures to each test without messing with global data; kudos to Martin Häcker for the contribution 291 | * qunit: added missing semicolons 292 | * qunit: fixed a semicolon, that should have been a comma 293 | * QUnit: implemented error handling for Opera as proposed by #3628 294 | * qunit: fix for http://dev.jquery.com/ticket/3215 changing wording of testresults, to something more positive (x of y passed, z failed) 295 | * QUnit: testrunner.js: Ensures equality of types (String, Boolean, Number) declared with the 'new' prefix. See comments #3, #4 and #5 on http://philrathe.com/articles/equiv 296 | * qunit: wrap name of test in span when a module is used for better styling 297 | * qunit: auto-prepend default mark (#header, #banner, #userAgent, #tests) when not present 298 | * Landing some changes to add logging to QUnit (so that it's easier to hook in to when a test finishes). 299 | * Added checkbox for hiding missing tests (tests that fail with the text 'missing test - untested code is broken code') 300 | * qunit: eol-style:native and mime-type 301 | * HTML being injected for the test result wasn't valid HTML. 302 | * qunit: setting mimetype for testsuite.css 303 | * qunit: update to Ariel's noglobals patch to support async tests as well 304 | * Landing Ariel's change - checks for global variable leakage. 305 | * qunit: run module-teardown in its own synchronize block to synchronize with async tests (ugh) 306 | * qunit: same: equiv - completely refactored in the testrunner. 307 | * testrunner.js: - Update equiv to support Date and RegExp. - Change behavior when comparing function: - abort when in an instance of Object (when references comparison failed) - skip otherwise (like before) 308 | * qunit: code refactoring and cleanup 309 | * QUnit: update equiv to latest version, handling multiple arguments and NaN, see http://philrathe.com/articles/equiv 310 | * QUnit: cleanup, deprecating compare, compare2 and serialArray: usage now throws an error with a helpful message 311 | * QUnit: optional timeout argument for stop, while making tests undetermined, useful for debugging 312 | * QUnit: added toolbar with "hide passed tests" checkbox to help focus on failed tests 313 | * QUnit: minor output formatting 314 | * QUnit: adding same-assertion for a recursive comparsion of primite values, arrays and objects, thanks to Philippe Rathé for the contribution, including tests 315 | * QUnit: adding same-assertion for a recursive comparsion of primite values, arrays and objects, thanks to Philippe Rathé for the contribution, including tests 316 | * QUnit: adding same-assertion for a recursive comparsion of primite values, arrays and objects, thanks to Philippe Rathé for the contribution, including tests 317 | * qunit: use window.load to initialize tests, allowing other code to run on document-ready before starting to run tests 318 | * qunit: allow either setup or teardown, instead of both or nothing 319 | * qunit: make everything private by default, expose only public API; removed old timeout-option (non-deterministic, disabled for a long time anyway); use local $ reference instead of global jQuery reference; minor code cleanup (var config instead of _config; queue.shift instead of slice) 320 | * qunit: added support for module level setup/teardown callbacks 321 | * qunit: modified example for equals to avoid confusion with parameter ordering 322 | * qunit: added id/classes to result element to enable integration with browser automation tools, see http://docs.jquery.com/QUnit#Integration_into_Browser_Automation_Tools 323 | * qunit: replaced $ alias with jQuery (merged from jquery/test/data/testrunner.js) 324 | * qunit: fixed inline documentation for equals 325 | * qunit testrunner - catch and log possible error during reset() 326 | * QUnit: Switched out Date and Rev for Id. 327 | * qunit: when errors are thrown in a test, the message is successfully show on all browsers. 328 | * qunit: added license header 329 | * qunit: moved jquery testrunner to top-level project, see http://docs.jquery.com/QUnit 330 | * Share project 'qunit' into 'https://jqueryjs.googlecode.com/svn' 331 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/README.md: -------------------------------------------------------------------------------- 1 | [QUnit](http://docs.jquery.com/QUnit) - A JavaScript Unit Testing framework. 2 | ================================ 3 | 4 | QUnit is a powerful, easy-to-use, JavaScript test suite. It's used by the jQuery 5 | project to test its code and plugins but is capable of testing any generic 6 | JavaScript code (and even capable of testing JavaScript code on the server-side). 7 | 8 | QUnit is especially useful for regression testing: Whenever a bug is reported, 9 | write a test that asserts the existence of that particular bug. Then fix it and 10 | commit both. Every time you work on the code again, run the tests. If the bug 11 | comes up again - a regression - you'll spot it immediately and know how to fix 12 | it, because you know what code you just changed. 13 | 14 | Having good unit test coverage makes safe refactoring easy and cheap. You can 15 | run the tests after each small refactoring step and always know what change 16 | broke something. 17 | 18 | QUnit is similar to other unit testing frameworks like JUnit, but makes use of 19 | the features JavaScript provides and helps with testing code in the browser, eg. 20 | with it's stop/start facilities for testing asynchronous code. 21 | 22 | If you are interested in helping developing QUnit, you are in the right place. 23 | For related discussions, visit the 24 | [QUnit and Testing forum](http://forum.jquery.com/qunit-and-testing). 25 | 26 | Planning for a qunitjs.com site and other testing tools related work now happens 27 | on the [jQuery Testing Team planning wiki](http://jquerytesting.pbworks.com/w/page/41556026/FrontPage). 28 | 29 | Releases 30 | -------- 31 | 32 | Install git-extras and run `git changelog` to update History.md. 33 | Update qunit/qunit.js|css to the release version, commit and tag, update them 34 | again to the next version, commit and push commits and tags. 35 | 36 | Put the 'v' in front of the tag (unlike the 1.1.0 release). Clean up the changelog, 37 | removing merge commits or whitespace cleanups. 38 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/canvas/README.md: -------------------------------------------------------------------------------- 1 | Canvas - A QUnit Addon For Testing Canvas Rendering 2 | ================================ 3 | 4 | This addon for QUnit adds a pixelEqual method that allows you to assert 5 | individual pixel values in a given canvas. 6 | 7 | Usage: 8 | 9 | pixelEqual(canvas, x, y, r, g, b, a, message) 10 | 11 | Where: 12 | 13 | * canvas: Reference to a canvas element 14 | * x, y: Coordinates of the pixel to test 15 | * r, g, b, a: The color and opacity value of the pixel that you except 16 | * message: Optional message, same as for other assertions 17 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/canvas/canvas-test.js: -------------------------------------------------------------------------------- 1 | test("Canvas pixels", function () { 2 | var canvas = document.getElementById('qunit-canvas'), context; 3 | try { 4 | context = canvas.getContext('2d'); 5 | } catch(e) { 6 | // propably no canvas support, just exit 7 | return; 8 | } 9 | context.fillStyle = 'rgba(0, 0, 0, 0)'; 10 | context.fillRect(0, 0, 5, 5); 11 | QUnit.pixelEqual(canvas, 0, 0, 0, 0, 0, 0); 12 | context.clearRect(0,0,5,5); 13 | context.fillStyle = 'rgba(255, 0, 0, 0)'; 14 | context.fillRect(0, 0, 5, 5); 15 | QUnit.pixelEqual(canvas, 0, 0, 0, 0, 0, 0); 16 | context.clearRect(0,0,5,5); 17 | context.fillStyle = 'rgba(0, 255, 0, 0)'; 18 | context.fillRect(0, 0, 5, 5); 19 | QUnit.pixelEqual(canvas, 0, 0, 0, 0, 0, 0); 20 | context.clearRect(0,0,5,5); 21 | context.fillStyle = 'rgba(0, 0, 255, 0)'; 22 | context.fillRect(0, 0, 5, 5); 23 | QUnit.pixelEqual(canvas, 0, 0, 0, 0, 0, 0); 24 | context.clearRect(0,0,5,5); 25 | 26 | context.fillStyle = 'rgba(0, 0, 0, 0.5)'; 27 | context.fillRect(0, 0, 5, 5); 28 | QUnit.pixelEqual(canvas, 0, 0, 0, 0, 0, 127); 29 | context.clearRect(0,0,5,5); 30 | context.fillStyle = 'rgba(255, 0, 0, 0.5)'; 31 | context.fillRect(0, 0, 5, 5); 32 | QUnit.pixelEqual(canvas, 0, 0, 255, 0, 0, 127); 33 | context.clearRect(0,0,5,5); 34 | context.fillStyle = 'rgba(0, 255, 0, 0.5)'; 35 | context.fillRect(0, 0, 5, 5); 36 | QUnit.pixelEqual(canvas, 0, 0, 0, 255, 0, 127); 37 | context.clearRect(0,0,5,5); 38 | context.fillStyle = 'rgba(0, 0, 255, 0.5)'; 39 | context.fillRect(0, 0, 5, 5); 40 | QUnit.pixelEqual(canvas, 0, 0, 0, 0, 255, 127); 41 | context.clearRect(0,0,5,5); 42 | 43 | context.fillStyle = 'rgba(0, 0, 0, 0.5)'; 44 | context.fillRect(0, 0, 5, 5); 45 | QUnit.pixelEqual(canvas, 2, 2, 0, 0, 0, 127); 46 | context.clearRect(0,0,5,5); 47 | context.fillStyle = 'rgba(255, 0, 0, 0.5)'; 48 | context.fillRect(0, 0, 5, 5); 49 | QUnit.pixelEqual(canvas, 2, 2, 255, 0, 0, 127); 50 | context.clearRect(0,0,5,5); 51 | context.fillStyle = 'rgba(0, 255, 0, 0.5)'; 52 | context.fillRect(0, 0, 5, 5); 53 | QUnit.pixelEqual(canvas, 2, 2, 0, 255, 0, 127); 54 | context.clearRect(0,0,5,5); 55 | context.fillStyle = 'rgba(0, 0, 255, 0.5)'; 56 | context.fillRect(0, 0, 5, 5); 57 | QUnit.pixelEqual(canvas, 2, 2, 0, 0, 255, 127); 58 | context.clearRect(0,0,5,5); 59 | 60 | context.fillStyle = 'rgba(0, 0, 0, 1)'; 61 | context.fillRect(0, 0, 5, 5); 62 | QUnit.pixelEqual(canvas, 4, 4, 0, 0, 0, 255); 63 | context.clearRect(0,0,5,5); 64 | context.fillStyle = 'rgba(255, 0, 0, 1)'; 65 | context.fillRect(0, 0, 5, 5); 66 | QUnit.pixelEqual(canvas, 4, 4, 255, 0, 0, 255); 67 | context.clearRect(0,0,5,5); 68 | context.fillStyle = 'rgba(0, 255, 0, 1)'; 69 | context.fillRect(0, 0, 5, 5); 70 | QUnit.pixelEqual(canvas, 4, 4, 0, 255, 0, 255); 71 | context.clearRect(0,0,5,5); 72 | context.fillStyle = 'rgba(0, 0, 255, 1)'; 73 | context.fillRect(0, 0, 5, 5); 74 | QUnit.pixelEqual(canvas, 4, 4, 0, 0, 255, 255); 75 | context.clearRect(0,0,5,5); 76 | }); 77 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/canvas/canvas.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Test Suite - Canvas Addon 6 | 7 | 8 | 9 | 10 | 11 | 12 |

      QUnit Test Suite - Canvas Addon

      13 |

      14 |
      15 |

      16 |
        17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/canvas/qunit-canvas.js: -------------------------------------------------------------------------------- 1 | QUnit.extend( QUnit, { 2 | pixelEqual: function(canvas, x, y, r, g, b, a, message) { 3 | var actual = Array.prototype.slice.apply(canvas.getContext('2d').getImageData(x, y, 1, 1).data), expected = [r, g, b, a]; 4 | QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); 5 | } 6 | }); 7 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/close-enough/README.md: -------------------------------------------------------------------------------- 1 | Close-Enough - A QUnit Addon For Number Approximations 2 | ================================ 3 | 4 | This addon for QUnit adds close and notClose assertion methods, to test that 5 | numbers are close enough (or different enough) from an expected number, with 6 | a specified accuracy. 7 | 8 | Usage: 9 | 10 | close(actual, expected, maxDifference, message) 11 | notClose(actual, expected, minDifference, message) 12 | 13 | Where: 14 | 15 | * maxDifference: the maximum inclusive difference allowed between the actual and expected numbers 16 | * minDifference: the minimum exclusive difference allowed between the actual and expected numbers 17 | * actual, expected, message: The usual 18 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/close-enough/close-enough-test.js: -------------------------------------------------------------------------------- 1 | test("Close Numbers", function () { 2 | 3 | QUnit.close(7, 7, 0); 4 | QUnit.close(7, 7.1, 0.1); 5 | QUnit.close(7, 7.1, 0.2); 6 | 7 | QUnit.close(3.141, Math.PI, 0.001); 8 | QUnit.close(3.1, Math.PI, 0.1); 9 | 10 | var halfPi = Math.PI / 2; 11 | QUnit.close(halfPi, 1.57, 0.001); 12 | 13 | var sqrt2 = Math.sqrt(2); 14 | QUnit.close(sqrt2, 1.4142, 0.0001); 15 | 16 | QUnit.close(Infinity, Infinity, 1); 17 | 18 | }); 19 | 20 | test("Distant Numbers", function () { 21 | 22 | QUnit.notClose(6, 7, 0); 23 | QUnit.notClose(7, 7.2, 0.1); 24 | QUnit.notClose(7, 7.2, 0.19999999999); 25 | 26 | QUnit.notClose(3.141, Math.PI, 0.0001); 27 | QUnit.notClose(3.1, Math.PI, 0.001); 28 | 29 | var halfPi = Math.PI / 2; 30 | QUnit.notClose(halfPi, 1.57, 0.0001); 31 | 32 | var sqrt2 = Math.sqrt(2); 33 | QUnit.notClose(sqrt2, 1.4142, 0.00001); 34 | 35 | QUnit.notClose(Infinity, -Infinity, 5); 36 | 37 | }); -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/close-enough/close-enough.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Test Suite - Close Enough Addon 6 | 7 | 8 | 9 | 10 | 11 | 12 |

        QUnit Test Suite - Close Enough

        13 |

        14 |
        15 |

        16 |
          17 | 18 | 19 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/close-enough/qunit-close-enough.js: -------------------------------------------------------------------------------- 1 | QUnit.extend( QUnit, { 2 | /** 3 | * Checks that the first two arguments are equal, or are numbers close enough to be considered equal 4 | * based on a specified maximum allowable difference. 5 | * 6 | * @example close(3.141, Math.PI, 0.001); 7 | * 8 | * @param Number actual 9 | * @param Number expected 10 | * @param Number maxDifference (the maximum inclusive difference allowed between the actual and expected numbers) 11 | * @param String message (optional) 12 | */ 13 | close: function(actual, expected, maxDifference, message) { 14 | var passes = (actual === expected) || Math.abs(actual - expected) <= maxDifference; 15 | QUnit.push(passes, actual, expected, message); 16 | }, 17 | 18 | /** 19 | * Checks that the first two arguments are numbers with differences greater than the specified 20 | * minimum difference. 21 | * 22 | * @example notClose(3.1, Math.PI, 0.001); 23 | * 24 | * @param Number actual 25 | * @param Number expected 26 | * @param Number minDifference (the minimum exclusive difference allowed between the actual and expected numbers) 27 | * @param String message (optional) 28 | */ 29 | notClose: function(actual, expected, minDifference, message) { 30 | QUnit.push(Math.abs(actual - expected) > minDifference, actual, expected, message); 31 | } 32 | }); -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/composite/README.md: -------------------------------------------------------------------------------- 1 | Composite - A QUnit Addon For Running Multiple Test Files 2 | ================================ 3 | 4 | Composite is a QUnit addon that, when handed an array of files, will 5 | open each of those files inside of an iframe, run the tests and 6 | display the results as a single suite of QUnit tests. 7 | 8 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/composite/composite-demo-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit SubsuiteRunner Test Suite 6 | 7 | 8 | 9 | 10 | 11 | 12 | 21 | 22 | 23 | 24 |

          QUnit SubsuiteRunner Test Suite

          25 |

          26 |
          27 |

          28 |
            29 |
            30 | 31 |
            32 | 33 | 34 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/composite/composite-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Core Test Suite 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

            QUnit Core Test Suite

            14 |

            15 |
            16 |

            17 |
              18 |
              test markup
              19 | 20 | 21 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/composite/composite-test.js: -------------------------------------------------------------------------------- 1 | module( "testSuites tests", (function(){ 2 | var asyncTest = QUnit.asyncTest, 3 | runSuite = QUnit.runSuite; 4 | 5 | return { 6 | setup: function(){ 7 | //proxy asyncTest and runSuite 8 | QUnit.asyncTest = window.asyncTest = function( name, callback ){ 9 | ok( true, "asyncTestCalled for each suite" ); 10 | callback(); //don't acutally create tests, just call callback 11 | }; 12 | QUnit.runSuite = window.runSuite = function(){ 13 | ok( true, "runSuite called for each suite" ); 14 | }; 15 | //ensure that subsuite's done doesn't run 16 | this.oldDone = QUnit.done; 17 | }, 18 | teardown: function(){ 19 | //restore 20 | QUnit.asyncTest = window.asyncTest = asyncTest; 21 | QUnit.runSuite = window.runSuite = runSuite; 22 | QUnit.done = this.oldDone; 23 | } 24 | }; 25 | })()); 26 | 27 | test( "proper number of asyncTest and runSuite calls", function(){ 28 | expect( 6 ); 29 | QUnit.testSuites( ["one.html", "two.html", "three.html"] ); 30 | }); 31 | 32 | test( "done callback changed", function(){ 33 | QUnit.testSuites( ["dummy.html"] ); 34 | notEqual( this.oldDone, QUnit.done, "done callback should be set" ); 35 | }); 36 | 37 | module( "testStart tests", (function(){ 38 | var id = QUnit.id; 39 | return { 40 | setup: function(){ 41 | //proxy id 42 | var fakeElem = this.fakeElem = document.createElement( "div" ); 43 | 44 | QUnit.id = function(){ 45 | return fakeElem; 46 | } 47 | }, 48 | teardown: function(){ 49 | QUnit.id = id; 50 | } 51 | }; 52 | })()); 53 | 54 | test( "running message printed", function(){ 55 | var hello = "hello world", 56 | expected = "Running " + hello + "...
               "; 57 | QUnit.testStart( {name: hello} ); 58 | equal( this.fakeElem.innerHTML, expected, "innerHTML was set correctly by testStart" ); 59 | }); 60 | 61 | module( "testDone tests", (function(){ 62 | var id = QUnit.id; 63 | return { 64 | setup: function(){ 65 | //proxy id 66 | var fakeElem = this.fakeElem = document.createElement( "div" ); 67 | fakeElem.appendChild( document.createElement( "ol" ) ); 68 | fakeElem.appendChild( document.createElement( "ol" ) ); 69 | QUnit.id = function(){ 70 | return fakeElem; 71 | } 72 | }, 73 | teardown: function(){ 74 | QUnit.id = id; 75 | } 76 | }; 77 | })()); 78 | 79 | test( "test expansions are hidden", function(){ 80 | QUnit.testDone(); 81 | equal( this.fakeElem.children[0].style.display, "none", "first ol display is none" ); 82 | equal( this.fakeElem.children[1].style.display, "none", "second ol display is none" ); 83 | }); 84 | 85 | test( "non-ol elements aren't hidden", function(){ 86 | this.fakeElem.appendChild( document.createElement( "span" ) ); 87 | 88 | QUnit.testDone(); 89 | notEqual( this.fakeElem.children[2].style.display, "none", "first ol display is none" ); 90 | }); 91 | 92 | module( "runSuite tests", (function(){ 93 | var getElementsByTagName = document.getElementsByTagName, 94 | createElement = document.createElement, 95 | runSuite = QUnit.runSuite; 96 | 97 | return { 98 | setup: function(){ 99 | //proxy getElementsByTagName and createElement 100 | var setAttributeCall = this.setAttributeCall = {}, 101 | appendChildCall = this.appendChildCall = {called: 0}, 102 | iframeLoad = this.iframeLoad = {}, 103 | iframeQUnitObject = this.iframeQUnitObject = {}, 104 | fakeElement = { 105 | appendChild: function(){appendChildCall.called++}, 106 | setAttribute: function(){setAttributeCall.args = arguments}, 107 | addEventListener: function( type, callback ){iframeLoad.callback = callback;}, 108 | contentWindow: {QUnit: iframeQUnitObject}, 109 | className: "", 110 | }; 111 | 112 | document.getElementsByTagName = function(){ 113 | return [fakeElement]; 114 | }; 115 | document.createElement = function(){ 116 | return fakeElement; 117 | } 118 | 119 | }, 120 | teardown: function(){ 121 | document.getElementsByTagName = getElementsByTagName; 122 | document.createElement = createElement; 123 | //must restore even though we didn't proxy; the runner overwrites upon first call 124 | QUnit.runSuite = runSuite; 125 | } 126 | }; 127 | })()); 128 | 129 | test( "runSuite different after first run", function(){ 130 | var before = QUnit.runSuite, 131 | after; 132 | QUnit.runSuite(); 133 | after = QUnit.runSuite; 134 | notEqual( before, after, "runSuite changed after initial run" ); 135 | }); 136 | 137 | test( "iframe only created once", function(){ 138 | QUnit.runSuite(); 139 | equal( this.appendChildCall.called, 1, "append child called once" ); 140 | QUnit.runSuite(); 141 | equal( this.appendChildCall.called, 1, "append child only ever called once" ); 142 | }); 143 | 144 | test( "iframe's QUnit object is modified when iframe source loads", function(){ 145 | var before = this.iframeQUnitObject, 146 | after; 147 | QUnit.runSuite(); 148 | this.iframeLoad.callback(); 149 | notEqual( before, after, "iframe's qunit object is modified upon load"); 150 | }); 151 | 152 | test( "iframe src set to suite passed", function(){ 153 | var pages = ["testing.html", "subsuiteRunner.html"]; 154 | QUnit.runSuite( pages[0] ); 155 | equal( this.setAttributeCall.args[0], "src", "src attribute set" ); 156 | equal( this.setAttributeCall.args[1], pages[0], "src attribute set" ); 157 | QUnit.runSuite( pages[1] ); 158 | equal( this.setAttributeCall.args[1], pages[1], "src attribute set" ); 159 | }); -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/composite/dummy-qunit-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Core Test Suite 6 | 7 | 8 | 9 | 10 | 11 | 12 |

              QUnit Core Test Suite

              13 |

              14 |
              15 |

              16 |
                17 |
                test markup
                18 | 19 | 20 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/composite/dummy-same-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Same Test Suite 6 | 7 | 8 | 9 | 10 | 11 | 12 |

                QUnit Same Test Suite

                13 |

                14 |
                15 |

                16 |
                  17 |
                  test markup
                  18 | 19 | 20 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/composite/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Composite 6 | 7 | 8 |

                  Composite

                  9 |

                  A QUnit Addon For Running Multiple Test Files

                  10 |

                  Composite is a QUnit addon that, when handed an array of 11 | files, will open each of those files inside of an iframe, run 12 | the tests and display the results as a single suite of QUnit 13 | tests.

                  14 |

                  Using Composite

                  15 |

                  To use Composite, setup a standard QUnit html page as you 16 | would with other QUnit tests. Remember to include composite.js 17 | and composite.css. Then, inside of either an external js file, 18 | or a script block call the only new method that Composite 19 | exposes, QUnit.testSuites().

                  QUnit.testSuites() is 20 | passed an array of test files to run as follows:

                  21 |
                  22 | QUnit.testSuites([
                  23 |     "test-file-1.html",
                  24 |     "test-file-2.html",
                  25 |     "test-file-3.html"
                  26 | ]);
                  27 | 		
                  28 |

                  Tests

                  29 |

                  Composite has tests of it's own.

                  30 |

                  31 | Composite Test: A suite which tests the implementation of composite.
                  32 | Composite Demo: A suite which demoes how Compisite is bootstrapped and run. 33 |

                  34 | 35 | 36 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/composite/qunit-composite.css: -------------------------------------------------------------------------------- 1 | iframe.qunit-subsuite{ 2 | position: fixed; 3 | bottom: 0; 4 | left: 0; 5 | 6 | margin: 0; 7 | padding: 0; 8 | border-width: 1px 0 0; 9 | height: 45%; 10 | width: 100%; 11 | 12 | background: #fff; 13 | } -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/composite/qunit-composite.js: -------------------------------------------------------------------------------- 1 | (function( QUnit ) { 2 | 3 | var subsuiteFrame; 4 | 5 | QUnit.extend( QUnit, { 6 | testSuites: function( suites ) { 7 | for ( var i = 0; i < suites.length; i++ ) { 8 | (function( suite ) { 9 | asyncTest( suite, function() { 10 | QUnit.runSuite( suite ); 11 | }); 12 | }( suites[i] ) ); 13 | } 14 | QUnit.done = function() { 15 | subsuiteFrame.style.display = "none"; 16 | }; 17 | }, 18 | 19 | testStart: function( data ) { 20 | // update the test status to show which test suite is running 21 | QUnit.id( "qunit-testresult" ).innerHTML = "Running " + data.name + "...
                   "; 22 | }, 23 | 24 | testDone: function() { 25 | var current = QUnit.id( this.config.current.id ), 26 | children = current.children; 27 | 28 | // undo the auto-expansion of failed tests 29 | for ( var i = 0; i < children.length; i++ ) { 30 | if ( children[i].nodeName === "OL" ) { 31 | children[i].style.display = "none"; 32 | } 33 | } 34 | }, 35 | 36 | runSuite: function( suite ) { 37 | var body = document.getElementsByTagName( "body" )[0], 38 | iframe = subsuiteFrame = document.createElement( "iframe" ), 39 | iframeWin; 40 | 41 | iframe.className = "qunit-subsuite"; 42 | body.appendChild( iframe ); 43 | 44 | function onIframeLoad() { 45 | var module, test, 46 | count = 0; 47 | 48 | QUnit.extend( iframeWin.QUnit, { 49 | moduleStart: function( data ) { 50 | // capture module name for messages 51 | module = data.name; 52 | }, 53 | 54 | testStart: function( data ) { 55 | // capture test name for messages 56 | test = data.name; 57 | }, 58 | 59 | log: function( data ) { 60 | // pass all test details through to the main page 61 | var message = module + ": " + test + ": " + data.message; 62 | expect( ++count ); 63 | QUnit.push( data.result, data.actual, data.expected, message ); 64 | }, 65 | 66 | done: function() { 67 | // start the wrapper test from the main page 68 | start(); 69 | } 70 | }); 71 | } 72 | QUnit.addEvent( iframe, "load", onIframeLoad ); 73 | 74 | iframeWin = iframe.contentWindow; 75 | iframe.setAttribute( "src", suite ); 76 | 77 | this.runSuite = function( suite ) { 78 | iframe.setAttribute( "src", suite ); 79 | }; 80 | } 81 | }); 82 | }( QUnit ) ); 83 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/step/README.md: -------------------------------------------------------------------------------- 1 | QUnit.step() - A QUnit Addon For Testing execution in order 2 | ============================================================ 3 | 4 | This addon for QUnit adds a step method that allows you to assert 5 | the proper sequence in which the code should execute. 6 | 7 | Example: 8 | 9 | test("example test", function () { 10 | function x() { 11 | QUnit.step(2, "function y should be called first"); 12 | } 13 | function y() { 14 | QUnit.step(1); 15 | } 16 | y(); 17 | x(); 18 | }); -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/step/qunit-step.js: -------------------------------------------------------------------------------- 1 | QUnit.extend( QUnit, { 2 | 3 | /** 4 | * Check the sequence/order 5 | * 6 | * @example step(1); setTimeout(function () { step(3); }, 100); step(2); 7 | * @param Number expected The excepted step within the test() 8 | * @param String message (optional) 9 | */ 10 | step: function (expected, message) { 11 | this.config.current.step++; // increment internal step counter. 12 | if (typeof message == "undefined") { 13 | message = "step " + expected; 14 | } 15 | var actual = this.config.current.step; 16 | QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); 17 | } 18 | }); 19 | 20 | /** 21 | * Reset the step counter for every test() 22 | */ 23 | QUnit.testStart(function () { 24 | this.config.current.step = 0; 25 | }); 26 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/step/step-test.js: -------------------------------------------------------------------------------- 1 | module('Step Addon'); 2 | test("step", 3, function () { 3 | QUnit.step(1, "step starts at 1"); 4 | setTimeout(function () { 5 | start(); 6 | QUnit.step(3); 7 | }, 100); 8 | QUnit.step(2, "before the setTimeout callback is run"); 9 | stop(); 10 | }); 11 | test("step counter", 1, function () { 12 | QUnit.step(1, "each test has its own step counter"); 13 | }); -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/addons/step/step.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Test Suite - Step Addon 6 | 7 | 8 | 9 | 10 | 11 | 12 |

                  QUnit Test Suite - Step Addon

                  13 |

                  14 |
                  15 |

                  16 |
                    17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qunit", 3 | "author": "The jQuery Project", 4 | "version": "1.1.0pre", 5 | "contributors": [ 6 | { 7 | "name": "John Resig", 8 | "email": "jeresig@gmail.com", 9 | "url": "http://ejohn.org/" 10 | }, 11 | { 12 | "name": "Jörn Zaefferer", 13 | "email": "joern.zaefferer@googlemail.com", 14 | "url": "http://bassistance.de/" 15 | }], 16 | "url": "http://docs.jquery.com/QUnit", 17 | "repositories" : [{ 18 | "type": "git", 19 | "url": "https://github.com/jquery/qunit.git" 20 | }], 21 | "license": { 22 | "name": "MIT", 23 | "url": "http://www.opensource.org/licenses/mit-license.php" 24 | }, 25 | "description": "An easy-to-use JavaScript Unit Testing framework.", 26 | "keywords": [ "testing", "unit", "jquery" ], 27 | "main": "qunit/qunit.js" 28 | } 29 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/qunit/qunit.css: -------------------------------------------------------------------------------- 1 | /** 2 | * QUnit v1.3.0pre - A JavaScript Unit Testing Framework 3 | * 4 | * http://docs.jquery.com/QUnit 5 | * 6 | * Copyright (c) 2011 John Resig, Jörn Zaefferer 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * or GPL (GPL-LICENSE.txt) licenses. 9 | */ 10 | 11 | /** Font Family and Sizes */ 12 | 13 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 14 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; 15 | } 16 | 17 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 18 | #qunit-tests { font-size: smaller; } 19 | 20 | 21 | /** Resets */ 22 | 23 | #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { 24 | margin: 0; 25 | padding: 0; 26 | } 27 | 28 | 29 | /** Header */ 30 | 31 | #qunit-header { 32 | padding: 0.5em 0 0.5em 1em; 33 | 34 | color: #8699a4; 35 | background-color: #0d3349; 36 | 37 | font-size: 1.5em; 38 | line-height: 1em; 39 | font-weight: normal; 40 | 41 | border-radius: 15px 15px 0 0; 42 | -moz-border-radius: 15px 15px 0 0; 43 | -webkit-border-top-right-radius: 15px; 44 | -webkit-border-top-left-radius: 15px; 45 | } 46 | 47 | #qunit-header a { 48 | text-decoration: none; 49 | color: #c2ccd1; 50 | } 51 | 52 | #qunit-header a:hover, 53 | #qunit-header a:focus { 54 | color: #fff; 55 | } 56 | 57 | #qunit-banner { 58 | height: 5px; 59 | } 60 | 61 | #qunit-testrunner-toolbar { 62 | padding: 0.5em 0 0.5em 2em; 63 | color: #5E740B; 64 | background-color: #eee; 65 | } 66 | 67 | #qunit-userAgent { 68 | padding: 0.5em 0 0.5em 2.5em; 69 | background-color: #2b81af; 70 | color: #fff; 71 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 72 | } 73 | 74 | 75 | /** Tests: Pass/Fail */ 76 | 77 | #qunit-tests { 78 | list-style-position: inside; 79 | } 80 | 81 | #qunit-tests li { 82 | padding: 0.4em 0.5em 0.4em 2.5em; 83 | border-bottom: 1px solid #fff; 84 | list-style-position: inside; 85 | } 86 | 87 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { 88 | display: none; 89 | } 90 | 91 | #qunit-tests li strong { 92 | cursor: pointer; 93 | } 94 | 95 | #qunit-tests li a { 96 | padding: 0.5em; 97 | color: #c2ccd1; 98 | text-decoration: none; 99 | } 100 | #qunit-tests li a:hover, 101 | #qunit-tests li a:focus { 102 | color: #000; 103 | } 104 | 105 | #qunit-tests ol { 106 | margin-top: 0.5em; 107 | padding: 0.5em; 108 | 109 | background-color: #fff; 110 | 111 | border-radius: 15px; 112 | -moz-border-radius: 15px; 113 | -webkit-border-radius: 15px; 114 | 115 | box-shadow: inset 0px 2px 13px #999; 116 | -moz-box-shadow: inset 0px 2px 13px #999; 117 | -webkit-box-shadow: inset 0px 2px 13px #999; 118 | } 119 | 120 | #qunit-tests table { 121 | border-collapse: collapse; 122 | margin-top: .2em; 123 | } 124 | 125 | #qunit-tests th { 126 | text-align: right; 127 | vertical-align: top; 128 | padding: 0 .5em 0 0; 129 | } 130 | 131 | #qunit-tests td { 132 | vertical-align: top; 133 | } 134 | 135 | #qunit-tests pre { 136 | margin: 0; 137 | white-space: pre-wrap; 138 | word-wrap: break-word; 139 | } 140 | 141 | #qunit-tests del { 142 | background-color: #e0f2be; 143 | color: #374e0c; 144 | text-decoration: none; 145 | } 146 | 147 | #qunit-tests ins { 148 | background-color: #ffcaca; 149 | color: #500; 150 | text-decoration: none; 151 | } 152 | 153 | /*** Test Counts */ 154 | 155 | #qunit-tests b.counts { color: black; } 156 | #qunit-tests b.passed { color: #5E740B; } 157 | #qunit-tests b.failed { color: #710909; } 158 | 159 | #qunit-tests li li { 160 | margin: 0.5em; 161 | padding: 0.4em 0.5em 0.4em 0.5em; 162 | background-color: #fff; 163 | border-bottom: none; 164 | list-style-position: inside; 165 | } 166 | 167 | /*** Passing Styles */ 168 | 169 | #qunit-tests li li.pass { 170 | color: #5E740B; 171 | background-color: #fff; 172 | border-left: 26px solid #C6E746; 173 | } 174 | 175 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } 176 | #qunit-tests .pass .test-name { color: #366097; } 177 | 178 | #qunit-tests .pass .test-actual, 179 | #qunit-tests .pass .test-expected { color: #999999; } 180 | 181 | #qunit-banner.qunit-pass { background-color: #C6E746; } 182 | 183 | /*** Failing Styles */ 184 | 185 | #qunit-tests li li.fail { 186 | color: #710909; 187 | background-color: #fff; 188 | border-left: 26px solid #EE5757; 189 | white-space: pre; 190 | } 191 | 192 | #qunit-tests > li:last-child { 193 | border-radius: 0 0 15px 15px; 194 | -moz-border-radius: 0 0 15px 15px; 195 | -webkit-border-bottom-right-radius: 15px; 196 | -webkit-border-bottom-left-radius: 15px; 197 | } 198 | 199 | #qunit-tests .fail { color: #000000; background-color: #EE5757; } 200 | #qunit-tests .fail .test-name, 201 | #qunit-tests .fail .module-name { color: #000000; } 202 | 203 | #qunit-tests .fail .test-actual { color: #EE5757; } 204 | #qunit-tests .fail .test-expected { color: green; } 205 | 206 | #qunit-banner.qunit-fail { background-color: #EE5757; } 207 | 208 | 209 | /** Result */ 210 | 211 | #qunit-testresult { 212 | padding: 0.5em 0.5em 0.5em 2.5em; 213 | 214 | color: #2b81af; 215 | background-color: #D2E0E6; 216 | 217 | border-bottom: 1px solid white; 218 | } 219 | 220 | /** Fixture */ 221 | 222 | #qunit-fixture { 223 | position: absolute; 224 | top: -10000px; 225 | left: -10000px; 226 | } 227 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/test/headless.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | QUnit Test Suite 5 | 6 | 7 | 8 | 9 | 20 | 21 | 22 |
                    test markup
                    23 | 24 | 25 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Test Suite 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

                    QUnit Test Suite

                    15 |

                    16 |
                    17 |

                    18 |
                      19 |
                      test markup
                      20 | 21 | 22 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/test/logs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | QUnit Test Suite 5 | 6 | 7 | 8 | 9 | 10 |

                      QUnit Test Suite

                      11 |

                      12 |
                      13 |

                      14 |
                        15 |
                        test markup
                        16 | 17 | 18 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/test/logs.js: -------------------------------------------------------------------------------- 1 | // TODO disable reordering for this suite! 2 | 3 | 4 | var begin = 0, 5 | moduleStart = 0, 6 | moduleDone = 0, 7 | testStart = 0, 8 | testDone = 0, 9 | log = 0, 10 | moduleContext, 11 | moduleDoneContext, 12 | testContext, 13 | testDoneContext, 14 | logContext; 15 | 16 | QUnit.begin(function() { 17 | begin++; 18 | }); 19 | QUnit.done(function() { 20 | }); 21 | QUnit.moduleStart(function(context) { 22 | moduleStart++; 23 | moduleContext = context; 24 | }); 25 | QUnit.moduleDone(function(context) { 26 | moduleDone++; 27 | moduleDoneContext = context; 28 | }); 29 | QUnit.testStart(function(context) { 30 | testStart++; 31 | testContext = context; 32 | }); 33 | QUnit.testDone(function(context) { 34 | testDone++; 35 | testDoneContext = context; 36 | }); 37 | QUnit.log(function(context) { 38 | log++; 39 | logContext = context; 40 | }); 41 | 42 | var logs = ["begin", "testStart", "testDone", "log", "moduleStart", "moduleDone", "done"]; 43 | for (var i = 0; i < logs.length; i++) { 44 | (function() { 45 | var log = logs[i]; 46 | QUnit[log](function() { 47 | console.log(log, arguments); 48 | }); 49 | })(); 50 | } 51 | 52 | module("logs1"); 53 | 54 | test("test1", 13, function() { 55 | equal(begin, 1); 56 | equal(moduleStart, 1); 57 | equal(testStart, 1); 58 | equal(testDone, 0); 59 | equal(moduleDone, 0); 60 | 61 | deepEqual(logContext, { 62 | result: true, 63 | message: undefined, 64 | actual: 0, 65 | expected: 0 66 | }); 67 | equal("foo", "foo", "msg"); 68 | deepEqual(logContext, { 69 | result: true, 70 | message: "msg", 71 | actual: "foo", 72 | expected: "foo" 73 | }); 74 | strictEqual(testDoneContext, undefined); 75 | deepEqual(testContext, { 76 | module: "logs1", 77 | name: "test1" 78 | }); 79 | strictEqual(moduleDoneContext, undefined); 80 | deepEqual(moduleContext, { 81 | name: "logs1" 82 | }); 83 | 84 | equal(log, 12); 85 | }); 86 | test("test2", 10, function() { 87 | equal(begin, 1); 88 | equal(moduleStart, 1); 89 | equal(testStart, 2); 90 | equal(testDone, 1); 91 | equal(moduleDone, 0); 92 | 93 | deepEqual(testDoneContext, { 94 | module: "logs1", 95 | name: "test1", 96 | failed: 0, 97 | passed: 13, 98 | total: 13 99 | }); 100 | deepEqual(testContext, { 101 | module: "logs1", 102 | name: "test2" 103 | }); 104 | strictEqual(moduleDoneContext, undefined); 105 | deepEqual(moduleContext, { 106 | name: "logs1" 107 | }); 108 | 109 | equal(log, 22); 110 | }); 111 | 112 | module("logs2"); 113 | 114 | test("test1", 9, function() { 115 | equal(begin, 1); 116 | equal(moduleStart, 2); 117 | equal(testStart, 3); 118 | equal(testDone, 2); 119 | equal(moduleDone, 1); 120 | 121 | deepEqual(testContext, { 122 | module: "logs2", 123 | name: "test1" 124 | }); 125 | deepEqual(moduleDoneContext, { 126 | name: "logs1", 127 | failed: 0, 128 | passed: 23, 129 | total: 23 130 | }); 131 | deepEqual(moduleContext, { 132 | name: "logs2" 133 | }); 134 | 135 | equal(log, 31); 136 | }); 137 | test("test2", 8, function() { 138 | equal(begin, 1); 139 | equal(moduleStart, 2); 140 | equal(testStart, 4); 141 | equal(testDone, 3); 142 | equal(moduleDone, 1); 143 | 144 | deepEqual(testContext, { 145 | module: "logs2", 146 | name: "test2" 147 | }); 148 | deepEqual(moduleContext, { 149 | name: "logs2" 150 | }); 151 | 152 | equal(log, 39); 153 | }); 154 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/test/swarminject.js: -------------------------------------------------------------------------------- 1 | // load testswarm agent 2 | (function() { 3 | var url = window.location.search; 4 | url = decodeURIComponent( url.slice( url.indexOf("swarmURL=") + 9 ) ); 5 | if ( !url || url.indexOf("http") !== 0 ) { 6 | return; 7 | } 8 | document.write(""); 9 | })(); 10 | -------------------------------------------------------------------------------- /node_modules/qunit-tap/vendor/qunit/test/test.js: -------------------------------------------------------------------------------- 1 | test("module without setup/teardown (default)", function() { 2 | expect(1); 3 | ok(true); 4 | }); 5 | 6 | test("expect in test", 3, function() { 7 | ok(true); 8 | ok(true); 9 | ok(true); 10 | }); 11 | 12 | test("expect in test", 1, function() { 13 | ok(true); 14 | }); 15 | 16 | module("setup test", { 17 | setup: function() { 18 | ok(true); 19 | } 20 | }); 21 | 22 | test("module with setup", function() { 23 | expect(2); 24 | ok(true); 25 | }); 26 | 27 | 28 | test("module with setup, expect in test call", 2, function() { 29 | ok(true); 30 | }); 31 | 32 | var state; 33 | 34 | module("setup/teardown test", { 35 | setup: function() { 36 | state = true; 37 | ok(true); 38 | }, 39 | teardown: function() { 40 | ok(true); 41 | } 42 | }); 43 | 44 | test("module with setup/teardown", function() { 45 | expect(3); 46 | ok(true); 47 | }); 48 | 49 | module("setup/teardown test 2"); 50 | 51 | test("module without setup/teardown", function() { 52 | expect(1); 53 | ok(true); 54 | }); 55 | 56 | if (typeof setTimeout !== 'undefined') { 57 | state = 'fail'; 58 | 59 | module("teardown and stop", { 60 | teardown: function() { 61 | equal(state, "done", "Test teardown."); 62 | } 63 | }); 64 | 65 | test("teardown must be called after test ended", function() { 66 | expect(1); 67 | stop(); 68 | setTimeout(function() { 69 | state = "done"; 70 | start(); 71 | }, 13); 72 | }); 73 | 74 | test("parameter passed to stop increments semaphore n times", function() { 75 | expect(1); 76 | stop(3); 77 | setTimeout(function() { 78 | state = "not enough starts"; 79 | start(), start(); 80 | }, 13); 81 | setTimeout(function() { 82 | state = "done"; 83 | start(); 84 | }, 15); 85 | }); 86 | 87 | test("parameter passed to start decrements semaphore n times", function() { 88 | expect(1); 89 | stop(), stop(), stop(); 90 | setTimeout(function() { 91 | state = "done"; 92 | start(3); 93 | }, 18); 94 | }); 95 | 96 | module("async setup test", { 97 | setup: function() { 98 | stop(); 99 | setTimeout(function(){ 100 | ok(true); 101 | start(); 102 | }, 500); 103 | } 104 | }); 105 | 106 | asyncTest("module with async setup", function() { 107 | expect(2); 108 | ok(true); 109 | start(); 110 | }); 111 | 112 | module("async teardown test", { 113 | teardown: function() { 114 | stop(); 115 | setTimeout(function(){ 116 | ok(true); 117 | start(); 118 | }, 500); 119 | } 120 | }); 121 | 122 | asyncTest("module with async teardown", function() { 123 | expect(2); 124 | ok(true); 125 | start(); 126 | }); 127 | 128 | module("asyncTest"); 129 | 130 | asyncTest("asyncTest", function() { 131 | expect(2); 132 | ok(true); 133 | setTimeout(function() { 134 | state = "done"; 135 | ok(true); 136 | start(); 137 | }, 13); 138 | }); 139 | 140 | asyncTest("asyncTest", 2, function() { 141 | ok(true); 142 | setTimeout(function() { 143 | state = "done"; 144 | ok(true); 145 | start(); 146 | }, 13); 147 | }); 148 | 149 | test("sync", 2, function() { 150 | stop(); 151 | setTimeout(function() { 152 | ok(true); 153 | start(); 154 | }, 13); 155 | stop(); 156 | setTimeout(function() { 157 | ok(true); 158 | start(); 159 | }, 125); 160 | }); 161 | 162 | test("test synchronous calls to stop", 2, function() { 163 | stop(); 164 | setTimeout(function(){ 165 | ok(true, 'first'); 166 | start(); 167 | stop(); 168 | setTimeout(function(){ 169 | ok(true, 'second'); 170 | start(); 171 | }, 150); 172 | }, 150); 173 | }); 174 | } 175 | 176 | module("save scope", { 177 | setup: function() { 178 | this.foo = "bar"; 179 | }, 180 | teardown: function() { 181 | deepEqual(this.foo, "bar"); 182 | } 183 | }); 184 | test("scope check", function() { 185 | expect(2); 186 | deepEqual(this.foo, "bar"); 187 | }); 188 | 189 | module("simple testEnvironment setup", { 190 | foo: "bar", 191 | bugid: "#5311" // example of meta-data 192 | }); 193 | test("scope check", function() { 194 | deepEqual(this.foo, "bar"); 195 | }); 196 | test("modify testEnvironment",function() { 197 | this.foo="hamster"; 198 | }); 199 | test("testEnvironment reset for next test",function() { 200 | deepEqual(this.foo, "bar"); 201 | }); 202 | 203 | module("testEnvironment with object", { 204 | options:{ 205 | recipe:"soup", 206 | ingredients:["hamster","onions"] 207 | } 208 | }); 209 | test("scope check", function() { 210 | deepEqual(this.options, {recipe:"soup",ingredients:["hamster","onions"]}) ; 211 | }); 212 | test("modify testEnvironment",function() { 213 | // since we do a shallow copy, the testEnvironment can be modified 214 | this.options.ingredients.push("carrots"); 215 | }); 216 | test("testEnvironment reset for next test",function() { 217 | deepEqual(this.options, {recipe:"soup",ingredients:["hamster","onions","carrots"]}, "Is this a bug or a feature? Could do a deep copy") ; 218 | }); 219 | 220 | 221 | module("testEnvironment tests"); 222 | 223 | function makeurl() { 224 | var testEnv = QUnit.current_testEnvironment; 225 | var url = testEnv.url || 'http://example.com/search'; 226 | var q = testEnv.q || 'a search test'; 227 | return url + '?q='+encodeURIComponent(q); 228 | } 229 | 230 | test("makeurl working",function() { 231 | equal( QUnit.current_testEnvironment, this, 'The current testEnvironment is global'); 232 | equal( makeurl(), 'http://example.com/search?q=a%20search%20test', 'makeurl returns a default url if nothing specified in the testEnvironment'); 233 | }); 234 | 235 | module("testEnvironment with makeurl settings", { 236 | url: 'http://google.com/', 237 | q: 'another_search_test' 238 | }); 239 | test("makeurl working with settings from testEnvironment", function() { 240 | equal( makeurl(), 'http://google.com/?q=another_search_test', 'rather than passing arguments, we use test metadata to form the url'); 241 | }); 242 | test("each test can extend the module testEnvironment", { 243 | q:'hamstersoup' 244 | }, function() { 245 | equal( makeurl(), 'http://google.com/?q=hamstersoup', 'url from module, q from test'); 246 | }); 247 | 248 | module("jsDump"); 249 | test("jsDump output", function() { 250 | equal( QUnit.jsDump.parse([1, 2]), "[\n 1,\n 2\n]" ); 251 | equal( QUnit.jsDump.parse({top: 5, left: 0}), "{\n \"top\": 5,\n \"left\": 0\n}" ); 252 | if (typeof document !== 'undefined' && document.getElementById("qunit-header")) { 253 | equal( QUnit.jsDump.parse(document.getElementById("qunit-header")), "

                        " ); 254 | equal( QUnit.jsDump.parse(document.getElementsByTagName("h1")), "[\n

                        \n]" ); 255 | } 256 | }); 257 | 258 | module("assertions"); 259 | test("raises",function() { 260 | function CustomError( message ) { 261 | this.message = message; 262 | } 263 | 264 | CustomError.prototype.toString = function() { 265 | return this.message; 266 | }; 267 | 268 | raises( 269 | function() { 270 | throw "error" 271 | } 272 | ); 273 | 274 | raises( 275 | function() { 276 | throw "error" 277 | }, 278 | 'raises with just a message, no expected' 279 | ); 280 | 281 | raises( 282 | function() { 283 | throw new CustomError(); 284 | }, 285 | CustomError, 286 | 'raised error is an instance of CustomError' 287 | ); 288 | 289 | raises( 290 | function() { 291 | throw new CustomError("some error description"); 292 | }, 293 | /description/, 294 | "raised error message contains 'description'" 295 | ); 296 | 297 | raises( 298 | function() { 299 | throw new CustomError("some error description"); 300 | }, 301 | function( err ) { 302 | if ( (err instanceof CustomError) && /description/.test(err) ) { 303 | return true; 304 | } 305 | }, 306 | "custom validation function" 307 | ); 308 | 309 | }); 310 | 311 | if (typeof document !== "undefined") { 312 | 313 | module("fixture"); 314 | test("setup", function() { 315 | document.getElementById("qunit-fixture").innerHTML = "foobar"; 316 | }); 317 | test("basics", function() { 318 | equal( document.getElementById("qunit-fixture").innerHTML, "test markup", "automatically reset" ); 319 | }); 320 | 321 | } 322 | 323 | module("custom assertions"); 324 | (function() { 325 | function mod2(value, expected, message) { 326 | var actual = value % 2; 327 | QUnit.push(actual == expected, actual, expected, message); 328 | } 329 | test("mod2", function() { 330 | mod2(2, 0, "2 % 2 == 0"); 331 | mod2(3, 1, "3 % 2 == 1"); 332 | }) 333 | })(); 334 | 335 | 336 | module("recursions"); 337 | 338 | function Wrap(x) { 339 | this.wrap = x; 340 | if (x == undefined) this.first = true; 341 | } 342 | 343 | function chainwrap(depth, first, prev) { 344 | depth = depth || 0; 345 | var last = prev || new Wrap(); 346 | first = first || last; 347 | 348 | if (depth == 1) { 349 | first.wrap = last; 350 | } 351 | if (depth > 1) { 352 | last = chainwrap(depth-1, first, new Wrap(last)); 353 | } 354 | 355 | return last; 356 | } 357 | 358 | test("check jsDump recursion", function() { 359 | expect(4); 360 | 361 | var noref = chainwrap(0); 362 | var nodump = QUnit.jsDump.parse(noref); 363 | equal(nodump, '{\n "wrap": undefined,\n "first": true\n}'); 364 | 365 | var selfref = chainwrap(1); 366 | var selfdump = QUnit.jsDump.parse(selfref); 367 | equal(selfdump, '{\n "wrap": recursion(-1),\n "first": true\n}'); 368 | 369 | var parentref = chainwrap(2); 370 | var parentdump = QUnit.jsDump.parse(parentref); 371 | equal(parentdump, '{\n "wrap": {\n "wrap": recursion(-2),\n "first": true\n }\n}'); 372 | 373 | var circref = chainwrap(10); 374 | var circdump = QUnit.jsDump.parse(circref); 375 | ok(new RegExp("recursion\\(-10\\)").test(circdump), "(" +circdump + ") should show -10 recursion level"); 376 | }); 377 | 378 | test("check (deep-)equal recursion", function() { 379 | var noRecursion = chainwrap(0); 380 | equal(noRecursion, noRecursion, "I should be equal to me."); 381 | deepEqual(noRecursion, noRecursion, "... and so in depth."); 382 | 383 | var selfref = chainwrap(1); 384 | equal(selfref, selfref, "Even so if I nest myself."); 385 | deepEqual(selfref, selfref, "... into the depth."); 386 | 387 | var circref = chainwrap(10); 388 | equal(circref, circref, "Or hide that through some levels of indirection."); 389 | deepEqual(circref, circref, "... and checked on all levels!"); 390 | }); 391 | 392 | 393 | test('Circular reference with arrays', function() { 394 | 395 | // pure array self-ref 396 | var arr = []; 397 | arr.push(arr); 398 | 399 | var arrdump = QUnit.jsDump.parse(arr); 400 | 401 | equal(arrdump, '[\n recursion(-1)\n]'); 402 | equal(arr, arr[0], 'no endless stack when trying to dump arrays with circular ref'); 403 | 404 | 405 | // mix obj-arr circular ref 406 | var obj = {}; 407 | var childarr = [obj]; 408 | obj.childarr = childarr; 409 | 410 | var objdump = QUnit.jsDump.parse(obj); 411 | var childarrdump = QUnit.jsDump.parse(childarr); 412 | 413 | equal(objdump, '{\n "childarr": [\n recursion(-2)\n ]\n}'); 414 | equal(childarrdump, '[\n {\n "childarr": recursion(-2)\n }\n]'); 415 | 416 | equal(obj.childarr, childarr, 'no endless stack when trying to dump array/object mix with circular ref'); 417 | equal(childarr[0], obj, 'no endless stack when trying to dump array/object mix with circular ref'); 418 | 419 | }); 420 | 421 | 422 | test('Circular reference - test reported by soniciq in #105', function() { 423 | var MyObject = function() {}; 424 | MyObject.prototype.parent = function(obj) { 425 | if (obj === undefined) { return this._parent; } 426 | this._parent = obj; 427 | }; 428 | MyObject.prototype.children = function(obj) { 429 | if (obj === undefined) { return this._children; } 430 | this._children = obj; 431 | }; 432 | 433 | var a = new MyObject(), 434 | b = new MyObject(); 435 | 436 | var barr = [b]; 437 | a.children(barr); 438 | b.parent(a); 439 | 440 | equal(a.children(), barr); 441 | deepEqual(a.children(), [b]); 442 | }); 443 | 444 | 445 | 446 | 447 | (function() { 448 | var reset = QUnit.reset; 449 | function afterTest() { 450 | ok( false, "reset should not modify test status" ); 451 | } 452 | module("reset"); 453 | test("reset runs assertions", function() { 454 | QUnit.reset = function() { 455 | afterTest(); 456 | reset.apply( this, arguments ); 457 | }; 458 | }); 459 | test("reset runs assertions2", function() { 460 | QUnit.reset = reset; 461 | }); 462 | })(); 463 | 464 | if (typeof setTimeout !== 'undefined') { 465 | function testAfterDone(){ 466 | var testName = "ensure has correct number of assertions"; 467 | 468 | function secondAfterDoneTest(){ 469 | QUnit.config.done = []; 470 | //QUnit.done = function(){}; 471 | //because when this does happen, the assertion count parameter doesn't actually 472 | //work we use this test to check the assertion count. 473 | module("check previous test's assertion counts"); 474 | test('count previous two test\'s assertions', function(){ 475 | var spans = document.getElementsByTagName('span'), 476 | tests = [], 477 | countNodes; 478 | 479 | //find these two tests 480 | for (var i = 0; i < spans.length; i++) { 481 | if (spans[i].innerHTML.indexOf(testName) !== -1) { 482 | tests.push(spans[i]); 483 | } 484 | } 485 | 486 | //walk dom to counts 487 | countNodes = tests[0].nextSibling.nextSibling.getElementsByTagName('b'); 488 | equal(countNodes[1].innerHTML, "99"); 489 | countNodes = tests[1].nextSibling.nextSibling.getElementsByTagName('b'); 490 | equal(countNodes[1].innerHTML, "99"); 491 | }); 492 | } 493 | QUnit.config.done = []; 494 | QUnit.done(secondAfterDoneTest); 495 | 496 | module("Synchronous test after load of page"); 497 | 498 | asyncTest('Async test', function(){ 499 | start(); 500 | for (var i = 1; i < 100; i++) { 501 | ok(i); 502 | } 503 | }); 504 | 505 | test(testName, 99, function(){ 506 | for (var i = 1; i < 100; i++) { 507 | ok(i); 508 | } 509 | }); 510 | 511 | //we need two of these types of tests in order to ensure that assertions 512 | //don't move between tests. 513 | test(testName + ' 2', 99, function(){ 514 | for (var i = 1; i < 100; i++) { 515 | ok(i); 516 | } 517 | }); 518 | 519 | 520 | } 521 | 522 | QUnit.done(testAfterDone); 523 | 524 | } 525 | -------------------------------------------------------------------------------- /strftime.js: -------------------------------------------------------------------------------- 1 | // version 0.11 by Daniel Rench 2 | // More information: http://dren.ch/strftime/ 3 | // This is public domain software 4 | // 5 | // Some modification by tokuhirom. 6 | // Tokuhirom's modifications are public domain, too. 7 | (function () { 8 | "use strict"; 9 | 10 | function pad (d, n, p) { 11 | var s = '' + d; 12 | p = p || '0'; 13 | while (s.length < n) s = p + s; 14 | return s; 15 | } 16 | 17 | var locales = { 18 | en: { 19 | A: [ 20 | 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 21 | 'Thursday', 'Friday', 'Saturday' 22 | ], 23 | a: [ 24 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 25 | ], 26 | B: [ 27 | 'January', 'February', 'March', 'April', 'May', 'June', 'July', 28 | 'August', 'September', 'October', 'November', 'December' 29 | ], 30 | b: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 31 | }, 32 | ja: { 33 | B: [" 1月", " 2月", " 3月", " 4月", " 5月", " 6月", " 7月", " 8月", " 9月", "10月", "11月", "12月"], 34 | b: [" 1月", " 2月", " 3月", " 4月", " 5月", " 6月", " 7月", " 8月", " 9月", "10月", "11月", "12月"], 35 | A: ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"], 36 | a: ["日", "月", "火", "水", "木", "金", "土"] 37 | } 38 | }; 39 | 40 | var formats = { 41 | A: function (d, locale) { return locales[locale].A[d.getDay()]; }, 42 | a: function (d, locale) { return locales[locale].a[d.getDay()]; }, 43 | B: function (d, locale) { return locales[locale].B[d.getMonth()]; }, 44 | b: function (d, locale) { return locales[locale].b[d.getMonth()]; }, 45 | C: function (d) { return Math.floor(d.getFullYear()/100); }, 46 | c: function (d) { return d.toString(); }, 47 | D: function (d) { 48 | return formats.m(d) + '/' + 49 | formats.d(d) + '/' + formats.y(d); 50 | }, 51 | d: function (d) { return pad(d.getDate(), 2,'0'); }, 52 | e: function (d) { return pad(d.getDate(), 2,' '); }, 53 | F: function (d) { 54 | return formats.Y(d) + '-' + formats.m(d) + '-' + 55 | formats.d(d); 56 | }, 57 | H: function (d) { return pad(d.getHours(), 2,'0'); }, 58 | I: function (d) { return pad((d.getHours() % 12 || 12), 2); }, 59 | /* 60 | %g 61 | like %G, but without the century 62 | %G 63 | The 4-digit year corresponding to the ISO week number 64 | %j 65 | day of the year as a decimal number (range 001 to 366) 66 | %U 67 | week number of the current year as a decimal number, starting with the first Sunday as the first day of the first week 68 | %V 69 | The ISO 8601:1988 week number of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the current year, and with Monday as the first day of the week. 70 | %W 71 | week number of the current year as a decimal number, starting with the first Monday as the first day of the first week 72 | %Z 73 | time zone name or abbreviation 74 | 75 | j: function (d) { 76 | var t = d.getDate(); 77 | var m = d.getMonth() - 1; 78 | if (m > 1) { 79 | var y = d.getYear(); 80 | if (((y % 100) == 0) && ((y % 400) == 0)) ++t; 81 | else if ((y % 4) == 0) ++t; 82 | } 83 | while (m > -1) t += d.dpm[m--]; 84 | return t.pad(3,'0'); 85 | }, 86 | */ 87 | k: function (d) { return pad(d.getHours(), 2,' '); }, 88 | l: function (d) { return pad((d.getHours() % 12 || 12), 2,' '); }, 89 | M: function (d) { return pad(d.getMinutes(), 2,'0'); }, 90 | m: function (d) { return pad((d.getMonth()+1), 2,'0'); }, 91 | n: function (d) { return "\n"; }, 92 | p: function (d) { return (d.getHours() > 11) ? 'PM' : 'AM'; }, 93 | P: function (d) { return formats.p(d).toLowerCase(); }, 94 | R: function (d) { return formats.H(d) + ':' + formats.M(d); }, 95 | r: function (d) { 96 | return formats.I(d) + ':' + formats.M(d) + ':' + 97 | formats.S(d) + ' ' + formats.p(d); 98 | }, 99 | S: function (d) { return pad(d.getSeconds(), 2,'0'); }, 100 | s: function (d) { return Math.floor(d.getTime()/1000); }, 101 | T: function (d) { 102 | return formats.H(d) + ':' + formats.M(d) + ':' + 103 | formats.S(d); 104 | }, 105 | t: function (d) { return "\t"; }, 106 | /* U: function (d) { return false; }, */ 107 | u: function (d) { return(d.getDay() || 7); }, 108 | /* V: function (d) { return false; }, */ 109 | v: function (d) { 110 | return formats.e(d) + '-' + formats.b(d) + '-' + 111 | formats.Y(d); 112 | }, 113 | /* W: function (d) { return false; }, */ 114 | w: function (d) { return d.getDay(); }, 115 | X: function (d) { return d.toTimeString(); }, // wrong? 116 | x: function (d) { return d.toDateString(); }, // wrong? 117 | Y: function (d) { return d.getFullYear(); }, 118 | y: function (d) { return pad((d.getYear() % 100), 2); }, 119 | // Z: function (d) { return d.toString().match(/\((.+)\)$/)[1]; }, 120 | // z: function (d) { return d.getTimezoneOffset(); }, // wrong 121 | // z: function (d) { return d.toString().match(/\sGMT([+-]\d+)/)[1]; }, 122 | '%': function (d) { return '%'; } 123 | }; 124 | 125 | formats['+'] = formats.c; 126 | formats.h = formats.b; 127 | 128 | var defaultLocale = 'en'; 129 | 130 | function strftime(date, fmt, locale) { 131 | var r = ''; 132 | var n = 0; 133 | if (!locale) { locale = defaultLocale; } 134 | while(n < fmt.length) { 135 | var c = fmt.substring(n, n+1); 136 | if (c == '%') { 137 | c = fmt.substring(++n, n+1); 138 | r += (formats[c]) ? formats[c](date, locale) : c; 139 | } else r += c; 140 | ++n; 141 | } 142 | return r; 143 | } 144 | 145 | Date.prototype.strftime = function (fmt, locale) { 146 | return strftime(this, fmt, locale); 147 | }; 148 | 149 | Date.prototype.strftime.formats = formats; 150 | Date.prototype.strftime.setDefaultLocale = function (locale) { 151 | defaultLocale = locale; 152 | }; 153 | Date.prototype.strftime.locales = locales; 154 | 155 | })(); 156 | -------------------------------------------------------------------------------- /t/01_strftime.js: -------------------------------------------------------------------------------- 1 | var d = new Date(2011, 8, 1, 10, 4, 1); 2 | is(d.strftime('%Y-%m-%d'), '2011-09-01'); 3 | is(d.strftime('%T'), '10:04:01'); 4 | is(d.strftime('%%'), '%'); 5 | is(d.strftime('%e'), ' 1'); 6 | is(d.strftime('%H'), '10'); 7 | is(d.strftime('%I'), '10'); 8 | is(d.strftime('%k'), '10'); 9 | is(d.strftime('%M'), '04', '%M'); 10 | is(d.strftime('%m'), '09'); 11 | is(d.strftime('%S'), '01'); 12 | is(d.strftime('%y'), '11'); 13 | is(d.strftime('%+'), 'Thu Sep 01 2011 10:04:01 GMT+0900 (JST)'); 14 | is(d.strftime('%h'), 'Sep'); 15 | 16 | is(d.strftime('%A'), 'Thursday'); 17 | is(d.strftime('%a'), 'Thu'); 18 | is(d.strftime('%B'), 'September'); 19 | is(d.strftime('%b'), 'Sep'); 20 | is(d.strftime('%d'), '01', '%d'); 21 | 22 | Date.prototype.strftime.locales['de'] = { 23 | B: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], 24 | b: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], 25 | A: ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"], 26 | a: ["Mo\.", "Di\.", "Mi\.", "Do\.", "Fr\.", "Sa\.", "So\."] 27 | }; 28 | 29 | is(d.strftime('%A', 'ja'), '木曜日'); 30 | is(d.strftime('%a', 'ja'), '木'); 31 | is(d.strftime('%B', 'ja'), ' 9月'); 32 | is(d.strftime('%b', 'ja'), ' 9月'); 33 | 34 | is(d.strftime('%A', 'de'), 'Freitag'); 35 | is(d.strftime('%a', 'de'), 'Fr.'); 36 | is(d.strftime('%B', 'de'), 'September'); 37 | is(d.strftime('%b', 'de'), 'Sep'); 38 | 39 | // custom formats 40 | is(d.strftime('%z'), 'z'); 41 | Date.prototype.strftime.formats.z = function () { return '+0900' }; 42 | is(d.strftime('%z'), '+0900'); 43 | 44 | // %P %p 45 | (function () { 46 | var d = (new Date(2011, 8, 1, 10, 4, 1)); 47 | d.setHours(10); 48 | is(d.strftime('%p'), 'AM'); 49 | is(d.strftime('%P'), 'am'); 50 | is(d.strftime('%r'), '10:04:01 AM'); 51 | is(d.strftime('%R'), '10:04'); 52 | is(d.strftime('%s'), '1314839041'); 53 | is(d.strftime('%S'), '01'); 54 | is(d.strftime('%t'), "\t"); 55 | is(d.strftime('%T'), '10:04:01'); 56 | is(d.strftime('%u'), '4'); 57 | is(d.strftime('%w'), '4'); 58 | is(d.strftime('%x'), 'Thu Sep 01 2011'); 59 | is(d.strftime('%X'), '10:04:01 GMT+0900 (JST)'); 60 | is(d.strftime('%Y'), '2011'); 61 | is(d.strftime('%y'), '11'); 62 | is(d.strftime('%z'), '+0900'); 63 | 64 | d.setHours(13); 65 | is(d.strftime('%p'), 'PM'); 66 | is(d.strftime('%P'), 'pm'); 67 | is(d.strftime('%r'), '01:04:01 PM'); 68 | })(); 69 | 70 | (function () { 71 | Date.prototype.strftime.setDefaultLocale('ja'); 72 | var d = (new Date(2011, 8, 1, 10, 4, 1)); 73 | is(d.strftime('%a'), '木'); 74 | })(); 75 | -------------------------------------------------------------------------------- /t/lib/test-more.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | var global = this; 4 | var sys = require('sys'); 5 | 6 | var n = 1; 7 | global.ok = function ok(b, message) { 8 | var ret = (b ? 'ok' : 'not ok') + ' ' + n; 9 | if (typeof message !== 'undefined') { 10 | ret += ' # ' + message; 11 | } 12 | sys.puts(ret); 13 | n++; 14 | return b; 15 | } 16 | global.is = function is(got, expected, message) { 17 | if (ok(got === expected, message)) { 18 | return true; 19 | } 20 | sys.puts(" # Got : " + got); 21 | sys.puts(" # Expected : " + expected); 22 | return false; 23 | } 24 | global.done_testing = function done_testing() { 25 | sys.puts('1..' + (n-1)); 26 | } 27 | 28 | })(); 29 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Test Suite 6 | 7 | 8 | 9 | 10 | 21 | 22 | 23 |

                        QUnit Test Suite

                        24 |

                        25 |
                        26 |

                        27 |
                          28 |
                          test markup
                          29 | 30 | 31 | -------------------------------------------------------------------------------- /test/node-test.js: -------------------------------------------------------------------------------- 1 | var QUnit = require('./qunit').QUnit, 2 | qunitTap = require('qunit-tap').qunitTap, 3 | sys = require('sys'), 4 | fs = require('fs'); 5 | 6 | qunitTap(QUnit, sys.puts, {noPlan: true}); 7 | 8 | QUnit.init(); 9 | QUnit.config.updateRate = 0; 10 | 11 | require('../strftime'); 12 | with ({is: QUnit.equal, subtest: QUnit.test}) { 13 | var content = fs.readFileSync('t/01_strftime.js', 'utf-8'); 14 | subtest('strftime', function () { 15 | eval(content); 16 | }); 17 | } 18 | 19 | QUnit.start(); 20 | -------------------------------------------------------------------------------- /test/qunit-git.css: -------------------------------------------------------------------------------- 1 | /** 2 | * QUnit v1.3.0pre - A JavaScript Unit Testing Framework 3 | * 4 | * http://docs.jquery.com/QUnit 5 | * 6 | * Copyright (c) 2011 John Resig, Jörn Zaefferer 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * or GPL (GPL-LICENSE.txt) licenses. 9 | * Pulled Live from Git Sun Dec 4 04:30:01 UTC 2011 10 | * Last Commit: c319c356cb4942a16ea62e5b9020044e7d97c1b9 11 | */ 12 | 13 | /** Font Family and Sizes */ 14 | 15 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 16 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; 17 | } 18 | 19 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 20 | #qunit-tests { font-size: smaller; } 21 | 22 | 23 | /** Resets */ 24 | 25 | #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { 26 | margin: 0; 27 | padding: 0; 28 | } 29 | 30 | 31 | /** Header */ 32 | 33 | #qunit-header { 34 | padding: 0.5em 0 0.5em 1em; 35 | 36 | color: #8699a4; 37 | background-color: #0d3349; 38 | 39 | font-size: 1.5em; 40 | line-height: 1em; 41 | font-weight: normal; 42 | 43 | border-radius: 15px 15px 0 0; 44 | -moz-border-radius: 15px 15px 0 0; 45 | -webkit-border-top-right-radius: 15px; 46 | -webkit-border-top-left-radius: 15px; 47 | } 48 | 49 | #qunit-header a { 50 | text-decoration: none; 51 | color: #c2ccd1; 52 | } 53 | 54 | #qunit-header a:hover, 55 | #qunit-header a:focus { 56 | color: #fff; 57 | } 58 | 59 | #qunit-banner { 60 | height: 5px; 61 | } 62 | 63 | #qunit-testrunner-toolbar { 64 | padding: 0.5em 0 0.5em 2em; 65 | color: #5E740B; 66 | background-color: #eee; 67 | } 68 | 69 | #qunit-userAgent { 70 | padding: 0.5em 0 0.5em 2.5em; 71 | background-color: #2b81af; 72 | color: #fff; 73 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 74 | } 75 | 76 | 77 | /** Tests: Pass/Fail */ 78 | 79 | #qunit-tests { 80 | list-style-position: inside; 81 | } 82 | 83 | #qunit-tests li { 84 | padding: 0.4em 0.5em 0.4em 2.5em; 85 | border-bottom: 1px solid #fff; 86 | list-style-position: inside; 87 | } 88 | 89 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { 90 | display: none; 91 | } 92 | 93 | #qunit-tests li strong { 94 | cursor: pointer; 95 | } 96 | 97 | #qunit-tests li a { 98 | padding: 0.5em; 99 | color: #c2ccd1; 100 | text-decoration: none; 101 | } 102 | #qunit-tests li a:hover, 103 | #qunit-tests li a:focus { 104 | color: #000; 105 | } 106 | 107 | #qunit-tests ol { 108 | margin-top: 0.5em; 109 | padding: 0.5em; 110 | 111 | background-color: #fff; 112 | 113 | border-radius: 15px; 114 | -moz-border-radius: 15px; 115 | -webkit-border-radius: 15px; 116 | 117 | box-shadow: inset 0px 2px 13px #999; 118 | -moz-box-shadow: inset 0px 2px 13px #999; 119 | -webkit-box-shadow: inset 0px 2px 13px #999; 120 | } 121 | 122 | #qunit-tests table { 123 | border-collapse: collapse; 124 | margin-top: .2em; 125 | } 126 | 127 | #qunit-tests th { 128 | text-align: right; 129 | vertical-align: top; 130 | padding: 0 .5em 0 0; 131 | } 132 | 133 | #qunit-tests td { 134 | vertical-align: top; 135 | } 136 | 137 | #qunit-tests pre { 138 | margin: 0; 139 | white-space: pre-wrap; 140 | word-wrap: break-word; 141 | } 142 | 143 | #qunit-tests del { 144 | background-color: #e0f2be; 145 | color: #374e0c; 146 | text-decoration: none; 147 | } 148 | 149 | #qunit-tests ins { 150 | background-color: #ffcaca; 151 | color: #500; 152 | text-decoration: none; 153 | } 154 | 155 | /*** Test Counts */ 156 | 157 | #qunit-tests b.counts { color: black; } 158 | #qunit-tests b.passed { color: #5E740B; } 159 | #qunit-tests b.failed { color: #710909; } 160 | 161 | #qunit-tests li li { 162 | margin: 0.5em; 163 | padding: 0.4em 0.5em 0.4em 0.5em; 164 | background-color: #fff; 165 | border-bottom: none; 166 | list-style-position: inside; 167 | } 168 | 169 | /*** Passing Styles */ 170 | 171 | #qunit-tests li li.pass { 172 | color: #5E740B; 173 | background-color: #fff; 174 | border-left: 26px solid #C6E746; 175 | } 176 | 177 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } 178 | #qunit-tests .pass .test-name { color: #366097; } 179 | 180 | #qunit-tests .pass .test-actual, 181 | #qunit-tests .pass .test-expected { color: #999999; } 182 | 183 | #qunit-banner.qunit-pass { background-color: #C6E746; } 184 | 185 | /*** Failing Styles */ 186 | 187 | #qunit-tests li li.fail { 188 | color: #710909; 189 | background-color: #fff; 190 | border-left: 26px solid #EE5757; 191 | white-space: pre; 192 | } 193 | 194 | #qunit-tests > li:last-child { 195 | border-radius: 0 0 15px 15px; 196 | -moz-border-radius: 0 0 15px 15px; 197 | -webkit-border-bottom-right-radius: 15px; 198 | -webkit-border-bottom-left-radius: 15px; 199 | } 200 | 201 | #qunit-tests .fail { color: #000000; background-color: #EE5757; } 202 | #qunit-tests .fail .test-name, 203 | #qunit-tests .fail .module-name { color: #000000; } 204 | 205 | #qunit-tests .fail .test-actual { color: #EE5757; } 206 | #qunit-tests .fail .test-expected { color: green; } 207 | 208 | #qunit-banner.qunit-fail { background-color: #EE5757; } 209 | 210 | 211 | /** Result */ 212 | 213 | #qunit-testresult { 214 | padding: 0.5em 0.5em 0.5em 2.5em; 215 | 216 | color: #2b81af; 217 | background-color: #D2E0E6; 218 | 219 | border-bottom: 1px solid white; 220 | } 221 | 222 | /** Fixture */ 223 | 224 | #qunit-fixture { 225 | position: absolute; 226 | top: -10000px; 227 | left: -10000px; 228 | } 229 | -------------------------------------------------------------------------------- /test/qunit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * QUnit v1.3.0pre - A JavaScript Unit Testing Framework 3 | * 4 | * http://docs.jquery.com/QUnit 5 | * 6 | * Copyright (c) 2011 John Resig, Jörn Zaefferer 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * or GPL (GPL-LICENSE.txt) licenses. 9 | */ 10 | 11 | (function(window) { 12 | 13 | var defined = { 14 | setTimeout: typeof window.setTimeout !== "undefined", 15 | sessionStorage: (function() { 16 | try { 17 | return !!sessionStorage.getItem; 18 | } catch(e) { 19 | return false; 20 | } 21 | })() 22 | }; 23 | 24 | var testId = 0, 25 | toString = Object.prototype.toString, 26 | hasOwn = Object.prototype.hasOwnProperty; 27 | 28 | var Test = function(name, testName, expected, testEnvironmentArg, async, callback) { 29 | this.name = name; 30 | this.testName = testName; 31 | this.expected = expected; 32 | this.testEnvironmentArg = testEnvironmentArg; 33 | this.async = async; 34 | this.callback = callback; 35 | this.assertions = []; 36 | }; 37 | Test.prototype = { 38 | init: function() { 39 | var tests = id("qunit-tests"); 40 | if (tests) { 41 | var b = document.createElement("strong"); 42 | b.innerHTML = "Running " + this.name; 43 | var li = document.createElement("li"); 44 | li.appendChild( b ); 45 | li.className = "running"; 46 | li.id = this.id = "test-output" + testId++; 47 | tests.appendChild( li ); 48 | } 49 | }, 50 | setup: function() { 51 | if (this.module != config.previousModule) { 52 | if ( config.previousModule ) { 53 | runLoggingCallbacks('moduleDone', QUnit, { 54 | name: config.previousModule, 55 | failed: config.moduleStats.bad, 56 | passed: config.moduleStats.all - config.moduleStats.bad, 57 | total: config.moduleStats.all 58 | } ); 59 | } 60 | config.previousModule = this.module; 61 | config.moduleStats = { all: 0, bad: 0 }; 62 | runLoggingCallbacks( 'moduleStart', QUnit, { 63 | name: this.module 64 | } ); 65 | } 66 | 67 | config.current = this; 68 | this.testEnvironment = extend({ 69 | setup: function() {}, 70 | teardown: function() {} 71 | }, this.moduleTestEnvironment); 72 | if (this.testEnvironmentArg) { 73 | extend(this.testEnvironment, this.testEnvironmentArg); 74 | } 75 | 76 | runLoggingCallbacks( 'testStart', QUnit, { 77 | name: this.testName, 78 | module: this.module 79 | }); 80 | 81 | // allow utility functions to access the current test environment 82 | // TODO why?? 83 | QUnit.current_testEnvironment = this.testEnvironment; 84 | 85 | try { 86 | if ( !config.pollution ) { 87 | saveGlobal(); 88 | } 89 | 90 | this.testEnvironment.setup.call(this.testEnvironment); 91 | } catch(e) { 92 | QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message ); 93 | } 94 | }, 95 | run: function() { 96 | config.current = this; 97 | if ( this.async ) { 98 | QUnit.stop(); 99 | } 100 | 101 | if ( config.notrycatch ) { 102 | this.callback.call(this.testEnvironment); 103 | return; 104 | } 105 | try { 106 | this.callback.call(this.testEnvironment); 107 | } catch(e) { 108 | fail("Test " + this.testName + " died, exception and test follows", e, this.callback); 109 | QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) ); 110 | // else next test will carry the responsibility 111 | saveGlobal(); 112 | 113 | // Restart the tests if they're blocking 114 | if ( config.blocking ) { 115 | QUnit.start(); 116 | } 117 | } 118 | }, 119 | teardown: function() { 120 | config.current = this; 121 | try { 122 | this.testEnvironment.teardown.call(this.testEnvironment); 123 | checkPollution(); 124 | } catch(e) { 125 | QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message ); 126 | } 127 | }, 128 | finish: function() { 129 | config.current = this; 130 | if ( this.expected != null && this.expected != this.assertions.length ) { 131 | QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); 132 | } 133 | 134 | var good = 0, bad = 0, 135 | tests = id("qunit-tests"); 136 | 137 | config.stats.all += this.assertions.length; 138 | config.moduleStats.all += this.assertions.length; 139 | 140 | if ( tests ) { 141 | var ol = document.createElement("ol"); 142 | 143 | for ( var i = 0; i < this.assertions.length; i++ ) { 144 | var assertion = this.assertions[i]; 145 | 146 | var li = document.createElement("li"); 147 | li.className = assertion.result ? "pass" : "fail"; 148 | li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); 149 | ol.appendChild( li ); 150 | 151 | if ( assertion.result ) { 152 | good++; 153 | } else { 154 | bad++; 155 | config.stats.bad++; 156 | config.moduleStats.bad++; 157 | } 158 | } 159 | 160 | // store result when possible 161 | if ( QUnit.config.reorder && defined.sessionStorage ) { 162 | if (bad) { 163 | sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad); 164 | } else { 165 | sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName); 166 | } 167 | } 168 | 169 | if (bad == 0) { 170 | ol.style.display = "none"; 171 | } 172 | 173 | var b = document.createElement("strong"); 174 | b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; 175 | 176 | var a = document.createElement("a"); 177 | a.innerHTML = "Rerun"; 178 | a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); 179 | 180 | addEvent(b, "click", function() { 181 | var next = b.nextSibling.nextSibling, 182 | display = next.style.display; 183 | next.style.display = display === "none" ? "block" : "none"; 184 | }); 185 | 186 | addEvent(b, "dblclick", function(e) { 187 | var target = e && e.target ? e.target : window.event.srcElement; 188 | if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { 189 | target = target.parentNode; 190 | } 191 | if ( window.location && target.nodeName.toLowerCase() === "strong" ) { 192 | window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); 193 | } 194 | }); 195 | 196 | var li = id(this.id); 197 | li.className = bad ? "fail" : "pass"; 198 | li.removeChild( li.firstChild ); 199 | li.appendChild( b ); 200 | li.appendChild( a ); 201 | li.appendChild( ol ); 202 | 203 | } else { 204 | for ( var i = 0; i < this.assertions.length; i++ ) { 205 | if ( !this.assertions[i].result ) { 206 | bad++; 207 | config.stats.bad++; 208 | config.moduleStats.bad++; 209 | } 210 | } 211 | } 212 | 213 | try { 214 | QUnit.reset(); 215 | } catch(e) { 216 | fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset); 217 | } 218 | 219 | runLoggingCallbacks( 'testDone', QUnit, { 220 | name: this.testName, 221 | module: this.module, 222 | failed: bad, 223 | passed: this.assertions.length - bad, 224 | total: this.assertions.length 225 | } ); 226 | }, 227 | 228 | queue: function() { 229 | var test = this; 230 | synchronize(function() { 231 | test.init(); 232 | }); 233 | function run() { 234 | // each of these can by async 235 | synchronize(function() { 236 | test.setup(); 237 | }); 238 | synchronize(function() { 239 | test.run(); 240 | }); 241 | synchronize(function() { 242 | test.teardown(); 243 | }); 244 | synchronize(function() { 245 | test.finish(); 246 | }); 247 | } 248 | // defer when previous test run passed, if storage is available 249 | var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName); 250 | if (bad) { 251 | run(); 252 | } else { 253 | synchronize(run, true); 254 | }; 255 | } 256 | 257 | }; 258 | 259 | var QUnit = { 260 | 261 | // call on start of module test to prepend name to all tests 262 | module: function(name, testEnvironment) { 263 | config.currentModule = name; 264 | config.currentModuleTestEnviroment = testEnvironment; 265 | }, 266 | 267 | asyncTest: function(testName, expected, callback) { 268 | if ( arguments.length === 2 ) { 269 | callback = expected; 270 | expected = null; 271 | } 272 | 273 | QUnit.test(testName, expected, callback, true); 274 | }, 275 | 276 | test: function(testName, expected, callback, async) { 277 | var name = '' + testName + '', testEnvironmentArg; 278 | 279 | if ( arguments.length === 2 ) { 280 | callback = expected; 281 | expected = null; 282 | } 283 | // is 2nd argument a testEnvironment? 284 | if ( expected && typeof expected === 'object') { 285 | testEnvironmentArg = expected; 286 | expected = null; 287 | } 288 | 289 | if ( config.currentModule ) { 290 | name = '' + config.currentModule + ": " + name; 291 | } 292 | 293 | if ( !validTest(config.currentModule + ": " + testName) ) { 294 | return; 295 | } 296 | 297 | var test = new Test(name, testName, expected, testEnvironmentArg, async, callback); 298 | test.module = config.currentModule; 299 | test.moduleTestEnvironment = config.currentModuleTestEnviroment; 300 | test.queue(); 301 | }, 302 | 303 | /** 304 | * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. 305 | */ 306 | expect: function(asserts) { 307 | config.current.expected = asserts; 308 | }, 309 | 310 | /** 311 | * Asserts true. 312 | * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); 313 | */ 314 | ok: function(a, msg) { 315 | a = !!a; 316 | var details = { 317 | result: a, 318 | message: msg 319 | }; 320 | msg = escapeInnerText(msg); 321 | runLoggingCallbacks( 'log', QUnit, details ); 322 | config.current.assertions.push({ 323 | result: a, 324 | message: msg 325 | }); 326 | }, 327 | 328 | /** 329 | * Checks that the first two arguments are equal, with an optional message. 330 | * Prints out both actual and expected values. 331 | * 332 | * Prefered to ok( actual == expected, message ) 333 | * 334 | * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); 335 | * 336 | * @param Object actual 337 | * @param Object expected 338 | * @param String message (optional) 339 | */ 340 | equal: function(actual, expected, message) { 341 | QUnit.push(expected == actual, actual, expected, message); 342 | }, 343 | 344 | notEqual: function(actual, expected, message) { 345 | QUnit.push(expected != actual, actual, expected, message); 346 | }, 347 | 348 | deepEqual: function(actual, expected, message) { 349 | QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); 350 | }, 351 | 352 | notDeepEqual: function(actual, expected, message) { 353 | QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); 354 | }, 355 | 356 | strictEqual: function(actual, expected, message) { 357 | QUnit.push(expected === actual, actual, expected, message); 358 | }, 359 | 360 | notStrictEqual: function(actual, expected, message) { 361 | QUnit.push(expected !== actual, actual, expected, message); 362 | }, 363 | 364 | raises: function(block, expected, message) { 365 | var actual, ok = false; 366 | 367 | if (typeof expected === 'string') { 368 | message = expected; 369 | expected = null; 370 | } 371 | 372 | try { 373 | block(); 374 | } catch (e) { 375 | actual = e; 376 | } 377 | 378 | if (actual) { 379 | // we don't want to validate thrown error 380 | if (!expected) { 381 | ok = true; 382 | // expected is a regexp 383 | } else if (QUnit.objectType(expected) === "regexp") { 384 | ok = expected.test(actual); 385 | // expected is a constructor 386 | } else if (actual instanceof expected) { 387 | ok = true; 388 | // expected is a validation function which returns true is validation passed 389 | } else if (expected.call({}, actual) === true) { 390 | ok = true; 391 | } 392 | } 393 | 394 | QUnit.ok(ok, message); 395 | }, 396 | 397 | start: function(count) { 398 | config.semaphore -= count || 1; 399 | if (config.semaphore > 0) { 400 | // don't start until equal number of stop-calls 401 | return; 402 | } 403 | if (config.semaphore < 0) { 404 | // ignore if start is called more often then stop 405 | config.semaphore = 0; 406 | } 407 | // A slight delay, to avoid any current callbacks 408 | if ( defined.setTimeout ) { 409 | window.setTimeout(function() { 410 | if (config.semaphore > 0) { 411 | return; 412 | } 413 | if ( config.timeout ) { 414 | clearTimeout(config.timeout); 415 | } 416 | 417 | config.blocking = false; 418 | process(true); 419 | }, 13); 420 | } else { 421 | config.blocking = false; 422 | process(true); 423 | } 424 | }, 425 | 426 | stop: function(count) { 427 | config.semaphore += count || 1; 428 | config.blocking = true; 429 | 430 | if ( config.testTimeout && defined.setTimeout ) { 431 | clearTimeout(config.timeout); 432 | config.timeout = window.setTimeout(function() { 433 | QUnit.ok( false, "Test timed out" ); 434 | config.semaphore = 1; 435 | QUnit.start(); 436 | }, config.testTimeout); 437 | } 438 | } 439 | }; 440 | 441 | //We want access to the constructor's prototype 442 | (function() { 443 | function F(){}; 444 | F.prototype = QUnit; 445 | QUnit = new F(); 446 | //Make F QUnit's constructor so that we can add to the prototype later 447 | QUnit.constructor = F; 448 | })(); 449 | 450 | // Backwards compatibility, deprecated 451 | QUnit.equals = QUnit.equal; 452 | QUnit.same = QUnit.deepEqual; 453 | 454 | // Maintain internal state 455 | var config = { 456 | // The queue of tests to run 457 | queue: [], 458 | 459 | // block until document ready 460 | blocking: true, 461 | 462 | // when enabled, show only failing tests 463 | // gets persisted through sessionStorage and can be changed in UI via checkbox 464 | hidepassed: false, 465 | 466 | // by default, run previously failed tests first 467 | // very useful in combination with "Hide passed tests" checked 468 | reorder: true, 469 | 470 | // by default, modify document.title when suite is done 471 | altertitle: true, 472 | 473 | urlConfig: ['noglobals', 'notrycatch'], 474 | 475 | //logging callback queues 476 | begin: [], 477 | done: [], 478 | log: [], 479 | testStart: [], 480 | testDone: [], 481 | moduleStart: [], 482 | moduleDone: [] 483 | }; 484 | 485 | // Load paramaters 486 | (function() { 487 | var location = window.location || { search: "", protocol: "file:" }, 488 | params = location.search.slice( 1 ).split( "&" ), 489 | length = params.length, 490 | urlParams = {}, 491 | current; 492 | 493 | if ( params[ 0 ] ) { 494 | for ( var i = 0; i < length; i++ ) { 495 | current = params[ i ].split( "=" ); 496 | current[ 0 ] = decodeURIComponent( current[ 0 ] ); 497 | // allow just a key to turn on a flag, e.g., test.html?noglobals 498 | current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; 499 | urlParams[ current[ 0 ] ] = current[ 1 ]; 500 | } 501 | } 502 | 503 | QUnit.urlParams = urlParams; 504 | config.filter = urlParams.filter; 505 | 506 | // Figure out if we're running the tests from a server or not 507 | QUnit.isLocal = !!(location.protocol === 'file:'); 508 | })(); 509 | 510 | // Expose the API as global variables, unless an 'exports' 511 | // object exists, in that case we assume we're in CommonJS 512 | if ( typeof exports === "undefined" || typeof require === "undefined" ) { 513 | extend(window, QUnit); 514 | window.QUnit = QUnit; 515 | } else { 516 | extend(exports, QUnit); 517 | exports.QUnit = QUnit; 518 | } 519 | 520 | // define these after exposing globals to keep them in these QUnit namespace only 521 | extend(QUnit, { 522 | config: config, 523 | 524 | // Initialize the configuration options 525 | init: function() { 526 | extend(config, { 527 | stats: { all: 0, bad: 0 }, 528 | moduleStats: { all: 0, bad: 0 }, 529 | started: +new Date, 530 | updateRate: 1000, 531 | blocking: false, 532 | autostart: true, 533 | autorun: false, 534 | filter: "", 535 | queue: [], 536 | semaphore: 0 537 | }); 538 | 539 | var tests = id( "qunit-tests" ), 540 | banner = id( "qunit-banner" ), 541 | result = id( "qunit-testresult" ); 542 | 543 | if ( tests ) { 544 | tests.innerHTML = ""; 545 | } 546 | 547 | if ( banner ) { 548 | banner.className = ""; 549 | } 550 | 551 | if ( result ) { 552 | result.parentNode.removeChild( result ); 553 | } 554 | 555 | if ( tests ) { 556 | result = document.createElement( "p" ); 557 | result.id = "qunit-testresult"; 558 | result.className = "result"; 559 | tests.parentNode.insertBefore( result, tests ); 560 | result.innerHTML = 'Running...
                           '; 561 | } 562 | }, 563 | 564 | /** 565 | * Resets the test setup. Useful for tests that modify the DOM. 566 | * 567 | * If jQuery is available, uses jQuery's html(), otherwise just innerHTML. 568 | */ 569 | reset: function() { 570 | if ( window.jQuery ) { 571 | jQuery( "#qunit-fixture" ).html( config.fixture ); 572 | } else { 573 | var main = id( 'qunit-fixture' ); 574 | if ( main ) { 575 | main.innerHTML = config.fixture; 576 | } 577 | } 578 | }, 579 | 580 | /** 581 | * Trigger an event on an element. 582 | * 583 | * @example triggerEvent( document.body, "click" ); 584 | * 585 | * @param DOMElement elem 586 | * @param String type 587 | */ 588 | triggerEvent: function( elem, type, event ) { 589 | if ( document.createEvent ) { 590 | event = document.createEvent("MouseEvents"); 591 | event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, 592 | 0, 0, 0, 0, 0, false, false, false, false, 0, null); 593 | elem.dispatchEvent( event ); 594 | 595 | } else if ( elem.fireEvent ) { 596 | elem.fireEvent("on"+type); 597 | } 598 | }, 599 | 600 | // Safe object type checking 601 | is: function( type, obj ) { 602 | return QUnit.objectType( obj ) == type; 603 | }, 604 | 605 | objectType: function( obj ) { 606 | if (typeof obj === "undefined") { 607 | return "undefined"; 608 | 609 | // consider: typeof null === object 610 | } 611 | if (obj === null) { 612 | return "null"; 613 | } 614 | 615 | var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || ''; 616 | 617 | switch (type) { 618 | case 'Number': 619 | if (isNaN(obj)) { 620 | return "nan"; 621 | } else { 622 | return "number"; 623 | } 624 | case 'String': 625 | case 'Boolean': 626 | case 'Array': 627 | case 'Date': 628 | case 'RegExp': 629 | case 'Function': 630 | return type.toLowerCase(); 631 | } 632 | if (typeof obj === "object") { 633 | return "object"; 634 | } 635 | return undefined; 636 | }, 637 | 638 | push: function(result, actual, expected, message) { 639 | var details = { 640 | result: result, 641 | message: message, 642 | actual: actual, 643 | expected: expected 644 | }; 645 | 646 | message = escapeInnerText(message) || (result ? "okay" : "failed"); 647 | message = '' + message + ""; 648 | expected = escapeInnerText(QUnit.jsDump.parse(expected)); 649 | actual = escapeInnerText(QUnit.jsDump.parse(actual)); 650 | var output = message + ''; 651 | if (actual != expected) { 652 | output += ''; 653 | output += ''; 654 | } 655 | if (!result) { 656 | var source = sourceFromStacktrace(); 657 | if (source) { 658 | details.source = source; 659 | output += ''; 660 | } 661 | } 662 | output += "
                          Expected:
                          ' + expected + '
                          Result:
                          ' + actual + '
                          Diff:
                          ' + QUnit.diff(expected, actual) +'
                          Source:
                          ' + escapeInnerText(source) + '
                          "; 663 | 664 | runLoggingCallbacks( 'log', QUnit, details ); 665 | 666 | config.current.assertions.push({ 667 | result: !!result, 668 | message: output 669 | }); 670 | }, 671 | 672 | url: function( params ) { 673 | params = extend( extend( {}, QUnit.urlParams ), params ); 674 | var querystring = "?", 675 | key; 676 | for ( key in params ) { 677 | if ( !hasOwn.call( params, key ) ) { 678 | continue; 679 | } 680 | querystring += encodeURIComponent( key ) + "=" + 681 | encodeURIComponent( params[ key ] ) + "&"; 682 | } 683 | return window.location.pathname + querystring.slice( 0, -1 ); 684 | }, 685 | 686 | extend: extend, 687 | id: id, 688 | addEvent: addEvent 689 | }); 690 | 691 | //QUnit.constructor is set to the empty F() above so that we can add to it's prototype later 692 | //Doing this allows us to tell if the following methods have been overwritten on the actual 693 | //QUnit object, which is a deprecated way of using the callbacks. 694 | extend(QUnit.constructor.prototype, { 695 | // Logging callbacks; all receive a single argument with the listed properties 696 | // run test/logs.html for any related changes 697 | begin: registerLoggingCallback('begin'), 698 | // done: { failed, passed, total, runtime } 699 | done: registerLoggingCallback('done'), 700 | // log: { result, actual, expected, message } 701 | log: registerLoggingCallback('log'), 702 | // testStart: { name } 703 | testStart: registerLoggingCallback('testStart'), 704 | // testDone: { name, failed, passed, total } 705 | testDone: registerLoggingCallback('testDone'), 706 | // moduleStart: { name } 707 | moduleStart: registerLoggingCallback('moduleStart'), 708 | // moduleDone: { name, failed, passed, total } 709 | moduleDone: registerLoggingCallback('moduleDone') 710 | }); 711 | 712 | if ( typeof document === "undefined" || document.readyState === "complete" ) { 713 | config.autorun = true; 714 | } 715 | 716 | QUnit.load = function() { 717 | runLoggingCallbacks( 'begin', QUnit, {} ); 718 | 719 | // Initialize the config, saving the execution queue 720 | var oldconfig = extend({}, config); 721 | QUnit.init(); 722 | extend(config, oldconfig); 723 | 724 | config.blocking = false; 725 | 726 | var urlConfigHtml = '', len = config.urlConfig.length; 727 | for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) { 728 | config[val] = QUnit.urlParams[val]; 729 | urlConfigHtml += ''; 730 | } 731 | 732 | var userAgent = id("qunit-userAgent"); 733 | if ( userAgent ) { 734 | userAgent.innerHTML = navigator.userAgent; 735 | } 736 | var banner = id("qunit-header"); 737 | if ( banner ) { 738 | banner.innerHTML = ' ' + banner.innerHTML + ' ' + urlConfigHtml; 739 | addEvent( banner, "change", function( event ) { 740 | var params = {}; 741 | params[ event.target.name ] = event.target.checked ? true : undefined; 742 | window.location = QUnit.url( params ); 743 | }); 744 | } 745 | 746 | var toolbar = id("qunit-testrunner-toolbar"); 747 | if ( toolbar ) { 748 | var filter = document.createElement("input"); 749 | filter.type = "checkbox"; 750 | filter.id = "qunit-filter-pass"; 751 | addEvent( filter, "click", function() { 752 | var ol = document.getElementById("qunit-tests"); 753 | if ( filter.checked ) { 754 | ol.className = ol.className + " hidepass"; 755 | } else { 756 | var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; 757 | ol.className = tmp.replace(/ hidepass /, " "); 758 | } 759 | if ( defined.sessionStorage ) { 760 | if (filter.checked) { 761 | sessionStorage.setItem("qunit-filter-passed-tests", "true"); 762 | } else { 763 | sessionStorage.removeItem("qunit-filter-passed-tests"); 764 | } 765 | } 766 | }); 767 | if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { 768 | filter.checked = true; 769 | var ol = document.getElementById("qunit-tests"); 770 | ol.className = ol.className + " hidepass"; 771 | } 772 | toolbar.appendChild( filter ); 773 | 774 | var label = document.createElement("label"); 775 | label.setAttribute("for", "qunit-filter-pass"); 776 | label.innerHTML = "Hide passed tests"; 777 | toolbar.appendChild( label ); 778 | } 779 | 780 | var main = id('qunit-fixture'); 781 | if ( main ) { 782 | config.fixture = main.innerHTML; 783 | } 784 | 785 | if (config.autostart) { 786 | QUnit.start(); 787 | } 788 | }; 789 | 790 | addEvent(window, "load", QUnit.load); 791 | 792 | // addEvent(window, "error") gives us a useless event object 793 | window.onerror = function( message, file, line ) { 794 | if ( QUnit.config.current ) { 795 | ok( false, message + ", " + file + ":" + line ); 796 | } else { 797 | test( "global failure", function() { 798 | ok( false, message + ", " + file + ":" + line ); 799 | }); 800 | } 801 | }; 802 | 803 | function done() { 804 | config.autorun = true; 805 | 806 | // Log the last module results 807 | if ( config.currentModule ) { 808 | runLoggingCallbacks( 'moduleDone', QUnit, { 809 | name: config.currentModule, 810 | failed: config.moduleStats.bad, 811 | passed: config.moduleStats.all - config.moduleStats.bad, 812 | total: config.moduleStats.all 813 | } ); 814 | } 815 | 816 | var banner = id("qunit-banner"), 817 | tests = id("qunit-tests"), 818 | runtime = +new Date - config.started, 819 | passed = config.stats.all - config.stats.bad, 820 | html = [ 821 | 'Tests completed in ', 822 | runtime, 823 | ' milliseconds.
                          ', 824 | '', 825 | passed, 826 | ' tests of ', 827 | config.stats.all, 828 | ' passed, ', 829 | config.stats.bad, 830 | ' failed.' 831 | ].join(''); 832 | 833 | if ( banner ) { 834 | banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); 835 | } 836 | 837 | if ( tests ) { 838 | id( "qunit-testresult" ).innerHTML = html; 839 | } 840 | 841 | if ( config.altertitle && typeof document !== "undefined" && document.title ) { 842 | // show ✖ for good, ✔ for bad suite result in title 843 | // use escape sequences in case file gets loaded with non-utf-8-charset 844 | document.title = [ 845 | (config.stats.bad ? "\u2716" : "\u2714"), 846 | document.title.replace(/^[\u2714\u2716] /i, "") 847 | ].join(" "); 848 | } 849 | 850 | runLoggingCallbacks( 'done', QUnit, { 851 | failed: config.stats.bad, 852 | passed: passed, 853 | total: config.stats.all, 854 | runtime: runtime 855 | } ); 856 | } 857 | 858 | function validTest( name ) { 859 | var filter = config.filter, 860 | run = false; 861 | 862 | if ( !filter ) { 863 | return true; 864 | } 865 | 866 | var not = filter.charAt( 0 ) === "!"; 867 | if ( not ) { 868 | filter = filter.slice( 1 ); 869 | } 870 | 871 | if ( name.indexOf( filter ) !== -1 ) { 872 | return !not; 873 | } 874 | 875 | if ( not ) { 876 | run = true; 877 | } 878 | 879 | return run; 880 | } 881 | 882 | // so far supports only Firefox, Chrome and Opera (buggy) 883 | // could be extended in the future to use something like https://github.com/csnover/TraceKit 884 | function sourceFromStacktrace() { 885 | try { 886 | throw new Error(); 887 | } catch ( e ) { 888 | if (e.stacktrace) { 889 | // Opera 890 | return e.stacktrace.split("\n")[6]; 891 | } else if (e.stack) { 892 | // Firefox, Chrome 893 | return e.stack.split("\n")[4]; 894 | } else if (e.sourceURL) { 895 | // Safari, PhantomJS 896 | // TODO sourceURL points at the 'throw new Error' line above, useless 897 | //return e.sourceURL + ":" + e.line; 898 | } 899 | } 900 | } 901 | 902 | function escapeInnerText(s) { 903 | if (!s) { 904 | return ""; 905 | } 906 | s = s + ""; 907 | return s.replace(/[\&<>]/g, function(s) { 908 | switch(s) { 909 | case "&": return "&"; 910 | case "<": return "<"; 911 | case ">": return ">"; 912 | default: return s; 913 | } 914 | }); 915 | } 916 | 917 | function synchronize( callback, last ) { 918 | config.queue.push( callback ); 919 | 920 | if ( config.autorun && !config.blocking ) { 921 | process(last); 922 | } 923 | } 924 | 925 | function process( last ) { 926 | var start = new Date().getTime(); 927 | config.depth = config.depth ? config.depth + 1 : 1; 928 | 929 | while ( config.queue.length && !config.blocking ) { 930 | if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { 931 | config.queue.shift()(); 932 | } else { 933 | window.setTimeout( function(){ 934 | process( last ); 935 | }, 13 ); 936 | break; 937 | } 938 | } 939 | config.depth--; 940 | if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { 941 | done(); 942 | } 943 | } 944 | 945 | function saveGlobal() { 946 | config.pollution = []; 947 | 948 | if ( config.noglobals ) { 949 | for ( var key in window ) { 950 | if ( !hasOwn.call( window, key ) ) { 951 | continue; 952 | } 953 | config.pollution.push( key ); 954 | } 955 | } 956 | } 957 | 958 | function checkPollution( name ) { 959 | var old = config.pollution; 960 | saveGlobal(); 961 | 962 | var newGlobals = diff( config.pollution, old ); 963 | if ( newGlobals.length > 0 ) { 964 | ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); 965 | } 966 | 967 | var deletedGlobals = diff( old, config.pollution ); 968 | if ( deletedGlobals.length > 0 ) { 969 | ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); 970 | } 971 | } 972 | 973 | // returns a new Array with the elements that are in a but not in b 974 | function diff( a, b ) { 975 | var result = a.slice(); 976 | for ( var i = 0; i < result.length; i++ ) { 977 | for ( var j = 0; j < b.length; j++ ) { 978 | if ( result[i] === b[j] ) { 979 | result.splice(i, 1); 980 | i--; 981 | break; 982 | } 983 | } 984 | } 985 | return result; 986 | } 987 | 988 | function fail(message, exception, callback) { 989 | if ( typeof console !== "undefined" && console.error && console.warn ) { 990 | console.error(message); 991 | console.error(exception); 992 | console.warn(callback.toString()); 993 | 994 | } else if ( window.opera && opera.postError ) { 995 | opera.postError(message, exception, callback.toString); 996 | } 997 | } 998 | 999 | function extend(a, b) { 1000 | for ( var prop in b ) { 1001 | if ( b[prop] === undefined ) { 1002 | delete a[prop]; 1003 | 1004 | // Avoid "Member not found" error in IE8 caused by setting window.constructor 1005 | } else if ( prop !== "constructor" || a !== window ) { 1006 | a[prop] = b[prop]; 1007 | } 1008 | } 1009 | 1010 | return a; 1011 | } 1012 | 1013 | function addEvent(elem, type, fn) { 1014 | if ( elem.addEventListener ) { 1015 | elem.addEventListener( type, fn, false ); 1016 | } else if ( elem.attachEvent ) { 1017 | elem.attachEvent( "on" + type, fn ); 1018 | } else { 1019 | fn(); 1020 | } 1021 | } 1022 | 1023 | function id(name) { 1024 | return !!(typeof document !== "undefined" && document && document.getElementById) && 1025 | document.getElementById( name ); 1026 | } 1027 | 1028 | function registerLoggingCallback(key){ 1029 | return function(callback){ 1030 | config[key].push( callback ); 1031 | }; 1032 | } 1033 | 1034 | // Supports deprecated method of completely overwriting logging callbacks 1035 | function runLoggingCallbacks(key, scope, args) { 1036 | //debugger; 1037 | var callbacks; 1038 | if ( QUnit.hasOwnProperty(key) ) { 1039 | QUnit[key].call(scope, args); 1040 | } else { 1041 | callbacks = config[key]; 1042 | for( var i = 0; i < callbacks.length; i++ ) { 1043 | callbacks[i].call( scope, args ); 1044 | } 1045 | } 1046 | } 1047 | 1048 | // Test for equality any JavaScript type. 1049 | // Author: Philippe Rathé 1050 | QUnit.equiv = function () { 1051 | 1052 | var innerEquiv; // the real equiv function 1053 | var callers = []; // stack to decide between skip/abort functions 1054 | var parents = []; // stack to avoiding loops from circular referencing 1055 | 1056 | // Call the o related callback with the given arguments. 1057 | function bindCallbacks(o, callbacks, args) { 1058 | var prop = QUnit.objectType(o); 1059 | if (prop) { 1060 | if (QUnit.objectType(callbacks[prop]) === "function") { 1061 | return callbacks[prop].apply(callbacks, args); 1062 | } else { 1063 | return callbacks[prop]; // or undefined 1064 | } 1065 | } 1066 | } 1067 | 1068 | var getProto = Object.getPrototypeOf || function (obj) { 1069 | return obj.__proto__; 1070 | }; 1071 | 1072 | var callbacks = function () { 1073 | 1074 | // for string, boolean, number and null 1075 | function useStrictEquality(b, a) { 1076 | if (b instanceof a.constructor || a instanceof b.constructor) { 1077 | // to catch short annotaion VS 'new' annotation of a 1078 | // declaration 1079 | // e.g. var i = 1; 1080 | // var j = new Number(1); 1081 | return a == b; 1082 | } else { 1083 | return a === b; 1084 | } 1085 | } 1086 | 1087 | return { 1088 | "string" : useStrictEquality, 1089 | "boolean" : useStrictEquality, 1090 | "number" : useStrictEquality, 1091 | "null" : useStrictEquality, 1092 | "undefined" : useStrictEquality, 1093 | 1094 | "nan" : function(b) { 1095 | return isNaN(b); 1096 | }, 1097 | 1098 | "date" : function(b, a) { 1099 | return QUnit.objectType(b) === "date" 1100 | && a.valueOf() === b.valueOf(); 1101 | }, 1102 | 1103 | "regexp" : function(b, a) { 1104 | return QUnit.objectType(b) === "regexp" 1105 | && a.source === b.source && // the regex itself 1106 | a.global === b.global && // and its modifers 1107 | // (gmi) ... 1108 | a.ignoreCase === b.ignoreCase 1109 | && a.multiline === b.multiline; 1110 | }, 1111 | 1112 | // - skip when the property is a method of an instance (OOP) 1113 | // - abort otherwise, 1114 | // initial === would have catch identical references anyway 1115 | "function" : function() { 1116 | var caller = callers[callers.length - 1]; 1117 | return caller !== Object && typeof caller !== "undefined"; 1118 | }, 1119 | 1120 | "array" : function(b, a) { 1121 | var i, j, loop; 1122 | var len; 1123 | 1124 | // b could be an object literal here 1125 | if (!(QUnit.objectType(b) === "array")) { 1126 | return false; 1127 | } 1128 | 1129 | len = a.length; 1130 | if (len !== b.length) { // safe and faster 1131 | return false; 1132 | } 1133 | 1134 | // track reference to avoid circular references 1135 | parents.push(a); 1136 | for (i = 0; i < len; i++) { 1137 | loop = false; 1138 | for (j = 0; j < parents.length; j++) { 1139 | if (parents[j] === a[i]) { 1140 | loop = true;// dont rewalk array 1141 | } 1142 | } 1143 | if (!loop && !innerEquiv(a[i], b[i])) { 1144 | parents.pop(); 1145 | return false; 1146 | } 1147 | } 1148 | parents.pop(); 1149 | return true; 1150 | }, 1151 | 1152 | "object" : function(b, a) { 1153 | var i, j, loop; 1154 | var eq = true; // unless we can proove it 1155 | var aProperties = [], bProperties = []; // collection of 1156 | // strings 1157 | 1158 | // comparing constructors is more strict than using 1159 | // instanceof 1160 | if (a.constructor !== b.constructor) { 1161 | // Allow objects with no prototype to be equivalent to 1162 | // objects with Object as their constructor. 1163 | if (!((getProto(a) === null && getProto(b) === Object.prototype) || 1164 | (getProto(b) === null && getProto(a) === Object.prototype))) 1165 | { 1166 | return false; 1167 | } 1168 | } 1169 | 1170 | // stack constructor before traversing properties 1171 | callers.push(a.constructor); 1172 | // track reference to avoid circular references 1173 | parents.push(a); 1174 | 1175 | for (i in a) { // be strict: don't ensures hasOwnProperty 1176 | // and go deep 1177 | loop = false; 1178 | for (j = 0; j < parents.length; j++) { 1179 | if (parents[j] === a[i]) 1180 | loop = true; // don't go down the same path 1181 | // twice 1182 | } 1183 | aProperties.push(i); // collect a's properties 1184 | 1185 | if (!loop && !innerEquiv(a[i], b[i])) { 1186 | eq = false; 1187 | break; 1188 | } 1189 | } 1190 | 1191 | callers.pop(); // unstack, we are done 1192 | parents.pop(); 1193 | 1194 | for (i in b) { 1195 | bProperties.push(i); // collect b's properties 1196 | } 1197 | 1198 | // Ensures identical properties name 1199 | return eq 1200 | && innerEquiv(aProperties.sort(), bProperties 1201 | .sort()); 1202 | } 1203 | }; 1204 | }(); 1205 | 1206 | innerEquiv = function() { // can take multiple arguments 1207 | var args = Array.prototype.slice.apply(arguments); 1208 | if (args.length < 2) { 1209 | return true; // end transition 1210 | } 1211 | 1212 | return (function(a, b) { 1213 | if (a === b) { 1214 | return true; // catch the most you can 1215 | } else if (a === null || b === null || typeof a === "undefined" 1216 | || typeof b === "undefined" 1217 | || QUnit.objectType(a) !== QUnit.objectType(b)) { 1218 | return false; // don't lose time with error prone cases 1219 | } else { 1220 | return bindCallbacks(a, callbacks, [ b, a ]); 1221 | } 1222 | 1223 | // apply transition with (1..n) arguments 1224 | })(args[0], args[1]) 1225 | && arguments.callee.apply(this, args.splice(1, 1226 | args.length - 1)); 1227 | }; 1228 | 1229 | return innerEquiv; 1230 | 1231 | }(); 1232 | 1233 | /** 1234 | * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | 1235 | * http://flesler.blogspot.com Licensed under BSD 1236 | * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 1237 | * 1238 | * @projectDescription Advanced and extensible data dumping for Javascript. 1239 | * @version 1.0.0 1240 | * @author Ariel Flesler 1241 | * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} 1242 | */ 1243 | QUnit.jsDump = (function() { 1244 | function quote( str ) { 1245 | return '"' + str.toString().replace(/"/g, '\\"') + '"'; 1246 | }; 1247 | function literal( o ) { 1248 | return o + ''; 1249 | }; 1250 | function join( pre, arr, post ) { 1251 | var s = jsDump.separator(), 1252 | base = jsDump.indent(), 1253 | inner = jsDump.indent(1); 1254 | if ( arr.join ) 1255 | arr = arr.join( ',' + s + inner ); 1256 | if ( !arr ) 1257 | return pre + post; 1258 | return [ pre, inner + arr, base + post ].join(s); 1259 | }; 1260 | function array( arr, stack ) { 1261 | var i = arr.length, ret = Array(i); 1262 | this.up(); 1263 | while ( i-- ) 1264 | ret[i] = this.parse( arr[i] , undefined , stack); 1265 | this.down(); 1266 | return join( '[', ret, ']' ); 1267 | }; 1268 | 1269 | var reName = /^function (\w+)/; 1270 | 1271 | var jsDump = { 1272 | parse:function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance 1273 | stack = stack || [ ]; 1274 | var parser = this.parsers[ type || this.typeOf(obj) ]; 1275 | type = typeof parser; 1276 | var inStack = inArray(obj, stack); 1277 | if (inStack != -1) { 1278 | return 'recursion('+(inStack - stack.length)+')'; 1279 | } 1280 | //else 1281 | if (type == 'function') { 1282 | stack.push(obj); 1283 | var res = parser.call( this, obj, stack ); 1284 | stack.pop(); 1285 | return res; 1286 | } 1287 | // else 1288 | return (type == 'string') ? parser : this.parsers.error; 1289 | }, 1290 | typeOf:function( obj ) { 1291 | var type; 1292 | if ( obj === null ) { 1293 | type = "null"; 1294 | } else if (typeof obj === "undefined") { 1295 | type = "undefined"; 1296 | } else if (QUnit.is("RegExp", obj)) { 1297 | type = "regexp"; 1298 | } else if (QUnit.is("Date", obj)) { 1299 | type = "date"; 1300 | } else if (QUnit.is("Function", obj)) { 1301 | type = "function"; 1302 | } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") { 1303 | type = "window"; 1304 | } else if (obj.nodeType === 9) { 1305 | type = "document"; 1306 | } else if (obj.nodeType) { 1307 | type = "node"; 1308 | } else if ( 1309 | // native arrays 1310 | toString.call( obj ) === "[object Array]" || 1311 | // NodeList objects 1312 | ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) 1313 | ) { 1314 | type = "array"; 1315 | } else { 1316 | type = typeof obj; 1317 | } 1318 | return type; 1319 | }, 1320 | separator:function() { 1321 | return this.multiline ? this.HTML ? '
                          ' : '\n' : this.HTML ? ' ' : ' '; 1322 | }, 1323 | indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing 1324 | if ( !this.multiline ) 1325 | return ''; 1326 | var chr = this.indentChar; 1327 | if ( this.HTML ) 1328 | chr = chr.replace(/\t/g,' ').replace(/ /g,' '); 1329 | return Array( this._depth_ + (extra||0) ).join(chr); 1330 | }, 1331 | up:function( a ) { 1332 | this._depth_ += a || 1; 1333 | }, 1334 | down:function( a ) { 1335 | this._depth_ -= a || 1; 1336 | }, 1337 | setParser:function( name, parser ) { 1338 | this.parsers[name] = parser; 1339 | }, 1340 | // The next 3 are exposed so you can use them 1341 | quote:quote, 1342 | literal:literal, 1343 | join:join, 1344 | // 1345 | _depth_: 1, 1346 | // This is the list of parsers, to modify them, use jsDump.setParser 1347 | parsers:{ 1348 | window: '[Window]', 1349 | document: '[Document]', 1350 | error:'[ERROR]', //when no parser is found, shouldn't happen 1351 | unknown: '[Unknown]', 1352 | 'null':'null', 1353 | 'undefined':'undefined', 1354 | 'function':function( fn ) { 1355 | var ret = 'function', 1356 | name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE 1357 | if ( name ) 1358 | ret += ' ' + name; 1359 | ret += '('; 1360 | 1361 | ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); 1362 | return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); 1363 | }, 1364 | array: array, 1365 | nodelist: array, 1366 | arguments: array, 1367 | object:function( map, stack ) { 1368 | var ret = [ ]; 1369 | QUnit.jsDump.up(); 1370 | for ( var key in map ) { 1371 | var val = map[key]; 1372 | ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(val, undefined, stack)); 1373 | } 1374 | QUnit.jsDump.down(); 1375 | return join( '{', ret, '}' ); 1376 | }, 1377 | node:function( node ) { 1378 | var open = QUnit.jsDump.HTML ? '<' : '<', 1379 | close = QUnit.jsDump.HTML ? '>' : '>'; 1380 | 1381 | var tag = node.nodeName.toLowerCase(), 1382 | ret = open + tag; 1383 | 1384 | for ( var a in QUnit.jsDump.DOMAttrs ) { 1385 | var val = node[QUnit.jsDump.DOMAttrs[a]]; 1386 | if ( val ) 1387 | ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); 1388 | } 1389 | return ret + close + open + '/' + tag + close; 1390 | }, 1391 | functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function 1392 | var l = fn.length; 1393 | if ( !l ) return ''; 1394 | 1395 | var args = Array(l); 1396 | while ( l-- ) 1397 | args[l] = String.fromCharCode(97+l);//97 is 'a' 1398 | return ' ' + args.join(', ') + ' '; 1399 | }, 1400 | key:quote, //object calls it internally, the key part of an item in a map 1401 | functionCode:'[code]', //function calls it internally, it's the content of the function 1402 | attribute:quote, //node calls it internally, it's an html attribute value 1403 | string:quote, 1404 | date:quote, 1405 | regexp:literal, //regex 1406 | number:literal, 1407 | 'boolean':literal 1408 | }, 1409 | DOMAttrs:{//attributes to dump from nodes, name=>realName 1410 | id:'id', 1411 | name:'name', 1412 | 'class':'className' 1413 | }, 1414 | HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) 1415 | indentChar:' ',//indentation unit 1416 | multiline:true //if true, items in a collection, are separated by a \n, else just a space. 1417 | }; 1418 | 1419 | return jsDump; 1420 | })(); 1421 | 1422 | // from Sizzle.js 1423 | function getText( elems ) { 1424 | var ret = "", elem; 1425 | 1426 | for ( var i = 0; elems[i]; i++ ) { 1427 | elem = elems[i]; 1428 | 1429 | // Get the text from text nodes and CDATA nodes 1430 | if ( elem.nodeType === 3 || elem.nodeType === 4 ) { 1431 | ret += elem.nodeValue; 1432 | 1433 | // Traverse everything else, except comment nodes 1434 | } else if ( elem.nodeType !== 8 ) { 1435 | ret += getText( elem.childNodes ); 1436 | } 1437 | } 1438 | 1439 | return ret; 1440 | }; 1441 | 1442 | //from jquery.js 1443 | function inArray( elem, array ) { 1444 | if ( array.indexOf ) { 1445 | return array.indexOf( elem ); 1446 | } 1447 | 1448 | for ( var i = 0, length = array.length; i < length; i++ ) { 1449 | if ( array[ i ] === elem ) { 1450 | return i; 1451 | } 1452 | } 1453 | 1454 | return -1; 1455 | } 1456 | 1457 | /* 1458 | * Javascript Diff Algorithm 1459 | * By John Resig (http://ejohn.org/) 1460 | * Modified by Chu Alan "sprite" 1461 | * 1462 | * Released under the MIT license. 1463 | * 1464 | * More Info: 1465 | * http://ejohn.org/projects/javascript-diff-algorithm/ 1466 | * 1467 | * Usage: QUnit.diff(expected, actual) 1468 | * 1469 | * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" 1470 | */ 1471 | QUnit.diff = (function() { 1472 | function diff(o, n) { 1473 | var ns = {}; 1474 | var os = {}; 1475 | 1476 | for (var i = 0; i < n.length; i++) { 1477 | if (ns[n[i]] == null) 1478 | ns[n[i]] = { 1479 | rows: [], 1480 | o: null 1481 | }; 1482 | ns[n[i]].rows.push(i); 1483 | } 1484 | 1485 | for (var i = 0; i < o.length; i++) { 1486 | if (os[o[i]] == null) 1487 | os[o[i]] = { 1488 | rows: [], 1489 | n: null 1490 | }; 1491 | os[o[i]].rows.push(i); 1492 | } 1493 | 1494 | for (var i in ns) { 1495 | if ( !hasOwn.call( ns, i ) ) { 1496 | continue; 1497 | } 1498 | if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { 1499 | n[ns[i].rows[0]] = { 1500 | text: n[ns[i].rows[0]], 1501 | row: os[i].rows[0] 1502 | }; 1503 | o[os[i].rows[0]] = { 1504 | text: o[os[i].rows[0]], 1505 | row: ns[i].rows[0] 1506 | }; 1507 | } 1508 | } 1509 | 1510 | for (var i = 0; i < n.length - 1; i++) { 1511 | if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && 1512 | n[i + 1] == o[n[i].row + 1]) { 1513 | n[i + 1] = { 1514 | text: n[i + 1], 1515 | row: n[i].row + 1 1516 | }; 1517 | o[n[i].row + 1] = { 1518 | text: o[n[i].row + 1], 1519 | row: i + 1 1520 | }; 1521 | } 1522 | } 1523 | 1524 | for (var i = n.length - 1; i > 0; i--) { 1525 | if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && 1526 | n[i - 1] == o[n[i].row - 1]) { 1527 | n[i - 1] = { 1528 | text: n[i - 1], 1529 | row: n[i].row - 1 1530 | }; 1531 | o[n[i].row - 1] = { 1532 | text: o[n[i].row - 1], 1533 | row: i - 1 1534 | }; 1535 | } 1536 | } 1537 | 1538 | return { 1539 | o: o, 1540 | n: n 1541 | }; 1542 | } 1543 | 1544 | return function(o, n) { 1545 | o = o.replace(/\s+$/, ''); 1546 | n = n.replace(/\s+$/, ''); 1547 | var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/)); 1548 | 1549 | var str = ""; 1550 | 1551 | var oSpace = o.match(/\s+/g); 1552 | if (oSpace == null) { 1553 | oSpace = [" "]; 1554 | } 1555 | else { 1556 | oSpace.push(" "); 1557 | } 1558 | var nSpace = n.match(/\s+/g); 1559 | if (nSpace == null) { 1560 | nSpace = [" "]; 1561 | } 1562 | else { 1563 | nSpace.push(" "); 1564 | } 1565 | 1566 | if (out.n.length == 0) { 1567 | for (var i = 0; i < out.o.length; i++) { 1568 | str += '' + out.o[i] + oSpace[i] + ""; 1569 | } 1570 | } 1571 | else { 1572 | if (out.n[0].text == null) { 1573 | for (n = 0; n < out.o.length && out.o[n].text == null; n++) { 1574 | str += '' + out.o[n] + oSpace[n] + ""; 1575 | } 1576 | } 1577 | 1578 | for (var i = 0; i < out.n.length; i++) { 1579 | if (out.n[i].text == null) { 1580 | str += '' + out.n[i] + nSpace[i] + ""; 1581 | } 1582 | else { 1583 | var pre = ""; 1584 | 1585 | for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { 1586 | pre += '' + out.o[n] + oSpace[n] + ""; 1587 | } 1588 | str += " " + out.n[i].text + nSpace[i] + pre; 1589 | } 1590 | } 1591 | } 1592 | 1593 | return str; 1594 | }; 1595 | })(); 1596 | 1597 | })(this); 1598 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | module("strftime"); 2 | 3 | test("foo", function () { 4 | 5 | var is = equal; 6 | var d = new Date(2011, 8, 1, 10, 4, 1); 7 | is(d.strftime('%Y-%m-%d'), '2011-09-01'); 8 | is(d.strftime('%T'), '10:04:01'); 9 | is(d.strftime('%%'), '%'); 10 | is(d.strftime('%e'), ' 1'); 11 | is(d.strftime('%H'), '10'); 12 | is(d.strftime('%I'), '10'); 13 | is(d.strftime('%k'), '10'); 14 | is(d.strftime('%M'), '04', '%M'); 15 | is(d.strftime('%m'), '09'); 16 | is(d.strftime('%S'), '01'); 17 | is(d.strftime('%y'), '11'); 18 | is(d.strftime('%+'), 'Thu Sep 01 2011 10:04:01 GMT+0900 (JST)'); 19 | is(d.strftime('%h'), 'Sep'); 20 | 21 | is(d.strftime('%A'), 'Thursday'); 22 | is(d.strftime('%a'), 'Thu'); 23 | is(d.strftime('%B'), 'September'); 24 | is(d.strftime('%b'), 'Sep'); 25 | is(d.strftime('%d'), '01', '%d'); 26 | 27 | Date.prototype.strftime.locales['de'] = { 28 | B: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], 29 | b: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], 30 | A: ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"], 31 | a: ["Mo\.", "Di\.", "Mi\.", "Do\.", "Fr\.", "Sa\.", "So\."] 32 | }; 33 | 34 | is(d.strftime('%A', 'ja'), '木曜日'); 35 | is(d.strftime('%a', 'ja'), '木'); 36 | is(d.strftime('%B', 'ja'), ' 9月'); 37 | is(d.strftime('%b', 'ja'), ' 9月'); 38 | 39 | is(d.strftime('%A', 'de'), 'Freitag'); 40 | is(d.strftime('%a', 'de'), 'Fr.'); 41 | is(d.strftime('%B', 'de'), 'September'); 42 | is(d.strftime('%b', 'de'), 'Sep'); 43 | 44 | // custom formats 45 | is(d.strftime('%z'), 'z'); 46 | Date.prototype.strftime.formats.z = function () { return '+0900' }; 47 | is(d.strftime('%z'), '+0900'); 48 | 49 | // %P %p 50 | (function () { 51 | var d = (new Date(2011, 8, 1, 10, 4, 1)); 52 | d.setHours(10); 53 | is(d.strftime('%p'), 'AM'); 54 | is(d.strftime('%P'), 'am'); 55 | is(d.strftime('%r'), '10:04:01 AM'); 56 | is(d.strftime('%R'), '10:04'); 57 | is(d.strftime('%s'), '1314839041'); 58 | is(d.strftime('%S'), '01'); 59 | is(d.strftime('%t'), "\t"); 60 | is(d.strftime('%T'), '10:04:01'); 61 | is(d.strftime('%u'), '4'); 62 | is(d.strftime('%w'), '4'); 63 | is(d.strftime('%x'), 'Thu Sep 01 2011'); 64 | is(d.strftime('%X'), '10:04:01 GMT+0900 (JST)'); 65 | is(d.strftime('%Y'), '2011'); 66 | is(d.strftime('%y'), '11'); 67 | is(d.strftime('%z'), '+0900'); 68 | 69 | d.setHours(13); 70 | is(d.strftime('%p'), 'PM'); 71 | is(d.strftime('%P'), 'pm'); 72 | is(d.strftime('%r'), '01:04:01 PM'); 73 | })(); 74 | 75 | }); 76 | --------------------------------------------------------------------------------