55# You must source `_GO_CORE_DIR/lib/testing/environment` before this file.
66
77. " ${BASH_SOURCE[0]%/* } /stack-trace"
8+ . " $_GO_CORE_DIR /lib/bats/assertions"
89
10+ # Log timestamps are disabled by for testing by default.
11+ export _GO_LOG_TIMESTAMP_FORMAT=
12+
13+ # Creates a `./go` script that imports the `log` module
14+ #
15+ # If `TEST_LOG_FILE` is defined, it will add that file for logging output as
16+ # well.
17+ #
18+ # Globals:
19+ # TEST_LOG_FILE: (Optional) Path to the log file to add for all log levels
20+ #
21+ # Arguments:
22+ # ...: Lines comprising the `./go` script
23+ create_log_script (){
24+ create_test_go_script \
25+ " . \"\$ _GO_USE_MODULES\" 'log'" \
26+ ' if [[ -n "$TEST_LOG_FILE" ]]; then' \
27+ ' @go.log_add_output_file "$TEST_LOG_FILE"' \
28+ ' fi' \
29+ " $@ "
30+ }
31+
32+ # Creates and executes a `./go` script that imports the `log` module
33+ #
34+ # Globals and arguments are identical to `create_log_script`.
35+ run_log_script () {
36+ create_log_script " $@ "
37+ run " $TEST_GO_SCRIPT "
38+ }
39+
40+ # Format a `log` module log level label
41+ #
42+ # Arguments:
43+ # label: Log level label to format
44+ format_log_label () {
45+ local label=" $1 "
46+
47+ . " $_GO_USE_MODULES " ' log'
48+ _@go.log_init
49+
50+ local __go_log_level_index=0
51+ if ! _@go.log_level_index " $label " ; then
52+ printf ' Unknown log level label: %s\n' " $label " >&2
53+ exit 1
54+ fi
55+ printf ' %s' " ${__GO_LOG_LEVELS_FORMATTED[$__go_log_level_index]} "
56+ }
57+
58+ # Validates that `output` matches the expected `@go.log` output
59+ #
60+ # Each line can be expressed one of two ways:
61+ # - As a pair of strings: first the log level label, then the log message
62+ # - As a single string without a log level label prefix
63+ #
64+ # Each log level label must exist within `_GO_LOG_LEVELS`, and can be either a
65+ # plaintext label or a label formatted with `format_log_label`. Any unknown
66+ # labels will be parsed as "a single string without a log label prefix".
67+ #
68+ # If you aren't looking for exact log output, consider using one of the standard
69+ # assertions from `_GO_CORE_DIR/lib/bats/assertions` instead.
70+ #
71+ # Note that this does NOT handle timestamps. If you wish to validate specific
72+ # timestamps, see `_GO_CORE_DIR/tests/log/timestamp.bats` for ideas.
73+ #
74+ # Arguments:
75+ # ...: Lines of expected log output
76+ assert_log_equals () {
77+ set " $BATS_ASSERTION_DISABLE_SHELL_OPTIONS "
78+ local __log_level_label
79+ local expected=()
80+ local i
81+
82+ . " $_GO_USE_MODULES " ' format' ' log'
83+ _@go.log_init
84+
85+ for (( i= 0 ; $# != 0 ; ++ i)) ; do
86+ if __parse_log_level_label " $1 " ; then
87+ expected+=(" $__log_level_label $2 " )
88+
89+ if [[ " ${__log_level_label: 0: 1} " == $' \e ' ]]; then
90+ expected[" $(( ${# expected[@]} - 1 )) " ]+=$' \e [0m'
91+ fi
92+
93+ if ! shift 2; then
94+ printf ' ERROR: Wrong number of arguments for log line %d.\n' " $i " >&2
95+ return_from_bats_assertion 1
96+ return
97+ fi
98+ else
99+ expected+=(" $1 " )
100+ shift
101+ fi
102+ done
103+
104+ if ! assert_lines_equal " ${expected[@]} " ; then
105+ return_from_bats_assertion ' 1'
106+ else
107+ return_from_bats_assertion
108+ fi
109+ }
110+
111+ # Validates that a file matches the expected `@go.log` output
112+ #
113+ # Aside from the first file path argument, the remaining arguments and semantics
114+ # are exactly the same as `assert_log_equals`.
115+ #
116+ # In cases where `@go.log_add_output_file` is used to add a `TEST_LOG_FILE` to
117+ # all levels, and all test output comes from `@go.log`, this may be invoked
118+ # following `assert_log_equals` like so to ensure the log file output matches
119+ # standard output and standard error:
120+ #
121+ # assert_log_file_equals "$TEST_LOG_FILE" "${lines[@]}"
122+ #
123+ # If you aren't looking for exact log output, consider using one of the standard
124+ # assertions from `_GO_CORE_DIR/lib/bats/assertions` instead.
125+ #
126+ # Arguments:
127+ # log_file: Path to the log file to validate
128+ # ...: Lines of expected log output
129+ assert_log_file_equals () {
130+ set " $BATS_ASSERTION_DISABLE_SHELL_OPTIONS "
131+ local log_file=" $1 "
132+ shift
133+
134+ if ! set_bats_output_and_lines_from_file " $log_file " ; then
135+ return_from_bats_assertion ' 1'
136+ else
137+ assert_log_equals " $@ "
138+ return_from_bats_assertion " $? "
139+ fi
140+ }
141+
142+ # Creates `LOG_COMMAND_STACK_TRACE_ITEMS` to help validate stack trace output.
143+ #
144+ # Call this before using "${LOG_COMMAND_STACK_TRACE_ITEMS[@]}" to inject
145+ # entries from `@go.log_command` into your expected stack trace output. This
146+ # helps validate stack trace output generated by logged commands, and ensures
147+ # that your stack trace validation stays up-to-date even when the internal
148+ # structure of `lib/log` changes.
149+ #
150+ # Globals:
151+ # LOG_COMMAND_STACK_TRACE_ITEMS:
152+ # Stack trace lines from `@go.log_command` comprising the command logging
153+ # mechanism
9154set_log_command_stack_trace_items () {
10155 if [[ " ${# LOG_COMMAND_STACK_TRACE_ITEMS[@]} " -eq ' 0' ]]; then
11156 export LOG_COMMAND_STACK_TRACE_ITEMS
@@ -18,3 +163,39 @@ set_log_command_stack_trace_items() {
18163 " $( stack_trace_item " $_GO_CORE_DIR /lib/log" ' @go.log_command' ) " )
19164 fi
20165}
166+
167+ # --------------------------------
168+ # IMPLEMENTATION - HERE BE DRAGONS
169+ #
170+ # None of the functions below this line are part of the public interface.
171+ # --------------------------------
172+
173+ # Determines whether a log level label is a valid member of `_GO_LOG_LEVELS`.
174+ #
175+ # If so, pads the label and assigns it to `__log_level_label`.
176+ #
177+ # Arguments:
178+ # level_label: Log level label to examine
179+ #
180+ # Returns:
181+ # zero if `level_label` exists in `_GO_LOG_LEVELS`, nonzero otherwise
182+ # __log_level_label: Assigned the padded version of `level_label` if valid
183+ __parse_log_level_label () {
184+ local level_label=" $1 "
185+ local try_level
186+ local __go_log_level_index
187+
188+ @go.strip_formatting_codes " $level_label " ' try_level'
189+ if [[ " $try_level " =~ \ +$ ]]; then
190+ try_level=" ${try_level% ${BASH_REMATCH[0]} } "
191+ fi
192+
193+ if ! _@go.log_level_index " $try_level " ; then
194+ return 1
195+ elif [[ " $level_label " != " $try_level " ]]; then
196+ __log_level_label=" $level_label "
197+ else
198+ @go.strip_formatting_codes \
199+ " ${__GO_LOG_LEVELS_FORMATTED[$__go_log_level_index]} " __log_level_label
200+ fi
201+ }
0 commit comments