Selaa lähdekoodia

Added limonade

Laurent Treguier 9 vuotta sitten
vanhempi
commit
7d4d1c54c2

+ 2707
- 0
lib/limonade.php
File diff suppressed because it is too large
Näytä tiedosto


+ 193
- 0
lib/limonade/abstract.php Näytä tiedosto

@@ -0,0 +1,193 @@
1
+<?php
2
+/**
3
+ * Abstract methods that might be redefined by user
4
+ * Do not include this file in your app: it only aims to provide documentation
5
+ * about those functions.
6
+ * 
7
+ * @package limonade
8
+ * @subpackage abstract
9
+ */
10
+ 
11
+/**
12
+ * It will be called when app is launched (at the begining of the run function).
13
+ * You can define options inside it, a connection to a database ...
14
+ *
15
+ * @abstract this function might be redefined by user
16
+ * @return void 
17
+ */
18
+function configure()
19
+{
20
+  return;
21
+}
22
+
23
+/**
24
+ * Called in run() just after session start, and before checking request method
25
+ * and output buffer start.  
26
+ *
27
+ * @abstract this function might be redefined by user
28
+ * @return void 
29
+ */
30
+function initialize()
31
+{
32
+  return;
33
+}
34
+
35
+/**
36
+ * Called in run() just after the route matching, in order to load controllers. 
37
+ * If not specfied, the default function is called:
38
+ * 
39
+ * <code>
40
+ * function autoload_controller($callback)
41
+ * {
42
+ *   require_once_dir(option('controllers_dir'));
43
+ * }
44
+ * </code>
45
+ * 
46
+ *
47
+ * @param string $callback the callback defined in matching route
48
+ * @return void
49
+ */
50
+function autoload_controller($callback)
51
+{
52
+  return;
53
+}
54
+ 
55
+/**
56
+ * Called before each request.
57
+ * This is very useful to define a default layout or passing common variables
58
+ * to the templates.
59
+ *
60
+ * @abstract this function might be redefined by user
61
+ * @param array() $route array (like returned by {@link route_build()},
62
+ *   with keys "method", "pattern", "names", "callback", "options")
63
+ * @return void 
64
+ */
65
+function before($route)
66
+{
67
+  
68
+}
69
+ 
70
+/**
71
+ * An `after` output filter
72
+ * 
73
+ * Called after each request and can apply a transformation to the output
74
+ * (except for `render_file` outputs  which are sent directly to the output buffer).
75
+ *
76
+ * @abstract this function might be redefined by user
77
+ * @param string $output 
78
+ * @param array() $route array (like returned by {@link route_find()},
79
+ *   with keys "method", "pattern", "names", "callback", "params", "options")
80
+ * @return string 
81
+ */
82
+function after($output, $route)
83
+{
84
+  # Call functions...
85
+  # .. modifies $output...
86
+  return $output;
87
+}
88
+ 
89
+/**
90
+ * Not found error output
91
+ *
92
+ * @abstract this function might be redefined by user
93
+ * @param string $errno 
94
+ * @param string $errstr 
95
+ * @param string $errfile 
96
+ * @param string $errline 
97
+ * @return string "not found" output string
98
+ */
99
+function not_found($errno, $errstr, $errfile=null, $errline=null)
100
+{
101
+ 
102
+}
103
+ 
104
+/**
105
+ * Server error output
106
+ *
107
+ * @abstract this function might be redefined by user
108
+ * @param string $errno 
109
+ * @param string $errstr 
110
+ * @param string $errfile 
111
+ * @param string $errline 
112
+ * @return string "server error" output string
113
+ */
114
+function server_error($errno, $errstr, $errfile=null, $errline=null)
115
+{
116
+  
117
+}
118
+ 
119
+/**
120
+ * Called when a route is not found.
121
+ * 
122
+ * 
123
+ * @abstract this function might be redefined by user
124
+ * @param string $request_method 
125
+ * @param string $request_uri 
126
+ * @return void 
127
+ */
128
+function route_missing($request_method, $request_uri)
129
+{
130
+  halt(NOT_FOUND, "($request_method) $request_uri"); # by default
131
+}
132
+
133
+/**
134
+ * Called before stoppping and exiting application.
135
+ *
136
+ * @abstract this function might be redefined by user
137
+ * @param boolean exit or not
138
+ * @return void 
139
+ */
140
+function before_exit($exit)
141
+{
142
+  
143
+}
144
+
145
+/**
146
+ * Rendering prefilter.
147
+ * Useful if you want to transform your views before rendering.
148
+ * The first three parameters are the same as those provided 
149
+ * to the `render` function.
150
+ *
151
+ * @abstract this function might be redefined by user
152
+ * @param string $content_or_func a function, a file in current views dir or a string
153
+ * @param string $layout 
154
+ * @param array $locals 
155
+ * @param array $view_path (by default <code>file_path(option('views_dir'),$content_or_func);</code>)
156
+ * @return array with, in order, $content_or_func, $layout, $locals vars
157
+ *  and the calculated $view_path
158
+ */
159
+function before_render($content_or_func, $layout, $locals, $view_path)
160
+{
161
+  # transform $content_or_func, $layout, $locals or $view_path…
162
+  return array($content_or_func, $layout, $locals, $view_path);
163
+}
164
+
165
+
166
+/**
167
+ * Called only if rendering $output is_null,
168
+ * like in a controller with no return statement.
169
+ *
170
+ * @abstract this function might be defined by user
171
+ * @param array() $route array (like returned by {@link route_build()},
172
+ *   with keys "method", "pattern", "names", "callback", "options")
173
+ * @return string
174
+ */
175
+function autorender($route)
176
+{
177
+  # process output depending on $route
178
+  return $output;
179
+}
180
+
181
+/**
182
+ * Called if a header is about to be sent
183
+ *
184
+ * @abstract this function might be defined by user
185
+ * @param string the headers that limonade will send
186
+ * @return void
187
+ */
188
+function before_sending_header($header)
189
+{
190
+
191
+}
192
+
193
+

