https://kotlinlang.org logo
Title
j

Javier

10/17/2021, 3:56 AM
Is it possible to pass two dir files and assert all files and directories have the same structure and content?
j

Jim

10/17/2021, 3:59 AM
Sounds like a fun assertion to write, I'm not sure that it exists though
s

sam

10/17/2021, 4:04 AM
yeah sounds like a useful addition
dir1 shouldHaveSomeStrutureAs dir2
feel free to call it what you want
sameContents sameTree etc
l

LeoColman

10/17/2021, 10:25 AM
we should differentiate between `deep`/`recursive` in a way (maybe an optional parameter) as well
j

Javier

10/17/2021, 11:35 AM
Should I file an issue?
I am going to create a PR
👍 1
👍🏻 1
s

sam

10/17/2021, 3:22 PM
val p = Runtime.getRuntime().exec("""reg query "HKU\S-1-5-19"""")
what does that do
j

Javier

10/17/2021, 3:22 PM
I called
shouldHaveSameTreeAndContents
to be more explicit, feels free to suggest if I should change it
I don't know, I didn't write that
s

sam

10/17/2021, 3:23 PM
oh lol
you just changed formatting ?
j

Javier

10/17/2021, 3:23 PM
maybe that line is appearing because the format was different in one function
s

sam

10/17/2021, 3:23 PM
the name is a touch verbose, what about
shouldHaveSameStructure
?
j

Javier

10/17/2021, 3:23 PM
I rename to that 🙂
Done
s

sam

10/17/2021, 3:30 PM
will merge once green
👍 1
j

Javier

10/17/2021, 9:35 PM
@sam I checking one documentation website is same than another, I got issues related to the content of the file can be different
\
instead of
/
and so on
so I am doing something like this
expectFiles.zip(actualFiles).forEach { (expect, actual) ->
    expect.replaceSlash()
    actual.replaceSlash()
    when {
        expect.extension == "gz" -> println("`.gz` files are ignored")
        expect.extension == "json" -> println("`.gz` files are ignored")
        expect.isDirectory -> actual.shouldBeADirectory()
        expect.isFile -> actual.shouldHaveSameContentAs(actual)
    }
}
s

sam

10/17/2021, 9:36 PM
the filename or the contents of the file ?
j

Javier

10/17/2021, 9:36 PM
what do you thing if we add a
transform
lambda and
filter
predicate?
the content inside the file
the gradle plugin I use to generate the content
generates the files differently in windows vs macos
s

sam

10/17/2021, 9:37 PM
the lambdas would work
I didn't realize we were checking file contents
I thought were just checking file tree
j

Javier

10/17/2021, 9:37 PM
nono, tree + content
s

sam

10/17/2021, 9:37 PM
I mus have missed that
j

Javier

10/17/2021, 9:37 PM
that was the reason I named it
shouldHaveSameTreeAndContents
s

sam

10/17/2021, 9:37 PM
yeah I see now
j

Jim

10/17/2021, 9:37 PM
Is this jvm only?
j

Javier

10/17/2021, 9:37 PM
yeah
s

sam

10/17/2021, 9:37 PM
yeah
j

Javier

10/17/2021, 9:38 PM
files api is not ready in kmp
j

Jim

10/17/2021, 9:38 PM
Should we try to use system.fileseperaror?
s

sam

10/17/2021, 9:38 PM
wanna rename it back 🙂
j

Javier

10/17/2021, 9:38 PM
okio is almost there tho
nono
the function is working fine
the merged one
technically the files have different content
s

sam

10/17/2021, 9:38 PM
I think the name same strucutre only makes sense for file names / tree
not actual contents
j

Javier

10/17/2021, 9:39 PM
so what should I do?
in my case I was thinking if you see feasible I add another function to bypass those issues
s

sam

10/17/2021, 9:40 PM
I think if we start comparing file contents we're gonna run into all kinds of issues
j

Javier

10/17/2021, 9:40 PM
no no, there is no issues with that, only if files are generated or something so
s

sam

10/17/2021, 9:41 PM
ok
I still think it's useful to have an assertion that only checks structure too
j

Javier

10/17/2021, 9:41 PM
for example this gradle plugin generates html files with
\
in its content in windows
s

sam

10/17/2021, 9:41 PM
right
j

Javier

10/17/2021, 9:41 PM
what do you think about three functions
structure
structure + content
structure + content + transform + filtering
s

sam

10/17/2021, 9:42 PM
yes that works
I like that
j

Javier

10/17/2021, 9:42 PM
ie:
fun File.shouldHaveSameStructure(file: File, transform: transform: (T) -> Unit, filter: (T) -> Boolean)
I am going to add them
s

sam

10/17/2021, 9:43 PM
ok
j

Jim

10/17/2021, 9:43 PM
Can you use "mutate" instead of transform perhaps?
s

sam

10/17/2021, 9:43 PM
I think transform is a more common name than mutate
j

Jim

10/17/2021, 9:44 PM
Huh I deduced what it did from the type, it wasn't clear to me
Also
other: File
s

sam

10/17/2021, 9:45 PM
Actually yeah, what is T ?
j

Javier

10/17/2021, 9:45 PM
yeah you have right
should be
s

sam

10/17/2021, 9:45 PM
Do like a ByteArray or something
j

Javier

10/17/2021, 9:45 PM
filter (File, File) -> boolean
s

sam

10/17/2021, 9:46 PM
or file
j

Javier

10/17/2021, 9:46 PM
in my case, I am filtering all gz files
s

sam

10/17/2021, 9:46 PM
why double file on the filter ?
j

Javier

10/17/2021, 9:48 PM
technically you are comparing pairs of files
s

sam

10/17/2021, 9:48 PM
It's a filter, shouldn't it be File -> Boolean
j

Javier

10/17/2021, 9:48 PM
probably having only one file is enough, "because they should be the same", but not sure if there is use case where you can filter using the file B instead of file A or viceversa
or even both
i.e. filter { a, b -> a.readLines().size == 1 && b.readLines().size == 2 }
s

sam

10/17/2021, 9:50 PM
I thought the filter function would "normalize" it
if it's actuallying comparing the files then call it compare
j

Javier

10/17/2021, 9:57 PM
fun File.shouldHaveSameStructure(
  file: File,
  filter: (expect: File, actual: File) -> Boolean
) {
  val expectFiles = this.walkTopDown().toList()
  val actualFiles = file.walkTopDown().toList()

  expectFiles shouldBeSameSizeAs actualFiles

  expectFiles.zip(actualFiles) { expect, actual ->
    when {
      filter(expect, actual) -> {}
      expect.isDirectory -> actual.shouldBeADirectory()
      expect.isFile -> expect shouldHavePath actual.path
      else -> error("There is an unexpected error analyzing file trees")
    }
  }
}
what do you think?
s

sam

10/17/2021, 9:58 PM
I wouldn't call it filter. Filter implies you are filtering things out. Here you are comparing. So I would call it compare, or isEqual or something
👍 1
But other than that, I like
j

Javier

10/17/2021, 9:58 PM
techncally, you are filtering that comparison
s

sam

10/17/2021, 9:58 PM
I dunno, it doesn't seem right to me
I know you are filtering the file contents, but I'd never expect a function called filter to compare two things
j

Javier

10/17/2021, 9:59 PM
but the function is not comparing, is filtering
one sample
fileA.shouldHaveSameStructure(fileB, filter = { a, b -> a.extension == "html" })
s

sam

10/17/2021, 10:00 PM
so what's b doing here ?
you don't use the b arg
j

Javier

10/17/2021, 10:01 PM
when it is going to be compared the file a with b, if a is a json, it is filtered
yeah
but you can do different comparison
ie
fileA.shouldHaveSameStructure(fileB, filter = { a, b -> a.readlines().size == 2 || b.readlines().size == 5 })
s

sam

10/17/2021, 10:02 PM
you're not filtering anything there. You're applying a predicate to the files.
j

Jim

10/17/2021, 10:02 PM
Are we trying to test that two file trees have the same structure ignoring nodes based on some predicate?
j

Javier

10/17/2021, 10:02 PM
I am removing from the comparison all files with have those predicates
s

sam

10/17/2021, 10:03 PM
so you are filtering files FROM the comparison ?
If so why can't it just be File -> Boolean
j

Javier

10/17/2021, 10:03 PM
it can, but a and b can be different, so maybe there can be use cases where you need both
@Jim both trees are identical, but you can remove from the comparison some files
for example, a tree generated in windows and a tree generated in macos, I want to filter if the file extension is
.gz
what name should I put @sam? compare is weird for me, because I am not comparing, I am comparing and removing from the comparison
j

Jim

10/17/2021, 10:06 PM
Yeah so File -> Boolean makes sense here
j

Javier

10/17/2021, 10:07 PM
and about the
filter
name?
j

Jim

10/17/2021, 10:10 PM
Yeah I think so, it should apply the same filter to both files in the comparison but hide that from the tester I think,
it
instead of
a, b
s

sam

10/17/2021, 10:12 PM
filter is fine if it's File -> Boolean
j

Javier

10/17/2021, 10:12 PM
fun File.shouldHaveSameStructure(
  file: File,
  filter: (File) -> Boolean
) {
  val expectFiles = this.walkTopDown().toList()
  val actualFiles = file.walkTopDown().toList()

  expectFiles shouldBeSameSizeAs actualFiles

  expectFiles.zip(actualFiles) { expect, actual ->
    when {
      filter(expect) -> {}
      expect.isDirectory -> actual.shouldBeADirectory()
      expect.isFile -> expect shouldHavePath actual.path
      else -> error("There is an unexpected error analyzing file trees")
    }
  }
}
s

sam

10/17/2021, 10:12 PM
if it's File,File -> Boolean then filter is odd
Yep, either
fun File.shouldHaveSameStructure(
  file: File,
  filter: (File) -> Boolean
)
or
fun File.shouldHaveSameStructure(
  file: File,
  filterLhs: (File) -> Boolean,
  filterRhs: (File-> Boolean,
)
If you really really want to filter the two sides separately
j

Javier

10/17/2021, 10:13 PM
I like that
about
transform
, I should do that too?
s

sam

10/17/2021, 10:15 PM
personally, I'd keep it simple for now
can always add more stuff later
j

Javier

10/17/2021, 10:15 PM
and about filterLhs and Rhs, should be
&&
or
||
filterLhs(expect) && filterRhs(actual) -> {}
s

sam

10/17/2021, 10:16 PM
|| makes sense to me
j

Javier

10/17/2021, 10:16 PM
yep
I would like to add the transform one because I need it too, I think it can be useful for codegen files comparison where the file content can vary only in separators or something so
s

sam

10/17/2021, 10:19 PM
Ok then :)
j

Javier

10/17/2021, 10:20 PM
should I separate the transform there in two transform functions, or in this case it is better to have only one transform?
s

sam

10/17/2021, 10:20 PM
I don't really have an opinion on that so we can just go with whatver you think is best
j

Javier

10/17/2021, 10:21 PM
my use case a and b have different content because the codegen, so I want to transform the files "to be the same" (if really they are the same and only separators are the problem)
I think it should be one
s

sam

10/17/2021, 10:21 PM
Ok that's cool
j

Javier

10/17/2021, 10:24 PM
well, technically with the filter functions I can achieve that
well, no, because there is separated
fun File.shouldHaveSameStructure(
  file: File,
  filterLhs: (File) -> Boolean,
  filterRhs: (File) -> Boolean,
) {
if I remerge them into one, there is no need to add another with transform
I know understand your
compare
, my head did "tick"
👍🏻 1