Skip to content

Commit

Permalink
Merge pull request #205 from mbland/diff-lib
Browse files Browse the repository at this point in the history
lib/diff: Add module to log and resolve file diffs
  • Loading branch information
mbland committed Sep 4, 2017
2 parents 5761ec8 + 7f1db2a commit 19403c9
Show file tree
Hide file tree
Showing 4 changed files with 354 additions and 0 deletions.
120 changes: 120 additions & 0 deletions lib/diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#! /usr/bin/env bash
#
# Tools for examining file differences
#
# Exports:
# @go.diff_check_editor
# Checks that `_GO_DIFF_EDITOR` is set
#
# @go.diff_files
# Log differences between two files
#
# @go.diff_directories
# Log differences between two directory structures

export _GO_DIFF_EDITOR="${_GO_DIFF_EDITOR:-vimdiff}"

. "$_GO_USE_MODULES" 'log' 'path'

# Checks that `_GO_DIFF_EDITOR` is set
#
# Used by the functions in this module when the `--edit` flag is specified.
# Fails with a stack trace if it isn't set.
@go.diff_check_editor() {
if [[ -z "$_GO_DIFF_EDITOR" ]]; then
@go.log FATAL "_GO_DIFF_EDITOR not defined"
elif ! command -v "$_GO_DIFF_EDITOR" >/dev/null; then
@go.log FATAL "_GO_DIFF_EDITOR not installed: $_GO_DIFF_EDITOR"
fi
}

# Log differences between two files
#
# Options:
# --edit: Open `_GO_DIFF_EDITOR` on the files if they differ
#
# Arguments:
# lhs: The "left-hand side" file
# rhs: The "right-hand side" file
@go.diff_files() {
local lhs
local rhs
local edit

if [[ "$1" == '--edit' ]]; then
@go.diff_check_editor
edit='true'
shift
fi

lhs="$1"
rhs="$2"

if [[ ! -f "$lhs" ]]; then
@go.log WARN "Left-hand side file $1 doesn't exist or isn't a regular file"
elif [[ ! -f "$rhs" ]]; then
@go.log WARN "Right-hand side file $2 doesn't exist or isn't a regular file"
elif ! diff "$lhs" "$rhs" >/dev/null; then
@go.log WARN "$lhs" differs from "$rhs"
if [[ -n "$edit" ]]; then
@go.log INFO "Editing $lhs and $rhs"
"$_GO_DIFF_EDITOR" "$lhs" "$rhs"
fi
else
return '0'
fi
return '1'
}

# Log differences between two directory structures
#
# Note that files and directories from `lhs_dir` that are missing in `rhs_dir`
# are reported, but not the other way around.
#
# Options:
# --edit: Open `_GO_DIFF_EDITOR` on any files that differ between the dirs
#
# Arguments:
# lhs_dir: The "left-hand side" directory
# rhs_dir: The "right-hand side" directory
@go.diff_directories() {
local __go_lhs_dir
local __go_rhs_dir
local __go_diff_files_args=()
local __go_diff_directories_result='0'

if [[ "$1" == '--edit' ]]; then
__go_diff_files_args=('--edit')
shift
fi

__go_lhs_dir="$1"
__go_rhs_dir="$2"

if [[ ! -d "$__go_lhs_dir" ]]; then
@go.log WARN \
"Left-hand side directory $1 doesn't exist or isn't a directory"
elif [[ ! -d "$__go_rhs_dir" ]]; then
@go.log WARN \
"Right-hand side directory $2 doesn't exist or isn't a directory"
else
@go.walk_file_system _@go.diff_directories_impl "$__go_lhs_dir" || :
return "$__go_diff_directories_result"
fi
return '1'
}

# --------------------------------
# IMPLEMENTATION - HERE BE DRAGONS
#
# None of the functions below this line are part of the public interface.
# --------------------------------
_@go.diff_directories_impl() {
local lhs="$1"
local rhs="${__go_rhs_dir}${lhs#$__go_lhs_dir}"

if [[ -f "$lhs" ]] &&
! @go.diff_files "${__go_diff_files_args[@]}" "$lhs" "$rhs"; then
__go_diff_directories_result='1'
fi
}
37 changes: 37 additions & 0 deletions tests/diff/check-diff-editor.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#! /usr/bin/env bats

load ../environment

