darcs 2.4 → 2.4.1
raw patch · 27 files changed
+2503/−1379 lines, 27 filesdep ~hashed-storagedep ~mmapPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: hashed-storage, mmap
API changes (from Hackage documentation)
- Darcs.Commands.ShowFiles: showManifest :: DarcsCommand
- Darcs.Commands.ShowIndex: showPristine :: DarcsCommand
- Darcs.Test.Patch.Check: FC :: Map Int ByteString -> Int -> FileContents
- Darcs.Test.Patch.Check: check_move :: String -> String -> PatchCheck Bool
- Darcs.Test.Patch.Check: create_dir :: String -> PatchCheck Bool
- Darcs.Test.Patch.Check: create_file :: String -> PatchCheck Bool
- Darcs.Test.Patch.Check: data FileContents
- Darcs.Test.Patch.Check: delete_line :: String -> Int -> ByteString -> PatchCheck Bool
- Darcs.Test.Patch.Check: dir_exists :: String -> PatchCheck Bool
- Darcs.Test.Patch.Check: do_check :: PatchCheck a -> a
- Darcs.Test.Patch.Check: do_verbose_check :: PatchCheck a -> a
- Darcs.Test.Patch.Check: fc_lines :: FileContents -> Map Int ByteString
- Darcs.Test.Patch.Check: fc_maxline :: FileContents -> Int
- Darcs.Test.Patch.Check: file_empty :: String -> PatchCheck Bool
- Darcs.Test.Patch.Check: file_exists :: String -> PatchCheck Bool
- Darcs.Test.Patch.Check: insert_line :: String -> Int -> ByteString -> PatchCheck Bool
- Darcs.Test.Patch.Check: instance Eq FileContents
- Darcs.Test.Patch.Check: instance Eq Prop
- Darcs.Test.Patch.Check: instance Show FileContents
- Darcs.Test.Patch.Check: instance Show KnownState
- Darcs.Test.Patch.Check: instance Show Prop
- Darcs.Test.Patch.Check: is_valid :: PatchCheck Bool
- Darcs.Test.Patch.Check: modify_file :: String -> (Maybe FileContents -> Maybe FileContents) -> PatchCheck Bool
- Darcs.Test.Patch.Check: remove_dir :: String -> PatchCheck Bool
- Darcs.Test.Patch.Check: remove_file :: String -> PatchCheck Bool
- Darcs.Test.Patch.Check: type PatchCheck = State KnownState
+ Darcs.Commands.ShowFiles: manifestCmd :: ([DarcsFlag] -> Slurpy -> [FilePath]) -> [DarcsFlag] -> [String] -> IO ()
+ Darcs.Commands.ShowFiles: toListManifest :: [DarcsFlag] -> Slurpy -> [FilePath]
+ Darcs.Commands.ShowIndex: showPristineCmd :: [DarcsFlag] -> [String] -> IO ()
- Darcs.Commands: commandAlias :: String -> DarcsCommand -> DarcsCommand
+ Darcs.Commands: commandAlias :: String -> Maybe DarcsCommand -> DarcsCommand -> DarcsCommand
Files
- NEWS +90/−0
- darcs.cabal +17/−8
- doc/manual/bigimages.tex +0/−605
- doc/manual/images.tex +0/−605
- doc/manual/patch-theory.tex +0/−79
- release/distributed-context +1/−1
- src/Darcs/Commands.lhs +6/−4
- src/Darcs/Commands/Changes.lhs +1/−1
- src/Darcs/Commands/GZCRCs.lhs +3/−2
- src/Darcs/Commands/Get.lhs +1/−1
- src/Darcs/Commands/MarkConflicts.lhs +1/−1
- src/Darcs/Commands/Move.lhs +1/−1
- src/Darcs/Commands/Remove.lhs +21/−11
- src/Darcs/Commands/Show.lhs +21/−4
- src/Darcs/Commands/ShowFiles.lhs +4/−7
- src/Darcs/Commands/ShowIndex.lhs +4/−12
- src/Darcs/Commands/Unrecord.lhs +1/−1
- src/Darcs/Test/Email.hs +86/−0
- src/Darcs/Test/Patch/QuickCheck.hs +782/−0
- src/Darcs/Test/Patch/Test.hs +682/−0
- src/Darcs/Test/Patch/Unit.hs +397/−0
- tests/README.test_maintainers.txt +100/−0
- tests/failing-issue1645-ignore-symlinks.sh +0/−35
- tests/issue1645-ignore-symlinks-case-fold.sh +73/−0
- tests/issue1645-ignore-symlinks.sh +173/−0
- tests/issue1765_recursive-remove-on-root.sh +36/−0
- tests/issue458.sh +2/−1
NEWS view
@@ -1,3 +1,93 @@+Darcs 2.4.1, 31 March 2010++ * Important changes in Darcs 2.4.1++ * darcs works again on Windows shared directories+ * missing documentation and test files have been added to the tarball+ * darcs will no longer give errors about a nonexistent file when compiled+ with the wrong mmap+ * moving files between directories can no longer break the directory index+ * darcs handles the case that someone uses 'remove -r' on an+ untracked directory++ * Bugs Fixed in Darcs 2.4.1++ * 1750: uncover help text for 'darcs show pristine'+ * 1753: restrict mmap to version used by hashed-storage+ * 1754: fix issue458.sh on systems with xattrs+ * 1756: moving files between directories breaks index+ * 1757: add test files to distribution tarball+ * 1765: refuse to remove non-tracked directories recursively+ * 1767: send CRC erros to standard error+++Darcs 2.4, 27 February 2010++ * Important changes in Darcs 2.4++ * Use fast index-based diffing everywhere (Petr)+ * Interactive patch splitting (Ganesh)+ * An 'optimize --upgrade' option to convert to hashed format in-place+ (Eric)+ * Hunk matching (Kamil Dworakowski, tat.wright)+ * Progress reporting is no longer deceptive (Roman)+ * A 'remove --recursive' option to remove a directory tree from revision+ control (Roman)+ * 'show files' accepts arguments to show a subset of tracked files (Luca)+ * A '--remote-darcs' flag for pushing to a host where darcs isn't called+ darcs+ * Many miscellaneous Windows improvements (Salvatore, Petr and others)+ * 'darcs send' now mentions the repository name in the email body (Joachim)+ * Handle files with boring names in the repository correctly (Petr)+ * Fix parsing of .authorspellings file (Tomáš)+ * Various sane new command-line option names (Florent)+ * Remove the '--checkpoint' option (Petr)+ * Use external libraries for all UTF-8 handling (Eric, Reinier)+ * Use the Haskell zlib package exclusively for compression (Petr)++ * Bugs Fixed in Darcs 2.4++ * 183: do not sort changes --summary output+ * 223: add --remote-darcs flag to specify name of remote darcs executable+ * 291: provide (basic) interactive patch splitting+ * 540: darcs remove --recursive+ * 835: 'show files' with arguments+ * 1122: get --complete should not offer to create a lazy repository+ * 1216: list Match section in ToC+ * 1224: refuse to convert a repo that's already in darcs-2 format+ * 1300: logfile deleted on unsucessful record+ * 1308: push should warn about unpulled patches before patch-selection+ * 1336: sane error message on --last "" (empty string to numbers parser)+ * 1362: mention repo name in mail send body+ * 1377: getProgname for local darcs instances+ * 1392: use parsec to parse .authorspelling+ * 1424: darcs get wrongly reports "using lazy repository" if you ctrl-c + old-fashioned get+ * 1447: different online help for send/apply --cc+ * 1488: fix crash in whatsnew when invoked in non-tracked directory+ * 1548: show contents requires at least one argument+ * 1554: allow opt-out of -threaded (fix ARM builds)+ * 1563: official thank-you page+ * 1578: don't put newlines in the Haskeline prompts+ * 1583: on darcs get, suggest upgrading source repo to hashed+ * 1584: provide optimize --upgrade command+ * 1588: add --skip-conflicts option+ * 1594: define PREPROCHTML in makefile+ * 1620: make amend leave a log file when it should+ * 1636: hunk matching+ * 1643: optimize --upgrade should do optimize+ * 1652: suggest cabal update before cabal install+ * 1659: make restrictBoring take recorded state into account+ * 1677: create correct hashes for empty directories in index+ * 1681: preserve log on amend failure+ * 1709: fix short version of progress reporting+ * 1712: correctly report number of patches to pull+ * 1720: fix cabal haddock problem+ * 1731: fix performance regression in check and repair+ * 1741: fix --list-options when option has multiple names+ * 1749: refuse to remove non-empty directories++ Darcs 2.3.1, 20 Sep 2009 * Important changes in Darcs 2.3.1
darcs.cabal view
@@ -1,5 +1,5 @@ Name: darcs-version: 2.4+version: 2.4.1 License: GPL License-file: COPYING Author: David Roundy <droundy@darcs.net>, <darcs-users@darcs.net>@@ -48,7 +48,6 @@ -- documentation files src/best_practices.tex, src/building_darcs.tex, src/configuring_darcs.tex, src/features.tex, src/formats.tex, src/gpl.tex, src/switching.tex, src/darcs.tex- doc/manual/images.tex, doc/manual/bigimages.tex, doc/manual/patch-theory.tex, doc/darcs.css README, NEWS@@ -64,6 +63,7 @@ tests/network/*.sh tests/lib tests/example_binary.png+ tests/README.test_maintainers.txt GNUmakefile @@ -126,6 +126,9 @@ src/maybe_relink.c src/umask.c src/Crypt/sha2.c+ -- this module isn't exported by libdarcs, so not included in the tarball+ -- if not mentioned+ other-modules: Darcs.Test.Patch.Check extensions: CPP@@ -276,7 +279,6 @@ Darcs.SlurpDirectory Darcs.SlurpDirectory.Internal Darcs.Test- Darcs.Test.Patch.Check Darcs.TheCommands Darcs.URL Darcs.Utils@@ -323,7 +325,7 @@ html == 1.0.*, filepath == 1.1.*, haskeline >= 0.6.1 && < 0.7,- hashed-storage >= 0.4.7 && < 0.5+ hashed-storage == 0.4.11 if !os(windows) build-depends: unix >= 1.0 && < 2.5@@ -369,7 +371,7 @@ buildable: False if flag(mmap) && !os(windows)- build-depends: mmap >= 0.2+ build-depends: mmap >= 0.2 && < 0.5 cpp-options: -DHAVE_MMAP build-depends: zlib >= 0.5.1.0 && < 0.6.0.0@@ -453,7 +455,7 @@ html == 1.0.*, filepath == 1.1.*, haskeline >= 0.6.1 && < 0.7,- hashed-storage >= 0.4.4 && < 0.5+ hashed-storage == 0.4.11 if !os(windows) build-depends: unix >= 1.0 && < 2.5@@ -491,7 +493,7 @@ buildable: False if flag(mmap) && !os(windows)- build-depends: mmap >= 0.2+ build-depends: mmap >= 0.2 && < 0.5 cpp-options: -DHAVE_MMAP build-depends: zlib >= 0.5.1.0 && < 0.6.0.0@@ -539,6 +541,13 @@ src/maybe_relink.c src/umask.c src/Crypt/sha2.c+ -- list all unit test modules not exported by libdarcs; otherwise Cabal won't+ -- include them in the tarball+ other-modules: Darcs.Test.Email+ Darcs.Test.Patch.Check+ Darcs.Test.Patch.QuickCheck+ Darcs.Test.Patch.Test+ Darcs.Test.Patch.Unit -- We need optimizations, regardless of what Hackage says ghc-options: -Wall -O2 -funbox-strict-fields@@ -591,7 +600,7 @@ random == 1.0.* if flag(mmap) && !os(windows)- build-depends: mmap >= 0.2+ build-depends: mmap >= 0.2 && < 0.5 cpp-options: -DHAVE_MMAP build-depends: zlib >= 0.5.1.0 && < 0.6.0.0
− doc/manual/bigimages.tex
@@ -1,605 +0,0 @@-\batchmode---\documentclass{book}-\RequirePackage{ifthen}-----\usepackage{verbatim}-\usepackage{html}-\usepackage{fancyvrb}--%-\newenvironment{code}{\comment}{\endcomment} -----\usepackage[dvips]{color}---\pagecolor[gray]{.7}--\usepackage[latin1]{inputenc}----\makeatletter--\makeatletter-\count@=\the\catcode`\_ \catcode`\_=8 -\newenvironment{tex2html_wrap}{}{}%-\catcode`\<=12\catcode`\_=\count@-\newcommand{\providedcommand}[1]{\expandafter\providecommand\csname #1\endcsname}%-\newcommand{\renewedcommand}[1]{\expandafter\providecommand\csname #1\endcsname{}%- \expandafter\renewcommand\csname #1\endcsname}%-\newcommand{\newedenvironment}[1]{\newenvironment{#1}{}{}\renewenvironment{#1}}%-\let\newedcommand\renewedcommand-\let\renewedenvironment\newedenvironment-\makeatother-\let\mathon=$-\let\mathoff=$-\ifx\AtBeginDocument\undefined \newcommand{\AtBeginDocument}[1]{}\fi-\newbox\sizebox-\setlength{\hoffset}{0pt}\setlength{\voffset}{0pt}-\addtolength{\textheight}{\footskip}\setlength{\footskip}{0pt}-\addtolength{\textheight}{\topmargin}\setlength{\topmargin}{0pt}-\addtolength{\textheight}{\headheight}\setlength{\headheight}{0pt}-\addtolength{\textheight}{\headsep}\setlength{\headsep}{0pt}-\setlength{\textwidth}{349pt}-\newwrite\lthtmlwrite-\makeatletter-\let\realnormalsize=\normalsize-\global\topskip=2sp-\def\preveqno{}\let\real@float=\@float \let\realend@float=\end@float-\def\@float{\let\@savefreelist\@freelist\real@float}-\def\liih@math{\ifmmode$\else\bad@math\fi}-\def\end@float{\realend@float\global\let\@freelist\@savefreelist}-\let\real@dbflt=\@dbflt \let\end@dblfloat=\end@float-\let\@largefloatcheck=\relax-\let\if@boxedmulticols=\iftrue-\def\@dbflt{\let\@savefreelist\@freelist\real@dbflt}-\def\adjustnormalsize{\def\normalsize{\mathsurround=0pt \realnormalsize- \parindent=0pt\abovedisplayskip=0pt\belowdisplayskip=0pt}%- \def\phantompar{\csname par\endcsname}\normalsize}%-\def\lthtmltypeout#1{{\let\protect\string \immediate\write\lthtmlwrite{#1}}}%-\newcommand\lthtmlhboxmathA{\adjustnormalsize\setbox\sizebox=\hbox\bgroup\kern.05em }%-\newcommand\lthtmlhboxmathB{\adjustnormalsize\setbox\sizebox=\hbox to\hsize\bgroup\hfill }%-\newcommand\lthtmlvboxmathA{\adjustnormalsize\setbox\sizebox=\vbox\bgroup %- \let\ifinner=\iffalse \let\)\liih@math }%-\newcommand\lthtmlboxmathZ{\@next\next\@currlist{}{\def\next{\voidb@x}}%- \expandafter\box\next\egroup}%-\newcommand\lthtmlmathtype[1]{\gdef\lthtmlmathenv{#1}}%-\newcommand\lthtmllogmath{\dimen0\ht\sizebox \advance\dimen0\dp\sizebox- \ifdim\dimen0>.95\vsize- \lthtmltypeout{%-*** image for \lthtmlmathenv\space is too tall at \the\dimen0, reducing to .95 vsize ***}%- \ht\sizebox.95\vsize \dp\sizebox\z@ \fi- \lthtmltypeout{l2hSize %-:\lthtmlmathenv:\the\ht\sizebox::\the\dp\sizebox::\the\wd\sizebox.\preveqno}}%-\newcommand\lthtmlfigureA[1]{\let\@savefreelist\@freelist- \lthtmlmathtype{#1}\lthtmlvboxmathA}%-\newcommand\lthtmlpictureA{\bgroup\catcode`\_=8 \lthtmlpictureB}%-\newcommand\lthtmlpictureB[1]{\lthtmlmathtype{#1}\egroup- \let\@savefreelist\@freelist \lthtmlhboxmathB}%-\newcommand\lthtmlpictureZ[1]{\hfill\lthtmlfigureZ}%-\newcommand\lthtmlfigureZ{\lthtmlboxmathZ\lthtmllogmath\copy\sizebox- \global\let\@freelist\@savefreelist}%-\newcommand\lthtmldisplayA{\bgroup\catcode`\_=8 \lthtmldisplayAi}%-\newcommand\lthtmldisplayAi[1]{\lthtmlmathtype{#1}\egroup\lthtmlvboxmathA}%-\newcommand\lthtmldisplayB[1]{\edef\preveqno{(\theequation)}%- \lthtmldisplayA{#1}\let\@eqnnum\relax}%-\newcommand\lthtmldisplayZ{\lthtmlboxmathZ\lthtmllogmath\lthtmlsetmath}%-\newcommand\lthtmlinlinemathA{\bgroup\catcode`\_=8 \lthtmlinlinemathB}-\newcommand\lthtmlinlinemathB[1]{\lthtmlmathtype{#1}\egroup\lthtmlhboxmathA- \vrule height1.5ex width0pt }%-\newcommand\lthtmlinlineA{\bgroup\catcode`\_=8 \lthtmlinlineB}%-\newcommand\lthtmlinlineB[1]{\lthtmlmathtype{#1}\egroup\lthtmlhboxmathA}%-\newcommand\lthtmlinlineZ{\egroup\expandafter\ifdim\dp\sizebox>0pt %- \expandafter\centerinlinemath\fi\lthtmllogmath\lthtmlsetinline}-\newcommand\lthtmlinlinemathZ{\egroup\expandafter\ifdim\dp\sizebox>0pt %- \expandafter\centerinlinemath\fi\lthtmllogmath\lthtmlsetmath}-\newcommand\lthtmlindisplaymathZ{\egroup %- \centerinlinemath\lthtmllogmath\lthtmlsetmath}-\def\lthtmlsetinline{\hbox{\vrule width.1em \vtop{\vbox{%- \kern.1em\copy\sizebox}\ifdim\dp\sizebox>0pt\kern.1em\else\kern.3pt\fi- \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}}-\def\lthtmlsetmath{\hbox{\vrule width.1em\kern-.05em\vtop{\vbox{%- \kern.1em\kern0.8 pt\hbox{\hglue.17em\copy\sizebox\hglue0.8 pt}}\kern.3pt%- \ifdim\dp\sizebox>0pt\kern.1em\fi \kern0.8 pt%- \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}}-\def\centerinlinemath{%- \dimen1=\ifdim\ht\sizebox<\dp\sizebox \dp\sizebox\else\ht\sizebox\fi- \advance\dimen1by.5pt \vrule width0pt height\dimen1 depth\dimen1 - \dp\sizebox=\dimen1\ht\sizebox=\dimen1\relax}--\def\lthtmlcheckvsize{\ifdim\ht\sizebox<\vsize - \ifdim\wd\sizebox<\hsize\expandafter\hfill\fi \expandafter\vfill- \else\expandafter\vss\fi}%-\providecommand{\selectlanguage}[1]{}%-\makeatletter \tracingstats = 1 ---\begin{document}-\pagestyle{empty}\thispagestyle{empty}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength hsize=\the\hsize}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength vsize=\the\vsize}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength hoffset=\the\hoffset}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength voffset=\the\voffset}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength topmargin=\the\topmargin}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength topskip=\the\topskip}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength headheight=\the\headheight}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength headsep=\the\headsep}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength parskip=\the\parskip}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength oddsidemargin=\the\oddsidemargin}\lthtmltypeout{}%-\makeatletter-\if@twoside\lthtmltypeout{latex2htmlLength evensidemargin=\the\evensidemargin}%-\else\lthtmltypeout{latex2htmlLength evensidemargin=\the\oddsidemargin}\fi%-\lthtmltypeout{}%-\makeatother-\setcounter{page}{1}-\onecolumn--% !!! IMAGES START HERE !!!--\stepcounter{chapter}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{chapter}-\stepcounter{section}-\stepcounter{section}-\stepcounter{section}-\stepcounter{section}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2771}%-$<$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2773}%-$>$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{paragraph}-\stepcounter{chapter}-\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{section}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{section}-\stepcounter{chapter}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2775}%-$+$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{section}-\stepcounter{section}-\stepcounter{section}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2777}%-$R_{c}$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2779}%-$f_1$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2781}%-$R_c$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2783}%-$R_1$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2787}%-$f_2$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2795}%-$R_2$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{subsection}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2835}%-$R_p$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2839}%-$R_l$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{chapter}-\stepcounter{chapter}-\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{paragraph}-\stepcounter{subsection}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2841}%-$\backslash$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2847}%-$ R_1 \bigcup R_2-\bigcup R_3 \ldots$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2849}%-$ R_1 \bigcap R_2 \bigcap R_3 \ldots$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2851}%-$ S-\backslash S \rightarrow \emptyset $%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2853}%-$ R_1-\backslash (R_2 \bigcup R_3 \bigcup \ldots$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}--%-\providecommand{\pullwarning}[1]{-\textbf{WARNING:} #1 should not be run when there is a possibility-that another user may be pulling from the same repository. Attempting to do so-may cause repository corruption.}%--\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsubsection}-\stepcounter{subsection}-\appendix-\stepcounter{section}-\stepcounter{paragraph}---\addtolength{\itemsep}{-0.5\baselineskip}%--\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{paragraph}---\addtolength{\itemsep}{-0.5\baselineskip}%--\stepcounter{paragraph}-\stepcounter{chapter}-\stepcounter{section}-\stepcounter{section}-\stepcounter{chapter}---\newtheorem{thm}{Theorem}%----\newtheorem{dfn}{Definition}%--\stepcounter{section}-\stepcounter{section}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2863}%-$P_1$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2865}%-$P_2$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2867}%-$P_2P_1$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2873}%-$P_1\parallel P_2$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2875}%-$P^{ -1}$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2877}%-$P$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2759}%-\( P^{ -1} P \)%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmldisplayA{displaymath2763}%-\begin{displaymath} (P_2 P_1)^{ -1} = P_1^{ -1} P_2^{ -1}. \end{displaymath}%-\lthtmldisplayZ-\lthtmlcheckvsize\clearpage}--\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{subsection}-\stepcounter{subsection}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2881}%-$O(n)$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{section}-\stepcounter{subsection}--%-\providecommand{\commutex}{\longleftrightarrow}%---%-\providecommand{\commutes}{\longleftrightarrow}%--{\newpage\clearpage-\lthtmldisplayA{displaymath2764}%-\begin{displaymath} P_2 P_1 \longleftrightarrow {P_1}' {P_2}'. \end{displaymath}%-\lthtmldisplayZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2887}%-$P_1'$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2893}%-$P_2'$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2897}%-$\longleftrightarrow $%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2899}%-$==$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2901}%-$\ddot\frown$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{paragraph}--%-\providecommand{\merge}{\Longrightarrow}%--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2760}%-\( \Longrightarrow \)%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmldisplayA{displaymath2765}%-\begin{displaymath} P_2 \parallel P_1 \Longrightarrow {P_2}' P_1 \longleftrightarrow {P_1}' P_2. \end{displaymath}%-\lthtmldisplayZ-\lthtmlcheckvsize\clearpage}--\stepcounter{subsection}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2911}%-$ P_2' P_1 \longleftrightarrow P_1' P_2 $%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2913}%-$ P_1'^{ -1}-P_2' \longleftrightarrow P_2 P_1^{ -1} $%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2915}%-$P_1'^{ -1}$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2917}%-$P_1^{ -1}$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmldisplayA{displaymath2766}%-\begin{displaymath}-A^{ -1} C \longleftrightarrow C' A'^{ -1}-\end{displaymath}%-\lthtmldisplayZ-\lthtmlcheckvsize\clearpage}--\stepcounter{section}-\stepcounter{section}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{chapter}-\stepcounter{chapter}-\addtocounter{enumi}{-1}-\stepcounter{section}--\end{document}
− doc/manual/images.tex
@@ -1,605 +0,0 @@-\batchmode---\documentclass{book}-\RequirePackage{ifthen}-----\usepackage{verbatim}-\usepackage{html}-\usepackage{fancyvrb}--%-\newenvironment{code}{\comment}{\endcomment} -----\usepackage[dvips]{color}---\pagecolor[gray]{.7}--\usepackage[latin1]{inputenc}----\makeatletter--\makeatletter-\count@=\the\catcode`\_ \catcode`\_=8 -\newenvironment{tex2html_wrap}{}{}%-\catcode`\<=12\catcode`\_=\count@-\newcommand{\providedcommand}[1]{\expandafter\providecommand\csname #1\endcsname}%-\newcommand{\renewedcommand}[1]{\expandafter\providecommand\csname #1\endcsname{}%- \expandafter\renewcommand\csname #1\endcsname}%-\newcommand{\newedenvironment}[1]{\newenvironment{#1}{}{}\renewenvironment{#1}}%-\let\newedcommand\renewedcommand-\let\renewedenvironment\newedenvironment-\makeatother-\let\mathon=$-\let\mathoff=$-\ifx\AtBeginDocument\undefined \newcommand{\AtBeginDocument}[1]{}\fi-\newbox\sizebox-\setlength{\hoffset}{0pt}\setlength{\voffset}{0pt}-\addtolength{\textheight}{\footskip}\setlength{\footskip}{0pt}-\addtolength{\textheight}{\topmargin}\setlength{\topmargin}{0pt}-\addtolength{\textheight}{\headheight}\setlength{\headheight}{0pt}-\addtolength{\textheight}{\headsep}\setlength{\headsep}{0pt}-\setlength{\textwidth}{349pt}-\newwrite\lthtmlwrite-\makeatletter-\let\realnormalsize=\normalsize-\global\topskip=2sp-\def\preveqno{}\let\real@float=\@float \let\realend@float=\end@float-\def\@float{\let\@savefreelist\@freelist\real@float}-\def\liih@math{\ifmmode$\else\bad@math\fi}-\def\end@float{\realend@float\global\let\@freelist\@savefreelist}-\let\real@dbflt=\@dbflt \let\end@dblfloat=\end@float-\let\@largefloatcheck=\relax-\let\if@boxedmulticols=\iftrue-\def\@dbflt{\let\@savefreelist\@freelist\real@dbflt}-\def\adjustnormalsize{\def\normalsize{\mathsurround=0pt \realnormalsize- \parindent=0pt\abovedisplayskip=0pt\belowdisplayskip=0pt}%- \def\phantompar{\csname par\endcsname}\normalsize}%-\def\lthtmltypeout#1{{\let\protect\string \immediate\write\lthtmlwrite{#1}}}%-\newcommand\lthtmlhboxmathA{\adjustnormalsize\setbox\sizebox=\hbox\bgroup\kern.05em }%-\newcommand\lthtmlhboxmathB{\adjustnormalsize\setbox\sizebox=\hbox to\hsize\bgroup\hfill }%-\newcommand\lthtmlvboxmathA{\adjustnormalsize\setbox\sizebox=\vbox\bgroup %- \let\ifinner=\iffalse \let\)\liih@math }%-\newcommand\lthtmlboxmathZ{\@next\next\@currlist{}{\def\next{\voidb@x}}%- \expandafter\box\next\egroup}%-\newcommand\lthtmlmathtype[1]{\gdef\lthtmlmathenv{#1}}%-\newcommand\lthtmllogmath{\dimen0\ht\sizebox \advance\dimen0\dp\sizebox- \ifdim\dimen0>.95\vsize- \lthtmltypeout{%-*** image for \lthtmlmathenv\space is too tall at \the\dimen0, reducing to .95 vsize ***}%- \ht\sizebox.95\vsize \dp\sizebox\z@ \fi- \lthtmltypeout{l2hSize %-:\lthtmlmathenv:\the\ht\sizebox::\the\dp\sizebox::\the\wd\sizebox.\preveqno}}%-\newcommand\lthtmlfigureA[1]{\let\@savefreelist\@freelist- \lthtmlmathtype{#1}\lthtmlvboxmathA}%-\newcommand\lthtmlpictureA{\bgroup\catcode`\_=8 \lthtmlpictureB}%-\newcommand\lthtmlpictureB[1]{\lthtmlmathtype{#1}\egroup- \let\@savefreelist\@freelist \lthtmlhboxmathB}%-\newcommand\lthtmlpictureZ[1]{\hfill\lthtmlfigureZ}%-\newcommand\lthtmlfigureZ{\lthtmlboxmathZ\lthtmllogmath\copy\sizebox- \global\let\@freelist\@savefreelist}%-\newcommand\lthtmldisplayA{\bgroup\catcode`\_=8 \lthtmldisplayAi}%-\newcommand\lthtmldisplayAi[1]{\lthtmlmathtype{#1}\egroup\lthtmlvboxmathA}%-\newcommand\lthtmldisplayB[1]{\edef\preveqno{(\theequation)}%- \lthtmldisplayA{#1}\let\@eqnnum\relax}%-\newcommand\lthtmldisplayZ{\lthtmlboxmathZ\lthtmllogmath\lthtmlsetmath}%-\newcommand\lthtmlinlinemathA{\bgroup\catcode`\_=8 \lthtmlinlinemathB}-\newcommand\lthtmlinlinemathB[1]{\lthtmlmathtype{#1}\egroup\lthtmlhboxmathA- \vrule height1.5ex width0pt }%-\newcommand\lthtmlinlineA{\bgroup\catcode`\_=8 \lthtmlinlineB}%-\newcommand\lthtmlinlineB[1]{\lthtmlmathtype{#1}\egroup\lthtmlhboxmathA}%-\newcommand\lthtmlinlineZ{\egroup\expandafter\ifdim\dp\sizebox>0pt %- \expandafter\centerinlinemath\fi\lthtmllogmath\lthtmlsetinline}-\newcommand\lthtmlinlinemathZ{\egroup\expandafter\ifdim\dp\sizebox>0pt %- \expandafter\centerinlinemath\fi\lthtmllogmath\lthtmlsetmath}-\newcommand\lthtmlindisplaymathZ{\egroup %- \centerinlinemath\lthtmllogmath\lthtmlsetmath}-\def\lthtmlsetinline{\hbox{\vrule width.1em \vtop{\vbox{%- \kern.1em\copy\sizebox}\ifdim\dp\sizebox>0pt\kern.1em\else\kern.3pt\fi- \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}}-\def\lthtmlsetmath{\hbox{\vrule width.1em\kern-.05em\vtop{\vbox{%- \kern.1em\kern0.8 pt\hbox{\hglue.17em\copy\sizebox\hglue0.8 pt}}\kern.3pt%- \ifdim\dp\sizebox>0pt\kern.1em\fi \kern0.8 pt%- \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}}-\def\centerinlinemath{%- \dimen1=\ifdim\ht\sizebox<\dp\sizebox \dp\sizebox\else\ht\sizebox\fi- \advance\dimen1by.5pt \vrule width0pt height\dimen1 depth\dimen1 - \dp\sizebox=\dimen1\ht\sizebox=\dimen1\relax}--\def\lthtmlcheckvsize{\ifdim\ht\sizebox<\vsize - \ifdim\wd\sizebox<\hsize\expandafter\hfill\fi \expandafter\vfill- \else\expandafter\vss\fi}%-\providecommand{\selectlanguage}[1]{}%-\makeatletter \tracingstats = 1 ---\begin{document}-\pagestyle{empty}\thispagestyle{empty}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength hsize=\the\hsize}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength vsize=\the\vsize}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength hoffset=\the\hoffset}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength voffset=\the\voffset}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength topmargin=\the\topmargin}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength topskip=\the\topskip}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength headheight=\the\headheight}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength headsep=\the\headsep}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength parskip=\the\parskip}\lthtmltypeout{}%-\lthtmltypeout{latex2htmlLength oddsidemargin=\the\oddsidemargin}\lthtmltypeout{}%-\makeatletter-\if@twoside\lthtmltypeout{latex2htmlLength evensidemargin=\the\evensidemargin}%-\else\lthtmltypeout{latex2htmlLength evensidemargin=\the\oddsidemargin}\fi%-\lthtmltypeout{}%-\makeatother-\setcounter{page}{1}-\onecolumn--% !!! IMAGES START HERE !!!--\stepcounter{chapter}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{chapter}-\stepcounter{section}-\stepcounter{section}-\stepcounter{section}-\stepcounter{section}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2771}%-$<$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2773}%-$>$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{paragraph}-\stepcounter{chapter}-\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{section}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{section}-\stepcounter{chapter}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2775}%-$+$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{section}-\stepcounter{section}-\stepcounter{section}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2777}%-$R_{c}$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2779}%-$f_1$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2781}%-$R_c$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2783}%-$R_1$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2787}%-$f_2$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2795}%-$R_2$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{subsection}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2835}%-$R_p$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2839}%-$R_l$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{chapter}-\stepcounter{chapter}-\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{paragraph}-\stepcounter{subsection}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2841}%-$\backslash$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2847}%-$ R_1 \bigcup R_2-\bigcup R_3 \ldots$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2849}%-$ R_1 \bigcap R_2 \bigcap R_3 \ldots$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2851}%-$ S-\backslash S \rightarrow \emptyset $%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2853}%-$ R_1-\backslash (R_2 \bigcup R_3 \bigcup \ldots$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}--%-\providecommand{\pullwarning}[1]{-\textbf{WARNING:} #1 should not be run when there is a possibility-that another user may be pulling from the same repository. Attempting to do so-may cause repository corruption.}%--\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{subsubsection}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{subsubsection}-\stepcounter{subsection}-\appendix-\stepcounter{section}-\stepcounter{paragraph}---\addtolength{\itemsep}{-0.5\baselineskip}%--\stepcounter{paragraph}-\stepcounter{section}-\stepcounter{paragraph}---\addtolength{\itemsep}{-0.5\baselineskip}%--\stepcounter{paragraph}-\stepcounter{chapter}-\stepcounter{section}-\stepcounter{section}-\stepcounter{chapter}---\newtheorem{thm}{Theorem}%----\newtheorem{dfn}{Definition}%--\stepcounter{section}-\stepcounter{section}-\stepcounter{section}-\stepcounter{subsection}-\stepcounter{subsection}-\stepcounter{section}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2863}%-$P_1$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2865}%-$P_2$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2867}%-$P_2P_1$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2873}%-$P_1\parallel P_2$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2875}%-$P^{ -1}$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2877}%-$P$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2759}%-\( P^{ -1} P \)%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmldisplayA{displaymath2763}%-\begin{displaymath} (P_2 P_1)^{ -1} = P_1^{ -1} P_2^{ -1}. \end{displaymath}%-\lthtmldisplayZ-\lthtmlcheckvsize\clearpage}--\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{subsection}-\stepcounter{subsection}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2881}%-$O(n)$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{section}-\stepcounter{subsection}--%-\providecommand{\commutex}{\longleftrightarrow}%---%-\providecommand{\commutes}{\longleftrightarrow}%--{\newpage\clearpage-\lthtmldisplayA{displaymath2764}%-\begin{displaymath} P_2 P_1 \longleftrightarrow {P_1}' {P_2}'. \end{displaymath}%-\lthtmldisplayZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2887}%-$P_1'$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2893}%-$P_2'$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2897}%-$\longleftrightarrow $%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2899}%-$==$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2901}%-$\ddot\frown$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--\stepcounter{paragraph}--%-\providecommand{\merge}{\Longrightarrow}%--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2760}%-\( \Longrightarrow \)%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmldisplayA{displaymath2765}%-\begin{displaymath} P_2 \parallel P_1 \Longrightarrow {P_2}' P_1 \longleftrightarrow {P_1}' P_2. \end{displaymath}%-\lthtmldisplayZ-\lthtmlcheckvsize\clearpage}--\stepcounter{subsection}-{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2911}%-$ P_2' P_1 \longleftrightarrow P_1' P_2 $%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2913}%-$ P_1'^{ -1}-P_2' \longleftrightarrow P_2 P_1^{ -1} $%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2915}%-$P_1'^{ -1}$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmlinlinemathA{tex2html_wrap_inline2917}%-$P_1^{ -1}$%-\lthtmlinlinemathZ-\lthtmlcheckvsize\clearpage}--{\newpage\clearpage-\lthtmldisplayA{displaymath2766}%-\begin{displaymath}-A^{ -1} C \longleftrightarrow C' A'^{ -1}-\end{displaymath}%-\lthtmldisplayZ-\lthtmlcheckvsize\clearpage}--\stepcounter{section}-\stepcounter{section}-\stepcounter{paragraph}-\stepcounter{paragraph}-\stepcounter{chapter}-\stepcounter{chapter}-\addtocounter{enumi}{-1}-\stepcounter{section}--\end{document}
− doc/manual/patch-theory.tex
@@ -1,79 +0,0 @@-%% This file was automatically generated by preproc.-% Copyright (C) 2007 David Roundy-%-% This program is free software; you can redistribute it and/or modify-% it under the terms of the GNU General Public License as published by-% the Free Software Foundation; either version 2, or (at your option)-% any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; see the file COPYING. If not, write to-% the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,-% Boston, MA 02110-1301, USA.--\documentclass{article}-%\usepackage{color}--\usepackage{verbatim}-\usepackage{hyperref}-\usepackage{fancyvrb}-\newenvironment{code}{\comment}{\endcomment}-% \newenvironment{code}{\color{blue}\verbatim}{\endverbatim}--\newcommand{\commutes}{\longleftrightarrow}--\begin{document}---\section{Patch properties}--Darcs is built on a hierarchy of patch types. At the lowest level are-``primitive'' patches, and from these building blocks, a whole hierarchy of-patch types are built. Each of these patch types must support a number of-functions, which must obey a number of laws.--\subsection{Properties of identity}--\newtheorem{prp}{Property}--\begin{prp}[Identity commutes trivially]- The identity patch must commute with any patch without modifying said patch.-\end{prp}---\begin{prp}[Inverse doesn't commute]- A patch and its inverse will always commute, unless that patch is an- identity patch (or an identity-like patch that has no effect).-\end{prp}---\subsection{Commute properties}--\begin{prp}[Recommute]- $AB \commutes B'A'$ if and only if $B'A' \commutes AB$-\end{prp}---\begin{prp}[Commute inverses]- $AB \commutes B'A'$ if and only if $B^{-1}A^{-1} \commutes A'^{-1}B'^{-1}$-\end{prp}---\begin{prp}[Patch and inverse]- If $AB \commutes B'A'$ then $A^{-1}B' \commutes BA'^{-1}$-\end{prp}--This property is only true of primitive patches.---\begin{prp}[Permutivity]- (to be added...)-\end{prp}---\end{document}
release/distributed-context view
@@ -1,1 +1,1 @@-Just "\nContext:\n\n[TAG 2.4\nReinier Lamers <tux_rocker@reinier.de>**20100226180900\n Ignore-this: 36ce0456c214345f55a7bc5fc142e985\n] \n"+Just "\nContext:\n\n[TAG 2.4.1\nReinier Lamers <tux_rocker@reinier.de>**20100412161826\n Ignore-this: 17bcd98358f6da527cd14ab1a725f0b7\n] \n"
src/Darcs/Commands.lhs view
@@ -167,14 +167,16 @@ getSubcommands c@(SuperCommand {}) = commandSubCommands c getSubcommands _ = [] -commandAlias :: String -> DarcsCommand -> DarcsCommand-commandAlias n c =+commandAlias :: String -> Maybe DarcsCommand -> DarcsCommand -> DarcsCommand+commandAlias n msuper c = c { commandName = n- , commandDescription = "Alias for `darcs " ++ commandName c ++ "'."+ , commandDescription = "Alias for `darcs " ++ cmdName ++ "'." , commandHelp = "The `darcs " ++ n ++ "' command is an alias for " ++- "`darcs " ++ commandName c ++ "'.\n" +++ "`darcs " ++ cmdName ++ "'.\n" ++ commandHelp c }+ where+ cmdName = unwords . map commandName . maybe id (:) msuper $ [ c ] commandStub :: String -> String -> String -> DarcsCommand -> DarcsCommand commandStub n h d c =
src/Darcs/Commands/Changes.lhs view
@@ -293,5 +293,5 @@ headRL NilRL = impossible log :: DarcsCommand-log = commandAlias "log" changes+log = commandAlias "log" Nothing changes \end{code}
src/Darcs/Commands/GZCRCs.lhs view
@@ -38,6 +38,7 @@ import System.Directory ( getDirectoryContents, doesFileExist, doesDirectoryExist ) import System.Exit ( ExitCode(..), exitWith )+import System.IO ( hPutStr, hPutStrLn, stderr ) import Data.IORef ( newIORef, readIORef, writeIORef ) import Darcs.Commands ( DarcsCommand(..), nodefaults )@@ -110,12 +111,12 @@ files <- getCRCWarnings resetCRCWarnings when (not . null $ files) $ do- putStr . formatText $+ hPutStr stderr . formatText $ ["", "Warning: CRC errors found. These are probably harmless but should " ++ "be repaired. See 'darcs gzcrcs --help' for more information.", ""]- when verbose $ putStrLn $ unlines ("The following corrupt files were found:":files)+ when verbose $ hPutStrLn stderr $ unlines ("The following corrupt files were found:":files) gzcrcs :: DarcsCommand gzcrcs = DarcsCommand {commandName = "gzcrcs",
src/Darcs/Commands/Get.lhs view
@@ -132,7 +132,7 @@ getInventoryChoices]} clone :: DarcsCommand-clone = commandAlias "clone" get+clone = commandAlias "clone" Nothing get getCmd :: [DarcsFlag] -> [String] -> IO () getCmd opts [inrepodir, outname] = getCmd (NewRepo outname:opts) [inrepodir]
src/Darcs/Commands/MarkConflicts.lhs view
@@ -101,5 +101,5 @@ -- |resolve is an alias for mark-conflicts. resolve :: DarcsCommand-resolve = commandAlias "resolve" markconflicts+resolve = commandAlias "resolve" Nothing markconflicts \end{code}
src/Darcs/Commands/Move.lhs view
@@ -178,7 +178,7 @@ | otherwise = return () mv :: DarcsCommand-mv = commandAlias "mv" move+mv = commandAlias "mv" Nothing move \end{code}
src/Darcs/Commands/Remove.lhs view
@@ -23,6 +23,7 @@ module Darcs.Commands.Remove ( remove, rm, unadd ) where import Control.Monad ( when )+import Data.Maybe ( isJust ) import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias, commandStub, putWarning@@ -47,7 +48,6 @@ import Darcs.Commands.Add( expandDirs ) import Printer ( text )-import Debug.Trace #include "gadts.h" @@ -101,28 +101,38 @@ where mrp ftf recorded unrecorded (f:fs) = do let recorded' = modifyTree recorded f Nothing unrecorded' = modifyTree unrecorded f Nothing- Sealed rest <- mrp ftf recorded' unrecorded' fs- let f_fp = anchorPath "" f+ f_fp = anchorPath "" f skipAndWarn reason = do putWarning opts . text $ "Can't remove " ++ f_fp ++ " (" ++ reason ++ ")"- return $ Sealed rest+ return $ Nothing - case (find recorded f, find unrecorded f) of+ local <- case (find recorded f, find unrecorded f) of (Just (SubTree _), Just (SubTree unrecordedChildren)) -> do if not $ null (list unrecordedChildren) then skipAndWarn "it is not empty"- else return . Sealed $ rmdir f_fp :>: rest+ else return $ Just (rmdir f_fp :>: NilFL) (Just (File _), Just (File _)) ->- do diff <- treeDiff ftf unrecorded unrecorded'- return . Sealed $ diff +>+ rest+ Just `fmap` treeDiff ftf unrecorded unrecorded' (Just (File _), _) ->- return . Sealed $ addfile f_fp :>: rmfile f_fp :>: rest+ return $ Just (addfile f_fp :>: rmfile f_fp :>: NilFL) (Just (SubTree _), _) ->- return . Sealed $ adddir f_fp :>: rmdir f_fp :>: rest+ return $ Just (adddir f_fp :>: rmdir f_fp :>: NilFL) (_, _) -> skipAndWarn "it is not tracked by darcs" + -- we can tell if the remove succeeded by looking if local is+ -- empty. If the remove succeeded, we should pass on updated+ -- recorded and unrecorded that reflect the removal+ let nextRecorded | isJust local = recorded'+ | otherwise = recorded+ nextUnrecorded | isJust local = unrecorded'+ | otherwise = unrecorded + Sealed rest <- mrp ftf nextRecorded nextUnrecorded fs+ return . Sealed $ case local of+ Just localFL -> (localFL +>+ rest)+ Nothing -> rest+ mrp _ _ _ [] = return (Sealed NilFL) rmDescription :: String@@ -140,7 +150,7 @@ rm = commandStub "rm" rmHelp rmDescription remove unadd :: DarcsCommand-unadd = commandAlias "unadd" remove+unadd = commandAlias "unadd" Nothing remove \end{code}
src/Darcs/Commands/Show.lhs view
@@ -25,10 +25,10 @@ import Darcs.Commands.ShowAuthors ( showAuthors ) import Darcs.Commands.ShowBug ( showBug ) import Darcs.Commands.ShowContents ( showContents )-import Darcs.Commands.ShowFiles ( showFiles, showManifest )+import Darcs.Commands.ShowFiles ( showFiles, manifestCmd, toListManifest ) import Darcs.Commands.ShowTags ( showTags ) import Darcs.Commands.ShowRepo ( showRepo )-import Darcs.Commands.ShowIndex ( showIndex, showPristine )+import Darcs.Commands.ShowIndex ( showIndex, showPristineCmd ) import Darcs.Repository ( amInRepository ) showDescription :: String@@ -58,10 +58,27 @@ } query :: DarcsCommand-query = commandAlias "query" showCommand+query = commandAlias "query" Nothing showCommand list :: DarcsCommand-list = commandAlias "list" showCommand+list = commandAlias "list" Nothing showCommand++-- unfortunately, aliases for sub-commands have to live in their parent command+-- to avoid an import cycle+showPristine :: DarcsCommand+showPristine = (commandAlias "pristine" (Just showCommand) showIndex) {+ commandCommand = showPristineCmd,+ commandDescription = "Dump contents of pristine cache.",+ commandHelp =+ "The `darcs show pristine' command lists all version-controlled files " +++ "and directories along with the hashes of their pristine copies. " +++ "For files, the fields correspond to file size, sha256 of the pristine " +++ "file content and the filename." }++showManifest :: DarcsCommand+showManifest = (commandAlias "manifest" (Just showCommand) showFiles) {+ commandCommand = manifestCmd toListManifest+} \end{code} \subsection{darcs show}
src/Darcs/Commands/ShowFiles.lhs view
@@ -20,10 +20,12 @@ {-# OPTIONS_GHC -cpp #-} {-# LANGUAGE CPP #-} #include "gadts.h"-module Darcs.Commands.ShowFiles ( showFiles, showManifest ) where+module Darcs.Commands.ShowFiles ( showFiles+ , manifestCmd, toListManifest -- for alias+ ) where import Darcs.Arguments ( DarcsFlag(..), workingRepoDir, files, directories, pending, nullFlag, matchOne )-import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias )+import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Repository ( Repository, amInRepository, slurp_pending, slurp_recorded, withRepository ) import Darcs.Patch ( RepoPatch )@@ -75,11 +77,6 @@ commandAdvancedOptions = [], commandBasicOptions = [files, directories, pending, nullFlag, matchOne, workingRepoDir] }--showManifest :: DarcsCommand-showManifest = commandAlias "manifest" showFiles {- commandCommand = manifestCmd toListManifest-} toListFiles, toListManifest :: [DarcsFlag] -> Slurpy -> [FilePath] toListFiles opts = filesDirs (NoFiles `notElem` opts) (NoDirectories `notElem` opts)
src/Darcs/Commands/ShowIndex.lhs view
@@ -25,10 +25,12 @@ {-# OPTIONS_GHC -cpp #-} {-# LANGUAGE CPP #-} #include "gadts.h"-module Darcs.Commands.ShowIndex ( showIndex, showPristine ) where+module Darcs.Commands.ShowIndex ( showIndex+ , showPristineCmd -- for alias+ ) where import Darcs.Arguments ( DarcsFlag(..), workingRepoDir, files, directories, nullFlag )-import Darcs.Commands ( DarcsCommand(..), nodefaults, commandAlias )+import Darcs.Commands ( DarcsCommand(..), nodefaults ) import Darcs.Repository ( amInRepository, withRepository, ($-), readIndex ) import Darcs.Repository.State ( readRecorded ) @@ -57,16 +59,6 @@ commandArgdefaults = nodefaults, commandAdvancedOptions = [], commandBasicOptions = [files, directories, nullFlag, workingRepoDir] }--showPristine :: DarcsCommand-showPristine = commandAlias "pristine" showIndex {- commandCommand = showPristineCmd,- commandDescription = "Dump contents of pristine cache.",- commandHelp =- "The `darcs show pristine' command lists all version-controlled files " ++- "and directories along with the hashes of their pristine copies. " ++- "For files, the fields correspond to file size, sha256 of the pristine " ++- "file content and the filename." } dump :: [DarcsFlag] -> Tree IO -> IO () dump opts tree = do
src/Darcs/Commands/Unrecord.lhs view
@@ -189,7 +189,7 @@ "will lose precious code by unpulling!\n" unpull :: DarcsCommand-unpull = (commandAlias "unpull" obliterate)+unpull = (commandAlias "unpull" Nothing obliterate) {commandHelp = unpullHelp, commandDescription = unpullDescription, commandCommand = unpullCmd}
+ src/Darcs/Test/Email.hs view
@@ -0,0 +1,86 @@+-- Copyright (C) 2002-2005,2007 David Roundy+-- Copyright (C) 2009 Reinier Lamers+--+-- This program is free software; you can redistribute it and/or modify+-- it under the terms of the GNU General Public License as published by+-- the Free Software Foundation; either version 2, or (at your option)+-- any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; see the file COPYING. If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++-- | This module contains unit tests of the code in 'Darcs.Email'+--+-- These tests check whether the emails generated by darcs meet a few criteria.+-- We check for line length and non-ASCII characters. We apparently do not have+-- to check for CR-LF newlines because that's handled by sendmail.+module Darcs.Test.Email ( email_parsing, email_header_no_long_lines,+ email_header_ascii_chars, email_header_lines_start,+ email_header_no_empty_lines+ ) where+import Data.Char ( isPrint )+import qualified Data.ByteString as B ( length, unpack, null, head, filter,+ cons, empty, foldr, ByteString )+import qualified Data.ByteString.Char8 as BC ( unpack )+import Test.Framework ( Test )+import Test.Framework.Providers.QuickCheck2 ( testProperty )+import Printer ( text, renderPS )+import Darcs.Email ( make_email, read_email, formatHeader )++-- | Checks that darcs can read the emails it generates+email_parsing :: Test+email_parsing = testProperty "Checking that email can be parsed" $ \s ->+ unlines ("":s++["", ""]) ==+ BC.unpack (read_email (renderPS+ $ make_email "reponame" [] (Just (text "contents\n"))+ (text $ unlines s) (Just "filename")))++-- | Check that formatHeader never creates lines longer than 78 characters+-- (excluding the carriage return and line feed)+email_header_no_long_lines :: Test+email_header_no_long_lines =+ testProperty "Checking email header line length" $ \field value ->+ let cleanField = clean_field_string field+ in not $ any (>78) $ map B.length $ bs_lines $ formatHeader cleanField value++-- Check that an email header does not contain non-ASCII characters+-- formatHeader doesn't escape field names, there is no such thing as non-ascii+-- field names afaik+email_header_ascii_chars :: Test+email_header_ascii_chars =+ testProperty "Checking email for illegal characters" $ \field value ->+ let cleanField = clean_field_string field+ in not (any (>127) (B.unpack (formatHeader cleanField value)))++-- Check that header the second and later lines of a header start with a space+email_header_lines_start :: Test+email_header_lines_start =+ testProperty "Checking for spaces at start of folded email header lines" $ \field value ->+ let headerLines = bs_lines (formatHeader cleanField value)+ cleanField = clean_field_string field+ in all (\l -> B.null l || B.head l == 32) (tail headerLines)++-- Checks that there are no lines in email headers with only whitespace+email_header_no_empty_lines :: Test+email_header_no_empty_lines =+ testProperty "Checking that there are no empty lines in email headers" $ \field value ->+ let headerLines = bs_lines (formatHeader cleanField value)+ cleanField = clean_field_string field+ in all (not . B.null . B.filter (not . (`elem` [10, 32, 9]))) headerLines++bs_lines :: B.ByteString -> [B.ByteString]+bs_lines = finalizeFold . B.foldr splitAtLines (B.empty, [])+ where splitAtLines 10 (thisLine, prevLines) = (B.empty, thisLine:prevLines)+ splitAtLines c (thisLine, prevLines) = (B.cons c thisLine, prevLines)+ finalizeFold (lastLine, otherLines) = lastLine : otherLines++clean_field_string :: String -> String+clean_field_string = filter (\c -> isPrint c && c < '\x80' && c /= ':')+
+ src/Darcs/Test/Patch/QuickCheck.hs view
@@ -0,0 +1,782 @@+{-# OPTIONS_GHC -fno-warn-deprecations -fno-warn-orphans -fglasgow-exts #-}+{-# LANGUAGE CPP, UndecidableInstances, ScopedTypeVariables #-}++#include "gadts.h"+module Darcs.Test.Patch.QuickCheck ( WithStartState, RepoModel, Tree,+#ifndef GADT_WITNESSES+ merge_examples, commute_examples, triple_examples,+#endif+ prop_consistent_tree_flattenings, prop_fail,+ prop_is_mergeable,+ flattenOne, testConditional,+ commutePairFromTree, mergePairFromTree,+ commuteTripleFromTree,+ commutePairFromTWFP, mergePairFromTWFP, getPairs, getTriples,+ patchFromTree,+ quickCheck, real_patch_loop_examples, shrink+ ) where++import Control.Arrow ( (***) )+import Control.Monad ( liftM, replicateM, mplus, mzero )+import qualified Data.ByteString.Char8 as BC (pack)+import qualified Data.ByteString as B (ByteString)+import Test.QuickCheck+import Test.Framework ( Test )+import Test.Framework.Providers.QuickCheck2 ( testProperty )+import Darcs.Witnesses.Sealed+import Darcs.Patch ( Patch )+import Darcs.Witnesses.Ordered+import Darcs.Patch.Patchy (--showPatch,+ Invert(..), Commute(..))+import Darcs.Patch.Prim (Prim(..), Effect(..), FilePatchType(..), FromPrim(..), is_identity )+import Darcs.Patch.Real ( RealPatch, prim2real )+--import Darcs.ColorPrinter ( errorDoc )+--import Darcs.ColorPrinter ( traceDoc )+import Darcs.Witnesses.Show+--import Printer ( greenText, ($$) )+import Darcs.Patch.FileName ( FileName, fp2fn )++#include "impossible.h"+++#ifndef GADT_WITNESSES+instance Eq (a C(x y)) => Eq (Sealed2 a) where+ (Sealed2 x) == (Sealed2 y) = x == y+#endif++instance Show2 Patch where+ show2 = show++#ifndef GADT_WITNESSES+triple_examples :: (FromPrim p, Commute p, Invert p) => [p :> p :> p]+triple_examples = [commuteTripleFromTree id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "g"]))+ (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "j"]))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "s"])) NilTree)))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "e"])) NilTree))+ ,commuteTripleFromTree id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file",+ rmFileContents = [BC.pack "j"] })+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "s"]))+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "j"] [])) NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "j"] [])) NilTree)))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "j"] [])) NilTree))+ ]+++merge_examples :: (FromPrim p, Commute p, Invert p) => [p :\/: p]+merge_examples = map (mergePairFromCommutePair id) commute_examples++commute_examples :: (FromPrim p, Commute p) => [p :> p]+commute_examples = [+ commutePairFromTWFP id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+ (TWFP 3+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "h"])) NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "b"]))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "f"]))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "v"]))+ (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "f"] [])) NilTree)))))),+ commutePairFromTWFP id $+ WithStartState+ (RepoModel { rmFileName = fp2fn "./file",+ rmFileContents = [BC.pack "f",BC.pack "s",BC.pack "d"] })+ (TWFP 3+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 2 [BC.pack "d"] [])) NilTree)+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "f"] [])) NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "f"] []))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "s",BC.pack "d"] []))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "v"])) NilTree)))))),+{- commutePairFromTWFP id $+ WithStartState+ (RepoModel { rmFileName = fp2fn "./file",+ rmFileContents = [BC.pack "f",BC.pack "u",+ BC.pack "s",BC.pack "d"] })+ (TWFP 5+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 4 [] [BC.pack "x"]))+ (SeqTree (FP (fp2fn "./file") (Hunk 3 [BC.pack "d"] [])) NilTree))+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "f",BC.pack "u"] [])) NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "f"] []))+ (SeqTree (FP(fp2fn "./file") (Hunk 0 [BC.pack "u",BC.pack "s",BC.pack "d"] []))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "a"]))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "a"] [])) NilTree))))))),-}+ commutePairFromTree id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file",+ rmFileContents = [BC.pack "n",BC.pack "t",BC.pack "h"] })+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "n",BC.pack "t",BC.pack "h"] []))+ NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 2 [BC.pack "h"] []))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "n"] []))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "t"] [])) NilTree)))),+ commutePairFromTree id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "n"])) NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "i"]))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "i"])) NilTree))),+ commutePairFromTree id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "c"]))+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "c"] [BC.pack "r"])) NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "h"]))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "d"])) NilTree))))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "f"])) NilTree)),+ commutePairFromTWFP id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+ (TWFP 1+ (ParTree+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "t"])) NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "t"])) NilTree))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "f"])) NilTree))),+ commutePairFromTWFP id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file",+ rmFileContents = [BC.pack "f",BC.pack " r",+ BC.pack "c",BC.pack "v"] })+ (TWFP 4+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 2 [BC.pack "c",BC.pack "v"] []))+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "r"] []))+ (SeqTree (FP (fp2fn "fi le") (Hunk 0 [BC.pack "f"] [])) NilTree))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "f",BC.pack "r"] []))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "y"])) NilTree))))+ (SeqTree (FP (fp2fn "./file") (Hunk 3 [BC.pack "v"] [])) NilTree))),+ commutePairFromTree id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "z"])) NilTree)+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "f"])) NilTree)+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "r"])) NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "d"])) NilTree))))+ , commutePairFromTree id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file",+ rmFileContents = [BC.pack "t",BC.pack "r",+ BC.pack "h"] })+ (ParTree+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "t",BC.pack "r",BC.pack "h"] []))+ NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "o"])) NilTree))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "t"] []))+ (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "h"] [])) NilTree)))+ , commutePairFromTWFP id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] }) $+ TWFP 2+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "h"])) NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "y"]))+ (SeqTree (FP (fp2fn "./file") (Hunk 1 [] [BC.pack "m"]))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "v"])) NilTree))))+ , commutePairFromTree id $+ WithStartState (RepoModel {rmFileName = fp2fn "./file",rmFileContents = [] })+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "p"]))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "p"] []))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "c"])) NilTree)))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "z"])) NilTree))+ , commutePairFromTree id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "j" ]))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "j"] [])) NilTree))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "v"])) NilTree))+ , commutePairFromTree id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "v"])) NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "j" ]))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [BC.pack "j"] [])) NilTree)))+ , commutePairFromTree id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file",+ rmFileContents = [BC.pack "x",BC.pack "c"] })+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "h"]))+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 2 [BC.pack "c"] [])) NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 1 [BC.pack "x"] []))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "j"])) NilTree))))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] [BC.pack "l"])) NilTree))+ , commutePairFromTree id $+ WithStartState (RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] })+ (ParTree+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] (packStringLetters "s"))) NilTree)+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] (packStringLetters "k")))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 (packStringLetters "k") []))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 [] (packStringLetters "m")))+ (SeqTree (FP (fp2fn "./file") (Hunk 0 (packStringLetters "m") [])) NilTree)))))+ ]+#endif++-- | Turns a condition and a test function into a conditional quickcheck+-- property that can be run by test-framework.+testConditional :: (Arbitrary p, Show p, Show q) => String -- ^ Test name+ -> (p -> Bool) -- ^ Condition+ -> (p -> Maybe q) -- ^ Test function+ -> Test+testConditional name nottrivial t = testProperty name t'+ where t' p = nottrivial p ==> case t p of+ Nothing -> True+ Just q -> error $ show q++data RepoModel C(x)+ = RepoModel {+ rmFileName :: !FileName,+ rmFileContents :: [B.ByteString]+ } deriving (Eq)++instance Show (RepoModel C(x)) where+ showsPrec d rm = showParen (d > app_prec) $+ showString "RepoModel { rmFileName = " . showsPrec 0 (rmFileName rm) .+ showString ", rmFileContents = " . showsPrec 0 (rmFileContents rm) .+ showString " }"++instance Show1 RepoModel where+ showsPrec1 = showsPrec++#ifdef GADT_WITNESSES+-- | The initial repository state, to be used as an argument to the @RepoModel@+-- data type.+data InitRepoModel -- this ought to be defined somewhere central as the unique starting state+#endif++-- | The initial repository model. The repository contains a single file named+-- @./file@, which is empty.+initRepoModel :: RepoModel C(InitRepoModel)+initRepoModel = RepoModel { rmFileName = fp2fn "./file", rmFileContents = [] }+rebuildRepoModel :: RepoModel C(x) -> RepoModel C(y)+rebuildRepoModel rm = RepoModel { rmFileName = rmFileName rm, rmFileContents = rmFileContents rm }++-- | A combination of a patch and its final state. The state, in this module, is+-- typically represented by a 'RepoModel' value. The @px@ type is typically a+-- patch type applied to its pre-state, e.g. @Prim x@.+data WithEndState px s C(y) = WithEndState { wesPatch :: px C(y), _wesState :: s C(y) }++-- | A type class to generate arbitrary values, threading a state through the+-- arbitrary calls. So this can be used to generate a patch that comes after+-- another patch. The post-state of the generated patch is hidden by the+-- 'Sealed'.+class ArbitraryState s p where+ arbitraryState :: s C(x) -> Gen (Sealed (WithEndState (p C(x)) s))+ -- does a coarbitrary make sense?++-- | Generate a patch to a certain state.+class ArbitraryStateIn s p where+ arbitraryStateIn :: s C(x) -> Gen (p C(x))++instance ArbitraryState RepoModel Prim where+ arbitraryState rm = oneof [arbitraryFP rm]++instance Arbitrary (Sealed2 (FL Prim)) where+ arbitrary = do Sealed2 ps1 <- liftM (unseal (seal2 . wesPatch)) $ arbitraryState initRepoModel+ return $ Sealed2 $ mapFL_FL make_identity_identity ps1+ where make_identity_identity :: Prim C(x y) -> Prim C(x y)+ make_identity_identity p | IsEq <- is_identity p = identity+ | otherwise = p++instance Arbitrary (Sealed2 (FL (WithState RepoModel Prim))) where+ arbitrary = liftM (unseal (seal2 . wesPatch)) $ arbitraryState initRepoModel++prop_consistent_tree_flattenings :: Sealed (WithStartState RepoModel (Tree Prim)) -> Bool+prop_consistent_tree_flattenings (Sealed (WithStartState start t))+ = fromJust $+ do Sealed (G2 flat) <- return $ flattenTree $ mapTree prim2real t+ rms <- return $ map (applyPatch start) flat+ return $ and $ zipWith assert_equal_fst (zip rms flat) (tail $ zip rms flat)++assert_equal_fst :: (Eq a, Show a, Show b, Show c) => (a, b) -> (a, c) -> Bool+assert_equal_fst (x,bx) (y,by)+ | x == y = True+ | otherwise = error ("Not really equal:\n" ++ show x ++ "\nand\n" ++ show y+ ++ "\ncoming from\n" ++ show bx ++ "\nand\n" ++ show by)++-- WithState and prop_fail are handy for debugging arbitrary code+data WithState s p C(x y) = WithState (s C(x)) (p C(x y)) (s C(y))+ deriving Show++data WithStartState s p C(x) = WithStartState (s C(x)) (p C(x))++instance (Show1 s, Show1 p) => Show (WithStartState s p C(x)) where+ showsPrec d (WithStartState s p) = showParen (d > app_prec) $ showString "WithStartState " .+ showsPrec1 (app_prec + 1) s . showString " " .+ showsPrec1 (app_prec + 1) p++instance (Show1 s, Show1 p) => Show1 (WithStartState s p) where+ showsPrec1 = showsPrec++prop_fail :: Int -> Tree Prim C(x) -> Bool+prop_fail n xs = sizeTree xs < n++instance ArbitraryState s p => ArbitraryState s (WithState s p) where+ arbitraryState rm = do xandrm' <- arbitraryState rm+ flip unseal xandrm' $ \(WithEndState x rm') ->+ return $ seal $ WithEndState (WithState rm x rm') rm'++instance ArbitraryState s p => ArbitraryState s (FL p) where+ arbitraryState rm1 = sized $ \n -> do k <- choose (0, n)+ arbitraryList k rm1+ where arbitraryList :: FORALL(x) Int -> s C(x) -> Gen (Sealed (WithEndState (FL p C(x)) s))+ arbitraryList 0 rm = return $ seal $ WithEndState NilFL rm+ arbitraryList (n+1) rm = do Sealed (WithEndState x rm') <- arbitraryState rm+ Sealed (WithEndState xs rm'') <- arbitraryList n rm'+ return $ seal $ WithEndState (x :>: xs) rm''+ arbitraryList _ _ = impossible++data Tree p C(x) where+ NilTree :: Tree p C(x)+ SeqTree :: p C(x y) -> Tree p C(y) -> Tree p C(x)+ ParTree :: Tree p C(x) -> Tree p C(x) -> Tree p C(x)++mapTree :: (FORALL(y z) p C(y z) -> q C(y z)) -> Tree p C(x) -> Tree q C(x)+mapTree _ NilTree = NilTree+mapTree f (SeqTree p t) = SeqTree (f p) (mapTree f t)+mapTree f (ParTree t1 t2) = ParTree (mapTree f t1) (mapTree f t2)++instance Show2 p => Show (Tree p C(x)) where+ showsPrec _ NilTree = showString "NilTree"+ showsPrec d (SeqTree a t) = showParen (d > app_prec) $ showString "SeqTree " .+ showsPrec2 (app_prec + 1) a . showString " " .+ showsPrec (app_prec + 1) t+ showsPrec d (ParTree t1 t2) = showParen (d > app_prec) $ showString "ParTree " .+ showsPrec (app_prec + 1) t1 . showString " " .+ showsPrec (app_prec + 1) t2++instance Show2 p => Show1 (Tree p) where+ showsPrec1 = showsPrec++sizeTree :: Tree p C(x) -> Int+sizeTree NilTree = 0+sizeTree (SeqTree _ t) = 1 + sizeTree t+sizeTree (ParTree t1 t2) = 1 + sizeTree t1 + sizeTree t2++-- newtype G1 l p C(x) = G1 { _unG1 :: l (p C(x)) }+newtype G2 l p C(x y) = G2 { unG2 :: l (p C(x y)) }++flattenTree :: (Commute p) => Tree p C(z) -> Sealed (G2 [] (FL p) C(z))+flattenTree NilTree = seal $ G2 $ return NilFL+flattenTree (SeqTree p t) = mapSeal (G2 . map (p :>:) . unG2) $ flattenTree t+flattenTree (ParTree t1 t2) = flip unseal (flattenTree t1) $ \gpss1 ->+ flip unseal (flattenTree t2) $ \gpss2 ->+ seal $ G2 $+ do ps1 <- unG2 gpss1+ ps2 <- unG2 gpss2+ ps2' :/\: ps1' <- return $ merge (ps1 :\/: ps2)+ -- We can't prove that the existential type in the result+ -- of merge will be the same for each pair of+ -- ps1 and ps2.+ map unsafeCoerceP [ps1 +>+ ps2', ps2 +>+ ps1']++instance ArbitraryState s p => ArbitraryStateIn s (Tree p) where+ -- don't generate trees deeper than 5 with default QuickCheck size+ arbitraryStateIn rm = sized $ \s -> arbitraryTree rm (s `div` 17)++-- | Generate a tree of patches, bounded by the size @maxSize@.+arbitraryTree :: ArbitraryState s p => s C(x) -> Int -> Gen (Tree p C(x))+arbitraryTree rm maxDepth+ | maxDepth == 0 = return NilTree+ | otherwise = frequency [(2, return NilTree)+ ,(2, do Sealed (WithEndState p rm') <- arbitraryState rm+ t <- arbitraryTree rm' maxDepth+ return (SeqTree p t))+ ,(1, do t1 <- arbitraryTree rm (maxDepth - 1)+ t2 <- arbitraryTree rm (maxDepth - 1)+ return (ParTree t1 t2))]+++shrinkWSSTree :: Sealed (WithStartState RepoModel (Tree Prim))+ -> [Sealed (WithStartState RepoModel (Tree Prim))]+shrinkWSSTree = unseal doShrinkWSSTree+ where+ doShrinkWSSTree wss@(WithStartState rm t)+ = shrinkWSSTree' wss -- shrink the tree+ `mplus`+ do -- shrink the starting context+ pos <- [0 .. length (rmFileContents rm) - 1]+ let rmFileContents' = take pos (rmFileContents rm) ++ drop (pos+1) (rmFileContents rm)+ t' = shrinkPosStart pos (canonizeTree t)+ return $ seal $ WithStartState (rm { rmFileContents = rmFileContents' }) (canonizeTree t')+++-- If we had a more general repo model, then Int would need to be more general too++class ShrinkablePos p where+ shrinkPos :: Int -> p C(x y) -> (p C(x y), Maybe Int)+ shrinkPatch :: p C(x y) -> [(p C(x y), Maybe Int)]+ nullPatch :: p C(x y) -> EqCheck C(x y)++class ShrinkablePosStart p where+ shrinkPosStart :: Int -> p C(x) -> p C(x)++instance ShrinkablePos p => ShrinkablePosStart (Tree p) where+ shrinkPosStart _ NilTree = NilTree+ shrinkPosStart pos (SeqTree p t)+ = let (p', mpos') = shrinkPos pos p+ in case mpos' of+ Nothing -> SeqTree p' t+ Just pos' -> SeqTree p' (shrinkPosStart pos' t)+ shrinkPosStart pos (ParTree t1 t2) = ParTree (shrinkPosStart pos t1) (shrinkPosStart pos t2)++smartFP :: FileName -> FilePatchType C(x y) -> Prim C(x y)+smartFP _ (Hunk _ [] []) | avoidEmptyHunks = unsafeCoerceP Identity+smartFP fn filepatch = FP fn filepatch++instance ShrinkablePos Prim where+ shrinkPos pos (FP fn fp) = (smartFP fn *** id) (shrinkPos pos fp)+ shrinkPos pos Identity = (Identity, Just pos)+ shrinkPos _ _ = impossible+ shrinkPatch (FP fn fp) = map (smartFP fn *** id) (shrinkPatch fp)+ shrinkPatch Identity = []+ shrinkPatch _ = impossible+ nullPatch (FP _ fp) = nullPatch fp+ nullPatch Identity = IsEq+ nullPatch _ = impossible++avoidEmptyHunks :: Bool+avoidEmptyHunks = True++instance ShrinkablePos FilePatchType where+ shrinkPos pos (Hunk n old new)+ | pos < n = (Hunk (n-1) old new, Just pos)+ | pos >= n + length old = (Hunk n old new, Just (pos + length new - length old))+ | otherwise = (Hunk n (take pos' old ++ drop (pos'+1) old) new, Nothing)+ where pos' = pos - n+ shrinkPos _ _ = bug "foo1 in ShrinkablePos"+ shrinkPatch (Hunk (n+1) [] []) = [(Hunk n [] [], Nothing)]+ shrinkPatch (Hunk n old new)+ = do i <- [0 .. length new - 1]+ return (Hunk n old (take i new ++ drop (i+1) new), Just (n + i))+ shrinkPatch _ = bug "foo in ShrinkablePos"+ nullPatch (Hunk _ [] []) = unsafeCoerceP IsEq -- is this safe?+ nullPatch _ = NotEq++shrinkWSSTree'+ -- start a new line here because apparently ' confuses CPP..+ :: WithStartState RepoModel (Tree Prim) C(x)+ -> [Sealed (WithStartState RepoModel (Tree Prim))]+shrinkWSSTree' (WithStartState _ NilTree) = []+shrinkWSSTree' (WithStartState rm t@(SeqTree p t'))+ = return (seal (WithStartState (applyPatch rm p) (canonizeTree t')))+ `mplus`+ liftM (seal . WithStartState rm) (map canonizeTree $ shrinkTree t)+shrinkWSSTree' (WithStartState rm t@(ParTree _ _))+ = liftM (seal . WithStartState rm) (map canonizeTree $ shrinkTree t)++-- canonize a tree, removing any dead branches+canonizeTree :: ShrinkablePos p => Tree p C(x) -> Tree p C(x)+canonizeTree NilTree = NilTree+canonizeTree (ParTree t1 t2)+ | NilTree <- canonizeTree t1 = canonizeTree t2+ | NilTree <- canonizeTree t2 = canonizeTree t1+ | otherwise = ParTree (canonizeTree t1) (canonizeTree t2)+canonizeTree (SeqTree p t) | IsEq <- nullPatch p = canonizeTree t+ | otherwise = SeqTree p (canonizeTree t)++-- shrink the tree without changing the starting context+shrinkTree :: ShrinkablePos p => Tree p C(x) -> [Tree p C(x)]+shrinkTree NilTree = []+shrinkTree (SeqTree p t) = do case nullPatch p of+ IsEq -> return t+ NotEq -> mzero+ `mplus`+ do (p', pos) <- shrinkPatch p+ return (SeqTree p' (maybe id shrinkPosStart pos t))+ `mplus`+ do t' <- shrinkTree t+ return (SeqTree p t')+shrinkTree (ParTree t1 t2) = [t1, t2]+ `mplus`+ do t1' <- shrinkTree t1+ return (ParTree t1' t2)+ `mplus`+ do t2' <- shrinkTree t2+ return (ParTree t1 t2')++instance Arbitrary (Sealed (WithStartState RepoModel (Tree Prim))) where+ arbitrary = do Sealed (WithStartState rm tree) <-+ liftM (seal . WithStartState initRepoModel) (arbitraryStateIn initRepoModel)+ return $ Sealed $ WithStartState rm (canonizeTree tree)+ shrink = shrinkWSSTree++prop_is_mergeable :: forall p C(x) . (FromPrim p, Commute p)+ => Sealed (WithStartState RepoModel (Tree Prim))+ -> Maybe (Tree p C(x))+prop_is_mergeable (Sealed (WithStartState _ t))+ = case flattenOne t of+ Sealed ps -> let _ = seal2 ps :: Sealed2 (FL p)+ in case lengthFL ps of+ _ -> Nothing++flattenOne :: (FromPrim p, Commute p) => Tree Prim C(x) -> Sealed (FL p C(x))+flattenOne NilTree = seal NilFL+flattenOne (SeqTree p t) = flip unseal (flattenOne t) $ \ps -> seal (fromPrim p :>: ps)+flattenOne (ParTree t1 t2) =+ flip unseal (flattenOne t1) $ \ps1 ->+ flip unseal (flattenOne t2) $ \ps2 ->+ --traceDoc (greenText "flattening two parallel series: ps1" $$ showPatch ps1 $$+ -- greenText "ps2" $$ showPatch ps2) $+ case merge (ps1 :\/: ps2) of+ ps2' :/\: _ -> seal (ps1 +>+ ps2')++instance Arbitrary (Sealed2 (FL RealPatch)) where+ arbitrary = do Sealed (WithStartState _ tree) <- arbitrary :: Gen (Sealed (WithStartState RepoModel (Tree Prim)))+ return $ unseal seal2 (flattenOne tree)++instance Arbitrary (Sealed2 RealPatch) where+ arbitrary = do Sealed (WithStartState _ tree) <- arbitrary :: Gen (Sealed (WithStartState RepoModel (Tree Prim)))+ case mapFL seal2 `unseal` flattenOne tree of+ [] -> return $ seal2 $ fromPrim Identity+ ps -> elements ps++instance (Arbitrary (Sealed2 (FL p)), Commute p) => Arbitrary (Sealed2 (p :\/: p)) where+ arbitrary = do Sealed2 (a :> b) <- arbitrary+ case commute (a :> b) of+ Just (b' :> _) -> return (seal2 (a :\/: b'))+ Nothing -> arbitrary++instance Arbitrary (Sealed2 (FL p)) => Arbitrary (Sealed2 (p :> p)) where+ arbitrary = do Sealed2 ps <- arbitrary+ let pairs = getPairs ps+ case pairs of+ [] -> arbitrary+ _ -> elements pairs++instance (Invert p, Arbitrary (Sealed2 (FL p))) => Arbitrary (Sealed2 (p :> p :> p)) where+ arbitrary = do Sealed2 ps <- arbitrary+ return $ last_triple ps+ where last_triple :: FL p C(x y) -> Sealed2 (p :> p :> p)+ last_triple NilFL = seal2 $ identity :> identity :> identity+ last_triple (a :>: NilFL) = seal2 $ a :> invert a :> identity+ last_triple (a :>: b :>: NilFL) = seal2 $ invert a :> a :> b+ last_triple (a :>: b :>: c :>: NilFL) = seal2 $ a :> b :> c+ last_triple (_ :>: xs) = last_triple xs++data TreeWithFlattenPos p C(x) = TWFP Int (Tree p C(x))++commutePairFromTWFP :: (FromPrim p, Commute p)+ => (FORALL (y z) (p :> p) C(y z) -> t)+ -> (WithStartState RepoModel (TreeWithFlattenPos Prim) C(x) -> t)+commutePairFromTWFP handlePair (WithStartState _ (TWFP n t))+ = unseal2 handlePair $+ let xs = unseal getPairs (flattenOne t)+ in if length xs > n && n >= 0 then xs!!n else seal2 (fromPrim Identity :> fromPrim Identity)++commutePairFromTree :: (FromPrim p, Commute p)+ => (FORALL (y z) (p :> p) C(y z) -> t)+ -> (WithStartState RepoModel (Tree Prim) C(x) -> t)+commutePairFromTree handlePair (WithStartState _ t)+ = unseal2 handlePair $+ case flattenOne t of+ Sealed ps ->+ let xs = --traceDoc (greenText "I'm flattening one to get:" $$ showPatch ps) $+ getPairs ps+ in if null xs then seal2 (fromPrim Identity :> fromPrim Identity) else last xs++commuteTripleFromTree :: (FromPrim p, Commute p)+ => (FORALL (y z) (p :> p :> p) C(y z) -> t)+ -> (WithStartState RepoModel (Tree Prim) C(x) -> t)+commuteTripleFromTree handle (WithStartState _ t)+ = unseal2 handle $+ case flattenOne t of+ Sealed ps ->+ let xs = --traceDoc (greenText "I'm flattening one to get:" $$ showPatch ps) $+ getTriples ps+ in if null xs+ then seal2 (fromPrim Identity :> fromPrim Identity :> fromPrim Identity)+ else last xs++mergePairFromCommutePair :: (Commute p, Invert p)+ => (FORALL (y z) (p :\/: p) C(y z) -> t)+ -> (FORALL (y z) (p :> p) C(y z) -> t)+mergePairFromCommutePair handlePair (a :> b)+ = case commute (a :> b) of+ Just (b' :> _) -> handlePair (a :\/: b')+ Nothing -> handlePair (b :\/: b)++-- impredicativity problems mean we can't use (.) in the definitions below++mergePairFromTWFP :: (FromPrim p, Commute p, Invert p)+ => (FORALL (y z) (p :\/: p) C(y z) -> t)+ -> (WithStartState RepoModel (TreeWithFlattenPos Prim) C(x) -> t)+mergePairFromTWFP x = commutePairFromTWFP (mergePairFromCommutePair x)++mergePairFromTree :: (FromPrim p, Commute p, Invert p)+ => (FORALL (y z) (p :\/: p) C(y z) -> t)+ -> (WithStartState RepoModel (Tree Prim) C(x) -> t)+mergePairFromTree x = commutePairFromTree (mergePairFromCommutePair x)++patchFromCommutePair :: (Commute p, Invert p)+ => (FORALL (y z) p C(y z) -> t)+ -> (FORALL (y z) (p :> p) C(y z) -> t)+patchFromCommutePair handle (_ :> b) = handle b++patchFromTree :: (FromPrim p, Commute p, Invert p)+ => (FORALL (y z) p C(y z) -> t)+ -> (WithStartState RepoModel (Tree Prim) C(x) -> t)+patchFromTree x = commutePairFromTree (patchFromCommutePair x)+++instance Show2 p => Show (TreeWithFlattenPos p C(x)) where+ showsPrec d (TWFP n t) = showParen (d > app_prec) $ showString "TWFP " .+ showsPrec (app_prec + 1) n . showString " " .+ showsPrec1 (app_prec + 1) t++instance Show1 (TreeWithFlattenPos Prim) where+ show1 = show++instance Arbitrary (Sealed (WithStartState RepoModel (TreeWithFlattenPos Prim))) where+ arbitrary = do Sealed (WithStartState rm t) <- arbitrary+ let num = unseal (length . getPairs) (flattenOneRP t)+ if num == 0 then return $ Sealed $ WithStartState rm $ TWFP 0 NilTree+ else do n <- choose (0, num - 1)+ return $ Sealed $ WithStartState rm $ TWFP n t+ where -- just used to get the length. In principle this should be independent of the patch type.+ flattenOneRP :: Tree Prim C(x) -> Sealed (FL RealPatch C(x))+ flattenOneRP = flattenOne+ shrink (Sealed (WithStartState rm (TWFP n t))) =+ [Sealed (WithStartState rm' (TWFP n' t')) | Sealed (WithStartState rm' t') <- shrink (Sealed (WithStartState rm t)),+ n' <- [0..n]]+++getPairs :: FL p C(x y) -> [Sealed2 (p :> p)]+getPairs NilFL = []+getPairs (_:>:NilFL) = []+getPairs (a:>:b:>:c) = seal2 (a:>b) : getPairs (b:>:c)++getTriples :: FL p C(x y) -> [Sealed2 (p :> p :> p)]+getTriples NilFL = []+getTriples (_:>:NilFL) = []+getTriples (_:>:_:>:NilFL) = []+getTriples (a:>:b:>:c:>:d) = seal2 (a:>b:>c) : getTriples (b:>:c:>:d)++arbitraryFP :: RepoModel C(x) -> Gen (Sealed (WithEndState (Prim C(x)) RepoModel))+arbitraryFP rm+ = do (fp, newcontents) <- arbitraryFilePatchType (rmFileContents rm)+ return $ seal $ WithEndState (FP (rmFileName rm) fp) (rebuildRepoModel (rm { rmFileContents = newcontents }))++-- Really [B.ByteString] should be parametrised by x y, and the result tuple sealed on y+arbitraryFilePatchType :: [B.ByteString] -> Gen (FilePatchType C(x y), [B.ByteString])+arbitraryFilePatchType contents = oneof [arbitraryHunk contents]++arbitraryHunk :: [B.ByteString] -> Gen (FilePatchType C(x y), [B.ByteString])+arbitraryHunk contents+ = sized $ \n ->+ do start <- choose (0, min n (length contents))+ (removelen, _)+ <- frequency $ zip (if start == length contents then [1, 13, 0, 0] else [1, 3, 5, 3])+ [return (0, 0)+ ,do xa <- choose (0, n)+ return (0, xa)+ ,do xr <- choose (1, min n (length contents - start))+ return (xr, 0)+ ,do xr <- choose (1, min n (length contents - start))+ xa <- choose (0, n)+ return (xr, xa)+ ]+ addlen <- choose (0, n)+ additems <- replicateM addlen (do c <- choose ('a', 'z')+ return $ BC.pack [c])+ let newcontents = take start contents ++ additems ++ drop (start + removelen) contents+ return (Hunk start (take removelen $ drop start $ contents) additems, newcontents)++class Applyable p where+ applyPatch :: RepoModel C(x) -> p C(x y) -> RepoModel C(y)++instance Applyable p => Applyable (FL p) where+ applyPatch rm NilFL = rm+ applyPatch rm (p :>: ps) = applyPatch (applyPatch rm p) ps++instance Applyable RealPatch where+ applyPatch rm p = applyPatch rm (effect p)++instance Applyable Prim where+ applyPatch (rm@RepoModel { rmFileName = filename, rmFileContents = oldcontents }) (FP filename' fp)+ | filename == filename' = rebuildRepoModel (rm { rmFileContents = applyFilePatchType oldcontents fp })+ applyPatch rm Identity = rm+ applyPatch _ _ = bug "We haven't defined applyPatch on Prim for all patch types."++applyFilePatchType :: [B.ByteString] -> FilePatchType C(x y) -> [B.ByteString]+applyFilePatchType oldcontents (Hunk n old new)+ = if take (length old) (drop n oldcontents) == old+ then take n oldcontents ++ new ++ drop (n + length old) oldcontents+ else error "Bad patch context"+applyFilePatchType _ _ = bug "We haven't defined applyFilePatchType for all patch types."++packStringLetters :: String -> [B.ByteString]+packStringLetters = map (BC.pack . (:[]))++real_patch_loop_examples :: [Sealed (WithStartState RepoModel (Tree Prim))]+real_patch_loop_examples =+ [Sealed (WithStartState (RepoModel { rmFileName = fx, rmFileContents = [] })+ $ canonizeTree+ (ParTree+ (SeqTree (FP fx (Hunk 0 [] (packStringLetters "pkotufogbvdabnmbzajvolwviqebieonxvcvuvigkfgybmqhzuaaurjspd")))+ (ParTree+ (SeqTree (FP fx (Hunk 46 (packStringLetters "qhzu") (packStringLetters "zafybdcokyjskcgnvhkbzpysaafnjjhcstgrczplxsfwagmh")))+ (ParTree+ (ParTree+ NilTree+ (ParTree+ (ParTree+ (ParTree+ (SeqTree (FP fx (Hunk 14 (packStringLetters "mbzajvolwviqebieonxvcvuvigkfgyb") (packStringLetters "vujnxnhvybvpouyciaabszfmgssezlwwjgnethvrpnfrkubphzvdgymjjoacppqps")))+ (ParTree+ NilTree+ (ParTree+ (SeqTree (FP fx (Hunk 39 (packStringLetters "ssezlwwjgnethvrpnfrkubphzvdgymjjoacppqpsmzafybdcokyjskcgnvhkbz") (packStringLetters "wnesidpccwoiqiichxaaejdsyrhrusqljlcoro")))+ (ParTree+ (ParTree+ (SeqTree (FP fx (Hunk 11 (packStringLetters "abnvujnxnhvybvpouyciaabszfmgwnesidpccwoiqii") (packStringLetters "czfdhqkipdstfjycqaxwnbxrihrufdeyneqiiiafwzlmg"))) NilTree)+ NilTree)+ NilTree))+ (SeqTree (FP fx (Hunk 24 [] (packStringLetters "dihgmsotezucqdgxczvcivijootyvhlwymbiueufnvpwpeukmskqllalfe"))) NilTree))))+ (SeqTree (FP fx (Hunk 55 (packStringLetters "yjskcgnvhkbzpysaafnjjhcstgrczplxsfwagmhaaurjsp") (packStringLetters "xldhrutyhcyaqeezwujiguawfyawjjqlirxshjddvq"))) NilTree))+ (SeqTree (FP fx (Hunk 19 [] (packStringLetters "ooygwiyogqrqnytixqtmvdxx")))+ (SeqTree (FP fx (Hunk 25 (packStringLetters "yogqrqnytixqtmvdxxvolwviqebieonxvcvuvigkfgybmzafybdcokyjskcgnvhkbz") (packStringLetters "akhsmlbkdxnvfoikmiatfbpzdrsyykkpoxvvddeaspzxe")))+ (SeqTree (FP fx (Hunk 38 [] (packStringLetters "ji")))+ (ParTree+ NilTree+ (ParTree+ NilTree+ (ParTree+ (ParTree+ NilTree+ (SeqTree (FP fx (Hunk 25 (packStringLetters "akhsmlbkdxnvfjioikmiatfbpzdrsyykkpoxvvddeaspzxepysaafnjjhcstgrczplxs") (packStringLetters "onjbhddskcj")))+ (SeqTree (FP fx (Hunk 38 [] (packStringLetters "fyscunxxxjjtyqpfxeznhtwvlphmp"))) NilTree)))+ (ParTree+ NilTree+ (SeqTree (FP fx (Hunk 43 [] (packStringLetters "xcchzwmzoezxkmkhcmesplnjpqriypshgiqklgdnbmmkldnydiy")))+ (ParTree+ NilTree+ (SeqTree (FP fx (Hunk 63 (packStringLetters "plnjpqriypshgiqklgdnbmmkldnydiymiatfbpzdrsyykkpoxvvddeaspzxepysaafn") (packStringLetters "anjlzfdqbjqbcplvqvkhwjtkigp"))) NilTree)))))))))))+ (ParTree+ NilTree+ NilTree)))+ NilTree))+ NilTree))+ (ParTree+ NilTree+ (SeqTree (FP fx (Hunk 0 [] (packStringLetters "ti")))+ (SeqTree (FP fx (Hunk 0 (packStringLetters "t") (packStringLetters "ybcop")))+ (SeqTree (FP fx (Hunk 1 [] (packStringLetters "dvlhgwqlpaeweerqrhnjtfolczbqbzoccnvdsyqiefqitrqneralf")))+ (SeqTree (FP fx (Hunk 14 [] (packStringLetters "yairbjphwtnaerccdlfewujvjvmjakbc")))+ (SeqTree (FP fx (Hunk 50 [] (packStringLetters "xayvfuwaiiogginufnhsrmktpmlbvxiakjwllddkiyofyfw")))+ (ParTree+ NilTree+ NilTree)))))))))]++fx :: FileName+fx = fp2fn "./F"
+ src/Darcs/Test/Patch/Test.hs view
@@ -0,0 +1,682 @@+-- Copyright (C) 2002-2003,2007 David Roundy+--+-- This program is free software; you can redistribute it and/or modify+-- it under the terms of the GNU General Public License as published by+-- the Free Software Foundation; either version 2, or (at your option)+-- any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; see the file COPYING. If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++{-# OPTIONS_GHC -cpp -fno-warn-deprecations -fglasgow-exts -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}++#include "gadts.h"++module Darcs.Test.Patch.Test+ ( prop_read_show,+ prop_inverse_composition, prop_commute_twice,+ prop_inverse_valid, prop_other_inverse_valid,+ prop_commute_equivalency, prop_commute_either_order,+ prop_commute_either_way, prop_merge_is_commutable_and_correct,+ prop_merge_is_swapable, prop_merge_valid,+ prop_unravel_three_merge, prop_unravel_seq_merge,+ prop_unravel_order_independent,+ prop_simple_smart_merge_good_enough,+ prop_elegant_merge_good_enough,+ prop_patch_and_inverse_is_identity,+ quickmerge, check_patch, check_a_patch, verbose_check_a_patch,+ prop_resolve_conflicts_valid,+ test_patch, prop_commute_inverse,+ subcommutes_inverse, subcommutes_nontrivial_inverse,+ subcommutes_failure,+ join_patches+ ) where++import Prelude hiding ( pi )+import System.IO.Unsafe ( unsafePerformIO )+import Test.QuickCheck+import Control.Monad ( liftM, liftM2, liftM3, liftM4, replicateM )++import Darcs.Patch.Info ( PatchInfo, patchinfo )+import Darcs.Test.Patch.Check ( PatchCheck,+ check_move, remove_dir, create_dir,+ is_valid, insert_line, file_empty, file_exists,+ delete_line, modify_file, create_file, remove_file,+ do_check, do_verbose_check, FileContents(..)+ )+import Darcs.Patch.RegChars ( regChars )+import ByteStringUtils ( linesPS )+import qualified Data.ByteString as B ( ByteString, null, concat )+import qualified Data.ByteString.Char8 as BC ( break, pack )+import Darcs.Patch.FileName ( fn2fp )+import qualified Data.Map as M ( mapMaybe )++import Darcs.Patch.Patchy ( Commute )+import Darcs.Patch ( addfile, adddir, move, showPatch,+ hunk, tokreplace, joinPatches, binary,+ changepref, isMerger, invert, commute, merge,+ readPatch, resolveConflicts,+ effect, fromPrims,+ unravel, merger, elegantMerge )+import Darcs.Patch.Core ( Patch(..) )+import Darcs.Patch.Prim ( Prim(..), DirPatchType(..), FilePatchType(..),+ CommuteFunction, Perhaps(..),+ subcommutes )+import Printer ( renderPS )+import Darcs.Witnesses.Ordered+import Darcs.Witnesses.Sealed ( Sealed(Sealed), unsafeUnseal, unseal )++#include "impossible.h"++instance Eq Patch where+ x == y = IsEq == (x =\/= y)++instance Eq Prim where+ x == y = IsEq == (x =\/= y)++instance (Commute a, MyEq a) => Eq (FL a) where+ x == y = IsEq == (x =\/= y)++instance Arbitrary Patch where+ arbitrary = sized arbpatch+-- coarbitrary p = coarbitrary (show p)++instance Arbitrary Prim where+ arbitrary = onepatchgen+-- coarbitrary = impossible++hunkgen :: Gen Prim+hunkgen = do+ i <- frequency [(1,choose (0,5)),(1,choose (0,35)),+ (2,return 0),(3,return 1),(2,return 2),(1,return 3)]+ j <- frequency [(1,choose (0,5)),(1,choose (0,35)),+ (2,return 0),(3,return 1),(2,return 2),(1,return 3)]+ if i == 0 && j == 0 then hunkgen+ else liftM4 hunk filepathgen linenumgen+ (replicateM i filelinegen)+ (replicateM j filelinegen)++tokreplacegen :: Gen Prim+tokreplacegen = do+ f <- filepathgen+ o <- tokengen+ n <- tokengen+ if o == n+ then return $ tokreplace f "A-Za-z" "old" "new"+ else return $ tokreplace f "A-Za-z_" o n++twofilegen :: (FilePath -> FilePath -> Prim) -> Gen Prim+twofilegen p = do+ n1 <- filepathgen+ n2 <- filepathgen+ if n1 /= n2 && (check_a_patch $ fromPrims $ (p n1 n2 :>: NilFL))+ then return $ p n1 n2+ else twofilegen p++chprefgen :: Gen Prim+chprefgen = do+ f <- oneof [return "color", return "movie"]+ o <- tokengen+ n <- tokengen+ if o == n then return $ changepref f "old" "new"+ else return $ changepref f o n++simplepatchgen :: Gen Prim+simplepatchgen = frequency [(1,liftM addfile filepathgen),+ (1,liftM adddir filepathgen),+ (1,liftM3 binary filepathgen arbitrary arbitrary),+ (1,twofilegen move),+ (1,tokreplacegen),+ (1,chprefgen),+ (7,hunkgen)+ ]++onepatchgen :: Gen Prim+onepatchgen = oneof [simplepatchgen, (invert) `fmap` simplepatchgen]++norecursgen :: Int -> Gen Patch+norecursgen 0 = PP `fmap` onepatchgen+norecursgen n = oneof [PP `fmap` onepatchgen,flatcompgen n]++arbpatch :: Int -> Gen Patch+arbpatch 0 = PP `fmap` onepatchgen+arbpatch n = frequency [(3,PP `fmap` onepatchgen),+ -- (1,compgen n),+ (2,flatcompgen n),+ (0,raw_merge_gen n),+ (0,mergegen n),+ (1,PP `fmap` onepatchgen)+ ]++unempty :: Arbitrary a => Gen [a]+unempty = do+ as <- arbitrary+ case as of+ [] -> unempty+ _ -> return as++join_patches :: [Patch] -> Patch+join_patches = joinPatches . unsafeFL++raw_merge_gen :: Int -> Gen Patch+raw_merge_gen n = do p1 <- arbpatch len+ p2 <- arbpatch len+ if (check_a_patch $ join_patches [invert p1,p2]) &&+ (check_a_patch $ join_patches [invert p2,p1])+ then case merge (p2 :\/: p1) of+ _ :/\: p2' -> return p2'+ else raw_merge_gen n+ where len = if n < 15 then n`div`3 else 3++mergegen :: Int -> Gen Patch+mergegen n = do+ p1 <- norecursgen len+ p2 <- norecursgen len+ if (check_a_patch $ join_patches [invert p1,p2]) &&+ (check_a_patch $ join_patches [invert p2,p1])+ then case merge (p2:\/:p1) of+ p1' :/\: p2' ->+ if check_a_patch $ join_patches [p1,p2']+ then return $ join_patches [p1,p2']+ else return $ join_patches [PP $ addfile "Error_in_mergegen",+ PP $ addfile "Error_in_mergegen",+ p1,p2,p1',p2']+ else mergegen n+ where len = if n < 15 then n`div`3 else 3++arbpi :: Gen PatchInfo+arbpi = do n <- unempty+ a <- unempty+ l <- unempty+ d <- unempty+ return $ unsafePerformIO $ patchinfo n d a l++instance Arbitrary PatchInfo where+ arbitrary = arbpi+-- coarbitrary pi = coarbitrary (show pi)++instance Arbitrary B.ByteString where+ arbitrary = liftM BC.pack arbitrary+-- coarbitrary ps = coarbitrary (unpackPS ps)++{-+plistgen :: Int -> Int -> Gen [Patch]+plistgen s n+ | n <= 0 = return []+ | otherwise = do+ next <- arbpatch s+ rest <- plistgen s (n-1)+ return $ next : rest++compgen :: Int -> Gen Patch+compgen n = do+ size <- choose (0,n)+ myp <- liftM join_patches $ plistgen size ((n+1) `div` (size+1))+-- here I assume we only want to consider valid patches...+ if check_a_patch myp+ then return myp+ else compgen n+-}++flatlistgen :: Int -> Gen [Patch]+flatlistgen n = replicateM n (PP `fmap` onepatchgen)++flatcompgen :: Int -> Gen Patch+flatcompgen n = do+ myp <- liftM (join_patches . regularize_patches) $ flatlistgen n+ if check_a_patch myp+ then return myp+ else flatcompgen n++-- resize to size 25, that means we'll get line numbers no greater+-- than 1025 using QuickCheck 2.1+linenumgen :: Gen Int+linenumgen = frequency [(1,return 1), (1,return 2), (1,return 3),+ (3,liftM (\n->1+abs n) (resize 25 arbitrary)) ]++tokengen :: Gen String+tokengen = oneof [return "hello", return "world", return "this",+ return "is", return "a", return "silly",+ return "token", return "test"]++toklinegen :: Gen String+toklinegen = liftM unwords $ replicateM 3 tokengen++filelinegen :: Gen B.ByteString+filelinegen = liftM BC.pack $+ frequency [(1,map fromSafeChar `fmap` arbitrary),(5,toklinegen),+ (1,return ""), (1,return "{"), (1,return "}") ]++filepathgen :: Gen String+filepathgen = liftM fixpath badfpgen++fixpath :: String -> String+fixpath "" = "test"+fixpath p = fpth p++fpth :: String -> String+fpth ('/':'/':cs) = fpth ('/':cs)+fpth (c:cs) = c : fpth cs+fpth [] = []++newtype SafeChar = SS Char+instance Arbitrary SafeChar where+ arbitrary = oneof $ map (return . SS) (['a'..'z']++['A'..'Z']++['1'..'9']++"0")++fromSafeChar :: SafeChar -> Char+fromSafeChar (SS s) = s++badfpgen :: Gen String+badfpgen = frequency [(1,return "test"), (1,return "hello"), (1,return "world"),+ (1,map fromSafeChar `fmap` arbitrary),+ (1,liftM2 (\a b-> a++"/"++b) filepathgen filepathgen) ]++{-+instance Arbitrary Char where+ arbitrary = oneof $ map return+ (['a'..'z']++['A'..'Z']++['1'..'9']++['0','~','.',',','-','/'])+-}+-- coarbitrary c = coarbitrary (ord c)++check_patch :: Patch -> PatchCheck Bool+check_a_patch :: Patch -> Bool+check_a_patch p = do_check $ do check_patch p+ check_patch $ invert p+verbose_check_a_patch :: Patch -> Bool+verbose_check_a_patch p = do_verbose_check $ do check_patch p+ check_patch $ invert p++check_patch p | isMerger p = do+ check_patch $ fromPrims $ effect p+check_patch (Merger _ _ _ _) = impossible+check_patch (Regrem _ _ _ _) = impossible+check_patch (ComP NilFL) = is_valid+check_patch (ComP (p:>:ps)) =+ check_patch p >> check_patch (ComP ps)+check_patch (PP Identity) = is_valid+check_patch (PP (Split NilFL)) = is_valid+check_patch (PP (Split (p:>:ps))) =+ check_patch (PP p) >> check_patch (PP (Split ps))++check_patch (PP (FP f RmFile)) = remove_file $ fn2fp f+check_patch (PP (FP f AddFile)) = create_file $ fn2fp f+check_patch (PP (FP f (Hunk line old new))) = do+ file_exists $ fn2fp f+ mapM_ (delete_line (fn2fp f) line) old+ mapM_ (insert_line (fn2fp f) line) (reverse new)+ is_valid+check_patch (PP (FP f (TokReplace t old new))) =+ modify_file (fn2fp f) (try_tok_possibly t old new)+-- note that the above isn't really a sure check, as it leaves PSomethings+-- and PNothings which may have contained new...+check_patch (PP (FP f (Binary o n))) = do+ file_exists $ fn2fp f+ mapM_ (delete_line (fn2fp f) 1) (linesPS o)+ file_empty $ fn2fp f+ mapM_ (insert_line (fn2fp f) 1) (reverse $ linesPS n)+ is_valid++check_patch (PP (DP d AddDir)) = create_dir $ fn2fp d+check_patch (PP (DP d RmDir)) = remove_dir $ fn2fp d++check_patch (PP (Move f f')) = check_move (fn2fp f) (fn2fp f')+check_patch (PP (ChangePref _ _ _)) = return True++regularize_patches :: [Patch] -> [Patch]+regularize_patches patches = rpint [] patches+ where rpint ok_ps [] = ok_ps+ rpint ok_ps (p:ps) =+ if check_a_patch (join_patches $ p:ok_ps)+ then rpint (p:ok_ps) ps+ else rpint ok_ps ps++prop_inverse_composition :: Patch -> Patch -> Bool+prop_inverse_composition p1 p2 =+ invert (join_patches [p1,p2]) == join_patches [invert p2, invert p1]+prop_inverse_valid :: Patch -> Bool+prop_inverse_valid p1 = check_a_patch $ join_patches [invert p1,p1]+prop_other_inverse_valid :: Patch -> Bool+prop_other_inverse_valid p1 = check_a_patch $ join_patches [p1,invert p1]++prop_commute_twice :: Patch -> Patch -> Property+prop_commute_twice p1 p2 =+ (does_commute p1 p2) ==> (Just (p1:>p2) == (commute (p1:>p2) >>= commute))+does_commute :: Patch -> Patch -> Bool+does_commute p1 p2 =+ commute (p1:>p2) /= Nothing && (check_a_patch $ join_patches [p1,p2])+prop_commute_equivalency :: Patch -> Patch -> Property+prop_commute_equivalency p1 p2 =+ (does_commute p1 p2) ==>+ case commute (p1:>p2) of+ Just (p2':>p1') -> check_a_patch $ join_patches [p1,p2,invert p1',invert p2']+ _ -> impossible++prop_commute_either_way :: Patch -> Patch -> Property+prop_commute_either_way p1 p2 =+ does_commute p1 p2 ==> does_commute (invert p2) (invert p1)++prop_commute_either_order :: Patch -> Patch -> Patch -> Property+prop_commute_either_order p1 p2 p3 =+ check_a_patch (join_patches [p1,p2,p3]) &&+ does_commute p1 (join_patches [p2,p3]) &&+ does_commute p2 p3 ==>+ case commute (p1:>p2) of+ Nothing -> False+ Just (p2':>p1') ->+ case commute (p1':>p3) of+ Nothing -> False+ Just (p3':>_) ->+ case commute (p2':>p3') of+ Nothing -> False+ Just (p3'' :> _) ->+ case commute (p2:>p3) of+ Nothing -> False+ Just (p3'a:>_) ->+ case commute (p1:>p3'a) of+ Just (p3''a:>_) -> p3''a == p3''+ Nothing -> False++prop_patch_and_inverse_is_identity :: Patch -> Patch -> Property+prop_patch_and_inverse_is_identity p1 p2 =+ (check_a_patch $ join_patches [p1,p2]) && (commute (p1:>p2) /= Nothing) ==>+ case commute (p1:>p2) of+ Just (p2':>_) -> case commute (invert p1:>p2') of+ Nothing -> True -- This is a subtle distinction.+ Just (p2'':>_) -> p2'' == p2+ Nothing -> impossible++quickmerge :: (Patch :\/: Patch) -> Patch+quickmerge (p1:\/:p2) = case merge (p1:\/:p2) of+ _ :/\: p1' -> p1'++prop_merge_is_commutable_and_correct :: Patch -> Patch -> Property+prop_merge_is_commutable_and_correct p1 p2 =+ (check_a_patch $ join_patches [invert p1,p2]) ==>+ case merge (p2:\/:p1) of+ p1' :/\: p2' ->+ case commute (p1:>p2') of+ Nothing -> False+ Just (p2'':>p1'') -> p2'' == p2 && p1' == p1''+prop_merge_is_swapable :: Patch -> Patch -> Property+prop_merge_is_swapable p1 p2 =+ (check_a_patch $ join_patches [invert p1,p2]) ==>+ case merge (p2:\/:p1) of+ p1' :/\: p2' ->+ case merge (p1:\/:p2) of+ p2''' :/\: p1''' -> p1' == p1''' && p2' == p2'''++prop_merge_valid :: Patch -> Patch -> Property+prop_merge_valid p1 p2 =+ (check_a_patch $ join_patches [invert p1,p2]) ==>+ case merge (p2:\/:p1) of+ _ :/\: p2' ->+ check_a_patch $ join_patches [invert p1,p2,invert p2,p1,p2']++prop_simple_smart_merge_good_enough :: Patch -> Patch -> Property+prop_simple_smart_merge_good_enough p1 p2 =+ (check_a_patch $ join_patches [invert p1,p2]) ==>+ smart_merge (p2:\/:p1) == simple_smart_merge (p2:\/:p1)++smart_merge :: (Patch :\/: Patch) -> Maybe (Patch :< Patch)+smart_merge (p1 :\/: p2) =+ case simple_smart_merge (p1:\/:p2) of+ Nothing -> Nothing+ Just (p1'a:<p2a) ->+ case simple_smart_merge (p2 :\/: p1) of+ Nothing -> Nothing+ Just (x:<y) ->+ case commute (y:>x) of+ Nothing -> Nothing+ Just (p2b :> p1'b) ->+ if p1'a == p1'b && p2a == p2b && p2a == p2+ then Just (p1'a :< p2)+ else Nothing+simple_smart_merge :: (Patch :\/: Patch) -> Maybe (Patch :< Patch)+simple_smart_merge (p1 :\/: p2) =+ case commute (invert p2 :> p1) of+ Just (p1':>_) ->+ case commute (p2:>p1') of+ Just (p1o:>_) ->+ if p1o == p1 then Just (p1' :< p2)+ else Nothing+ Nothing -> Nothing+ Nothing -> Nothing++prop_elegant_merge_good_enough :: Patch -> Patch -> Property+prop_elegant_merge_good_enough p1 p2 =+ (check_a_patch $ join_patches [invert p1,p2]) ==>+ (fst' `fmap` smart_merge (p2:\/:p1)) ==+ (snd'' `fmap` elegantMerge (p2:\/:p1))++fst' :: p :< p -> p+fst' (x:<_) = x++snd'' :: q :/\: p -> p+snd'' (_:/\:x) = x++instance Eq p => Eq (p :< p) where+ (x:<y) == (x':<y') = x == x' && y == y'++instance Eq p => Eq (p :> p) where+ (x:>y) == (x':>y') = x == x' && y == y'++instance Show p => Show (p :< p) where+ show (x :< y) = show x ++ " :< " ++ show y++instance Show p => Show (p :> p) where+ show (x :> y) = show x ++ " :> " ++ show y++test_patch :: String+test_patch = test_str ++ test_note+tp1, tp2 :: Patch+tp1 = unsafeUnseal . fst . fromJust . readPatch $ BC.pack "\nmove ./test/test ./hello\n"+tp2 = unsafeUnseal . fst . fromJust . readPatch $ BC.pack "\nmove ./test ./hello\n"+tp1', tp2' :: Patch+tp2' = quickmerge (tp2:\/:tp1)+tp1' = quickmerge (tp1:\/:tp2)+test_note :: String+test_note = (if commute (tp1:>tp2') == Just (tp2:>tp1')+ then "At least they commutex right.\n"+ else "Argh! they don't even commutex right.\n")+ ++(if check_a_patch $ tp2+ then "tp2 itself is valid!\n"+ else "Oh my! tp2 isn't even valid!\n")+ ++(if check_a_patch $ tp2'+ then "tp2' itself is valid!\n"+ else "Aaack! tp2' itself is invalid!\n")+ ++(if check_a_patch $ join_patches [tp1, tp2']+ then "Valid merge tp2'!\n"+ else "Bad merge tp2'!\n")+ ++ (if check_a_patch $ join_patches [tp2, tp1']+ then "Valid merge tp1'!\n"+ else "Bad merge tp1'!\n")+ ++ (if check_a_patch $ join_patches [tp2,tp1',invert tp2',invert tp1]+ then "Both agree!\n"+ else "The two merges don't agree!\n")+ ++ (if check_a_patch $ join_patches [invert tp2, tp1]+ then "They should be mergable!\n"+ else "Wait a minute, these guys can't be merged!\n")+tp :: Patch+tp = tp1'++test_str :: String+test_str = "Patches are:\n"++(show tp)+ ++(if check_a_patch tp+ then "At least the patch itself is valid.\n"+ else "The patch itself is bad!\n")+ ++"commute of tp2 and tp1' is "++show (commute (tp2:>tp1'))++"\n"+ ++"commute of tp1 and tp2' is "++show (commute (tp1:>tp2'))++"\n"+ {-++ "\nSimply flattened, it is:\n"+ ++ (show $ mapFL (joinPatches.flattenFL.merger_equivalent) $ flattenFL tp)+ ++ "\n\nUnravelled, it gives:\n" ++ (show $ map unravel $ flatten tp)+ ++ "\n\nUnwound, it gives:\n" ++ (show $ mapFL unwind $ flattenFL tp)+ ++(if check_a_patch (join_patches$ reverse $ unwind tp)+ then "Unwinding is valid.\n"+ else "Bad unwinding!\n")+ ++(if check_a_patch $ join_patches [tp,invert tp]+ then "Inverse is valid.\n"+ else "Bad inverse!\n")+ ++(if check_a_patch $ join_patches [invert tp, tp]+ then "Other inverse is valid.\n"+ else "Bad other inverse!\n")-}++-- | The conflict resolution code (glump) begins by "unravelling" the merger+-- into a set of sequences of patches. Each sequence of patches corresponds+-- to one non-conflicted patch that got merged together with the others. The+-- result of the unravelling of a series of merges must obviously be+-- independent of the order in which those merges are performed. This+-- unravelling code (which uses the unwind code mentioned above) uses probably+-- the second most complicated algorithm. Fortunately, if we can successfully+-- unravel the merger, almost any function of the unravelled merger satisfies+-- the two constraints mentioned above that the conflict resolution code must+-- satisfy.+prop_unravel_three_merge :: Patch -> Patch -> Patch -> Property+prop_unravel_three_merge p1 p2 p3 =+ (check_a_patch $ join_patches [invert p1,p2,invert p2,p3]) ==>+ (unravel $ merger "0.0" (merger "0.0" p2 p3) (merger "0.0" p2 p1)) ==+ (unravel $ merger "0.0" (merger "0.0" p1 p3) (merger "0.0" p1 p2))++prop_unravel_seq_merge :: Patch -> Patch -> Patch -> Property+prop_unravel_seq_merge p1 p2 p3 =+ (check_a_patch $ join_patches [invert p1,p2,p3]) ==>+ (unravel $ merger "0.0" p3 $ merger "0.0" p2 p1) ==+ (unravel $ merger "0.0" (merger "0.0" p2 p1) p3)++prop_unravel_order_independent :: Patch -> Patch -> Property+prop_unravel_order_independent p1 p2 =+ (check_a_patch $ join_patches [invert p1,p2]) ==>+ (unravel $ merger "0.0" p2 p1) == (unravel $ merger "0.0" p1 p2)++prop_resolve_conflicts_valid :: Patch -> Patch -> Property+prop_resolve_conflicts_valid p1 p2 =+ (check_a_patch $ join_patches [invert p1,p2]) ==>+ and $ map (check_a_patch.(\l-> join_patches [p,merge_list l]))+ $ resolveConflicts p+ where p = case merge (p1:\/:p2) of+ _ :/\: p1' -> join_patches [p2,p1']++merge_list :: [Sealed (FL Prim C(x))] -> Patch+merge_list patches = fromPrims `unseal` doml NilFL patches+ where doml mp (Sealed p:ps) =+ case commute (invert p :> mp) of+ Just (mp' :> _) -> doml (effect p +>+ effect mp') ps+ Nothing -> doml mp ps -- This shouldn't happen for "good" resolutions.+ doml mp [] = Sealed mp++try_tok_possibly :: String -> String -> String+ -> (Maybe FileContents) -> (Maybe FileContents)+try_tok_possibly t o n = liftM $ \contents ->+ let lines' = M.mapMaybe (liftM B.concat+ . try_tok_internal t (BC.pack o) (BC.pack n))+ (fc_lines contents)+ in contents { fc_lines = lines' }++try_tok_internal :: String -> B.ByteString -> B.ByteString+ -> B.ByteString -> Maybe [B.ByteString]+try_tok_internal _ _ _ s | B.null s = Just []+try_tok_internal t o n s =+ case BC.break (regChars t) s of+ (before,s') ->+ case BC.break (not . regChars t) s' of+ (tok,after) ->+ case try_tok_internal t o n after of+ Nothing -> Nothing+ Just rest ->+ if tok == o+ then Just $ before : n : rest+ else if tok == n+ then Nothing+ else Just $ before : tok : rest++prop_read_show :: Patch -> Bool+prop_read_show p = case readPatch $ renderPS $ showPatch p of+ Just (Sealed p',_) -> p' == p+ Nothing -> False++-- |In order for merges to work right with commuted patches, inverting a patch+-- past a patch and its inverse had golly well better give you the same patch+-- back again.+prop_commute_inverse :: Patch -> Patch -> Property+prop_commute_inverse p1 p2 =+ does_commute p1 p2 ==> case commute (p1 :> p2) of+ Nothing -> impossible+ Just (_ :> p1') ->+ case commute (p1' :> invert p2) of+ Nothing -> False+ Just (_ :> p1'') -> p1'' == p1++subcommutes_inverse :: [(String, Prim -> Prim -> Property)]+subcommutes_inverse = zip names (map prop_subcommute cs)+ where (names, cs) = unzip subcommutes+ prop_subcommute c p1 p2 =+ does c p1 p2 ==>+ case c (p2:< p1) of+ Succeeded (p1':<p2') ->+ case c (invert p2:< p1') of+ Succeeded (p1'':<ip2x') -> p1'' == p1 &&+ case c (invert p1:< invert p2) of+ Succeeded (ip2':< ip1') ->+ case c (p2':< invert p1) of+ Succeeded (ip1o':< p2o) ->+ invert ip1' == p1' && invert ip2' == p2' &&+ ip1o' == ip1' && p2o == p2 &&+ p1'' == p1 && ip2x' == ip2'+ _ -> False+ _ -> False+ _ -> False+ _ -> False++subcommutes_nontrivial_inverse :: [(String, Prim -> Prim -> Property)]+subcommutes_nontrivial_inverse = zip names (map prop_subcommute cs)+ where (names, cs) = unzip subcommutes+ prop_subcommute c p1 p2 =+ nontrivial c p1 p2 ==>+ case c (p2:< p1) of+ Succeeded (p1':<p2') ->+ case c (invert p2:< p1') of+ Succeeded (p1'':<ip2x') -> p1'' == p1 &&+ case c (invert p1:< invert p2) of+ Succeeded (ip2':< ip1') ->+ case c (p2':< invert p1) of+ Succeeded (ip1o':< p2o) ->+ invert ip1' == p1' && invert ip2' == p2' &&+ ip1o' == ip1' && p2o == p2 &&+ p1'' == p1 && ip2x' == ip2'+ _ -> False+ _ -> False+ _ -> False+ _ -> False++subcommutes_failure :: [(String, Prim -> Prim -> Property)]+subcommutes_failure = zip names (map prop cs)+ where (names, cs) = unzip subcommutes+ prop c p1 p2 =+ does_fail c p1 p2 ==> case c (invert p1 :< invert p2) of+ Failed -> True+ _ -> False++does_fail :: CommuteFunction -> Prim -> Prim -> Bool+does_fail c p1 p2 =+ fails (c (p2:<p1)) && (check_a_patch $ fromPrims $ unsafeFL [p1,p2])+ where fails Failed = True+ fails _ = False++does :: CommuteFunction -> Prim -> Prim -> Bool+does c p1 p2 =+ succeeds (c (p2:<p1)) && (check_a_patch $ fromPrims $ unsafeFL [p1,p2])+ where succeeds (Succeeded _) = True+ succeeds _ = False++nontrivial :: CommuteFunction -> Prim -> Prim -> Bool+nontrivial c p1 p2 =+ succeeds (c (p2:<p1)) && (check_a_patch $ fromPrims $ unsafeFL [p1,p2])+ where succeeds (Succeeded (p1' :< p2')) = p1' /= p1 || p2' /= p2+ succeeds _ = False
+ src/Darcs/Test/Patch/Unit.hs view
@@ -0,0 +1,397 @@+-- Copyright (C) 2007 David Roundy+--+-- This program is free software; you can redistribute it and/or modify+-- it under the terms of the GNU General Public License as published by+-- the Free Software Foundation; either version 2, or (at your option)+-- any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; see the file COPYING. If not, write to+-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,+-- Boston, MA 02110-1301, USA.++{-# OPTIONS_GHC -cpp -fno-warn-deprecations -fno-warn-orphans -fglasgow-exts #-}+{-# LANGUAGE CPP #-}++#include "gadts.h"++module Darcs.Test.Patch.Unit ( patch_unit_tests ) where++import Data.Maybe ( catMaybes, isNothing )+import qualified Data.ByteString.Char8 as BC ( pack )+import Darcs.Witnesses.Sealed+import Darcs.Patch+import Darcs.Patch.Patchy ( mergeFL, Invert )+import Darcs.Patch.Real ( RealPatch, prim2real, is_consistent, is_forward, is_duplicate )+import Darcs.Test.Patch.Test () -- for instance Eq Patch+import Darcs.Witnesses.Ordered+import Darcs.Patch.Properties ( recommute, commute_inverses, permutivity, partial_permutivity,+ inverse_doesnt_commute, patch_and_inverse_commute,+ merge_commute, merge_consistent, merge_arguments_consistent,+ merge_either_way, show_read,+ join_inverses, join_commute )+import Darcs.Patch.Prim ( join )+import Darcs.Test.Patch.QuickCheck+import Printer ( Doc, redText, ($$) )+--import Printer ( greenText )+--import Darcs.ColorPrinter ( traceDoc )+--import Darcs.ColorPrinter ( errorDoc )+import Darcs.ColorPrinter () -- for instance Show Doc+import Test.HUnit ( assertBool )+import Test.Framework.Providers.HUnit ( testCase )+import Test.Framework.Providers.QuickCheck2 ( testProperty )+import Test.Framework ( Test )++-- import Debug.Trace+-- #include "impossible.h"++-- | The unit tests defined about patches+patch_unit_tests :: [Test]+patch_unit_tests = [--do putStr "Checking with quickcheck that real patches have consistent flattenings... "+ -- quickCheck (not . isBottomTimeOut (Just 10) . prop_consistent_tree_flattenings) >> return 0+ run_primitive_tests "prim join inverses" (\ (a:\/:_) -> join_inverses join a) mergeables,+ testProperty "Checking prim join inverses using QuickCheck... " (isNothing . join_inverses join),+ run_primitive_tests "prim inverse doesn't commute" (\ (a:\/:_) -> inverse_doesnt_commute a) mergeables,+ -- The following fails because of setpref patches...+ --,do putStr "Checking prim inverse doesn't commute using QuickCheck... "+ -- simpleCheck (inverse_doesnt_commute :: Prim -> Maybe Doc)+ run_primitive_tests "join commute" (join_commute join) prim_permutables,+ testProperty "Checking prim join commute using QuickCheck... " (unseal2 (isNothing . join_commute join)),+ run_primitive_tests "prim recommute" (recommute commute) $ map mergeable2commutable mergeables,+ run_primitive_tests "prim patch and inverse commute" (patch_and_inverse_commute commute) $ map mergeable2commutable mergeables,+ run_primitive_tests "prim inverses commute" (commute_inverses commute) $ map mergeable2commutable mergeables,+ --,do putStr "Checking prim recommute using QuickCheck... "+ -- simpleCheck (recommute+ -- (commute :: Prim :> Prim+ -- -> Maybe (Prim :> Prim)))+ run_primitive_tests "FL prim recommute" (recommute commute) $ map mergeable2commutable mergeablesFL,+ run_primitive_tests "FL prim patch and inverse commute" (patch_and_inverse_commute commute) $ map mergeable2commutable mergeablesFL,+ run_primitive_tests "FL prim inverses commute" (commute_inverses commute) $ map mergeable2commutable mergeablesFL,+ run_primitive_tests "fails" (commute_fails commute) ([] :: [Prim :> Prim]),+ run_primitive_tests "read and show work on Prim" show_read prim_patches,+ run_primitive_tests "read and show work on RealPatch" show_read real_patches,+ testProperty "Checking that readPatch and showPatch work on RealPatch... "+ (isNothing . (unseal $ patchFromTree $ (show_read :: RealPatch -> Maybe Doc))),+ testProperty "Checking that readPatch and showPatch work on FL RealPatch... "+ (isNothing . (unseal2 $ (show_read :: FL RealPatch -> Maybe Doc))),+ run_primitive_tests "example flattenings work"+ (\x -> if prop_consistent_tree_flattenings x+ then Nothing+ else Just $ redText "oops")+ real_patch_loop_examples,+ testProperty "Checking that tree flattenings are consistent... " prop_consistent_tree_flattenings,+ testProperty "Checking with quickcheck that real patches are consistent... "+ (isNothing . (unseal $ patchFromTree $ is_consistent)),+ run_primitive_tests "real merge input consistent" (merge_arguments_consistent is_consistent) real_mergeables,+ run_primitive_tests "real merge input is forward" (merge_arguments_consistent is_forward) real_mergeables,+ run_primitive_tests "real merge output is forward" (merge_consistent is_forward) real_mergeables,+ run_primitive_tests "real merge output consistent" (merge_consistent is_consistent) real_mergeables,+ run_primitive_tests "real merge either way" merge_either_way real_mergeables,+ run_primitive_tests "real merge and commute" merge_commute real_mergeables,++ run_primitive_tests "real recommute" (recommute commute) real_commutables,+ run_primitive_tests "real inverses commute" (commute_inverses commute) real_commutables,+ run_primitive_tests "real permutivity" (permutivity commute) $ filter (not_duplicatestriple) real_triples,+ run_primitive_tests "real partial permutivity" (partial_permutivity commute) $ filter (not_duplicatestriple) real_triples,++ testProperty "Checking we can do merges using QuickCheck"+ (isNothing . (prop_is_mergeable ::+ Sealed (WithStartState RepoModel (Tree Prim))+ -> Maybe (Tree RealPatch C(x)))),+ testProperty "Checking recommute using QuickCheck Tree generator"+ (isNothing. (unseal $ commutePairFromTree $+ (recommute+ (commute :: RealPatch :> RealPatch+ -> Maybe (RealPatch :> RealPatch))))),+ testProperty "Checking recommute using QuickCheck TWFP generator"+ (isNothing . (unseal $ commutePairFromTWFP $+ (recommute+ (commute :: RealPatch :> RealPatch+ -> Maybe (RealPatch :> RealPatch))))),+ testConditional "Checking nontrivial recommute"+ (unseal $ commutePairFromTree $ nontrivial_reals)+ (unseal $ commutePairFromTree $+ (recommute+ (commute :: RealPatch :> RealPatch+ -> Maybe (RealPatch :> RealPatch)))),+ testConditional "Checking nontrivial recommute using TWFP"+ (unseal $ commutePairFromTWFP $ nontrivial_reals)+ (unseal $ commutePairFromTWFP $+ (recommute+ (commute :: RealPatch :> RealPatch+ -> Maybe (RealPatch :> RealPatch)))),++ testProperty "Checking inverses commute using QuickCheck Tree generator"+ (isNothing . (unseal $ commutePairFromTree $+ (commute_inverses+ (commute :: RealPatch :> RealPatch+ -> Maybe (RealPatch :> RealPatch))))),+ testProperty "Checking inverses commute using QuickCheck TWFP generator"+ (isNothing . (unseal $ commutePairFromTWFP $+ (commute_inverses+ (commute :: RealPatch :> RealPatch+ -> Maybe (RealPatch :> RealPatch))))),+ testConditional "Checking nontrivial inverses commute"+ (unseal $ commutePairFromTree $ nontrivial_reals)+ (unseal $ commutePairFromTree $+ (commute_inverses+ (commute :: RealPatch :> RealPatch+ -> Maybe (RealPatch :> RealPatch)))),+ testConditional "Checking nontrivial inverses commute using TWFP"+ (unseal $ commutePairFromTWFP $ nontrivial_reals)+ (unseal $ commutePairFromTWFP $+ (commute_inverses+ (commute :: RealPatch :> RealPatch+ -> Maybe (RealPatch :> RealPatch)))),++ testProperty "Checking merge either way using QuickCheck TWFP generator"+ (isNothing . (unseal $ mergePairFromTWFP $+ (merge_either_way :: RealPatch :\/: RealPatch -> Maybe Doc))),+ testProperty "Checking merge either way using QuickCheck Tree generator"+ (isNothing . (unseal $ mergePairFromTree $+ (merge_either_way :: RealPatch :\/: RealPatch -> Maybe Doc))),+ testConditional "Checking nontrivial merge either way"+ (unseal $ mergePairFromTree $ nontrivial_merge_reals)+ (unseal $ mergePairFromTree $+ (merge_either_way :: RealPatch :\/: RealPatch -> Maybe Doc)),+ testConditional "Checking nontrivial merge either way using TWFP"+ (unseal $ mergePairFromTWFP $ nontrivial_merge_reals)+ (unseal $ mergePairFromTWFP $+ (merge_either_way :: RealPatch :\/: RealPatch -> Maybe Doc)),++ testConditional "Checking permutivity"+ (unseal $ commuteTripleFromTree not_duplicatestriple)+ (unseal $ commuteTripleFromTree $ permutivity+ (commute :: RealPatch :> RealPatch -> Maybe (RealPatch :> RealPatch))),+ testConditional "Checking partial permutivity"+ (unseal $ commuteTripleFromTree not_duplicatestriple)+ (unseal $ commuteTripleFromTree $ partial_permutivity+ (commute :: RealPatch :> RealPatch -> Maybe (RealPatch :> RealPatch))),+ testConditional "Checking nontrivial permutivity"+ (unseal $ commuteTripleFromTree+ (\t -> nontrivial_triple t && not_duplicatestriple t))+ (unseal $ commuteTripleFromTree $+ (permutivity+ (commute :: RealPatch :> RealPatch+ -> Maybe (RealPatch :> RealPatch))))+ ]++not_duplicatestriple :: RealPatch :> RealPatch :> RealPatch -> Bool+not_duplicatestriple (a :> b :> c) = not $ any is_duplicate [a,b,c]++--not_duplicates_pair :: RealPatch :> RealPatch -> Bool+--not_duplicates_pair (a :> b) = not $ any is_duplicate [a,b]++nontrivial_triple :: RealPatch :> RealPatch :> RealPatch -> Bool+nontrivial_triple (a :> b :> c) =+ case commute (a :> b) of+ Nothing -> False+ Just (b' :> a') ->+ case commute (a' :> c) of+ Nothing -> False+ Just (c'' :> a'') ->+ case commute (b :> c) of+ Nothing -> False+ Just (c' :> b'') -> (not (a `unsafeCompare` a') || not (b `unsafeCompare` b')) &&+ (not (c' `unsafeCompare` c) || not (b'' `unsafeCompare` b)) &&+ (not (c'' `unsafeCompare` c) || not (a'' `unsafeCompare` a'))++nontrivial_reals :: RealPatch :> RealPatch -> Bool+nontrivial_reals = nontrivial_commute++nontrivial_commute :: Patchy p => p :> p -> Bool+nontrivial_commute (x :> y) = case commute (x :> y) of+ Just (y' :> x') -> not (y' `unsafeCompare` y) ||+ not (x' `unsafeCompare` x)+ Nothing -> False++nontrivial_merge_reals :: RealPatch :\/: RealPatch -> Bool+nontrivial_merge_reals = nontrivial_merge++nontrivial_merge :: Patchy p => p :\/: p -> Bool+nontrivial_merge (x :\/: y) = case merge (x :\/: y) of+ y' :/\: x' -> not (y' `unsafeCompare` y) ||+ not (x' `unsafeCompare` x)++-- | Run a test function on a set of data, using HUnit. The test function should+-- return @Nothing@ upon success and a @Just x@ upon failure.+run_primitive_tests :: (Show a, Show b) => String -- ^ The test name+ -> (a -> Maybe b) -- ^ The test function+ -> [a] -- ^ The test data+ -> Test+run_primitive_tests name test datas = testCase name (assertBool assertName res)+ where assertName = "Boolean assertion for \"" ++ name ++ "\""+ res = and $ map (isNothing . test) datas++quickhunk :: Int -> String -> String -> Prim+quickhunk l o n = hunk "test" l (map (\c -> BC.pack [c]) o)+ (map (\c -> BC.pack [c]) n)++prim_permutables :: [Prim :> Prim :> Prim]+prim_permutables =+ [quickhunk 0 "e" "bo" :> quickhunk 3 "" "x" :> quickhunk 2 "f" "qljo"]++mergeables :: [Prim :\/: Prim]+mergeables = [quickhunk 1 "a" "b" :\/: quickhunk 1 "a" "c",+ quickhunk 1 "a" "b" :\/: quickhunk 3 "z" "c",+ quickhunk 0 "" "a" :\/: quickhunk 1 "" "b",+ quickhunk 0 "a" "" :\/: quickhunk 1 "" "b",+ quickhunk 0 "a" "" :\/: quickhunk 1 "b" "",+ quickhunk 0 "" "a" :\/: quickhunk 1 "b" ""+ ]++mergeablesFL :: [FL Prim :\/: FL Prim]+mergeablesFL = map (\ (x:\/:y) -> (x :>: NilFL) :\/: (y :>: NilFL)) mergeables +++ [] -- [(quickhunk 1 "a" "b" :>: quickhunk 3 "z" "c" :>: NilFL)+ -- :\/: (quickhunk 1 "a" "z" :>: NilFL),+ -- (quickhunk 1 "a" "b" :>: quickhunk 1 "b" "c" :>: NilFL)+ -- :\/: (quickhunk 1 "a" "z" :>: NilFL)]++mergeable2commutable :: Invert p => p :\/: p -> p :> p+mergeable2commutable (x :\/: y) = invert x :> y++prim_patches :: [Prim]+prim_patches = concatMap mergeable2patches mergeables+ where mergeable2patches (x:\/:y) = [x,y]++real_patches :: [RealPatch]+real_patches = concatMap commutable2patches real_commutables+ where commutable2patches (x:>y) = [x,y]++real_triples :: [RealPatch :> RealPatch :> RealPatch]+real_triples = [ob' :> oa2 :> a2'',+ oa' :> oa2 :> a2''] ++ triple_examples+ ++ map unsafeUnseal2 (concatMap getTriples realFLs)+ where oa = prim2real $ quickhunk 1 "o" "aa"+ oa2 = oa+ a2 = prim2real $ quickhunk 2 "a34" "2xx"+ ob = prim2real $ quickhunk 1 "o" "bb"+ ob' :/\: oa' = merge (oa :\/: ob)+ a2' :/\: _ = merge (ob' :\/: a2)+ a2'' :/\: _ = merge (oa2 :\/: a2')++realFLs :: [FL RealPatch]+realFLs = [oa :>: invert oa :>: oa :>: invert oa :>: ps +>+ oa :>: invert oa :>: NilFL]+ where oa = prim2real $ quickhunk 1 "o" "a"+ ps :/\: _ = merge (oa :>: invert oa :>: NilFL :\/: oa :>: invert oa :>: NilFL)++real_commutables :: [RealPatch :> RealPatch]+real_commutables = commute_examples ++ map mergeable2commutable real_mergeables+++ [invert oa :> ob'] ++ map unsafeUnseal2 (concatMap getPairs realFLs)+ where oa = prim2real $ quickhunk 1 "o" "a"+ ob = prim2real $ quickhunk 1 "o" "b"+ _ :/\: ob' = mergeFL (ob :\/: oa :>: invert oa :>: NilFL)++real_mergeables :: [RealPatch :\/: RealPatch]+real_mergeables = map (\ (x :\/: y) -> prim2real x :\/: prim2real y) mergeables+ ++ real_igloo_mergeables+ ++ real_quickcheck_mergeables+ ++ merge_examples+ ++ catMaybes (map pair2m (concatMap getPairs realFLs))+ ++ [(oa :\/: od),+ (oa :\/: a2'),+ (ob' :\/: od''),+ (oe :\/: od),+ (of' :\/: oe'),+ (ob' :\/: oe'),+ (oa :\/: oe'),+ (ob' :\/: oc'),+ (b2' :\/: oc'''),+ (ob' :\/: a2),+ (b2' :\/: og'''),+ (oc''' :\/: og'''),+ (oc'' :\/: og''),+ (ob'' :\/: og''),+ (ob'' :\/: oc''),+ (oc' :\/: od'')]+ where oa = prim2real $ quickhunk 1 "o" "aa"+ a2 = prim2real $ quickhunk 2 "a34" "2xx"+ og = prim2real $ quickhunk 3 "4" "g"+ ob = prim2real $ quickhunk 1 "o" "bb"+ b2 = prim2real $ quickhunk 2 "b" "2"+ oc = prim2real $ quickhunk 1 "o" "cc"+ od = prim2real $ quickhunk 7 "x" "d"+ oe = prim2real $ quickhunk 7 "x" "e"+ pf = prim2real $ quickhunk 7 "x" "f"+ od'' = prim2real $ quickhunk 8 "x" "d"+ ob' :>: b2' :>: NilFL :/\: _ = mergeFL (oa :\/: ob :>: b2 :>: NilFL)+ a2' :/\: _ = merge (ob' :\/: a2)+ ob'' :/\: _ = merge (a2 :\/: ob')+ og' :/\: _ = merge (oa :\/: og)+ og'' :/\: _ = merge (a2 :\/: og')+ og''' :/\: _ = merge (ob' :\/: og')+ oc' :/\: _ = merge (oa :\/: oc)+ oc'' :/\: _ = merge (a2 :\/: oc)+ oc''' :/\: _ = merge (ob' :\/: oc')+ oe' :/\: _ = merge (od :\/: oe)+ of' :/\: _ = merge (od :\/: pf)+ pair2m :: Sealed2 (RealPatch :> RealPatch)+ -> Maybe (RealPatch :\/: RealPatch)+ pair2m (Sealed2 (xx :> y)) = do y' :> _ <- commute (xx :> y)+ return (xx :\/: y')++real_igloo_mergeables :: [RealPatch :\/: RealPatch]+real_igloo_mergeables = [(a :\/: b),+ (b :\/: c),+ (a :\/: c),+ (x :\/: a),+ (y :\/: b),+ (z :\/: c),+ (x' :\/: y'),+ (z' :\/: y'),+ (x' :\/: z'),+ (a :\/: a)]+ where a = prim2real $ quickhunk 1 "1" "A"+ b = prim2real $ quickhunk 2 "2" "B"+ c = prim2real $ quickhunk 3 "3" "C"+ x = prim2real $ quickhunk 1 "1BC" "xbc"+ y = prim2real $ quickhunk 1 "A2C" "ayc"+ z = prim2real $ quickhunk 1 "AB3" "abz"+ x' :/\: _ = merge (a :\/: x)+ y' :/\: _ = merge (b :\/: y)+ z' :/\: _ = merge (c :\/: z)++real_quickcheck_mergeables :: [RealPatch :\/: RealPatch]+real_quickcheck_mergeables = [-- invert k1 :\/: n1+ --, invert k2 :\/: n2+ hb :\/: k+ , b' :\/: b'+ , n' :\/: n'+ , b :\/: d+ , k' :\/: k'+ , k3 :\/: k3+ ] ++ catMaybes (map pair2m pairs)+ where hb = prim2real $ quickhunk 0 "" "hb"+ k = prim2real $ quickhunk 0 "" "k"+ n = prim2real $ quickhunk 0 "" "n"+ b = prim2real $ quickhunk 1 "b" ""+ d = prim2real $ quickhunk 2 "" "d"+ d':/\:_ = merge (b :\/: d)+ --k1 :>: n1 :>: NilFL :/\: _ = mergeFL (hb :\/: k :>: n :>: NilFL)+ --k2 :>: n2 :>: NilFL :/\: _ =+ -- merge (hb :>: b :>: NilFL :\/: k :>: n :>: NilFL)+ k' :>: n' :>: NilFL :/\: _ :>: b' :>: _ = merge (hb :>: b :>: d' :>: NilFL :\/: k :>: n :>: NilFL)+ pairs = getPairs (hb :>: b :>: d' :>: k' :>: n' :>: NilFL)+ pair2m :: Sealed2 (RealPatch :> RealPatch)+ -> Maybe (RealPatch :\/: RealPatch)+ pair2m (Sealed2 (xx :> y)) = do y' :> _ <- commute (xx :> y)+ return (xx :\/: y')++ i = prim2real $ quickhunk 0 "" "i"+ x = prim2real $ quickhunk 0 "" "x"+ xi = prim2real $ quickhunk 0 "xi" ""+ d3 :/\: _ = merge (xi :\/: d)+ _ :/\: k3 = mergeFL (k :\/: i :>: x :>: xi :>: d3 :>: NilFL)++commute_fails :: (MyEq p, Patchy p) => (p :> p -> Maybe (p :> p)) -> p :> p+ -> Maybe Doc+commute_fails c (x :> y) = do y' :> x' <- c (x :> y)+ return $ redText "x" $$ showPatch x $$+ redText ":> y" $$ showPatch y $$+ redText "y'" $$ showPatch y' $$+ redText ":> x'" $$ showPatch x'
+ tests/README.test_maintainers.txt view
@@ -0,0 +1,100 @@++The following is provided as a reference for those interested in understanding+how the test suite works, and how to add and maintain tests.++Overview of types of tests+==========================++Darcs has tests in two formats. Unit tests that directly test Haskell+functions are written in Haskell and live in modules under src/Darcs/Test.+Functional tests that test the darcs binary are written in Shell and live in+tests/.++Haskell tests+--------------------------++These are QuickCheck and HUnit tests primarily testing the Darcs core. The+Haskell modules containing these tests are under Darcs.Test in the module+hierarchy. They are called from src/unit.lhs using the test-framework package+from Hackage.++More about the Haskell tests can be found on http://wiki.darcs.net/UnitTests.++Shell tests+---------------------------++Shell tests are useful because they are easy to create from a copy/paste+of actual shell commands executed. They are considered successful if no+bad exit codes are returned from the commands in the script. If the name of the+script file starts with 'failing-' however, the script is expected to return+a bad exit code. If such a script returns a bad exit code, this will not be+treated as a test suite failure. This is useful to document bugs and to-do+items.++How to run tests+=============================++To build the unit tests, pass the "-ftest" flag to "cabal configure" and then+do "cabal build". To run them, do "dist/build/unit/unit". They take a while.+Output like "[OK]" and "[OK, passed 100 tests]" is good. Output like+"Arguments exhausted after 33 tests" is a shortage of QuickCheck test+cases, not a test failure.++"runghc Setup.lhs test" causes all the functional tests in "tests/" to be run+against repositories in the old, hashed, and darcs2 formats.++Because "runghc Setup.lhs test" can take a long time to run, it's useful to run+fewer tests at once. To help with that, 'runghc Setup.lhs test' accepts+arguments to run only a specific group of test scripts, or only named test+scripts:++ runghc Setup.lhs test tests # all tests, excluding bugs or network tests+ runghc Setup.lhs test bugs # all bugs (the 'failing-' scripts)+ runghc Setup.lhs test network # the network tests++ # and this one runs tests/issue279_get_extra.sh and tests/repair_corrupt.sh+ runghc Setup.lhs test issue279_get_extra repair-corrupt++Tips for writing (and reading) tests+====================================++- Avoid including a repo format type to "darcs init"+ This insures that all three repo formats will be tested.+ However, if you know that the test only passes under some+ repo formats, *do* explicitly include a format option to "darcs init".+++Tips for writing tests+----------------------++- Copy an existing test, which will already have the following properties:++- Simply call darcs using "darcs" as you would in the shell. It is the+ responsibility of the test harness to ensure that the darcs we are+ testing is first in the path.++- Always use Bash explicitly - this improves the portability of our tests.++- Always add this near the top of the script:++ set -ev++ The "v" causes the contents of the script to be printed as part of the run,+ which is helpful for debugging. The "e" causes the script to exit as soon as+ there is an error.++- Try to avoid defining functions where possible. This makes them+ harder to run and generally harder to use. There are certainly cases+ where it is appropriate to define a function, but please do not do+ this just to avoid a little duplication.++- Also try to be careful using certain utilities; 'yes' is prohibited since+ it can cause infinite loops on Mac OS X; 'find' can be very useful, but+ options and behavior can differ from GNU find to the BSD finds to Solaris's+ find and so on. In general, stick to POSIX flags and functionality.++- There is a utility script intended for factoring out common calls and+ functions, called 'lib'. It can be invoked by adding a line like '. lib' to+ your shell script. lib provides 'set -ev', a common definition of 'not', and+ 'abort_windows' for use in scripts which shouldn't run under Windows.+ You don't have to use lib if you don't want to, or if it causes problems.
− tests/failing-issue1645-ignore-symlinks.sh
@@ -1,35 +0,0 @@-#!/usr/bin/env bash-## Test for issue1645 - whatsnew -l should not consider symlinks to be-## "real" files in the working tree.-##-## Copyright (C) 2009 Trent W. Buck-##-## Permission is hereby granted, free of charge, to any person-## obtaining a copy of this software and associated documentation-## files (the "Software"), to deal in the Software without-## restriction, including without limitation the rights to use, copy,-## modify, merge, publish, distribute, sublicense, and/or sell copies-## of the Software, and to permit persons to whom the Software is-## furnished to do so, subject to the following conditions:-##-## The above copyright notice and this permission notice shall be-## included in all copies or substantial portions of the Software.-##-## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,-## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF-## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND-## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS-## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN-## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN-## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-## SOFTWARE.--. ../tests/lib # Load some portability helpers.-rm -rf R f # Another script may have left a mess.-darcs init --repo R # Create our test repos.--cd R-echo 'Example content.' > ../f # a file outside the repo-ln -s ../f # a symlink to same inside the repo-darcs whatsnew -l >log-fgrep 'No changes!' log # Darcs shouldn't report any changes.
+ tests/issue1645-ignore-symlinks-case-fold.sh view
@@ -0,0 +1,73 @@+#!/usr/bin/env bash+## Test for issue1645 - Since Darcs does not version-contol symlinks,+## it should not follow them, ESPECIALLY symlinks to directories+## outside the repository. All these tests are passed with darcs-2.2+##+## See path_resolution(7) and symlink(7) for more info, especially+## the former.+##+## This only covers the case-folding test cases.+## See also the issue1645-ignore-symlinks for the main test+##+## Copyright (C) 2010 Trent W. Buck, Dmitry Astapov+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. lib # Load some portability helpers.+rm -rf R S # Another script may have left a mess.+darcs init --repo R # Create our test repos.+darcs init --repo S++add_to_boring() {+ echo "$1" >> _darcs/prefs/boring+}++## These are the simple does-the-wrong-thing errors.+cd R+touch log+add_to_boring '^log$'++unset pwd # Since this test is pretty much linux-specific, hspwd.hs is not needed++# Skip the case-folding tests on systems that don't support it+touch cs-test+ln -s cs-test cs-Test || exit 200++rm cs-test cs-Test # move file and symlink out of the way for real tests++# Case 15: case-folding link to non-recorded file+touch non-recorded-file2+ln -s ./non-recorded-file2 ./Non-Recorded-File2+ln -s "`pwd`"/non-recorded-file2 ./Non-ReCoRdEd-File2+darcs w -l >log 2>&1 # should report only "non-recorded-file"+darcs rec -alm "added ./non-recorded-file2" >>log 2>&1 # should add only file, not symlink+darcs changes -s --patch="added ./non-recorded-file2" >>log 2>&1 # should report only file, not symlink+cat log+not grep -vE "(^ *$|^\+|[0-9]:[0-9][0-9]:[0-9]|./non-recorded-file2)" log+rm Non-Recorded-File2 ./Non-ReCoRdEd-File2++# Case 16: case-folding link to recorded file+ln -s ./recorded-file ./Recorded-File+ln -s "`pwd`"/recorded-file ./ReCorded-File+not darcs w -l >log 2>&1 # expecting "No changes!"+darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well+not grep -vE "(^ *$|^\+|No changes!)" log+rm Recorded-File ReCorded-File
+ tests/issue1645-ignore-symlinks.sh view
@@ -0,0 +1,173 @@+#!/usr/bin/env bash+## Test for issue1645 - Since Darcs does not version-contol symlinks, +## it should not follow them, ESPECIALLY symlinks to directories+## outside the repository. All these tests are passed with darcs-2.2+##+## See path_resolution(7) and symlink(7) for more info, especially+## the former.+##+## There's a second section to this test for systems that support+## case-folding. See issue1645-ignore-symlinks-case-fold.sh+##+## Copyright (C) 2010 Trent W. Buck, Dmitry Astapov+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. lib # Load some portability helpers.+rm -rf R S # Another script may have left a mess.+darcs init --repo R # Create our test repos.+darcs init --repo S++darcs --version++add_to_boring() {+ echo "$1" >> _darcs/prefs/boring+}++## These are the simple does-the-wrong-thing errors.+cd R+touch log+add_to_boring '^log$'++unset pwd # Since this test is pretty much linux-specific, hspwd.hs is not needed++# Case 1: looping symlink to non-recorded non-boring dir+mkdir non-recorded-dir+ln -s ../non-recorded-dir ./non-recorded-dir/loop # relative symlink+ln -s "`pwd`"/non-recorded-dir ./non-recorded-dir/loop2 # absolute symlink+darcs w -l >log 2>&1 # should not loop+darcs rec -alm "added ./non-recorded-dir" >>log 2>&1 # should not loop+darcs changes -s --patch="added ./non-recorded-dir" >>log 2>&1 # should report only dir, not symlink+not grep -vE "(^ *$|^\+|[0-9]:[0-9][0-9]:[0-9]|./non-recorded-dir)" log++# Case 2: looping symlink to recorded dir+mkdir recorded-dir+darcs add recorded-dir+darcs rec -am "added recorded-dir"+ln -s ../recorded-dir ./recorded-dir/loop # relative symlink+ln -s "`pwd`"/recorded-dir ./recorded-dir/loop2 # absolute symlink+not darcs w -l >log 2>&1 # expecting "No changes!"+darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well+not grep -vE "(^ *$|^\+|No changes!)" log++# Case 3: looping symlink to boring dir+mkdir boring-dir+add_to_boring '^boring-dir$'+ln -s ../boring-dir ./boring-dir/loop+ln -s "`pwd`"/boting-dir ./boring-dir/loop2+not darcs w -l >log 2>&1 # expecting "No changes!"+darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well+not grep -vE "(^ *$|^\+|No changes!)" log++# Case 4: non-looping symlink to non-recorded non-boring dir+mkdir non-recorded-dir2+ln -s ./non-recorded-dir2 link+ln -s "`pwd`"/non-recorded-dir2 ./link2+darcs w -l >log 2>&1 # should report only "non-recorded-dir2"+darcs rec -alm "added ./non-recorded-dir2" >>log 2>&1 # should add only dir, not symlink+darcs changes -s --patch="added ./non-recorded-dir2" >>log 2>&1 # should report only dir, not symlink+not grep -vE "(^ *$|^\+|[0-9]:[0-9][0-9]:[0-9]|./non-recorded-dir2)" log+rm link link2++# Case 5: non-looping symlink to recorded dir+ln -s ./recorded-dir ./link+ln -s "`pwd`"/recorded-dir ./link2+not darcs w -l >log 2>&1 # expecting "No changes!"+darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well+not grep -vE "(^ *$|^\+|No changes!)" log+rm link link2++# Case 6: non-looping symlink to boring dir+ln -s ./boring-dir ./link+ln -s "`pwd`"/boring-dir ./link2+not darcs w -l >log 2>&1 # expecting "No changes!"+darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well+not grep -vE "(^ *$|^\+|No changes!)" log+rm link link2++# Case 7: symlink pointing outside the repo+ln -s ../S link+(cd ..; ln -s "`pwd`"/S ./R/link2)+not darcs w -l >log 2>&1 # expecting "No changes!"+darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well+not grep -vE "(^ *$|^\+|No changes!)" log+rm link link2++# Case 8: symlink to non-recorded non-boring file+touch non-recorded-file+ln -s ./non-recorded-file ./link+ln -s "`pwd`"/non-recorded-file ./link2+darcs w -l >log 2>&1 # should report only "non-recorded-file"+darcs rec -alm "added ./non-recorded-file" >>log 2>&1 # should add only file, not symlink+darcs changes -s --patch="added ./non-recorded-file" >>log 2>&1 # should report only file, not symlink+not grep -vE "(^ *$|^\+|[0-9]:[0-9][0-9]:[0-9]|./non-recorded-file)" log+rm link link2++# Case 9: symlink to recorded file+echo "some content" > recorded-file+darcs add recorded-file+darcs rec -am "added recorded-file" recorded-file+ln -s ./recorded-file ./link+ln -s "`pwd`"/recorded-file ./link2+not darcs w -l >log 2>&1 # expecting "No changes!"+darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well+not grep -vE "(^ *$|^\+|No changes!)" log+rm link link2++# Case 10: symlink to boring file+ln -s ./log ./link+ln -s "`pwd`"/log ./link2+not darcs w -l >log 2>&1 # expecting "No changes!"+darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well+not grep -vE "(^ *$|^\+|No changes!)" log+rm link link2++# Case 11: dangling symlink+ln -s /completely/bogus/path ./link+ln -s ../../../../not/exist ./link2+not darcs w -l >log 2>&1 # expecting "No changes!"+darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well+not grep -vE "(^ *$|^\+|No changes!)" log+rm link link2++# Case 12: self-referencing link+ln -s l l+ln -s "`pwd`"/l2 ./l2+not darcs w -l >log 2>&1 # expecting "No changes!"+darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well+not grep -vE "(^ *$|^\+|No changes!)" log+rm l l2++# Case 13: link to device file outside the repo+ln -s /dev/zero l+not darcs w -l >log 2>&1 # expecting "No changes!"+darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well+not grep -vE "(^ *$|^\+|No changes!)" log+rm l++# Case 14: link to fifo+mkfifo f+ln -s f l+ln -s "`pwd`"/f ./l2+not darcs w -l >log 2>&1 # expecting "No changes!"+darcs rec -alm "should not happen" >>log 2>&1 # expecting "No changes!" as well+not grep -vE "(^ *$|^\+|No changes!)" log+rm f l l2
+ tests/issue1765_recursive-remove-on-root.sh view
@@ -0,0 +1,36 @@+#!/usr/bin/env bash+## Test for issueNNNN - <SYNOPSIS: WHAT IS THE BUG? THIS SYNOPSIS+## SHOULD BE ONE OR TWO SENTENCES.>+##+## Copyright (C) YEAR AUTHOR+##+## Permission is hereby granted, free of charge, to any person+## obtaining a copy of this software and associated documentation+## files (the "Software"), to deal in the Software without+## restriction, including without limitation the rights to use, copy,+## modify, merge, publish, distribute, sublicense, and/or sell copies+## of the Software, and to permit persons to whom the Software is+## furnished to do so, subject to the following conditions:+##+## The above copyright notice and this permission notice shall be+## included in all copies or substantial portions of the Software.+##+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS+## BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+## ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN+## CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+## SOFTWARE.++. lib # Load some portability helpers.+rm -rf R S # Another script may have left a mess.+darcs init --repo R # Create our test repos.+darcs init --repo S++cd R+mkdir d e # Change the working tree.+echo 'Example content.' > d/f+darcs record -lam 'Add d/f and e.'+darcs remove * -r
tests/issue458.sh view
@@ -20,7 +20,8 @@ darcs record --repodir repo1 -lam x x umask 077 # DENY ALL access to group, all darcs get --set-scripts-executable repo1 repo2-ls -l repo2/x | cut -f 1 -d\ > mode+# remove trailing-dot for xattr+ls -l repo2/x | cut -f 1 -d\ | sed -e "s/\.$//" > mode echo -rwx------ > desired-mode diff -u desired-mode mode