-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[WIP] consolidate entity serialization #2074
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- refactored JavaEntity to be DRY with respect to repeating the serialization of fields shared by many types of entities - added tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job, pretty much exactly what we want - as well as finding a few spots where we missed fields. Just a few nitpicks to fix and then we can merge 🎉
case ent: Val => ent.asJava | ||
case ent: TypeAlias => ent.asJava | ||
case _ => Map.empty.asJava | ||
private def parseEntity(ent: Entity, extras: Map[String, _]): JMap[String, _] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we still using the extras
or can we kill that parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, looks like none of the current callers actually pass any extras. I'll remove it!
case _ => Map.empty.asJava | ||
private def parseEntity(ent: Entity, extras: Map[String, _]): JMap[String, _] = { | ||
val entity = Map( | ||
"kind" -> ent.kind, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's kill vertical alignment now that we're writing code that may change:
+ val entity = Map(
+ "kind" -> ent.kind,
) | ||
case _ => Map.empty | ||
} | ||
(entity ++ members ++ superTypes ++ modifiers ++ typeParams ++ constructors ++ companion ++ returnValue ++ implicitlyAddedEntity ++ typeAlias ++ trt ++ df).asJava |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's make this a:
{
entity ++
members ++
...
df
}.asJava
import model.references.{ConstantReference, TypeReference, NoLink} | ||
import model.comment.Comment | ||
import dotty.tools.dotc.core.Symbols.NoSymbol | ||
import _root_.java.util.{Optional => JOptional, Map => JMap} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can get rid of _root_
now, it was needed previously for historic (i.e. dumb) reasons.
import model.JavaConverters._ | ||
|
||
@Test def entityConversions = { | ||
trait TestEntity extends Entity { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to create all these intermediate subclasses of entities.scala
- see below
trait TestTrait extends TestModifiers with TestTypeParams with TestSuperTypes with TestMembers with TestCompanion { | ||
def traitParams = List() | ||
} | ||
val ent = new TestEntity {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of extending and instantiating, just do:
val ent = new Entity {
val symbol = ...
val name = ...
}
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to do this without repeating the fields of Entity (and some others) in each anonymous trait instantiation? I ended up making a bunch of TestX traits implementing each entity trait just to avoid repeating common fields, but I agree that it does feel a little verbose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, but there are only a few concrete instances of the entities, eg:
- Package
- CaseClass
- Class
- Object
- Trait
- Def
- Val
- TypeAlias
See internal.scala
. No need to instantiate Entity with Members
et al
val implicitlyAddedEntity_serialized = implicitlyAddedEntity.asJava() | ||
val typeAlias_serialized = typeAlias.asJava() | ||
val def_serialized = df.asJava() | ||
val trait_serialized = trt.asJava() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here we're not really testing the result of the conversion, just that the conversions apply to all entities, we could be doing:
val df = new Def { val name = "foo"; ... }.asJava
assertEquals("foo", df.get("name"))
100% test coverage here might be overkill, but perhaps testing a that (pseudo code):
(Foo extends Bar).asJava.get("superTypes").asScala.toList == List(Foo)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, the tests are pretty weak as they are. I'll add some checking of the actual results - especially the low-hanging fruit.
Feel free to include feedback as a second commit, no probs |
- Added tests to ensure that the results of serialization match their pre-serialization values. - Removed unused parameter `extras` from Entity.asJava() implicit methods. - Removed _root_ imports - Fixed several code style issues
Contents of the second commit:
The tests are fairly comprehensive (with the most notable omission being no testing of Comment serialization), but at the same time they are fairly repetitive, which I'm worried could lead to them being out of sync with the serialization code in the future. What are your thoughts on using reflection or macros to DRY up the test code? Too much unnecessary complexity? |
assertSerializedCorrectly(pkg, pkg.asJava()) | ||
} | ||
|
||
def assertEach[E, A, C[E] <: Seq[E]](expected: C[E], serialized: Any, pairwiseAssertion: (E, A) => Unit) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we separate this into two parameter lists, do we still need the type annotation at call site?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
e.g:
def map[A,B](a: A, f: A => B) = f(a)
map(1, x => x * 2) // does not compile, needs type annotation
def map2[A,B](a: A)(f: A => B) = f(a)
map(1)(x => x * 2) // compiles
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, looks like we don't! Removing the type annotations significantly improves the readability of the calls.
Can I amend the commit, or would that confuse the system?
Well it looks like you had fun with the testing ^^ I'll have a look in the morning, for now just one feedback point already posted. Cheers, |
just rebase and force push, that's fine :)
…On Tue, Mar 14, 2017 at 7:59 PM Valthor Halldorsson < ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In doc-tool/test/JavaConverterTest.scala
<#2074 (comment)>:
> + }
+ assertSerializedCorrectly(vl, vl.asJava())
+ val pkg = new Package {
+ def symbol = NoSymbol
+ def name = "test"
+ def path = "path" :: "to" :: "test" :: Nil
+ def comment = None
+ def annotations = List("test")
+ def parent = NonEntity
+ def members = trt :: typeAlias :: Nil
+ def superTypes = new NoLink("title", "query") :: Nil
+ }
+ assertSerializedCorrectly(pkg, pkg.asJava())
+ }
+
+ def assertEach[E, A, C[E] <: Seq[E]](expected: C[E], serialized: Any, pairwiseAssertion: (E, A) => Unit) {
Nope, looks like we don't! Removing the type annotations significantly
improves the readability of the calls.
Can I amend the commit, or would that confuse the system?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2074 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABdYwfv4F5Vh6jDxO2U3DDo4TNhKeGmRks5rluOFgaJpZM4MZGaT>
.
|
28f7823
to
6c92428
Compare
- Added tests to ensure that the results of serialization match their pre-serialization values. - Removed unused parameter `extras` from Entity.asJava() implicit methods. - Removed _root_ imports - Fixed several code style issues
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
assertSameSeq(expected.path, actual.get("path")) | ||
assertEquals(expected.hasShortenedDocstring, actual.get("hasShortenedDocstring")) | ||
// Only test if a comment is present | ||
expected.comment match { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is fine, but the idiomatic way to do this would be:
expected.comment.foreach(assertNotEquals(null, actual.get("comment")))
Thanks @vlthr! Happy to get this merged 🎉 |
Related issue: #1950
Refactored the various implicit classes that handled serialization of entities into a single class. Entities are now serialized by unioning together the result of serializing their individual subtypes/inherited traits.
I also added a test to statically ensure that the implicit conversions work, and that the serializations are successful (but not whether the result is correct).
Review by @felixmulder