setup() {
test_filter
@go.create_test_go_script \
'. "$_GO_USE_MODULES" "diff"'\
'@go.diff_check_editor'
}

teardown() {
@go.remove_test_go_rootdir
}

@test "$SUITE: fails if __GO_DIFF_EDITOR not defined" {
@go.create_test_go_script \
'. "$_GO_USE_MODULES" "diff"'\
'_GO_DIFF_EDITOR= @go.diff_check_editor'
run "$TEST_GO_SCRIPT"
assert_failure
assert_output_matches 'FATAL.* _GO_DIFF_EDITOR not defined'
}

@test "$SUITE: fails if _GO_DIFF_EDITOR not found" {
_GO_DIFF_EDITOR='nonexistent-editor' run "$TEST_GO_SCRIPT"
assert_failure
assert_output_matches \
'FATAL.* _GO_DIFF_EDITOR not installed: nonexistent-editor'
}

@test "$SUITE: does nothing if _GO_DIFF_EDITOR found" {
stub_program_in_path 'vimdiff'
_GO_DIFF_EDITOR='vimdiff' run "$TEST_GO_SCRIPT"
restore_program_in_path 'vimdiff'
assert_success ''
}
107 changes: 107 additions & 0 deletions tests/diff/diff-directories.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#! /usr/bin/env bats

load ../environment

LHS_DIR=
RHS_DIR=

setup() {
test_filter
@go.create_test_go_script \
'. "$_GO_USE_MODULES" "diff"' \
'@go.diff_directories "$@"'

LHS_DIR="$TEST_GO_ROOTDIR/lhs"
RHS_DIR="$TEST_GO_ROOTDIR/rhs"
mkdir -p "$LHS_DIR" "$RHS_DIR"
}

teardown() {
@go.remove_test_go_rootdir
}

@test "$SUITE: warns if LHS dir doesn't exist" {
local lhs="$LHS_DIR"
rmdir "$lhs"
run "$TEST_GO_SCRIPT" "$lhs" "$RHS_DIR"
assert_failure
assert_output_matches \
"WARN.* Left-hand side directory $lhs doesn't exist or isn't a directory"
}

@test "$SUITE: warns if RHS dir doesn't exist" {
local rhs="$RHS_DIR"
rmdir "$rhs"
run "$TEST_GO_SCRIPT" "$LHS_DIR" "$rhs"
assert_failure
assert_output_matches \
"WARN.* Right-hand side directory $rhs doesn't exist or isn't a directory"
}

@test "$SUITE: does nothing if first directory empty" {
printf '%s\n' 'foo' >"$RHS_DIR/foo"
run "$TEST_GO_SCRIPT" "$LHS_DIR" "$RHS_DIR"
assert_success ''
}

@test "$SUITE: returns success if directories contain the same single file" {
skip_if_system_missing 'diff'
printf '%s\n' 'foo' >"$LHS_DIR/foo"
printf '%s\n' 'foo' >"$RHS_DIR/foo"
run "$TEST_GO_SCRIPT" "$LHS_DIR" "$RHS_DIR"
assert_success ''
}

@test "$SUITE: returns success if rhs contains more files" {
skip_if_system_missing 'diff'
printf '%s\n' 'foo' >"$LHS_DIR/foo"
printf '%s\n' 'foo' >"$RHS_DIR/foo"
printf '%s\n' 'bar' >"$RHS_DIR/bar"
run "$TEST_GO_SCRIPT" "$LHS_DIR" "$RHS_DIR"
assert_success ''
}

@test "$SUITE: returns an error if rhs contains fewer files" {
skip_if_system_missing 'diff'
local missing="$RHS_DIR/bar"

printf '%s\n' 'foo' >"$LHS_DIR/foo"
printf '%s\n' 'bar' >"$LHS_DIR/bar"
printf '%s\n' 'foo' >"$RHS_DIR/foo"

run "$TEST_GO_SCRIPT" "$LHS_DIR" "$RHS_DIR"
assert_failure
assert_output_matches \
"WARN.* Right-hand side file $missing doesn't exist or isn't a regular file"
}

@test "$SUITE: warns and returns an error when files differ" {
skip_if_system_missing 'diff'

printf '%s\n' 'foo' >"$LHS_DIR/foo"
printf '%s\n' 'bar' >"$RHS_DIR/foo"

run "$TEST_GO_SCRIPT" "$LHS_DIR" "$RHS_DIR"
assert_failure
assert_output_matches "WARN.* $LHS_DIR/foo differs from $RHS_DIR/foo"
}