+ 173
- 0
lib/limonade/assertions.php Näytä tiedosto

@@ -0,0 +1,173 @@
1
+<?php
2
+/**
3
+ * @package tests
4
+ * @subpackage assertions
5
+ */
6
+# ============================================================================ #
7
+#    ASSERTIONS                                                                #
8
+# ============================================================================ #
9
+
10
+/**
11
+ * assert_true
12
+ *
13
+ * @param string $value 
14
+ * @param string $message 
15
+ * @return boolean
16
+ */
17
+function assert_true($value, $message = '<1> should be TRUE')
18
+{
19
+   test_run_assertion();
20
+   return assert('$value === TRUE; //'.$message);
21
+}
22
+
23
+function assert_false($value, $message = '<1> should be FALSE')
24
+{
25
+   test_run_assertion();
26
+   return assert('$value === FALSE; //'.$message);
27
+}
28
+
29
+function assert_null($value, $message = '<1> should be NULL')
30
+{
31
+   test_run_assertion();
32
+   return assert('$value === NULL; //'.$message);
33
+}
34
+
35
+function assert_not_null($value, $message = '<1> should not be NULL')
36
+{
37
+   test_run_assertion();
38
+   return assert('$value !== NULL; //'.$message);
39
+}
40
+
41
+function assert_empty($value, $message = '<1> should be empty')
42
+{
43
+   test_run_assertion();
44
+   return assert('empty($value); //'.$message);
45
+}
46
+
47
+function assert_not_empty($value, $message = '<1> should not be empty')
48
+{
49
+   test_run_assertion();
50
+   return assert('!empty($value); //'.$message);
51
+}
52
+
53
+function assert_equal($expected, $value, $message = '<1> should be equal to <2>')
54
+{
55
+   test_run_assertion();
56
+   return assert('$expected == $value; //'.$message);
57
+}
58
+
59
+function assert_not_equal($expected, $value, $message = '<1> should not equal to <2>')
60
+{
61
+   test_run_assertion();
62
+   return assert('$expected != $value; //'.$message);
63
+}
64
+
65
+function assert_identical($expected, $value, $message = '<1> should be identical to <2>')
66
+{
67
+   test_run_assertion();
68
+   return assert('$expected === $value; //'.$message);
69
+}
70
+
71
+function assert_not_identical($expected, $value, $message = '<1> should not be identical to <2>')
72
+{
73
+   test_run_assertion();
74
+   return assert('$expected !== $value; //'.$message);
75
+}
76
+
77
+function assert_match($pattern, $string, $message = '<2> expected to match regular expression <1>') {
78
+   test_run_assertion();
79
+   return assert('preg_match($pattern, $string); //'.$message);
80
+}
81
+ 
82
+function assert_no_match($pattern, $string, $message = '<2> expected to not match regular expression <1>') {
83
+   test_run_assertion();
84
+   return assert('!preg_match($pattern, $string); //'.$message);
85
+}
86
+
87
+function assert_type($type, $value, $message = '<1> is not of type <2>') {
88
+  test_run_assertion();
89
+  $predicate = 'is_' . strtolower(is_string($type) ? $type : gettype($type));
90
+  return assert('$predicate($value); //'.$message);
91
+}
92
+ 
93
+function assert_instance_of($class, $object, $message = '<2> is not an instance of class <1>') {
94
+   test_run_assertion();
95
+   return assert('$object instanceof $class; //'.$message);
96
+}
97
+ 
98
+function assert_length_of($value, $length, $message = '<1> expected to be of length <2>') {
99
+   test_run_assertion();
100
+   $count = is_string($value) ? 'strlen' : 'count';
101
+   return assert('$count($value) == $length; //'.$message);
102
+}
103
+
104
+function assert_trigger_error($callable, $args = array(), $message = '<1> should trigger an error') {
105
+  test_run_assertion();
106
+  $trigger_errors = count($GLOBALS["limonade"]["test_errors"]);
107
+  set_error_handler("test_error_handler");
108
+  $result = call_user_func_array($callable, $args);
109
+  restore_error_handler();
110
+  return assert('$trigger_errors < count($GLOBALS["limonade"]["test_errors"]); //'.$message);
111
+}
112
+
113
+# TODO add web browser assertions assert_http_get, assert_http_response... as in SimpleTest (http://www.simpletest.org/en/web_tester_documentation.html)
114
+
115
+function assert_header($response, $expected_name, $expected_value = null, $message = "expected header '%s' to be equal to '%s' but received '%s: %s'")
116
+{
117
+  test_run_assertion();
118
+  # see assert_header in http://github.com/fnando/voodoo-test/blob/f3b0994ef138a6ba94d5e7cef6c1fb1720797a86/lib/assertions.php
119
+  $headers = preg_split("/^\s*$/ms", $response);
120
+  //var_dump($headers);    
121
+  $headers = preg_replace("/\s*$/sm", "", $headers[0]);
122
+  //var_dump($headers);   
123
+  
124
+  $regex_header = str_replace("/", "\\/", $expected_name);
125
+  $regex_header = str_replace(".", "\\.", $regex_header);
126
+  
127
+  $header = $expected_name;
128
+  
129
+  # from http://www.faqs.org/rfcs/rfc2616
130
+  # Field names are case-insensitive
131
+  if ($expected_value) {
132
+      $regex = "/^{$regex_header}:(.*?)$/ism";
133
+      $header .= ": {$expected_value}";
134
+  } else {
135
+      $regex = "/^{$regex_header}(:.*?)?$/ism";
136
+  }
137
+  
138
+  $has_header = preg_match($regex, $headers, $matches);    
139
+  $sent_header = trim((string)$matches[1]);
140
+
141
+  
142
+  if(empty($sent_header))
143
+  {
144
+    if(is_null($expected_value))
145
+    {
146
+      $message = "expected header '%s' but header has not been sent";
147
+    }
148
+    else
149
+    {
150
+      $message = "expected header '%s' to be equal to '%s' but header has not been sent";
151
+    }
152
+    
153
+    $message = sprintf($message, $expected_name, $expected_value);
154
+    return assert("false; //".$message);
155
+  }
156
+  else if($expected_value)
157
+  {
158
+    $message = sprintf($message, $expected_name, $expected_value, $expected_name, $sent_header);
159
+    return assert('$expected_value && $sent_header == $expected_value; //'.$message);
160
+  }
161
+  return assert("true; //");
162
+}
163
+
164
+function assert_status($response, $expected_status, $message = "expected status code to be equal to '%s' but received '%s'")
165
+{
166
+  $lines = explode('\n', trim($response));
167
+  if (preg_match('/HTTP\/(\d+\.\d+)\s+(\d+)/i', $lines[0], $matches))
168
+  {
169
+      $status = $matches[2];
170
+      return assert('$expected_status == $status; //'.sprintf($message, $expected_status, $status));
171
+  }
172
+  return assert("false; //no status code returned in this response string");
173
+}

