The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
my $reason;
BEGIN {
    my $line = (split /\n/, `make -v`)[0];
    if ($line) {
        warn $line, "\n";
        if ($line =~ /GNU Make (\d+\.\d+)(\s+(?:alpha|beta))?/) {
            my ($make_ver, $modifier) = ($1, $2);
            if ($make_ver < 3.81 || ($make_ver == 3.81 && $modifier)) {
                $reason = 'GNU make too old (at least 3.81 final is required).';
            }
        } else {
            $reason = 'No GNU make found.';
        }
    } else {
        $reason = 'No make found in env.';
    }
}

use Test::Base $reason ? (skip_all => $reason) : ();

use File::Slurp;
use IPC::Run3;
use Cwd;

use lib 't/lib';
use Test::Make::Util;
#use Test::LongString;

plan tests => 3 * blocks();

my $makefile = 'makesimple.tmp.mk';

my $saved_cwd = cwd;

run {
    my $block = shift;
    my $name = $block->name;
    chdir $saved_cwd;
    system('rm -rf t/tmp');
    system('mkdir t/tmp');
    chdir 't/tmp';
    write_file($makefile, $block->in);
    my ($stdout, $stderr, @options);
    if ($block->options) {
        @options = split /\s+/, $block->options;
    }
    my $touch = $block->touch;
    if ($touch) {
        for my $file (split /\s+/, $touch) {
            touch($file);
        }
    }
    run3(
        [$^X, "$saved_cwd/script/makesimple", '-f', $makefile, @options],
        undef,
        \$stdout,
        \$stderr,
    );
    is(($? >> 8), 0, "$name - process returned the 0 status");

    my $expected_out = $block->out;

    if (ref $expected_out && ref $expected_out eq 'Regexp') {
        like $stdout, $block->out,
            "$name - script/makesimple generated the right output";

    } else {
        is $stdout, $block->out,
            "$name - script/makesimple generated the right output";
    }

    is $stderr, $block->err,
        "$name - script/makesimple generated the right error";
};

__DATA__

=== TEST 1: basics
--- in

FOO = world
all: ; @ echo hello $(FOO)

--- out
all:
	@echo hello world
--- err



=== TEST 2: canned sequence of commands
--- in
define FOO
  @echo
  -touch
  :
endef

all:
	@$(FOO)
--- out
all:
	@echo
	@-touch
	@:
--- err



=== TEST 3: double-colon rules
--- in

all: foo

foo:: bar
	@echo $@ $<

foo:: blah blue
	-echo $^
--- out
all: foo

foo:: bar
	@echo foo bar

foo:: blah blue
	-echo blah blue

--- err
makesimple: *** No rule to make target `bar', needed by `foo'.  Ignored.
makesimple: *** No rule to make target `blah', needed by `foo'.  Ignored.
makesimple: *** No rule to make target `blue', needed by `foo'.  Ignored.



=== TEST 4: double-colon rules (no warnings)
--- in

all: foo

foo:: bar
	@echo $@ $<

foo:: blah blue
	-echo $^
--- out
all: foo

foo:: bar
	@echo foo bar

foo:: blah blue
	-echo blah blue

--- touch: bar blah blue
--- err



=== TEST 5: .DEFAUL_GOAL
--- in
.DEFAULT_GOAL = foo

all: foo
	@echo $<

foo: bah ; :


--- out
foo: bah
	:

all: foo
	@echo foo

--- err
makesimple: *** No rule to make target `bah', needed by `foo'.  Ignored.



=== TEST 6: order-only prereqs
--- in

all : a b \
    | c \
; echo

--- out
all: a b | c
	echo

--- err
makesimple: *** No rule to make target `a', needed by `all'.  Ignored.
makesimple: *** No rule to make target `b', needed by `all'.  Ignored.
makesimple: *** No rule to make target `c', needed by `all'.  Ignored.



=== TEST 7: multi-target rules
--- in
foo bar: a.h

foo: blah ; echo $< > $@

--- out
foo: blah a.h
	echo blah > foo

bar: a.h

--- err
makesimple: *** No rule to make target `blah', needed by `foo'.  Ignored.
makesimple: *** No rule to make target `a.h', needed by `foo'.  Ignored.



=== TEST 8: pattern rules (no match)
--- in
all: foo.x bar.w

%.x: %.h
	touch $@

%.w: %.hpp ; $(CC)

--- out
all: foo.x bar.w

--- err
makesimple: *** No rule to make target `foo.x', needed by `all'.  Ignored.
makesimple: *** No rule to make target `bar.w', needed by `all'.  Ignored.



=== TEST 9: pattern rules (no warnings)
--- in
all: foo.x bar.w

%.x: %.h
	touch $@

%.w: %.hpp ; $(CC)

--- touch: foo.x bar.w
--- out
all: foo.x bar.w

--- err



=== TEST 10: pattern rules (with match)
--- in
all: foo.x bar.w

%.x: %.h
	touch $@

%.w: %.hpp ; echo '$(CC)'

--- touch: foo.h bar.hpp
--- out
all: foo.x bar.w

foo.x: foo.h
	touch foo.x

bar.w: bar.hpp
	echo ''
--- err



=== TEST 11: chained implicit rules
--- in

all: foo.a bar.a baz.a

%.a: %.b ; @touch $@
%.b: %.d ; @touch $@

--- touch: foo.d bar.d baz.d
--- out
all: foo.a bar.a baz.a

foo.b: foo.d
	@touch foo.b