@test "$SUITE: --edit opens _GO_DIFF_EDITOR when files differ" {
skip_if_system_missing 'diff'

printf '%s\n' 'foo' >"$LHS_DIR/foo"
printf '%s\n' 'bar' >"$RHS_DIR/foo"

stub_program_in_path 'vimdiff' \
'printf "%s\n" "LHS: $1" "RHS: $2"'

_GO_DIFF_EDITOR='vimdiff' run "$TEST_GO_SCRIPT" --edit "$LHS_DIR" "$RHS_DIR"
restore_program_in_path 'vimdiff'

assert_failure
assert_lines_match \
"WARN.* $LHS_DIR/foo differs from $RHS_DIR/foo" \
"INFO.* Editing $LHS_DIR/foo and $RHS_DIR/foo" \
"LHS: $LHS_DIR/foo" \
"RHS: $RHS_DIR/foo"
}
90 changes: 90 additions & 0 deletions tests/diff/diff-files.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#! /usr/bin/env bats

load ../environment

setup() {
test_filter
@go.create_test_go_script \
'. "$_GO_USE_MODULES" "diff"'\
'@go.diff_files "$@"'
}

teardown() {
@go.remove_test_go_rootdir
}

@test "$SUITE: warns if lhs file doesn't exist or isn't regular" {
local lhs="$TEST_GO_ROOTDIR/foo"

run "$TEST_GO_SCRIPT" "$lhs"
assert_failure
assert_output_matches \
"WARN.* Left-hand side file $lhs doesn't exist or isn't a regular file"
}

@test "$SUITE: warns if rhs file doesn't exist or isn't regular" {
local lhs="$TEST_GO_ROOTDIR/foo"
local rhs="$TEST_GO_ROOTDIR/bar"

mkdir -p "$TEST_GO_ROOTDIR"
printf '%s\n' 'foo' >"$lhs"
mkdir "$rhs"

run "$TEST_GO_SCRIPT" "$lhs" "$rhs"
assert_failure
assert_output_matches \
"WARN.* Right-hand side file $rhs doesn't exist or isn't a regular file"
}

@test "$SUITE: return success if the files match" {
skip_if_system_missing 'diff'

local lhs="$TEST_GO_ROOTDIR/foo"
local rhs="$TEST_GO_ROOTDIR/bar"

mkdir -p "$TEST_GO_ROOTDIR"
printf '%s\n' 'foo' >"$lhs"
printf '%s\n' 'foo' >"$rhs"

run "$TEST_GO_SCRIPT" "$lhs" "$rhs"
assert_success ''
}

@test "$SUITE: warns and return failure if the files differ" {
skip_if_system_missing 'diff'

local lhs="$TEST_GO_ROOTDIR/foo"
local rhs="$TEST_GO_ROOTDIR/bar"

mkdir -p "$TEST_GO_ROOTDIR"
printf '%s\n' 'foo' >"$lhs"
printf '%s\n' 'bar' >"$rhs"

run "$TEST_GO_SCRIPT" "$lhs" "$rhs"
assert_failure
assert_output_matches "WARN.* $lhs differs from $rhs"
}

@test "$SUITE: --edit opens _GO_DIFF_EDITOR if the files differ" {
skip_if_system_missing 'diff'

local lhs="$TEST_GO_ROOTDIR/foo"
local rhs="$TEST_GO_ROOTDIR/bar"

mkdir -p "$TEST_GO_ROOTDIR"
printf '%s\n' 'foo' >"$lhs"
printf '%s\n' 'bar' >"$rhs"

stub_program_in_path 'vimdiff' \
'printf "%s\n" "LHS: $1" "RHS: $2"'

_GO_DIFF_EDITOR='vimdiff' run "$TEST_GO_SCRIPT" --edit "$lhs" "$rhs"
restore_program_in_path 'vimdiff'

assert_failure
assert_lines_match \
"WARN.* $lhs differs from $rhs" \
"INFO.* Editing $lhs and $rhs" \
"LHS: $lhs" \
"RHS: $rhs"
}

0 comments on commit 19403c9

Please sign in to comment.