+ 220
- 0
lib/limonade/public/css/screen.css Näytä tiedosto

@@ -0,0 +1,220 @@
1
+/* -----------------------------------------------------------------------
2
+
3
+
4
+ Blueprint CSS Framework 0.8
5
+ http://blueprintcss.org
6
+
7
+   * Copyright (c) 2007-Present. See LICENSE for more info.
8
+   * See README for instructions on how to use Blueprint.
9
+   * For credits and origins, see AUTHORS.
10
+   * This is a compressed file. See the sources in the 'src' directory.
11
+
12
+----------------------------------------------------------------------- */
13
+
14
+/* reset.css */
15
+html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;}
16
+body {line-height:1.5;}
17
+table {border-collapse:separate;border-spacing:0;}
18
+caption, th, td {text-align:left;font-weight:normal;}
19
+table, td, th {vertical-align:middle;}
20
+blockquote:before, blockquote:after, q:before, q:after {content:"";}
21
+blockquote, q {quotes:"" "";}
22
+a img {border:none;}
23
+
24
+/* typography.css */
25
+body {font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;}
26
+h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;}
27
+h1 {font-size:3em;line-height:1;margin-bottom:0.5em;}
28
+h2 {font-size:2em;margin-bottom:0.75em;}
29
+h3 {font-size:1.5em;line-height:1;margin-bottom:1em;}
30
+h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;}
31
+h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;}
32
+h6 {font-size:1em;font-weight:bold;}
33
+h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;}
34
+p {margin:0 0 1.5em;}
35
+p img.left {float:left;margin:1.5em 1.5em 1.5em 0;padding:0;}
36
+p img.right {float:right;margin:1.5em 0 1.5em 1.5em;}
37
+a:focus, a:hover {color:#000;}
38
+a {color:#009;text-decoration:underline;}
39
+blockquote {margin:1.5em;color:#666;font-style:italic;}
40
+strong {font-weight:bold;}
41
+em, dfn {font-style:italic;}
42
+dfn {font-weight:bold;}
43
+sup, sub {line-height:0;}
44
+abbr, acronym {border-bottom:1px dotted #666;}
45
+address {margin:0 0 1.5em;font-style:italic;}
46
+del {color:#666;}
47
+pre {margin:1.5em 0;white-space:pre;}
48
+pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;}
49
+li ul, li ol {margin:0 1.5em;}
50
+ul, ol {margin:0 1.5em 1.5em 1.5em;}
51
+ul {list-style-type:disc;}
52
+ol {list-style-type:decimal;}
53
+dl {margin:0 0 1.5em 0;}
54
+dl dt {font-weight:bold;}
55
+dd {margin-left:1.5em;}
56
+table {margin-bottom:1.4em;width:100%;}
57
+th {font-weight:bold;}
58
+thead th {background:#c3d9ff;}
59
+th, td, caption {padding:4px 10px 4px 5px;}
60
+tr.even td {background:#e5ecf9;}
61
+tfoot {font-style:italic;}
62
+caption {background:#eee;}
63
+.small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;}
64
+.large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;}
65
+.hide {display:none;}
66
+.quiet {color:#666;}
67
+.loud {color:#000;}
68
+.highlight {background:#ff0;}
69
+.added {background:#060;color:#fff;}
70
+.removed {background:#900;color:#fff;}
71
+.first {margin-left:0;padding-left:0;}
72
+.last {margin-right:0;padding-right:0;}
73
+.top {margin-top:0;padding-top:0;}
74
+.bottom {margin-bottom:0;padding-bottom:0;}
75
+
76
+/* forms.css */
77
+label {font-weight:bold;}
78
+fieldset {padding:1.4em;margin:0 0 1.5em 0;border:1px solid #ccc;}
79
+legend {font-weight:bold;font-size:1.2em;}
80
+input.text, input.title, textarea, select {margin:0.5em 0;border:1px solid #bbb;}
81
+input.text:focus, input.title:focus, textarea:focus, select:focus {border:1px solid #666;}
82
+input.text, input.title {width:300px;padding:5px;}
83
+input.title {font-size:1.5em;}
84
+textarea {width:390px;height:250px;padding:5px;}
85
+.error, .notice, .success {padding:.8em;margin-bottom:1em;border:2px solid #ddd;}
86
+.error {background:#FBE3E4;color:#8a1f11;border-color:#FBC2C4;}
87
+.notice {background:#FFF6BF;color:#514721;border-color:#FFD324;}
88
+.success {background:#E6EFC2;color:#264409;border-color:#C6D880;}
89
+.error a {color:#8a1f11;}
90
+.notice a {color:#514721;}
91
+.success a {color:#264409;}
92
+
93
+.box {padding:1.5em;margin-bottom:1.5em;background:#E5ECF9;}
94
+hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:none;}
95
+hr.space {background:#fff;color:#fff;}
96
+.clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;}
97
+.clearfix, .container {display:block;}
98
+.clear {clear:both;}
99
+
100
+/* -----------------------------------------------------------------------
101
+
102
+ LIMONADE
103
+ 
104
+ Design and logo by <a href="http://www.minimau.com">Minimau</a>
105
+
106
+----------------------------------------------------------------------- */
107
+
108
+html {
109
+ 	background-color: #b4a689;
110
+ 	text-align: center;
111
+ 	}
112
+ 	body {
113
+ 		width: auto; /* 16 col */
114
+ 		margin: 0 20px;
115
+ 		text-align: left;
116
+ 		/*background: #fff url(blueprint/src/grid.png);*/
117
+ 		font-family: Verdana, Geneva, sans-serif;
118
+ 		color: #303030;
119
+ 		}
120
+ 		a, a:hover, a:visited {
121
+ 			color: #4596cd;
122
+ 			}
123
+ 		a:hover {
124
+ 			text-decoration: none;
125
+ 			}
126
+ 		#header, h1, h2, h3, h4 {
127
+ 			font-family: "Arial Black", Gadget, sans-serif;
128
+ 			}
129
+ 		h1 {
130
+ 			color: #b4a689;
131
+ 			font-size: 2em;
132
+ 			line-height: 2;
133
+ 			border-bottom: 7px solid #000;
134
+ 			margin-bottom: 0.75em;
135
+ 			margin-top:0;
136
+ 			}
137
+ 		h2 {
138
+ 			font-size: 1.5em;
139
+ 			color: #cddb12;
140
+ 			margin-top: 2em;
141
+ 			line-height: 0.8;
142
+ 			margin-bottom: 1.2em;
143
+ 			}
144
+ 		h3 {
145
+ 			font-size: 1.33em;
146
+ 			line-height: 0.89;
147
+ 			margin-top: 2.66em;
148
+ 			margin-bottom: 1.33em;
149
+ 			color:#95b383;
150
+ 			}
151
+ 		pre {
152
+ 			background-color: #cddb12;
153
+ 			font-size: 12px;
154
+ 			padding: 1.5em;
155
+ 			margin-bottom: 1.5em;
156
+ 			overflow: auto;
157
+ 			}
158
+ 		code {
159
+ 			font: 10px Monaco, "Courier New", Courier, monospace;
160
+ 			color: #0d562a;
161
+ 			}
162
+ 		#header {
163
+ 			/*position:relative;*/
164
+ 			height: 187px; /* 12 lines */
165
+ 			background: #fff url(<?=url_for('/_lim_public/img/bg_header.png')?>) no-repeat 0 0;
166
+ 			margin-top: 10px;
167
+      padding:0;
168
+ 			}
169
+ 			#header h1 {
170
+ 				position: absolute;
171
+ 				left:-9999px;
172
+ 				   			margin:0;
173
+ 				}
174
+ 		#footer {
175
+ 			padding: 0 55px;
176
+ 			background-color: #1a1818;
177
+ 			color: #999;
178
+ 			height: 2em;
179
+ 			line-height: 2em;
180
+ 			text-align: right;
181
+ 			}
182
+ 			#footer a {
183
+ 				color: #a3d8de;
184
+ 				text-decoration: none;
185
+ 				}
186
+ 			#footer a:hover {
187
+ 				color: #fff;
188
+ 				}
189
+ 		#content {
190
+ 		  background-color: #fff;
191
+ 			padding: 0 55px;
192
+ 			min-height: 400px;
193
+ 			}
194
+    		p.bt {
195
+    		   text-align:right;
196
+    		   }
197
+       		p.bt a {
198
+       		   text-decoration:none;
199
+       		   padding: 2px 4px;
200
+       		   }
201
+       		p.bt a:hover {
202
+      	      background-color: #4596cd;
203
+      	      color: #fff;
204
+      	      }
205
+      	#debug-menu {
206
+      	   position: fixed;
207
+      	   top: 0px;
208
+      	   right:20px;
209
+      	   background-color: rgba(100,100,100, 0.7);
210
+      	   padding:5px;
211
+      	}
212
+      	#debug-menu a {
213
+      	   color: #fff;
214
+      	   font-size: 90%;
215
+      	   text-decoration:none;
216
+   	   }
217
+   	   #debug-menu a:hover {
218
+   	      text-decoration: underline;
219
+	      }
220
+   	

BIN
lib/limonade/public/img/bg_header.png Näytä tiedosto


+ 350
- 0
lib/limonade/tests.php Näytä tiedosto

@@ -0,0 +1,350 @@
1
+<?php
2
+/**
3
+ * @package tests
4
+ */
5
+ 
6
+# ============================================================================ #
7
+#    TESTS                                                                     #
8
+# ============================================================================ #
9
+
10
+/**
11
+ * load assertions
12
+ */
13
+require_once dirname(__FILE__)."/assertions.php";
14
+
15
+
16
+ 
17
+/**
18
+ * Constants and globals
19
+ */
20
+if(!defined('DS')) define("DS", DIRECTORY_SEPARATOR);
21
+
22
+if(!array_key_exists("limonade", $GLOBALS))
23
+   $GLOBALS["limonade"] = array();
24
+if(!array_key_exists("test_cases", $GLOBALS["limonade"]))
25
+   $GLOBALS["limonade"]["test_cases"] = array();
26
+if(!array_key_exists("test_errors", $GLOBALS["limonade"]))
27
+   $GLOBALS["limonade"]["test_errors"] = array();
28
+if(!array_key_exists("test_case_current", $GLOBALS["limonade"]))
29
+   $GLOBALS["limonade"]["test_case_current"] = NULL;
30
+if(!array_key_exists("test_suites", $GLOBALS["limonade"]))
31
+   $GLOBALS["limonade"]["test_suites"] = NULL;
32
+
33
+ini_set("display_errors", true);
34
+error_reporting(E_ALL ^ (E_USER_WARNING | E_NOTICE | E_USER_NOTICE));
35
+// error_reporting(E_ALL | E_STRICT);
36
+assert_options(ASSERT_ACTIVE, 1);
37
+assert_options(ASSERT_WARNING, 0);
38
+assert_options(ASSERT_BAIL, 0);
39
+assert_options(ASSERT_QUIET_EVAL, 0);
40
+assert_options(ASSERT_CALLBACK, 'test_assert_failure');
41
+
42
+# TODO: separate display from logic
43
+# TODO: clean results output
44
+# TODO: add all tests results
45
+
46
+/**
47
+ * Starts a test suite
48
+ *
49
+ * @param string $name 
50
+ * @return void
51
+ */
52
+function test_suite($name)
53
+{
54
+  $GLOBALS["limonade"]["test_suites"] = $name;
55
+  echo test_cli_format("===========================================================\n", 'white');
56
+  echo test_cli_format(">>>> START $name tests suites\n", 'white');
57
+  echo test_cli_format("-----------------------------------------------------------\n", 'white');
58
+}
59
+
60
+/**
61
+ * Ends the last group of test suites
62
+ *
63
+ * @return void
64
+ */
65
+function end_test_suite()
66
+{
67
+  $name         = $GLOBALS["limonade"]["test_suites"];
68
+  $failures     = 0;
69
+  $tests        = 0;
70
+  $passed_tests = 0;
71
+  $assertions   = 0;
72
+
73
+  foreach($GLOBALS["limonade"]["test_cases"] as $test)
74
+  {
75
+    $failures += $test['failures'];
76
+    $assertions += $test['assertions'];
77
+    if(empty($test['failures'])) $passed_tests++;
78
+    $tests++;
79
+  }
80
+  echo ">> ENDING $name tests suites\n  ";
81
+  echo $failures > 0 ? test_cli_format("|FAILED!|", "red") : test_cli_format("|PASSED|", "green");;
82
+  echo " Passes ".$passed_tests."/".$tests.", ";
83
+  echo " {$failures} failures for {$assertions} assertions.\n";
84
+  echo test_cli_format("===========================================================\n", 'white');
85
+}
86
+
87
+/**
88
+ * Starting a new test case
89
+ *
90
+ * @param string $name 
91
+ * @return void
92
+ */
93
+function test_case($name)
94
+{
95
+   $name = strtolower($name); // TODO: normalize name
96
+   
97
+   if(!array_key_exists($name, $GLOBALS["limonade"]["test_cases"]))
98
+   {
99
+      $GLOBALS["limonade"]["test_cases"][$name] = array( 
100
+                                                      "name" => $name,
101
+                                                      "assertions" => 0, 
102
+                                                      "failures" => 0,
103
+                                                      "description" => NULL
104
+                                                   );      
105
+      $GLOBALS["limonade"]["test_case_current"] = $name;
106
+   }
107
+   else
108
+   {
109
+      
110
+   }
111
+}
112
+
113
+/**
114
+ * Displays and ending the current tests suite
115
+ * 
116
+ * @return void
117
+ */
118
+function end_test_case()
119
+{
120
+   $name = $GLOBALS["limonade"]["test_case_current"];
121
+   echo "## ".strtoupper($name)."\n";
122
+      
123
+   $desc = test_case_describe();
124
+   if(!is_null($desc)) echo $desc."\n";
125
+
126
+   echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n";
127
+   
128
+   test_case_execute_current();
129
+   
130
+   
131
+   if(!is_null($name))
132
+   {
133
+      $test = $GLOBALS["limonade"]["test_cases"][$name];
134
+      // closing previous test
135
+      echo "\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n";
136
+      echo $test['failures'] > 0 ? test_cli_format("|FAILED!|", "red") : test_cli_format("|PASSED|", "green");
137
+      echo " Test case '$name' finished: ";
138
+      echo count(test_case_all_func())." tests, ";
139
+      echo " {$test['failures']} failures for {$test['assertions']} assertions.\n";
140
+      
141
+      echo "-----------------------------------------------------------\n";
142
+   }
143
+   $GLOBALS["limonade"]["test_case_current"] = null;
144
+}
145
+
146
+/**
147
+ * Describes the current tests suite
148
+ *
149
+ * @param string $msg 
150
+ * @return string tests description
151
+ */
152
+function test_case_describe($msg = NULL)
153
+{
154
+   $test =& test_case_current();
155
+   if(!is_null($msg))
156
+   {
157
+      $test["description"] = $msg;
158
+   }
159
+   //var_dump($test["description"]);
160
+   return $test["description"];
161
+}
162
+
163
+/**
164
+ * Returns all user test case functions
165
+ *
166
+ * @access private
167
+ * @return void
168
+ */
169
+function test_case_all_func()
170
+{
171
+   $functions = get_defined_functions();
172
+   $functions = $functions['user'];
173
+   $tests = array();
174
+   $name = $GLOBALS["limonade"]["test_case_current"];
175
+   while ($func = array_shift($functions)) {
176
+      $regexp = "/^test_{$name}_(.*)$/";
177
+      if(!preg_match($regexp, $func)) continue;
178
+      if($func == test_before_func_name()) continue;
179
+      // TODO: adding break for all test api methods
180
+      
181
+      $tests[] = $func;
182
+   }
183
+   return $tests;
184
+}
185
+
186
+/**
187
+ * Execute current test case
188
+ *
189
+ * @access private
190
+ * @return void
191
+ */
192
+function test_case_execute_current()
193
+{
194
+   $tests = test_case_all_func();
195
+   while($func = array_shift($tests))
196
+   {
197
+      test_call_func(test_before_func_name());
198
+      call_user_func($func);
199
+   }
200
+}
201
+
202
+
203
+function &test_case_current()
204
+{
205
+   $name = $GLOBALS["limonade"]["test_case_current"];
206
+   return $GLOBALS["limonade"]["test_cases"][$name];
207
+}
208
+
209
+
210
+
211
+function test_before_func_name()
212
+{
213
+   $test = test_case_current();
214
+   $func = "before_each_test_in_".$test["name"];
215
+   return $func;
216
+}
217
+
218
+function test_before_assert_func_name()
219
+{
220
+   $test = test_case_current();
221
+   $func = "before_each_assert_in_$name".$test["name"];
222
+   return $func;
223
+}
224
+
225
+function test_run_assertion()
226
+{
227
+   $name = $GLOBALS["limonade"]["test_case_current"];
228
+   $GLOBALS["limonade"]["test_cases"][$name]['assertions']++;
229
+   test_call_func(test_before_assert_func_name());
230
+}
231
+
232
+/**
233
+ * Calls a function if exists
234
+ *
235
+ * @param string $func the function name
236
+ * @param mixed $arg,.. (optional)
237
+ * @return mixed
238
+ */
239
+function test_call_func($func)
240
+{
241
+  if(empty($func)) return;
242
+  $args = func_get_args();
243
+  $func = array_shift($args);
244
+  if(function_exists($func)) return call_user_func_array($func, $args);
245
+  return;
246
+}
247
+
248
+/**
249
+ * Error handler 
250
+ * 
251
+ * @access private
252
+ * @return boolean true
253
+ */
254
+function test_error_handler($errno, $errstr, $errfile, $errline)
255
+{
256
+	if($errno < E_USER_ERROR || $errno > E_USER_NOTICE) 
257
+	   echo test_cli_format("!!! ERROR", "red") . " [$errno], $errstr in $errfile at line $errline\n";
258
+	$GLOBALS["limonade"]["test_errors"][] = array($errno, $errstr, $errfile, $errline);
259
+   return true;
260
+}
261
+
262
+/**
263
+ * Assert callback
264
+ * 
265
+ * @access private
266
+ * @param string $script 
267
+ * @param string $line 
268
+ * @param string $message 
269
+ * @return void
270
+ */
271
+function test_assert_failure($script, $line, $message)
272
+{
273
+   // Using the stack trace, find the outermost assert*() call
274
+   $stacktrace = array_slice(debug_backtrace(), 1); // skip self
275
+   $assertion = reset($stacktrace);
276
+   while ($stackframe = array_shift($stacktrace)) {
277
+    if (!preg_match('/^assert/', $stackframe['function']))
278
+      break;
279
+    $assertion = $stackframe;
280
+   }
281
+
282
+   extract($assertion, EXTR_PREFIX_ALL, 'assert');
283
+   $code = explode("\n", file_get_contents($assert_file));
284
+   $code = trim($code[$assert_line - 1]);
285
+   
286
+   list($assert_code, $message) = explode("//", $message);
287
+   echo test_cli_format("Assertion failed", "yellow");
288
+   echo " in script *{$assert_file}* (line {$assert_line}):\n";
289
+   echo "   * assertion: $code\n";
290
+   echo "   * message:   $message\n";
291
+   $name = $GLOBALS["limonade"]["test_case_current"];
292
+   $GLOBALS["limonade"]["test_cases"][$name]['failures']++;
293
+}
294
+
295
+function test_cli_format($text, $format) {
296
+    $formats = array(
297
+        "blue"       => 34,
298
+        "bold"       => 1,
299
+        "green"      => 32,
300
+        "highlight"  => 7,
301
+        "light_blue" => 36,
302
+        "purple"     => 35,
303
+        "red"        => 31,
304
+        "underline"  => 4,
305
+        "white"      => 37,
306
+        "yellow"     => 33
307
+    );
308
+
309
+    if (array_key_exists($format, $formats)) $format = $formats[$format];
310
+    return chr(27) . "[01;{$format} m{$text}" . chr(27) . "[00m";
311
+}
312
+
313
+/**
314
+ * Do HTTP request and return the response content.
315
+ * 
316
+ * @param string $url
317
+ * @param string $method
318
+ * @param bool $include_header
319
+ * @return string
320
+ * @author Nando Vieira
321
+ */
322
+function test_request($url, $method="GET", $include_header=false, $post_data=array(), $http_header=array()) {
323
+    $method = strtoupper($method);
324
+    $allowed_methods = array("GET", "PUT", "POST", "DELETE", "HEAD");
325
+    if(!in_array($method, $allowed_methods))
326
+    {
327
+      $message = "The requested method '$method' is not allowed";
328
+      return assert('false; //'.$message);
329
+    }
330
+    
331
+    $curl = curl_init($url);
332
+    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
333
+    curl_setopt($curl, CURLOPT_HEADER, $include_header);
334
+    curl_setopt($curl, CURLOPT_HTTPHEADER, $http_header);
335
+    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
336
+    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); 
337
+    if($method == 'POST' || $method == 'PUT')
338
+    {
339
+      curl_setopt($curl, CURLOPT_POST, 1);
340
+      curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
341
+    }
342
+    if($method == 'HEAD')
343
+    {
344
+      curl_setopt($curl, CURLOPT_NOBODY, true);
345
+    }
346
+    $response = curl_exec($curl);
347
+    curl_close($curl);
348
+
349
+    return $response;
350
+}

+ 37
- 0
lib/limonade/views/_debug.html.php Näytä tiedosto

@@ -0,0 +1,37 @@
1
+<?php if(option('env') > ENV_PRODUCTION && option('debug')): ?>
2
+  <?php if(!$is_http_error): ?>
3
+  <p>[<?php echo error_type($errno)?>]
4
+  	<?php echo $errstr?> (in <strong><?php echo $errfile?></strong> line <strong><?php echo $errline?></strong>)
5
+  	</p>
6
+  	<?php endif; ?>
7
+
8
+
9
+  <?php if($debug_args = set('_lim_err_debug_args')): ?>
10
+  <h2 id="debug-arguments">Debug arguments</h2>
11
+  	<pre><code><?php echo h(print_r($debug_args, true))?></code></pre>
12
+  <?php endif; ?>
13
+  
14
+  <h2 id="limonade-options">Options</strong></h2>
15
+  <pre><code><?php echo h(print_r(option(), true))?></code></pre>
16
+  <p class="bt top"><a href="#header">[ &#x2191; ]</a></p>
17
+  
18
+  <h2 id="environment">Environment</h2>
19
+  <pre><code><?php echo h(print_r(env(), true))?></code></pre>
20
+  <p class="bt top"><a href="#header">[ &#x2191; ]</a></p>
21
+  
22
+  <h2 id="debug-backtrace">Backtrace</h2>
23
+  <pre><code><?php echo h(print_r(debug_backtrace(), true))?></code></pre>
24
+  <p class="bt top"><a href="#header">[ &#x2191; ]</a></p>
25
+
26
+  <div id="debug-menu">
27
+    
28
+    <?php if($debug_args = set('_lim_err_debug_args')): ?>
29
+    <a href="#debug-arguments">Debug arguments</a> |
30
+    <?php endif; ?>
31
+    <a href="#limonade-options">Options</a> |
32
+    <a href="#environment">Environment</a> |
33
+    <a href="#debug-backtrace">Backtrace</a> |
34
+    <a href="#header">[ &#x2191; ]</a>
35
+  </div>
36
+  
37
+<?php endif; ?>

+ 15
- 0
lib/limonade/views/_notices.html.php Näytä tiedosto

@@ -0,0 +1,15 @@
1
+<?php if(!empty($notices)): ?>
2
+<div class="lim-debug lim-notices">
3
+  <h4> &#x2192; Notices and warnings</h4>
4
+  <dl>
5
+  <?php $cpt = 1; foreach($notices as $notice): ?>
6
+    <dt>[<?php echo $cpt.'. '.error_type($notice['errno'])?>]</dt>
7
+    <dd>
8
+    <?php echo $notice['errstr']?> in <strong><code><?php echo $notice['errfile']?></code></strong> 
9
+    line <strong><code><?php echo $notice['errline']?></code></strong>
10
+    </dd>
11
+  <?php $cpt++; endforeach; ?>
12
+  </dl>
13
+  <hr>
14
+</div>
15
+<?php endif; ?>

+ 22
- 0
lib/limonade/views/default_layout.php Näytä tiedosto

@@ -0,0 +1,22 @@
1
+<!DOCTYPE html>
2
+<html>
3
+<head>
4
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+	<title>Limonade, the fizzy PHP micro-framework</title>
6
+	<link rel="stylesheet" href="<?php echo url_for('/_lim_css/screen.css');?>" type="text/css" media="screen">
7
+</head>
8
+<body>
9
+  <div id="header">
10
+    <h1>Limonade</h1>
11
+  </div>
12
+  
13
+  <div id="content">
14
+    <?php echo error_notices_render(); ?>
15
+    <div id="main">
16
+      <?php echo $content;?>
17
+      <hr class="space">
18
+    </div>
19
+  </div>
20
+
21
+</body>
22
+</html>

+ 6
- 0
lib/limonade/views/error.html.php Näytä tiedosto

@@ -0,0 +1,6 @@
1
+  <h1><?php echo h(error_http_status($errno));?></h1>
2
+  <?php if($is_http_error): ?>
3
+  <p><?php echo h($errstr)?></p>
4
+  <?php endif; ?>
5
+  
6
+  <?php echo  render('_debug.html.php', null, $vars); ?>