packages feed

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 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.
@@ -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