From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E0BDFC11F64 for ; Thu, 1 Jul 2021 06:19:36 +0000 (UTC) Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B349261425 for ; Thu, 1 Jul 2021 06:19:35 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B349261425 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 0A5E9832A2; Thu, 1 Jul 2021 08:17:17 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="n4geB5L7"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id BE7378324F; Thu, 1 Jul 2021 08:16:53 +0200 (CEST) Received: from mail-qk1-x72c.google.com (mail-qk1-x72c.google.com [IPv6:2607:f8b0:4864:20::72c]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id AF4308326A for ; Thu, 1 Jul 2021 08:16:28 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=seanga2@gmail.com Received: by mail-qk1-x72c.google.com with SMTP id 65so5011287qko.5 for ; Wed, 30 Jun 2021 23:16:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=uYFW+eha2yjc2LZPtiy+Ds0cR6cXIiRrqbwimyt7+FU=; b=n4geB5L7p19jXag1WrjSqkGV7nEI2kusJcVINT4puxZMaiR9oS5SaesF/9FTqq2LVZ 9q8dCnI3eCP6DqoTjSgMqhX79w5zzODviGL29XFk66f4JVnz8JNC//3luy5MGxeRE/dv Y+0nsr1cCzQyry+RnWl2HEXTz9pCLeQxD4qUhlpZRbN5ZdJ8839xgAsQouJvdAjScWCJ uoeUg6JTqFJ8YNbg8FIHe44Je3YeZI1eHexyhuJ+rIC9IJ9kwBMHp7AxWoV2iVEPOE5D kJ6QxzEIkMS4+1csBkq9CUit29rJ7e8tabBP5UVnm/uohbMhkpynnPmcCwrZr+dUTJBw VomQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=uYFW+eha2yjc2LZPtiy+Ds0cR6cXIiRrqbwimyt7+FU=; b=Hu7jBCbsZNG5JGEaayNhgcXYlyyBLHJx38Eu0MO7IGShlok10reqaCsiKWYrRT0fK8 RuudjjBJWJuwzSwMCc64G5aUiDDNJnPTt1XGaJh8cRWwCE8vL+GbiSyrSRWBDZD3mVRF hyzTkY7WoXcT1FiyrLmE98nvrKg8zgRnBWvpR9e0afmG5xM95TbadWQp+YhmQC68/neo ps8e4r7p9HwoJ9D0bshkv8fIsRmNez2xKpQHqBV8SiKnesPwETXcNF/dPsrqKh9/Xp56 fECYs3lpVkqP8o97QR7py99gHmFddBwu7XDFgW1pMwuVz3IgjXfApL7B9hvvMqedw9J4 kEAw== X-Gm-Message-State: AOAM532OCmqT/y8B6y5iOhpxJ7q3ButjXXbZ+aSkA7C7Yfa+6EppI1fW Vl9WCk6ympfc8a1b1fTPKAIviJmiQ+o= X-Google-Smtp-Source: ABdhPJxlLACPvh7jIn1DMWXdzD1YBcNNArqC8OQgAryteJgyylY2X3szPAPoPC+ZH5mSNl/2rBaqdQ== X-Received: by 2002:a37:5886:: with SMTP id m128mr33895064qkb.414.1625120187340; Wed, 30 Jun 2021 23:16:27 -0700 (PDT) Received: from godwin.fios-router.home (pool-74-96-87-9.washdc.fios.verizon.net. [74.96.87.9]) by smtp.gmail.com with ESMTPSA id g21sm1684673qts.90.2021.06.30.23.16.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Jun 2021 23:16:27 -0700 (PDT) From: Sean Anderson To: u-boot@lists.denx.de, Tom Rini Cc: =?UTF-8?q?Marek=20Beh=C3=BAn?= , Wolfgang Denk , Simon Glass , Roland Gaudig , Heinrich Schuchardt , Kostas Michalopoulos , Sean Anderson Subject: [RFC PATCH 17/28] test: Add tests for LIL Date: Thu, 1 Jul 2021 02:16:00 -0400 Message-Id: <20210701061611.957918-18-seanga2@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210701061611.957918-1-seanga2@gmail.com> References: <20210701061611.957918-1-seanga2@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean This tests several aspects of the parser. These tests are primarily adapted from the *.lil code examples included with upstream LIL. These tests should probably get their own category, especially if I add additional styles of tests. Signed-off-by: Sean Anderson --- Yes, I know checkpatch complains about the quoted string being split, but that warning is intended for user-visible strings. MAINTAINERS | 1 + test/cmd/Makefile | 1 + test/cmd/lil.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 341 insertions(+) create mode 100644 test/cmd/lil.c diff --git a/MAINTAINERS b/MAINTAINERS index 0184de5f93..3bf460127b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -771,6 +771,7 @@ M: Sean Anderson S: Maintained F: common/cli_lil.c F: include/cli_lil.h +F: test/cmd/lil.c LOGGING M: Simon Glass diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 2cfe43a6bd..4f7440cb44 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -5,6 +5,7 @@ ifdef CONFIG_HUSH_PARSER obj-$(CONFIG_CONSOLE_RECORD) += test_echo.o endif +obj-$(CONFIG_LIL_FULL) += lil.o obj-y += mem.o obj-$(CONFIG_CMD_ADDRMAP) += addrmap.o obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o diff --git a/test/cmd/lil.c b/test/cmd/lil.c new file mode 100644 index 0000000000..896b2fed15 --- /dev/null +++ b/test/cmd/lil.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0+ AND Zlib +/* + * Copyright (C) 2021 Sean Anderson + * Copyright (C) 2010-2021 Kostas Michalopoulos + * + * This file contains code which originated from the LIL project, licensed under + * Zlib. All modifications are licensed under GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +const char helpers[] = + "proc assert {cond} {" + "if not [upeval expr [set cond]] {" + "error [set cond]" + "}" + "};" + "proc assert_err {cmd} {" + "set ok 1;" + "try {upeval $cmd; set ok 0} {};" + "assert {$ok};" + "};" + "proc asserteq {expr1 expr2} {" + "set val1 [upeval 'expr \"$expr1\"'];" + "set val2 [upeval 'expr \"$expr2\"'];" + "if {$val1 != $val2} {" + "error '$expr1 == ${expr2}: " + "Expected ${val1}, got $val2'" + "}" + "};" + "proc asserteq_str {expr1 expr2} {" + "set val1 [upeval 'subst \"$expr1\"'];" + "set val2 [upeval 'subst \"$expr2\"'];" + "if not [streq $val1 $val2] {" + "error '$expr1 == ${expr2}: " + "Expected ${val1}, got $val2'" + "}" + "};" + "proc asserteq_list {xs ys} {" + "set xlen [count $xs];" + "set ylen [count $ys];" + "if not {$xlen == $ylen} {" + "error '\\[count ${xs}\\] == \\[count ${ys}\\]: " + "Expected ${xlen}, got $ylen'\n" + "};" + "for {set i 0} {$i < $xlen} {incr i} {" + "set x [index $xs $i];" + "set y [index $ys $i];" + "if not {[streq $x $y]} {" + "error '$xs == ${ys}: " + "Expected $x at ${i}, got $y'" + "}" + "}" + "}"; + +static const struct { + const char *name; + const char *cmd; +} lil_tests[] = { + {"and", + "proc and args {" + "foreach [slice $args 1] {" + "upeval 'downeval \\'set v \\'\\[${i}\\]';" + "if not $v { return 0 }" + "};" + "return 1" + "};" + "set a 0;" + "set final [and {set a 3} {return 0} {set a 32}];" + "asserteq 0 {$final};" + "assert 3 {$a};" + }, + {"assert", + "assert 1;" + "assert_err {assert 0};" + "asserteq 1 1;" + "assert_err {asserteq 1 0};" + "asserteq_str {string one} {string one};" + "assert_err {asserteq_str {string one} {string two}};" + "asserteq_list [list 1 2 3] [list 1 2 3];" + "assert_err {asserteq_list [list 1 2] [list 1 2 3]};" + "assert_err {asserteq_list [list 1 2 3] [list 1 2]};" + "assert_err {asserteq_list [list 1 2 3] [list 1 2 4]};" + }, + {"downeval", + "proc grab-some-list {} {" + "set items {};" + "upeval {" + "foreach $some-list {" + "downeval 'append items $i'" + "}" + "};" + "return $items" + "};" + "set some-list [list foo bar baz blah moo boo];" + "asserteq_list $some-list [grab-some-list]" + }, + {"expr", + "asserteq 7 {1 + ( 2 * 3 )};" + "asserteq 7 {1+(2*3)};" + "asserteq -6 {1+ ~(2*3)};" + "asserteq -6 {1 + ~( 2 * 3 )};" + "asserteq -6 {1 +~ (2*3 )};" + "asserteq -6 {~(2*3)+1};" + "asserteq 0 {1*!(2+2)};" + "asserteq -1 {~!(!{})};" + "asserteq 1 {1 +~*(2*3)};" + "asserteq 1 {'hello'};" + "asserteq 0 {0};" + "asserteq 0 {{}};" + "asserteq 1 {()};" + "asserteq 1 {( )};" + "asserteq_str '' {[expr]};" + }, + {"factorial", + "proc fact {n} {" + "if {$n} {" + "expr {$n * [fact [expr {$n - 1}]]}" + "} {" + "return 1" + "}" + "};" + "asserteq 1 {[fact 0]};" + "asserteq 1 {[fact 1]};" + "asserteq 6 {[fact 3]};" + "asserteq 3628800 {[fact 10]};" + "asserteq 2432902008176640000 {[fact 20]}" + }, + {"filter", + "set short_procs [filter [reflect procs] {[length $x] < 5}];" + "foreach $short_procs {assert {[length $i] < 5}}" + }, + {"funcs", + "proc lapply {list proc} {" + "set ret {};" + "foreach $list {" + "append ret [$proc $i];" + "};" + "return $ret" + "};" + "set list [list {bad's day} {good's day} eh??];" + "asserteq_list [lapply $list split] [list " + "[list {bad's} day] " + "[list {good's} day] " + "[list eh??]" + "];" + "asserteq_list [lapply $list length] [list 9 10 4];" + "asserteq_list [lapply $list [proc {a} {" + "return [index [split $a] 0]" + "}]] [list {bad's} {good's} eh??]" + }, + {"lists", + "set l [list foo bar baz bad];" + "asserteq_str baz {[index $l 2]};" + "append l 'Hello, world!';" + "asserteq_list $l [list foo bar baz bad 'Hello, world!'];" + "set l [subst $l];" + "asserteq_list $l [list foo bar baz bad Hello, world!];" + "lmap $l foox barx bamia;" + "asserteq_str foo {$foox};" + "asserteq_str bar {$barx};" + "asserteq_str baz {$bamia};" + "set l {one # linebreaks are ignored in list parsing mode\n" + "\n" + "two;three # a semicolon still counts as line break\n" + " # (which in list mode is treated as a\n" + " # separator for list entries)\n" + "# of course a semicolon inside quotes is treated like normal\n" + "three';'and';a;half'\n" + "# like in code mode, a semicolon will stop the comment; four\n" + "\n" + "# below we have a quote, square brackets for inline\n" + "# expansions are still taken into consideration\n" + "[quote {this line will be ignored completely\n" + " as will this line and instead be replaced\n" + " with the 'five' below since while in code\n" + " mode (that is, inside the brackets here)\n" + " linebreaks are still processed}\n" + " quote five]\n" + "\n" + "# The curly brackets are also processed so the next three\n" + "# lines will show up as three separate lines\n" + "{six\n" + "seven\n" + "eight}}\n" + "asserteq_list $l [list one two three 'three;and;a;half' four " + "five 'six\\nseven\\neight'];" + }, + {"local", + "proc bits-for {x} {" + "local y bits;" + "set y 0 bits 0;" + "while {$y <= $x} {" + "incr bits;" + "set y [expr 1 << $bits]" + "};" + "return $bits" + "};" + "set y 1001;" + "set bits [bits-for $y];" + "set x 45;" + "set bitsx [bits-for $x];" + "asserteq 1001 {$y};" + "asserteq 10 {$bits};" + "asserteq 45 {$x};" + "asserteq 6 {$bitsx}" + }, + {"multiline comment", + "# this line will not be executed, but the following will\n" + "set ok1 1\n" + "## This is a multiline comment\n" + " which, as the name implies,\n" + " spans multiple lines.\n" + "set ok2 1\n" + " the code above wouldn't execute,\n" + " but this will --> ##set ok3 1\n" + "### more than two #s will not count as multiline comments\n" + "set ok4 1\n" + "# Note that semicolons can be used as linebreaks so\n" + "# this code will be executed: ; set ok5 1\n" + "##\n" + " ...however inside multiline comments semicolons do not\n" + " stop the comment section (pretty much like linebreaks)\n" + " and this code will not be executed: ; set ok6 1\n" + "##\n" + "# Also note that unlike in regular code, semicolons cannot\n" + "# be escaped in single-line comments, e.g.: ; set ok7 1\n" + "asserteq_str 1 {$ok1};" + "assert {![reflect has-var ok2]}" + "asserteq_str 1 {$ok3};" + "asserteq_str 1 {$ok4};" + "asserteq_str 1 {$ok5};" + "assert {![reflect has-var ok6]}" + "asserteq_str 1 {$ok7};" + }, + {"multiline code", + "asserteq_list [list hello \\\n" + " world] [list hello world]" + }, + {"return", + "proc uses_return {} {" + "return 1;" + "return 0;" + "};" + "proc doesnt_use_return {} {" + "quote 1;" + "};" + "proc uses_result {} {" + "result 1;" + "quote 0;" + "};" + "assert {[uses_return]};" + "assert {[doesnt_use_return]};" + "assert {[uses_result]}" + }, + {"strings", + "set a 'This is a string';" + "set b 'This is another string';" + "asserteq 16 {[length $a]};" + "asserteq 22 {[length $b]};" + "asserteq_str a {[charat $a [expr [length $a] / 2]]};" + "asserteq_str t {[charat $b [expr [length $b] / 2]]};" + "asserteq 97 {[codeat $a [expr [length $a] / 2]]};" + "asserteq 116 {[codeat $b [expr [length $b] / 2]]};" + "asserteq 10 {[strpos $a string]};" + "asserteq 16 {[strpos $b string]};" + "asserteq -78 {[compare $a $b]};" + "assert {![streq $a $b]};" + "asserteq_str 'This is a foo' {[repstr $a string foo]};" + "asserteq_str 'This is another foo' {[repstr $b string foo]};" + "asserteq_list [split $a] [list This is a string];" + "asserteq_list [split $b] [list This is another string];" + }, + {"topeval", + "proc does-something {} {" + "topeval {" + "asserteq 10 {$x};" + "set x 42;" + "downeval {set y [expr $x * 10]}" + "};" + "asserteq 420 {$y}" + "};" + "proc calls-something {} {" + "local x;" + "set x 33;" + "does-something;" + "asserteq 33 {$x};" + "asserteq 420 {$y}" + "};" + "set x 10;" + "set y 20;" + "calls-something;" + "asserteq 42 {$x};" + "asserteq 420 {$y}" + }, + {"trim", + "set str ' Hello, world! ';" + "asserteq_str 'Hello, world!' {[trim $str]};" + "asserteq_str 'Hello, world! ' {[ltrim $str]};" + "asserteq_str ' Hello, world!' {[rtrim $str]};" + "asserteq_str 'Hello world' {[foreach [split $str] {" + "quote [trim $i {,!}]" + "}]};" + "asserteq_str 'Hello world' {[filter [split $str {,! }] {" + "[length $x] > 0" + "}]};" + }, +}; + +static int lib_test_lil(struct unit_test_state *uts) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(lil_tests); i++) { + const char *err_msg; + enum lil_error err; + struct lil *lil = lil_new(NULL); + + lil_free_value(lil_parse(lil, helpers, sizeof(helpers) - 1, 0)); + ut_asserteq(LIL_ERR_NONE, lil_error(lil, &err_msg)); + lil_free_value(lil_parse(lil, lil_tests[i].cmd, 0, 0)); + err = lil_error(lil, &err_msg); + if (err) { + ut_failf(uts, __FILE__, __LINE__, __func__, + lil_tests[i].name, "err=%d: %s", err, err_msg); + lil_free(lil); + return CMD_RET_FAILURE; + }; + lil_free(lil); + } + + return 0; +} +LIB_TEST(lib_test_lil, 0); -- 2.32.0