Skip to content

Commit

Permalink
fix: do not redact regular case classes (#16)
Browse files Browse the repository at this point in the history
* fix: scala2: do not run redaction on case classes without any @redacted annotation

* fix: added example & test for value case classes; bumped version
  • Loading branch information
polentino authored May 13, 2024
1 parent 288a99d commit 3beede8
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 7 deletions.
26 changes: 20 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ in your `build.sbt` file, add the following lines

```scala 3
val redactedVersion = // use latest version of the library
resolvers += DefaultMavenRepository
,
resolvers += DefaultMavenRepository

libraryDependencies ++= Seq(
"io.github.polentino" %% "redacted" % redactedVersion cross CrossVersion.full,
compilerPlugin("io.github.polentino" %% "redacted-plugin" % redactedVersion cross CrossVersion.full)
Expand Down Expand Up @@ -104,7 +104,7 @@ will still print the real values:
> $ abcdefghijklmnopqrstuvwxyz
> $ polentino911@somemail.com
### Nested case class!
### Nested case class

It also works with nested case classes:

Expand All @@ -118,7 +118,7 @@ println(wrapper)
will print
> Wrapper(id-1,User(8b2d4570-d043-473b-a56d-fe98105ccc2b, polentino911, ***))
### Nested case class with upper level annotation!
### Nested case class with upper level annotation

It also works with nested case classes:

Expand All @@ -132,6 +132,21 @@ println(wrapper)
will print
> Wrapper(id-1,***)
### Value case classes

`@redacted` plays nicely with value case classes too, i.e.

```scala 3
case class Password(@redacted value: String) extends AnyVal
val p = Password("somepassword")
println(p)
```
will print on console

```scala 3
Password(***)
```

### Note on curried case classes

While it is possible to write something like
Expand Down Expand Up @@ -182,8 +197,7 @@ implementation by selectively returning either the `***` string, or the value of

```scala 3
def toString(): String =
"<class name>(" + this.< field not redacted > + "," + "***" +
...+")"
"<class name>(" + this.< field not redacted > + "," + "***" +...+")"
```

## Improvements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ class RedactedPluginComponent(val global: Global) extends PluginComponent with T
classDef.impl.body.collectFirst {
case d: DefDef if d.name.decode == GenBCode.INSTANCE_CONSTRUCTOR_NAME =>
d.vparamss.headOption.fold(List.empty[ValDef])(v => v.filter(_.mods.hasAnnotationNamed(redactedTypeName)))
} match {
case Some(fields) if fields.nonEmpty => Some(fields)
case _ => None
}

/** Utility method to generate a new `toString` definition based on the parameters marked with `@redacted`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ class RedactedSpec extends AnyFlatSpec with ScalaCheckPropertyChecks {
}
}

it should "not change the default behavior, if no annotation is used" in {
case class NormalCaseClass(name: String, age: Int)

forAll { (name: String, age: Int) =>
val expected = s"NormalCaseClass($name,$age)"
val testing = NormalCaseClass(name, age)
val implicitToString = s"$testing"
val explicitToString = testing.toString

val cp = new Checkpoint
cp { assert(implicitToString == expected) }
cp { assert(explicitToString == expected) }
cp {
assert(testing.name == name && testing.age == age)
}
cp.reportAll()
}
}

it should "work with a redacted case class with many members" in {
case class ManyMembers(field1: String, @redacted field2: String, @redacted field3: String, field4: String)

Expand Down Expand Up @@ -136,6 +155,21 @@ class RedactedSpec extends AnyFlatSpec with ScalaCheckPropertyChecks {
}
}

it should "work with value case classes" in {
forAll { (pwd: String) =>
val expected = s"Password(***)"
val testing = Password(pwd)
val implicitToString = s"$testing"
val explicitToString = testing.toString

val cp = new Checkpoint
cp { assert(implicitToString == expected) }
cp { assert(explicitToString == expected) }
cp { assert(testing.value == pwd) }
cp.reportAll()
}
}

it must "not change the behavior of `hashCode`" in {
final case class TestClass(uuid: UUID, name: String, age: Int)
object RedactedTestClass {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.github.polentino

package object redacted {
case class Password(@redacted value: String) extends AnyVal
}
2 changes: 1 addition & 1 deletion version.sbt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ThisBuild / version := "0.5.0"
ThisBuild / version := "0.5.1"

0 comments on commit 3beede8

Please sign in to comment.