vweb: run vfmt, add it to `v test-cleancode`

pull/7606/head
Delyan Angelov 2020-12-27 11:38:12 +02:00
parent 1b9d514275
commit d563261e58
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
8 changed files with 94 additions and 181 deletions

View File

@ -66,6 +66,7 @@ const (
'vlib/semver/',
'vlib/strings/',
'vlib/time/',
'vlib/vweb/',
]
)

View File

@ -8,8 +8,6 @@ const (
known_failing_exceptions = [
'vlib/crypto/aes/const.v',
/* multiple narrow columns of []string turned to 1 long single column, otherwise works */
'vlib/vweb/vweb.v',
/* $for method in T.methods { => $for method in T(methods) { , `return // xx` => parse expr error */
'vlib/v/gen/js/tests/life.v',
/* error: unexpected `,`, expecting ), on JS.setInterval(fn () { show(game) game = step(game) }, 500) */
'vlib/builtin/js/builtin.v',
@ -17,11 +15,10 @@ const (
'vlib/builtin/js/jsfns_node.js.v',
'vlib/builtin/js/jsfns.js.v',
'vlib/builtin/js/jsfns_browser.js.v',
'vlib/builtin/bare/linuxsys_bare.v',
/* error: expr(): bad token `asm`, on `asm {}` */
'vlib/picoev/picoev.v',
'vlib/builtin/bare/linuxsys_bare.v',
/* the fn args are removed, then `cb fn (picohttpparser.Request, mut picohttpparser.Response)` can not be reparsed */
'vlib/os/os.v' /* os.v - `a := [ c'/bin/sh', c'-c', byteptr(cmd.str), 0 ]` */,
'vlib/picoev/picoev.v',
]
)

View File

@ -77,16 +77,12 @@ fn (am AssetManager) combine(asset_type string, to_file bool) string {
if to_file {
return out_file
}
cached := os.read_file(out_file) or {
return ''
}
cached := os.read_file(out_file) or { return '' }
return cached
}
// rebuild
for asset in am.get_assets(asset_type) {
data := os.read_file(asset.file_path) or {
return ''
}
data := os.read_file(asset.file_path) or { return '' }
out += data
}
if am.minify {
@ -100,13 +96,9 @@ fn (am AssetManager) combine(asset_type string, to_file bool) string {
return out
}
if !os.is_dir(am.cache_dir) {
os.mkdir(am.cache_dir) or {
panic(err)
}
}
mut file := os.create(out_file) or {
panic(err)
os.mkdir(am.cache_dir) or { panic(err) }
}
mut file := os.create(out_file) or { panic(err) }
file.write(out.bytes())
file.close()
return out_file

View File

@ -20,15 +20,12 @@ fn cache_dir(test_name string) string {
fn get_test_file_path(file string) string {
path := os.join_path(base_cache_dir(), file)
if ! os.is_dir(base_cache_dir()) {
if !os.is_dir(base_cache_dir()) {
os.mkdir_all(base_cache_dir())
}
if ! os.exists(path) {
if !os.exists(path) {
os.write_file(path, get_test_file_contents(file))
}
return path
}
@ -40,7 +37,6 @@ fn get_test_file_contents(file string) string {
'test2.css' { '.two {\n\tcolor: #996633;\n}\n' }
else { 'wibble\n' }
}
return contents
}
@ -80,23 +76,19 @@ fn test_combine_css() {
mut am := assets.new_manager()
am.cache_dir = cache_dir('test_combine_css')
clean_cache_dir(am.cache_dir)
am.add_css(get_test_file_path('test1.css'))
am.add_css(get_test_file_path('test2.css'))
// TODO: How do I test non-minified, is there a "here doc" format that keeps formatting?
am.minify = true
expected := '.one { color: #336699; } .two { color: #996633; } '
actual := am.combine_css(false)
assert actual == expected
assert actual.contains(expected)
// Test cache path doesn't change when input files and minify setting do not.
path1 := am.combine_css(true)
clean_cache_dir(am.cache_dir)
path2 := am.combine_css(true)
assert path1 == path2
clean_cache_dir(am.cache_dir)
}
@ -104,10 +96,8 @@ fn test_combine_js() {
mut am := assets.new_manager()
am.cache_dir = cache_dir('test_combine_js')
clean_cache_dir(am.cache_dir)
am.add_js(get_test_file_path('test1.js'))
am.add_js(get_test_file_path('test2.js'))
expected1 := '{"one": 1}'
expected2 := '{"two": 2}'
expected := expected1 + '\n' + expected2 + '\n'
@ -116,20 +106,17 @@ fn test_combine_js() {
assert actual.contains(expected)
assert actual.contains(expected1)
assert actual.contains(expected2)
am.minify = true
clean_cache_dir(am.cache_dir)
expected3 := expected1 + ' ' + expected2 + ' '
actual2 := am.combine_js(false)
assert actual2 == expected3
assert actual2.contains(expected3)
// Test cache path doesn't change when input files and minify setting do not.
path1 := am.combine_js(true)
clean_cache_dir(am.cache_dir)
path2 := am.combine_js(true)
assert path1 == path2
clean_cache_dir(am.cache_dir)
}
@ -141,29 +128,24 @@ fn test_include_css() {
actual := am.include_css(false)
assert actual == expected
assert actual.contains(expected)
// Two lines of output.
file2 := get_test_file_path('test2.css')
am.add_css(file2)
am.cache_dir = cache_dir('test_include_css')
clean_cache_dir(am.cache_dir)
expected2 := expected + '<link rel="stylesheet" href="$file2">\n'
actual2 := am.include_css(false)
assert actual2 == expected2
assert actual2.contains(expected2)
// Combined output.
clean_cache_dir(am.cache_dir)
actual3 := am.include_css(true)
assert actual3.contains(expected2) == false
assert actual3.starts_with('<link rel="stylesheet" href="${am.cache_dir}/') == true
assert actual3.starts_with('<link rel="stylesheet" href="$am.cache_dir/') == true
// Test cache path doesn't change when input files and minify setting do not.
clean_cache_dir(am.cache_dir)
actual4 := am.include_css(true)
assert actual4 == actual3
clean_cache_dir(am.cache_dir)
}
@ -175,28 +157,23 @@ fn test_include_js() {
actual := am.include_js(false)
assert actual == expected
assert actual.contains(expected)
// Two lines of output.
file2 := get_test_file_path('test2.js')
am.add_js(file2)
am.cache_dir = cache_dir('test_include_js')
clean_cache_dir(am.cache_dir)
expected2 := expected + '<script type="text/javascript" src="$file2"></script>\n'
actual2 := am.include_js(false)
assert actual2 == expected2
assert actual2.contains(expected2)
// Combined output.
clean_cache_dir(am.cache_dir)
actual3 := am.include_js(true)
assert actual3.contains(expected2) == false
assert actual3.starts_with('<script type="text/javascript" src="${am.cache_dir}/')
assert actual3.starts_with('<script type="text/javascript" src="$am.cache_dir/')
// Test cache path doesn't change when input files and minify setting do not.
clean_cache_dir(am.cache_dir)
actual4 := am.include_js(true)
assert actual4 == actual3
clean_cache_dir(am.cache_dir)
}

View File

@ -64,9 +64,7 @@ fn test_a_simple_tcp_client_can_connect_to_the_vweb_server() {
}
fn test_a_simple_tcp_client_simple_route() {
received := simple_tcp_client({
path: '/simple'
}) or {
received := simple_tcp_client(path: '/simple') or {
assert err == ''
return
}
@ -77,9 +75,7 @@ fn test_a_simple_tcp_client_simple_route() {
}
fn test_a_simple_tcp_client_html_page() {
received := simple_tcp_client({
path: '/html_page'
}) or {
received := simple_tcp_client(path: '/html_page') or {
assert err == ''
return
}
@ -97,9 +93,7 @@ fn assert_common_http_headers(x http.Response) {
}
fn test_http_client_index() {
x := http.get('http://127.0.0.1:$sport/') or {
panic(err)
}
x := http.get('http://127.0.0.1:$sport/') or { panic(err) }
assert_common_http_headers(x)
assert x.headers['Content-Type'] == 'text/plain'
assert x.text == 'Welcome to VWeb'
@ -112,61 +106,45 @@ fn test_http_client_404() {
'http://127.0.0.1:$sport/unknown',
]
for url in url_404_list {
res := http.get(url) or {
panic(err)
}
res := http.get(url) or { panic(err) }
assert res.status_code == 404
}
}
fn test_http_client_simple() {
x := http.get('http://127.0.0.1:$sport/simple') or {
panic(err)
}
x := http.get('http://127.0.0.1:$sport/simple') or { panic(err) }
assert_common_http_headers(x)
assert x.headers['Content-Type'] == 'text/plain'
assert x.text == 'A simple result'
}
fn test_http_client_html_page() {
x := http.get('http://127.0.0.1:$sport/html_page') or {
panic(err)
}
x := http.get('http://127.0.0.1:$sport/html_page') or { panic(err) }
assert_common_http_headers(x)
assert x.headers['Content-Type'] == 'text/html'
assert x.text == '<h1>ok</h1>'
}
fn test_http_client_settings_page() {
x := http.get('http://127.0.0.1:$sport/bilbo/settings') or {
panic(err)
}
x := http.get('http://127.0.0.1:$sport/bilbo/settings') or { panic(err) }
assert_common_http_headers(x)
assert x.text == 'username: bilbo'
//
y := http.get('http://127.0.0.1:$sport/kent/settings') or {
panic(err)
}
y := http.get('http://127.0.0.1:$sport/kent/settings') or { panic(err) }
assert_common_http_headers(y)
assert y.text == 'username: kent'
}
fn test_http_client_user_repo_settings_page() {
x := http.get('http://127.0.0.1:$sport/bilbo/gostamp/settings') or {
panic(err)
}
x := http.get('http://127.0.0.1:$sport/bilbo/gostamp/settings') or { panic(err) }
assert_common_http_headers(x)
assert x.text == 'username: bilbo | repository: gostamp'
//
y := http.get('http://127.0.0.1:$sport/kent/golang/settings') or {
panic(err)
}
y := http.get('http://127.0.0.1:$sport/kent/golang/settings') or { panic(err) }
assert_common_http_headers(y)
assert y.text == 'username: kent | repository: golang'
//
z := http.get('http://127.0.0.1:$sport/missing/golang/settings') or {
panic(err)
}
z := http.get('http://127.0.0.1:$sport/missing/golang/settings') or { panic(err) }
assert z.status_code == 404
}
@ -181,17 +159,13 @@ fn test_http_client_json_post() {
age: 123
}
json_for_ouser := json.encode(ouser)
x := http.post_json('http://127.0.0.1:$sport/json_echo', json_for_ouser) or {
panic(err)
}
x := http.post_json('http://127.0.0.1:$sport/json_echo', json_for_ouser) or { panic(err) }
$if debug_net_socket_client ? {
eprintln('json response: $x')
}
assert x.headers['Content-Type'] == 'application/json'
assert x.text == json_for_ouser
nuser := json.decode(User, x.text) or {
User{}
}
nuser := json.decode(User, x.text) or { User{} }
assert '$ouser' == '$nuser'
}
@ -207,12 +181,9 @@ fn test_http_client_shutdown_does_not_work_without_a_cookie() {
fn testsuite_end() {
// This test is guaranteed to be called last.
// It sends a request to the server to shutdown.
x := http.fetch('http://127.0.0.1:$sport/shutdown', {
method: .get
cookies: {
x := http.fetch('http://127.0.0.1:$sport/shutdown', method: .get, cookies: {
'skey': 'superman'
}
}) or {
}) or {
assert err == ''
return
}

View File

@ -86,9 +86,7 @@ pub fn (mut app App) json() vweb.Result {
}
pub fn (mut app App) shutdown() vweb.Result {
session_key := app.vweb.get_cookie('skey') or {
return app.vweb.not_found()
}
session_key := app.vweb.get_cookie('skey') or { return app.vweb.not_found() }
if session_key != 'superman' {
return app.vweb.not_found()
}

View File

@ -13,17 +13,15 @@ const (
// compile_file compiles the content of a file by the given path as a template
pub fn compile_file(path string, fn_name string) string {
html := os.read_file(path) or {
panic('html failed')
}
html := os.read_file(path) or { panic('html failed') }
return compile_template(html, fn_name)
}
enum State {
html
css // <style>
js // <script>
//span // span.{
js // <script>
// span // span.{
}
pub fn compile_template(html_ string, fn_name string) string {
@ -45,15 +43,15 @@ pub fn compile_template(html_ string, fn_name string) string {
footer = f.trim_space().replace("\'", '"')
html += footer
}
mut lines := html.split_into_lines()
lstartlength := lines.len * 30
mut s := strings.new_builder(1000)
// base := path.all_after_last('/').replace('.html', '')
s.writeln("
import strings
// === vweb html template ===
fn vweb_tmpl_${fn_name}() {
mut sb := strings.new_builder(${lines.len * 30})\n
mut sb := strings.new_builder($lstartlength)\n
header := \' \' // TODO remove
_ = header
footer := \' \' // TODO remove
@ -63,25 +61,21 @@ _ = footer
s.write(str_start)
mut state := State.html
mut in_span := false
//for _line in lines {
for i := 0; i < lines.len; i ++ {
// for _line in lines {
for i := 0; i < lines.len; i++ {
line := lines[i].trim_space()
if line == '<style>' {
state = .css
} else if line == '</style>' {
state = .html
}
else if line == '<script>' {
} else if line == '<script>' {
state = .js
}
else if line == '</script>' {
} else if line == '</script>' {
state = .html
}
if line.contains('@include ') && false {
// TODO
pos := line.index('@include ') or {
continue
}
pos := line.index('@include ') or { continue }
file_name := line[pos + 9..]
file_path := os.join_path('templates', '${file_name}.html')
mut file_content := os.read_file(file_path) or {
@ -90,29 +84,23 @@ _ = footer
file_content = file_content.replace("\'", '"')
lines2 := file_content.split_into_lines()
for l in lines2 {
lines.insert(i+1, l)
lines.insert(i + 1, l)
}
continue
//s.writeln(file_content)
// s.writeln(file_content)
} else if line.contains('@js ') {
pos := line.index('@js') or {
continue
}
pos := line.index('@js') or { continue }
s.write('<script src="')
s.write(line[pos + 5..line.len-1])
s.write(line[pos + 5..line.len - 1])
s.writeln('"></script>')
} else if line.contains('@css ') {
pos := line.index('@css') or {
continue
}
pos := line.index('@css') or { continue }
s.write('<link href="')
s.write(line[pos + 6..line.len-1])
s.write(line[pos + 6..line.len - 1])
s.writeln('" rel="stylesheet" type="text/css">')
} else if line.contains('@if ') {
s.writeln(str_end)
pos := line.index('@if') or {
continue
}
pos := line.index('@if') or { continue }
s.writeln('if ' + line[pos + 4..] + '{')
s.writeln(str_start)
} else if line.contains('@end') {
@ -125,16 +113,14 @@ _ = footer
s.writeln(str_start)
} else if line.contains('@for') {
s.writeln(str_end)
pos := line.index('@for') or {
continue
}
pos := line.index('@for') or { continue }
s.writeln('for ' + line[pos + 4..] + '{')
s.writeln(str_start)
} else if state == .html && line.contains('span.') && line.ends_with('{') {
// `span.header {` => `<span class='header'>`
class := line.find_between('span.', '{').trim_space()
s.writeln('<span class="$class">')
in_span = true
in_span = true
} else if state == .html && line.contains('.') && line.ends_with('{') {
// `.header {` => `<div class='header'>`
class := line.find_between('.', '{').trim_space()
@ -162,4 +148,3 @@ _ = footer
s.writeln('// === end of vweb html template ===')
return s.str()
}

View File

@ -20,20 +20,20 @@ pub const (
http_404 = 'HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n${headers_close}404 Not Found'
http_500 = 'HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\n${headers_close}500 Internal Server Error'
mime_types = {
'.css': 'text/css; charset=utf-8'
'.gif': 'image/gif'
'.htm': 'text/html; charset=utf-8'
'.css': 'text/css; charset=utf-8'
'.gif': 'image/gif'
'.htm': 'text/html; charset=utf-8'
'.html': 'text/html; charset=utf-8'
'.jpg': 'image/jpeg'
'.js': 'application/javascript'
'.jpg': 'image/jpeg'
'.js': 'application/javascript'
'.json': 'application/json'
'.md': 'text/markdown; charset=utf-8'
'.pdf': 'application/pdf'
'.png': 'image/png'
'.svg': 'image/svg+xml'
'.txt': 'text/plain; charset=utf-8'
'.md': 'text/markdown; charset=utf-8'
'.pdf': 'application/pdf'
'.png': 'image/png'
'.svg': 'image/svg+xml'
'.txt': 'text/plain; charset=utf-8'
'.wasm': 'application/wasm'
'.xml': 'text/xml; charset=utf-8'
'.xml': 'text/xml; charset=utf-8'
}
max_http_post_size = 1024 * 1024
default_port = 8080
@ -46,8 +46,8 @@ mut:
content_type string = 'text/plain'
status string = '200 OK'
pub:
req http.Request
conn net.TcpConn
req http.Request
conn net.TcpConn
// TODO Response
pub mut:
form map[string]string
@ -117,7 +117,9 @@ pub fn (mut ctx Context) redirect(url string) Result {
return Result{}
}
ctx.done = true
send_string(ctx.conn, 'HTTP/1.1 302 Found\r\nLocation: ${url}${ctx.headers}\r\n${headers_close}') or { return Result{} }
send_string(ctx.conn, 'HTTP/1.1 302 Found\r\nLocation: $url$ctx.headers\r\n$headers_close') or {
return Result{}
}
return Result{}
}
@ -126,8 +128,8 @@ pub fn (mut ctx Context) not_found() Result {
return Result{}
}
ctx.done = true
send_string(ctx.conn, http_404) or {}
return vweb.Result{}
send_string(ctx.conn, http_404) or { }
return Result{}
}
pub fn (mut ctx Context) set_cookie(cookie Cookie) {
@ -212,11 +214,11 @@ pub fn run_app<T>(mut app T, port int) {
for {
mut conn := l.accept() or { panic('accept() failed') }
handle_conn<T>(mut conn, mut app)
//app.vweb.page_gen_time = time.ticks() - t
//eprintln('handle conn() took ${time.ticks()-t}ms')
//message := readall(conn)
//println(message)
/*
// app.vweb.page_gen_time = time.ticks() - t
// eprintln('handle conn() took ${time.ticks()-t}ms')
// message := readall(conn)
// println(message)
/*
if message.len > max_http_post_size {
println('message.len = $message.len > max_http_post_size')
conn.send_string(http_500) or {}
@ -238,13 +240,13 @@ pub fn run_app<T>(mut app T, port int) {
fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
conn.set_read_timeout(1 * time.second)
defer { conn.close() or {} }
//fn handle_conn<T>(conn net.Socket, app_ T) T {
//mut app := app_
//first_line := strip(lines[0])
defer {
conn.close() or { }
}
// fn handle_conn<T>(conn net.Socket, app_ T) T {
// mut app := app_
// first_line := strip(lines[0])
mut reader := io.new_buffered_reader(reader: io.make_reader(conn))
page_gen_start := time.ticks()
first_line := reader.read_line() or {
println('Failed first_line')
@ -259,36 +261,34 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
vals := first_line.split(' ')
if vals.len < 2 {
println('no vals for http')
send_string(conn, http_500) or {}
send_string(conn, http_500) or { }
return
}
mut headers := []string{}
mut body := ''
mut in_headers := true
mut len := 0
//for line in lines[1..] {
for _ in 0..100 {
//println(j)
// for line in lines[1..] {
for _ in 0 .. 100 {
// println(j)
line := reader.read_line() or {
println('Failed read_line')
break
}
sline := strip(line)
if sline == '' {
//if in_headers {
// End of headers, no body => exit
if len == 0 {
break
}
// if in_headers {
// End of headers, no body => exit
if len == 0 {
break
}
//} //else {
// End of body
//break
// End of body
// break
//}
// read body
read_body := io.read_all(reader: reader) or { []byte{} }
body += read_body.bytestr()
break
}
if in_headers {
@ -343,7 +343,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
mime_type := app.vweb.static_mime_types[static_file_name]
if static_file != '' && mime_type != '' {
data := os.read_file(static_file) or {
send_string(conn, http_404) or {}
send_string(conn, http_404) or { }
return
}
app.vweb.send_response_to_client(mime_type, data)
@ -491,7 +491,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
}
if action == '' {
// site not found
send_string(conn, http_404) or {}
send_string(conn, http_404) or { }
return
}
$for method in T.methods {
@ -526,12 +526,8 @@ fn (mut ctx Context) parse_form(s string) {
if keyval.len != 2 {
continue
}
key := urllib.query_unescape(keyval[0]) or {
continue
}
val := urllib.query_unescape(keyval[1]) or {
continue
}
key := urllib.query_unescape(keyval[0]) or { continue }
val := urllib.query_unescape(keyval[1]) or { continue }
$if debug {
println('http form "$key" => "$val"')
}
@ -543,9 +539,7 @@ fn (mut ctx Context) parse_form(s string) {
}
fn (mut ctx Context) scan_static_directory(directory_path string, mount_path string) {
files := os.ls(directory_path) or {
panic(err)
}
files := os.ls(directory_path) or { panic(err) }
if files.len > 0 {
for file in files {
full_path := directory_path + '/' + file
@ -556,8 +550,7 @@ fn (mut ctx Context) scan_static_directory(directory_path string, mount_path str
// Rudimentary guard against adding files not in mime_types.
// Use serve_static directly to add non-standard mime types.
if ext in mime_types {
ctx.serve_static(mount_path + '/' + file, full_path,
mime_types[ext])
ctx.serve_static(mount_path + '/' + file, full_path, mime_types[ext])
}
}
}
@ -639,7 +632,6 @@ fn filter(s string) string {
pub type RawHtml = string
fn send_string(conn net.TcpConn, s string) ? {
conn.write(s.bytes())?
conn.write(s.bytes()) ?
}