foo.a: foo.b
	@touch foo.a

bar.b: bar.d
	@touch bar.b

bar.a: bar.b
	@touch bar.a

baz.b: baz.d
	@touch baz.b

baz.a: baz.b
	@touch baz.a

--- err



=== TEST 12: extra goals given from the command line
--- in

all: foo.a

%.a: %.b ; @touch $@
%.b: %.d ; @touch $@

--- options: bar.a
--- touch: foo.d bar.d
--- out

all: foo.a

bar.b: bar.d
	@touch bar.b

bar.a: bar.b
	@touch bar.a

foo.b: foo.d
	@touch foo.b

foo.a: foo.b
	@touch foo.a

--- err



=== TEST 13: target-specific variables
--- in

FOO = foo
default: all any
all: FOO += one
all: FOO += two
all: BAR = bar
all: FOO += three
all: BAR += baz
all: ; @echo $(FOO); echo $(BAR)
any: ; @echo $(FOO); echo $(BAR) end

--- out
default: all any

all:
	@echo foo one two three; echo bar baz

any:
	@echo foo; echo  end

--- err



=== TEST 14: ditto (override cmd line vars)
--- in

all: override FOO = foo
all: ; @echo $(FOO)
--- options:  FOO=cmd
--- out
all:
	@echo foo
--- err



=== TEST 15: ditto (cmd line vars) (2)
--- in

all: FOO = foo
all: ; @echo $(FOO)
--- options:  FOO=cmd
--- out
all:
	@echo cmd
--- err



=== TEST 16: static pattern rules
--- in

CC = gcc
CFLAGS =
objects = foo.o bar.o

all: $(objects)

$(objects): %.o: %.c
	$(CC) -c $(CFLAGS) $< -o $@

--- out

all: foo.o bar.o

foo.o: foo.c
	gcc -c  foo.c -o foo.o

bar.o: bar.c
	gcc -c  bar.c -o bar.o

--- err
makesimple: *** No rule to make target `foo.c', needed by `foo.o'.  Ignored.
makesimple: *** No rule to make target `bar.c', needed by `bar.o'.  Ignored.



=== TEST 17: static pattern rules (no warnings)
--- in

CC = gcc
CFLAGS = -O
objects = foo.o bar.o

all: $(objects)

$(objects): %.o: %.c
	$(CC) -c $(CFLAGS) $< -o $@

--- touch: foo.c bar.c
--- out

all: foo.o bar.o

foo.o: foo.c
	gcc -c -O foo.c -o foo.o

bar.o: bar.c
	gcc -c -O bar.c -o bar.o

--- err



=== TEST 18: conditionals - ifdef $(foo)
--- in

bar = true
foo = bar
ifdef $(foo)
all: ; @echo hello
else
foo: bar
	touch $@
endif
	-rm blahblah

--- out

all:
	@echo hello
	-rm blahblah

--- err



=== TEST 19: conditionals - ifdef foo
--- in

foo = bar
ifdef foo
all: ; @echo hello
else
foo: bar
	touch $@
endif
	-rm blahblah

--- out

all:
	@echo hello
	-rm blahblah

--- err



=== TEST 20: conditionals - override var foo via cmd line options
--- in

foo = bar
ifdef foo
all: ; @echo hello
else
foo: bar
	touch $@
endif
	-rm blahblah

--- options: foo=
--- out

foo: bar
	touch foo
	-rm blahblah

--- err
makesimple: *** No rule to make target `bar', needed by `foo'.  Ignored.



=== TEST 21: functions in the first pass
--- in

objects = foo.o bar.o baz.o
all : $(objects:.o=.c)
	@ echo $^

--- out
all: foo.c bar.c baz.c
	@echo foo.c bar.c baz.c
--- err
makesimple: *** No rule to make target `foo.c', needed by `all'.  Ignored.
makesimple: *** No rule to make target `bar.c', needed by `all'.  Ignored.
makesimple: *** No rule to make target `baz.c', needed by `all'.  Ignored.



=== TEST 22: functions in the second pass
--- in

objects = foo.o bar.o baz.o
all :
	echo $(patsubst %.o,%.c,${objects})

--- out
all:
	echo foo.c bar.c baz.c
--- err



=== TEST 23: functions in the both passes
--- in

objects = $(sort $(wildcard *.o))
all : ; echo $(patsubst %.o,%.c,${objects})

--- touch: foo.o bar.o baz.o
--- out
all:
	echo bar.c baz.c foo.c
--- err



=== TEST 24: commands spanning multiple lines
--- in

foo=hello
bar=my
baz=world

all:
	@echo $(foo) \
  $(bar) \
      $(baz)

--- out eval
qr/^all:
\t\@echo hello \\
[ \t]+my \\
[ \t]+world
$/s
--- err



=== TEST 25: dynamics
--- in

head = all:
$(head)
	@echo $@

--- out
all:
	@echo all
--- err



=== TEST 26: dynamics (2)
--- in

head = all:
$(head)
	@echo $@

--- options: head=all:bar
--- out
all: bar
	@echo all
--- err
makesimple: *** No rule to make target `bar', needed by `all'.  Ignored.



=== TEST 27: ifeq/endif
--- in
FOO=123
ifeq ($(FOO), 123)
    FOO = bar
endif

all: ; echo $(FOO)
--- out
all:
	echo bar
--- err



=== TEST 28: define/endef
--- in
define foo =

     bar 
 
endef

all: ; echo $(foo)
--- out
all:
	echo bar
--- err