Removed submodules
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
# Ignore all compiled files regardless of location
|
||||
**/*.o
|
||||
|
||||
# But not the private.o
|
||||
!tests/private.o
|
||||
|
||||
# Ignore executables for this project
|
||||
shell
|
||||
testsuite
|
||||
|
||||
# Ignore test outputs
|
||||
tests/ckstyle
|
||||
tests/itests.txt
|
||||
tests/outputs
|
||||
tests/style.txt
|
||||
tests/valgrind
|
||||
tests/utests.txt
|
||||
|
||||
**/.nfs*
|
||||
**/.vscode
|
||||
@@ -0,0 +1,51 @@
|
||||
#
|
||||
# Simple Makefile
|
||||
# Mike Lam, James Madison University, August 2016
|
||||
#
|
||||
# This makefile builds a simple application that contains a main module
|
||||
# (specified by the EXE variable) and a predefined list of additional modules
|
||||
# (specified by the MODS variable). If there are any external library
|
||||
# dependencies (e.g., the math library, "-lm"), list them in the LIBS variable.
|
||||
# If there are any precompiled object files, list them in the OBJS variable.
|
||||
#
|
||||
# By default, this makefile will build the project with debugging symbols and
|
||||
# without optimization. To change this, edit or remove the "-g" and "-O0"
|
||||
# options in CFLAGS and LDFLAGS accordingly.
|
||||
#
|
||||
# By default, this makefile build the application using the GNU C compiler,
|
||||
# adhering to the C99 standard with all warnings enabled.
|
||||
|
||||
|
||||
# application-specific settings and run target
|
||||
|
||||
EXE=shell
|
||||
MODS=model.o effects.o
|
||||
OBJS=
|
||||
LIBS=
|
||||
|
||||
default: $(EXE)
|
||||
|
||||
test: $(EXE)
|
||||
make -C tests test
|
||||
|
||||
# compiler/linker settings
|
||||
|
||||
CC=gcc
|
||||
CFLAGS=-g -O0 -Wall -Werror --std=c99 -pedantic
|
||||
LDFLAGS=-g -O0
|
||||
|
||||
|
||||
# build targets
|
||||
|
||||
$(EXE): main.o $(MODS) $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $(EXE) $^ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -f $(EXE) main.o $(MODS)
|
||||
make -C tests clean
|
||||
|
||||
.PHONY: default clean
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#define _POSIX_C_SOURCE 200809L // needed for strdup extension
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "effects.h"
|
||||
#include "model.h"
|
||||
|
||||
/* Executed when starting to process a new command line. The fsm_t
|
||||
should have been updated to include a pointer to the current token.
|
||||
For instance, if the command line was "ls -l data NL", the fsm_t
|
||||
has a field that points to "ls". */
|
||||
void
|
||||
start_command (fsm_t *cmdmodel)
|
||||
{
|
||||
printf ("Starting new command: %s\n", cmdmodel->current_token);
|
||||
// TODO: Copy the current token to store it in the FSM's command
|
||||
// field. Next, create the FSM's args array (length MAX_ARGUMENTS)
|
||||
// set the current token as args[0], and initialize nargs to be
|
||||
// the number of arguments (1 at this point).
|
||||
// Allocate args array (NULL-initialized) if not already
|
||||
cmdmodel->args = calloc (MAX_ARGUMENTS, sizeof (char *));
|
||||
cmdmodel->command = cmdmodel->current_token;
|
||||
cmdmodel->args[0] = cmdmodel->current_token;
|
||||
cmdmodel->nargs = 1;
|
||||
}
|
||||
|
||||
/* Executed when processing a token after the command name. For instance,
|
||||
if the command line was "ls -l data NL", this function will be called
|
||||
when the current token is "-l" and again when it is "data". */
|
||||
void
|
||||
append (fsm_t *cmdmodel)
|
||||
{
|
||||
if (cmdmodel->nargs >= MAX_ARGUMENTS)
|
||||
return;
|
||||
|
||||
printf ("Appending %s to the argument list\n", cmdmodel->current_token);
|
||||
assert (cmdmodel->args != NULL);
|
||||
|
||||
// TODO: Store the current token into the args array and increment nargs
|
||||
cmdmodel->args[cmdmodel->nargs++] = cmdmodel->current_token;
|
||||
}
|
||||
|
||||
/* Executed when either a NL or | (pipe) is encountered. For instance, if
|
||||
the command line is "ls -l data NL", the current token will be "NL"; also,
|
||||
the FSM's args array should be complete, containing "ls", "-l", and "data",
|
||||
followed by several NULL pointers. */
|
||||
void
|
||||
execute (fsm_t *cmdmodel)
|
||||
{
|
||||
assert (cmdmodel->args != NULL);
|
||||
|
||||
// TODO: Print out the argument list similar to the format shown and free
|
||||
// the args array.
|
||||
printf ("Execute %s with arguments { ", cmdmodel->args[0]);
|
||||
for (uint8_t i = 0; i < cmdmodel->nargs; i++)
|
||||
{
|
||||
printf ("%s, ", cmdmodel->args[i]);
|
||||
}
|
||||
printf ("(null) }\n");
|
||||
}
|
||||
|
||||
// No changes are needed to the effects below
|
||||
|
||||
void
|
||||
link_commands (fsm_t *cmdmodel)
|
||||
{
|
||||
printf ("Set up pipe\n");
|
||||
execute (cmdmodel);
|
||||
}
|
||||
|
||||
void
|
||||
error_pipe (fsm_t *cmdmodel)
|
||||
{
|
||||
printf ("ERROR: Received token %s while in state %s\n",
|
||||
cmdmodel->current_token, state_name (cmdmodel->state));
|
||||
}
|
||||
|
||||
void
|
||||
error_newline (fsm_t *cmdmodel)
|
||||
{
|
||||
printf ("ERROR: Received token %s while in state %s\n",
|
||||
cmdmodel->current_token, state_name (cmdmodel->state));
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef __effects_h__
|
||||
#define __effects_h__
|
||||
|
||||
#include "model.h"
|
||||
|
||||
void start_command (fsm_t *);
|
||||
void append (fsm_t *);
|
||||
void execute (fsm_t *);
|
||||
void link_commands (fsm_t *);
|
||||
void error_pipe (fsm_t *);
|
||||
void error_newline (fsm_t *);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* CS 361: Template lab driver
|
||||
*
|
||||
* Name:
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "model.h"
|
||||
|
||||
void
|
||||
usage (void)
|
||||
{
|
||||
printf ("shell, a command line state model simulator\n\n");
|
||||
printf ("usage: shell cmd [arg ...] [ | cmd [arg ...] ... ]\n");
|
||||
printf ("Each cmd can contain an argument list of variable length\n");
|
||||
printf ("Each cmd after the first must be preceded by a pipe | character\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
// With no arguments, show usage and exit
|
||||
if (argc != 2)
|
||||
{
|
||||
usage ();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Declare and initialize a FSM
|
||||
fsm_t *cmdmodel = cmdline_init ();
|
||||
if (cmdmodel == NULL)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
// TODO: Change this to split the string into tokens, where
|
||||
// each token is an event that needs to be handled. After
|
||||
// looking up the event number, store the token in the FSM
|
||||
// and call handle_event().
|
||||
char *token = strtok (argv[1], " ");
|
||||
while (token != NULL)
|
||||
{
|
||||
cmdmodel->current_token = token;
|
||||
event_t event = lookup (token);
|
||||
if (!handle_event (cmdmodel, event))
|
||||
break;
|
||||
|
||||
token = strtok (NULL, " ");
|
||||
}
|
||||
|
||||
// Free remaining allocated data
|
||||
if (cmdmodel->args != NULL)
|
||||
free (cmdmodel->args);
|
||||
free (cmdmodel);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "effects.h"
|
||||
#include "model.h"
|
||||
|
||||
// TODO: Complete this table mapping state/events to the target state. Each
|
||||
// row corresponds to the current state. Each column within that row indicates
|
||||
// the next state for a given event. If there is no transition defined, that
|
||||
// entry should be NST ("no state").
|
||||
static state_t const _transitions[NUM_STATES][NUM_EVENTS]
|
||||
= { { Command, Term, NST },
|
||||
{ Arguments, Make_Pipe, Term },
|
||||
{ Arguments, Make_Pipe, Term },
|
||||
{ Command, Term, Term },
|
||||
{ NST, NST, NST } };
|
||||
|
||||
// TODO: Create a table mapping states/events to the effect functions. If
|
||||
// there is no valid transition, the entry here would be NULL because actions
|
||||
// are function pointers.
|
||||
static action_t const _effects[NUM_STATES][NUM_EVENTS]
|
||||
= { { start_command, error_pipe, NULL },
|
||||
{ append, link_commands, execute },
|
||||
{ append, link_commands, execute },
|
||||
{ start_command, error_pipe, error_newline },
|
||||
{ NULL, NULL, NULL } };
|
||||
|
||||
/* Create an instance of an FSM and initialize its fields as appropriate.
|
||||
Some fields are common to most FSMs (such as an initial state or a
|
||||
pointer to a transition function). Other fields will be specific to
|
||||
this fsm_t declaration. Return NULL if any part of the initialization
|
||||
fails. */
|
||||
fsm_t *
|
||||
cmdline_init (void)
|
||||
{
|
||||
fsm_t *fsm = calloc (1, sizeof (fsm_t));
|
||||
fsm->state = Init;
|
||||
fsm->transition = transition;
|
||||
|
||||
return fsm;
|
||||
}
|
||||
|
||||
// TODO: Create a transition function that is specific to this type
|
||||
// of FSM. This function needs to take an fsm_t* and an event, returning
|
||||
// both the new state and the effect to perform (the latter is returned
|
||||
// using a call-by-reference parameter. This function should NOT contain
|
||||
// any "if" types of statements based on the state or event; it should
|
||||
// simply lookup these values in the tables defined above.
|
||||
state_t
|
||||
transition (struct fsm *fsm, event_t event, action_t *effect)
|
||||
{
|
||||
assert (fsm->state < NST);
|
||||
assert (event < NIL);
|
||||
|
||||
*effect = _effects[fsm->state][event];
|
||||
return _transitions[fsm->state][event];
|
||||
}
|
||||
|
||||
/* Helper function for providing a printable string name for an event */
|
||||
const char *
|
||||
event_name (event_t evt)
|
||||
{
|
||||
assert (evt <= NIL);
|
||||
|
||||
// Event names for printing out
|
||||
const char *names[] = { "TOKEN", "PIPE", "NEWLINE", "NIL" };
|
||||
return names[evt];
|
||||
}
|
||||
|
||||
/* Helper function for providing a printable string name for an state */
|
||||
const char *
|
||||
state_name (state_t st)
|
||||
{
|
||||
assert (st <= NST);
|
||||
|
||||
// State names for printing out
|
||||
const char *names[]
|
||||
= { "Init", "Command", "Arguments", "Make_Pipe", "Term", "NST" };
|
||||
return names[st];
|
||||
}
|
||||
|
||||
/* Generic front-end for handling events. Should do nothing more
|
||||
than calling the FSM's transition function, performing an effect
|
||||
(if appropriate) and updating the state. Return false if the new
|
||||
state is the terminal state. */
|
||||
bool
|
||||
handle_event (fsm_t *fsm, event_t event)
|
||||
{
|
||||
assert (fsm != NULL);
|
||||
// TODO: Look up the current state/event combination in the
|
||||
// transition table. Print the following line for debugging
|
||||
// purposes just for this lab. This should be printed even
|
||||
// if there is no transition.
|
||||
action_t effect;
|
||||
state_t new_state = fsm->transition (fsm, event, &effect);
|
||||
printf ("[%s.%s -> %s]\n", state_name (fsm->state), event_name (event),
|
||||
state_name (new_state));
|
||||
|
||||
// TODO: If the state/event combination is valid, execute
|
||||
// the transition and effect function (if there is one).
|
||||
// If the next state is Term (terminated), return false.
|
||||
// Otherwise return true.
|
||||
if (new_state != NST)
|
||||
{
|
||||
if (effect != NULL)
|
||||
{
|
||||
effect (fsm);
|
||||
}
|
||||
|
||||
fsm->state = new_state;
|
||||
}
|
||||
|
||||
return fsm->state != Term;
|
||||
}
|
||||
|
||||
/* Given a string, return the event type. Do not modify this function. */
|
||||
event_t
|
||||
lookup (char *token)
|
||||
{
|
||||
if (!strcmp (token, "|"))
|
||||
return PIPE;
|
||||
|
||||
if (!strcmp (token, "NL"))
|
||||
return NEWLINE;
|
||||
|
||||
return TOKEN;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef __model_h__
|
||||
#define __model_h__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Generic definitions for any type of statemodel
|
||||
|
||||
// States and events should just be integers
|
||||
typedef int state_t;
|
||||
typedef int event_t;
|
||||
|
||||
// Needed for circular typedef. This lets action_t use fsm_t in its parameter
|
||||
// list, while the struct fsm can use action_t as a field.
|
||||
typedef struct fsm fsm_t;
|
||||
|
||||
// All entry, exit, and effect instances use the action type
|
||||
typedef void (*action_t) (fsm_t *);
|
||||
|
||||
// Each FSM instance contains a current state
|
||||
struct fsm
|
||||
{
|
||||
state_t state; // current state
|
||||
|
||||
// pointer to the FSM's transition function
|
||||
state_t (*transition) (struct fsm *, event_t, action_t *);
|
||||
|
||||
// Additional data fields specific to this FSM
|
||||
char *command; // the name of the command to run
|
||||
size_t nargs; // the number of command-line arguments
|
||||
char **args; // the command-line arguments
|
||||
char *current_token; // current token being processed
|
||||
};
|
||||
|
||||
// Generic entry point for handling events
|
||||
bool handle_event (fsm_t *, event_t);
|
||||
|
||||
// Additional definitions specific to an FSM for command line processing
|
||||
|
||||
#define MAX_ARGUMENTS 10
|
||||
|
||||
// Events
|
||||
typedef enum
|
||||
{
|
||||
TOKEN, // normal command-line token
|
||||
PIPE, // vertical bar character
|
||||
NEWLINE, // newline at the end of the command
|
||||
NIL // invalid non-event
|
||||
} cmdevt_t;
|
||||
#define NUM_EVENTS NIL
|
||||
|
||||
// States
|
||||
typedef enum
|
||||
{
|
||||
Init, // initial state
|
||||
Command, // establishing the command name
|
||||
Arguments, // building the argument list
|
||||
Make_Pipe, // linking the commands together for a pipe
|
||||
Term, // terminal state (execute program or error)
|
||||
NST // invalid non-state
|
||||
} cmdst_t;
|
||||
#define NUM_STATES NST
|
||||
|
||||
// Helper functions
|
||||
fsm_t *cmdline_init (void); // initialize the FSM
|
||||
state_t transition (struct fsm *fsm, event_t event, action_t *effect);
|
||||
event_t lookup (char *); // convert an event string to its numeric value
|
||||
|
||||
// Translate event/state numbers to their string equivalent
|
||||
const char *event_name (event_t);
|
||||
const char *state_name (state_t);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,88 @@
|
||||
#
|
||||
# Simple Test Makefile
|
||||
# Mike Lam, James Madison University, August 2016
|
||||
#
|
||||
# This version of the Makefile includes support for building a test suite. The
|
||||
# recommended framework is Check (http://check.sourceforge.net/). To build and
|
||||
# run the test suite, execute the "test" target. The test suite must be located
|
||||
# in a module called "testsuite". The MODS, LIBS, and OBJS variables work as
|
||||
# they do in the main Makefile.
|
||||
#
|
||||
# To change the default build target (which executes when you just type
|
||||
# "make"), change the right-hand side of the definition of the "default"
|
||||
# target.
|
||||
#
|
||||
# By default, this makefile will build the project with debugging symbols and
|
||||
# without optimization. To change this, edit or remove the "-g" and "-O0"
|
||||
# options in CFLAGS and LDFLAGS accordingly.
|
||||
#
|
||||
# By default, this makefile build the application using the GNU C compiler,
|
||||
# adhering to the C99 standard with all warnings enabled.
|
||||
|
||||
|
||||
# application-specific settings and run target
|
||||
|
||||
EXE=../fsm
|
||||
TEST=testsuite
|
||||
MODS=public.o
|
||||
OBJS=../model.o ../effects.o private.o
|
||||
LIBS=
|
||||
|
||||
UTESTOUT=utests.txt
|
||||
ITESTOUT=itests.txt
|
||||
SCHECKOUT=style.txt
|
||||
|
||||
default: $(TEST)
|
||||
|
||||
$(EXE):
|
||||
make -C ../
|
||||
|
||||
test: utest itest style
|
||||
@echo "========================================"
|
||||
|
||||
utest: $(EXE) $(TEST)
|
||||
@echo "========================================"
|
||||
@echo " UNIT TESTS"
|
||||
@./utests.sh | tee $(UTESTOUT)
|
||||
|
||||
itest: $(EXE)
|
||||
@echo "========================================"
|
||||
@echo " INTEGRATION TESTS"
|
||||
@./integration.sh | tee $(ITESTOUT)
|
||||
|
||||
style: $(EXE)
|
||||
@echo "========================================"
|
||||
@echo " CODING STYLE CHECK"
|
||||
@./style.sh 2>/dev/null >$(SCHECKOUT)
|
||||
@cat $(SCHECKOUT)
|
||||
|
||||
# compiler/linker settings
|
||||
|
||||
CC=gcc
|
||||
CFLAGS=-g -O0 -Wall --std=c99
|
||||
LDFLAGS=-g -O0
|
||||
|
||||
#CFLAGS+=-I/opt/local/include -Wno-gnu-zero-variadic-macro-arguments
|
||||
#CFLAGS+=-Wno-gnu-zero-variadic-macro-arguments
|
||||
#LDFLAGS+=-L/opt/local/lib
|
||||
#LDFLAGS=
|
||||
LIBS+=-lcheck -lm -lpthread
|
||||
|
||||
ifeq ($(shell uname -s),Linux)
|
||||
LIBS+=-lrt -lsubunit
|
||||
endif
|
||||
|
||||
|
||||
# build targets
|
||||
|
||||
$(TEST): $(TEST).o $(MODS) $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $(TEST) $^ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -rf $(TEST) $(TEST).o $(MODS) $(UTESTOUT) $(ITESTOUT) $(SCHECKOUT) outputs valgrind ckstyle
|
||||
|
||||
.PHONY: default clean test unittest inttest
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
015ebe95460b1d6fbf79df280ec3ae5fab362ae8
|
||||
@@ -0,0 +1 @@
|
||||
42ae8f1bdf52b57ad234791690bf611379fc8249
|
||||
@@ -0,0 +1 @@
|
||||
ebc846cda2557a05e691ef4d7dc7de4ee312cbd1
|
||||
@@ -0,0 +1 @@
|
||||
2fd3754d04e83c387269e26d81186b290d299f82
|
||||
@@ -0,0 +1 @@
|
||||
17611b03d098cb2d095ddac6dc39c08f66514f4e
|
||||
@@ -0,0 +1 @@
|
||||
10b932ebcb7ca5600c9b81652547ea3721854698
|
||||
@@ -0,0 +1,2 @@
|
||||
[Init.TOKEN -> Command]
|
||||
Starting new command: ls
|
||||
@@ -0,0 +1,4 @@
|
||||
[Init.TOKEN -> Command]
|
||||
Starting new command: ls
|
||||
[Command.NEWLINE -> Term]
|
||||
Execute ls with arguments { ls, (null) }
|
||||
@@ -0,0 +1,8 @@
|
||||
[Init.TOKEN -> Command]
|
||||
Starting new command: ls
|
||||
[Command.TOKEN -> Arguments]
|
||||
Appending -a to the argument list
|
||||
[Arguments.TOKEN -> Arguments]
|
||||
Appending -l to the argument list
|
||||
[Arguments.NEWLINE -> Term]
|
||||
Execute ls with arguments { ls, -a, -l, (null) }
|
||||
@@ -0,0 +1,6 @@
|
||||
[Init.TOKEN -> Command]
|
||||
Starting new command: ls
|
||||
[Command.TOKEN -> Arguments]
|
||||
Appending data to the argument list
|
||||
[Arguments.NEWLINE -> Term]
|
||||
Execute ls with arguments { ls, data, (null) }
|
||||
@@ -0,0 +1,9 @@
|
||||
[Init.TOKEN -> Command]
|
||||
Starting new command: ls
|
||||
[Command.PIPE -> Make_Pipe]
|
||||
Set up pipe
|
||||
Execute ls with arguments { ls, (null) }
|
||||
[Make_Pipe.TOKEN -> Command]
|
||||
Starting new command: head
|
||||
[Command.NEWLINE -> Term]
|
||||
Execute head with arguments { head, (null) }
|
||||
@@ -0,0 +1,15 @@
|
||||
[Init.TOKEN -> Command]
|
||||
Starting new command: ls
|
||||
[Command.TOKEN -> Arguments]
|
||||
Appending -l to the argument list
|
||||
[Arguments.PIPE -> Make_Pipe]
|
||||
Set up pipe
|
||||
Execute ls with arguments { ls, -l, (null) }
|
||||
[Make_Pipe.TOKEN -> Command]
|
||||
Starting new command: head
|
||||
[Command.TOKEN -> Arguments]
|
||||
Appending -n to the argument list
|
||||
[Arguments.TOKEN -> Arguments]
|
||||
Appending 1 to the argument list
|
||||
[Arguments.NEWLINE -> Term]
|
||||
Execute head with arguments { head, -n, 1, (null) }
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
|
||||
EXE="../shell"
|
||||
|
||||
function run_test {
|
||||
|
||||
# parameters
|
||||
TAG=$1
|
||||
ARGS=$2
|
||||
|
||||
# file paths
|
||||
OUTPUT=outputs/$TAG.txt
|
||||
DIFF=outputs/$TAG.diff
|
||||
EXPECT=expected/$TAG.txt
|
||||
VALGRND=valgrind/$TAG.txt
|
||||
|
||||
# print tag format
|
||||
PTAG=$(printf '%-30s' "$TAG")
|
||||
|
||||
# check for expected text that needs to be fixed
|
||||
if [ ! -z "$(egrep "<<<<.*>>>>" "$EXPECT")" ] ; then
|
||||
echo "$PTAG FAIL ($EXPECT not correct)"
|
||||
return
|
||||
fi
|
||||
|
||||
# compare the file
|
||||
SHAOUT=$(shasum "$EXPECT" | awk '{print $1}')
|
||||
SHAEXP=$(cat "expected/.$TAG.sha")
|
||||
if [ "$SHAOUT" != "$SHAEXP" ] ; then
|
||||
echo "$PTAG FAIL ($EXPECT not correct)"
|
||||
return
|
||||
fi
|
||||
|
||||
# run test and compare output to the expected version
|
||||
$EXE "$ARGS" 2>/dev/null >"$OUTPUT"
|
||||
diff -u "$OUTPUT" "$EXPECT" >"$DIFF"
|
||||
if [ -s "$DIFF" ]; then
|
||||
|
||||
# try alternative solution (if it exists)
|
||||
EXPECT=expected/$TAG-2.txt
|
||||
if [ -e "$EXPECT" ]; then
|
||||
diff -u "$OUTPUT" "$EXPECT" >"$DIFF"
|
||||
if [ -s "$DIFF" ]; then
|
||||
echo "$PTAG FAIL (see $DIFF for details)"
|
||||
else
|
||||
echo "$PTAG pass"
|
||||
fi
|
||||
else
|
||||
echo "$PTAG FAIL (see $DIFF for details)"
|
||||
fi
|
||||
else
|
||||
echo "$PTAG pass"
|
||||
fi
|
||||
|
||||
# run valgrind
|
||||
valgrind $EXE $ARGS &>$VALGRND
|
||||
}
|
||||
|
||||
# initialize output folders
|
||||
mkdir -p outputs
|
||||
mkdir -p valgrind
|
||||
rm -f outputs/* valgrind/*
|
||||
|
||||
# run individual tests
|
||||
source itests.include
|
||||
|
||||
# check for memory leaks
|
||||
LEAK=`cat valgrind/*.txt | grep 'definitely lost' | grep -v ' 0 bytes in 0 blocks'`
|
||||
if [ -z "$LEAK" ]; then
|
||||
echo "No memory leak found."
|
||||
else
|
||||
echo "Memory leak(s) found. See files listed below for details."
|
||||
grep 'definitely lost' valgrind/*.txt | grep -v ' 0 bytes in 0 blocks' | sed -e 's/:.*$//g' | sed -e 's/^/ - /g'
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# list of integration tests
|
||||
# format: run_test <TAG> <ARGS>
|
||||
# <TAG> used as the root for all filenames (i.e., "expected/$TAG.txt")
|
||||
# <ARGS> command-line arguments to test
|
||||
|
||||
run_test INTEG_command "ls"
|
||||
run_test INTEG_execute "ls NL"
|
||||
run_test INTEG_execute_name "ls data NL"
|
||||
run_test INTEG_execute_flags "ls -a -l NL"
|
||||
run_test INTEG_pipe "ls | head NL"
|
||||
run_test INTEG_pipe_flags "ls -l | head -n 1 NL"
|
||||
Binary file not shown.
@@ -0,0 +1,53 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <check.h>
|
||||
|
||||
#include "../effects.h"
|
||||
#include "../model.h"
|
||||
|
||||
/* nothing but starting a new cmdline */
|
||||
START_TEST (UNIT_new_cmdline)
|
||||
{
|
||||
printf ("\n======================================\n");
|
||||
printf ("UNIT TEST: new_cmdline\n\n");
|
||||
|
||||
fsm_t *fsm = cmdline_init ();
|
||||
assert (fsm != NULL);
|
||||
|
||||
handle_event (fsm, TOKEN);
|
||||
ck_assert_int_eq (fsm->state, Command);
|
||||
|
||||
free (fsm);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* a single cmdline from NEW to TRM */
|
||||
START_TEST (UNIT_exec_cmd)
|
||||
{
|
||||
printf ("\n======================================\n");
|
||||
printf ("UNIT TEST: exec_cmd\n\n");
|
||||
|
||||
fsm_t *fsm = cmdline_init ();
|
||||
assert (fsm != NULL);
|
||||
|
||||
handle_event (fsm, TOKEN);
|
||||
ck_assert_int_eq (fsm->state, Command);
|
||||
|
||||
handle_event (fsm, NEWLINE);
|
||||
ck_assert_int_eq (fsm->state, Term);
|
||||
|
||||
free (fsm);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void public_tests (Suite *s)
|
||||
{
|
||||
TCase *tc_public = tcase_create ("Public");
|
||||
tcase_add_test (tc_public, UNIT_new_cmdline);
|
||||
tcase_add_test (tc_public, UNIT_exec_cmd);
|
||||
suite_add_tcase (s, tc_public);
|
||||
}
|
||||
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
|
||||
STYLE="gnu"
|
||||
|
||||
IGNORE=()
|
||||
FAIL=0
|
||||
|
||||
function comp_file {
|
||||
|
||||
SRC=$1
|
||||
SRC_NAME=$2
|
||||
|
||||
# file paths
|
||||
FORMAT=ckstyle/${SRC_NAME}.$STYLE
|
||||
DIFF=ckstyle/${SRC_NAME}.diff
|
||||
|
||||
# run clang-format and compare results
|
||||
clang-format --style=$STYLE $source > $FORMAT
|
||||
diff -u $SRC $FORMAT >$DIFF
|
||||
|
||||
PTAG=$(printf '%-30s' "$SRC_NAME")
|
||||
if [ -s $DIFF ]; then
|
||||
echo "$PTAG FAIL (see $DIFF for details)"
|
||||
FAIL=1
|
||||
else
|
||||
echo "$PTAG pass"
|
||||
rm $DIFF
|
||||
fi
|
||||
rm $FORMAT
|
||||
}
|
||||
|
||||
mkdir -p ckstyle
|
||||
rm -f ckstyle/*
|
||||
|
||||
for source in $(ls ../*.c ../*.h) ; do
|
||||
SKIP=0
|
||||
src=$(basename $source)
|
||||
for ignore in ${IGNORE[*]} ; do
|
||||
if [ "$src" = "$ignore" ] ; then
|
||||
SKIP=1
|
||||
fi
|
||||
done
|
||||
if [ $SKIP = 0 ] ; then
|
||||
comp_file $source $src
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $FAIL != 0 ] ; then
|
||||
echo "Code that does not adhere to GNU standards will not be accepted."
|
||||
echo "You must fix these files before submission."
|
||||
else
|
||||
echo "Code correctly adheres to required style."
|
||||
fi
|
||||
@@ -0,0 +1,34 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <check.h>
|
||||
|
||||
extern void public_tests (Suite *s);
|
||||
extern void private_tests (Suite *s);
|
||||
|
||||
Suite * test_suite (void)
|
||||
{
|
||||
Suite *s = suite_create ("Default");
|
||||
public_tests (s);
|
||||
private_tests (s);
|
||||
return s;
|
||||
}
|
||||
|
||||
void run_testsuite ()
|
||||
{
|
||||
Suite *s = test_suite ();
|
||||
SRunner *sr = srunner_create (s);
|
||||
srunner_run_all (sr, CK_NORMAL);
|
||||
srunner_free (sr);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
srand((unsigned)time(NULL));
|
||||
run_testsuite ();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
OUTPUT=utests.output
|
||||
|
||||
./testsuite > "$OUTPUT" 2>/dev/null
|
||||
|
||||
if [ ! -s "$OUTPUT" ] ; then
|
||||
echo "UNIT FAIL (testsuite produced no output)"
|
||||
rm -f "$OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat "$OUTPUT" | awk '/Failures/,0'
|
||||
|
||||
percent=$(cat "$OUTPUT" | grep Failures | cut -d':' -f1)
|
||||
rm -f "$OUTPUT"
|
||||
[ "$percent" = "100%" ] && exit 0
|
||||
|
||||
echo "(run ./testsuite in tests directory for more information)"
|
||||
exit 1
|
||||
|
||||
Reference in New Issue
Block a user